[coreboot] [commit] r5177 - in trunk: src src/arch/i386 src/devices src/include src/lib src/mainboard/rca/rm4100 src/mainboard/thomson/ip1000 src/northbridge/intel/i82830 src/southbridge/intel/i82801dx util/c...

repository service svn at coreboot.org
Mon Mar 1 09:34:19 CET 2010


Author: stepan
Date: Mon Mar  1 09:34:19 2010
New Revision: 5177
URL: http://tracker.coreboot.org/trac/coreboot/changeset/5177

Log:
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 at coresystems.de>
Acked-by: Ronald G. Minnich <rminnich at gmail.com>

Added:
   trunk/src/mainboard/rca/rm4100/mainboard_smi.c
   trunk/src/mainboard/thomson/ip1000/mainboard_smi.c
   trunk/src/northbridge/intel/i82830/i82830_smihandler.c
   trunk/src/southbridge/intel/i82801dx/i82801dx_nvs.h
   trunk/src/southbridge/intel/i82801dx/i82801dx_smi.c
   trunk/src/southbridge/intel/i82801dx/i82801dx_smihandler.c
   trunk/src/southbridge/intel/i82801dx/i82801dx_tco_timer.c
Modified:
   trunk/src/Kconfig
   trunk/src/arch/i386/Makefile.inc
   trunk/src/devices/Kconfig
   trunk/src/include/cbfs.h
   trunk/src/lib/Makefile.inc
   trunk/src/lib/cbfs.c
   trunk/src/mainboard/rca/rm4100/Kconfig
   trunk/src/mainboard/rca/rm4100/Makefile.inc
   trunk/src/mainboard/rca/rm4100/devicetree.cb
   trunk/src/mainboard/rca/rm4100/mainboard.c
   trunk/src/mainboard/rca/rm4100/romstage.c
   trunk/src/mainboard/thomson/ip1000/Kconfig
   trunk/src/mainboard/thomson/ip1000/Makefile.inc
   trunk/src/mainboard/thomson/ip1000/devicetree.cb
   trunk/src/mainboard/thomson/ip1000/mainboard.c
   trunk/src/mainboard/thomson/ip1000/romstage.c
   trunk/src/northbridge/intel/i82830/Makefile.inc
   trunk/src/northbridge/intel/i82830/northbridge.c
   trunk/src/northbridge/intel/i82830/raminit.c
   trunk/src/northbridge/intel/i82830/vga.c
   trunk/src/southbridge/intel/i82801dx/Kconfig
   trunk/src/southbridge/intel/i82801dx/Makefile.inc
   trunk/src/southbridge/intel/i82801dx/i82801dx_ac97.c
   trunk/util/cbfstool/cbfs.h
   trunk/util/cbfstool/common.c
   trunk/util/x86emu/yabel/vbe.c

Modified: trunk/src/Kconfig
==============================================================================
--- trunk/src/Kconfig	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/Kconfig	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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"

Modified: trunk/src/arch/i386/Makefile.inc
==============================================================================
--- trunk/src/arch/i386/Makefile.inc	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/arch/i386/Makefile.inc	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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
 

Modified: trunk/src/devices/Kconfig
==============================================================================
--- trunk/src/devices/Kconfig	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/devices/Kconfig	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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

Modified: trunk/src/include/cbfs.h
==============================================================================
--- trunk/src/include/cbfs.h	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/include/cbfs.h	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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

Modified: trunk/src/lib/Makefile.inc
==============================================================================
--- trunk/src/lib/Makefile.inc	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/lib/Makefile.inc	Mon Mar  1 09:34:19 2010	(r5177)
@@ -31,3 +31,5 @@
 ifdef POST_EVALUATION
 $(obj)/lib/version.o :: $(obj)/build.h
 endif
+
+smmobj-y += memcpy.o

Modified: trunk/src/lib/cbfs.c
==============================================================================
--- trunk/src/lib/cbfs.c	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/lib/cbfs.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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)

Modified: trunk/src/mainboard/rca/rm4100/Kconfig
==============================================================================
--- trunk/src/mainboard/rca/rm4100/Kconfig	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/mainboard/rca/rm4100/Kconfig	Mon Mar  1 09:34:19 2010	(r5177)
@@ -9,6 +9,7 @@
 	select HAVE_PIRQ_TABLE
 	select UDELAY_TSC
 	select BOARD_ROMSIZE_KB_512
+	select HAVE_SMI_HANDLER
 
 config MAINBOARD_DIR
 	string

Modified: trunk/src/mainboard/rca/rm4100/Makefile.inc
==============================================================================
--- trunk/src/mainboard/rca/rm4100/Makefile.inc	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/mainboard/rca/rm4100/Makefile.inc	Mon Mar  1 09:34:19 2010	(r5177)
@@ -1 +1,4 @@
 ROMCCFLAGS=-mcpu=p3 -O
+
+smmobj-$(CONFIG_HAVE_SMI_HANDLER) += mainboard_smi.o
+

Modified: trunk/src/mainboard/rca/rm4100/devicetree.cb
==============================================================================
--- trunk/src/mainboard/rca/rm4100/devicetree.cb	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/mainboard/rca/rm4100/devicetree.cb	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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
 

Modified: trunk/src/mainboard/rca/rm4100/mainboard.c
==============================================================================
--- trunk/src/mainboard/rca/rm4100/mainboard.c	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/mainboard/rca/rm4100/mainboard.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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")
 };

Added: trunk/src/mainboard/rca/rm4100/mainboard_smi.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/mainboard/rca/rm4100/mainboard_smi.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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;
+}

Modified: trunk/src/mainboard/rca/rm4100/romstage.c
==============================================================================
--- trunk/src/mainboard/rca/rm4100/romstage.c	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/mainboard/rca/rm4100/romstage.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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();
 

Modified: trunk/src/mainboard/thomson/ip1000/Kconfig
==============================================================================
--- trunk/src/mainboard/thomson/ip1000/Kconfig	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/mainboard/thomson/ip1000/Kconfig	Mon Mar  1 09:34:19 2010	(r5177)
@@ -9,6 +9,7 @@
 	select HAVE_PIRQ_TABLE
 	select UDELAY_TSC
 	select BOARD_ROMSIZE_KB_512
+	select HAVE_SMI_HANDLER
 
 config MAINBOARD_DIR
 	string

Modified: trunk/src/mainboard/thomson/ip1000/Makefile.inc
==============================================================================
--- trunk/src/mainboard/thomson/ip1000/Makefile.inc	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/mainboard/thomson/ip1000/Makefile.inc	Mon Mar  1 09:34:19 2010	(r5177)
@@ -1 +1,4 @@
 ROMCCFLAGS=-mcpu=p3 -O
+
+smmobj-$(CONFIG_HAVE_SMI_HANDLER) += mainboard_smi.o
+

Modified: trunk/src/mainboard/thomson/ip1000/devicetree.cb
==============================================================================
--- trunk/src/mainboard/thomson/ip1000/devicetree.cb	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/mainboard/thomson/ip1000/devicetree.cb	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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
 

Modified: trunk/src/mainboard/thomson/ip1000/mainboard.c
==============================================================================
--- trunk/src/mainboard/thomson/ip1000/mainboard.c	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/mainboard/thomson/ip1000/mainboard.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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")
 };

Added: trunk/src/mainboard/thomson/ip1000/mainboard_smi.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/mainboard/thomson/ip1000/mainboard_smi.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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;
+}

Modified: trunk/src/mainboard/thomson/ip1000/romstage.c
==============================================================================
--- trunk/src/mainboard/thomson/ip1000/romstage.c	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/mainboard/thomson/ip1000/romstage.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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();
 

Modified: trunk/src/northbridge/intel/i82830/Makefile.inc
==============================================================================
--- trunk/src/northbridge/intel/i82830/Makefile.inc	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/northbridge/intel/i82830/Makefile.inc	Mon Mar  1 09:34:19 2010	(r5177)
@@ -1,2 +1,4 @@
 driver-y += northbridge.o
 driver-y += vga.o
+
+smmobj-$(CONFIG_HAVE_SMI_HANDLER) += i82830_smihandler.o

Added: trunk/src/northbridge/intel/i82830/i82830_smihandler.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/northbridge/intel/i82830/i82830_smihandler.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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);
+	}
+
+}

Modified: trunk/src/northbridge/intel/i82830/northbridge.c
==============================================================================
--- trunk/src/northbridge/intel/i82830/northbridge.c	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/northbridge/intel/i82830/northbridge.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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;

Modified: trunk/src/northbridge/intel/i82830/raminit.c
==============================================================================
--- trunk/src/northbridge/intel/i82830/raminit.c	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/northbridge/intel/i82830/raminit.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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");

Modified: trunk/src/northbridge/intel/i82830/vga.c
==============================================================================
--- trunk/src/northbridge/intel/i82830/vga.c	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/northbridge/intel/i82830/vga.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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 = {

Modified: trunk/src/southbridge/intel/i82801dx/Kconfig
==============================================================================
--- trunk/src/southbridge/intel/i82801dx/Kconfig	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/southbridge/intel/i82801dx/Kconfig	Mon Mar  1 09:34:19 2010	(r5177)
@@ -1,2 +1,3 @@
 config SOUTHBRIDGE_INTEL_I82801DX
 	bool
+	select IOAPIC

Modified: trunk/src/southbridge/intel/i82801dx/Makefile.inc
==============================================================================
--- trunk/src/southbridge/intel/i82801dx/Makefile.inc	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/southbridge/intel/i82801dx/Makefile.inc	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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

Modified: trunk/src/southbridge/intel/i82801dx/i82801dx_ac97.c
==============================================================================
--- trunk/src/southbridge/intel/i82801dx/i82801dx_ac97.c	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/src/southbridge/intel/i82801dx/i82801dx_ac97.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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
+
+#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);
 
-static struct device_operations ac97audio_ops  = {
+	/* 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,
 };
+
+

Added: trunk/src/southbridge/intel/i82801dx/i82801dx_nvs.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/southbridge/intel/i82801dx/i82801dx_nvs.h	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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;
+

Added: trunk/src/southbridge/intel/i82801dx/i82801dx_smi.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/southbridge/intel/i82801dx/i82801dx_smi.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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);
+}

Added: trunk/src/southbridge/intel/i82801dx/i82801dx_smihandler.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/southbridge/intel/i82801dx/i82801dx_smihandler.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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);
+	}
+
+}

Added: trunk/src/southbridge/intel/i82801dx/i82801dx_tco_timer.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/southbridge/intel/i82801dx/i82801dx_tco_timer.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008 Joseph Smith <joe at 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);
+}

Modified: trunk/util/cbfstool/cbfs.h
==============================================================================
--- trunk/util/cbfstool/cbfs.h	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/util/cbfstool/cbfs.h	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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

Modified: trunk/util/cbfstool/common.c
==============================================================================
--- trunk/util/cbfstool/common.c	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/util/cbfstool/common.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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"}
 };

Modified: trunk/util/x86emu/yabel/vbe.c
==============================================================================
--- trunk/util/x86emu/yabel/vbe.c	Mon Mar  1 08:42:02 2010	(r5176)
+++ trunk/util/x86emu/yabel/vbe.c	Mon Mar  1 09:34:19 2010	(r5177)
@@ -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);
 




More information about the coreboot mailing list