This patch implements MBI (modular bios interface) support to the i830 chipset.
authorStefan Reinauer <stepan@coresystems.de>
Mon, 1 Mar 2010 08:34:19 +0000 (08:34 +0000)
committerStefan Reinauer <stepan@openbios.org>
Mon, 1 Mar 2010 08:34:19 +0000 (08:34 +0000)
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

33 files changed:
src/Kconfig
src/arch/i386/Makefile.inc
src/devices/Kconfig
src/include/cbfs.h
src/lib/Makefile.inc
src/lib/cbfs.c
src/mainboard/rca/rm4100/Kconfig
src/mainboard/rca/rm4100/Makefile.inc
src/mainboard/rca/rm4100/devicetree.cb
src/mainboard/rca/rm4100/mainboard.c
src/mainboard/rca/rm4100/mainboard_smi.c [new file with mode: 0644]
src/mainboard/rca/rm4100/romstage.c
src/mainboard/thomson/ip1000/Kconfig
src/mainboard/thomson/ip1000/Makefile.inc
src/mainboard/thomson/ip1000/devicetree.cb
src/mainboard/thomson/ip1000/mainboard.c
src/mainboard/thomson/ip1000/mainboard_smi.c [new file with mode: 0644]
src/mainboard/thomson/ip1000/romstage.c
src/northbridge/intel/i82830/Makefile.inc
src/northbridge/intel/i82830/i82830_smihandler.c [new file with mode: 0644]
src/northbridge/intel/i82830/northbridge.c
src/northbridge/intel/i82830/raminit.c
src/northbridge/intel/i82830/vga.c
src/southbridge/intel/i82801dx/Kconfig
src/southbridge/intel/i82801dx/Makefile.inc
src/southbridge/intel/i82801dx/i82801dx_ac97.c
src/southbridge/intel/i82801dx/i82801dx_nvs.h [new file with mode: 0644]
src/southbridge/intel/i82801dx/i82801dx_smi.c [new file with mode: 0644]
src/southbridge/intel/i82801dx/i82801dx_smihandler.c [new file with mode: 0644]
src/southbridge/intel/i82801dx/i82801dx_tco_timer.c [new file with mode: 0644]
util/cbfstool/cbfs.h
util/cbfstool/common.c
util/x86emu/yabel/vbe.c

index dfb2d71a4c02076ef37fc31c992bc95439723be1..0fae6216dd44554747c626d55d6b3f01748bac7e 100644 (file)
@@ -447,6 +447,66 @@ config FALLBACK_VGA_BIOS_ID
          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"
index e24bd1b421d39df71f72178e1f4efb14adc01809..a16972ca9383b5b91f6bcc58fedce0c5fdc7a1e3 100644 (file)
@@ -27,6 +27,14 @@ endif
 ifeq ($(CONFIG_VGA_BIOS),y)
        @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
index 08e532d12c7221be61f9fc2daf482e0d21bb8ff6..5e13e4e39303eb3d1a928122c2498d83469932c5 100644 (file)
@@ -167,36 +167,6 @@ config YABEL_DIRECTHW
          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
index 38f18a461059d862b764210e2db2524433303091..d169c28799a7748f623da3e3ebeb5b3ad18de10e 100644 (file)
     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 @@ int cbfs_execute_stage(const char *name);
 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
index cbff717c32748f850569576d8edd619191bcaa89..95c10cf01163ef06a0410594a32ffb1a7148d8c0 100644 (file)
@@ -31,3 +31,5 @@ obj-$(CONFIG_BOOTSPLASH) += jpeg.o
 ifdef POST_EVALUATION
 $(obj)/lib/version.o :: $(obj)/build.h
 endif
+
+smmobj-y += memcpy.o
index 0bb6e838fb9c63e5cd9e7c2821ba9638a191aa99..e694952f39252875c1ec21acdda29c4a5945f6b1 100644 (file)
 #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_decompress(int algo, void *src, void *dst, int len)
        }
 }
 
-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_file *cbfs_find(const char *name)
        }
 }
 
-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 @@ struct cbfs_stage *cbfs_find_file(const char *name, int type)
        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 @@ void * cbfs_load_stage(const char *name)
        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 @@ int cbfs_execute_stage(const char *name)
  * 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)
index cdca002ea3e68b8c486b8b3abd013c233525bbd5..1654128b0373d331fd76c5a4ae6e8275148869d5 100644 (file)
@@ -9,6 +9,7 @@ config BOARD_RCA_RM4100
        select HAVE_PIRQ_TABLE
        select UDELAY_TSC
        select BOARD_ROMSIZE_KB_512
+       select HAVE_SMI_HANDLER
 
 config MAINBOARD_DIR
        string
index 5688262e6260b7ec5a1b0c6748e8f52d7a2afc7f..38a5a61fddc1f674b64f289150926b11c9393020 100644 (file)
@@ -1 +1,4 @@
 ROMCCFLAGS=-mcpu=p3 -O
+
+smmobj-$(CONFIG_HAVE_SMI_HANDLER) += mainboard_smi.o
+
index 2b04ad7d3a0403f06b7e02f9a6cb7bb15ea95885..4dff3bea53d16173facad82d68f1e2dfa3228a0c 100644 (file)
@@ -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 @@ chip northbridge/intel/i82830         # Northbridge
       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 @@ chip northbridge/intel/i82830                # Northbridge
       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
 
index cb907496e13272003732f239516aa3b1a67b2005..0324266a8d059478b9f74774803e9c9fd111d39d 100644 (file)
 #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 (file)
index 0000000..3e24235
--- /dev/null
@@ -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;
+}
index cf7464442db358d878179e47ef201ce9fa2f4c23..8b70d9ffc78d53a6433e1b4969153aea06538826 100644 (file)
@@ -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 mb_early_setup(void)
 
 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 @@ static void main(unsigned long bist)
        /* 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();
 
index b78a20e388b6306b297b1314f77e44e1d00259f6..48ab245fd7916db59770bc4b2f97b65f5a9a1e0b 100644 (file)
@@ -9,6 +9,7 @@ config BOARD_THOMSON_IP1000
        select HAVE_PIRQ_TABLE
        select UDELAY_TSC
        select BOARD_ROMSIZE_KB_512
+       select HAVE_SMI_HANDLER
 
 config MAINBOARD_DIR
        string
index 5688262e6260b7ec5a1b0c6748e8f52d7a2afc7f..38a5a61fddc1f674b64f289150926b11c9393020 100644 (file)
@@ -1 +1,4 @@
 ROMCCFLAGS=-mcpu=p3 -O
+
+smmobj-$(CONFIG_HAVE_SMI_HANDLER) += mainboard_smi.o
+
index f38c1c3e67854bbcb54e6bf5bf814a13f9e16e8b..a3ee26cc5991e7e5d0c0638fe38d29f89c188aaa 100644 (file)
@@ -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 @@ chip northbridge/intel/i82830         # Northbridge
       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 @@ chip northbridge/intel/i82830                # Northbridge
       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
 
index c6b4cdf738bc3fff0dfb077acc32818aca341996..daa6b7eb642086fcbfc1b6a1f3db4913b54933f9 100644 (file)
 #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 (file)
index 0000000..3e24235
--- /dev/null
@@ -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;
+}
index cf7464442db358d878179e47ef201ce9fa2f4c23..8b70d9ffc78d53a6433e1b4969153aea06538826 100644 (file)
@@ -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 mb_early_setup(void)
 
 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 @@ static void main(unsigned long bist)
        /* 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();
 
index 3ebb8a5aaf1f964317d211cacd2c1e832928044c..57dedfde73bedcd9c2eca7d2900bdcd683efca80 100644 (file)
@@ -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 (file)
index 0000000..ae5d5e2
--- /dev/null
@@ -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);
+       }
+
+}
index e482db6cf6baf4cd9bcc015159786dbf23e81132..af9663df09d36fbd5c7f53e0aefced98bc6abe6c 100644 (file)
@@ -116,7 +116,7 @@ static void pci_domain_set_resources(device_t dev)
                 */
                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;
index 9cb194ec22747c481f784da58cfc88028409a857..2b747158c6dcf918c14716220f69a35caeac3833 100644 (file)
@@ -536,6 +536,7 @@ static void northbridge_set_registers(void)
 
        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");
index e9cfdac0c65332ed3b9c54cfef4ced8b4ab49503..8c1cac0a842866d4d9ce47adbc21d8fc8579d812 100644 (file)
 #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 = {
index 6a35691b5d10b3376dd18bfbbe4fc086f4fcfdda..62da5cf8568cf88b5bc071354ac85f751796b8e2 100644 (file)
@@ -1,2 +1,3 @@
 config SOUTHBRIDGE_INTEL_I82801DX
        bool
+       select IOAPIC
index 7167e1d391970e951d3a2f98806eed405a3595f0..562e80afe0efa8c3a6c42f1013fb05a5d7bf2173 100644 (file)
@@ -7,3 +7,6 @@ driver-y += i82801dx_ac97.o
 #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
index 752449865db03865fca89273d4008c82ff2825e0..10b100beee94effb8c69457032a62e1b4635fd1a 100644 (file)
 /*
- * (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,
 };
+
+
diff --git a/src/southbridge/intel/i82801dx/i82801dx_nvs.h b/src/southbridge/intel/i82801dx/i82801dx_nvs.h
new file mode 100644 (file)
index 0000000..03f8de7
--- /dev/null
@@ -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 (file)
index 0000000..b934dcf
--- /dev/null
@@ -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 (file)
index 0000000..9994429
--- /dev/null
@@ -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 (file)
index 0000000..ea5485f
--- /dev/null
@@ -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);
+}
index 9d57165d85925781450652d6655b4b10784c52a0..9661bbd2c983032bc525a6724c1fc723dc460d88 100644 (file)
@@ -68,9 +68,14 @@ struct cbfs_payload {
     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
index 784e1f9f5fba8017c5c88a8d961e35eb2d44f31e..e0f4c312a35c86f7d27103b5284fb75f3d3b80a2 100644 (file)
@@ -128,6 +128,11 @@ struct filetypes_t {
        {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"}
 };
index 90b468bd25af9d09bd75b96dee245c84a68199df..6814b1964f9dd93a93b6a985b4c9de2e45380c89 100644 (file)
@@ -795,12 +795,11 @@ void vbe_set_graphics(void)
         * 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);