[coreboot-gerrit] Patch set updated for coreboot: 70f567a baytrail: SMM support

Aaron Durbin (adurbin@google.com) gerrit at coreboot.org
Tue Jan 28 05:29:15 CET 2014


Aaron Durbin (adurbin at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4892

-gerrit

commit 70f567ada818f52eeef5ec75de180e134789380c
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Mon Oct 21 22:32:00 2013 -0500

    baytrail: SMM support
    
    Initialize SMM on all CPUs by relocating the SMM region
    and setting SMRR on all the cores. Additionally SMI
    is enabled in the south cluster.
    
    BUG=chrome-os-partner:22862
    BRANCH=None
    TEST=Built and booted rambi. Tested with DEBUG_SMI and noted
         power button turns off board while in firmware.
    
    Change-Id: I92e3460572feeb67d4a3d4d26af5f0ecaf7d3dd5
    Signed-off-by: Aaron Durbin <adurbin at chromium.org>
    Reviewed-on: https://chromium-review.googlesource.com/173983
---
 src/soc/intel/baytrail/Makefile.inc        |   7 +
 src/soc/intel/baytrail/baytrail/pmc.h      | 118 +++++++++
 src/soc/intel/baytrail/baytrail/smm.h      |  41 +++
 src/soc/intel/baytrail/cpu.c               | 166 +++++++++++-
 src/soc/intel/baytrail/memmap.c            |   8 +-
 src/soc/intel/baytrail/placeholders.c      |   2 -
 src/soc/intel/baytrail/pmutil.c            | 297 +++++++++++++++++++++
 src/soc/intel/baytrail/romstage/romstage.c |   5 +-
 src/soc/intel/baytrail/smihandler.c        | 399 +++++++++++++++++++++++++++++
 src/soc/intel/baytrail/smm.c               |  91 +++++++
 src/soc/intel/baytrail/tsc_freq.c          |  14 +-
 11 files changed, 1135 insertions(+), 13 deletions(-)

diff --git a/src/soc/intel/baytrail/Makefile.inc b/src/soc/intel/baytrail/Makefile.inc
index fc6414c..9711549 100644
--- a/src/soc/intel/baytrail/Makefile.inc
+++ b/src/soc/intel/baytrail/Makefile.inc
@@ -3,6 +3,7 @@ subdirs-y += microcode
 subdirs-y += romstage
 subdirs-y += ../../../cpu/x86/lapic
 subdirs-y += ../../../cpu/x86/mtrr
+subdirs-y += ../../../cpu/x86/smm
 subdirs-y += ../../../cpu/x86/tsc
 subdirs-y += ../../../cpu/intel/microcode
 
@@ -10,10 +11,12 @@ ramstage-y += memmap.c
 romstage-y += memmap.c
 ramstage-y += tsc_freq.c
 romstage-y += tsc_freq.c
+smm-y += tsc_freq.c
 ramstage-$(CONFIG_CACHE_MRC_SETTINGS) += nvm.c
 ramstage-$(CONFIG_CACHE_MRC_SETTINGS) += mrc_cache.c
 romstage-$(CONFIG_CACHE_MRC_SETTINGS) += mrc_cache.c
 ramstage-y += spi.c
+smm-y += spi.c
 ramstage-y += chip.c
 ramstage-y += iosf.c
 romstage-y += iosf.c
@@ -23,6 +26,10 @@ ramstage-y += gpio.c
 romstage-y += reset.c
 ramstage-y += reset.c
 ramstage-y += cpu.c
+ramstage-y += pmutil.c
+smm-y += pmutil.c
+smm-y += smihandler.c
+ramstage-y += smm.c
 
 # Remove as ramstage gets fleshed out
 ramstage-y += placeholders.c
diff --git a/src/soc/intel/baytrail/baytrail/pmc.h b/src/soc/intel/baytrail/baytrail/pmc.h
index b85800a..e0e5cff 100644
--- a/src/soc/intel/baytrail/baytrail/pmc.h
+++ b/src/soc/intel/baytrail/baytrail/pmc.h
@@ -25,6 +25,7 @@
 
 /* Memory mapped IO registers behind PMC_BASE_ADDRESS */
 #define GEN_PMCONF1	0x20
+#	define AFTERG3_EN	(1 <<  0)
 #	define UART_EN		(1 << 24)
 #define ETR			0x48
 #	define CF9LOCK		(1 << 31)
@@ -34,6 +35,105 @@
 #	define CWORWRE		(1 << 18)
 
 /* IO Mapped registers behind ACPI_BASE_ADDRESS */
+#define PM1_STS			0x00
+#define   WAK_STS	(1 << 15)
+#define   PCIEXPWAK_STS	(1 << 14)
+#define   USB_STS	(1 << 13)
+#define   PRBTNOR_STS	(1 << 11)
+#define   RTC_STS	(1 << 10)
+#define   PWRBTN_STS	(1 << 8)
+#define   GBL_STS	(1 << 5)
+#define   TMROF_STS	(1 << 0)
+#define PM1_EN			0x02
+#define   PCIEXPWAK_DIS	(1 << 14)
+#define   USB_WAKE_EN	(1 << 13)
+#define   RTC_EN	(1 << 10)
+#define   PWRBTN_EN	(1 << 8)
+#define   GBL_EN	(1 << 5)
+#define   TMROF_EN	(1 << 0)
+#define PM1_CNT			0x04
+#define   SLP_EN	(1 << 13)
+#define   SLP_TYP	(7 << 10)
+#define    SLP_TYP_S0	0
+#define    SLP_TYP_S1	1
+#define    SLP_TYP_S3	5
+#define    SLP_TYP_S4	6
+#define    SLP_TYP_S5	7
+#define   GBL_RLS	(1 << 2)
+#define   BM_RLD	(1 << 1)
+#define   SCI_EN	(1 << 0)
+#define PM1_TMR			0x08
+#define GPE0_STS		0x20
+#define   CORE_GPIO_STS7	(1 << 31)
+#define   CORE_GPIO_STS6	(1 << 30)
+#define   CORE_GPIO_STS5	(1 << 29)
+#define   CORE_GPIO_STS4	(1 << 28)
+#define   CORE_GPIO_STS3	(1 << 27)
+#define   CORE_GPIO_STS2	(1 << 26)
+#define   CORE_GPIO_STS1	(1 << 25)
+#define   CORE_GPIO_STS0	(1 << 24)
+#define   SUS_GPIO_STS7		(1 << 23)
+#define   SUS_GPIO_STS6		(1 << 22)
+#define   SUS_GPIO_STS5		(1 << 21)
+#define   SUS_GPIO_STS4		(1 << 20)
+#define   SUS_GPIO_STS3		(1 << 19)
+#define   SUS_GPIO_STS2		(1 << 18)
+#define   SUS_GPIO_STS1		(1 << 17)
+#define   SUS_GPIO_STS0		(1 << 16)
+#define   PME_B0_STS		(1 << 13)
+#define   BATLOW_STS		(1 << 10)
+#define   PCI_EXP_STS		(1 << 9)
+#define   PCIE_WAKE3_STS	(1 << 8)
+#define   PCIE_WAKE2_STS	(1 << 7)
+#define   PCIE_WAKE1_STS	(1 << 6)
+#define   GUNIT_SCI_STS		(1 << 5)
+#define   PUNIT_SCI_STS		(1 << 4)
+#define   PCIE_WAKE0_STS	(1 << 3)
+#define   SWGPE_STS		(1 << 2)
+#define   HOT_PLUG_STS		(1 << 1)
+#define GPE0_EN			0x28
+#define   CORE_GPIO_EN7	(1 << 31)
+#define   CORE_GPIO_EN6	(1 << 30)
+#define   CORE_GPIO_EN5	(1 << 29)
+#define   CORE_GPIO_EN4	(1 << 28)
+#define   CORE_GPIO_EN3	(1 << 27)
+#define   CORE_GPIO_EN2	(1 << 26)
+#define   CORE_GPIO_EN1	(1 << 25)
+#define   CORE_GPIO_EN0	(1 << 24)
+#define   SUS_GPIO_EN7		(1 << 23)
+#define   SUS_GPIO_EN6		(1 << 22)
+#define   SUS_GPIO_EN5		(1 << 21)
+#define   SUS_GPIO_EN4		(1 << 20)
+#define   SUS_GPIO_EN3		(1 << 19)
+#define   SUS_GPIO_EN2		(1 << 18)
+#define   SUS_GPIO_EN1		(1 << 17)
+#define   SUS_GPIO_EN0		(1 << 16)
+#define   PME_B0_EN		(1 << 13)
+#define   BATLOW_EN		(1 << 10)
+#define   PCI_EXP_EN		(1 << 9)
+#define   PCIE_WAKE3_EN		(1 << 8)
+#define   PCIE_WAKE2_EN		(1 << 7)
+#define   PCIE_WAKE1_EN		(1 << 6)
+#define   PCIE_WAKE0_EN		(1 << 3)
+#define   SWGPE_EN		(1 << 2)
+#define   HOT_PLUG_EN		(1 << 1)
+#define SMI_EN			0x30
+#define   INTEL_USB2_EN	 (1 << 18) // Intel-Specific USB2 SMI logic
+#define   USB_EN	 (1 << 17) // Legacy USB2 SMI logic
+#define   PERIODIC_EN	 (1 << 14) // SMI on PERIODIC_STS in SMI_STS
+#define   TCO_EN	 (1 << 13) // Enable TCO Logic (BIOSWE et al)
+#define   BIOS_RLS	 (1 <<  7) // asserts SCI on bit set
+#define   SWSMI_TMR_EN	 (1 <<  6) // start software smi timer on bit set
+#define   APMC_EN	 (1 <<  5) // Writes to APM_CNT cause SMI#
+#define   SLP_SMI_EN	 (1 <<  4) // Write to SLP_EN in PM1_CNT asserts SMI#
+#define   BIOS_EN	 (1 <<  2) // Assert SMI# on setting GBL_RLS bit
+#define   EOS		 (1 <<  1) // End of SMI (deassert SMI#)
+#define   GBL_SMI_EN	 (1 <<  0) // SMI# generation at all?
+#define SMI_STS			0x34
+#define ALT_GPIO_SMI		0x38
+#define UPRWC			0x3c
+#define GPE_CTRL		0x40
+#define PM2A_CNT_BLK		0x50
 #define TCO_RLD			0x60
 #define TCO_STS			0x64
 #	define SECOND_TO_STS	(1 << 17)
@@ -49,4 +149,22 @@
 #	define RST_CPU		(1 << 2)
 #	define SYS_RST		(1 << 1)
 
+
+/* Power Management Utility Functions. */
+uint16_t get_pmbase(void);
+uint32_t clear_smi_status(void);
+uint16_t clear_pm1_status(void);
+uint32_t clear_tco_status(void);
+uint32_t clear_gpe_status(void);
+void enable_smi(uint32_t mask);
+void disable_smi(uint32_t mask);
+void enable_pm1(uint16_t events);
+void enable_pm1_control(uint32_t mask);
+void disable_pm1_control(uint32_t mask);
+void enable_gpe(uint32_t mask);
+void disable_gpe(uint32_t mask);
+void disable_all_gpe(void);
+
+static inline void southcluster_log_state(void) {}
+
 #endif /* _BAYTRAIL_PMC_H_ */
diff --git a/src/soc/intel/baytrail/baytrail/smm.h b/src/soc/intel/baytrail/baytrail/smm.h
new file mode 100644
index 0000000..19a0695
--- /dev/null
+++ b/src/soc/intel/baytrail/baytrail/smm.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _BAYTRAIL_SMM_H_
+#define _BAYTRAIL_SMM_H_
+
+/* There is a bug in the order of Kconfig includes in that arch/x86/Kconfig
+ * is included after chipset code. This causes the chipset's Kconfig to be
+ * cloberred by the arch/x86/Kconfig if they have the same name. */
+static inline int smm_region_size(void)
+{
+	/* Make it 8MiB by default. */
+	if (CONFIG_SMM_TSEG_SIZE == 0)
+		return (8 << 20);
+	return CONFIG_SMM_TSEG_SIZE;
+}
+
+void *smm_region_start(void);
+
+#if !defined(__PRE_RAM__) && !defined(__SMM___)
+void southcluster_smm_clear_state(void);
+void southcluster_smm_enable_smi(void);
+#endif
+
+#endif /* _BAYTRAIL_SMM_H_ */
diff --git a/src/soc/intel/baytrail/cpu.c b/src/soc/intel/baytrail/cpu.c
index 4217947..c93d253 100644
--- a/src/soc/intel/baytrail/cpu.c
+++ b/src/soc/intel/baytrail/cpu.c
@@ -21,14 +21,27 @@
 #include <console/console.h>
 #include <cpu/cpu.h>
 #include <cpu/intel/microcode.h>
-#include <cpu/x86/mtrr.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/lapic.h>
 #include <cpu/x86/mp.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/smm.h>
 
 #include <baytrail/pattrs.h>
 #include <baytrail/ramstage.h>
+#include <baytrail/smm.h>
+
+static const void *microcode_ptr;
+
+static void smm_relocate(void *unused);
+static void enable_smis(void *unused);
 
 static struct mp_flight_record mp_steps[] = {
+	MP_FR_BLOCK_APS(smm_relocate, NULL, smm_relocate, NULL),
 	MP_FR_BLOCK_APS(mp_initialize_cpu, NULL, mp_initialize_cpu, NULL),
+	/* Wait for APs to finish initialization before proceeding. */
+	MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL),
 };
 
 /* The APIC id space on Bay Trail is sparse. Each id is separated by 2. */
@@ -48,13 +61,15 @@ void baytrail_init_cpus(device_t dev)
 	x86_setup_var_mtrrs(pattrs->address_bits, 2);
 	x86_mtrr_check();
 
+	/* Stash microcode. */
+	microcode_ptr = intel_microcode_find();
+
 	mp_params.num_cpus = pattrs->num_cpus,
 	mp_params.parallel_microcode_load = 1,
 	mp_params.adjust_apic_id = adjust_apic_id;
 	mp_params.flight_plan = &mp_steps[0];
 	mp_params.num_records = ARRAY_SIZE(mp_steps);
-	mp_params.microcode_pointer = intel_microcode_find();
-	mp_params.microcode_pointer = NULL;
+	mp_params.microcode_pointer = microcode_ptr;
 
 	if (mp_init(cpu_bus, &mp_params)) {
 		printk(BIOS_ERR, "MP initialization failure.\n");
@@ -80,3 +95,148 @@ static const struct cpu_driver driver __cpu_driver = {
 	.id_table = cpu_table,
 };
 
+
+/*
+ * SMM loading and 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 adjust_apic_id_map(struct smm_loader_params *smm_params)
+{
+	int i;
+	struct smm_runtime *runtime = smm_params->runtime;
+
+	for (i = 0; i < CONFIG_MAX_CPUS; i++)
+		runtime->apic_id_to_cpu[i] = mp_get_apic_id(i);
+}
+
+static void asmlinkage
+cpu_smm_do_relocation(void *arg, int cpu, const struct smm_runtime *runtime)
+{
+	msr_t smrr;
+	em64t100_smm_state_save_area_t *smm_state;
+
+	if (cpu >= CONFIG_MAX_CPUS) {
+		printk(BIOS_CRIT,
+		       "Invalid CPU number assigned in SMM stub: %d\n", cpu);
+		return;
+	}
+
+	/* Set up SMRR. */
+	smrr.lo = relo_attrs.smrr_base;
+	smrr.hi = 0;
+	wrmsr(SMRRphysBase_MSR, smrr);
+	smrr.lo = relo_attrs.smrr_mask;
+	smrr.hi = 0;
+	wrmsr(SMRRphysMask_MSR, smrr);
+
+	/* The relocated handler runs with all CPUs concurrently. Therefore
+	 * stagger the entry points adjusting SMBASE downwards by save state
+	 * size * CPU num. */
+	smm_state = (void *)(SMM_EM64T100_SAVE_STATE_OFFSET + runtime->smbase);
+	smm_state->smbase = relo_attrs.smbase - cpu * runtime->save_state_size;
+	printk(BIOS_DEBUG, "New SMBASE 0x%08x\n", smm_state->smbase);
+}
+
+static int install_relocation_handler(int num_cpus)
+{
+	const int save_state_size = sizeof(em64t100_smm_state_save_area_t);
+
+	struct smm_loader_params smm_params = {
+		.per_cpu_stack_size = save_state_size,
+		.num_concurrent_stacks = num_cpus,
+		.per_cpu_save_state_size = save_state_size,
+		.num_concurrent_save_states = 1,
+		.handler = (smm_handler_t)&cpu_smm_do_relocation,
+	};
+
+	if (smm_setup_relocation_handler(&smm_params))
+		return -1;
+
+	adjust_apic_id_map(&smm_params);
+
+	return 0;
+}
+
+static int install_permanent_handler(int num_cpus)
+{
+	/* There are num_cpus concurrent stacks and num_cpus concurrent save
+	 * state areas. Lastly, set the stack size to the save state size. */
+	int save_state_size = sizeof(em64t100_smm_state_save_area_t);
+	struct smm_loader_params smm_params = {
+		.per_cpu_stack_size = save_state_size,
+		.num_concurrent_stacks = num_cpus,
+		.per_cpu_save_state_size = save_state_size,
+		.num_concurrent_save_states = num_cpus,
+	};
+	const int tseg_size = smm_region_size() - CONFIG_SMM_RESERVED_SIZE;
+
+	printk(BIOS_DEBUG, "Installing SMM handler to 0x%08x\n",
+	       relo_attrs.smbase);
+
+	if (smm_load_module((void *)relo_attrs.smbase, tseg_size, &smm_params))
+		return -1;
+
+	adjust_apic_id_map(&smm_params);
+
+	return 0;
+}
+
+static int smm_load_handlers(void)
+{
+	/* All range registers are aligned to 4KiB */
+	const uint32_t rmask = ~((1 << 12) - 1);
+	const struct pattrs *pattrs = pattrs_get();
+
+	/* Initialize global tracking state. */
+	relo_attrs.smbase = (uint32_t)smm_region_start();
+	relo_attrs.smrr_base = relo_attrs.smbase | MTRR_TYPE_WRBACK;
+	relo_attrs.smrr_mask = ~(smm_region_size() - 1) & rmask;
+	relo_attrs.smrr_mask |= MTRRphysMaskValid;
+
+	/* Install handlers. */
+	if (install_relocation_handler(pattrs->num_cpus) < 0) {
+		printk(BIOS_ERR, "Unable to install SMM relocation handler.\n");
+		return -1;
+	}
+
+	if (install_permanent_handler(pattrs->num_cpus) < 0) {
+		printk(BIOS_ERR, "Unable to install SMM permanent handler.\n");
+		return -1;
+	}
+
+	/* Ensure the SMM handlers hit DRAM before performing first SMI. */
+	wbinvd();
+
+	return 0;
+}
+
+static void smm_relocate(void *unused)
+{
+	/* Load relocation and permanent handler. */
+	if (boot_cpu()) {
+		if (smm_load_handlers() < 0) {
+			printk(BIOS_ERR, "Error loading SMM handlers.\n");
+			return;
+		}
+		southcluster_smm_clear_state();
+	}
+
+	/* Relocate SMM space. */
+	smm_initiate_relocation();
+
+	/* Load microcode after SMM relocation. */
+	intel_microcode_load_unlocked(microcode_ptr);
+}
+
+static void enable_smis(void *unused)
+{
+	southcluster_smm_enable_smi();
+}
diff --git a/src/soc/intel/baytrail/memmap.c b/src/soc/intel/baytrail/memmap.c
index f958bae..03b6713 100644
--- a/src/soc/intel/baytrail/memmap.c
+++ b/src/soc/intel/baytrail/memmap.c
@@ -20,8 +20,14 @@
 #include <arch/io.h>
 #include <cbmem.h>
 #include <baytrail/iosf.h>
+#include <baytrail/smm.h>
 
-unsigned long get_top_of_ram(void)
+void *smm_region_start(void)
 {
 	return (unsigned long)(iosf_bunit_read(BUNIT_SMRRL) << 20);
 }
+
+unsigned long get_top_of_ram(void)
+{
+	return (unsigned long)smm_region_start();
+}
diff --git a/src/soc/intel/baytrail/placeholders.c b/src/soc/intel/baytrail/placeholders.c
index 8f2342a..63f0fb3 100644
--- a/src/soc/intel/baytrail/placeholders.c
+++ b/src/soc/intel/baytrail/placeholders.c
@@ -13,8 +13,6 @@ void acpi_create_serialio_ssdt(acpi_header_t *ssdt) {}
 
 unsigned long acpi_fill_mcfg(unsigned long current) { return current; }
 
-void smm_setup_structures(void *gnvs, void *tcg, void *smi1) {}
-
 void smm_init(void) {}
 
 /* Rmodules don't like weak symbols. */
diff --git a/src/soc/intel/baytrail/pmutil.c b/src/soc/intel/baytrail/pmutil.c
new file mode 100644
index 0000000..738f880
--- /dev/null
+++ b/src/soc/intel/baytrail/pmutil.c
@@ -0,0 +1,297 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <arch/io.h>
+#include <console/console.h>
+
+#include <baytrail/lpc.h>
+#include <baytrail/pci_devs.h>
+#include <baytrail/pmc.h>
+
+#if defined(__SMM__)
+
+static const device_t pcu_dev = PCI_DEV(0, PCU_DEV, 0);
+
+static inline device_t get_pcu_dev(void)
+{
+	return pcu_dev;
+}
+
+#else /* !__SMM__ */
+#include <device/device.h>
+#include <device/pci.h>
+
+static device_t pcu_dev;
+static device_t get_pcu_dev(void)
+{
+	if (pcu_dev == NULL)
+		pcu_dev = dev_find_slot(0, PCI_DEVFN(PCU_DEV, 0));
+	return pcu_dev;
+}
+#endif
+
+uint16_t get_pmbase(void)
+{
+	return pci_read_config16(get_pcu_dev(), ABASE) & 0xfff8;
+}
+
+static void print_status_bits(uint32_t status, const char *bit_names[])
+{
+	int i;
+
+	if (!status)
+		return;
+
+	for (i = 31; i >= 0; i--) {
+		if (status & (1 << i)) {
+			if (bit_names[i])
+				printk(BIOS_DEBUG, "%s ", bit_names[i]);
+			else
+				printk(BIOS_DEBUG, "BIT%d ", i);
+		}
+	}
+}
+
+static uint32_t print_smi_status(uint32_t smi_sts)
+{
+	static const char *smi_sts_bits[] = {
+		[2] = "BIOS",
+		[4] = "SLP_SMI",
+		[5] = "APM",
+		[6] = "SWSMI_TMR",
+		[8] = "PM1",
+		[9] = "GPE0",
+		[12] = "DEVMON",
+		[13] = "TCO",
+		[14] = "PERIODIC",
+		[15] = "ILB",
+		[16] = "SMBUS_SMI",
+		[17] = "LEGACY_USB2",
+		[18] = "INTEL_USB2",
+		[20] = "PCI_EXP_SMI",
+		[26] = "SPI",
+		[28] = "PUNIT",
+		[29] = "GUNIT",
+	};
+
+	if (!smi_sts)
+		return 0;
+
+	printk(BIOS_DEBUG, "SMI_STS: ");
+	print_status_bits(smi_sts, smi_sts_bits);
+	printk(BIOS_DEBUG, "\n");
+
+	return smi_sts;
+}
+
+static uint32_t reset_smi_status(void)
+{
+	uint16_t pmbase = get_pmbase();
+	uint32_t smi_sts = inl(pmbase + SMI_STS);
+	outl(smi_sts, pmbase + SMI_STS);
+	return smi_sts;
+}
+
+uint32_t clear_smi_status(void)
+{
+	return print_smi_status(reset_smi_status());
+}
+
+void enable_smi(uint32_t mask)
+{
+	uint16_t pmbase = get_pmbase();
+	uint32_t smi_en = inl(pmbase + SMI_EN);
+	smi_en |= mask;
+	outl(smi_en, pmbase + SMI_EN);
+}
+
+void disable_smi(uint32_t mask)
+{
+	uint16_t pmbase = get_pmbase();
+	uint32_t smi_en = inl(pmbase + SMI_EN);
+	smi_en &= ~mask;
+	outl(smi_en, pmbase + SMI_EN);
+}
+
+void enable_pm1_control(uint32_t mask)
+{
+	uint16_t pmbase = get_pmbase();
+	uint32_t pm1_cnt = inl(pmbase + PM1_CNT);
+	pm1_cnt |= mask;
+	outl(pm1_cnt, pmbase + PM1_CNT);
+}
+
+void disable_pm1_control(uint32_t mask)
+{
+	uint16_t pmbase = get_pmbase();
+	uint32_t pm1_cnt = inl(pmbase + PM1_CNT);
+	pm1_cnt &= ~mask;
+	outl(pm1_cnt, pmbase + PM1_CNT);
+}
+
+static uint16_t reset_pm1_status(void)
+{
+	uint16_t pmbase = get_pmbase();
+	uint16_t pm1_sts = inw(pmbase + PM1_STS);
+	outw(pm1_sts, pmbase + PM1_STS);
+	return pm1_sts;
+}
+
+static uint16_t print_pm1_status(uint16_t pm1_sts)
+{
+	static const char *pm1_sts_bits[] = {
+		[0] = "TMROF",
+		[5] = "GBL",
+		[8] = "PWRBTN",
+		[10] = "RTC",
+		[11] = "PRBTNOR",
+		[13] = "USB",
+		[14] = "PCIEXPWAK",
+		[15] = "WAK",
+	};
+
+	if (!pm1_sts)
+		return 0;
+
+	printk(BIOS_SPEW, "PM1_STS: ");
+	print_status_bits(pm1_sts, pm1_sts_bits);
+	printk(BIOS_SPEW, "\n");
+
+	return pm1_sts;
+}
+
+uint16_t clear_pm1_status(void)
+{
+	return print_pm1_status(reset_pm1_status());
+}
+
+void enable_pm1(uint16_t events)
+{
+	outw(events, get_pmbase() + PM1_EN);
+}
+
+static uint32_t print_tco_status(uint32_t tco_sts)
+{
+	static const char *tco_sts_bits[] = {
+		[3] = "TIMEOUT",
+		[17] = "SECOND_TO",
+	};
+
+	if (!tco_sts)
+		return 0;
+
+	printk(BIOS_DEBUG, "TCO_STS: ");
+	print_status_bits(tco_sts, tco_sts_bits);
+	printk(BIOS_DEBUG, "\n");
+
+	return tco_sts;
+}
+
+static uint32_t reset_tco_status(void)
+{
+	uint16_t pmbase = get_pmbase();
+	uint32_t tco_sts = inl(pmbase + TCO_STS);
+	uint32_t tco_en = inl(pmbase + TCO1_CNT);
+
+	outl(tco_sts, pmbase + TCO_STS);
+	return tco_sts & tco_en;
+}
+
+uint32_t clear_tco_status(void)
+{
+	return print_tco_status(reset_tco_status());
+}
+
+void enable_gpe(uint32_t mask)
+{
+	uint16_t pmbase = get_pmbase();
+	uint32_t gpe0_en = inl(pmbase + GPE0_EN);
+	gpe0_en |= mask;
+	outl(gpe0_en, pmbase + GPE0_EN);
+}
+
+void disable_gpe(uint32_t mask)
+{
+	uint16_t pmbase = get_pmbase();
+	uint32_t gpe0_en = inl(pmbase + GPE0_EN);
+	gpe0_en &= ~mask;
+	outl(gpe0_en, pmbase + GPE0_EN);
+}
+
+void disable_all_gpe(void)
+{
+	disable_gpe(~0);
+}
+
+
+static uint32_t reset_gpe_status(void)
+{
+	uint16_t pmbase = get_pmbase();
+	uint32_t gpe_sts = inl(pmbase + GPE0_STS);
+	outl(gpe_sts, pmbase + GPE0_STS);
+	return gpe_sts;
+}
+
+static uint32_t print_gpe_sts(uint32_t gpe_sts)
+{
+	static const char *gpe_sts_bits[] = {
+		[1] = "HOTPLUG",
+		[2] = "SWGPE",
+		[3] = "PCIE_WAKE0",
+		[4] = "PUNIT",
+		[5] = "GUNIT",
+		[6] = "PCIE_WAKE1",
+		[7] = "PCIE_WAKE2",
+		[8] = "PCIE_WAKE3",
+		[9] = "PCI_EXP",
+		[10] = "BATLOW",
+		[13] = "PME_B0",
+		[16] = "SUS_GPIO_0",
+		[17] = "SUS_GPIO_1",
+		[18] = "SUS_GPIO_2",
+		[19] = "SUS_GPIO_3",
+		[20] = "SUS_GPIO_4",
+		[21] = "SUS_GPIO_5",
+		[22] = "SUS_GPIO_6",
+		[23] = "SUS_GPIO_7",
+		[24] = "CORE_GPIO_0",
+		[25] = "CORE_GPIO_1",
+		[26] = "CORE_GPIO_2",
+		[27] = "CORE_GPIO_3",
+		[28] = "CORE_GPIO_4",
+		[29] = "CORE_GPIO_5",
+		[30] = "CORE_GPIO_6",
+		[31] = "CORE_GPIO_7",
+	};
+
+	if (!gpe_sts)
+		return gpe_sts;
+
+	printk(BIOS_DEBUG, "GPE0a_STS: ");
+	print_status_bits(gpe_sts, gpe_sts_bits);
+	printk(BIOS_DEBUG, "\n");
+
+	return gpe_sts;
+}
+
+uint32_t clear_gpe_status(void)
+{
+	return print_gpe_sts(reset_gpe_status());
+}
diff --git a/src/soc/intel/baytrail/romstage/romstage.c b/src/soc/intel/baytrail/romstage/romstage.c
index 3ae52cf..10028ca 100644
--- a/src/soc/intel/baytrail/romstage/romstage.c
+++ b/src/soc/intel/baytrail/romstage/romstage.c
@@ -36,6 +36,7 @@
 #include <baytrail/pci_devs.h>
 #include <baytrail/reset.h>
 #include <baytrail/romstage.h>
+#include <baytrail/smm.h>
 
 static inline uint64_t timestamp_get(void)
 {
@@ -282,13 +283,13 @@ struct ramstage_cache *ramstage_cache_location(long *size)
 {
 	char *smm_base;
 	/* 1MiB cache size */
-	const long cache_size = (1 << 20);
+	const long cache_size = CONFIG_SMM_RESERVED_SIZE;
 
 	/* Ramstage cache lives in TSEG region which is the definition of
 	 * cbmem_top(). */
 	smm_base = cbmem_top();
 	*size = cache_size;
-	return (void *)&smm_base[CONFIG_SMM_TSEG_SIZE - cache_size];
+	return (void *)&smm_base[smm_region_size() - cache_size];
 }
 
 void ramstage_cache_invalid(struct ramstage_cache *cache)
diff --git a/src/soc/intel/baytrail/smihandler.c b/src/soc/intel/baytrail/smihandler.c
new file mode 100644
index 0000000..d5f6aa6
--- /dev/null
+++ b/src/soc/intel/baytrail/smihandler.c
@@ -0,0 +1,399 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <arch/hlt.h>
+#include <arch/io.h>
+#include <console/console.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/smm.h>
+#include <device/pci_def.h>
+#include <elog.h>
+
+#include <baytrail/pci_devs.h>
+#include <baytrail/pmc.h>
+#include <baytrail/nvs.h>
+
+/* GNVS needs to be set by coreboot initiating a software SMI. */
+static global_nvs_t *gnvs;
+static int smm_initialized;
+
+int southbridge_io_trap_handler(int smif)
+{
+	switch (smif) {
+	case 0x32:
+		printk(BIOS_DEBUG, "OS Init\n");
+		/* gnvs->smif:
+		 *  On success, the IO Trap Handler returns 0
+		 *  On failure, the IO Trap Handler returns a value != 0
+		 */
+		gnvs->smif = 0;
+		return 1; /* IO trap handled */
+	}
+
+	/* Not handled */
+	return 0;
+}
+
+void southbridge_smi_set_eos(void)
+{
+	enable_smi(EOS);
+}
+
+global_nvs_t *smm_get_gnvs(void)
+{
+	return gnvs;
+}
+
+static void busmaster_disable_on_bus(int bus)
+{
+	int slot, func;
+	unsigned int val;
+	unsigned char hdr;
+
+	for (slot = 0; slot < 0x20; slot++) {
+		for (func = 0; func < 8; func++) {
+			u32 reg32;
+			device_t dev = PCI_DEV(bus, slot, func);
+
+			val = pci_read_config32(dev, PCI_VENDOR_ID);
+
+			if (val == 0xffffffff || val == 0x00000000 ||
+			    val == 0x0000ffff || val == 0xffff0000)
+				continue;
+
+			/* Disable Bus Mastering for this one device */
+			reg32 = pci_read_config32(dev, PCI_COMMAND);
+			reg32 &= ~PCI_COMMAND_MASTER;
+			pci_write_config32(dev, PCI_COMMAND, reg32);
+
+			/* If this is a bridge, then follow it. */
+			hdr = pci_read_config8(dev, PCI_HEADER_TYPE);
+			hdr &= 0x7f;
+			if (hdr == PCI_HEADER_TYPE_BRIDGE ||
+			    hdr == PCI_HEADER_TYPE_CARDBUS) {
+				unsigned int buses;
+				buses = pci_read_config32(dev, PCI_PRIMARY_BUS);
+				busmaster_disable_on_bus((buses >> 8) & 0xff);
+			}
+		}
+	}
+}
+
+static void southbridge_smi_sleep(void)
+{
+	uint32_t reg32;
+	uint8_t slp_typ;
+	uint16_t pmbase = get_pmbase();
+
+	/* First, disable further SMIs */
+	disable_smi(SLP_SMI_EN);
+
+	/* Figure out SLP_TYP */
+	reg32 = inl(pmbase + PM1_CNT);
+	printk(BIOS_SPEW, "SMI#: SLP = 0x%08x\n", reg32);
+	slp_typ = (reg32 >> 10) & 7;
+
+	/* Do any mainboard sleep handling */
+	mainboard_smi_sleep(slp_typ-2);
+
+#if CONFIG_ELOG_GSMI
+	/* Log S3, S4, and S5 entry */
+	if (slp_typ >= 5)
+		elog_add_event_byte(ELOG_TYPE_ACPI_ENTER, slp_typ-2);
+#endif
+
+	/* Next, do the deed.
+	 */
+
+	switch (slp_typ) {
+	case SLP_TYP_S0:
+		printk(BIOS_DEBUG, "SMI#: Entering S0 (On)\n");
+		break;
+	case SLP_TYP_S1:
+		printk(BIOS_DEBUG, "SMI#: Entering S1 (Assert STPCLK#)\n");
+		break;
+	case SLP_TYP_S3:
+		printk(BIOS_DEBUG, "SMI#: Entering S3 (Suspend-To-RAM)\n");
+
+		/* Invalidate the cache before going to S3 */
+		wbinvd();
+		break;
+	case SLP_TYP_S4:
+		printk(BIOS_DEBUG, "SMI#: Entering S4 (Suspend-To-Disk)\n");
+		break;
+	case SLP_TYP_S5:
+		printk(BIOS_DEBUG, "SMI#: Entering S5 (Soft Power off)\n");
+
+		/* Disable all GPE */
+		disable_all_gpe();
+
+		/* also iterates over all bridges on bus 0 */
+		busmaster_disable_on_bus(0);
+		break;
+	default:
+		printk(BIOS_DEBUG, "SMI#: ERROR: SLP_TYP reserved\n");
+		break;
+	}
+
+	/* Write back to the SLP register to cause the originally intended
+	 * event again. We need to set BIT13 (SLP_EN) though to make the
+	 * sleep happen.
+	 */
+	enable_pm1_control(SLP_EN);
+
+	/* Make sure to stop executing code here for S3/S4/S5 */
+	if (slp_typ > 1)
+		hlt();
+
+	/* In most sleep states, the code flow of this function ends at
+	 * 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(pmbase + 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);
+	}
+}
+
+/*
+ * Look for Synchronous IO SMI and use save state from that
+ * core in case we are not running on the same core that
+ * initiated the IO transaction.
+ */
+static em64t100_smm_state_save_area_t *smi_apmc_find_state_save(uint8_t cmd)
+{
+	em64t100_smm_state_save_area_t *state;
+	int node;
+
+	/* Check all nodes looking for the one that issued the IO */
+	for (node = 0; node < CONFIG_MAX_CPUS; node++) {
+		state = smm_get_save_state(node);
+
+		/* Check for Synchronous IO (bit0==1) */
+		if (!(state->io_misc_info & (1 << 0)))
+			continue;
+
+		/* Make sure it was a write (bit4==0) */
+		if (state->io_misc_info & (1 << 4))
+			continue;
+
+		/* Check for APMC IO port */
+		if (((state->io_misc_info >> 16) & 0xff) != APM_CNT)
+			continue;
+
+		/* Check AX against the requested command */
+		if ((state->rax & 0xff) != cmd)
+			continue;
+
+		return state;
+	}
+
+	return NULL;
+}
+
+#if CONFIG_ELOG_GSMI
+static void southbridge_smi_gsmi(void)
+{
+	u32 *ret, *param;
+	uint8_t sub_command;
+	em64t100_smm_state_save_area_t *io_smi =
+		smi_apmc_find_state_save(ELOG_GSMI_APM_CNT);
+
+	if (!io_smi)
+		return;
+
+	/* Command and return value in EAX */
+	ret = (u32*)&io_smi->rax;
+	sub_command = (uint8_t)(*ret >> 8);
+
+	/* Parameter buffer in EBX */
+	param = (u32*)&io_smi->rbx;
+
+	/* drivers/elog/gsmi.c */
+	*ret = gsmi_exec(sub_command, param);
+}
+#endif
+static void southbridge_smi_apmc(void)
+{
+	uint8_t reg8;
+	em64t100_smm_state_save_area_t *state;
+
+	/* Emulate B2 register as the FADT / Linux expects it */
+
+	reg8 = inb(APM_CNT);
+	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:
+		disable_pm1_control(SCI_EN);
+		printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n");
+		break;
+	case APM_CNT_ACPI_ENABLE:
+		enable_pm1_control(SCI_EN);
+		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;
+		}
+		state = smi_apmc_find_state_save(reg8);
+		if (state) {
+			/* EBX in the state save contains the GNVS pointer */
+			gnvs = (global_nvs_t *)((uint32_t)state->rbx);
+			smm_initialized = 1;
+			printk(BIOS_DEBUG, "SMI#: Setting GNVS to %p\n", gnvs);
+		}
+		break;
+#if CONFIG_ELOG_GSMI
+	case ELOG_GSMI_APM_CNT:
+		southbridge_smi_gsmi();
+		break;
+#endif
+	}
+
+	mainboard_smi_apmc(reg8);
+}
+
+static void southbridge_smi_pm1(void)
+{
+	uint16_t pm1_sts = clear_pm1_status();
+
+	/* While OSPM is not active, poweroff immediately
+	 * on a power button event.
+	 */
+	if (pm1_sts & PWRBTN_STS) {
+		// power button pressed
+#if CONFIG_ELOG_GSMI
+		elog_add_event(ELOG_TYPE_POWER_BUTTON);
+#endif
+		disable_pm1_control(-1UL);
+		enable_pm1_control(SLP_EN | (SLP_TYP_S5 << 10));
+	}
+}
+
+static void southbridge_smi_gpe0(void)
+{
+	clear_gpe_status();
+}
+
+static void southbridge_smi_tco(void)
+{
+	uint32_t tco_sts = clear_tco_status();
+
+	/* Any TCO event? */
+	if (!tco_sts)
+		return;
+
+	if (tco_sts & TCO_TIMEOUT) { /* TIMEOUT */
+		/* Handle TCO timeout */
+		printk(BIOS_DEBUG, "TCO Timeout.\n");
+	}
+}
+
+static void southbridge_smi_periodic(void)
+{
+	uint32_t reg32;
+
+	reg32 = inl(get_pmbase() + SMI_EN);
+
+	/* Are periodic SMIs enabled? */
+	if ((reg32 & PERIODIC_EN) == 0)
+		return;
+
+	printk(BIOS_DEBUG, "Periodic SMI.\n");
+}
+
+typedef void (*smi_handler_t)(void);
+
+static 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
+};
+
+void southbridge_smi_handler(void)
+{
+	int i;
+	uint32_t smi_sts;
+
+	/* 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();
+
+	/* Call SMI sub handler for each of the status bits */
+	for (i = 0; i < ARRAY_SIZE(southbridge_smi); i++) {
+		if (!(smi_sts & (1 << i)))
+			continue;
+
+		if (southbridge_smi[i] != NULL) {
+			southbridge_smi[i]();
+		} else {
+			printk(BIOS_DEBUG,
+			       "SMI_STS[%d] occured, but no "
+			       "handler available.\n", i);
+		}
+	}
+}
diff --git a/src/soc/intel/baytrail/smm.c b/src/soc/intel/baytrail/smm.c
new file mode 100644
index 0000000..124f93b
--- /dev/null
+++ b/src/soc/intel/baytrail/smm.c
@@ -0,0 +1,91 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <device/device.h>
+#include <device/pci.h>
+#include <console/console.h>
+#include <arch/io.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/smm.h>
+#include <string.h>
+
+#include <baytrail/pmc.h>
+#include <baytrail/smm.h>
+
+void southcluster_smm_clear_state(void)
+{
+	uint32_t smi_en;
+
+	/* Log events from chipset before clearing */
+	southcluster_log_state();
+
+	printk(BIOS_DEBUG, "Initializing Southbridge SMI...");
+	printk(BIOS_SPEW, " pmbase = 0x%04x\n", get_pmbase());
+
+	smi_en = inl(get_pmbase() + SMI_EN);
+	if (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 southcluster_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:
+	 *  - on TCO events
+	 *  - on APMC writes (io 0xb2)
+	 *  - on writes to SLP_EN (sleep states)
+	 *  - on writes to GBL_RLS (bios commands)
+	 * No SMIs:
+	 *  - on microcontroller writes (io 0x62/0x66)
+	 */
+	enable_smi(TCO_EN | APMC_EN | SLP_SMI_EN | GBL_SMI_EN | 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" ((uint32_t)gnvs),
+		  "d" (APM_CNT)
+	);
+}
diff --git a/src/soc/intel/baytrail/tsc_freq.c b/src/soc/intel/baytrail/tsc_freq.c
index 3b662fe..6ee5c16 100644
--- a/src/soc/intel/baytrail/tsc_freq.c
+++ b/src/soc/intel/baytrail/tsc_freq.c
@@ -21,11 +21,6 @@
 #include <cpu/x86/msr.h>
 #include <cpu/x86/tsc.h>
 #include <baytrail/msr.h>
-#if !defined(__PRE_RAM__)
-#include <baytrail/ramstage.h>
-#else
-#include <baytrail/romstage.h>
-#endif
 
 unsigned long tsc_freq_mhz(void)
 {
@@ -44,6 +39,13 @@ unsigned long tsc_freq_mhz(void)
 	return (bclk_khz * ((platform_info.lo >> 8) & 0xff)) / 1000;
 }
 
+#if !defined(__SMM__)
+#if !defined(__PRE_RAM__)
+#include <baytrail/ramstage.h>
+#else
+#include <baytrail/romstage.h>
+#endif
+
 void set_max_freq(void)
 {
 	msr_t perf_ctl;
@@ -66,3 +68,5 @@ void set_max_freq(void)
 
 	wrmsr(MSR_IA32_PERF_CTL, perf_ctl);
 }
+
+#endif /* __SMM__ */



More information about the coreboot-gerrit mailing list