Brandon Breitenstein has uploaded a new change for review. ( https://review.coreboot.org/19392 )
Change subject: soc/intel/common: [WIP]Add SMI common code for Intel Platforms ......................................................................
soc/intel/common: [WIP]Add SMI common code for Intel Platforms
SMI code is very similar across Intel platforms. Move this code to common/block/smi to allow it to be shared between platforms instead of duplicating the code for each platform. This patch relies on the PMC implemenation for common code.
Change-Id: I599358f23d5de7564ef1ca414bccd54cebab5a4c Signed-off-by: Brandon Breitenstein brandon.breitenstein@intel.com --- M src/soc/intel/common/Makefile.inc A src/soc/intel/common/block/include/intelblocks/smi.h R src/soc/intel/common/block/include/intelblocks/smihandler.h A src/soc/intel/common/block/smi/Kconfig A src/soc/intel/common/block/smi/Makefile.inc A src/soc/intel/common/block/smi/smi.c R src/soc/intel/common/block/smi/smihandler.c 7 files changed, 165 insertions(+), 39 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/92/19392/6
diff --git a/src/soc/intel/common/Makefile.inc b/src/soc/intel/common/Makefile.inc index b01fc8a..1a1cef1 100644 --- a/src/soc/intel/common/Makefile.inc +++ b/src/soc/intel/common/Makefile.inc @@ -35,8 +35,6 @@ ramstage-$(CONFIG_SOC_INTEL_COMMON_ACPI) += ./acpi/acpi.c ramstage-$(CONFIG_SOC_INTEL_COMMON_NHLT) += nhlt.c
-smm-$(CONFIG_SOC_INTEL_COMMON_SMI) += smihandler.c - bootblock-$(CONFIG_MAINBOARD_HAS_TPM_CR50) += tpm_tis.c verstage-$(CONFIG_MAINBOARD_HAS_TPM_CR50) += tpm_tis.c romstage-$(CONFIG_MAINBOARD_HAS_TPM_CR50) += tpm_tis.c diff --git a/src/soc/intel/common/block/include/intelblocks/smi.h b/src/soc/intel/common/block/include/intelblocks/smi.h new file mode 100644 index 0000000..75a6e49 --- /dev/null +++ b/src/soc/intel/common/block/include/intelblocks/smi.h @@ -0,0 +1,33 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 201 Intel Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SOC_INTEL_COMMON_BLOCK_SMI_H +#define SOC_INTEL_COMMON_BLOCK_SMI_H + +#include <soc/gpio.h> + +/* + * The initialization of the southbridge is split into 2 compoments. One is + * for clearing the state in the SMM registers. The other is for enabling + * SMIs. + */ +void smi_southbridge_clear_state(void); +void smi_southbridge_enable(void); + +/* Mainboard handler for GPI SMIs*/ +void smi_mainboard_gpi_handler(const struct gpi_status *sts); + +#endif diff --git a/src/soc/intel/common/smi.h b/src/soc/intel/common/block/include/intelblocks/smihandler.h similarity index 76% rename from src/soc/intel/common/smi.h rename to src/soc/intel/common/block/include/intelblocks/smihandler.h index 22c5104..a119e18 100644 --- a/src/soc/intel/common/smi.h +++ b/src/soc/intel/common/block/include/intelblocks/smihandler.h @@ -13,8 +13,8 @@ * GNU General Public License for more details. */
-#ifndef _INTEL_COMMON_SMI_H_ -#define _INTEL_COMMON_SMI_H_ +#ifndef SOC_INTEL_COMMON_BLOCK_SMI_HANDLER_H +#define SOC_INTEL_COMMON_BLOCK_SMI_HANDLER_H
/* * The register value is used with get_reg and set_reg @@ -59,48 +59,55 @@ * the SMI event on SLP_EN. The default functionality is provided in * soc/intel/common/smihandler.c */ -void southbridge_smi_sleep(const struct smm_save_state_ops *save_state_ops); +void smihandler_southbridge_sleep(const struct smm_save_state_ops *save_state_ops);
/* * This function should be implemented in SOC specific code to handle * SMI_APM event. The default functionality is provided in * soc/intel/common/smihandler.c */ -void southbridge_smi_apmc(const struct smm_save_state_ops *save_state_ops); +void smihandler_southbridge_apmc(const struct smm_save_state_ops *save_state_ops);
/* * This function should be implemented in SOC specific code to handle * SMI_PM1 event. The default functionality is provided in * soc/intel/common/smihandler.c */ -void southbridge_smi_pm1(const struct smm_save_state_ops *save_state_ops); +void smihandler_southbridge_pm1(const struct smm_save_state_ops *save_state_ops);
/* * This function should be implemented in SOC specific code to handle * SMI_GPE0 event. The default functionality is provided in * soc/intel/common/smihandler.c */ -void southbridge_smi_gpe0(const struct smm_save_state_ops *save_state_ops); +void smihandler_southbridge_gpe0(const struct smm_save_state_ops *save_state_ops);
/* * This function should be implemented in SOC specific code to handle * SMI_TCO event. The default functionality is provided in * soc/intel/common/smihandler.c */ -void southbridge_smi_tco(const struct smm_save_state_ops *save_state_ops); +void smihandler_southbridge_tco(const struct smm_save_state_ops *save_state_ops);
/* * This function should be implemented in SOC specific code to handle * SMI PERIODIC_STS event. The default functionality is provided in * soc/intel/common/smihandler.c */ -void southbridge_smi_periodic(const struct smm_save_state_ops *save_state_ops); +void smihandler_southbridge_periodic(const struct smm_save_state_ops *save_state_ops);
/* * This function returns a 1 or 0 depending on whether disable_busmaster * needs to be done for the specified device on S5 entry */ -int smm_disable_busmaster(device_t dev); +int smihandler_disable_busmaster(device_t dev); + +/* + * This function returns the ACPI base address for the platform. This is + * dependent on the specific platform defining this value. 0 is returned + * if the value is not defined by the platform. + */ +uint16_t smihandler_get_acpi_base(void);
/* * Returns gnvs pointer within SMM context diff --git a/src/soc/intel/common/block/smi/Kconfig b/src/soc/intel/common/block/smi/Kconfig new file mode 100644 index 0000000..485986e --- /dev/null +++ b/src/soc/intel/common/block/smi/Kconfig @@ -0,0 +1,5 @@ +config SOC_INTEL_COMMON_BLOCK_SMI + bool + default n + help + Intel Processor common SMI support diff --git a/src/soc/intel/common/block/smi/Makefile.inc b/src/soc/intel/common/block/smi/Makefile.inc new file mode 100644 index 0000000..1737df8 --- /dev/null +++ b/src/soc/intel/common/block/smi/Makefile.inc @@ -0,0 +1,2 @@ +ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SMI) += smi.c +smm-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SMI) += smihandler.c diff --git a/src/soc/intel/common/block/smi/smi.c b/src/soc/intel/common/block/smi/smi.c new file mode 100644 index 0000000..8cf083a --- /dev/null +++ b/src/soc/intel/common/block/smi/smi.c @@ -0,0 +1,69 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * Copyright (C) 2014 Google Inc. + * Copyright (C) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <console/console.h> +#include <cpu/x86/smm.h> +#include <intelblocks/smi.h> +#include <soc/pm.h> + +void smi_southbridge_clear_state(void) +{ + printk(BIOS_DEBUG, "Initializing Southbridge SMI..."); + + if (pmc_get_smi_en() & APMC_EN) { + printk(BIOS_INFO, "SMI# handler already enabled?\n"); + return; + } + + printk(BIOS_DEBUG, "Done\n"); + + /* Dump and clear status registers */ + pmc_clear_smi_status(); + pmc_clear_pm1_status(); + pmc_clear_tco_status(); + pmc_clear_gpe_status(); +} + +void smi_southbridge_enable(void) +{ + printk(BIOS_DEBUG, "Enabling SMIs.\n"); + /* Configure events */ + pmc_enable_pm1(PWRBTN_EN | GBL_EN); + pmc_disable_gpe(PME_B0_EN); + + /* Enable SMI generation: */ + pmc_enable_smi(ENABLE_SMI_PARAMS); +} + +void smm_setup_structures(void *gnvs, void *tcg, void *smi1) +{ + /* + * Issue SMI to set the gnvs pointer in SMM. + * tcg and smi1 are unused. + * + * EAX = APM_CNT_GNVS_UPDATE + * EBX = gnvs pointer + * EDX = APM_CNT + */ + asm volatile ( + "outb %%al, %%dx\n\t" + : /* ignore result */ + : "a" (APM_CNT_GNVS_UPDATE), + "b" ((u32)gnvs), + "d" (APM_CNT) + ); +} diff --git a/src/soc/intel/common/smihandler.c b/src/soc/intel/common/block/smi/smihandler.c similarity index 87% rename from src/soc/intel/common/smihandler.c rename to src/soc/intel/common/block/smi/smihandler.c index 549a914..d7f0cb0 100644 --- a/src/soc/intel/common/smihandler.c +++ b/src/soc/intel/common/block/smi/smihandler.c @@ -21,6 +21,7 @@ #include <cpu/x86/smm.h> #include <device/pci_def.h> #include <elog.h> +#include <intelblocks/smihandler.h> #include <soc/nvs.h> #include <soc/pm.h> #include <soc/gpio.h> @@ -28,14 +29,18 @@ #include <spi-generic.h> #include <stdint.h> #include <stdlib.h> -#include "smi.h"
/* GNVS needs to be set by coreboot initiating a software SMI. */ static struct global_nvs_t *gnvs;
-__attribute__((weak)) int smm_disable_busmaster(device_t dev) +__attribute__((weak)) int smihandler_disable_busmaster(device_t dev) { return 1; +} + +__attribute__((weak)) uint16_t smihandler_get_acpi_base(void) +{ + return 0; }
static void *find_save_state(const struct smm_save_state_ops *save_state_ops, @@ -70,9 +75,10 @@ return state; }
+/* Inherited from cpu/x86/smm.h resulting in a different signature */ void southbridge_smi_set_eos(void) { - enable_smi(EOS); + pmc_enable_smi(EOS); }
struct global_nvs_t *smm_get_gnvs(void) @@ -91,7 +97,7 @@ u32 reg32; device_t dev = PCI_DEV(bus, slot, func);
- if (!smm_disable_busmaster(dev)) + if (!smihandler_disable_busmaster(dev)) continue; val = pci_read_config32(dev, PCI_VENDOR_ID);
@@ -127,15 +133,16 @@ }
-void southbridge_smi_sleep(const struct smm_save_state_ops *save_state_ops) +void smihandler_southbridge_sleep(const struct + smm_save_state_ops * save_state_ops) { uint32_t reg32; uint8_t slp_typ;
/* First, disable further SMIs */ - disable_smi(SLP_SMI_EN); + pmc_disable_smi(SLP_SMI_EN); /* Figure out SLP_TYP */ - reg32 = inl(ACPI_PMIO_BASE + PM1_CNT); + reg32 = inl(smihandler_get_acpi_base() + PM1_CNT); printk(BIOS_SPEW, "SMI#: SLP = 0x%08x\n", reg32); slp_typ = acpi_sleep_from_pm1(reg32);
@@ -147,7 +154,7 @@ elog_add_event_byte(ELOG_TYPE_ACPI_ENTER, slp_typ);
/* Clear pending GPE events */ - clear_gpe_status(); + pmc_clear_gpe_status();
/* Next, do the deed. */
@@ -168,7 +175,7 @@ printk(BIOS_DEBUG, "SMI#: Entering S5 (Soft Power off)\n");
/* Disable all GPE */ - disable_all_gpe(); + pmc_disable_all_gpe(); /* also iterates over all bridges on bus 0 */ busmaster_disable_on_bus(0); break; @@ -178,7 +185,7 @@ }
/* Clear the gpio gpe0 status bits in ACPI registers */ - clear_gpi_gpe_sts(); + pmc_clear_gpi_gpe_sts();
/* Tri-state specific GPIOS to avoid leakage during S3/S5 */
@@ -187,7 +194,7 @@ * event again. We need to set BIT13 (SLP_EN) though to make the * sleep happen. */ - enable_pm1_control(SLP_EN); + pmc_enable_pm1_control(SLP_EN);
/* Make sure to stop executing code here for S3/S4/S5 */ if (slp_typ >= ACPI_S3) @@ -198,15 +205,15 @@ * 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_PMIO_BASE + PM1_CNT); + reg32 = inl(smihandler_get_acpi_base() + PM1_CNT); if (reg32 & SCI_EN) { /* The OS is not an ACPI OS, so we set the state to S0 */ - disable_pm1_control(SLP_EN | SLP_TYP); + pmc_disable_pm1_control(SLP_EN | SLP_TYP); } }
static void southbridge_smi_gsmi(const struct - smm_save_state_ops *save_state_ops) + smm_save_state_ops * save_state_ops) { u8 sub_command, ret; void *io_smi = NULL; @@ -239,7 +246,8 @@
}
-void southbridge_smi_apmc(const struct smm_save_state_ops *save_state_ops) +void smihandler_southbridge_apmc(const struct + smm_save_state_ops * save_state_ops) { uint8_t reg8; void *state = NULL; @@ -266,11 +274,11 @@ printk(BIOS_DEBUG, "P-state control\n"); break; case APM_CNT_ACPI_DISABLE: - disable_pm1_control(SCI_EN); + pmc_disable_pm1_control(SCI_EN); printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n"); break; case APM_CNT_ACPI_ENABLE: - enable_pm1_control(SCI_EN); + pmc_enable_pm1_control(SCI_EN); printk(BIOS_DEBUG, "SMI#: ACPI enabled.\n"); break; case APM_CNT_GNVS_UPDATE: @@ -300,9 +308,10 @@ mainboard_smi_apmc(reg8); }
-void southbridge_smi_pm1(const struct smm_save_state_ops *save_state_ops) +void smihandler_southbridge_pm1(const struct + smm_save_state_ops * save_state_ops) { - uint16_t pm1_sts = clear_pm1_status(); + uint16_t pm1_sts = pmc_clear_pm1_status();
/* * While OSPM is not active, poweroff immediately @@ -312,19 +321,21 @@ /* power button pressed */ if (IS_ENABLED(CONFIG_ELOG_GSMI)) elog_add_event(ELOG_TYPE_POWER_BUTTON); - disable_pm1_control(-1UL); - enable_pm1_control(SLP_EN | (SLP_TYP_S5 << SLP_TYP_SHIFT)); + pmc_disable_pm1_control(-1UL); + pmc_enable_pm1_control(SLP_EN | (SLP_TYP_S5 << SLP_TYP_SHIFT)); } }
-void southbridge_smi_gpe0(const struct smm_save_state_ops *save_state_ops) +void smihandler_southbridge_gpe0(const struct + smm_save_state_ops * save_state_ops) { - clear_gpe_status(); + pmc_clear_gpe_status(); }
-void southbridge_smi_tco(const struct smm_save_state_ops *save_state_ops) +void smihandler_southbridge_tco(const struct + smm_save_state_ops * save_state_ops) { - uint32_t tco_sts = clear_tco_status(); + uint32_t tco_sts = pmc_clear_tco_status();
/* Any TCO event? */ if (!tco_sts) @@ -336,11 +347,12 @@ } }
-void southbridge_smi_periodic(const struct smm_save_state_ops *save_state_ops) +void smihandler_southbridge_periodic(const struct + smm_save_state_ops * save_state_ops) { uint32_t reg32;
- reg32 = get_smi_en(); + reg32 = pmc_get_smi_en();
/* Are periodic SMIs enabled? */ if ((reg32 & PERIODIC_EN) == 0) @@ -358,7 +370,7 @@ * We need to clear the SMI status registers, or we won't see what's * happening in the following calls. */ - smi_sts = clear_smi_status(); + smi_sts = pmc_clear_smi_status();
save_state_ops = get_smm_save_state_ops();