diff --git a/src/southbridge/amd/agesa/hudson/Makefile.inc b/src/southbridge/amd/agesa/hudson/Makefile.inc index 54a93d23f8..b92e850664 100644 --- a/src/southbridge/amd/agesa/hudson/Makefile.inc +++ b/src/southbridge/amd/agesa/hudson/Makefile.inc @@ -22,6 +22,9 @@ ramstage-$(CONFIG_HAVE_ACPI_RESUME) += resume.c romstage-y += imc.c ramstage-y += imc.c +smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c +ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c + # ROMSIG At ROMBASE + 0x20000: # +-----------+---------------+----------------+------------+ # |0x55AA55AA |EC ROM Address |GEC ROM Address |USB3 ROM | diff --git a/src/southbridge/amd/agesa/hudson/smi.c b/src/southbridge/amd/agesa/hudson/smi.c new file mode 100644 index 0000000000..bb5e192f53 --- /dev/null +++ b/src/southbridge/amd/agesa/hudson/smi.c @@ -0,0 +1,60 @@ +/* + * Utilities for SMM setup + * + * Copyright (C) 2014 Alexandru Gagniuc + * Subject to the GNU GPL v2, or (at your option) any later version. + */ + +#include "smi.h" + +#include +#include + +void smm_setup_structures(void *gnvs, void *tcg, void *smi1) +{ + printk(BIOS_DEBUG, "smm_setup_structures STUB!!!\n"); +} + +/** Set the EOS bit and enable SMI generation from southbridge */ +void hudson_enable_smi_generation(void) +{ + uint32_t reg = smi_read32(SMI_REG_SMITRIG0); + reg &= ~SMITRG0_SMIENB; /* Enable SMI generation */ + reg |= SMITRG0_EOS; /* Set EOS bit */ + smi_write32(SMI_REG_SMITRIG0, reg); +} + +static void enable_smi(uint8_t smi_num) +{ + uint8_t reg32_offset, bit_offset; + uint32_t reg32; + + /* SMI sources range from [0:149] */ + if (smi_num > 149) { + printk(BIOS_WARNING, "BUG: Invalid SMI: %u\n", smi_num); + return; + } + + /* 16 sources per register, 2 bits per source; registers are 4 bytes */ + reg32_offset = (smi_num / 16) * 4; + bit_offset = (smi_num % 16) * 2; + + reg32 = smi_read32(SMI_REG_CONTROL0 + reg32_offset); + reg32 &= ~(3 << (bit_offset)); + reg32 |= (SMI_SRC_MODE_SMI << (bit_offset)); + smi_write32(SMI_REG_CONTROL0 + reg32_offset, reg32); + +} + +/** Enable generation of SMIs for given GPE */ +void hudson_enable_gevent_smi(uint8_t gevent) +{ + /* GEVENT pins range from [0:23] */ + if (gevent > 23) { + printk(BIOS_WARNING, "BUG: Invalid GEVENT: %u\n", gevent); + return; + } + + /* SMI0 source is GEVENT0 and so on */ + enable_smi(gevent); +} diff --git a/src/southbridge/amd/agesa/hudson/smi.h b/src/southbridge/amd/agesa/hudson/smi.h new file mode 100644 index 0000000000..f7120c8b19 --- /dev/null +++ b/src/southbridge/amd/agesa/hudson/smi.h @@ -0,0 +1,57 @@ +/* + * Utilities for SMI handlers and SMM setup + * + * Copyright (C) 2014 Alexandru Gagniuc + * Subject to the GNU GPL v2, or (at your option) any later version. + */ + +#ifndef _SOUTHBRIDGE_AMD_AGESA_HUDSON_SMI_H +#define _SOUTHBRIDGE_AMD_AGESA_HUDSON_SMI_H + +#include + +/* ACPI_MMIO_BASE + 0x200 -- leave this string here so grep catches it. + * This is defined by AGESA, but we dpn't include AGESA headers to avoid + * polluting the namesace. + */ +#define SMI_BASE 0xfed80200 + +#define SMI_REG_SMITRIG0 0x98 +#define SMITRG0_EOS (1 << 28) +#define SMITRG0_SMIENB (1 << 31) + +#define SMI_REG_CONTROL0 0xa0 + +enum smi_src_mode { + SMI_SRC_MODE_DISABLE = 0, + SMI_SRC_MODE_SMI = 1, + SMI_SRC_MODE_NMI = 2, + SMI_SRC_MODE_IRQ13 = 3, +}; + +static inline uint32_t smi_read32(uint8_t offset) +{ + return read32(SMI_BASE + offset); +} + +static inline void smi_write32(uint8_t offset, uint32_t value) +{ + write32(SMI_BASE + offset, value); +} + +static inline uint16_t smi_read16(uint8_t offset) +{ + return read16(SMI_BASE + offset); +} + +static inline void smi_write16(uint8_t offset, uint16_t value) +{ + write16(SMI_BASE + offset, value); +} + +#ifndef __SMM__ +void hudson_enable_smi_generation(void); +void hudson_enable_gevent_smi(uint8_t gevent); +#endif + +#endif /* _SOUTHBRIDGE_AMD_AGESA_HUDSON_SMI_H */ diff --git a/src/southbridge/amd/agesa/hudson/smihandler.c b/src/southbridge/amd/agesa/hudson/smihandler.c new file mode 100644 index 0000000000..0bf0cdd1d3 --- /dev/null +++ b/src/southbridge/amd/agesa/hudson/smihandler.c @@ -0,0 +1,100 @@ +/* + * SMI handler for Hudson southbridges + * + * Copyright (C) 2014 Alexandru Gagniuc + * Subject to the GNU GPL v2, or (at your option) any later version. + */ + +#include "smi.h" + +#include +#include +#include + + +enum smi_source { + SMI_SOURCE_SCI = (1 << 0), + SMI_SOURCE_GPE = (1 << 1), + SMI_SOURCE_0x84 = (1 << 2), + SMI_SOURCE_0x88 = (1 << 3), + SMI_SOURCE_IRQ_TRAP = (1 << 4), + SMI_SOURCE_0x90 = (1 << 5) +}; + +int southbridge_io_trap_handler(int smif) +{ + return 0; +} + +static void process_smi_sci(void) +{ + const uint32_t status = smi_read32(0x10); + + /* Clear events to prevent re-entering SMI if event isn't handled */ + smi_write32(0x10, status); +} + +static void process_gpe_smi(void) +{ + const uint32_t status = smi_read32(0x80); + + /* Clear events to prevent re-entering SMI if event isn't handled */ + smi_write32(0x80, status); +} + +static void process_smi_0x84(void) +{ + const uint32_t status = smi_read32(0x84); + + /* Clear events to prevent re-entering SMI if event isn't handled */ + smi_write32(0x84, status); +} + +static void process_smi_0x88(void) +{ + const uint32_t status = smi_read32(0x88); + + /* Clear events to prevent re-entering SMI if event isn't handled */ + smi_write32(0x88, status); +} + +static void process_smi_0x8c(void) +{ + const uint32_t status = smi_read32(0x8c); + + /* Clear events to prevent re-entering SMI if event isn't handled */ + smi_write32(0x8c, status); +} + +static void process_smi_0x90(void) +{ + const uint32_t status = smi_read32(0x90); + + /* Clear events to prevent re-entering SMI if event isn't handled */ + smi_write32(0x90, status); +} + +void southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save) +{ + const uint16_t smi_src = smi_read16(0x94); + + if (smi_src & SMI_SOURCE_SCI) + process_smi_sci(); + if (smi_src & SMI_SOURCE_GPE) + process_gpe_smi(); + if (smi_src & SMI_SOURCE_0x84) + process_smi_0x84(); + if (smi_src & SMI_SOURCE_0x88) + process_smi_0x88(); + if (smi_src & SMI_SOURCE_IRQ_TRAP) + process_smi_0x8c(); + if (smi_src & SMI_SOURCE_0x90) + process_smi_0x90(); +} + +void southbridge_smi_set_eos(void) +{ + uint32_t reg = smi_read32(SMI_REG_SMITRIG0); + reg |= SMITRG0_EOS; + smi_write32(SMI_REG_SMITRIG0, reg); +}