diff options
author | Arthur Heymans <arthur@aheymans.xyz> | 2018-04-10 12:56:19 +0200 |
---|---|---|
committer | Arthur Heymans <arthur@aheymans.xyz> | 2018-11-27 12:09:53 +0000 |
commit | 31312b21d147938cb4d88ed90e570ac7804c930d (patch) | |
tree | 57a714d7939d23838e990686b089f9364dc049ef | |
parent | 516f06e0fb7e4ba4e9ae6c024ab36a079b7cbb76 (diff) |
sb/intel/i82801gx: Use common Intel SMM code
Use the common Intel code to set up smm and the smihandler. This is
expected to break S3 resume and other smihandler related
functionality as this code is meant to be used with
CONFIG_SMM_TSEG. Platforms (i945, pineview, x4x) using this
southbridge will adapt the CONFIG_SMM_TSEG codepath in subsequent
patches.
Tested on Intel D945GCLF, still boots fine but breaks S3 resume
support because it hangs on SMI.
Change-Id: If7016a3b98fc5f14c287ce800325084f9dc602a0
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/c/25594
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
-rw-r--r-- | src/mainboard/apple/macbook21/smihandler.c | 2 | ||||
-rw-r--r-- | src/mainboard/lenovo/t60/smihandler.c | 2 | ||||
-rw-r--r-- | src/mainboard/lenovo/x60/smihandler.c | 2 | ||||
-rw-r--r-- | src/mainboard/lenovo/z61t/smihandler.c | 2 | ||||
-rw-r--r-- | src/southbridge/intel/common/pmutil.h | 10 | ||||
-rw-r--r-- | src/southbridge/intel/i82801gx/Kconfig | 1 | ||||
-rw-r--r-- | src/southbridge/intel/i82801gx/i82801gx.h | 1 | ||||
-rw-r--r-- | src/southbridge/intel/i82801gx/smi.c | 257 | ||||
-rw-r--r-- | src/southbridge/intel/i82801gx/smihandler.c | 626 |
9 files changed, 22 insertions, 881 deletions
diff --git a/src/mainboard/apple/macbook21/smihandler.c b/src/mainboard/apple/macbook21/smihandler.c index ab33801560..ec2f0772cb 100644 --- a/src/mainboard/apple/macbook21/smihandler.c +++ b/src/mainboard/apple/macbook21/smihandler.c @@ -18,7 +18,7 @@ #include <console/console.h> #include <cpu/x86/smm.h> #include <southbridge/intel/i82801gx/nvs.h> -#include <southbridge/intel/i82801gx/i82801gx.h> +#include <southbridge/intel/common/pmutil.h> #include <delay.h> #define GPE_EC_SCI 12 diff --git a/src/mainboard/lenovo/t60/smihandler.c b/src/mainboard/lenovo/t60/smihandler.c index 4e6a68d356..aa29984ef4 100644 --- a/src/mainboard/lenovo/t60/smihandler.c +++ b/src/mainboard/lenovo/t60/smihandler.c @@ -18,7 +18,7 @@ #include <console/console.h> #include <cpu/x86/smm.h> #include <southbridge/intel/i82801gx/nvs.h> -#include <southbridge/intel/i82801gx/i82801gx.h> +#include <southbridge/intel/common/pmutil.h> #include <ec/acpi/ec.h> #include "dock.h" #include "smi.h" diff --git a/src/mainboard/lenovo/x60/smihandler.c b/src/mainboard/lenovo/x60/smihandler.c index 6d95ee1adc..3c8565d496 100644 --- a/src/mainboard/lenovo/x60/smihandler.c +++ b/src/mainboard/lenovo/x60/smihandler.c @@ -18,7 +18,7 @@ #include <console/console.h> #include <cpu/x86/smm.h> #include <southbridge/intel/i82801gx/nvs.h> -#include <southbridge/intel/i82801gx/i82801gx.h> +#include <southbridge/intel/common/pmutil.h> #include <ec/acpi/ec.h> #include <pc80/mc146818rtc.h> #include <ec/lenovo/h8/h8.h> diff --git a/src/mainboard/lenovo/z61t/smihandler.c b/src/mainboard/lenovo/z61t/smihandler.c index 253ab44e90..4f622241a6 100644 --- a/src/mainboard/lenovo/z61t/smihandler.c +++ b/src/mainboard/lenovo/z61t/smihandler.c @@ -18,7 +18,7 @@ #include <console/console.h> #include <cpu/x86/smm.h> #include <southbridge/intel/i82801gx/nvs.h> -#include <southbridge/intel/i82801gx/i82801gx.h> +#include <southbridge/intel/common/pmutil.h> #include <ec/acpi/ec.h> #include "dock.h" #include "smi.h" diff --git a/src/southbridge/intel/common/pmutil.h b/src/southbridge/intel/common/pmutil.h index c578982e92..2e761ccef2 100644 --- a/src/southbridge/intel/common/pmutil.h +++ b/src/southbridge/intel/common/pmutil.h @@ -63,8 +63,14 @@ #define LV2 0x14 #define LV3 0x15 #define LV4 0x16 +#if IS_ENABLED(CONFIG_SOUTHBRIDGE_INTEL_I82801GX) +#define PM2_CNT 0x20 // mobile only +#define GPE0_STS 0x28 +#else #define PM2_CNT 0x50 // mobile only #define GPE0_STS 0x20 +#endif /* IS_ENABLED(CONFIG_SOUTHBRIDGE_INTEL_I82801GX) */ +#define USB4_STS (1 << 14) /* i82801gx only */ #define PME_B0_STS (1 << 13) #define PME_STS (1 << 11) #define BATLOW_STS (1 << 10) @@ -74,7 +80,11 @@ #define TCOSCI_STS (1 << 6) #define SWGPE_STS (1 << 2) #define HOT_PLUG_STS (1 << 1) +#if IS_ENABLED(CONFIG_SOUTHBRIDGE_INTEL_I82801GX) +#define GPE0_EN 0x2c +#else #define GPE0_EN 0x28 +#endif /* IS_ENABLED(CONFIG_SOUTHBRIDGE_INTEL_I82801GX) */ #define PME_B0_EN (1 << 13) #define PME_EN (1 << 11) #define TCOSCI_EN (1 << 6) diff --git a/src/southbridge/intel/i82801gx/Kconfig b/src/southbridge/intel/i82801gx/Kconfig index 28d42ffbe9..d4615faf7d 100644 --- a/src/southbridge/intel/i82801gx/Kconfig +++ b/src/southbridge/intel/i82801gx/Kconfig @@ -28,6 +28,7 @@ config SOUTHBRIDGE_INTEL_I82801GX select HAVE_INTEL_CHIPSET_LOCKDOWN select SOUTHBRIDGE_INTEL_COMMON_RCBA_PIRQ select INTEL_HAS_TOP_SWAP + select SOUTHBRIDGE_INTEL_COMMON_SMM if SOUTHBRIDGE_INTEL_I82801GX diff --git a/src/southbridge/intel/i82801gx/i82801gx.h b/src/southbridge/intel/i82801gx/i82801gx.h index d14a809f66..40c2bb72e3 100644 --- a/src/southbridge/intel/i82801gx/i82801gx.h +++ b/src/southbridge/intel/i82801gx/i82801gx.h @@ -42,7 +42,6 @@ #if !defined(__SIMPLE_DEVICE__) void i82801gx_enable(struct device *dev); #endif -void gpi_route_interrupt(u8 gpi, u8 mode); #else void enable_smbus(void); int smbus_read_byte(unsigned int device, unsigned int address); diff --git a/src/southbridge/intel/i82801gx/smi.c b/src/southbridge/intel/i82801gx/smi.c index 8cfd511ae4..5618db7840 100644 --- a/src/southbridge/intel/i82801gx/smi.c +++ b/src/southbridge/intel/i82801gx/smi.c @@ -23,6 +23,7 @@ #include <cpu/x86/cache.h> #include <cpu/x86/smm.h> #include <string.h> +#include <southbridge/intel/common/pmutil.h> #include "i82801gx.h" /* I945 */ @@ -38,253 +39,6 @@ */ static u16 pmbase = DEFAULT_PMBASE; -/** - * @brief read and clear PM1_STS - * @return PM1_STS register - */ -static u16 reset_pm1_status(void) -{ - u16 reg16; - - reg16 = inw(pmbase + PM1_STS); - /* set status bits are cleared by writing 1 to them */ - outw(reg16, pmbase + PM1_STS); - - return reg16; -} - -static void dump_pm1_status(u16 pm1_sts) -{ - printk(BIOS_DEBUG, "PM1_STS: "); - if (pm1_sts & (1 << 15)) - printk(BIOS_DEBUG, "WAK "); - if (pm1_sts & (1 << 14)) - printk(BIOS_DEBUG, "PCIEXPWAK "); - if (pm1_sts & (1 << 11)) - printk(BIOS_DEBUG, "PRBTNOR "); - if (pm1_sts & (1 << 10)) - printk(BIOS_DEBUG, "RTC "); - if (pm1_sts & (1 << 8)) - printk(BIOS_DEBUG, "PWRBTN "); - if (pm1_sts & (1 << 5)) - printk(BIOS_DEBUG, "GBL "); - if (pm1_sts & (1 << 4)) - printk(BIOS_DEBUG, "BM "); - if (pm1_sts & (1 << 0)) - printk(BIOS_DEBUG, "TMROF "); - printk(BIOS_DEBUG, "\n"); -} - -/** - * @brief read and clear SMI_STS - * @return SMI_STS register - */ -static u32 reset_smi_status(void) -{ - u32 reg32; - - reg32 = inl(pmbase + SMI_STS); - /* set status bits are cleared by writing 1 to them */ - outl(reg32, pmbase + SMI_STS); - - return reg32; -} - -static void dump_smi_status(u32 smi_sts) -{ - printk(BIOS_DEBUG, "SMI_STS: "); - if (smi_sts & (1 << 26)) - printk(BIOS_DEBUG, "SPI "); - if (smi_sts & (1 << 25)) - printk(BIOS_DEBUG, "EL_SMI "); - if (smi_sts & (1 << 21)) - printk(BIOS_DEBUG, "MONITOR "); - if (smi_sts & (1 << 20)) - printk(BIOS_DEBUG, "PCI_EXP_SMI "); - if (smi_sts & (1 << 18)) - printk(BIOS_DEBUG, "INTEL_USB2 "); - if (smi_sts & (1 << 17)) - printk(BIOS_DEBUG, "LEGACY_USB2 "); - if (smi_sts & (1 << 16)) - printk(BIOS_DEBUG, "SMBUS_SMI "); - if (smi_sts & (1 << 15)) - printk(BIOS_DEBUG, "SERIRQ_SMI "); - if (smi_sts & (1 << 14)) - printk(BIOS_DEBUG, "PERIODIC "); - if (smi_sts & (1 << 13)) - printk(BIOS_DEBUG, "TCO "); - if (smi_sts & (1 << 12)) - printk(BIOS_DEBUG, "DEVMON "); - if (smi_sts & (1 << 11)) - printk(BIOS_DEBUG, "MCSMI "); - if (smi_sts & (1 << 10)) - printk(BIOS_DEBUG, "GPI "); - if (smi_sts & (1 << 9)) - printk(BIOS_DEBUG, "GPE0 "); - if (smi_sts & (1 << 8)) - printk(BIOS_DEBUG, "PM1 "); - if (smi_sts & (1 << 6)) - printk(BIOS_DEBUG, "SWSMI_TMR "); - if (smi_sts & (1 << 5)) - printk(BIOS_DEBUG, "APM "); - if (smi_sts & (1 << 4)) - printk(BIOS_DEBUG, "SLP_SMI "); - if (smi_sts & (1 << 3)) - printk(BIOS_DEBUG, "LEGACY_USB "); - if (smi_sts & (1 << 2)) - printk(BIOS_DEBUG, "BIOS "); - printk(BIOS_DEBUG, "\n"); -} - - -/** - * @brief read and clear GPE0_STS - * @return GPE0_STS register - */ -static u32 reset_gpe0_status(void) -{ - u32 reg32; - - reg32 = inl(pmbase + GPE0_STS); - /* set status bits are cleared by writing 1 to them */ - outl(reg32, pmbase + GPE0_STS); - - return reg32; -} - -static void dump_gpe0_status(u32 gpe0_sts) -{ - int i; - printk(BIOS_DEBUG, "GPE0_STS: "); - for (i = 31; i >= 16; i--) { - if (gpe0_sts & (1 << i)) - printk(BIOS_DEBUG, "GPIO%d ", (i-16)); - } - if (gpe0_sts & (1 << 14)) - printk(BIOS_DEBUG, "USB4 "); - if (gpe0_sts & (1 << 13)) - printk(BIOS_DEBUG, "PME_B0 "); - if (gpe0_sts & (1 << 12)) - printk(BIOS_DEBUG, "USB3 "); - if (gpe0_sts & (1 << 11)) - printk(BIOS_DEBUG, "PME "); - if (gpe0_sts & (1 << 10)) - printk(BIOS_DEBUG, "EL_SCI/BATLOW "); - if (gpe0_sts & (1 << 9)) - printk(BIOS_DEBUG, "PCI_EXP "); - if (gpe0_sts & (1 << 8)) - printk(BIOS_DEBUG, "RI "); - if (gpe0_sts & (1 << 7)) - printk(BIOS_DEBUG, "SMB_WAK "); - if (gpe0_sts & (1 << 6)) - printk(BIOS_DEBUG, "TCO_SCI "); - if (gpe0_sts & (1 << 5)) - printk(BIOS_DEBUG, "AC97 "); - if (gpe0_sts & (1 << 4)) - printk(BIOS_DEBUG, "USB2 "); - if (gpe0_sts & (1 << 3)) - printk(BIOS_DEBUG, "USB1 "); - if (gpe0_sts & (1 << 2)) - printk(BIOS_DEBUG, "HOT_PLUG "); - if (gpe0_sts & (1 << 0)) - printk(BIOS_DEBUG, "THRM "); - printk(BIOS_DEBUG, "\n"); -} - - -/** - * @brief read and clear ALT_GP_SMI_STS - * @return ALT_GP_SMI_STS register - */ -static u16 reset_alt_gp_smi_status(void) -{ - u16 reg16; - - reg16 = inl(pmbase + ALT_GP_SMI_STS); - /* set status bits are cleared by writing 1 to them */ - outl(reg16, pmbase + ALT_GP_SMI_STS); - - return reg16; -} - -static void dump_alt_gp_smi_status(u16 alt_gp_smi_sts) -{ - int i; - printk(BIOS_DEBUG, "ALT_GP_SMI_STS: "); - for (i = 15; i >= 0; i--) { - if (alt_gp_smi_sts & (1 << i)) - printk(BIOS_DEBUG, "GPI%d ", i); - } - printk(BIOS_DEBUG, "\n"); -} - - - -/** - * @brief read and clear TCOx_STS - * @return TCOx_STS registers - */ -static u32 reset_tco_status(void) -{ - u32 tcobase = pmbase + 0x60; - u32 reg32; - - reg32 = inl(tcobase + 0x04); - /* set status bits are cleared by writing 1 to them */ - outl(reg32 & ~(1 << 18), tcobase + 0x04); // Don't clear BOOT_STS before SECOND_TO_STS - if (reg32 & (1 << 18)) - outl(reg32 & (1 << 18), tcobase + 0x04); // clear BOOT_STS - - return reg32; -} - - -static void dump_tco_status(u32 tco_sts) -{ - printk(BIOS_DEBUG, "TCO_STS: "); - if (tco_sts & (1 << 20)) - printk(BIOS_DEBUG, "SMLINK_SLV "); - if (tco_sts & (1 << 18)) - printk(BIOS_DEBUG, "BOOT "); - if (tco_sts & (1 << 17)) - printk(BIOS_DEBUG, "SECOND_TO "); - if (tco_sts & (1 << 16)) - printk(BIOS_DEBUG, "INTRD_DET "); - if (tco_sts & (1 << 12)) - printk(BIOS_DEBUG, "DMISERR "); - if (tco_sts & (1 << 10)) - printk(BIOS_DEBUG, "DMISMI "); - if (tco_sts & (1 << 9)) - printk(BIOS_DEBUG, "DMISCI "); - if (tco_sts & (1 << 8)) - printk(BIOS_DEBUG, "BIOSWR "); - if (tco_sts & (1 << 7)) - printk(BIOS_DEBUG, "NEWCENTURY "); - if (tco_sts & (1 << 3)) - printk(BIOS_DEBUG, "TIMEOUT "); - if (tco_sts & (1 << 2)) - printk(BIOS_DEBUG, "TCO_INT "); - if (tco_sts & (1 << 1)) - printk(BIOS_DEBUG, "SW_TCO "); - if (tco_sts & (1 << 0)) - printk(BIOS_DEBUG, "NMI2SMI "); - printk(BIOS_DEBUG, "\n"); -} - - - -/** - * @brief Set the EOS bit - */ -static void smi_set_eos(void) -{ - u8 reg8; - - reg8 = inb(pmbase + SMI_EN); - reg8 |= EOS; - outb(reg8, pmbase + SMI_EN); -} - extern uint8_t smm_relocation_start, smm_relocation_end; static void *default_smm_area = NULL; @@ -429,12 +183,3 @@ void smm_lock(void) pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM, D_LCK | G_SMRAME | C_BASE_SEG); } - -void smm_setup_structures(void *gnvs, void *tcg, void *smi1) -{ - /* The GDT or coreboot table is going to live here. But a long time - * after we relocated the GNVS, so this is not troublesome. - */ - *(u32 *)0x500 = (u32)gnvs; - outb(0xea, 0xb2); -} diff --git a/src/southbridge/intel/i82801gx/smihandler.c b/src/southbridge/intel/i82801gx/smihandler.c index 3f537c07f0..1b4a063d0e 100644 --- a/src/southbridge/intel/i82801gx/smihandler.c +++ b/src/southbridge/intel/i82801gx/smihandler.c @@ -22,6 +22,7 @@ #include <device/pci_def.h> #include <halt.h> #include <pc80/mc146818rtc.h> +#include <southbridge/intel/common/pmutil.h> #include "i82801gx.h" /* I945 */ @@ -45,246 +46,10 @@ u8 smm_initialized = 0; */ global_nvs_t *gnvs = (global_nvs_t *)0x0; -static void alt_gpi_mask(u16 clr, u16 set) +void southbridge_update_gnvs(u8 apm_cnt, int *smm_done) { - u16 alt_gp = inw(pmbase + ALT_GP_SMI_EN); - alt_gp &= ~clr; - alt_gp |= set; - outw(alt_gp, pmbase + ALT_GP_SMI_EN); -} - -static void gpe0_mask(u32 clr, u32 set) -{ - u32 gpe0 = inl(pmbase + GPE0_EN); - gpe0 &= ~clr; - gpe0 |= set; - outl(gpe0, pmbase + GPE0_EN); -} - -void gpi_route_interrupt(u8 gpi, u8 mode) -{ - u32 gpi_rout; - if (gpi >= 16) - return; - - alt_gpi_mask(1 << gpi, 0); - gpe0_mask(1 << (gpi+16), 0); - - gpi_rout = pci_read_config32(PCI_DEV(0, 0x1f, 0), GPIO_ROUT); - gpi_rout &= ~(3 << (2 * gpi)); - gpi_rout |= ((mode & 3) << (2 * gpi)); - pci_write_config32(PCI_DEV(0, 0x1f, 0), GPIO_ROUT, gpi_rout); - - if (mode == GPI_IS_SCI) - gpe0_mask(0, 1 << (gpi+16)); - else if (mode == GPI_IS_SMI) - alt_gpi_mask(0, 1 << gpi); -} - -/** - * @brief read and clear PM1_STS - * @return PM1_STS register - */ -static u16 reset_pm1_status(void) -{ - u16 reg16; - - reg16 = inw(pmbase + PM1_STS); - /* set status bits are cleared by writing 1 to them */ - outw(reg16, pmbase + PM1_STS); - - return reg16; -} - -static void dump_pm1_status(u16 pm1_sts) -{ - printk(BIOS_SPEW, "PM1_STS: "); - if (pm1_sts & (1 << 15)) - printk(BIOS_SPEW, "WAK "); - if (pm1_sts & (1 << 14)) - printk(BIOS_SPEW, "PCIEXPWAK "); - if (pm1_sts & (1 << 11)) - printk(BIOS_SPEW, "PRBTNOR "); - if (pm1_sts & (1 << 10)) - printk(BIOS_SPEW, "RTC "); - if (pm1_sts & (1 << 8)) - printk(BIOS_SPEW, "PWRBTN "); - if (pm1_sts & (1 << 5)) - printk(BIOS_SPEW, "GBL "); - if (pm1_sts & (1 << 4)) - printk(BIOS_SPEW, "BM "); - if (pm1_sts & (1 << 0)) - printk(BIOS_SPEW, "TMROF "); - printk(BIOS_SPEW, "\n"); - int reg16 = inw(pmbase + PM1_EN); - printk(BIOS_SPEW, "PM1_EN: %x\n", reg16); -} - -/** - * @brief read and clear SMI_STS - * @return SMI_STS register - */ -static u32 reset_smi_status(void) -{ - u32 reg32; - - reg32 = inl(pmbase + SMI_STS); - /* set status bits are cleared by writing 1 to them */ - outl(reg32, pmbase + SMI_STS); - - return reg32; -} - -static void dump_smi_status(u32 smi_sts) -{ - printk(BIOS_DEBUG, "SMI_STS: "); - if (smi_sts & (1 << 26)) - printk(BIOS_DEBUG, "SPI "); - if (smi_sts & (1 << 25)) - printk(BIOS_DEBUG, "EL_SMI "); - if (smi_sts & (1 << 21)) - printk(BIOS_DEBUG, "MONITOR "); - if (smi_sts & (1 << 20)) - printk(BIOS_DEBUG, "PCI_EXP_SMI "); - if (smi_sts & (1 << 18)) - printk(BIOS_DEBUG, "INTEL_USB2 "); - if (smi_sts & (1 << 17)) - printk(BIOS_DEBUG, "LEGACY_USB2 "); - if (smi_sts & (1 << 16)) - printk(BIOS_DEBUG, "SMBUS_SMI "); - if (smi_sts & (1 << 15)) - printk(BIOS_DEBUG, "SERIRQ_SMI "); - if (smi_sts & (1 << 14)) - printk(BIOS_DEBUG, "PERIODIC "); - if (smi_sts & (1 << 13)) - printk(BIOS_DEBUG, "TCO "); - if (smi_sts & (1 << 12)) - printk(BIOS_DEBUG, "DEVMON "); - if (smi_sts & (1 << 11)) - printk(BIOS_DEBUG, "MCSMI "); - if (smi_sts & (1 << 10)) - printk(BIOS_DEBUG, "GPI "); - if (smi_sts & (1 << 9)) - printk(BIOS_DEBUG, "GPE0 "); - if (smi_sts & (1 << 8)) - printk(BIOS_DEBUG, "PM1 "); - if (smi_sts & (1 << 6)) - printk(BIOS_DEBUG, "SWSMI_TMR "); - if (smi_sts & (1 << 5)) - printk(BIOS_DEBUG, "APM "); - if (smi_sts & (1 << 4)) - printk(BIOS_DEBUG, "SLP_SMI "); - if (smi_sts & (1 << 3)) - printk(BIOS_DEBUG, "LEGACY_USB "); - if (smi_sts & (1 << 2)) - printk(BIOS_DEBUG, "BIOS "); - printk(BIOS_DEBUG, "\n"); -} - - -/** - * @brief read and clear GPE0_STS - * @return GPE0_STS register - */ -static u32 reset_gpe0_status(void) -{ - u32 reg32; - - reg32 = inl(pmbase + GPE0_STS); - /* set status bits are cleared by writing 1 to them */ - outl(reg32, pmbase + GPE0_STS); - - return reg32; -} - -static void dump_gpe0_status(u32 gpe0_sts) -{ - int i; - printk(BIOS_DEBUG, "GPE0_STS: "); - for (i = 31; i >= 16; i--) { - if (gpe0_sts & (1 << i)) - printk(BIOS_DEBUG, "GPIO%d ", (i-16)); - } - if (gpe0_sts & (1 << 14)) - printk(BIOS_DEBUG, "USB4 "); - if (gpe0_sts & (1 << 13)) - printk(BIOS_DEBUG, "PME_B0 "); - if (gpe0_sts & (1 << 12)) - printk(BIOS_DEBUG, "USB3 "); - if (gpe0_sts & (1 << 11)) - printk(BIOS_DEBUG, "PME "); - if (gpe0_sts & (1 << 10)) - printk(BIOS_DEBUG, "EL_SCI/BATLOW "); - if (gpe0_sts & (1 << 9)) - printk(BIOS_DEBUG, "PCI_EXP "); - if (gpe0_sts & (1 << 8)) - printk(BIOS_DEBUG, "RI "); - if (gpe0_sts & (1 << 7)) - printk(BIOS_DEBUG, "SMB_WAK "); - if (gpe0_sts & (1 << 6)) - printk(BIOS_DEBUG, "TCO_SCI "); - if (gpe0_sts & (1 << 5)) - printk(BIOS_DEBUG, "AC97 "); - if (gpe0_sts & (1 << 4)) - printk(BIOS_DEBUG, "USB2 "); - if (gpe0_sts & (1 << 3)) - printk(BIOS_DEBUG, "USB1 "); - if (gpe0_sts & (1 << 2)) - printk(BIOS_DEBUG, "HOT_PLUG "); - if (gpe0_sts & (1 << 0)) - printk(BIOS_DEBUG, "THRM "); - printk(BIOS_DEBUG, "\n"); -} - - -/** - * @brief read and clear TCOx_STS - * @return TCOx_STS registers - */ -static u32 reset_tco_status(void) -{ - u32 tcobase = pmbase + 0x60; - u32 reg32; - - reg32 = inl(tcobase + 0x04); - /* set status bits are cleared by writing 1 to them */ - outl(reg32 & ~(1 << 18), tcobase + 0x04); // Don't clear BOOT_STS before SECOND_TO_STS - if (reg32 & (1 << 18)) - outl(reg32 & (1 << 18), tcobase + 0x04); // clear BOOT_STS - - return reg32; -} - -static void dump_tco_status(u32 tco_sts) -{ - printk(BIOS_DEBUG, "TCO_STS: "); - if (tco_sts & (1 << 20)) - printk(BIOS_DEBUG, "SMLINK_SLV "); - if (tco_sts & (1 << 18)) - printk(BIOS_DEBUG, "BOOT "); - if (tco_sts & (1 << 17)) - printk(BIOS_DEBUG, "SECOND_TO "); - if (tco_sts & (1 << 16)) - printk(BIOS_DEBUG, "INTRD_DET "); - if (tco_sts & (1 << 12)) - printk(BIOS_DEBUG, "DMISERR "); - if (tco_sts & (1 << 10)) - printk(BIOS_DEBUG, "DMISMI "); - if (tco_sts & (1 << 9)) - printk(BIOS_DEBUG, "DMISCI "); - if (tco_sts & (1 << 8)) - printk(BIOS_DEBUG, "BIOSWR "); - if (tco_sts & (1 << 7)) - printk(BIOS_DEBUG, "NEWCENTURY "); - if (tco_sts & (1 << 3)) - printk(BIOS_DEBUG, "TIMEOUT "); - if (tco_sts & (1 << 2)) - printk(BIOS_DEBUG, "TCO_INT "); - if (tco_sts & (1 << 1)) - printk(BIOS_DEBUG, "SW_TCO "); - if (tco_sts & (1 << 0)) - printk(BIOS_DEBUG, "NMI2SMI "); - printk(BIOS_DEBUG, "\n"); + gnvs = *(global_nvs_t **)0x500; + *smm_done = 1; } int southbridge_io_trap_handler(int smif) @@ -304,312 +69,7 @@ int southbridge_io_trap_handler(int smif) return 0; } -/** - * @brief Set the EOS bit - */ -void southbridge_smi_set_eos(void) -{ - u8 reg8; - - reg8 = inb(pmbase + SMI_EN); - reg8 |= EOS; - outb(reg8, pmbase + SMI_EN); -} - -static void busmaster_disable_on_bus(int bus) -{ - int slot, func; - unsigned int val; - unsigned char hdr; - - for (slot = 0; slot < 0x20; slot++) { - for (func = 0; func < 8; func++) { - u32 reg32; - pci_devfn_t dev = PCI_DEV(bus, slot, func); - - val = pci_read_config32(dev, PCI_VENDOR_ID); - - if (val == 0xffffffff || val == 0x00000000 || - val == 0x0000ffff || val == 0xffff0000) - continue; - - /* Disable Bus Mastering for this one device */ - reg32 = pci_read_config32(dev, PCI_COMMAND); - reg32 &= ~PCI_COMMAND_MASTER; - pci_write_config32(dev, PCI_COMMAND, reg32); - - /* If this is a bridge, then follow it. */ - hdr = pci_read_config8(dev, PCI_HEADER_TYPE); - hdr &= 0x7f; - if (hdr == PCI_HEADER_TYPE_BRIDGE || - hdr == PCI_HEADER_TYPE_CARDBUS) { - unsigned int buses; - buses = pci_read_config32(dev, PCI_PRIMARY_BUS); - busmaster_disable_on_bus((buses >> 8) & 0xff); - } - } - } -} - - -static void southbridge_smi_sleep(unsigned int node, smm_state_save_area_t *state_save) -{ - u8 reg8; - u32 reg32; - u8 slp_typ; - u8 s5pwr = CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL; - - // save and recover RTC port values - u8 tmp70, tmp72; - tmp70 = inb(0x70); - tmp72 = inb(0x72); - get_option(&s5pwr, "power_on_after_fail"); - outb(tmp70, 0x70); - outb(tmp72, 0x72); - - /* First, disable further SMIs */ - reg8 = inb(pmbase + SMI_EN); - reg8 &= ~SLP_SMI_EN; - outb(reg8, pmbase + SMI_EN); - - /* Figure out SLP_TYP */ - reg32 = inl(pmbase + PM1_CNT); - printk(BIOS_SPEW, "SMI#: SLP = 0x%08x\n", reg32); - slp_typ = acpi_sleep_from_pm1(reg32); - - /* Next, do the deed. - */ - - switch (slp_typ) { - case ACPI_S0: - printk(BIOS_DEBUG, "SMI#: Entering S0 (On)\n"); break; - case ACPI_S1: - printk(BIOS_DEBUG, "SMI#: Entering S1 (Assert STPCLK#)\n"); break; - case ACPI_S3: - printk(BIOS_DEBUG, "SMI#: Entering S3 (Suspend-To-RAM)\n"); - /* Invalidate the cache before going to S3 */ - wbinvd(); - break; - case ACPI_S4: - printk(BIOS_DEBUG, "SMI#: Entering S4 (Suspend-To-Disk)\n"); break; - case ACPI_S5: - printk(BIOS_DEBUG, "SMI#: Entering S5 (Soft Power off)\n"); - - outl(0, pmbase + GPE0_EN); - - /* Always set the flag in case CMOS was changed on runtime. For - * "KEEP", switch to "OFF" - KEEP is software emulated - */ - reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3); - if (s5pwr == MAINBOARD_POWER_ON) - reg8 &= ~1; - else - reg8 |= 1; - pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8); - - /* also iterates over all bridges on bus 0 */ - busmaster_disable_on_bus(0); - break; - default: - printk(BIOS_DEBUG, "SMI#: ERROR: SLP_TYP reserved\n"); break; - } - -#if !IS_ENABLED(CONFIG_SMM_TSEG) - /* Unlock the SMI semaphore. We're currently in SMM, and the semaphore - * will never be unlocked because the next outl will switch off the CPU. - * This might open a small race between the smi_release_lock() and the outl() - * for other SMI handlers. Not sure if this could cause trouble. */ - if (slp_typ == ACPI_S3) - smi_release_lock(); -#endif - - /* Write back to the SLP register to cause the originally intended - * event again. We need to set BIT13 (SLP_EN) though to make the - * sleep happen. - */ - outl(reg32 | SLP_EN, pmbase + PM1_CNT); - - /* Make sure to stop executing code here for S3/S4/S5 */ - if (slp_typ >= ACPI_S3) - halt(); - /* In most sleep states, the code flow of this function ends at - * the line above. However, if we entered sleep state S1 and wake - * up again, we will continue to execute code in this function. - */ - reg32 = inl(pmbase + PM1_CNT); - if (reg32 & SCI_EN) { - /* The OS is not an ACPI OS, so we set the state to S0 */ - reg32 &= ~(SLP_EN | SLP_TYP); - outl(reg32, pmbase + PM1_CNT); - } -} - -static void southbridge_smi_apmc(unsigned int node, smm_state_save_area_t *state_save) -{ - u32 pmctrl; - u8 reg8; - - /* Emulate B2 register as the FADT / Linux expects it */ - - reg8 = inb(APM_CNT); - if (mainboard_smi_apmc(reg8)) - return; - - switch (reg8) { - case APM_CNT_CST_CONTROL: - /* Calling this function seems to cause - * some kind of race condition in Linux - * and causes a kernel oops - */ - printk(BIOS_DEBUG, "C-state control\n"); - break; - case APM_CNT_PST_CONTROL: - /* Calling this function seems to cause - * some kind of race condition in Linux - * and causes a kernel oops - */ - printk(BIOS_DEBUG, "P-state control\n"); - break; - case APM_CNT_ACPI_DISABLE: - pmctrl = inl(pmbase + PM1_CNT); - pmctrl &= ~SCI_EN; - outl(pmctrl, pmbase + PM1_CNT); - printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n"); - break; - case APM_CNT_ACPI_ENABLE: - pmctrl = inl(pmbase + PM1_CNT); - pmctrl |= SCI_EN; - outl(pmctrl, pmbase + PM1_CNT); - printk(BIOS_DEBUG, "SMI#: ACPI enabled.\n"); - break; - case APM_CNT_GNVS_UPDATE: - if (smm_initialized) { - printk(BIOS_DEBUG, "SMI#: SMM structures already initialized!\n"); - return; - } - gnvs = *(global_nvs_t **)0x500; - smm_initialized = 1; - printk(BIOS_DEBUG, "SMI#: Setting up structures to %p\n", gnvs); - break; - default: - printk(BIOS_DEBUG, "SMI#: Unknown function APM_CNT=%02x\n", reg8); - } -} - -static void southbridge_smi_pm1(unsigned int node, smm_state_save_area_t *state_save) -{ - u16 pm1_sts; - volatile u8 cmos_status; - - pm1_sts = reset_pm1_status(); - dump_pm1_status(pm1_sts); - - /* While OSPM is not active, poweroff immediately - * on a power button event. - */ - if (pm1_sts & PWRBTN_STS) { - // power button pressed - u32 reg32; - reg32 = (7 << 10) | (1 << 13); - outl(reg32, pmbase + PM1_CNT); - } - - if (pm1_sts & RTC_STS) { - /* read RTC status register to disable the interrupt */ - cmos_status = cmos_read(RTC_REG_C); - printk(BIOS_DEBUG, "RTC IRQ status: %02X\n", cmos_status); - } -} - -static void southbridge_smi_gpe0(unsigned int node, smm_state_save_area_t *state_save) -{ - u32 gpe0_sts; - - gpe0_sts = reset_gpe0_status(); - dump_gpe0_status(gpe0_sts); -} - -static void southbridge_smi_gpi(unsigned int node, smm_state_save_area_t *state_save) -{ - u16 reg16; - reg16 = inw(pmbase + ALT_GP_SMI_STS); - outw(reg16, pmbase + ALT_GP_SMI_STS); - - reg16 &= inw(pmbase + ALT_GP_SMI_EN); - - mainboard_smi_gpi(reg16); - - if (reg16) - printk(BIOS_DEBUG, "GPI (mask %04x)\n", reg16); -} - -static void southbridge_smi_mc(unsigned int node, smm_state_save_area_t *state_save) -{ - u32 reg32; - - reg32 = inl(pmbase + SMI_EN); - - /* Are periodic SMIs enabled? */ - if ((reg32 & MCSMI_EN) == 0) - return; - - printk(BIOS_DEBUG, "Microcontroller SMI.\n"); -} - - - -static void southbridge_smi_tco(unsigned int node, smm_state_save_area_t *state_save) -{ - u32 tco_sts; - - tco_sts = reset_tco_status(); - - /* Any TCO event? */ - if (!tco_sts) - return; - - if (tco_sts & (1 << 8)) { - /* BIOSWR */ - u8 bios_cntl; - - bios_cntl = pci_read_config16(PCI_DEV(0, 0x1f, 0), 0xdc); - - if (bios_cntl & 1) { - /* BWE is RW, so the SMI was caused by a - * write to BWE, not by a write to the BIOS - */ - - /* This is the place where we notice someone - * is trying to tinker with the BIOS. We are - * trying to be nice and just ignore it. A more - * resolute answer would be to power down the - * box. - */ - printk(BIOS_DEBUG, "Switching back to RO\n"); - pci_write_config32(PCI_DEV(0, 0x1f, 0), 0xdc, (bios_cntl & ~1)); - } /* No else for now? */ - } else if (tco_sts & (1 << 3)) { /* TIMEOUT */ - /* Handle TCO timeout */ - printk(BIOS_DEBUG, "TCO Timeout.\n"); - } else if (!tco_sts) { - dump_tco_status(tco_sts); - } -} - -static void southbridge_smi_periodic(unsigned int node, smm_state_save_area_t *state_save) -{ - u32 reg32; - - reg32 = inl(pmbase + SMI_EN); - - /* Are periodic SMIs enabled? */ - if ((reg32 & PERIODIC_EN) == 0) - return; - - printk(BIOS_DEBUG, "Periodic SMI.\n"); -} - -static void southbridge_smi_monitor(unsigned int node, smm_state_save_area_t *state_save) +void southbridge_smi_monitor(void) { #define IOTRAP(x) (trap_sts & (1 << x)) u32 trap_sts, trap_cycle; @@ -654,80 +114,6 @@ static void southbridge_smi_monitor(unsigned int node, smm_state_save_area_t *st #undef IOTRAP } -typedef void (*smi_handler_t)(unsigned int node, - smm_state_save_area_t *state_save); - -smi_handler_t southbridge_smi[32] = { - NULL, // [0] reserved - NULL, // [1] reserved - NULL, // [2] BIOS_STS - NULL, // [3] LEGACY_USB_STS - southbridge_smi_sleep, // [4] SLP_SMI_STS - southbridge_smi_apmc, // [5] APM_STS - NULL, // [6] SWSMI_TMR_STS - NULL, // [7] reserved - southbridge_smi_pm1, // [8] PM1_STS - southbridge_smi_gpe0, // [9] GPE0_STS - southbridge_smi_gpi, // [10] GPI_STS - southbridge_smi_mc, // [11] MCSMI_STS - NULL, // [12] DEVMON_STS - southbridge_smi_tco, // [13] TCO_STS - southbridge_smi_periodic, // [14] PERIODIC_STS - NULL, // [15] SERIRQ_SMI_STS - NULL, // [16] SMBUS_SMI_STS - NULL, // [17] LEGACY_USB2_STS - NULL, // [18] INTEL_USB2_STS - NULL, // [19] reserved - NULL, // [20] PCI_EXP_SMI_STS - southbridge_smi_monitor, // [21] MONITOR_STS - NULL, // [22] reserved - NULL, // [23] reserved - NULL, // [24] reserved - NULL, // [25] EL_SMI_STS - NULL, // [26] SPI_STS - NULL, // [27] reserved - NULL, // [28] reserved - NULL, // [29] reserved - NULL, // [30] reserved - NULL // [31] reserved -}; - -/** - * @brief Interrupt handler for SMI# - * @param node - * @param state_save - */ - -void southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save) +void southbridge_finalize_all(void) { - int i, dump = 0; - u32 smi_sts; - - /* Update global variable pmbase */ - pmbase = pci_read_config16(PCI_DEV(0, 0x1f, 0), 0x40) & 0xfffc; - - /* We need to clear the SMI status registers, or we won't see what's - * happening in the following calls. - */ - smi_sts = reset_smi_status(); - - /* Filter all non-enabled SMI events */ - // FIXME Double check, this clears MONITOR - // smi_sts &= inl(pmbase + SMI_EN); - - /* Call SMI sub handler for each of the status bits */ - for (i = 0; i < 31; i++) { - if (smi_sts & (1 << i)) { - if (southbridge_smi[i]) - southbridge_smi[i](node, state_save); - else { - printk(BIOS_DEBUG, "SMI_STS[%d] occured, but no " - "handler available.\n", i); - dump = 1; - } - } - } - - if (dump) - dump_smi_status(smi_sts); } |