summaryrefslogtreecommitdiff
path: root/src/southbridge/intel/i82801jx/smihandler.c
diff options
context:
space:
mode:
authorArthur Heymans <arthur@aheymans.xyz>2018-04-10 13:18:19 +0200
committerArthur Heymans <arthur@aheymans.xyz>2018-12-03 10:16:31 +0000
commit6af3e6f4ff2ff727fec3034ef64c6dd604d44c9c (patch)
treeb7608d73d142b141892ad7c24c60f234fb2be0e3 /src/southbridge/intel/i82801jx/smihandler.c
parent009518e79b9b3a7d756243dd6ca1b6789de1430a (diff)
downloadcoreboot-6af3e6f4ff2ff727fec3034ef64c6dd604d44c9c.tar.xz
sb/intel/i82801jx: 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. The platform (x4x) using this southbridge will adapt the CONFIG_SMM_TSEG codepath in subsequent patches. Change-Id: Id3b3b3abbb3920d68d77fd7db996a1dc3c6b85a3 Signed-off-by: Arthur Heymans <arthur@aheymans.xyz> Reviewed-on: https://review.coreboot.org/c/25596 Reviewed-by: Nico Huber <nico.h@gmx.de> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/southbridge/intel/i82801jx/smihandler.c')
-rw-r--r--src/southbridge/intel/i82801jx/smihandler.c417
1 files changed, 8 insertions, 409 deletions
diff --git a/src/southbridge/intel/i82801jx/smihandler.c b/src/southbridge/intel/i82801jx/smihandler.c
index f4382d74f1..67b45a1e92 100644
--- a/src/southbridge/intel/i82801jx/smihandler.c
+++ b/src/southbridge/intel/i82801jx/smihandler.c
@@ -22,6 +22,7 @@
#include <cpu/x86/smm.h>
#include <device/pci_def.h>
#include <pc80/mc146818rtc.h>
+#include <southbridge/intel/common/pmutil.h>
#include "i82801jx.h"
#include "nvs.h"
@@ -39,160 +40,6 @@ global_nvs_t *gnvs = (global_nvs_t *)0x0;
void *tcg = (void *)0x0;
void *smi1 = (void *)0x0;
-/**
- * @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 << 27)) printk(BIOS_DEBUG, "GPIO_UNLOCK ");
- if (smi_sts & (1 << 26)) printk(BIOS_DEBUG, "SPI ");
- 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 u64 reset_gpe0_status(void)
-{
- u32 reg_h, reg_l;
-
- reg_l = inl(pmbase + GPE0_STS);
- reg_h = inl(pmbase + GPE0_STS + 4);
- /* set status bits are cleared by writing 1 to them */
- outl(reg_l, pmbase + GPE0_STS);
- outl(reg_h, pmbase + GPE0_STS + 4);
-
- return (((u64)reg_h) << 32) | reg_l;
-}
-
-static void dump_gpe0_status(u64 gpe0_sts)
-{
- int i;
- printk(BIOS_DEBUG, "GPE0_STS: ");
- if (gpe0_sts & (1LL << 32)) printk(BIOS_DEBUG, "USB6 ");
- 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, "USB5 ");
- 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, "SWGPE ");
- if (gpe0_sts & (1 << 1)) 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");
-}
-
int southbridge_io_trap_handler(int smif)
{
switch (smif) {
@@ -210,165 +57,15 @@ int southbridge_io_trap_handler(int smif)
return 0;
}
-/**
- * @brief Set the EOS bit
- */
-void southbridge_smi_set_eos(void)
+void southbridge_update_gnvs(u8 apm_cnt, int *smm_done)
{
- u8 reg8;
-
- reg8 = inb(pmbase + SMI_EN);
- reg8 |= EOS;
- outb(reg8, pmbase + SMI_EN);
+ gnvs = *(global_nvs_t **)0x500;
+ tcg = *(void **)0x504;
+ smi1 = *(void **)0x508;
+ *smm_done = 1;
}
-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;
- tcg = *(void **)0x504;
- smi1 = *(void **)0x508;
- smm_initialized = 1;
- printk(BIOS_DEBUG, "SMI#: Setting up structures to %p, %p, %p\n", gnvs, tcg, smi1);
- 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);
- outl(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_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 {
- dump_tco_status(tco_sts);
- }
-}
-
-#if DEBUG_PERIODIC_SMIS
-static void southbridge_smi_periodic(unsigned int node, smm_state_save_area_t *state_save)
-{
- printk(BIOS_DEBUG, "Periodic SMI.\n");
-}
-#endif
-
-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;
@@ -422,104 +119,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
- NULL, // [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
- NULL, // [11] MCSMI_STS
- NULL, // [12] DEVMON_STS
- southbridge_smi_tco, // [13] TCO_STS
-#if DEBUG_PERIODIC_SMIS
- southbridge_smi_periodic, // [14] PERIODIC_STS
-#else
- NULL, // [14] PERIODIC_STS
-#endif
- 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] reserved
- NULL, // [26] SPI_STS
- NULL, // [27] reserved
- NULL, // [28] reserved
- NULL, // [29] reserved
- NULL, // [30] reserved
- NULL // [31] reserved
-};
-
-static u32 southbrigde_smi_mask_events(u32 smi_sts)
-{
- /* Clear all disabled bits in SMI_EN but the reserved ones. */
- smi_sts &= inl(pmbase + SMI_EN) | 0xf7f99700;
-
- /* Check if SCI is enabled. */
- if (inl(pmbase + PM1_CNT) & SCI_EN)
- /* Clear PM1, GPE. */
- smi_sts &= ~((1 << 8) | (1 << 9));
-
- /* Check if SPI generates SMI. */
- if (!(RCBA16(0x3806) & (1 << 15)) &&
- !(RCBA16(0x3891) & (1 << 15)))
- /* Clear SPI. */
- smi_sts &= ~(1 << 26);
-
- return smi_sts;
-}
-
-/**
- * @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), D31F0_PMBASE) & 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 */
- smi_sts = southbrigde_smi_mask_events(smi_sts);
-
- /* 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] occurred, but no "
- "handler available.\n", i);
- dump = 1;
- }
- }
- }
-
- if (dump) {
- dump_smi_status(smi_sts);
- }
-
}