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
This commit is contained in:
parent
405721d45c
commit
cadc545838
|
@ -499,11 +499,6 @@ static void model_fxx_init(device_t dev)
|
|||
|
||||
k8_errata();
|
||||
|
||||
/* Set SMMLOCK to avoid exploits messing with SMM */
|
||||
msr = rdmsr(HWCR_MSR);
|
||||
msr.lo |= (1 << 0);
|
||||
wrmsr(HWCR_MSR, msr);
|
||||
|
||||
enable_cache();
|
||||
|
||||
/* Set the processor name string */
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smm_init.c
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 coresystems GmbH
|
||||
* Copyright (C) 2010 Rudolf Marek
|
||||
*
|
||||
* 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 <console/console.h>
|
||||
#include <arch/io.h>
|
||||
#include <cpu/cpu.h>
|
||||
#include <cpu/x86/lapic.h>
|
||||
#include <cpu/x86/msr.h>
|
||||
#include <cpu/x86/mtrr.h>
|
||||
#include <cpu/amd/mtrr.h>
|
||||
#include <cpu/amd/model_fxx_msr.h>
|
||||
#include <cpu/x86/cache.h>
|
||||
#include <cpu/x86/smm.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SMM_BASE_MSR 0xc0010111
|
||||
#define SMM_ADDR_MSR 0xc0010112
|
||||
#define SMM_MASK_MSR 0xc0010113
|
||||
#define SMM_BASE 0xa0000
|
||||
|
||||
extern unsigned char _binary_smm_start;
|
||||
extern unsigned char _binary_smm_size;
|
||||
|
||||
static int smm_handler_copied = 0;
|
||||
|
||||
void smm_init(void)
|
||||
{
|
||||
msr_t msr;
|
||||
|
||||
msr = rdmsr(HWCR_MSR);
|
||||
if (msr.lo & (1 << 0)) {
|
||||
// This sounds like a bug... ?
|
||||
printk(BIOS_DEBUG, "SMM is still locked from last boot, using old handler.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only copy SMM handler once, not once per CPU */
|
||||
if (!smm_handler_copied) {
|
||||
msr_t syscfg_orig, mtrr_aseg_orig;
|
||||
|
||||
smm_handler_copied = 1;
|
||||
|
||||
/* MTRR changes don't like an enabled cache */
|
||||
disable_cache();
|
||||
|
||||
/* Back up MSRs for later restore */
|
||||
syscfg_orig = rdmsr(SYSCFG_MSR);
|
||||
mtrr_aseg_orig = rdmsr(MTRRfix16K_A0000_MSR);
|
||||
|
||||
msr = syscfg_orig;
|
||||
/* Allow changes to MTRR extended attributes */
|
||||
msr.lo |= SYSCFG_MSR_MtrrFixDramModEn;
|
||||
/* turn the extended attributes off until we fix
|
||||
* them so A0000 is routed to memory
|
||||
*/
|
||||
msr.lo &= ~SYSCFG_MSR_MtrrFixDramEn;
|
||||
wrmsr(SYSCFG_MSR, msr);
|
||||
|
||||
/* set DRAM access to 0xa0000 */
|
||||
/* A0000 is memory */
|
||||
msr.lo = 0x18181818;
|
||||
msr.hi = 0x18181818;
|
||||
wrmsr(MTRRfix16K_A0000_MSR, msr);
|
||||
enable_cache();
|
||||
|
||||
/* disable the extended features */
|
||||
msr = syscfg_orig;
|
||||
msr.lo |= SYSCFG_MSR_MtrrFixDramModEn;
|
||||
msr.lo |= SYSCFG_MSR_MtrrFixDramEn;
|
||||
wrmsr(SYSCFG_MSR, msr);
|
||||
|
||||
/* enable the SMM memory window */
|
||||
// TODO does "Enable ASEG SMRAM Range" have to happen on
|
||||
// every CPU core?
|
||||
msr = rdmsr(SMM_MASK_MSR);
|
||||
msr.lo |= (1 << 0); // Enable ASEG SMRAM Range
|
||||
msr.lo &= ~(1 << 2); // Open ASEG SMRAM Range
|
||||
wrmsr(SMM_MASK_MSR, msr);
|
||||
|
||||
/* copy the real SMM handler */
|
||||
memcpy((void *)SMM_BASE, &_binary_smm_start, (size_t)&_binary_smm_size);
|
||||
wbinvd();
|
||||
|
||||
msr = rdmsr(SMM_MASK_MSR);
|
||||
msr.lo |= ~(1 << 2); // Close ASEG SMRAM Range
|
||||
wrmsr(SMM_MASK_MSR, msr);
|
||||
|
||||
/* Change SYSCFG so we can restore the MTRR */
|
||||
msr = syscfg_orig;
|
||||
msr.lo |= SYSCFG_MSR_MtrrFixDramModEn;
|
||||
msr.lo &= ~SYSCFG_MSR_MtrrFixDramEn;
|
||||
wrmsr(SYSCFG_MSR, msr);
|
||||
|
||||
/* Restore MTRR */
|
||||
disable_cache();
|
||||
wrmsr(MTRRfix16K_A0000_MSR, mtrr_aseg_orig);
|
||||
|
||||
/* Restore SYSCFG */
|
||||
wrmsr(SYSCFG_MSR, syscfg_orig);
|
||||
enable_cache();
|
||||
}
|
||||
|
||||
/* But set SMM base address on all CPUs/cores */
|
||||
msr = rdmsr(SMM_BASE_MSR);
|
||||
msr.lo = SMM_BASE - (lapicid() * 0x400);
|
||||
wrmsr(SMM_BASE_MSR, msr);
|
||||
}
|
||||
|
||||
void smm_lock(void)
|
||||
{
|
||||
// TODO I think this should be running on each CPU
|
||||
msr_t msr;
|
||||
|
||||
printk(BIOS_DEBUG, "Locking SMM.\n");
|
||||
|
||||
/* Set SMMLOCK to avoid exploits messing with SMM */
|
||||
msr = rdmsr(HWCR_MSR);
|
||||
msr.lo |= (1 << 0);
|
||||
wrmsr(HWCR_MSR, msr);
|
||||
}
|
|
@ -8,5 +8,7 @@ subdirs-y += ../../x86/lapic
|
|||
subdirs-y += ../../x86/cache
|
||||
subdirs-y += ../../x86/mtrr
|
||||
subdirs-y += ../../x86/pae
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../smm
|
||||
|
||||
cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
|
||||
|
|
|
@ -8,5 +8,7 @@ subdirs-y += ../../x86/lapic
|
|||
subdirs-y += ../../x86/cache
|
||||
subdirs-y += ../../x86/mtrr
|
||||
subdirs-y += ../../x86/pae
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../smm
|
||||
|
||||
cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
|
||||
|
|
|
@ -8,5 +8,7 @@ subdirs-y += ../../x86/lapic
|
|||
subdirs-y += ../../x86/cache
|
||||
subdirs-y += ../../x86/mtrr
|
||||
subdirs-y += ../../x86/pae
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../smm
|
||||
|
||||
cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
|
||||
|
|
|
@ -9,5 +9,6 @@ subdirs-y += ../../x86/cache
|
|||
subdirs-y += ../../x86/mtrr
|
||||
subdirs-y += ../../x86/pae
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../smm
|
||||
|
||||
cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
|
||||
|
|
|
@ -7,7 +7,8 @@ subdirs-y += ../../x86/tsc
|
|||
subdirs-y += ../../x86/lapic
|
||||
subdirs-y += ../../x86/cache
|
||||
subdirs-y += ../../x86/pae
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../../x86/mtrr
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../smm
|
||||
|
||||
cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
|
||||
|
|
|
@ -7,7 +7,8 @@ subdirs-y += ../../x86/tsc
|
|||
subdirs-y += ../../x86/lapic
|
||||
subdirs-y += ../../x86/cache
|
||||
subdirs-y += ../../x86/pae
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../../x86/mtrr
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../smm
|
||||
|
||||
cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
|
||||
|
|
|
@ -7,7 +7,8 @@ subdirs-y += ../../x86/tsc
|
|||
subdirs-y += ../../x86/lapic
|
||||
subdirs-y += ../../x86/cache
|
||||
subdirs-y += ../../x86/pae
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../../x86/mtrr
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../smm
|
||||
|
||||
cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
|
||||
|
|
|
@ -9,5 +9,6 @@ subdirs-y += ../../x86/cache
|
|||
subdirs-y += ../../x86/mtrr
|
||||
subdirs-y += ../../x86/pae
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../smm
|
||||
|
||||
cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
|
||||
|
|
|
@ -9,5 +9,6 @@ subdirs-y += ../../x86/cache
|
|||
subdirs-y += ../../x86/mtrr
|
||||
subdirs-y += ../../x86/pae
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../smm
|
||||
|
||||
cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
|
||||
|
|
|
@ -7,7 +7,8 @@ subdirs-y += ../../x86/tsc
|
|||
subdirs-y += ../../x86/lapic
|
||||
subdirs-y += ../../x86/cache
|
||||
subdirs-y += ../../x86/pae
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../../x86/mtrr
|
||||
subdirs-y += ../../x86/smm
|
||||
subdirs-y += ../smm
|
||||
|
||||
cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
|
||||
|
|
|
@ -87,6 +87,24 @@ static void smi_set_eos(void)
|
|||
southbridge_smi_set_eos();
|
||||
}
|
||||
|
||||
static u32 pci_orig;
|
||||
|
||||
/**
|
||||
* @brief Backup PCI address to make sure we do not mess up the OS
|
||||
*/
|
||||
static void smi_backup_pci_address(void)
|
||||
{
|
||||
pci_orig = inl(0xcf8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Restore PCI address previously backed up
|
||||
*/
|
||||
static void smi_restore_pci_address(void)
|
||||
{
|
||||
outl(pci_orig, 0xcf8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Interrupt handler for SMI#
|
||||
*
|
||||
|
@ -107,6 +125,8 @@ void smi_handler(u32 smm_revision)
|
|||
return;
|
||||
}
|
||||
|
||||
smi_backup_pci_address();
|
||||
|
||||
node=nodeid();
|
||||
|
||||
console_init();
|
||||
|
@ -147,6 +167,8 @@ void smi_handler(u32 smm_revision)
|
|||
if (southbridge_smi_handler)
|
||||
southbridge_smi_handler(node, &state_save);
|
||||
|
||||
smi_restore_pci_address();
|
||||
|
||||
smi_release_lock();
|
||||
|
||||
/* De-assert SMI# signal to allow another SMI */
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
// Make sure no stage 2 code is included:
|
||||
#define __PRE_RAM__
|
||||
|
||||
#if !defined(CONFIG_NORTHBRIDGE_AMD_AMDK8) && !defined(CONFIG_NORTHBRIDGE_AMD_FAM10)
|
||||
|
||||
// FIXME: Is this piece of code southbridge specific, or
|
||||
// can it be cleaned up so this include is not required?
|
||||
// It's needed right now because we get our DEFAULT_PMBASE from
|
||||
|
@ -177,4 +179,4 @@ smm_relocate:
|
|||
/* That's it. return */
|
||||
rsm
|
||||
smm_relocation_end:
|
||||
|
||||
#endif
|
||||
|
|
|
@ -254,7 +254,7 @@ void smi_handler(u32 smm_revision);
|
|||
|
||||
void io_trap_handler(int smif);
|
||||
int southbridge_io_trap_handler(int smif);
|
||||
int mainboard_io_trap_handler(int smif);
|
||||
int __attribute__((weak)) mainboard_io_trap_handler(int smif);
|
||||
|
||||
void southbridge_smi_set_eos(void);
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy
|
|||
select HAVE_MAINBOARD_RESOURCES
|
||||
select QRANK_DIMM_SUPPORT
|
||||
select SET_FIDVID
|
||||
# TODO test on multicore machines and enable if it works:
|
||||
#select HAVE_SMI_HANDLER
|
||||
|
||||
config MAINBOARD_DIR
|
||||
string
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <string.h>
|
||||
#include <arch/acpi.h>
|
||||
#include <device/device.h>
|
||||
#include "southbridge/via/vt8237r/vt8237r.h"
|
||||
|
||||
void acpi_create_fadt(acpi_fadt_t *fadt,acpi_facs_t *facs,void *dsdt){
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue