From a050817ce57ef960bf2bec3a18f23b59039dd184 Mon Sep 17 00:00:00 2001 From: Arthur Heymans Date: Thu, 25 Jan 2018 11:30:22 +0100 Subject: sb/intel/common: Add common code for SMM setup and smihandler This moves the sandybridge both smm setup and smihandler code to a common place. Tested on Thinkpad X220, still boots, resume to and from S3 is fine so smihandler is still working fine. Change-Id: I28e2e6ad1e95a9e14462a456726a144ccdc63ec9 Signed-off-by: Arthur Heymans Reviewed-on: https://review.coreboot.org/23427 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi --- src/southbridge/intel/common/pmutil.c | 242 ++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 src/southbridge/intel/common/pmutil.c (limited to 'src/southbridge/intel/common/pmutil.c') diff --git a/src/southbridge/intel/common/pmutil.c b/src/southbridge/intel/common/pmutil.c new file mode 100644 index 0000000000..97df2010fa --- /dev/null +++ b/src/southbridge/intel/common/pmutil.c @@ -0,0 +1,242 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#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; +} -- cgit v1.2.3