diff --git a/src/soc/intel/apollolake/Kconfig b/src/soc/intel/apollolake/Kconfig index ad7ce18fbb..4643887d05 100644 --- a/src/soc/intel/apollolake/Kconfig +++ b/src/soc/intel/apollolake/Kconfig @@ -22,6 +22,7 @@ config CPU_SPECIFIC_OPTIONS select COLLECT_TIMESTAMPS select COMMON_FADT select HAVE_INTEL_FIRMWARE + select HAVE_SMI_HANDLER select MMCONF_SUPPORT select MMCONF_SUPPORT_DEFAULT select NO_FIXED_XIP_ROM_SIZE @@ -35,7 +36,9 @@ config CPU_SPECIFIC_OPTIONS select POSTCAR_STAGE select REG_SCRIPT select RELOCATABLE_RAMSTAGE # Build fails if this is not selected + select SMM_TSEG select SOC_INTEL_COMMON + select SOC_INTEL_COMMON_SMI select SPI_FLASH select UDELAY_TSC select TSC_CONSTANT_RATE diff --git a/src/soc/intel/apollolake/Makefile.inc b/src/soc/intel/apollolake/Makefile.inc index 607ad136e0..80617a7720 100644 --- a/src/soc/intel/apollolake/Makefile.inc +++ b/src/soc/intel/apollolake/Makefile.inc @@ -15,11 +15,9 @@ bootblock-y += car.c bootblock-y += gpio.c bootblock-y += lpc_lib.c bootblock-y += mmap_boot.c -bootblock-y += placeholders.c bootblock-y += tsc_freq.c bootblock-$(CONFIG_SOC_UART_DEBUG) += uart_early.c -romstage-y += placeholders.c romstage-y += car.c romstage-$(CONFIG_PLATFORM_USES_FSP2_0) += romstage.c romstage-y += gpio.c @@ -31,13 +29,12 @@ romstage-y += mmap_boot.c romstage-y += tsc_freq.c romstage-y += pmutil.c -smm-y += placeholders.c smm-y += pmutil.c +smm-y += smihandler.c ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c ramstage-y += cpu.c ramstage-y += chip.c -ramstage-y += placeholders.c ramstage-y += gpio.c ramstage-y += graphics.c ramstage-$(CONFIG_SOC_UART_DEBUG) += uart_early.c @@ -51,6 +48,7 @@ ramstage-y += spi.c ramstage-y += tsc_freq.c ramstage-y += pmutil.c ramstage-y += pmc.c +ramstage-y += smi.c postcar-y += exit_car.S postcar-y += memmap.c diff --git a/src/soc/intel/apollolake/cpu.c b/src/soc/intel/apollolake/cpu.c index 99cb5adb89..4f74def886 100644 --- a/src/soc/intel/apollolake/cpu.c +++ b/src/soc/intel/apollolake/cpu.c @@ -25,6 +25,7 @@ #include #include #include +#include static struct device_operations cpu_dev_ops = { .init = DEVICE_NOOP, @@ -41,6 +42,18 @@ static const struct cpu_driver driver __cpu_driver = { .id_table = cpu_table, }; + +/* + * MP and SMM loading initialization. + */ +struct smm_relocation_attrs { + uint32_t smbase; + uint32_t smrr_base; + uint32_t smrr_mask; +}; + +static struct smm_relocation_attrs relo_attrs; + static void read_cpu_topology(unsigned int *num_phys, unsigned int *num_virt) { msr_t msr; @@ -75,6 +88,42 @@ static int get_cpu_count(void) return num_virt_cores; } +static void get_smm_info(uintptr_t *perm_smbase, size_t *perm_smsize, + size_t *smm_save_state_size) +{ + void *smm_base; + size_t smm_size; + + /* All range registers are aligned to 4KiB */ + const uint32_t rmask = ~((1 << 12) - 1); + + /* Initialize global tracking state. */ + smm_region(&smm_base, &smm_size); + relo_attrs.smbase = (uint32_t)smm_base; + relo_attrs.smrr_base = relo_attrs.smbase | MTRR_TYPE_WRBACK; + relo_attrs.smrr_mask = ~(smm_size - 1) & rmask; + relo_attrs.smrr_mask |= MTRR_PHYS_MASK_VALID; + + *perm_smbase = relo_attrs.smbase; + *perm_smsize = smm_size - CONFIG_SMM_RESERVED_SIZE; + *smm_save_state_size = sizeof(em64t100_smm_state_save_area_t); +} + +static void relocation_handler(int cpu, uintptr_t curr_smbase, + uintptr_t staggered_smbase) +{ + msr_t smrr; + em64t100_smm_state_save_area_t *smm_state; + /* Set up SMRR. */ + smrr.lo = relo_attrs.smrr_base; + smrr.hi = 0; + wrmsr(SMRR_PHYS_BASE, smrr); + smrr.lo = relo_attrs.smrr_mask; + smrr.hi = 0; + wrmsr(SMRR_PHYS_MASK, smrr); + smm_state = (void *)(SMM_EM64T100_SAVE_STATE_OFFSET + curr_smbase); + smm_state->smbase = staggered_smbase; +} /* * CPU initialization recipe * @@ -85,6 +134,10 @@ static int get_cpu_count(void) static const struct mp_ops mp_ops = { .pre_mp_init = pre_mp_init, .get_cpu_count = get_cpu_count, + .get_smm_info = get_smm_info, + .pre_mp_smm_init = southbridge_smm_clear_state, + .relocation_handler = relocation_handler, + .post_mp_init = southbridge_smm_enable_smi, }; void apollolake_init_cpus(device_t dev) diff --git a/src/soc/intel/apollolake/include/soc/smm.h b/src/soc/intel/apollolake/include/soc/smm.h new file mode 100644 index 0000000000..07749745d9 --- /dev/null +++ b/src/soc/intel/apollolake/include/soc/smm.h @@ -0,0 +1,38 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * (Written by Lance Zhao for 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_SMM_H_ +#define _SOC_SMM_H_ + +#include + +/* These helpers are for performing SMM relocation. */ +void southbridge_clear_smi_status(void); + +/* + * 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 southbridge_smm_clear_state(void); +void southbridge_smm_enable_smi(void); + + +/* Fills in the arguments for the entire SMM region covered by chipset + * protections. e.g. TSEG. */ +void smm_region(void **start, size_t *size); +#endif diff --git a/src/soc/intel/apollolake/memmap.c b/src/soc/intel/apollolake/memmap.c index bf172cba6e..e57ed53d74 100644 --- a/src/soc/intel/apollolake/memmap.c +++ b/src/soc/intel/apollolake/memmap.c @@ -20,13 +20,27 @@ #include #include #include +#include static uintptr_t smm_region_start(void) { return ALIGN_DOWN(pci_read_config32(NB_DEV_ROOT, TSEG), 1*MiB); } +static size_t smm_region_size(void) +{ + uintptr_t smm_end = + ALIGN_DOWN(pci_read_config32(NB_DEV_ROOT, BGSM), 1*MiB); + return smm_end - smm_region_start(); +} + void *cbmem_top(void) { return (void *)smm_region_start(); } + +void smm_region(void **start, size_t *size) +{ + *start = (void *)smm_region_start(); + *size = smm_region_size(); +} diff --git a/src/soc/intel/apollolake/placeholders.c b/src/soc/intel/apollolake/placeholders.c deleted file mode 100644 index 1c3b581172..0000000000 --- a/src/soc/intel/apollolake/placeholders.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * 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. - */ - -#include -#include -#include -#include - -void southbridge_smi_set_eos(void) -{ -} diff --git a/src/soc/intel/apollolake/smi.c b/src/soc/intel/apollolake/smi.c new file mode 100644 index 0000000000..29bab55a12 --- /dev/null +++ b/src/soc/intel/apollolake/smi.c @@ -0,0 +1,88 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * (Written by Lance Zhao for 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void southbridge_smm_clear_state(void) +{ + printk(BIOS_DEBUG, "Initializing Southbridge SMI..."); + + if (get_smi_en() & APMC_EN) { + printk(BIOS_INFO, "SMI# handler already enabled?\n"); + return; + } + + printk(BIOS_DEBUG, "Done\n"); + + /* Dump and clear status registers */ + clear_smi_status(); + clear_pm1_status(); + clear_tco_status(); + clear_gpe_status(); +} + +void southbridge_smm_enable_smi(void) +{ + printk(BIOS_DEBUG, "Enabling SMIs.\n"); + /* Configure events */ + enable_pm1(PWRBTN_EN | GBL_EN); + disable_gpe(PME_B0_EN); + + /* Enable SMI generation */ + enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS); +} + +void southbridge_clear_smi_status(void) +{ + /* Clear SMI status */ + clear_smi_status(); + + /* Clear PM1 status */ + clear_pm1_status(); + + /* Set EOS bit so other SMIs can occur. */ + enable_smi(EOS); +} + +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/apollolake/smihandler.c b/src/soc/intel/apollolake/smihandler.c new file mode 100644 index 0000000000..580fd71d1f --- /dev/null +++ b/src/soc/intel/apollolake/smihandler.c @@ -0,0 +1,79 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2015-2016 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; 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int smm_disable_busmaster(device_t dev) +{ + if (dev == PMC_DEV) + return 0; + return 1; +} + +const struct smm_save_state_ops *get_smm_save_state_ops(void) +{ + return &em64t100_smm_ops; +} + +const 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 */ + NULL, /* [10] reserved */ + NULL, /* [11] reserved */ + NULL, /* [12] reserved */ + 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 */ + NULL, /* [21] reserved */ + NULL, /* [22] reserved */ + NULL, /* [23] reserved */ + NULL, /* [24] reserved */ + NULL, /* [25] reserved */ + NULL, /* [26] SPI_STS */ + NULL, /* [27] reserved */ + NULL, /* [28] PUNIT */ + NULL, /* [29] GUNIT */ + NULL, /* [30] reserved */ + NULL /* [31] reserved */ +};