aboutsummaryrefslogtreecommitdiff
path: root/src/southbridge
diff options
context:
space:
mode:
authorStefan Reinauer <stepan@coresystems.de>2010-12-18 23:29:37 +0000
committerStefan Reinauer <stepan@openbios.org>2010-12-18 23:29:37 +0000
commitcadc54583877db65f33d2db11088d5fae1b77b74 (patch)
tree86377962deb6e6b1faa2093828ff7cb3e127120b /src/southbridge
parent405721d45c8f7cd58c2466e43df8c2aee6f8e714 (diff)
SMM for AMD K8 Part 1/2
Signed-off-by: Stefan Reinauer <stepan@coresystems.de> Acked-by: Stefan Reinauer <stepan@coresystems.de> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@6201 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/southbridge')
-rw-r--r--src/southbridge/intel/i82801gx/i82801gx.h10
-rw-r--r--src/southbridge/intel/i82801gx/lpc.c2
-rw-r--r--src/southbridge/intel/i82801gx/smi.c9
-rw-r--r--src/southbridge/via/vt8237r/Makefile.inc1
-rw-r--r--src/southbridge/via/vt8237r/lpc.c16
-rw-r--r--src/southbridge/via/vt8237r/nvs.h46
-rw-r--r--src/southbridge/via/vt8237r/smihandler.c265
-rw-r--r--src/southbridge/via/vt8237r/vt8237r.h47
8 files changed, 378 insertions, 18 deletions
diff --git a/src/southbridge/intel/i82801gx/i82801gx.h b/src/southbridge/intel/i82801gx/i82801gx.h
index 37bcf572b9..208ff6d4af 100644
--- a/src/southbridge/intel/i82801gx/i82801gx.h
+++ b/src/southbridge/intel/i82801gx/i82801gx.h
@@ -38,18 +38,16 @@
#ifndef __ACPI__
#define DEBUG_PERIODIC_SMIS 0
-#if !defined(ASSEMBLY)
+#if !defined(ASSEMBLY) && !defined(__ROMCC__)
#if !defined(__PRE_RAM__)
#include "chip.h"
extern void i82801gx_enable(device_t dev);
-#endif
-void i82801gx_enable_usbdebug(unsigned int port);
-#endif
-
-#if defined(__PRE_RAM__) && !defined(__ROMCC__) && !defined(ASSEMBLY)
+#else
void enable_smbus(void);
int smbus_read_byte(unsigned device, unsigned address);
#endif
+void i82801gx_enable_usbdebug(unsigned int port);
+#endif
#define MAINBOARD_POWER_OFF 0
#define MAINBOARD_POWER_ON 1
diff --git a/src/southbridge/intel/i82801gx/lpc.c b/src/southbridge/intel/i82801gx/lpc.c
index f486c1ebf8..7feb76a5fb 100644
--- a/src/southbridge/intel/i82801gx/lpc.c
+++ b/src/southbridge/intel/i82801gx/lpc.c
@@ -27,6 +27,7 @@
#include <pc80/i8259.h>
#include <arch/io.h>
#include <arch/ioapic.h>
+#include <cpu/cpu.h>
#include "i82801gx.h"
#define NMI_OFF 0
@@ -335,7 +336,6 @@ static void enable_clock_gating(void)
#if CONFIG_HAVE_SMI_HANDLER
static void i82801gx_lock_smm(struct device *dev)
{
- void smm_lock(void);
#if TEST_SMM_FLASH_LOCKDOWN
u8 reg8;
#endif
diff --git a/src/southbridge/intel/i82801gx/smi.c b/src/southbridge/intel/i82801gx/smi.c
index 39d5c4dca2..95ec1129a3 100644
--- a/src/southbridge/intel/i82801gx/smi.c
+++ b/src/southbridge/intel/i82801gx/smi.c
@@ -318,8 +318,17 @@ static void smm_relocate(void)
outb(0x00, 0xb2);
}
+static int smm_handler_copied = 0;
+
static void smm_install(void)
{
+ /* The first CPU running this gets to copy the SMM handler. But not all
+ * of them.
+ */
+ if (smm_handler_copied)
+ return;
+ smm_handler_copied = 1;
+
/* enable the SMM memory window */
pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM,
D_OPEN | G_SMRAME | C_BASE_SEG);
diff --git a/src/southbridge/via/vt8237r/Makefile.inc b/src/southbridge/via/vt8237r/Makefile.inc
index dd14a00fdc..08545feca2 100644
--- a/src/southbridge/via/vt8237r/Makefile.inc
+++ b/src/southbridge/via/vt8237r/Makefile.inc
@@ -25,3 +25,4 @@ driver-y += sata.c
driver-y += usb.c
driver-$(CONFIG_PIRQ_ROUTE) += pirq.c
ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += fadt.c
+smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c
diff --git a/src/southbridge/via/vt8237r/lpc.c b/src/southbridge/via/vt8237r/lpc.c
index 72b85b37d5..3ffc377572 100644
--- a/src/southbridge/via/vt8237r/lpc.c
+++ b/src/southbridge/via/vt8237r/lpc.c
@@ -28,6 +28,7 @@
#include <pc80/mc146818rtc.h>
#include <arch/ioapic.h>
#include <cpu/x86/lapic.h>
+#include <cpu/cpu.h>
#include <pc80/keyboard.h>
#include <pc80/i8259.h>
#include <stdlib.h>
@@ -217,11 +218,8 @@ static void setup_pm(device_t dev)
/* Disable SMI on GPIO. */
outw(0x0, VT8237R_ACPI_IO_BASE + 0x24);
- /* Disable all global enable SMIs. */
- outw(0x0, VT8237R_ACPI_IO_BASE + 0x2a);
-
- /* All SMI off, both IDE buses ON, PSON rising edge. */
- outw(0x0, VT8237R_ACPI_IO_BASE + 0x2c);
+ /* Disable all global enable SMIs, except SW SMI */
+ outw(0x40, VT8237R_ACPI_IO_BASE + 0x2a);
/* Primary activity SMI disable. */
outl(0x0, VT8237R_ACPI_IO_BASE + 0x34);
@@ -238,6 +236,10 @@ static void setup_pm(device_t dev)
acpi_slp_type = ((tmp & (7 << 10)) >> 10) == 1 ? 3 : 0 ;
printk(BIOS_DEBUG, "SLP_TYP type was %x %x\n", tmp, acpi_slp_type);
#endif
+
+ /* All SMI on, both IDE buses ON, PSON rising edge. */
+ outw(0x1, VT8237R_ACPI_IO_BASE + 0x2c);
+
/* clear sleep */
tmp &= ~(7 << 10);
tmp |= 1;
@@ -500,7 +502,9 @@ static void vt8237_common_init(struct device *dev)
/* Enable serial IRQ, 6PCI clocks. */
pci_write_config8(dev, 0x52, 0x9);
-
+#endif
+#if CONFIG_HAVE_SMI_HANDLER
+ smm_lock();
#endif
/* Power management setup */
diff --git a/src/southbridge/via/vt8237r/nvs.h b/src/southbridge/via/vt8237r/nvs.h
new file mode 100644
index 0000000000..e8a0084c9f
--- /dev/null
+++ b/src/southbridge/via/vt8237r/nvs.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ *
+ * 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
+ */
+
+typedef struct {
+ /* Miscellaneous */
+ u16 osys; /* 0x00 - Operating System */
+ u8 smif; /* 0x02 - SMI function call ("TRAP") */
+ u8 prm0; /* 0x03 - SMI function call parameter */
+ u8 prm1; /* 0x04 - SMI function call parameter */
+ u8 scif; /* 0x05 - SCI function call (via _L00) */
+ u8 prm2; /* 0x06 - SCI function call parameter */
+ u8 prm3; /* 0x07 - SCI function call parameter */
+ u8 lckf; /* 0x08 - Global Lock function for EC */
+ u8 prm4; /* 0x09 - Lock function parameter */
+ u8 prm5; /* 0x0a - Lock function parameter */
+ u32 p80d; /* 0x0b - Debug port (IO 0x80) value */
+ u8 lids; /* 0x0f - LID state (open = 1) */
+ u8 pwrs; /* 0x10 - Power state (AC = 1) */
+ u8 dbgs; /* 0x11 - Debug state */
+ u8 linx; /* 0x12 - Linux OS */
+ u8 dckn; /* 0x13 - PCIe docking state */
+ u8 rsvd[0x28-0x14];
+ /* Processor Identification */
+ u8 apic; /* 0x28 - APIC enabled */
+ u8 mpen; /* 0x29 - MP capable/enabled */
+ u8 pcp0; /* 0x2a - PDC CPU/CORE 0 */
+ u8 pcp1; /* 0x2b - PDC CPU/CORE 1 */
+ u8 ppcm; /* 0x2c - Max. PPC state */
+} __attribute__((packed)) global_nvs_t;
+
diff --git a/src/southbridge/via/vt8237r/smihandler.c b/src/southbridge/via/vt8237r/smihandler.c
new file mode 100644
index 0000000000..344293dfa8
--- /dev/null
+++ b/src/southbridge/via/vt8237r/smihandler.c
@@ -0,0 +1,265 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008-2009 coresystems GmbH
+ * Copyright (C) 2010 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * 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 <types.h>
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+#include <console/console.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/smm.h>
+#include <device/pci_def.h>
+#include "vt8237r.h"
+
+#define APM_CNT 0xb2
+#define CST_CONTROL 0x85
+#define PST_CONTROL 0x80
+#define ACPI_DISABLE 0x1e
+#define ACPI_ENABLE 0xe1
+#define GNVS_UPDATE 0xea
+#define APM_STS 0xb3
+
+#include "nvs.h"
+
+/* While we read PMBASE dynamically in case it changed, let's
+ * initialize it with a sane value
+ */
+u16 pmbase = DEFAULT_PMBASE;
+u8 smm_initialized = 0;
+
+/* GNVS needs to be updated by an 0xEA PM Trap (B2) after it has been located
+ * by coreboot.
+ */
+global_nvs_t *gnvs = (global_nvs_t *)0x0;
+void *tcg = (void *)0x0;
+void *smi1 = (void *)0x0;
+
+#if 0
+/**
+ * @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);
+}
+#endif
+
+/**
+ * @brief read and clear SMI_STS
+ * @return SMI_STS register
+ */
+static u16 reset_smi_status(void)
+{
+ u16 reg16;
+
+ reg16 = inw(pmbase + SMI_STS);
+ /* set status bits are cleared by writing 1 to them */
+ outw(reg16, pmbase + SMI_STS);
+
+ return reg16;
+}
+
+static void dump_smi_status(u16 smi_sts)
+{
+ printk(BIOS_DEBUG, "SMI_STS: ");
+ if (smi_sts & (1 << 15)) printk(BIOS_DEBUG, "GPIO_RANGE_1 ");
+ if (smi_sts & (1 << 14)) printk(BIOS_DEBUG, "GPIO_RANGE_0 ");
+ if (smi_sts & (1 << 13)) printk(BIOS_DEBUG, "GP3_TIMEOUT ");
+ if (smi_sts & (1 << 12)) printk(BIOS_DEBUG, "GP2_TIMEOUT ");
+ if (smi_sts & (1 << 11)) printk(BIOS_DEBUG, "SERR_IRQ ");
+ if (smi_sts & (1 << 10)) printk(BIOS_DEBUG, "PMIO_5 ");
+ if (smi_sts & (1 << 9)) printk(BIOS_DEBUG, "THRMTRIP# ");
+ if (smi_sts & (1 << 8)) printk(BIOS_DEBUG, "CLKRUN# ");
+ if (smi_sts & (1 << 7)) printk(BIOS_DEBUG, "PRIMARY_IRQ/NMI/SMI ");
+ if (smi_sts & (1 << 6)) printk(BIOS_DEBUG, "SWSMI ");
+ if (smi_sts & (1 << 5)) printk(BIOS_DEBUG, "BIOS_STATUS ");
+ if (smi_sts & (1 << 4)) printk(BIOS_DEBUG, "LEGACY_USB ");
+ if (smi_sts & (1 << 3)) printk(BIOS_DEBUG, "GP1_TIMEOUT ");
+ if (smi_sts & (1 << 2)) printk(BIOS_DEBUG, "GP0_TIMEOUT ");
+ if (smi_sts & (1 << 1)) printk(BIOS_DEBUG, "SECONDARY_EVENT_TIMEOUT ");
+ if (smi_sts & (1 << 0)) printk(BIOS_DEBUG, "PRIMARY_ACTIVITY ");
+ printk(BIOS_DEBUG, "\n");
+}
+
+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;
+}
+
+/**
+ * @brief Set the EOS bit
+ */
+void southbridge_smi_set_eos(void)
+{
+ u8 reg8;
+
+ reg8 = inb(pmbase + SMI_EN);
+ reg8 |= EOS;
+ outb(reg8, pmbase + SMI_EN);
+}
+
+static void southbridge_smi_cmd(unsigned int node, smm_state_save_area_t *state_save)
+{
+ u16 pmctrl;
+ u8 reg8;
+
+ reg8 = inb(pmbase + 0x2f);
+ switch (reg8) {
+ case 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 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 ACPI_DISABLE:
+ pmctrl = inw(pmbase + PM1_CNT);
+ pmctrl &= ~SCI_EN;
+ outw(pmctrl, pmbase + PM1_CNT);
+ printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n");
+ break;
+ case ACPI_ENABLE:
+ pmctrl = inw(pmbase + PM1_CNT);
+ pmctrl |= SCI_EN;
+ outw(pmctrl, pmbase + PM1_CNT);
+ printk(BIOS_DEBUG, "SMI#: ACPI enabled.\n");
+ break;
+ case GNVS_UPDATE:
+ if (smm_initialized) {
+ printk(BIOS_DEBUG, "SMI#: SMM structures already initialized!\n");
+ return;
+ }
+ gnvs = *(global_nvs_t **)0x500;
+ tcg = *(void **)0x504;
+ smi1 = *(void **)0x508;
+ smm_initialized = 1;
+ printk(BIOS_DEBUG, "SMI#: Setting up structures to %p, %p, %p\n", gnvs, tcg, smi1);
+ break;
+ default:
+ printk(BIOS_DEBUG, "SMI#: Unknown function SMI_CMD=%02x\n", reg8);
+ }
+}
+
+typedef void (*smi_handler_t)(unsigned int node,
+ smm_state_save_area_t *state_save);
+
+smi_handler_t southbridge_smi[32] = {
+ NULL, // [0]
+ NULL, // [1]
+ NULL, // [2]
+ NULL, // [3]
+ southbridge_smi_cmd, // [4]
+ NULL, // [5]
+ NULL, // [6]
+ NULL, // [7]
+ NULL, // [8]
+ NULL, // [9]
+ NULL, // [10]
+ NULL, // [11]
+ NULL, // [12]
+ NULL, // [13]
+ NULL, // [14]
+ NULL, // [15]
+};
+
+/**
+ * @brief Interrupt handler for SMI#
+ *
+ * @param smm_revision revision of the smm state save map
+ */
+
+void southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save)
+{
+ int i, dump = 0;
+ u32 smi_sts;
+
+ /* Update global variable pmbase */
+ pmbase = pci_read_config16(PCI_DEV(0, 0x11, 0), 0x88) & 0xfffc;
+
+ /* We need to clear the SMI status registers, or we won't see what's
+ * happening in the following calls.
+ */
+ smi_sts = reset_smi_status();
+
+ /* Filter all non-enabled SMI events */
+ // FIXME Double check, this clears MONITOR
+ // smi_sts &= inl(pmbase + SMI_EN);
+
+ /* Call SMI sub handler for each of the status bits */
+ for (i = 0; i < 16; i++) {
+ if (smi_sts & (1 << i)) {
+ if (southbridge_smi[i])
+ southbridge_smi[i](node, state_save);
+ else {
+ printk(BIOS_DEBUG, "SMI_STS[%d] occured, but no "
+ "handler available.\n", i);
+ dump = 1;
+ }
+ }
+ }
+
+ if(dump) {
+ dump_smi_status(smi_sts);
+ }
+
+}
diff --git a/src/southbridge/via/vt8237r/vt8237r.h b/src/southbridge/via/vt8237r/vt8237r.h
index d187ce6dcf..94b1840361 100644
--- a/src/southbridge/via/vt8237r/vt8237r.h
+++ b/src/southbridge/via/vt8237r/vt8237r.h
@@ -20,12 +20,11 @@
#ifndef SOUTHBRIDGE_VIA_VT8237R_VT8237R_H
#define SOUTHBRIDGE_VIA_VT8237R_VT8237R_H
-#include <stdint.h>
-
/* Static resources for the VT8237R southbridge */
#define VT8237R_APIC_ID 0x2
#define VT8237R_ACPI_IO_BASE 0x500
+#define DEFAULT_PMBASE VT8237R_ACPI_IO_BASE
#define VT8237R_SMBUS_IO_BASE 0x400
/* 0x0 disabled, 0x2 reserved, 0xf = IRQ15 */
#define VT8237R_ACPI_IRQ 0x9
@@ -36,6 +35,36 @@
#endif
#define VT8237R_HPET_ADDR 0xfed00000ULL
+/* PMBASE FIXME mostly taken from ich7 */
+#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 SLP_EN (1 << 13)
+#define SLP_TYP (7 << 10)
+#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 SMI_STS 0x28
+#define SMI_EN 0x2d
+#define EOS (1 << 0)
+
/* IDE */
#define IDE_CS 0x40
#define IDE_CONF_I 0x41
@@ -107,6 +136,15 @@ __attribute__ ((packed))
#endif
;
+#define MAINBOARD_POWER_OFF 0
+#define MAINBOARD_POWER_ON 1
+#define MAINBOARD_POWER_KEEP 2
+
+#ifndef CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL
+#define CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
+#endif
+
+
#ifdef __PRE_RAM__
#ifndef __ROMCC__
u8 smbus_read_byte(u8 dimm, u8 offset);
@@ -119,10 +157,9 @@ void vt8237_early_spi_init(void);
int vt8237_early_network_init(struct vt8237_network_rom *rom);
#endif
#else
-#include <device/device.h>
-void writeback(struct device *dev, u16 where, u8 what);
+void writeback(device_t dev, u16 where, u8 what);
void dump_south(device_t dev);
-u32 vt8237_ide_80pin_detect(struct device *dev);
+u32 vt8237_ide_80pin_detect(device_t dev);
#endif
#endif