diff options
Diffstat (limited to 'src/soc/intel/common')
-rw-r--r-- | src/soc/intel/common/block/include/intelblocks/smihandler.h | 11 | ||||
-rw-r--r-- | src/soc/intel/common/block/include/intelblocks/smm.h | 2 | ||||
-rw-r--r-- | src/soc/intel/common/block/smm/smihandler.c | 42 | ||||
-rw-r--r-- | src/soc/intel/common/block/smm/smm.c | 4 |
4 files changed, 53 insertions, 6 deletions
diff --git a/src/soc/intel/common/block/include/intelblocks/smihandler.h b/src/soc/intel/common/block/include/intelblocks/smihandler.h index 5df5552685..f1e3ecf9cb 100644 --- a/src/soc/intel/common/block/include/intelblocks/smihandler.h +++ b/src/soc/intel/common/block/include/intelblocks/smihandler.h @@ -60,6 +60,11 @@ const struct smm_save_state_ops *get_smm_save_state_ops(void); */ extern const smi_handler_t southbridge_smi[32]; +#define SMI_HANDLER_SCI_EN(__bit) (1 << (__bit)) + +/* SMI handlers that should be serviced in SCI mode too. */ +uint32_t smi_handler_get_sci_mask(void); + /* * This function should be implemented in SOC specific code to handle * the SMI event on SLP_EN. The default functionality is provided in @@ -145,6 +150,12 @@ void smihandler_southbridge_espi( int smihandler_disable_busmaster(device_t dev); /* + * SoC needs to implement the mechanism to know if an illegal attempt + * has been made to write to the BIOS area. + */ +void smihandler_check_illegal_access(uint32_t tco_sts); + +/* * Returns gnvs pointer within SMM context */ struct global_nvs_t *smm_get_gnvs(void); diff --git a/src/soc/intel/common/block/include/intelblocks/smm.h b/src/soc/intel/common/block/include/intelblocks/smm.h index 84f34a5a7b..f560f24e2b 100644 --- a/src/soc/intel/common/block/include/intelblocks/smm.h +++ b/src/soc/intel/common/block/include/intelblocks/smm.h @@ -29,7 +29,7 @@ * SMIs. */ void smm_southbridge_clear_state(void); -void smm_southbridge_enable(void); +void smm_southbridge_enable(uint16_t pm1_events); /* API to get SMM region start and size based on Host Bridge register */ void smm_region_info(void **start, size_t *size); diff --git a/src/soc/intel/common/block/smm/smihandler.c b/src/soc/intel/common/block/smm/smihandler.c index 7821dbaddc..9a4ee7cf96 100644 --- a/src/soc/intel/common/block/smm/smihandler.c +++ b/src/soc/intel/common/block/smm/smihandler.c @@ -21,6 +21,7 @@ #include <cpu/x86/smm.h> #include <device/pci_def.h> #include <elog.h> +#include <intelblocks/fast_spi.h> #include <intelblocks/pmclib.h> #include <intelblocks/smihandler.h> #include <intelblocks/uart.h> @@ -35,11 +36,28 @@ /* GNVS needs to be set by coreboot initiating a software SMI. */ static struct global_nvs_t *gnvs; +/* SoC overrides. */ + __attribute__((weak)) int smihandler_disable_busmaster(device_t dev) { return 1; } +/* SMI handlers that should be serviced in SCI mode too. */ +__attribute__((weak)) uint32_t smi_handler_get_sci_mask(void) +{ + return 0; /* No valid SCI mask for SMI handler */ +} + +/* + * Needs to implement the mechanism to know if an illegal attempt + * has been made to write to the BIOS area. + */ +__attribute__((weak)) void smihandler_check_illegal_access(uint32_t tco_sts) +{ + return; +} + static void *find_save_state(const struct smm_save_state_ops *save_state_ops, int cmd) { @@ -175,6 +193,8 @@ void smihandler_southbridge_sleep( /* Disable all GPE */ pmc_disable_all_gpe(); + /* Set which state system will be after power reapplied */ + pmc_soc_restore_power_failure(); /* also iterates over all bridges on bus 0 */ busmaster_disable_on_bus(0); break; @@ -201,8 +221,7 @@ void smihandler_southbridge_sleep( * 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(ACPI_BASE_ADDRESS + PM1_CNT); - if (reg32 & SCI_EN) { + if (pmc_read_pm1_control() & SCI_EN) { /* The OS is not an ACPI OS, so we set the state to S0 */ pmc_disable_pm1_control(SLP_EN | SLP_TYP); } @@ -240,6 +259,9 @@ static void finalize(void) } finalize_done = 1; + if (IS_ENABLED(CONFIG_SPI_FLASH_SMM)) + /* Re-init SPI driver to handle locked BAR */ + fast_spi_init(); } void smihandler_southbridge_apmc( @@ -308,12 +330,13 @@ void smihandler_southbridge_pm1( const struct smm_save_state_ops *save_state_ops) { uint16_t pm1_sts = pmc_clear_pm1_status(); + u16 pm1_en = pmc_read_pm1_enable(); /* * While OSPM is not active, poweroff immediately * on a power button event. */ - if (pm1_sts & PWRBTN_STS) { + if ((pm1_sts & PWRBTN_STS) && (pm1_en & PWRBTN_EN)) { /* power button pressed */ if (IS_ENABLED(CONFIG_ELOG_GSMI)) elog_add_event(ELOG_TYPE_POWER_BUTTON); @@ -337,6 +360,8 @@ void smihandler_southbridge_tco( if (!tco_sts) return; + smihandler_check_illegal_access(tco_sts); + if (tco_sts & TCO_TIMEOUT) { /* TIMEOUT */ /* Handle TCO timeout */ printk(BIOS_DEBUG, "TCO Timeout.\n"); @@ -391,6 +416,17 @@ void southbridge_smi_handler(void) */ smi_sts = pmc_clear_smi_status(); + /* + * In SCI mode, execute only those SMI handlers that have + * declared themselves as available for service in that mode + * using smi_handler_get_sci_mask. + */ + if (pmc_read_pm1_control() & SCI_EN) + smi_sts &= smi_handler_get_sci_mask(); + + if (!smi_sts) + return; + save_state_ops = get_smm_save_state_ops(); /* Call SMI sub handler for each of the status bits */ diff --git a/src/soc/intel/common/block/smm/smm.c b/src/soc/intel/common/block/smm/smm.c index d5f42a76e6..e8c52459a1 100644 --- a/src/soc/intel/common/block/smm/smm.c +++ b/src/soc/intel/common/block/smm/smm.c @@ -38,11 +38,11 @@ void smm_southbridge_clear_state(void) pmc_clear_all_gpe_status(); } -void smm_southbridge_enable(void) +void smm_southbridge_enable(uint16_t pm1_events) { printk(BIOS_DEBUG, "Enabling SMIs.\n"); /* Configure events */ - pmc_enable_pm1(PWRBTN_EN | GBL_EN); + pmc_enable_pm1(pm1_events); pmc_disable_std_gpe(PME_B0_EN); /* |