[coreboot-gerrit] Change in coreboot[master]: sb/intel/common: Add common code for SMM setup and smihandler

Arthur Heymans (Code Review) gerrit at coreboot.org
Thu Jan 25 11:35:54 CET 2018


Arthur Heymans has uploaded this change for review. ( https://review.coreboot.org/23427


Change subject: sb/intel/common: Add common code for SMM setup and smihandler
......................................................................

sb/intel/common: Add common code for SMM setup and smihandler

Change-Id: I28e2e6ad1e95a9e14462a456726a144ccdc63ec9
Signed-off-by: Arthur Heymans <arthur at aheymans.xyz>
---
M src/southbridge/intel/bd82x6x/Kconfig
M src/southbridge/intel/bd82x6x/Makefile.inc
M src/southbridge/intel/bd82x6x/finalize.c
D src/southbridge/intel/bd82x6x/smi.c
M src/southbridge/intel/bd82x6x/smihandler.c
M src/southbridge/intel/common/Kconfig
M src/southbridge/intel/common/Makefile.inc
A src/southbridge/intel/common/pmutil.c
A src/southbridge/intel/common/pmutil.h
A src/southbridge/intel/common/smi.c
10 files changed, 534 insertions(+), 525 deletions(-)



  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/27/23427/1

diff --git a/src/southbridge/intel/bd82x6x/Kconfig b/src/southbridge/intel/bd82x6x/Kconfig
index ed2b979..9a70bf2 100644
--- a/src/southbridge/intel/bd82x6x/Kconfig
+++ b/src/southbridge/intel/bd82x6x/Kconfig
@@ -41,6 +41,7 @@
 	select SOUTHBRIDGE_INTEL_COMMON_GPIO
 	select RTC
 	select HAVE_INTEL_CHIPSET_LOCKDOWN
+	select SOUTHBRIDGE_INTEL_COMMON_SMM
 
 config EHCI_BAR
 	hex
diff --git a/src/southbridge/intel/bd82x6x/Makefile.inc b/src/southbridge/intel/bd82x6x/Makefile.inc
index a5825a8..ea8e96c 100644
--- a/src/southbridge/intel/bd82x6x/Makefile.inc
+++ b/src/southbridge/intel/bd82x6x/Makefile.inc
@@ -36,7 +36,6 @@
 
 ramstage-$(CONFIG_ELOG) += elog.c
 
-ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c
 smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c me.c me_8.x.c finalize.c pch.c
 
 romstage-y += early_smbus.c me_status.c
diff --git a/src/southbridge/intel/bd82x6x/finalize.c b/src/southbridge/intel/bd82x6x/finalize.c
index fe28af0..2b7ac4e 100644
--- a/src/southbridge/intel/bd82x6x/finalize.c
+++ b/src/southbridge/intel/bd82x6x/finalize.c
@@ -19,6 +19,7 @@
 #include <cpu/x86/smm.h>
 #include "pch.h"
 #include <spi-generic.h>
+#include <southbridge/intel/common/pmutil.h>
 
 void intel_pch_finalize_smm(void)
 {
@@ -75,7 +76,7 @@
 		    pci_read_config32(PCI_DEV(0, 27, 0), 0x74));
 
 	/* TCO_Lock */
-	pmbase = smm_get_pmbase();
+	pmbase = get_pmbase();
 	tco1_cnt = inw(pmbase + TCO1_CNT);
 	tco1_cnt |= TCO_LOCK;
 	outw(tco1_cnt, pmbase + TCO1_CNT);
diff --git a/src/southbridge/intel/bd82x6x/smi.c b/src/southbridge/intel/bd82x6x/smi.c
deleted file mode 100644
index 2248904..0000000
--- a/src/southbridge/intel/bd82x6x/smi.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2008-2009 coresystems GmbH
- *
- * 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 <device/device.h>
-#include <device/pci.h>
-#include <console/console.h>
-#include <arch/io.h>
-#include <cpu/cpu.h>
-#include <cpu/x86/cache.h>
-#include <cpu/x86/smm.h>
-#include <string.h>
-#include <cpu/intel/smm/gen1/smi.h>
-#include "pch.h"
-
-/* While we read PMBASE dynamically in case it changed, let's
- * initialize it with a sane value
- */
-static u16 pmbase = DEFAULT_PMBASE;
-
-/**
- * @brief read and clear PM1_STS
- * @return PM1_STS register
- */
-static u16 reset_pm1_status(void)
-{
-	u16 reg16;
-
-	reg16 = inw(pmbase + PM1_STS);
-	/* set status bits are cleared by writing 1 to them */
-	outw(reg16, pmbase + PM1_STS);
-
-	return reg16;
-}
-
-static void dump_pm1_status(u16 pm1_sts)
-{
-	printk(BIOS_DEBUG, "PM1_STS: ");
-	if (pm1_sts & (1 << 15)) printk(BIOS_DEBUG, "WAK ");
-	if (pm1_sts & (1 << 14)) printk(BIOS_DEBUG, "PCIEXPWAK ");
-	if (pm1_sts & (1 << 11)) printk(BIOS_DEBUG, "PRBTNOR ");
-	if (pm1_sts & (1 << 10)) printk(BIOS_DEBUG, "RTC ");
-	if (pm1_sts & (1 <<  8)) printk(BIOS_DEBUG, "PWRBTN ");
-	if (pm1_sts & (1 <<  5)) printk(BIOS_DEBUG, "GBL ");
-	if (pm1_sts & (1 <<  4)) printk(BIOS_DEBUG, "BM ");
-	if (pm1_sts & (1 <<  0)) printk(BIOS_DEBUG, "TMROF ");
-	printk(BIOS_DEBUG, "\n");
-}
-
-/**
- * @brief read and clear SMI_STS
- * @return SMI_STS register
- */
-static u32 reset_smi_status(void)
-{
-	u32 reg32;
-
-	reg32 = inl(pmbase + SMI_STS);
-	/* set status bits are cleared by writing 1 to them */
-	outl(reg32, pmbase + SMI_STS);
-
-	return reg32;
-}
-
-static void dump_smi_status(u32 smi_sts)
-{
-	printk(BIOS_DEBUG, "SMI_STS: ");
-	if (smi_sts & (1 << 26)) printk(BIOS_DEBUG, "SPI ");
-	if (smi_sts & (1 << 25)) printk(BIOS_DEBUG, "EL_SMI ");
-	if (smi_sts & (1 << 21)) printk(BIOS_DEBUG, "MONITOR ");
-	if (smi_sts & (1 << 20)) printk(BIOS_DEBUG, "PCI_EXP_SMI ");
-	if (smi_sts & (1 << 18)) printk(BIOS_DEBUG, "INTEL_USB2 ");
-	if (smi_sts & (1 << 17)) printk(BIOS_DEBUG, "LEGACY_USB2 ");
-	if (smi_sts & (1 << 16)) printk(BIOS_DEBUG, "SMBUS_SMI ");
-	if (smi_sts & (1 << 15)) printk(BIOS_DEBUG, "SERIRQ_SMI ");
-	if (smi_sts & (1 << 14)) printk(BIOS_DEBUG, "PERIODIC ");
-	if (smi_sts & (1 << 13)) printk(BIOS_DEBUG, "TCO ");
-	if (smi_sts & (1 << 12)) printk(BIOS_DEBUG, "DEVMON ");
-	if (smi_sts & (1 << 11)) printk(BIOS_DEBUG, "MCSMI ");
-	if (smi_sts & (1 << 10)) printk(BIOS_DEBUG, "GPI ");
-	if (smi_sts & (1 <<  9)) printk(BIOS_DEBUG, "GPE0 ");
-	if (smi_sts & (1 <<  8)) printk(BIOS_DEBUG, "PM1 ");
-	if (smi_sts & (1 <<  6)) printk(BIOS_DEBUG, "SWSMI_TMR ");
-	if (smi_sts & (1 <<  5)) printk(BIOS_DEBUG, "APM ");
-	if (smi_sts & (1 <<  4)) printk(BIOS_DEBUG, "SLP_SMI ");
-	if (smi_sts & (1 <<  3)) printk(BIOS_DEBUG, "LEGACY_USB ");
-	if (smi_sts & (1 <<  2)) printk(BIOS_DEBUG, "BIOS ");
-	printk(BIOS_DEBUG, "\n");
-}
-
-
-/**
- * @brief read and clear GPE0_STS
- * @return GPE0_STS register
- */
-static u32 reset_gpe0_status(void)
-{
-	u32 reg32;
-
-	reg32 = inl(pmbase + GPE0_STS);
-	/* set status bits are cleared by writing 1 to them */
-	outl(reg32, pmbase + GPE0_STS);
-
-	return reg32;
-}
-
-static void dump_gpe0_status(u32 gpe0_sts)
-{
-	int i;
-	printk(BIOS_DEBUG, "GPE0_STS: ");
-	for (i=31; i>= 16; i--) {
-		if (gpe0_sts & (1 << i)) printk(BIOS_DEBUG, "GPIO%d ", (i-16));
-	}
-	if (gpe0_sts & (1 << 14)) printk(BIOS_DEBUG, "USB4 ");
-	if (gpe0_sts & (1 << 13)) printk(BIOS_DEBUG, "PME_B0 ");
-	if (gpe0_sts & (1 << 12)) printk(BIOS_DEBUG, "USB3 ");
-	if (gpe0_sts & (1 << 11)) printk(BIOS_DEBUG, "PME ");
-	if (gpe0_sts & (1 << 10)) printk(BIOS_DEBUG, "EL_SCI/BATLOW ");
-	if (gpe0_sts & (1 <<  9)) printk(BIOS_DEBUG, "PCI_EXP ");
-	if (gpe0_sts & (1 <<  8)) printk(BIOS_DEBUG, "RI ");
-	if (gpe0_sts & (1 <<  7)) printk(BIOS_DEBUG, "SMB_WAK ");
-	if (gpe0_sts & (1 <<  6)) printk(BIOS_DEBUG, "TCO_SCI ");
-	if (gpe0_sts & (1 <<  5)) printk(BIOS_DEBUG, "AC97 ");
-	if (gpe0_sts & (1 <<  4)) printk(BIOS_DEBUG, "USB2 ");
-	if (gpe0_sts & (1 <<  3)) printk(BIOS_DEBUG, "USB1 ");
-	if (gpe0_sts & (1 <<  2)) printk(BIOS_DEBUG, "HOT_PLUG ");
-	if (gpe0_sts & (1 <<  0)) printk(BIOS_DEBUG, "THRM ");
-	printk(BIOS_DEBUG, "\n");
-}
-
-
-/**
- * @brief read and clear ALT_GP_SMI_STS
- * @return ALT_GP_SMI_STS register
- */
-static u16 reset_alt_gp_smi_status(void)
-{
-	u16 reg16;
-
-	reg16 = inl(pmbase + ALT_GP_SMI_STS);
-	/* set status bits are cleared by writing 1 to them */
-	outl(reg16, pmbase + ALT_GP_SMI_STS);
-
-	return reg16;
-}
-
-static void dump_alt_gp_smi_status(u16 alt_gp_smi_sts)
-{
-	int i;
-	printk(BIOS_DEBUG, "ALT_GP_SMI_STS: ");
-	for (i=15; i>= 0; i--) {
-		if (alt_gp_smi_sts & (1 << i)) printk(BIOS_DEBUG, "GPI%d ", i);
-	}
-	printk(BIOS_DEBUG, "\n");
-}
-
-
-
-/**
- * @brief read and clear TCOx_STS
- * @return TCOx_STS registers
- */
-static u32 reset_tco_status(void)
-{
-	u32 tcobase = pmbase + 0x60;
-	u32 reg32;
-
-	reg32 = inl(tcobase + 0x04);
-	/* set status bits are cleared by writing 1 to them */
-	outl(reg32 & ~(1<<18), tcobase + 0x04); //  Don't clear BOOT_STS before SECOND_TO_STS
-	if (reg32 & (1 << 18))
-		outl(reg32 & (1<<18), tcobase + 0x04); // clear BOOT_STS
-
-	return reg32;
-}
-
-
-static void dump_tco_status(u32 tco_sts)
-{
-	printk(BIOS_DEBUG, "TCO_STS: ");
-	if (tco_sts & (1 << 20)) printk(BIOS_DEBUG, "SMLINK_SLV ");
-	if (tco_sts & (1 << 18)) printk(BIOS_DEBUG, "BOOT ");
-	if (tco_sts & (1 << 17)) printk(BIOS_DEBUG, "SECOND_TO ");
-	if (tco_sts & (1 << 16)) printk(BIOS_DEBUG, "INTRD_DET ");
-	if (tco_sts & (1 << 12)) printk(BIOS_DEBUG, "DMISERR ");
-	if (tco_sts & (1 << 10)) printk(BIOS_DEBUG, "DMISMI ");
-	if (tco_sts & (1 <<  9)) printk(BIOS_DEBUG, "DMISCI ");
-	if (tco_sts & (1 <<  8)) printk(BIOS_DEBUG, "BIOSWR ");
-	if (tco_sts & (1 <<  7)) printk(BIOS_DEBUG, "NEWCENTURY ");
-	if (tco_sts & (1 <<  3)) printk(BIOS_DEBUG, "TIMEOUT ");
-	if (tco_sts & (1 <<  2)) printk(BIOS_DEBUG, "TCO_INT ");
-	if (tco_sts & (1 <<  1)) printk(BIOS_DEBUG, "SW_TCO ");
-	if (tco_sts & (1 <<  0)) printk(BIOS_DEBUG, "NMI2SMI ");
-	printk(BIOS_DEBUG, "\n");
-}
-
-
-
-/**
- * @brief Set the EOS bit
- */
-static void smi_set_eos(void)
-{
-	u8 reg8;
-
-	reg8 = inb(pmbase + SMI_EN);
-	reg8 |= EOS;
-	outb(reg8, pmbase + SMI_EN);
-}
-
-void southbridge_smm_init(void)
-{
-	u32 smi_en;
-	u16 pm1_en;
-	u32 gpe0_en;
-
-#if IS_ENABLED(CONFIG_ELOG)
-	/* Log events from chipset before clearing */
-	pch_log_state();
-#endif
-
-	printk(BIOS_DEBUG, "Initializing southbridge SMI...");
-
-	pmbase = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x1f, 0)),
-							PMBASE) & 0xff80;
-
-	printk(BIOS_SPEW, " ... pmbase = 0x%04x\n", pmbase);
-
-	smi_en = inl(pmbase + SMI_EN);
-	if (smi_en & APMC_EN) {
-		printk(BIOS_INFO, "SMI# handler already enabled?\n");
-		return;
-	}
-
-	printk(BIOS_DEBUG, "\n");
-	dump_smi_status(reset_smi_status());
-	dump_pm1_status(reset_pm1_status());
-	dump_gpe0_status(reset_gpe0_status());
-	dump_alt_gp_smi_status(reset_alt_gp_smi_status());
-	dump_tco_status(reset_tco_status());
-
-	/* Disable GPE0 PME_B0 */
-	gpe0_en = inl(pmbase + GPE0_EN);
-	gpe0_en &= ~PME_B0_EN;
-	outl(gpe0_en, pmbase + GPE0_EN);
-
-	pm1_en = 0;
-	pm1_en |= PWRBTN_EN;
-	pm1_en |= GBL_EN;
-	outw(pm1_en, pmbase + PM1_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)
-	 */
-
-	smi_en = 0; /* reset SMI enables */
-
-#if 0
-	smi_en |= LEGACY_USB2_EN | LEGACY_USB_EN;
-#endif
-	smi_en |= TCO_EN;
-	smi_en |= APMC_EN;
-#if DEBUG_PERIODIC_SMIS
-	/* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
-	 * periodic SMIs.
-	 */
-	smi_en |= PERIODIC_EN;
-#endif
-	smi_en |= SLP_SMI_EN;
-#if 0
-	smi_en |= BIOS_EN;
-#endif
-
-	/* The following need to be on for SMIs to happen */
-	smi_en |= EOS | GBL_SMI_EN;
-
-	outl(smi_en, pmbase + SMI_EN);
-}
-
-void southbridge_trigger_smi(void)
-{
-	/**
-	 * There are several methods of raising a controlled SMI# via
-	 * software, among them:
-	 *  - Writes to io 0xb2 (APMC)
-	 *  - Writes to the Local Apic ICR with Delivery mode SMI.
-	 *
-	 * Using the local apic is a bit more tricky. According to
-	 * AMD Family 11 Processor BKDG no destination shorthand must be
-	 * used.
-	 * The whole SMM initialization is quite a bit hardware specific, so
-	 * I'm not too worried about the better of the methods at the moment
-	 */
-
-	/* raise an SMI interrupt */
-	printk(BIOS_SPEW, "  ... raise SMI#\n");
-	outb(0x00, 0xb2);
-}
-
-void southbridge_clear_smi_status(void)
-{
-	/* Clear SMI status */
-	reset_smi_status();
-
-	/* Clear PM1 status */
-	reset_pm1_status();
-
-	/* Set EOS bit so other SMIs can occur. */
-	smi_set_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/southbridge/intel/bd82x6x/smihandler.c b/src/southbridge/intel/bd82x6x/smihandler.c
index 165acab..1fa7b10 100644
--- a/src/southbridge/intel/bd82x6x/smihandler.c
+++ b/src/southbridge/intel/bd82x6x/smihandler.c
@@ -32,43 +32,27 @@
 #include <southbridge/intel/bd82x6x/me.h>
 #include <southbridge/intel/common/gpio.h>
 #include <cpu/intel/model_206ax/model_206ax.h>
-
-/* While we read PMBASE dynamically in case it changed, let's
- * initialize it with a sane value
- */
-static u16 pmbase = DEFAULT_PMBASE;
-u16 smm_get_pmbase(void)
-{
-	return pmbase;
-}
+#include <southbridge/intel/common/pmutil.h>
 
 static u8 smm_initialized = 0;
 
+static u16 pmbase = DEFAULT_PMBASE;
+
 /* GNVS needs to be updated by an 0xEA PM Trap (B2) after it has been located
  * by coreboot.
  */
+
+u16 get_pmbase(void)
+{
+	return pmbase;
+}
+
 static global_nvs_t *gnvs;
 global_nvs_t *smm_get_gnvs(void)
 {
 	return gnvs;
 }
 
-static void alt_gpi_mask(u16 clr, u16 set)
-{
-	u16 alt_gp = inw(pmbase + ALT_GP_SMI_EN);
-	alt_gp &= ~clr;
-	alt_gp |= set;
-	outw(alt_gp, pmbase + ALT_GP_SMI_EN);
-}
-
-static void gpe0_mask(u32 clr, u32 set)
-{
-	u32 gpe0 = inl(pmbase + GPE0_EN);
-	gpe0 &= ~clr;
-	gpe0 |= set;
-	outl(gpe0, pmbase + GPE0_EN);
-}
-
 void gpi_route_interrupt(u8 gpi, u8 mode)
 {
 	u32 gpi_rout;
@@ -89,157 +73,6 @@
 		alt_gpi_mask(0, 1 << gpi);
 }
 
-/**
- * @brief read and clear PM1_STS
- * @return PM1_STS register
- */
-static u16 reset_pm1_status(void)
-{
-	u16 reg16;
-
-	reg16 = inw(pmbase + PM1_STS);
-	/* set status bits are cleared by writing 1 to them */
-	outw(reg16, pmbase + PM1_STS);
-
-	return reg16;
-}
-
-static void dump_pm1_status(u16 pm1_sts)
-{
-	printk(BIOS_SPEW, "PM1_STS: ");
-	if (pm1_sts & (1 << 15)) printk(BIOS_SPEW, "WAK ");
-	if (pm1_sts & (1 << 14)) printk(BIOS_SPEW, "PCIEXPWAK ");
-	if (pm1_sts & (1 << 11)) printk(BIOS_SPEW, "PRBTNOR ");
-	if (pm1_sts & (1 << 10)) printk(BIOS_SPEW, "RTC ");
-	if (pm1_sts & (1 <<  8)) printk(BIOS_SPEW, "PWRBTN ");
-	if (pm1_sts & (1 <<  5)) printk(BIOS_SPEW, "GBL ");
-	if (pm1_sts & (1 <<  4)) printk(BIOS_SPEW, "BM ");
-	if (pm1_sts & (1 <<  0)) printk(BIOS_SPEW, "TMROF ");
-	printk(BIOS_SPEW, "\n");
-	int reg16 = inw(pmbase + PM1_EN);
-	printk(BIOS_SPEW, "PM1_EN: %x\n", reg16);
-}
-
-/**
- * @brief read and clear SMI_STS
- * @return SMI_STS register
- */
-static u32 reset_smi_status(void)
-{
-	u32 reg32;
-
-	reg32 = inl(pmbase + SMI_STS);
-	/* set status bits are cleared by writing 1 to them */
-	outl(reg32, pmbase + SMI_STS);
-
-	return reg32;
-}
-
-static void dump_smi_status(u32 smi_sts)
-{
-	printk(BIOS_DEBUG, "SMI_STS: ");
-	if (smi_sts & (1 << 26)) printk(BIOS_DEBUG, "SPI ");
-	if (smi_sts & (1 << 21)) printk(BIOS_DEBUG, "MONITOR ");
-	if (smi_sts & (1 << 20)) printk(BIOS_DEBUG, "PCI_EXP_SMI ");
-	if (smi_sts & (1 << 18)) printk(BIOS_DEBUG, "INTEL_USB2 ");
-	if (smi_sts & (1 << 17)) printk(BIOS_DEBUG, "LEGACY_USB2 ");
-	if (smi_sts & (1 << 16)) printk(BIOS_DEBUG, "SMBUS_SMI ");
-	if (smi_sts & (1 << 15)) printk(BIOS_DEBUG, "SERIRQ_SMI ");
-	if (smi_sts & (1 << 14)) printk(BIOS_DEBUG, "PERIODIC ");
-	if (smi_sts & (1 << 13)) printk(BIOS_DEBUG, "TCO ");
-	if (smi_sts & (1 << 12)) printk(BIOS_DEBUG, "DEVMON ");
-	if (smi_sts & (1 << 11)) printk(BIOS_DEBUG, "MCSMI ");
-	if (smi_sts & (1 << 10)) printk(BIOS_DEBUG, "GPI ");
-	if (smi_sts & (1 <<  9)) printk(BIOS_DEBUG, "GPE0 ");
-	if (smi_sts & (1 <<  8)) printk(BIOS_DEBUG, "PM1 ");
-	if (smi_sts & (1 <<  6)) printk(BIOS_DEBUG, "SWSMI_TMR ");
-	if (smi_sts & (1 <<  5)) printk(BIOS_DEBUG, "APM ");
-	if (smi_sts & (1 <<  4)) printk(BIOS_DEBUG, "SLP_SMI ");
-	if (smi_sts & (1 <<  3)) printk(BIOS_DEBUG, "LEGACY_USB ");
-	if (smi_sts & (1 <<  2)) printk(BIOS_DEBUG, "BIOS ");
-	printk(BIOS_DEBUG, "\n");
-}
-
-
-/**
- * @brief read and clear GPE0_STS
- * @return GPE0_STS register
- */
-static u32 reset_gpe0_status(void)
-{
-	u32 reg32;
-
-	reg32 = inl(pmbase + GPE0_STS);
-	/* set status bits are cleared by writing 1 to them */
-	outl(reg32, pmbase + GPE0_STS);
-
-	return reg32;
-}
-
-static void dump_gpe0_status(u32 gpe0_sts)
-{
-	int i;
-	printk(BIOS_DEBUG, "GPE0_STS: ");
-	for (i=31; i>= 16; i--) {
-		if (gpe0_sts & (1 << i)) printk(BIOS_DEBUG, "GPIO%d ", (i-16));
-	}
-	if (gpe0_sts & (1 << 14)) printk(BIOS_DEBUG, "USB4 ");
-	if (gpe0_sts & (1 << 13)) printk(BIOS_DEBUG, "PME_B0 ");
-	if (gpe0_sts & (1 << 12)) printk(BIOS_DEBUG, "USB3 ");
-	if (gpe0_sts & (1 << 11)) printk(BIOS_DEBUG, "PME ");
-	if (gpe0_sts & (1 << 10)) printk(BIOS_DEBUG, "BATLOW ");
-	if (gpe0_sts & (1 <<  9)) printk(BIOS_DEBUG, "PCI_EXP ");
-	if (gpe0_sts & (1 <<  8)) printk(BIOS_DEBUG, "RI ");
-	if (gpe0_sts & (1 <<  7)) printk(BIOS_DEBUG, "SMB_WAK ");
-	if (gpe0_sts & (1 <<  6)) printk(BIOS_DEBUG, "TCO_SCI ");
-	if (gpe0_sts & (1 <<  5)) printk(BIOS_DEBUG, "AC97 ");
-	if (gpe0_sts & (1 <<  4)) printk(BIOS_DEBUG, "USB2 ");
-	if (gpe0_sts & (1 <<  3)) printk(BIOS_DEBUG, "USB1 ");
-	if (gpe0_sts & (1 <<  2)) printk(BIOS_DEBUG, "SWGPE ");
-	if (gpe0_sts & (1 <<  1)) printk(BIOS_DEBUG, "HOTPLUG ");
-	if (gpe0_sts & (1 <<  0)) printk(BIOS_DEBUG, "THRM ");
-	printk(BIOS_DEBUG, "\n");
-}
-
-
-/**
- * @brief read and clear TCOx_STS
- * @return TCOx_STS registers
- */
-static u32 reset_tco_status(void)
-{
-	u32 tcobase = pmbase + 0x60;
-	u32 reg32;
-
-	reg32 = inl(tcobase + 0x04);
-	/* set status bits are cleared by writing 1 to them */
-	outl(reg32 & ~(1<<18), tcobase + 0x04); //  Don't clear BOOT_STS before SECOND_TO_STS
-	if (reg32 & (1 << 18))
-		outl(reg32 & (1<<18), tcobase + 0x04); // clear BOOT_STS
-
-	return reg32;
-}
-
-
-static void dump_tco_status(u32 tco_sts)
-{
-	printk(BIOS_DEBUG, "TCO_STS: ");
-	if (tco_sts & (1 << 20)) printk(BIOS_DEBUG, "SMLINK_SLV ");
-	if (tco_sts & (1 << 18)) printk(BIOS_DEBUG, "BOOT ");
-	if (tco_sts & (1 << 17)) printk(BIOS_DEBUG, "SECOND_TO ");
-	if (tco_sts & (1 << 16)) printk(BIOS_DEBUG, "INTRD_DET ");
-	if (tco_sts & (1 << 12)) printk(BIOS_DEBUG, "DMISERR ");
-	if (tco_sts & (1 << 10)) printk(BIOS_DEBUG, "DMISMI ");
-	if (tco_sts & (1 <<  9)) printk(BIOS_DEBUG, "DMISCI ");
-	if (tco_sts & (1 <<  8)) printk(BIOS_DEBUG, "BIOSWR ");
-	if (tco_sts & (1 <<  7)) printk(BIOS_DEBUG, "NEWCENTURY ");
-	if (tco_sts & (1 <<  3)) printk(BIOS_DEBUG, "TIMEOUT ");
-	if (tco_sts & (1 <<  2)) printk(BIOS_DEBUG, "TCO_INT ");
-	if (tco_sts & (1 <<  1)) printk(BIOS_DEBUG, "SW_TCO ");
-	if (tco_sts & (1 <<  0)) printk(BIOS_DEBUG, "NMI2SMI ");
-	printk(BIOS_DEBUG, "\n");
-}
-
 int southbridge_io_trap_handler(int smif)
 {
 	switch (smif) {
diff --git a/src/southbridge/intel/common/Kconfig b/src/southbridge/intel/common/Kconfig
index 0d2e3b1..4f8a407 100644
--- a/src/southbridge/intel/common/Kconfig
+++ b/src/southbridge/intel/common/Kconfig
@@ -22,6 +22,9 @@
 config HAVE_INTEL_CHIPSET_LOCKDOWN
 	def_bool n
 
+config SOUTHBRIDGE_INTEL_COMMON_SMM
+	def_bool n
+
 config INTEL_CHIPSET_LOCKDOWN
 	depends on HAVE_INTEL_CHIPSET_LOCKDOWN && HAVE_SMI_HANDLER && !CHROMEOS
 	#ChromeOS's payload seems to handle finalization on its on.
diff --git a/src/southbridge/intel/common/Makefile.inc b/src/southbridge/intel/common/Makefile.inc
index 2feefcb..e054a14 100644
--- a/src/southbridge/intel/common/Makefile.inc
+++ b/src/southbridge/intel/common/Makefile.inc
@@ -36,4 +36,7 @@
 ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_PIRQ_ACPI_GEN) += acpi_pirq_gen.c
 ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_RCBA_PIRQ) += rcba_pirq.c
 
+ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SMM) += pmutil.c smi.c
+smm-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SMM) += pmutil.c
+
 endif
diff --git a/src/southbridge/intel/common/pmutil.c b/src/southbridge/intel/common/pmutil.c
new file mode 100644
index 0000000..96ad837
--- /dev/null
+++ b/src/southbridge/intel/common/pmutil.c
@@ -0,0 +1,243 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 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.
+ */
+
+#include <types.h>
+#include <arch/io.h>
+#include <console/console.h>
+#include <cpu/x86/cache.h>
+#include <device/pci_def.h>
+#include <cpu/x86/smm.h>
+#include <elog.h>
+#include <halt.h>
+#include <pc80/mc146818rtc.h>
+
+#include <southbridge/intel/common/gpio.h>
+
+#include "pmutil.h"
+
+void alt_gpi_mask(u16 clr, u16 set)
+{
+	u16 pmbase = get_pmbase();
+	u16 alt_gp = inw(pmbase + ALT_GP_SMI_EN);
+	alt_gp &= ~clr;
+	alt_gp |= set;
+	outw(alt_gp, pmbase + ALT_GP_SMI_EN);
+}
+
+void gpe0_mask(u32 clr, u32 set)
+{
+	u16 pmbase = get_pmbase();
+	u32 gpe0 = inl(pmbase + GPE0_EN);
+	gpe0 &= ~clr;
+	gpe0 |= set;
+	outl(gpe0, pmbase + GPE0_EN);
+}
+
+/**
+ * @brief read and clear PM1_STS
+ * @return PM1_STS register
+ */
+u16 reset_pm1_status(void)
+{
+	u16 pmbase = get_pmbase();
+	u16 reg16;
+
+	reg16 = inw(pmbase + PM1_STS);
+	/* set status bits are cleared by writing 1 to them */
+	outw(reg16, pmbase + PM1_STS);
+
+	return reg16;
+}
+
+void dump_pm1_status(u16 pm1_sts)
+{
+	printk(BIOS_SPEW, "PM1_STS: ");
+	if (pm1_sts & (1 << 15)) printk(BIOS_SPEW, "WAK ");
+	if (pm1_sts & (1 << 14)) printk(BIOS_SPEW, "PCIEXPWAK ");
+	if (pm1_sts & (1 << 11)) printk(BIOS_SPEW, "PRBTNOR ");
+	if (pm1_sts & (1 << 10)) printk(BIOS_SPEW, "RTC ");
+	if (pm1_sts & (1 <<  8)) printk(BIOS_SPEW, "PWRBTN ");
+	if (pm1_sts & (1 <<  5)) printk(BIOS_SPEW, "GBL ");
+	if (pm1_sts & (1 <<  4)) printk(BIOS_SPEW, "BM ");
+	if (pm1_sts & (1 <<  0)) printk(BIOS_SPEW, "TMROF ");
+	printk(BIOS_SPEW, "\n");
+	int reg16 = inw(get_pmbase() + PM1_EN);
+	printk(BIOS_SPEW, "PM1_EN: %x\n", reg16);
+}
+
+/**
+ * @brief read and clear SMI_STS
+ * @return SMI_STS register
+ */
+u32 reset_smi_status(void)
+{
+	u16 pmbase = get_pmbase();
+	u32 reg32;
+
+	reg32 = inl(pmbase + SMI_STS);
+	/* set status bits are cleared by writing 1 to them */
+	outl(reg32, pmbase + SMI_STS);
+
+	return reg32;
+}
+
+void dump_smi_status(u32 smi_sts)
+{
+	printk(BIOS_DEBUG, "SMI_STS: ");
+	if (smi_sts & (1 << 26)) printk(BIOS_DEBUG, "SPI ");
+	if (smi_sts & (1 << 21)) printk(BIOS_DEBUG, "MONITOR ");
+	if (smi_sts & (1 << 20)) printk(BIOS_DEBUG, "PCI_EXP_SMI ");
+	if (smi_sts & (1 << 18)) printk(BIOS_DEBUG, "INTEL_USB2 ");
+	if (smi_sts & (1 << 17)) printk(BIOS_DEBUG, "LEGACY_USB2 ");
+	if (smi_sts & (1 << 16)) printk(BIOS_DEBUG, "SMBUS_SMI ");
+	if (smi_sts & (1 << 15)) printk(BIOS_DEBUG, "SERIRQ_SMI ");
+	if (smi_sts & (1 << 14)) printk(BIOS_DEBUG, "PERIODIC ");
+	if (smi_sts & (1 << 13)) printk(BIOS_DEBUG, "TCO ");
+	if (smi_sts & (1 << 12)) printk(BIOS_DEBUG, "DEVMON ");
+	if (smi_sts & (1 << 11)) printk(BIOS_DEBUG, "MCSMI ");
+	if (smi_sts & (1 << 10)) printk(BIOS_DEBUG, "GPI ");
+	if (smi_sts & (1 <<  9)) printk(BIOS_DEBUG, "GPE0 ");
+	if (smi_sts & (1 <<  8)) printk(BIOS_DEBUG, "PM1 ");
+	if (smi_sts & (1 <<  6)) printk(BIOS_DEBUG, "SWSMI_TMR ");
+	if (smi_sts & (1 <<  5)) printk(BIOS_DEBUG, "APM ");
+	if (smi_sts & (1 <<  4)) printk(BIOS_DEBUG, "SLP_SMI ");
+	if (smi_sts & (1 <<  3)) printk(BIOS_DEBUG, "LEGACY_USB ");
+	if (smi_sts & (1 <<  2)) printk(BIOS_DEBUG, "BIOS ");
+	printk(BIOS_DEBUG, "\n");
+}
+
+
+/**
+ * @brief read and clear GPE0_STS
+ * @return GPE0_STS register
+ */
+u64 reset_gpe0_status(void)
+{
+	u16 pmbase = get_pmbase();
+	u32 reg_h, reg_l;
+
+	reg_l = inl(pmbase + GPE0_STS);
+	reg_h = inl(pmbase + GPE0_STS + 4);
+	/* set status bits are cleared by writing 1 to them */
+	outl(reg_l, pmbase + GPE0_STS);
+	outl(reg_h, pmbase + GPE0_STS + 4);
+
+	return (((u64)reg_h) << 32) | reg_l;
+}
+
+void dump_gpe0_status(u64 gpe0_sts)
+{
+	int i;
+	printk(BIOS_DEBUG, "GPE0_STS: ");
+	if (gpe0_sts & (1LL << 32)) printk(BIOS_DEBUG, "USB6 ");
+	for (i=31; i>= 16; i--) {
+		if (gpe0_sts & (1 << i)) printk(BIOS_DEBUG, "GPIO%d ", (i-16));
+	}
+	if (gpe0_sts & (1 << 14)) printk(BIOS_DEBUG, "USB4 ");
+	if (gpe0_sts & (1 << 13)) printk(BIOS_DEBUG, "PME_B0 ");
+	if (gpe0_sts & (1 << 12)) printk(BIOS_DEBUG, "USB3 ");
+	if (gpe0_sts & (1 << 11)) printk(BIOS_DEBUG, "PME ");
+	if (gpe0_sts & (1 << 10)) printk(BIOS_DEBUG, "EL_SCI/BATLOW ");
+	if (gpe0_sts & (1 <<  9)) printk(BIOS_DEBUG, "PCI_EXP ");
+	if (gpe0_sts & (1 <<  8)) printk(BIOS_DEBUG, "RI ");
+	if (gpe0_sts & (1 <<  7)) printk(BIOS_DEBUG, "SMB_WAK ");
+	if (gpe0_sts & (1 <<  6)) printk(BIOS_DEBUG, "TCO_SCI ");
+	if (gpe0_sts & (1 <<  5)) printk(BIOS_DEBUG, "USB5 ");
+	if (gpe0_sts & (1 <<  4)) printk(BIOS_DEBUG, "USB2 ");
+	if (gpe0_sts & (1 <<  3)) printk(BIOS_DEBUG, "USB1 ");
+	if (gpe0_sts & (1 <<  2)) printk(BIOS_DEBUG, "SWGPE ");
+	if (gpe0_sts & (1 <<  1)) printk(BIOS_DEBUG, "HOT_PLUG ");
+	if (gpe0_sts & (1 <<  0)) printk(BIOS_DEBUG, "THRM ");
+	printk(BIOS_DEBUG, "\n");
+}
+
+/**
+ * @brief read and clear TCOx_STS
+ * @return TCOx_STS registers
+ */
+u32 reset_tco_status(void)
+{
+	u32 tcobase = get_pmbase() + 0x60;
+	u32 reg32;
+
+	reg32 = inl(tcobase + 0x04);
+	/* set status bits are cleared by writing 1 to them */
+	outl(reg32 & ~(1<<18), tcobase + 0x04); //  Don't clear BOOT_STS before SECOND_TO_STS
+	if (reg32 & (1 << 18))
+		outl(reg32 & (1<<18), tcobase + 0x04); // clear BOOT_STS
+
+	return reg32;
+}
+
+
+void dump_tco_status(u32 tco_sts)
+{
+	printk(BIOS_DEBUG, "TCO_STS: ");
+	if (tco_sts & (1 << 20)) printk(BIOS_DEBUG, "SMLINK_SLV ");
+	if (tco_sts & (1 << 18)) printk(BIOS_DEBUG, "BOOT ");
+	if (tco_sts & (1 << 17)) printk(BIOS_DEBUG, "SECOND_TO ");
+	if (tco_sts & (1 << 16)) printk(BIOS_DEBUG, "INTRD_DET ");
+	if (tco_sts & (1 << 12)) printk(BIOS_DEBUG, "DMISERR ");
+	if (tco_sts & (1 << 10)) printk(BIOS_DEBUG, "DMISMI ");
+	if (tco_sts & (1 <<  9)) printk(BIOS_DEBUG, "DMISCI ");
+	if (tco_sts & (1 <<  8)) printk(BIOS_DEBUG, "BIOSWR ");
+	if (tco_sts & (1 <<  7)) printk(BIOS_DEBUG, "NEWCENTURY ");
+	if (tco_sts & (1 <<  3)) printk(BIOS_DEBUG, "TIMEOUT ");
+	if (tco_sts & (1 <<  2)) printk(BIOS_DEBUG, "TCO_INT ");
+	if (tco_sts & (1 <<  1)) printk(BIOS_DEBUG, "SW_TCO ");
+	if (tco_sts & (1 <<  0)) printk(BIOS_DEBUG, "NMI2SMI ");
+	printk(BIOS_DEBUG, "\n");
+}
+
+/**
+ * @brief Set the EOS bit
+ */
+void smi_set_eos(void)
+{
+	u16 pmbase = get_pmbase();
+	u8 reg8;
+
+	reg8 = inb(pmbase + SMI_EN);
+	reg8 |= EOS;
+	outb(reg8, pmbase + SMI_EN);
+}
+
+
+void dump_alt_gp_smi_status(u16 alt_gp_smi_sts)
+{
+	int i;
+	printk(BIOS_DEBUG, "ALT_GP_SMI_STS: ");
+	for (i=15; i>= 0; i--) {
+		if (alt_gp_smi_sts & (1 << i)) printk(BIOS_DEBUG, "GPI%d ", i);
+	}
+	printk(BIOS_DEBUG, "\n");
+}
+
+/**
+ * @brief read and clear ALT_GP_SMI_STS
+ * @return ALT_GP_SMI_STS register
+ */
+u16 reset_alt_gp_smi_status(void)
+{
+	u16 pmbase = get_pmbase();
+	u16 reg16;
+
+	reg16 = inl(pmbase + ALT_GP_SMI_STS);
+	/* set status bits are cleared by writing 1 to them */
+	outl(reg16, pmbase + ALT_GP_SMI_STS);
+
+	return reg16;
+}
diff --git a/src/southbridge/intel/common/pmutil.h b/src/southbridge/intel/common/pmutil.h
new file mode 100644
index 0000000..db2ec57
--- /dev/null
+++ b/src/southbridge/intel/common/pmutil.h
@@ -0,0 +1,111 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 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.
+ */
+
+#ifndef INTEL_COMMON_PMUTIL_H
+#define INTEL_COMMON_PMUTIL_H
+
+#define D31F0_PMBASE	0x40
+#define D31F0_GPIO_ROUT	0xb8
+#define GPI_DISABLE	0x00
+#define GPI_IS_SMI	0x01
+#define GPI_IS_SCI	0x02
+#define GPI_IS_NMI	0x03
+
+
+#define PM1_STS		0x00
+#define   WAK_STS	(1 << 15)
+#define   PCIEXPWAK_STS	(1 << 14)
+#define   PRBTNOR_STS	(1 << 11)
+#define   RTC_STS	(1 << 10)
+#define   PWRBTN_STS	(1 << 8)
+#define   GBL_STS	(1 << 5)
+#define   BM_STS	(1 << 4)
+#define   TMROF_STS	(1 << 0)
+#define PM1_EN		0x02
+#define   PCIEXPWAK_DIS	(1 << 14)
+#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   GBL_RLS	(1 << 2)
+#define   BM_RLD	(1 << 1)
+#define   SCI_EN	(1 << 0)
+#define PM1_TMR		0x08
+#define PROC_CNT	0x10
+#define LV2		0x14
+#define LV3		0x15
+#define LV4		0x16
+#define PM2_CNT		0x50 // mobile only
+#define GPE0_STS	0x20
+#define   PME_B0_STS	(1 << 13)
+#define   PME_STS	(1 << 11)
+#define   BATLOW_STS	(1 << 10)
+#define   PCI_EXP_STS	(1 << 9)
+#define   RI_STS	(1 << 8)
+#define   SMB_WAK_STS	(1 << 7)
+#define   TCOSCI_STS	(1 << 6)
+#define   SWGPE_STS	(1 << 2)
+#define   HOT_PLUG_STS	(1 << 1)
+#define GPE0_EN		0x28
+#define   PME_B0_EN	(1 << 13)
+#define   PME_EN	(1 << 11)
+#define   TCOSCI_EN	(1 << 6)
+#define SMI_EN		0x30
+#define   INTEL_USB2_EN	 (1 << 18) // Intel-Specific USB2 SMI logic
+#define   LEGACY_USB2_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   MCSMI_EN	 (1 << 11) // Trap microcontroller range access
+#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   LEGACY_USB_EN  (1 <<  3) // Legacy USB circuit SMI logic
+#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_GP_SMI_EN	0x38
+#define ALT_GP_SMI_STS	0x3a
+#define GPE_CNTL	0x42
+#define DEVACT_STS	0x44
+#define SS_CNT		0x50
+#define C3_RES		0x54
+#define TCO1_STS	0x64
+#define   DMISCI_STS	(1 << 9)
+#define TCO2_STS	0x66
+#define TCO1_CNT	0x68
+#define   TCO_LOCK	(1 << 12)
+#define TCO2_CNT	0x6a
+
+u16 get_pmbase(void);
+
+u16 reset_pm1_status(void);
+void dump_pm1_status(u16 pm1_sts);
+void dump_tco_status(u32 tco_sts);
+u32 reset_tco_status(void);
+void dump_gpe0_status(u64 gpe0_sts);
+u64 reset_gpe0_status(void);
+void dump_smi_status(u32 smi_sts);
+u32 reset_smi_status(void);
+void gpe0_mask(u32 clr, u32 set);
+void alt_gpi_mask(u16 clr, u16 set);
+void smi_set_eos(void);
+void dump_alt_gp_smi_status(u16 alt_gp_smi_sts);
+u16 reset_alt_gp_smi_status(void);
+
+#endif /*INTEL_COMMON_PMUTIL_H */
diff --git a/src/southbridge/intel/common/smi.c b/src/southbridge/intel/common/smi.c
new file mode 100644
index 0000000..762b704
--- /dev/null
+++ b/src/southbridge/intel/common/smi.c
@@ -0,0 +1,162 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008-2009 coresystems GmbH
+ *
+ * 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 <device/device.h>
+#include <device/pci.h>
+#include <console/console.h>
+#include <arch/io.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/smm.h>
+#include <string.h>
+#include <cpu/intel/smm/gen1/smi.h>
+
+#include "pmutil.h"
+
+#define DEBUG_PERIODIC_SMIS 0
+
+static u16 pmbase;
+
+u16 get_pmbase(void)
+{
+	return pmbase;
+}
+
+void southbridge_smm_init(void)
+{
+	u32 smi_en;
+	u16 pm1_en;
+	u32 gpe0_en;
+
+#if IS_ENABLED(CONFIG_ELOG)
+	/* Log events from chipset before clearing */
+	pch_log_state();
+#endif
+
+	printk(BIOS_DEBUG, "Initializing southbridge SMI...");
+
+	pmbase = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x1f, 0)),
+						D31F0_PMBASE) & 0xff80;
+
+	printk(BIOS_SPEW, " ... pmbase = 0x%04x\n", pmbase);
+
+	smi_en = inl(pmbase + SMI_EN);
+	if (smi_en & APMC_EN) {
+		printk(BIOS_INFO, "SMI# handler already enabled?\n");
+		return;
+	}
+
+	printk(BIOS_DEBUG, "\n");
+	dump_smi_status(reset_smi_status());
+	dump_pm1_status(reset_pm1_status());
+	dump_gpe0_status(reset_gpe0_status());
+	dump_alt_gp_smi_status(reset_alt_gp_smi_status());
+	dump_tco_status(reset_tco_status());
+
+	/* Disable GPE0 PME_B0 */
+	gpe0_en = inl(pmbase + GPE0_EN);
+	gpe0_en &= ~PME_B0_EN;
+	outl(gpe0_en, pmbase + GPE0_EN);
+
+	pm1_en = 0;
+	pm1_en |= PWRBTN_EN;
+	pm1_en |= GBL_EN;
+	outw(pm1_en, pmbase + PM1_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)
+	 */
+
+	smi_en = 0; /* reset SMI enables */
+
+#if 0
+	smi_en |= LEGACY_USB2_EN | LEGACY_USB_EN;
+#endif
+	smi_en |= TCO_EN;
+	smi_en |= APMC_EN;
+#if DEBUG_PERIODIC_SMIS
+	/* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
+	 * periodic SMIs.
+	 */
+	smi_en |= PERIODIC_EN;
+#endif
+	smi_en |= SLP_SMI_EN;
+#if 0
+	smi_en |= BIOS_EN;
+#endif
+
+	/* The following need to be on for SMIs to happen */
+	smi_en |= EOS | GBL_SMI_EN;
+
+	outl(smi_en, pmbase + SMI_EN);
+}
+
+void southbridge_trigger_smi(void)
+{
+	/**
+	 * There are several methods of raising a controlled SMI# via
+	 * software, among them:
+	 *  - Writes to io 0xb2 (APMC)
+	 *  - Writes to the Local Apic ICR with Delivery mode SMI.
+	 *
+	 * Using the local apic is a bit more tricky. According to
+	 * AMD Family 11 Processor BKDG no destination shorthand must be
+	 * used.
+	 * The whole SMM initialization is quite a bit hardware specific, so
+	 * I'm not too worried about the better of the methods at the moment
+	 */
+
+	/* raise an SMI interrupt */
+	printk(BIOS_SPEW, "  ... raise SMI#\n");
+	outb(0x00, 0xb2);
+}
+
+void southbridge_clear_smi_status(void)
+{
+	/* Clear SMI status */
+	reset_smi_status();
+
+	/* Clear PM1 status */
+	reset_pm1_status();
+
+	/* Set EOS bit so other SMIs can occur. */
+	smi_set_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)
+	);
+}

-- 
To view, visit https://review.coreboot.org/23427
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I28e2e6ad1e95a9e14462a456726a144ccdc63ec9
Gerrit-Change-Number: 23427
Gerrit-PatchSet: 1
Gerrit-Owner: Arthur Heymans <arthur at aheymans.xyz>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20180125/ecd7a007/attachment-0001.html>


More information about the coreboot-gerrit mailing list