This patch implements MBI (modular bios interface) support to the i830 chipset.
This is needed on the IP1000T to get VGA output. The VGA option rom will ask
through an SMI for hardware specifics (in form of a VBT, video bios table)
which the SMI handler copies into the VGA option rom.
Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
Acked-by: Ronald G. Minnich <rminnich@gmail.com>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5177 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
diff --git a/src/Kconfig b/src/Kconfig
index dfb2d71..0fae6216 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -447,6 +447,66 @@
the "0x" prefix) and 3230 specifies the PCI device ID of the
video card (also in hex, without "0x" prefix).
+config INTEL_MBI
+ bool "Add an MBI image"
+ depends on NORTHBRIDGE_INTEL_I82830
+ help
+ Select this option if you have an Intel MBI image that you would
+ like to add to your ROM.
+
+ You will be able to specify the location and file name of the
+ image later.
+
+config FALLBACK_MBI_FILE
+ string "Intel MBI path and filename"
+ depends on INTEL_MBI
+ default "mbi.bin"
+ help
+ The path and filename of the file to use as VGA BIOS.
+
+endmenu
+
+menu "Bootsplash"
+ depends on PCI_OPTION_ROM_RUN_YABEL
+
+config BOOTSPLASH
+ prompt "Show graphical bootsplash"
+ bool
+ depends on PCI_OPTION_ROM_RUN_YABEL
+ help
+ This option shows a graphical bootsplash screen. The grapics are
+ loaded from the CBFS file bootsplash.jpg.
+
+config FALLBACK_BOOTSPLASH_FILE
+ string "Bootsplash path and filename"
+ depends on BOOTSPLASH
+ default "bootsplash.jpg"
+ help
+ The path and filename of the file to use as graphical bootsplash
+ screen. The file format has to be jpg.
+
+# TODO: Turn this into a "choice".
+config FRAMEBUFFER_VESA_MODE
+ prompt "VESA framebuffer video mode"
+ hex
+ default 0x117
+ depends on BOOTSPLASH
+ help
+ This option sets the resolution used for the coreboot framebuffer and
+ bootsplash screen. Set to 0x117 for 1024x768x16. A diligent soul will
+ some day make this a "choice".
+
+config COREBOOT_KEEP_FRAMEBUFFER
+ prompt "Keep VESA framebuffer"
+ bool
+ depends on BOOTSPLASH
+ help
+ This option keeps the framebuffer mode set after coreboot finishes
+ execution. If this option is enabled, coreboot will pass a
+ framebuffer entry in its coreboot table and the payload will need a
+ framebuffer driver. If this option is disabled, coreboot will switch
+ back to text mode before handing control to a payload.
+
endmenu
menu "Debugging"
diff --git a/src/arch/i386/Makefile.inc b/src/arch/i386/Makefile.inc
index e24bd1b..a16972c 100644
--- a/src/arch/i386/Makefile.inc
+++ b/src/arch/i386/Makefile.inc
@@ -28,6 +28,14 @@
@printf " VGABIOS $(CONFIG_FALLBACK_VGA_BIOS_FILE) $(CONFIG_FALLBACK_VGA_BIOS_ID)\n"
$(CBFSTOOL) $(obj)/coreboot.rom add $(CONFIG_FALLBACK_VGA_BIOS_FILE) "pci$(CONFIG_FALLBACK_VGA_BIOS_ID).rom" optionrom
endif
+ifeq ($(CONFIG_INTEL_MBI),y)
+ @printf " MBI $(CONFIG_FALLBACK_MBI_FILE)\n"
+ $(CBFSTOOL) $(obj)/coreboot.rom add $(CONFIG_FALLBACK_MBI_FILE) mbi.bin mbi
+endif
+ifeq ($(CONFIG_BOOTSPLASH),y)
+ @printf " BOOTSPLASH $(CONFIG_FALLBACK_BOOTSPLASH_FILE)\n"
+ $(CBFSTOOL) $(obj)/coreboot.rom add $(CONFIG_FALLBACK_BOOTSPLASH_FILE) bootsplash.jpg bootsplash
+endif
@printf " CBFSPRINT $(subst $(obj)/,,$(@))\n\n"
$(CBFSTOOL) $(obj)/coreboot.rom print
diff --git a/src/devices/Kconfig b/src/devices/Kconfig
index 08e532d..5e13e4e 100644
--- a/src/devices/Kconfig
+++ b/src/devices/Kconfig
@@ -167,36 +167,6 @@
they can still access all devices in the system.
Enable this option for a good compromise between security and speed.
-config BOOTSPLASH
- prompt "Show graphical bootsplash"
- bool
- depends on PCI_OPTION_ROM_RUN_YABEL
- help
- This option shows a graphical bootsplash screen. The grapics are
- loaded from the CBFS file bootsplash.jpg.
-
-# TODO: Turn this into a "choice".
-config FRAMEBUFFER_VESA_MODE
- prompt "VESA framebuffer video mode"
- hex
- default 0x117
- depends on BOOTSPLASH
- help
- This option sets the resolution used for the coreboot framebuffer and
- bootsplash screen. Set to 0x117 for 1024x768x16. A diligent soul will
- some day make this a "choice".
-
-config COREBOOT_KEEP_FRAMEBUFFER
- prompt "Keep VESA framebuffer"
- bool
- depends on BOOTSPLASH
- help
- This option keeps the framebuffer mode set after coreboot finishes
- execution. If this option is enabled, coreboot will pass a
- framebuffer entry in its coreboot table and the payload will need a
- framebuffer driver. If this option is disabled, coreboot will switch
- back to text mode before handing control to a payload.
-
config CONSOLE_VGA_MULTI
bool
default n
diff --git a/src/include/cbfs.h b/src/include/cbfs.h
index 38f18a4..d169c28 100644
--- a/src/include/cbfs.h
+++ b/src/include/cbfs.h
@@ -63,9 +63,14 @@
Users are welcome to use any other value for their
components */
-#define CBFS_TYPE_STAGE 0x10
-#define CBFS_TYPE_PAYLOAD 0x20
-#define CBFS_TYPE_OPTIONROM 0x30
+#define CBFS_TYPE_STAGE 0x10
+#define CBFS_TYPE_PAYLOAD 0x20
+#define CBFS_TYPE_OPTIONROM 0x30
+#define CBFS_TYPE_BOOTSPLASH 0x40
+#define CBFS_TYPE_RAW 0x50
+#define CBFS_TYPE_VSA 0x51
+#define CBFS_TYPE_MBI 0x52
+#define CBFS_TYPE_MICROCODE 0x53
/** this is the master cbfs header - it need to be
located somewhere in the bootblock. Where it
@@ -164,11 +169,8 @@
void * cbfs_get_file(const char *name);
void *cbfs_load_optionrom(u16 vendor, u16 device, void * dest);
int run_address(void *f);
-int cbfs_decompress(int algo, void *src, void *dst, int len);
-struct cbfs_stage *cbfs_find_file(const char *name, int type);
-int cbfs_check_magic(struct cbfs_file *file);
-struct cbfs_header *cbfs_master_header(void);
struct cbfs_file *cbfs_find(const char *name);
+void *cbfs_find_file(const char *name, int type);
void cbfs_and_run_core(const char *filename, unsigned int ebp);
#endif
diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc
index cbff717..95c10cf 100644
--- a/src/lib/Makefile.inc
+++ b/src/lib/Makefile.inc
@@ -31,3 +31,5 @@
ifdef POST_EVALUATION
$(obj)/lib/version.o :: $(obj)/build.h
endif
+
+smmobj-y += memcpy.o
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c
index 0bb6e83..e694952 100644
--- a/src/lib/cbfs.c
+++ b/src/lib/cbfs.c
@@ -24,7 +24,16 @@
#include <lib.h>
#include <arch/byteorder.h>
-int cbfs_decompress(int algo, void *src, void *dst, int len)
+
+/**
+ * Decompression wrapper for CBFS
+ * @param algo
+ * @param src
+ * @param dst
+ * @param len
+ * @return 0 on success, -1 on failure
+ */
+static int cbfs_decompress(int algo, void *src, void *dst, int len)
{
switch(algo) {
case CBFS_COMPRESS_NONE:
@@ -44,12 +53,12 @@
}
}
-int cbfs_check_magic(struct cbfs_file *file)
+static int cbfs_check_magic(struct cbfs_file *file)
{
return !strcmp(file->magic, CBFS_FILE_MAGIC) ? 1 : 0;
}
-struct cbfs_header *cbfs_master_header(void)
+static struct cbfs_header *cbfs_master_header(void)
{
struct cbfs_header *header;
@@ -103,7 +112,7 @@
}
}
-struct cbfs_stage *cbfs_find_file(const char *name, int type)
+void *cbfs_find_file(const char *name, int type)
{
struct cbfs_file *file = cbfs_find(name);
@@ -123,7 +132,7 @@
return (void *) CBFS_SUBHEADER(file);
}
-static int tohex4(unsigned int c)
+static inline int tohex4(unsigned int c)
{
return (c<=9)?(c+'0'):(c-10+'a');
}
@@ -205,11 +214,6 @@
return (void *) entry;
}
-void * cbfs_get_file(const char *name)
-{
- return (void *) cbfs_find(name);
-}
-
int cbfs_execute_stage(const char *name)
{
struct cbfs_stage *stage = (struct cbfs_stage *)
@@ -233,7 +237,7 @@
* run_address is passed the address of a function taking no parameters and
* jumps to it, returning the result.
* @param f the address to call as a function.
- * returns value returned by the function.
+ * @return value returned by the function.
*/
int run_address(void *f)
diff --git a/src/mainboard/rca/rm4100/Kconfig b/src/mainboard/rca/rm4100/Kconfig
index cdca002..1654128 100644
--- a/src/mainboard/rca/rm4100/Kconfig
+++ b/src/mainboard/rca/rm4100/Kconfig
@@ -9,6 +9,7 @@
select HAVE_PIRQ_TABLE
select UDELAY_TSC
select BOARD_ROMSIZE_KB_512
+ select HAVE_SMI_HANDLER
config MAINBOARD_DIR
string
diff --git a/src/mainboard/rca/rm4100/Makefile.inc b/src/mainboard/rca/rm4100/Makefile.inc
index 5688262..38a5a61 100644
--- a/src/mainboard/rca/rm4100/Makefile.inc
+++ b/src/mainboard/rca/rm4100/Makefile.inc
@@ -1 +1,4 @@
ROMCCFLAGS=-mcpu=p3 -O
+
+smmobj-$(CONFIG_HAVE_SMI_HANDLER) += mainboard_smi.o
+
diff --git a/src/mainboard/rca/rm4100/devicetree.cb b/src/mainboard/rca/rm4100/devicetree.cb
index 2b04ad7..4dff3be 100644
--- a/src/mainboard/rca/rm4100/devicetree.cb
+++ b/src/mainboard/rca/rm4100/devicetree.cb
@@ -1,4 +1,9 @@
chip northbridge/intel/i82830 # Northbridge
+ device apic_cluster 0 on # APIC cluster
+ chip cpu/intel/socket_PGA370 # Mobile Celeron Micro-FCBGA Socket 479
+ device apic 0 on end # APIC
+ end
+ end
device pci_domain 0 on # PCI domain
device pci 0.0 on end # Host bridge
device pci 2.0 on end # VGA (Intel 82830 CGC)
@@ -19,9 +24,7 @@
device pci 1d.1 on end # USB UHCI Controller #2
device pci 1d.2 on end # USB UHCI Controller #3
device pci 1d.7 on end # USB2 EHCI Controller
- device pci 1e.0 on # PCI bridge
- device pci 08.0 on end # Intel 82801DB PRO/100 VE Ethernet
- end
+ device pci 1e.0 on end # PCI bridge
device pci 1f.0 on # ISA/LPC bridge
chip superio/smsc/smscsuperio # Super I/O
device pnp 2e.0 off # Floppy
@@ -61,10 +64,5 @@
device pci 1f.6 on end # AC'97 modem
end
end
- device apic_cluster 0 on # APIC cluster
- chip cpu/intel/socket_PGA370 # Mobile Celeron Micro-FCBGA Socket 479
- device apic 0 on end # APIC
- end
- end
end
diff --git a/src/mainboard/rca/rm4100/mainboard.c b/src/mainboard/rca/rm4100/mainboard.c
index cb90749..0324266 100644
--- a/src/mainboard/rca/rm4100/mainboard.c
+++ b/src/mainboard/rca/rm4100/mainboard.c
@@ -21,6 +21,18 @@
#include <device/device.h>
#include "chip.h"
+static void mainboard_init(device_t dev)
+{
+ // TODO Switch parport LEDs again
+}
+
+static void mainboard_enable(device_t dev)
+{
+ // TODO Switch parport LEDs
+ dev->ops->init = mainboard_init;
+}
+
struct chip_operations mainboard_ops = {
+ .enable_dev = mainboard_enable,
CHIP_NAME("RCA RM4100 Mainboard")
};
diff --git a/src/mainboard/rca/rm4100/mainboard_smi.c b/src/mainboard/rca/rm4100/mainboard_smi.c
new file mode 100644
index 0000000..3e24235
--- /dev/null
+++ b/src/mainboard/rca/rm4100/mainboard_smi.c
@@ -0,0 +1,30 @@
+/*
+ * 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
+ */
+
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+#include <console/console.h>
+
+int mainboard_io_trap_handler(int smif)
+{
+ printk_debug("MAINBOARD IO TRAP HANDLER!\n");
+ return 1;
+}
diff --git a/src/mainboard/rca/rm4100/romstage.c b/src/mainboard/rca/rm4100/romstage.c
index cf74644..8b70d9ff 100644
--- a/src/mainboard/rca/rm4100/romstage.c
+++ b/src/mainboard/rca/rm4100/romstage.c
@@ -45,6 +45,7 @@
#define SERIAL_DEV PNP_DEV(0x2e, SMSCSUPERIO_SP1)
#include "southbridge/intel/i82801dx/i82801dx_early_smbus.c"
+#include "southbridge/intel/i82801dx/i82801dx_tco_timer.c"
/**
* The onboard 64MB PC133 memory does not have a SPD EEPROM so the
@@ -102,11 +103,12 @@
static void main(unsigned long bist)
{
- if (bist == 0)
+ if (bist == 0) {
early_mtrr_init();
if (memory_initialized()) {
hard_reset();
}
+ }
/* Set southbridge and superio gpios */
mb_gpio_init();
@@ -118,6 +120,9 @@
/* Halt if there was a built in self test failure. */
report_bist_failure(bist);
+ /* disable TCO timers */
+ i82801dx_halt_tco_timer();
+
/* Setup mainboard specific registers */
mb_early_setup();
diff --git a/src/mainboard/thomson/ip1000/Kconfig b/src/mainboard/thomson/ip1000/Kconfig
index b78a20e..48ab245 100644
--- a/src/mainboard/thomson/ip1000/Kconfig
+++ b/src/mainboard/thomson/ip1000/Kconfig
@@ -9,6 +9,7 @@
select HAVE_PIRQ_TABLE
select UDELAY_TSC
select BOARD_ROMSIZE_KB_512
+ select HAVE_SMI_HANDLER
config MAINBOARD_DIR
string
diff --git a/src/mainboard/thomson/ip1000/Makefile.inc b/src/mainboard/thomson/ip1000/Makefile.inc
index 5688262..38a5a61 100644
--- a/src/mainboard/thomson/ip1000/Makefile.inc
+++ b/src/mainboard/thomson/ip1000/Makefile.inc
@@ -1 +1,4 @@
ROMCCFLAGS=-mcpu=p3 -O
+
+smmobj-$(CONFIG_HAVE_SMI_HANDLER) += mainboard_smi.o
+
diff --git a/src/mainboard/thomson/ip1000/devicetree.cb b/src/mainboard/thomson/ip1000/devicetree.cb
index f38c1c3..a3ee26c 100644
--- a/src/mainboard/thomson/ip1000/devicetree.cb
+++ b/src/mainboard/thomson/ip1000/devicetree.cb
@@ -1,4 +1,10 @@
chip northbridge/intel/i82830 # Northbridge
+ device apic_cluster 0 on # APIC cluster
+ chip cpu/intel/socket_PGA370 # Low Voltage PIII Micro-FCBGA Socket 479
+ device apic 0 on end # APIC
+ end
+ end
+
device pci_domain 0 on # PCI domain
device pci 0.0 on end # Host bridge
device pci 2.0 on end # VGA (Intel 82830 CGC)
@@ -19,9 +25,7 @@
device pci 1d.1 on end # USB UHCI Controller #2
device pci 1d.2 on end # USB UHCI Controller #3
device pci 1d.7 on end # USB2 EHCI Controller
- device pci 1e.0 on # PCI bridge
- device pci 08.0 on end # Intel 82801DB PRO/100 VE Ethernet
- end
+ device pci 1e.0 on end # PCI bridge
device pci 1f.0 on # ISA/LPC bridge
chip superio/smsc/smscsuperio # Super I/O
device pnp 2e.0 off # Floppy
@@ -61,10 +65,5 @@
device pci 1f.6 off end # AC'97 modem
end
end
- device apic_cluster 0 on # APIC cluster
- chip cpu/intel/socket_PGA370 # Low Voltage PIII Micro-FCBGA Socket 479
- device apic 0 on end # APIC
- end
- end
end
diff --git a/src/mainboard/thomson/ip1000/mainboard.c b/src/mainboard/thomson/ip1000/mainboard.c
index c6b4cdf..daa6b7e 100644
--- a/src/mainboard/thomson/ip1000/mainboard.c
+++ b/src/mainboard/thomson/ip1000/mainboard.c
@@ -21,6 +21,18 @@
#include <device/device.h>
#include "chip.h"
+static void mainboard_init(device_t dev)
+{
+ // TODO Switch parport LEDs again
+}
+
+static void mainboard_enable(device_t dev)
+{
+ // TODO Switch parport LEDs
+ dev->ops->init = mainboard_init;
+}
+
struct chip_operations mainboard_ops = {
+ .enable_dev = mainboard_enable,
CHIP_NAME("THOMSON IP1000 Mainboard")
};
diff --git a/src/mainboard/thomson/ip1000/mainboard_smi.c b/src/mainboard/thomson/ip1000/mainboard_smi.c
new file mode 100644
index 0000000..3e24235
--- /dev/null
+++ b/src/mainboard/thomson/ip1000/mainboard_smi.c
@@ -0,0 +1,30 @@
+/*
+ * 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
+ */
+
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+#include <console/console.h>
+
+int mainboard_io_trap_handler(int smif)
+{
+ printk_debug("MAINBOARD IO TRAP HANDLER!\n");
+ return 1;
+}
diff --git a/src/mainboard/thomson/ip1000/romstage.c b/src/mainboard/thomson/ip1000/romstage.c
index cf74644..8b70d9ff 100644
--- a/src/mainboard/thomson/ip1000/romstage.c
+++ b/src/mainboard/thomson/ip1000/romstage.c
@@ -45,6 +45,7 @@
#define SERIAL_DEV PNP_DEV(0x2e, SMSCSUPERIO_SP1)
#include "southbridge/intel/i82801dx/i82801dx_early_smbus.c"
+#include "southbridge/intel/i82801dx/i82801dx_tco_timer.c"
/**
* The onboard 64MB PC133 memory does not have a SPD EEPROM so the
@@ -102,11 +103,12 @@
static void main(unsigned long bist)
{
- if (bist == 0)
+ if (bist == 0) {
early_mtrr_init();
if (memory_initialized()) {
hard_reset();
}
+ }
/* Set southbridge and superio gpios */
mb_gpio_init();
@@ -118,6 +120,9 @@
/* Halt if there was a built in self test failure. */
report_bist_failure(bist);
+ /* disable TCO timers */
+ i82801dx_halt_tco_timer();
+
/* Setup mainboard specific registers */
mb_early_setup();
diff --git a/src/northbridge/intel/i82830/Makefile.inc b/src/northbridge/intel/i82830/Makefile.inc
index 3ebb8a5..57dedfd 100644
--- a/src/northbridge/intel/i82830/Makefile.inc
+++ b/src/northbridge/intel/i82830/Makefile.inc
@@ -1,2 +1,4 @@
driver-y += northbridge.o
driver-y += vga.o
+
+smmobj-$(CONFIG_HAVE_SMI_HANDLER) += i82830_smihandler.o
diff --git a/src/northbridge/intel/i82830/i82830_smihandler.c b/src/northbridge/intel/i82830/i82830_smihandler.c
new file mode 100644
index 0000000..ae5d5e2
--- /dev/null
+++ b/src/northbridge/intel/i82830/i82830_smihandler.c
@@ -0,0 +1,374 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 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
+ */
+
+#include <types.h>
+#include <string.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 "i82830.h"
+
+extern unsigned char *mbi;
+extern u32 mbi_len;
+
+#define DEBUG_SMI
+
+/* If YABEL is enabled and it's not running at 0x00000000, we have to add some
+ * offset to all our mbi object memory accesses
+ */
+#if defined(CONFIG_PCI_OPTION_ROM_RUN_YABEL) && !defined(CONFIG_YABEL_DIRECTHW)
+#define OBJ_OFFSET CONFIG_YABEL_VIRTMEM_LOCATION
+#else
+#define OBJ_OFFSET 0x00000
+#endif
+
+/* I830M */
+#define SMRAM 0x90
+#define D_OPEN (1 << 6)
+#define D_CLS (1 << 5)
+#define D_LCK (1 << 4)
+#define G_SMRANE (1 << 3)
+#define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0))
+
+
+typedef struct {
+ u32 mhid;
+ u32 function;
+ u32 retsts;
+ u32 rfu;
+} __attribute__((packed)) banner_id_t;
+
+#define MSH_OK 0x0000
+#define MSH_OK_RESTART 0x0001
+#define MSH_FWH_ERR 0x00ff
+#define MSH_IF_BAD_ID 0x0100
+#define MSH_IF_BAD_FUNC 0x0101
+#define MSH_IF_MBI_CORRUPT 0x0102
+#define MSH_IF_BAD_HANDLE 0x0103
+#define MSH_ALRDY_ATCHED 0x0104
+#define MSH_NOT_ATCHED 0x0105
+#define MSH_IF 0x0106
+#define MSH_IF_INVADDR 0x0107
+#define MSH_IF_UKN_TYPE 0x0108
+#define MSH_IF_NOT_FOUND 0x0109
+#define MSH_IF_NO_KEY 0x010a
+#define MSH_IF_BUF_SIZE 0x010b
+#define MSH_IF_NOT_PENDING 0x010c
+
+static void
+dump(u8 * addr, u32 len)
+{
+ printk_debug("\n%s(%p, %x):\n", __func__, addr, len);
+ while (len) {
+ unsigned int tmpCnt = len;
+ unsigned char x;
+ if (tmpCnt > 8)
+ tmpCnt = 8;
+ printk_debug("\n%p: ", addr);
+ // print hex
+ while (tmpCnt--) {
+ x = *addr++;
+ printk_debug("%02x ", x);
+ }
+ tmpCnt = len;
+ if (tmpCnt > 8)
+ tmpCnt = 8;
+ len -= tmpCnt;
+ //reset addr ptr to print ascii
+ addr = addr - tmpCnt;
+ // print ascii
+ while (tmpCnt--) {
+ x = *addr++;
+ if ((x < 32) || (x >= 127)) {
+ //non-printable char
+ x = '.';
+ }
+ printk_debug("%c", x);
+ }
+ }
+ printk_debug("\n");
+}
+
+typedef struct {
+ banner_id_t banner;
+ u16 versionmajor;
+ u16 versionminor;
+ u32 smicombuffersize;
+} __attribute__((packed)) version_t;
+
+typedef struct {
+ u16 header_id;
+ u16 attributes;
+ u16 size;
+ u8 name_len;
+ u8 reserved;
+ u32 type;
+ u32 header_ext;
+ u8 name[0];
+} __attribute__((packed)) mbi_header_t;
+
+typedef struct {
+ banner_id_t banner;
+ u64 handle;
+ u32 objnum;
+ mbi_header_t header;
+} __attribute__((packed)) obj_header_t;
+
+typedef struct {
+ banner_id_t banner;
+ u64 handle;
+ u32 objnum;
+ u32 start;
+ u32 numbytes;
+ u32 buflen;
+ u32 buffer;
+} __attribute__((packed)) get_object_t;
+
+static void mbi_call(u8 subf, banner_id_t *banner_id)
+{
+ // printk_debug("MBI\n");
+ // printk_debug("|- sub function %x\n", subf);
+ // printk_debug("|- banner id @ %x\n", (u32)banner_id);
+ // printk_debug("| |- mhid %x\n", banner_id->mhid);
+ // printk_debug("| |- function %x\n", banner_id->function);
+ // printk_debug("| |- return status %x\n", banner_id->retsts);
+ // printk_debug("| |- rfu %x\n", banner_id->rfu);
+
+ switch(banner_id->function) {
+ case 0x0001: {
+ version_t *version;
+ printk_debug("|- MBI_QueryInterface\n");
+ version = (version_t *)banner_id;
+ version->banner.retsts = MSH_OK;
+ version->versionmajor=1;
+ version->versionminor=3;
+ version->smicombuffersize=0x1000;
+ break;
+ }
+ case 0x0002:
+ printk_debug("|- MBI_Attach\n");
+ printk_debug("| |- Not Implemented!\n");
+ break;
+ case 0x0003:
+ printk_debug("|- MBI_Detach\n");
+ printk_debug("| |- Not Implemented!\n");
+ break;
+ case 0x0201: {
+ obj_header_t *obj_header = (obj_header_t *)banner_id;
+ mbi_header_t *mbi_header = NULL;
+ printk_debug("|- MBI_GetObjectHeader\n");
+ printk_debug("| |- objnum = %d\n", obj_header->objnum);
+
+ int i, count=0;
+ obj_header->banner.retsts = MSH_IF_NOT_FOUND;
+
+ for (i=0; i< mbi_len;) {
+ int len;
+
+ if (!(mbi[i] == 0xf0 && mbi [i+1] == 0xf6)) {
+ i+=16;
+ continue;
+ }
+
+ mbi_header = (mbi_header_t *)&mbi[i];
+ len = ALIGN((mbi_header->size * 16) + sizeof(mbi_header) + mbi_header->name_len, 16);
+
+ if (obj_header->objnum == count) {
+ int headerlen = ALIGN(sizeof(mbi_header) + mbi_header->name_len + 15, 16);
+ // printk_debug("| |- headerlen = %d\n", headerlen);
+ memcpy(&obj_header->header, mbi_header, headerlen);
+ obj_header->banner.retsts = MSH_OK;
+ printk_debug("| |- MBI module '");
+ int j;
+ for (j=0; j < mbi_header->name_len && mbi_header->name[j]; j++)
+ printk_debug("%c", mbi_header->name[j]);
+ printk_debug("' found.\n", obj_header->objnum);
+ // dump(banner_id, sizeof(obj_header_t) + 16);
+ break;
+ }
+ i += len;
+ count++;
+ }
+ if (obj_header->banner.retsts == MSH_IF_NOT_FOUND)
+ printk_debug("| |- MBI object #%d not found.\n", obj_header->objnum);
+ break;
+ }
+ case 0x0203: {
+ get_object_t *getobj = (get_object_t *)banner_id;
+ mbi_header_t *mbi_header = NULL;
+ printk_debug("|- MBI_GetObject\n");
+ // printk_debug("| |- handle = %016lx\n", getobj->handle);
+ printk_debug("| |- objnum = %d\n", getobj->objnum);
+ printk_debug("| |- start = %x\n", getobj->start);
+ printk_debug("| |- numbytes = %x\n", getobj->numbytes);
+ printk_debug("| |- buflen = %x\n", getobj->buflen);
+ printk_debug("| |- buffer = %x\n", getobj->buffer);
+
+ int i, count=0;
+ getobj->banner.retsts = MSH_IF_NOT_FOUND;
+
+ for (i=0; i< mbi_len;) {
+ int len;
+
+ if (!(mbi[i] == 0xf0 && mbi [i+1] == 0xf6)) {
+ i+=16;
+ continue;
+ }
+
+ mbi_header = (mbi_header_t *)&mbi[i];
+ len = ALIGN((mbi_header->size * 16) + sizeof(mbi_header) + mbi_header->name_len, 16);
+
+ if (getobj->objnum == count) {
+ printk_debug("| |- len = %x\n", len);
+ memcpy((void *)(getobj->buffer + OBJ_OFFSET),
+ ((char *)mbi_header) + 0x20 , (len > getobj->buflen ? getobj->buflen : len));
+
+ getobj->banner.retsts = MSH_OK;
+ //dump(banner_id, sizeof(getobj) + len);
+ break;
+ }
+ i += len;
+ count++;
+ }
+ if (getobj->banner.retsts == MSH_IF_NOT_FOUND)
+ printk_debug("MBI module %d not found.\n", getobj->objnum);
+ break;
+ }
+ default:
+ printk_debug("|- function %x\n", banner_id->function);
+ printk_debug("| |- Unknown Function!\n");
+ break;
+ }
+ printk_debug("\n");
+ //dump(banner_id, 0x20);
+}
+
+#define SMI_IFC_SUCCESS 1
+#define SMI_IFC_FAILURE_GENERIC 0
+#define SMI_IFC_FAILURE_INVALID 2
+#define SMI_IFC_FAILURE_CRITICAL 4
+#define SMI_IFC_FAILURE_NONCRITICAL 6
+
+#define PC10 0x10
+#define PC11 0x11
+#define PC12 0x12
+#define PC13 0x13
+
+void smi_interface_call(void)
+{
+ u32 mmio;
+ mmio = pci_read_config32(PCI_DEV(0, 0x02, 0), 0x14);
+ // mmio &= 0xfff80000;
+ // printk_debug("mmio=%x\n", mmio);
+
+ u16 swsmi;
+ swsmi=pci_read_config16(PCI_DEV(0, 0x02, 0), 0xe0);
+
+ if (!(swsmi & 1))
+ return;
+
+ swsmi &= ~(1 << 0); // clear SMI toggle
+
+ switch ((swsmi>>1) & 0xf) {
+ case 0:
+ printk_debug("Interface Function Presence Test.\n");
+ swsmi = 0;
+ swsmi &= ~(7 << 5); // Exit: Result
+ swsmi |= (SMI_IFC_SUCCESS << 5);
+ swsmi &= 0xff;
+ swsmi |= (PC13 << 8);
+ pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi);
+ // pathetic
+ write32(mmio + 0x71428, 0x494e5443);
+ return;
+ case 4:
+ printk_debug("Get BIOS Data.\n");
+ printk_debug("swsmi=%04x\n", swsmi);
+ break;
+ case 5:
+ printk_debug("Call MBI Functions.\n");
+ mbi_call(swsmi >> 8, (banner_id_t *)((readl(mmio + 0x71428) & 0x000fffff) + OBJ_OFFSET) );
+ // swsmi = 0x0000;
+ swsmi &= ~(7 << 5); // Exit: Result
+ swsmi |= (SMI_IFC_SUCCESS << 5);
+ pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi);
+ return;
+ case 6:
+ printk_debug("System BIOS Callbacks.\n");
+ printk_debug("swsmi=%04x\n", swsmi);
+ break;
+ default:
+ printk_debug("Unknown SMI interface call %04x\n", swsmi);
+ break;
+ }
+
+ swsmi &= ~(7 << 5); // Exit: Result
+ swsmi |= (SMI_IFC_FAILURE_CRITICAL << 7);
+ pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi);
+}
+
+/**
+ * @brief read and clear ERRSTS
+ * @return ERRSTS register
+ */
+static u16 reset_err_status(void)
+{
+ u16 reg16;
+
+ reg16 = pci_read_config16(PCI_DEV(0, 0x00, 0), ERRSTS);
+ /* set status bits are cleared by writing 1 to them */
+ pci_write_config16(PCI_DEV(0, 0x00, 0), ERRSTS, reg16);
+
+ return reg16;
+}
+
+static void dump_err_status(u32 errsts)
+{
+ printk_debug("ERRSTS: ");
+ if (errsts & (1 << 12)) printk_debug("MBI ");
+ if (errsts & (1 << 9)) printk_debug("LCKF ");
+ if (errsts & (1 << 8)) printk_debug("DTF ");
+ if (errsts & (1 << 5)) printk_debug("UNSC ");
+ if (errsts & (1 << 4)) printk_debug("OOGF ");
+ if (errsts & (1 << 3)) printk_debug("IAAF ");
+ if (errsts & (1 << 2)) printk_debug("ITTEF ");
+ printk_debug("\n");
+}
+
+void northbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save)
+{
+ u16 errsts;
+
+ /* We need to clear the SMI status registers, or we won't see what's
+ * happening in the following calls.
+ */
+ errsts = reset_err_status();
+ if (errsts & (1 << 12)) {
+ smi_interface_call();
+ } else {
+ if (errsts)
+ dump_err_status(errsts);
+ }
+
+}
diff --git a/src/northbridge/intel/i82830/northbridge.c b/src/northbridge/intel/i82830/northbridge.c
index e482db6..af9663d 100644
--- a/src/northbridge/intel/i82830/northbridge.c
+++ b/src/northbridge/intel/i82830/northbridge.c
@@ -116,7 +116,7 @@
*/
tomk = ((unsigned long)pci_read_config8(mc_dev, DRB + 3)) << 15;
tomk -= igd_memory;
- printk_debug("Setting RAM size to %ld\n", tomk);
+ printk_debug("Memory detected: %ldKB RAM\n", tomk);
/* Compute the top of low memory. */
tolmk = pci_tolm >> 10;
diff --git a/src/northbridge/intel/i82830/raminit.c b/src/northbridge/intel/i82830/raminit.c
index 9cb194e..2b74715 100644
--- a/src/northbridge/intel/i82830/raminit.c
+++ b/src/northbridge/intel/i82830/raminit.c
@@ -536,6 +536,7 @@
value = pci_read_config16(NORTHBRIDGE, GCC1);
value |= igd_memory << 4;
+ value |= 1; // 64MB aperture
pci_write_config16(NORTHBRIDGE, GCC1, value);
PRINT_DEBUG("Initial northbridge registers have been set.\r\n");
diff --git a/src/northbridge/intel/i82830/vga.c b/src/northbridge/intel/i82830/vga.c
index e9cfdac..8c1cac0 100644
--- a/src/northbridge/intel/i82830/vga.c
+++ b/src/northbridge/intel/i82830/vga.c
@@ -24,13 +24,67 @@
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
+#include <cbfs.h>
+#include <x86emu/x86emu.h>
-static void vga_init(device_t dev) {
-
+static void vga_init(device_t dev)
+{
printk_info("Starting Graphics Initialization\n");
+ struct cbfs_file *file = cbfs_find("mbi.bin");
+ void *mbi = NULL;
+ unsigned int mbi_len = 0;
+
+ if (file) {
+ if (ntohl(file->type) != CBFS_TYPE_MBI) {
+ printk_info( "CBFS: MBI binary is of type %x instead of"
+ "type %x\n", file->type, CBFS_TYPE_MBI);
+ } else {
+ mbi = (void *) CBFS_SUBHEADER(file);
+ mbi_len = file->len;
+ }
+ } else {
+ printk_info( "Could not find MBI.\n");
+ }
+
+ if (mbi && mbi_len) {
+ /* The GDT or coreboot table is going to live here. But
+ * a long time after we relocated the GNVS, so this is
+ * not troublesome.
+ */
+ *(u32 *)0x500 = (u32)mbi;
+ *(u32 *)0x504 = (u32)mbi_len;
+ outb(0xeb, 0xb2);
+ }
+
pci_dev_init(dev);
printk_info("Graphics Initialization Complete\n");
- /* Future TV-OUT code will be called from here. */
+
+ /* Enable TV-Out */
+#if defined(CONFIG_PCI_OPTION_ROM_RUN_YABEL) && CONFIG_PCI_OPTION_ROM_RUN_YABEL
+#define PIPE_A_CRT (1 << 0)
+#define PIPE_A_LFP (1 << 1)
+#define PIPE_A_TV (1 << 3)
+#define PIPE_B_CRT (1 << 8)
+#define PIPE_B_TV (1 << 10)
+ printk_debug("Enabling TV-Out\n");
+ void runInt10(void);
+ M.x86.R_AX = 0x5f64;
+ M.x86.R_BX = 0x0001; // Set Display Device, force execution
+ M.x86.R_CX = PIPE_A_CRT | PIPE_A_TV;
+ // M.x86.R_CX = PIPE_B_TV;
+ runInt10();
+ switch (M.x86.R_AX) {
+ case 0x005f:
+ printk_debug("... failed.\n");
+ break;
+ case 0x015f:
+ printk_debug("... ok.\n");
+ break;
+ default:
+ printk_debug("... not supported.\n");
+ break;
+ }
+#endif
}
static const struct device_operations vga_operations = {
diff --git a/src/southbridge/intel/i82801dx/Kconfig b/src/southbridge/intel/i82801dx/Kconfig
index 6a35691..62da5cf 100644
--- a/src/southbridge/intel/i82801dx/Kconfig
+++ b/src/southbridge/intel/i82801dx/Kconfig
@@ -1,2 +1,3 @@
config SOUTHBRIDGE_INTEL_I82801DX
bool
+ select IOAPIC
diff --git a/src/southbridge/intel/i82801dx/Makefile.inc b/src/southbridge/intel/i82801dx/Makefile.inc
index 7167e1d..562e80a 100644
--- a/src/southbridge/intel/i82801dx/Makefile.inc
+++ b/src/southbridge/intel/i82801dx/Makefile.inc
@@ -7,3 +7,6 @@
#driver-y += i82801dx_nic.o
#driver-y += i82801dx_pci.o
obj-y += i82801dx_reset.o
+
+obj-$(CONFIG_HAVE_SMI_HANDLER) += i82801dx_smi.o
+smmobj-$(CONFIG_HAVE_SMI_HANDLER) += i82801dx_smihandler.o
diff --git a/src/southbridge/intel/i82801dx/i82801dx_ac97.c b/src/southbridge/intel/i82801dx/i82801dx_ac97.c
index 7524498..10b100b 100644
--- a/src/southbridge/intel/i82801dx/i82801dx_ac97.c
+++ b/src/southbridge/intel/i82801dx/i82801dx_ac97.c
@@ -1,41 +1,285 @@
/*
- * (C) 2003 Linux Networx
+ * 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
*/
+
#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
-#include <device/pci_ops.h>
+#include <arch/io.h>
+#include <delay.h>
#include "i82801dx.h"
+#define NAMBAR 0x10
+#define MASTER_VOL 0x02
+#define PAGING 0x24
+#define EXT_AUDIO 0x28
+#define FUNC_SEL 0x66
+#define INFO_IO 0x68
+#define CONNECTOR 0x6a
+#define VENDOR_ID1 0x7c
+#define VENDOR_ID2 0x7e
+#define SEC_VENDOR_ID1 0xfc
+#define SEC_VENDOR_ID2 0xfe
-static struct device_operations ac97audio_ops = {
+#define NABMBAR 0x14
+#define GLOB_CNT 0x2c
+#define GLOB_STA 0x30
+#define CAS 0x34
+
+#define MMBAR 0x10
+#define EXT_MODEM_ID1 0x3c
+#define EXT_MODEM_ID2 0xbc
+
+#define MBAR 0x14
+#define SEC_CODEC 0x40
+
+
+/* FIXME. This table is probably mainboard specific */
+static u16 ac97_function[16*2][4] = {
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
+ { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }
+};
+
+static u16 nabmbar;
+static u16 nambar;
+
+static int ac97_semaphore(void)
+{
+ int timeout;
+ u8 reg8;
+
+ timeout = 0xffff;
+ do {
+ reg8 = inb(nabmbar + CAS);
+ timeout--;
+ } while ((reg8 & 1) && timeout);
+ if (! timeout) {
+ printk_debug("Timeout!\n");
+ }
+
+ return (!timeout);
+}
+
+static void init_cnr(void)
+{
+ // TODO
+}
+
+static void program_sigid(struct device *dev, u32 id)
+{
+ pci_write_config32(dev, 0x2c, id);
+}
+
+static void ac97_audio_init(struct device *dev)
+{
+ u16 reg16;
+ u32 reg32;
+ int i;
+
+ printk_debug("Initializing AC'97 Audio.\n");
+
+ /* top 16 bits are zero, so don't read them */
+ nabmbar = pci_read_config16(dev, NABMBAR) & 0xfffe;
+ nambar = pci_read_config16(dev, NAMBAR) & 0xfffe;
+
+ reg16 = inw(nabmbar + GLOB_CNT);
+ reg16 |= (1 << 1); /* Remove AC_RESET# */
+ outw(reg16, nabmbar + GLOB_CNT);
+
+ /* Wait 600ms. Ouch. */
+ udelay(600 * 1000);
+
+ init_cnr();
+
+ /* Detect Primary AC'97 Codec */
+ reg32 = inl(nabmbar + GLOB_STA);
+ if ((reg32 & ((1 << 28) | (1 << 9) | (1 << 8))) == 0) {
+ /* Primary Codec not found */
+ printk_debug("No primary codec. Disabling AC'97 Audio.\n");
+ return;
+ }
+
+ ac97_semaphore();
+
+ /* Detect if codec is programmable */
+ outw(0x8000, nambar + MASTER_VOL);
+ ac97_semaphore();
+ if (inw(nambar + MASTER_VOL) != 0x8000) {
+ printk_debug("Codec not programmable. Disabling AC'97 Audio.\n");
+ return;
+ }
+
+ /* Program Vendor IDs */
+ reg32 = inw(nambar + VENDOR_ID1);
+ reg32 <<= 16;
+ reg32 |= (u16)inw(nambar + VENDOR_ID2);
+
+ program_sigid(dev, reg32);
+
+ /* Is Codec AC'97 2.3 compliant? */
+ reg16 = inw(nambar + EXT_AUDIO);
+ /* [11:10] = 10b -> AC'97 2.3 */
+ if ((reg16 & 0x0c00) != 0x0800) {
+ /* No 2.3 Codec. We're done */
+ return;
+ }
+
+ /* Select Page 1 */
+ reg16 = inw(nambar + PAGING);
+ reg16 &= 0xfff0;
+ reg16 |= 0x0001;
+ outw(reg16, nambar + PAGING);
+
+ for (i = 0x0a * 2; i > 0; i--) {
+ outw(i, nambar + FUNC_SEL);
+
+ /* Function could not be selected. Next one */
+ if (inw(nambar + FUNC_SEL) != i)
+ continue;
+
+ reg16 = inw(nambar + INFO_IO);
+
+ /* Function Information present? */
+ if (!(reg16 & (1 << 0)))
+ continue;
+
+ /* Function Information valid? */
+ if (!(reg16 & (1 << 4)))
+ continue;
+
+ /* Program Buffer Delay [9:5] */
+ reg16 &= 0x03e0;
+ reg16 |= ac97_function[i][0];
+
+ /* Program Gain [15:11] */
+ reg16 |= ac97_function[i][1];
+
+ /* Program Inversion [10] */
+ reg16 |= ac97_function[i][2];
+
+ outw(reg16, nambar + INFO_IO);
+
+ /* Program Connector / Jack Location */
+ reg16 = inw(nambar + CONNECTOR);
+ reg16 &= 0x1fff;
+ reg16 |= ac97_function[i][3];
+ outw(reg16, nambar + CONNECTOR);
+ }
+}
+
+static void ac97_modem_init(struct device *dev)
+{
+ u16 reg16;
+ u32 reg32;
+ u16 mmbar, mbar;
+
+ mmbar = pci_read_config16(dev, MMBAR) & 0xfffe;
+ mbar = pci_read_config16(dev, MBAR) & 0xfffe;
+
+ reg16 = inw(mmbar + EXT_MODEM_ID1);
+ if ((reg16 & 0xc000) != 0xc000 ) {
+ if (reg16 & (1 << 0)) {
+ reg32 = inw(mmbar + VENDOR_ID2);
+ reg32 <<= 16;
+ reg32 |= (u16)inw(mmbar + VENDOR_ID1);
+ program_sigid(dev, reg32);
+ return;
+ }
+ }
+
+ /* Secondary codec? */
+ reg16 = inw(mbar + SEC_CODEC);
+ if ((reg16 & (1 << 9)) == 0)
+ return;
+
+ reg16 = inw(mmbar + EXT_MODEM_ID2);
+ if ((reg16 & 0xc000) == 0x4000) {
+ if (reg16 & (1 << 0)) {
+ reg32 = inw(mmbar + SEC_VENDOR_ID2);
+ reg32 <<= 16;
+ reg32 |= (u16)inw(mmbar + SEC_VENDOR_ID1);
+ program_sigid(dev, reg32);
+ return;
+ }
+ }
+}
+
+static struct device_operations ac97_audio_ops = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.enable = i82801dx_enable,
- .init = 0,
+ .init = ac97_audio_init,
.scan_bus = 0,
};
-static const struct pci_driver ac97audio_driver __pci_driver = {
- .ops = &ac97audio_ops,
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_82801DBM_AC97_AUDIO,
-};
-
-
-static struct device_operations ac97modem_ops = {
+static struct device_operations ac97_modem_ops = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.enable = i82801dx_enable,
- .init = 0,
+ .init = ac97_modem_init,
.scan_bus = 0,
};
-static const struct pci_driver ac97modem_driver __pci_driver = {
- .ops = &ac97modem_ops,
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_82801DBM_AC97_MODEM,
+/* 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) */
+static const struct pci_driver i82801db_ac97_audio __pci_driver = {
+ .ops = &ac97_audio_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801DB_AC97_AUDIO,
};
+
+static const struct pci_driver i82801db_ac97_modem __pci_driver = {
+ .ops = &ac97_modem_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82801DB_AC97_MODEM,
+};
+
+
diff --git a/src/southbridge/intel/i82801dx/i82801dx_nvs.h b/src/southbridge/intel/i82801dx/i82801dx_nvs.h
new file mode 100644
index 0000000..03f8de7
--- /dev/null
+++ b/src/southbridge/intel/i82801dx/i82801dx_nvs.h
@@ -0,0 +1,138 @@
+/*
+ * 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 */
+ /* Thermal policy */
+ u8 actt; /* 0x14 - active trip point */
+ u8 psvt; /* 0x15 - passive trip point */
+ u8 tc1v; /* 0x16 - passive trip point TC1 */
+ u8 tc2v; /* 0x17 - passive trip point TC2 */
+ u8 tspv; /* 0x18 - passive trip point TSP */
+ u8 crtt; /* 0x19 - critical trip point */
+ u8 dtse; /* 0x1a - Digital Thermal Sensor enable */
+ u8 dts1; /* 0x1b - DT sensor 1 */
+ u8 dts2; /* 0x1c - DT sensor 2 */
+ u8 rsvd2;
+ /* Battery Support */
+ u8 bnum; /* 0x1e - number of batteries */
+ u8 b0sc, b1sc, b2sc; /* 0x1f-0x21 - stored capacity */
+ u8 b0ss, b1ss, b2ss; /* 0x22-0x24 - stored status */
+ u8 rsvd3[3];
+ /* 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 */
+ u8 rsvd4[5];
+ /* Super I/O & CMOS config */
+ u8 natp; /* 0x32 - SIO type */
+ u8 cmap; /* 0x33 - */
+ u8 cmbp; /* 0x34 - */
+ u8 lptp; /* 0x35 - LPT port */
+ u8 fdcp; /* 0x36 - Floppy Disk Controller */
+ u8 rfdv; /* 0x37 - */
+ u8 hotk; /* 0x38 - Hot Key */
+ u8 rtcf;
+ u8 util;
+ u8 acin;
+ /* Integrated Graphics Device */
+ u8 igds; /* 0x3c - IGD state */
+ u8 tlst; /* 0x3d - Display Toggle List Pointer */
+ u8 cadl; /* 0x3e - currently attached devices */
+ u8 padl; /* 0x3f - previously attached devices */
+ u16 cste; /* 0x40 - current display state */
+ u16 nste; /* 0x42 - next display state */
+ u16 sste; /* 0x44 - set display state */
+ u8 ndid; /* 0x46 - number of device ids */
+ u32 did[5]; /* 0x47 - 5b device id 1..5 */
+ u8 rsvd5[0x9];
+ /* Backlight Control */
+ u8 blcs; /* 0x64 - Backlight Control possible */
+ u8 brtl;
+ u8 odds;
+ u8 rsvd6[0x7];
+ /* Ambient Light Sensors*/
+ u8 alse; /* 0x6e - ALS enable */
+ u8 alaf;
+ u8 llow;
+ u8 lhih;
+ u8 rsvd7[0x6];
+ /* EMA */
+ u8 emae; /* 0x78 - EMA enable */
+ u16 emap;
+ u16 emal;
+ u8 rsvd8[0x5];
+ /* MEF */
+ u8 mefe; /* 0x82 - MEF enable */
+ u8 rsvd9[0x9];
+ /* TPM support */
+ u8 tpmp; /* 0x8c - TPM */
+ u8 tpme;
+ u8 rsvd10[8];
+ /* SATA */
+ u8 gtf0[7]; /* 0x96 - GTF task file buffer for port 0 */
+ u8 gtf1[7];
+ u8 gtf2[7];
+ u8 idem;
+ u8 idet;
+ u8 rsvd11[7];
+ /* IGD OpRegion (not implemented yet) */
+ u32 aslb; /* 0xb4 - IGD OpRegion Base Address */
+ u8 ibtt;
+ u8 ipat;
+ u8 itvf;
+ u8 itvm;
+ u8 ipsc;
+ u8 iblc;
+ u8 ibia;
+ u8 issc;
+ u8 i409;
+ u8 i509;
+ u8 i609;
+ u8 i709;
+ u8 idmm;
+ u8 idms;
+ u8 if1e;
+ u8 hvco;
+ u32 nxd[8];
+ u8 rsvd12[8];
+ /* Mainboard specific */
+ u8 dock; /* 0xf0 - Docking Status */
+ u8 bten;
+ u8 rsvd13[14];
+} __attribute__((packed)) global_nvs_t;
+
diff --git a/src/southbridge/intel/i82801dx/i82801dx_smi.c b/src/southbridge/intel/i82801dx/i82801dx_smi.c
new file mode 100644
index 0000000..b934dcf
--- /dev/null
+++ b/src/southbridge/intel/i82801dx/i82801dx_smi.c
@@ -0,0 +1,365 @@
+/*
+ * 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
+ */
+
+
+#include <device/device.h>
+#include <device/pci.h>
+#include <console/console.h>
+#include <arch/io.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/smm.h>
+#include <string.h>
+#include "i82801dx.h"
+
+extern unsigned char smm[];
+extern unsigned int smm_len;
+
+/* I945 */
+#define SMRAM 0x90
+#define D_OPEN (1 << 6)
+#define D_CLS (1 << 5)
+#define D_LCK (1 << 4)
+#define G_SMRAME (1 << 3)
+#define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0))
+
+/* While we read PMBASE dynamically in case it changed, let's
+ * initialize it with a sane value
+ */
+static u16 pmbase = PMBASE_ADDR;
+
+/**
+ * @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_debug("PM1_STS: ");
+ if (pm1_sts & (1 << 15)) printk_debug("WAK ");
+ if (pm1_sts & (1 << 14)) printk_debug("PCIEXPWAK ");
+ if (pm1_sts & (1 << 11)) printk_debug("PRBTNOR ");
+ if (pm1_sts & (1 << 10)) printk_debug("RTC ");
+ if (pm1_sts & (1 << 8)) printk_debug("PWRBTN ");
+ if (pm1_sts & (1 << 5)) printk_debug("GBL ");
+ if (pm1_sts & (1 << 4)) printk_debug("BM ");
+ if (pm1_sts & (1 << 0)) printk_debug("TMROF ");
+ printk_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_debug("SMI_STS: ");
+ if (smi_sts & (1 << 26)) printk_debug("SPI ");
+ if (smi_sts & (1 << 25)) printk_debug("EL_SMI ");
+ if (smi_sts & (1 << 21)) printk_debug("MONITOR ");
+ if (smi_sts & (1 << 20)) printk_debug("PCI_EXP_SMI ");
+ if (smi_sts & (1 << 18)) printk_debug("INTEL_USB2 ");
+ if (smi_sts & (1 << 17)) printk_debug("LEGACY_USB2 ");
+ if (smi_sts & (1 << 16)) printk_debug("SMBUS_SMI ");
+ if (smi_sts & (1 << 15)) printk_debug("SERIRQ_SMI ");
+ if (smi_sts & (1 << 14)) printk_debug("PERIODIC ");
+ if (smi_sts & (1 << 13)) printk_debug("TCO ");
+ if (smi_sts & (1 << 12)) printk_debug("DEVMON ");
+ if (smi_sts & (1 << 11)) printk_debug("MCSMI ");
+ if (smi_sts & (1 << 10)) printk_debug("GPI ");
+ if (smi_sts & (1 << 9)) printk_debug("GPE0 ");
+ if (smi_sts & (1 << 8)) printk_debug("PM1 ");
+ if (smi_sts & (1 << 6)) printk_debug("SWSMI_TMR ");
+ if (smi_sts & (1 << 5)) printk_debug("APM ");
+ if (smi_sts & (1 << 4)) printk_debug("SLP_SMI ");
+ if (smi_sts & (1 << 3)) printk_debug("LEGACY_USB ");
+ if (smi_sts & (1 << 2)) printk_debug("BIOS ");
+ printk_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_debug("GPE0_STS: ");
+ for (i=31; i<= 16; i--) {
+ if (gpe0_sts & (1 << i)) printk_debug("GPIO%d ", (i-16));
+ }
+ if (gpe0_sts & (1 << 14)) printk_debug("USB4 ");
+ if (gpe0_sts & (1 << 13)) printk_debug("PME_B0 ");
+ if (gpe0_sts & (1 << 12)) printk_debug("USB3 ");
+ if (gpe0_sts & (1 << 11)) printk_debug("PME ");
+ if (gpe0_sts & (1 << 10)) printk_debug("EL_SCI/BATLOW ");
+ if (gpe0_sts & (1 << 9)) printk_debug("PCI_EXP ");
+ if (gpe0_sts & (1 << 8)) printk_debug("RI ");
+ if (gpe0_sts & (1 << 7)) printk_debug("SMB_WAK ");
+ if (gpe0_sts & (1 << 6)) printk_debug("TCO_SCI ");
+ if (gpe0_sts & (1 << 5)) printk_debug("AC97 ");
+ if (gpe0_sts & (1 << 4)) printk_debug("USB2 ");
+ if (gpe0_sts & (1 << 3)) printk_debug("USB1 ");
+ if (gpe0_sts & (1 << 2)) printk_debug("HOT_PLUG ");
+ if (gpe0_sts & (1 << 0)) printk_debug("THRM ");
+ printk_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_debug("ALT_GP_SMI_STS: ");
+ for (i=15; i<= 0; i--) {
+ if (alt_gp_smi_sts & (1 << i)) printk_debug("GPI%d ", (i-16));
+ }
+ printk_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_debug("TCO_STS: ");
+ if (tco_sts & (1 << 20)) printk_debug("SMLINK_SLV ");
+ if (tco_sts & (1 << 18)) printk_debug("BOOT ");
+ if (tco_sts & (1 << 17)) printk_debug("SECOND_TO ");
+ if (tco_sts & (1 << 16)) printk_debug("INTRD_DET ");
+ if (tco_sts & (1 << 12)) printk_debug("DMISERR ");
+ if (tco_sts & (1 << 10)) printk_debug("DMISMI ");
+ if (tco_sts & (1 << 9)) printk_debug("DMISCI ");
+ if (tco_sts & (1 << 8)) printk_debug("BIOSWR ");
+ if (tco_sts & (1 << 7)) printk_debug("NEWCENTURY ");
+ if (tco_sts & (1 << 3)) printk_debug("TIMEOUT ");
+ if (tco_sts & (1 << 2)) printk_debug("TCO_INT ");
+ if (tco_sts & (1 << 1)) printk_debug("SW_TCO ");
+ if (tco_sts & (1 << 0)) printk_debug("NMI2SMI ");
+ printk_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);
+}
+
+extern uint8_t smm_relocation_start, smm_relocation_end;
+
+void smm_relocate(void)
+{
+ u32 smi_en;
+ u16 pm1_en;
+
+ printk_debug("Initializing SMM handler...");
+
+ pmbase = pci_read_config16(dev_find_slot(0, PCI_DEVFN(0x1f, 0)), 0x40) & 0xfffc;
+ printk_spew(" ... pmbase = 0x%04x\n", pmbase);
+
+ smi_en = inl(pmbase + SMI_EN);
+ if (smi_en & APMC_EN) {
+ printk_info("SMI# handler already enabled?\n");
+ return;
+ }
+
+ /* copy the SMM relocation code */
+ memcpy((void *)0x38000, &smm_relocation_start,
+ &smm_relocation_end - &smm_relocation_start);
+
+ printk_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());
+
+ /* 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 i82801gx.h to debug using
+ * periodic SMIs.
+ */
+ smi_en |= PERIODIC_EN;
+#endif
+ smi_en |= SLP_SMI_EN;
+ smi_en |= BIOS_EN;
+
+ /* The following need to be on for SMIs to happen */
+ smi_en |= EOS | GBL_SMI_EN;
+
+ outl(smi_en, pmbase + SMI_EN);
+
+ pm1_en = 0;
+ pm1_en |= PWRBTN_EN;
+ pm1_en |= GBL_EN;
+ outw(pm1_en, pmbase + PM1_EN);
+
+ /**
+ * 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_spew(" ... raise SMI#\n");
+ outb(0x00, 0xb2);
+}
+
+void smm_install(void)
+{
+ /* enable the SMM memory window */
+ pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM,
+ D_OPEN | G_SMRAME | C_BASE_SEG);
+
+ /* copy the real SMM handler */
+ memcpy((void *)0xa0000, smm, smm_len);
+ wbinvd();
+
+ /* close the SMM memory window and enable normal SMM */
+ pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM,
+ G_SMRAME | C_BASE_SEG);
+}
+
+void smm_init(void)
+{
+ // FIXME is this a race condition?
+ smm_relocate();
+ smm_install();
+
+ // We're done. Make sure SMIs can happen!
+ smi_set_eos();
+}
+
+void smm_lock(void)
+{
+ /* LOCK the SMM memory window and enable normal SMM.
+ * After running this function, only a full reset can
+ * make the SMM registers writable again.
+ */
+ printk_debug("Locking SMM.\n");
+ pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM,
+ D_LCK | G_SMRAME | C_BASE_SEG);
+}
+
+void smm_setup_structures(void *gnvs, void *tcg, void *smi1)
+{
+ /* The GDT or coreboot table is going to live here. But a long time
+ * after we relocated the GNVS, so this is not troublesome.
+ */
+ *(u32 *)0x500 = (u32)gnvs;
+ *(u32 *)0x504 = (u32)tcg;
+ *(u32 *)0x508 = (u32)smi1;
+ outb(0xea, 0xb2);
+}
diff --git a/src/southbridge/intel/i82801dx/i82801dx_smihandler.c b/src/southbridge/intel/i82801dx/i82801dx_smihandler.c
new file mode 100644
index 0000000..9994429
--- /dev/null
+++ b/src/southbridge/intel/i82801dx/i82801dx_smihandler.c
@@ -0,0 +1,669 @@
+/*
+ * 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
+ */
+
+#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 "i82801dx.h"
+
+#define DEBUG_SMI
+
+#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 MBI_UPDATE 0xeb
+#define APM_STS 0xb3
+
+/* I830M */
+#define SMRAM 0x90
+#define D_OPEN (1 << 6)
+#define D_CLS (1 << 5)
+#define D_LCK (1 << 4)
+#define G_SMRANE (1 << 3)
+#define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0))
+
+#include "i82801dx_nvs.h"
+
+/* While we read PMBASE dynamically in case it changed, let's
+ * initialize it with a sane value
+ */
+u16 pmbase = PMBASE_ADDR;
+u8 smm_initialized = 0;
+
+unsigned char *mbi = NULL;
+u32 mbi_len;
+u8 mbi_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;
+
+/**
+ * @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_spew("PM1_STS: ");
+ if (pm1_sts & (1 << 15)) printk_spew("WAK ");
+ if (pm1_sts & (1 << 14)) printk_spew("PCIEXPWAK ");
+ if (pm1_sts & (1 << 11)) printk_spew("PRBTNOR ");
+ if (pm1_sts & (1 << 10)) printk_spew("RTC ");
+ if (pm1_sts & (1 << 8)) printk_spew("PWRBTN ");
+ if (pm1_sts & (1 << 5)) printk_spew("GBL ");
+ if (pm1_sts & (1 << 4)) printk_spew("BM ");
+ if (pm1_sts & (1 << 0)) printk_spew("TMROF ");
+ printk_spew("\n");
+ int reg16 = inw(pmbase + PM1_EN);
+ printk_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_debug("SMI_STS: ");
+ if (smi_sts & (1 << 26)) printk_debug("SPI ");
+ if (smi_sts & (1 << 25)) printk_debug("EL_SMI ");
+ if (smi_sts & (1 << 21)) printk_debug("MONITOR ");
+ if (smi_sts & (1 << 20)) printk_debug("PCI_EXP_SMI ");
+ if (smi_sts & (1 << 18)) printk_debug("INTEL_USB2 ");
+ if (smi_sts & (1 << 17)) printk_debug("LEGACY_USB2 ");
+ if (smi_sts & (1 << 16)) printk_debug("SMBUS_SMI ");
+ if (smi_sts & (1 << 15)) printk_debug("SERIRQ_SMI ");
+ if (smi_sts & (1 << 14)) printk_debug("PERIODIC ");
+ if (smi_sts & (1 << 13)) printk_debug("TCO ");
+ if (smi_sts & (1 << 12)) printk_debug("DEVMON ");
+ if (smi_sts & (1 << 11)) printk_debug("MCSMI ");
+ if (smi_sts & (1 << 10)) printk_debug("GPI ");
+ if (smi_sts & (1 << 9)) printk_debug("GPE0 ");
+ if (smi_sts & (1 << 8)) printk_debug("PM1 ");
+ if (smi_sts & (1 << 6)) printk_debug("SWSMI_TMR ");
+ if (smi_sts & (1 << 5)) printk_debug("APM ");
+ if (smi_sts & (1 << 4)) printk_debug("SLP_SMI ");
+ if (smi_sts & (1 << 3)) printk_debug("LEGACY_USB ");
+ if (smi_sts & (1 << 2)) printk_debug("BIOS ");
+ printk_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_debug("GPE0_STS: ");
+ for (i=31; i<= 16; i--) {
+ if (gpe0_sts & (1 << i)) printk_debug("GPIO%d ", (i-16));
+ }
+ if (gpe0_sts & (1 << 14)) printk_debug("USB4 ");
+ if (gpe0_sts & (1 << 13)) printk_debug("PME_B0 ");
+ if (gpe0_sts & (1 << 12)) printk_debug("USB3 ");
+ if (gpe0_sts & (1 << 11)) printk_debug("PME ");
+ if (gpe0_sts & (1 << 10)) printk_debug("EL_SCI/BATLOW ");
+ if (gpe0_sts & (1 << 9)) printk_debug("PCI_EXP ");
+ if (gpe0_sts & (1 << 8)) printk_debug("RI ");
+ if (gpe0_sts & (1 << 7)) printk_debug("SMB_WAK ");
+ if (gpe0_sts & (1 << 6)) printk_debug("TCO_SCI ");
+ if (gpe0_sts & (1 << 5)) printk_debug("AC97 ");
+ if (gpe0_sts & (1 << 4)) printk_debug("USB2 ");
+ if (gpe0_sts & (1 << 3)) printk_debug("USB1 ");
+ if (gpe0_sts & (1 << 2)) printk_debug("HOT_PLUG ");
+ if (gpe0_sts & (1 << 0)) printk_debug("THRM ");
+ printk_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_debug("TCO_STS: ");
+ if (tco_sts & (1 << 20)) printk_debug("SMLINK_SLV ");
+ if (tco_sts & (1 << 18)) printk_debug("BOOT ");
+ if (tco_sts & (1 << 17)) printk_debug("SECOND_TO ");
+ if (tco_sts & (1 << 16)) printk_debug("INTRD_DET ");
+ if (tco_sts & (1 << 12)) printk_debug("DMISERR ");
+ if (tco_sts & (1 << 10)) printk_debug("DMISMI ");
+ if (tco_sts & (1 << 9)) printk_debug("DMISCI ");
+ if (tco_sts & (1 << 8)) printk_debug("BIOSWR ");
+ if (tco_sts & (1 << 7)) printk_debug("NEWCENTURY ");
+ if (tco_sts & (1 << 3)) printk_debug("TIMEOUT ");
+ if (tco_sts & (1 << 2)) printk_debug("TCO_INT ");
+ if (tco_sts & (1 << 1)) printk_debug("SW_TCO ");
+ if (tco_sts & (1 << 0)) printk_debug("NMI2SMI ");
+ printk_debug("\n");
+}
+
+/* We are using PCIe accesses for now
+ * 1. the chipset can do it
+ * 2. we don't need to worry about how we leave 0xcf8/0xcfc behind
+ */
+// #include "../../../northbridge/intel/i945/pcie_config.c"
+
+int southbridge_io_trap_handler(int smif)
+{
+ switch (smif) {
+ case 0x32:
+ printk_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 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(unsigned int node, smm_state_save_area_t *state_save)
+{
+ u8 reg8;
+ u32 reg32;
+ u8 slp_typ;
+ /* FIXME: the power state on boot should be read from
+ * CMOS or even better from GNVS. Right now it's hard
+ * coded at compile time.
+ */
+ u8 s5pwr = CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
+
+ /* First, disable further SMIs */
+ reg8 = inb(pmbase + SMI_EN);
+ reg8 &= ~SLP_SMI_EN;
+ outb(reg8, pmbase + SMI_EN);
+
+ /* Figure out SLP_TYP */
+ reg32 = inl(pmbase + PM1_CNT);
+ printk_spew("SMI#: SLP = 0x%08x\n", reg32);
+ slp_typ = (reg32 >> 10) & 7;
+
+ /* Next, do the deed.
+ */
+
+ switch (slp_typ) {
+ case 0: printk_debug("SMI#: Entering S0 (On)\n"); break;
+ case 1: printk_debug("SMI#: Entering S1 (Assert STPCLK#)\n"); break;
+ case 5:
+ printk_debug("SMI#: Entering S3 (Suspend-To-RAM)\n");
+ /* Invalidate the cache before going to S3 */
+ wbinvd();
+ break;
+ case 6: printk_debug("SMI#: Entering S4 (Suspend-To-Disk)\n"); break;
+ case 7:
+ printk_debug("SMI#: Entering S5 (Soft Power off)\n");
+
+ outl(0, pmbase + GPE0_EN);
+
+ /* Should we keep the power state after a power loss?
+ * In case the setting is "ON" or "OFF" we don't have
+ * to do anything. But if it's "KEEP" we have to switch
+ * to "OFF" before entering S5.
+ */
+ if (s5pwr == MAINBOARD_POWER_KEEP) {
+ reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3);
+ reg8 |= 1;
+ pci_write_config8(PCI_DEV(0, 0x1f, 0), GEN_PMCON_3, reg8);
+ }
+
+ /* also iterates over all bridges on bus 0 */
+ busmaster_disable_on_bus(0);
+ break;
+ default: printk_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.
+ */
+ outl(reg32 | SLP_EN, pmbase + PM1_CNT);
+
+ /* 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 */
+ reg32 &= ~(SLP_EN | SLP_TYP);
+ outl(reg32, pmbase + PM1_CNT);
+ }
+}
+
+static void southbridge_smi_apmc(unsigned int node, smm_state_save_area_t *state_save)
+{
+ u32 pmctrl;
+ u8 reg8;
+
+ /* Emulate B2 register as the FADT / Linux expects it */
+
+ reg8 = inb(APM_CNT);
+ switch (reg8) {
+ case CST_CONTROL:
+ /* Calling this function seems to cause
+ * some kind of race condition in Linux
+ * and causes a kernel oops
+ */
+ printk_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_debug("P-state control\n");
+ break;
+ case ACPI_DISABLE:
+ pmctrl = inl(pmbase + PM1_CNT);
+ pmctrl &= ~SCI_EN;
+ outl(pmctrl, pmbase + PM1_CNT);
+ printk_debug("SMI#: ACPI disabled.\n");
+ break;
+ case ACPI_ENABLE:
+ pmctrl = inl(pmbase + PM1_CNT);
+ pmctrl |= SCI_EN;
+ outl(pmctrl, pmbase + PM1_CNT);
+ printk_debug("SMI#: ACPI enabled.\n");
+ break;
+ case GNVS_UPDATE:
+ if (smm_initialized) {
+ printk_debug("SMI#: SMM structures already initialized!\n");
+ return;
+ }
+ gnvs = *(global_nvs_t **)0x500;
+ tcg = *(void **)0x504;
+ smi1 = *(void **)0x508;
+ smm_initialized = 1;
+ printk_debug("SMI#: Setting up structures to %p, %p, %p\n", gnvs, tcg, smi1);
+ break;
+ case MBI_UPDATE: // FIXME
+ if (mbi_initialized) {
+ printk_debug("SMI#: mbi already registered!\n");
+ return;
+ }
+ mbi = *(void **)0x500;
+ mbi_len = *(u32 *)0x504;
+ mbi_initialized = 1;
+ printk_debug("SMI#: Registered MBI at %p (%d bytes)\n", mbi, mbi_len);
+ break;
+
+ default:
+ printk_debug("SMI#: Unknown function APM_CNT=%02x\n", reg8);
+ }
+}
+
+static void southbridge_smi_pm1(unsigned int node, smm_state_save_area_t *state_save)
+{
+ u16 pm1_sts;
+
+ pm1_sts = reset_pm1_status();
+ dump_pm1_status(pm1_sts);
+
+ /* While OSPM is not active, poweroff immediately
+ * on a power button event.
+ */
+ if (pm1_sts & PWRBTN_STS) {
+ // power button pressed
+ u32 reg32;
+ reg32 = (7 << 10) | (1 << 13);
+ outl(reg32, pmbase + PM1_CNT);
+ }
+}
+
+static void southbridge_smi_gpe0(unsigned int node, smm_state_save_area_t *state_save)
+{
+ u32 gpe0_sts;
+
+ gpe0_sts = reset_gpe0_status();
+ dump_gpe0_status(gpe0_sts);
+}
+
+void __attribute__((weak)) mainboard_smi_gpi(u16 gpi_sts);
+
+static void southbridge_smi_gpi(unsigned int node, smm_state_save_area_t *state_save)
+{
+ u16 reg16;
+ reg16 = inw(pmbase + ALT_GP_SMI_STS);
+ outl(reg16, pmbase + ALT_GP_SMI_STS);
+
+ reg16 &= inw(pmbase + ALT_GP_SMI_EN);
+
+ if (mainboard_smi_gpi) {
+ mainboard_smi_gpi(reg16);
+ } else {
+ if (reg16)
+ printk_debug("GPI (mask %04x)\n",reg16);
+ }
+}
+
+static void southbridge_smi_mc(unsigned int node, smm_state_save_area_t *state_save)
+{
+ u32 reg32;
+
+ reg32 = inl(pmbase + SMI_EN);
+
+ /* Are periodic SMIs enabled? */
+ if ((reg32 & MCSMI_EN) == 0)
+ return;
+
+ printk_debug("Microcontroller SMI.\n");
+}
+
+
+
+static void southbridge_smi_tco(unsigned int node, smm_state_save_area_t *state_save)
+{
+ u32 tco_sts;
+
+ tco_sts = reset_tco_status();
+
+ /* Any TCO event? */
+ if (!tco_sts)
+ return;
+
+ if (tco_sts & (1 << 8)) { // BIOSWR
+ u8 bios_cntl;
+
+ bios_cntl = pci_read_config16(PCI_DEV(0, 0x1f, 0), 0xdc);
+
+ if (bios_cntl & 1) {
+ /* BWE is RW, so the SMI was caused by a
+ * write to BWE, not by a write to the BIOS
+ */
+
+ /* This is the place where we notice someone
+ * is trying to tinker with the BIOS. We are
+ * trying to be nice and just ignore it. A more
+ * resolute answer would be to power down the
+ * box.
+ */
+ printk_debug("Switching back to RO\n");
+ pci_write_config32(PCI_DEV(0, 0x1f, 0), 0xdc, (bios_cntl & ~1));
+ } /* No else for now? */
+ } else if (tco_sts & (1 << 3)) { /* TIMEOUT */
+ /* Handle TCO timeout */
+ printk_debug("TCO Timeout.\n");
+ } else if (!tco_sts) {
+ dump_tco_status(tco_sts);
+ }
+}
+
+static void southbridge_smi_periodic(unsigned int node, smm_state_save_area_t *state_save)
+{
+ u32 reg32;
+
+ reg32 = inl(pmbase + SMI_EN);
+
+ /* Are periodic SMIs enabled? */
+ if ((reg32 & PERIODIC_EN) == 0)
+ return;
+
+ printk_debug("Periodic SMI.\n");
+}
+
+static void southbridge_smi_monitor(unsigned int node, smm_state_save_area_t *state_save)
+{
+#define IOTRAP(x) (trap_sts & (1 << x))
+#if 0
+ u32 trap_sts, trap_cycle;
+ u32 data, mask = 0;
+ int i;
+
+ trap_sts = RCBA32(0x1e00); // TRSR - Trap Status Register
+ RCBA32(0x1e00) = trap_sts; // Clear trap(s) in TRSR
+
+ trap_cycle = RCBA32(0x1e10);
+ for (i=16; i<20; i++) {
+ if (trap_cycle & (1 << i))
+ mask |= (0xff << ((i - 16) << 2));
+ }
+
+
+ /* IOTRAP(3) SMI function call */
+ if (IOTRAP(3)) {
+ if (gnvs && gnvs->smif)
+ io_trap_handler(gnvs->smif); // call function smif
+ return;
+ }
+
+ /* IOTRAP(2) currently unused
+ * IOTRAP(1) currently unused */
+
+ /* IOTRAP(0) SMIC */
+ if (IOTRAP(0)) {
+ if (!(trap_cycle & (1 << 24))) { // It's a write
+ printk_debug("SMI1 command\n");
+ data = RCBA32(0x1e18);
+ data &= mask;
+ // if (smi1)
+ // southbridge_smi_command(data);
+ // return;
+ }
+ // Fall through to debug
+ }
+
+ printk_debug(" trapped io address = 0x%x\n", trap_cycle & 0xfffc);
+ for (i=0; i < 4; i++) if(IOTRAP(i)) printk_debug(" TRAP = %d\n", i);
+ printk_debug(" AHBE = %x\n", (trap_cycle >> 16) & 0xf);
+ printk_debug(" MASK = 0x%08x\n", mask);
+ printk_debug(" read/write: %s\n", (trap_cycle & (1 << 24)) ? "read" : "write");
+
+ if (!(trap_cycle & (1 << 24))) {
+ /* Write Cycle */
+ data = RCBA32(0x1e18);
+ printk_debug(" iotrap written data = 0x%08x\n", data);
+ }
+#endif
+#undef IOTRAP
+}
+
+typedef void (*smi_handler)(unsigned int node,
+ smm_state_save_area_t *state_save);
+
+smi_handler 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
+ southbridge_smi_gpi, // [10] GPI_STS
+ southbridge_smi_mc, // [11] MCSMI_STS
+ NULL, // [12] DEVMON_STS
+ 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
+ southbridge_smi_monitor, // [21] MONITOR_STS
+ NULL, // [22] reserved
+ NULL, // [23] reserved
+ NULL, // [24] reserved
+ NULL, // [25] EL_SMI_STS
+ NULL, // [26] SPI_STS
+ NULL, // [27] reserved
+ NULL, // [28] reserved
+ NULL, // [29] reserved
+ NULL, // [30] reserved
+ NULL // [31] reserved
+};
+
+/**
+ * @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, 0x1f, 0), 0x40) & 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 < 31; i++) {
+ if (smi_sts & (1 << i)) {
+ if (southbridge_smi[i])
+ southbridge_smi[i](node, state_save);
+ else {
+ printk_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/intel/i82801dx/i82801dx_tco_timer.c b/src/southbridge/intel/i82801dx/i82801dx_tco_timer.c
new file mode 100644
index 0000000..ea5485f
--- /dev/null
+++ b/src/southbridge/intel/i82801dx/i82801dx_tco_timer.c
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008 Joseph Smith <joe@settoplinux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+ *
+ */
+
+static void i82801dx_halt_tco_timer(void)
+{
+ device_t dev;
+ uint16_t halt_tco_timer;
+
+ /* Set the LPC device statically. */
+ dev = PCI_DEV(0x0, 0x1f, 0x0);
+
+ /* Temporarily set ACPI base address (I/O space). */
+ pci_write_config32(dev, PMBASE, (PMBASE_ADDR | 1));
+
+ /* Enable ACPI I/O. */
+ pci_write_config8(dev, ACPI_CNTL, 0x10);
+
+ /* Halt the TCO timer, preventing SMI and automatic reboot */
+ outw(inw(PMBASE_ADDR + TCOBASE + TCO1_CNT) | (1 << 11), PMBASE_ADDR + TCOBASE + TCO1_CNT);
+}
diff --git a/util/cbfstool/cbfs.h b/util/cbfstool/cbfs.h
index 9d57165..9661bbd 100644
--- a/util/cbfstool/cbfs.h
+++ b/util/cbfstool/cbfs.h
@@ -68,9 +68,14 @@
Users are welcome to use any other value for their
components */
-#define CBFS_COMPONENT_STAGE 0x10
-#define CBFS_COMPONENT_PAYLOAD 0x20
-#define CBFS_COMPONENT_OPTIONROM 0x30
+#define CBFS_COMPONENT_STAGE 0x10
+#define CBFS_COMPONENT_PAYLOAD 0x20
+#define CBFS_COMPONENT_OPTIONROM 0x30
+#define CBFS_COMPONENT_BOOTSPLASH 0x40
+#define CBFS_COMPONENT_RAW 0x50
+#define CBFS_COMPONENT_VSA 0x51
+#define CBFS_COMPONENT_MBI 0x52
+#define CBFS_COMPONENT_MICROCODE 0x53
/* The deleted type is chosen to be a value
* that can be written in a FLASH from all other
diff --git a/util/cbfstool/common.c b/util/cbfstool/common.c
index 784e1f9..e0f4c31 100644
--- a/util/cbfstool/common.c
+++ b/util/cbfstool/common.c
@@ -128,6 +128,11 @@
{CBFS_COMPONENT_STAGE, "stage"},
{CBFS_COMPONENT_PAYLOAD, "payload"},
{CBFS_COMPONENT_OPTIONROM, "optionrom"},
+ {CBFS_COMPONENT_BOOTSPLASH, "bootsplash"},
+ {CBFS_COMPONENT_RAW, "raw"},
+ {CBFS_COMPONENT_VSA, "vsa"},
+ {CBFS_COMPONENT_MBI, "mbi"},
+ {CBFS_COMPONENT_MICROCODE, "microcode"},
{CBFS_COMPONENT_DELETED, "deleted"},
{CBFS_COMPONENT_NULL, "null"}
};
diff --git a/util/x86emu/yabel/vbe.c b/util/x86emu/yabel/vbe.c
index 90b468b..6814b19 100644
--- a/util/x86emu/yabel/vbe.c
+++ b/util/x86emu/yabel/vbe.c
@@ -795,12 +795,11 @@
* cares. */
int imagesize = 1024*768*2;
- struct cbfs_file *file = cbfs_find("bootsplash.jpg");
- if (!file) {
+ unsigned char *jpeg = cbfs_find_file("bootsplash.jpg", CBFS_TYPE_BOOTSPLASH);
+ if (!jpeg) {
DEBUG_PRINTF_VBE("Could not find bootsplash.jpg\n");
return;
}
- unsigned char *jpeg = ((unsigned char *)file) + ntohl(file->offset);
DEBUG_PRINTF_VBE("Splash at %08x ...\n", jpeg);
dump(jpeg, 64);