diff --git a/src/soc/intel/apollolake/Kconfig b/src/soc/intel/apollolake/Kconfig index 8d9f56293a..23e514901b 100644 --- a/src/soc/intel/apollolake/Kconfig +++ b/src/soc/intel/apollolake/Kconfig @@ -68,7 +68,7 @@ config CPU_SPECIFIC_OPTIONS select SOC_INTEL_COMMON_BLOCK_UART select SOC_INTEL_COMMON_BLOCK_XDCI select SOC_INTEL_COMMON_BLOCK_XHCI - select SOC_INTEL_COMMON_SMI + select SOC_INTEL_COMMON_BLOCK_SMM select SOC_INTEL_COMMON_SPI_FLASH_PROTECT select UDELAY_TSC select TSC_CONSTANT_RATE diff --git a/src/soc/intel/apollolake/Makefile.inc b/src/soc/intel/apollolake/Makefile.inc index 619713876e..fe55ae9b5e 100644 --- a/src/soc/intel/apollolake/Makefile.inc +++ b/src/soc/intel/apollolake/Makefile.inc @@ -65,7 +65,6 @@ ramstage-y += spi.c ramstage-y += pmutil.c ramstage-y += pmc.c ramstage-y += reset.c -ramstage-y += smi.c ramstage-y += sram.c ramstage-y += spi.c ramstage-y += xdci.c diff --git a/src/soc/intel/apollolake/cpu.c b/src/soc/intel/apollolake/cpu.c index 43f9b8381f..caf749f25f 100644 --- a/src/soc/intel/apollolake/cpu.c +++ b/src/soc/intel/apollolake/cpu.c @@ -25,14 +25,15 @@ #include #include #include +#include #include #include #include +#include #include #include #include #include -#include #include static const struct reg_script core_msr_script[] = { @@ -189,9 +190,9 @@ static const struct mp_ops mp_ops = { .get_cpu_count = get_cpu_count, .get_smm_info = get_smm_info, .get_microcode_info = get_microcode_info, - .pre_mp_smm_init = southbridge_smm_clear_state, + .pre_mp_smm_init = smm_southbridge_clear_state, .relocation_handler = relocation_handler, - .post_mp_init = southbridge_smm_enable_smi, + .post_mp_init = smm_southbridge_enable, }; void apollolake_init_cpus(struct device *dev) diff --git a/src/soc/intel/apollolake/include/soc/pm.h b/src/soc/intel/apollolake/include/soc/pm.h index 7db63f6bdc..6c189198ab 100644 --- a/src/soc/intel/apollolake/include/soc/pm.h +++ b/src/soc/intel/apollolake/include/soc/pm.h @@ -82,6 +82,20 @@ #define EOS (1 << SMI_EOS) /* End of SMI (deassert SMI#) */ #define GBL_SMI_EN (1 << SMI_GBL) /* Global SMI Enable */ +/* SMI_EN Params for this platform to pass to enable_smi + * + * Enable SMI generation: + * - on APMC writes (io 0xb2) + * - on writes to SLP_EN (sleep states) + * - on writes to GBL_RLS (bios commands) + * - on eSPI events (does nothing on LPC systems) + * No SMIs: + * - on microcontroller writes (io 0x62/0x66) + * - on TCO events + */ +#define ENABLE_SMI_PARAMS \ + (APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS | GPIO_EN) + #define SMI_STS 0x44 /* Bits for SMI status */ #define PMC_OCP_SMI_STS 27 diff --git a/src/soc/intel/apollolake/memmap.c b/src/soc/intel/apollolake/memmap.c index 0f85b10aab..c54423c944 100644 --- a/src/soc/intel/apollolake/memmap.c +++ b/src/soc/intel/apollolake/memmap.c @@ -27,9 +27,9 @@ #include #include #include +#include #include #include -#include static uintptr_t smm_region_start(void) { diff --git a/src/soc/intel/apollolake/smihandler.c b/src/soc/intel/apollolake/smihandler.c index 0272a5c3c2..f834b1da70 100644 --- a/src/soc/intel/apollolake/smihandler.c +++ b/src/soc/intel/apollolake/smihandler.c @@ -14,25 +14,15 @@ * GNU General Public License for more details. */ -#include #include -#include -#include #include -#include -#include -#include -#include +#include #include #include #include -#include -#include -#include -#include -#include +#include -int smm_disable_busmaster(device_t dev) +int smihandler_disable_busmaster(device_t dev) { if (dev == PCH_DEV_PMC) return 0; @@ -47,7 +37,8 @@ const struct smm_save_state_ops *get_smm_save_state_ops(void) void __attribute__((weak)) mainboard_smi_gpi_handler(const struct gpi_status *sts) { } -static void southbridge_smi_gpi(const struct smm_save_state_ops *save_state_ops) +static void southbridge_smi_gpi( + const struct smm_save_state_ops *save_state_ops) { struct gpi_status smi_sts; @@ -59,10 +50,10 @@ static void southbridge_smi_gpi(const struct smm_save_state_ops *save_state_ops) } const smi_handler_t southbridge_smi[32] = { - [SLP_SMI_STS] = southbridge_smi_sleep, - [APM_SMI_STS] = southbridge_smi_apmc, - [FAKE_PM1_SMI_STS] = southbridge_smi_pm1, + [SLP_SMI_STS] = smihandler_southbridge_sleep, + [APM_SMI_STS] = smihandler_southbridge_apmc, + [FAKE_PM1_SMI_STS] = smihandler_southbridge_pm1, [GPIO_SMI_STS] = southbridge_smi_gpi, - [TCO_SMI_STS] = southbridge_smi_tco, - [PERIODIC_SMI_STS] = southbridge_smi_periodic, + [TCO_SMI_STS] = smihandler_southbridge_tco, + [PERIODIC_SMI_STS] = smihandler_southbridge_periodic, }; diff --git a/src/soc/intel/common/Makefile.inc b/src/soc/intel/common/Makefile.inc index 340e001d2d..110977585d 100644 --- a/src/soc/intel/common/Makefile.inc +++ b/src/soc/intel/common/Makefile.inc @@ -31,8 +31,6 @@ ramstage-$(CONFIG_SOC_INTEL_COMMON_GFX_OPREGION) += opregion.c 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/smi.h b/src/soc/intel/common/block/include/intelblocks/smihandler.h similarity index 69% rename from src/soc/intel/common/smi.h rename to src/soc/intel/common/block/include/intelblocks/smihandler.h index 22c510435b..b587bb136d 100644 --- a/src/soc/intel/common/smi.h +++ b/src/soc/intel/common/block/include/intelblocks/smihandler.h @@ -13,8 +13,13 @@ * 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 + +#include + +struct gpi_status; +struct global_nvs_t; /* * The register value is used with get_reg and set_reg @@ -26,8 +31,7 @@ enum smm_reg { RDX, }; - -struct smm_save_state_ops { +struct smm_save_state_ops { /* return io_misc_info from SMM Save State Area */ uint32_t (*get_io_misc_info)(void *state); @@ -50,63 +54,72 @@ const struct smm_save_state_ops *get_smm_save_state_ops(void); /* * southbridge_smi should be defined inside SOC specific code and should have * handlers for any SMI events that need to be handled. Default handlers - * for some SMI events are provided in soc/intel/common/smihandler.c + * for some SMI events are provided in soc/intel/common/block/smm/smihandler.c */ extern const smi_handler_t southbridge_smi[32]; /* * This function should be implemented in SOC specific code to handle * the SMI event on SLP_EN. The default functionality is provided in - * soc/intel/common/smihandler.c + * soc/intel/common/block/smm/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 + * soc/intel/common/block/smm/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 + * soc/intel/common/block/smm/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 + * soc/intel/common/block/smm/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 + * soc/intel/common/block/smm/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 + * soc/intel/common/block/smm/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); /* * Returns gnvs pointer within SMM context */ struct global_nvs_t *smm_get_gnvs(void); +/* Mainboard handler for GPI SMIs */ +void mainboard_smi_gpi_handler(const struct gpi_status *sts); + extern const struct smm_save_state_ops em64t100_smm_ops; extern const struct smm_save_state_ops em64t101_smm_ops; diff --git a/src/soc/intel/common/block/include/intelblocks/smm.h b/src/soc/intel/common/block/include/intelblocks/smm.h new file mode 100644 index 0000000000..09378b9463 --- /dev/null +++ b/src/soc/intel/common/block/include/intelblocks/smm.h @@ -0,0 +1,34 @@ +/* + * 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_SMM_H +#define SOC_INTEL_COMMON_BLOCK_SMM_H + +/* + * This common code block relies on each specific SOC defining the macro + * ENABLE_SMI_PARAMS for the values needed for SMI enabling on the + * specific SOC + */ + +/* + * 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 smm_southbridge_clear_state(void); +void smm_southbridge_enable(void); + +#endif diff --git a/src/soc/intel/common/block/smm/Kconfig b/src/soc/intel/common/block/smm/Kconfig new file mode 100644 index 0000000000..003fc24cd8 --- /dev/null +++ b/src/soc/intel/common/block/smm/Kconfig @@ -0,0 +1,4 @@ +config SOC_INTEL_COMMON_BLOCK_SMM + bool + help + Intel Processor common SMM support diff --git a/src/soc/intel/common/block/smm/Makefile.inc b/src/soc/intel/common/block/smm/Makefile.inc new file mode 100644 index 0000000000..13793ee891 --- /dev/null +++ b/src/soc/intel/common/block/smm/Makefile.inc @@ -0,0 +1,2 @@ +ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SMM) += smm.c +smm-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SMM) += smihandler.c diff --git a/src/soc/intel/common/smihandler.c b/src/soc/intel/common/block/smm/smihandler.c similarity index 92% rename from src/soc/intel/common/smihandler.c rename to src/soc/intel/common/block/smm/smihandler.c index 88ea819012..b620ff9f1e 100644 --- a/src/soc/intel/common/smihandler.c +++ b/src/soc/intel/common/block/smm/smihandler.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -28,18 +29,17 @@ #include #include #include -#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; } static void *find_save_state(const struct smm_save_state_ops *save_state_ops, - int cmd) + int cmd) { int node; void *state = NULL; @@ -70,6 +70,7 @@ static void *find_save_state(const struct smm_save_state_ops *save_state_ops, return state; } +/* Inherited from cpu/x86/smm.h resulting in a different signature */ void southbridge_smi_set_eos(void) { enable_smi(EOS); @@ -91,7 +92,7 @@ static void busmaster_disable_on_bus(int bus) 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,7 +128,8 @@ static void busmaster_disable_on_bus(int bus) } -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; @@ -205,8 +207,8 @@ void southbridge_smi_sleep(const struct smm_save_state_ops *save_state_ops) } } -static void southbridge_smi_gsmi(const struct - smm_save_state_ops *save_state_ops) +static void southbridge_smi_gsmi( + const struct smm_save_state_ops *save_state_ops) { u8 sub_command, ret; void *io_smi = NULL; @@ -239,7 +241,8 @@ static void finalize(void) } -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; @@ -300,7 +303,8 @@ void southbridge_smi_apmc(const struct smm_save_state_ops *save_state_ops) 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(); @@ -317,12 +321,14 @@ void southbridge_smi_pm1(const struct smm_save_state_ops *save_state_ops) } } -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(); } -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(); @@ -336,7 +342,8 @@ void southbridge_smi_tco(const struct smm_save_state_ops *save_state_ops) } } -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; diff --git a/src/soc/intel/common/block/smm/smm.c b/src/soc/intel/common/block/smm/smm.c new file mode 100644 index 0000000000..ab60af615d --- /dev/null +++ b/src/soc/intel/common/block/smm/smm.c @@ -0,0 +1,78 @@ +/* + * 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 +#include +#include +#include + +void smm_southbridge_clear_state(void) +{ + printk(BIOS_DEBUG, "Clearing SMI status registers\n"); + + if (get_smi_en() & APMC_EN) { + printk(BIOS_INFO, "SMI# handler already enabled?\n"); + return; + } + + /* Dump and clear status registers */ + clear_smi_status(); + clear_pm1_status(); + clear_tco_status(); + clear_gpe_status(); +} + +void smm_southbridge_enable(void) +{ + printk(BIOS_DEBUG, "Enabling SMIs.\n"); + /* Configure events */ + enable_pm1(PWRBTN_EN | GBL_EN); + disable_gpe(PME_B0_EN); + + /* + * Enable SMI generation: + * - on APMC writes (io 0xb2) + * - on writes to SLP_EN (sleep states) + * - on writes to GBL_RLS (bios commands) + * - on eSPI events (does nothing on LPC systems) + * No SMIs: + * - on microcontroller writes (io 0x62/0x66) + * - on TCO events + */ + + /* Enable SMI generation: */ + 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) + ); +}