- Moved hlt() to it's own header.
- Reworked pnp superio device support.  Now complete superio support is less than 100 lines.
- Added support for hard coding resource assignments in Config.lb
- Minor bug fixes to romcc
- Initial support for catching the x86 processor BIST error codes.  I've only seen
  this trigger once in production during a very suspcious reset but...
- added raminit_test to test the code paths in raminit.c for the Opteron
- Removed the IORESOURCE_SET bit and added IORESOURCE_ASSIGNED and IORESOURCE_STORED
  so we can tell what we have really done.
- Added generic AGP/IOMMU setting code to x86
- Added an implementation of memmove and removed reserved identifiers from memcpy
- Added minimal support for booting on pre b3 stepping K8 cores
- Moved the checksum on amd8111 boards because our default location was on top of
  extended RTC registers
- On the Hdama added support for enabling i2c hub so we can get at the temperature
  sensors.  Not that i2c bus was implemented well enough to make that useful.
- Redid the Opteron port so we should only need one reset and most of memory initialization
  is done in cpu_fixup.  This is much, much faster.
- Attempted to make the VGA IO region assigment work.  The code seems to work now...
- Redid the error handling in amdk8/raminit.c to distinguish between a bad value
  and a smbus error, and moved memory clearing out to cpufixup.
- Removed CONFIG_KEYBOARD as it was useless.  See pc87360/superio.c for how to
  setup a legacy keyboard properly.
- Reworked the register values for standard hardware, moving the defintions from
  chip.h into the headers of the initialization routines.  This is much saner
  and is actually implemented.
- Made the hdama port an under clockers BIOS.  I debuged so many interesting problems.
- On amd8111_lpc added setup of architectural/legacy hardware
- Enabled PCI error reporting as much as possible.
- Enhanded build_opt_tbl to generate a header of the cmos option locations so
  that romcc compiled code can query the cmos options.
- In romcc gracefully handle function names that degenerate into function pointers
- Bumped the version to 1.1.6 as we are getting closer to 2.0

  TODO finish optimizing the HT links of non dual boards
  TODO make all Opteron board work again
  TODO convert all superio devices to use the new helpers
  TODO convert the via/epia to freebios2 conventions
  TODO cpu fixup/setup by cpu type


git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1390 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
diff --git a/src/arch/i386/include/arch/hlt.h b/src/arch/i386/include/arch/hlt.h
new file mode 100644
index 0000000..86ed7c8
--- /dev/null
+++ b/src/arch/i386/include/arch/hlt.h
@@ -0,0 +1,20 @@
+#ifndef ARCH_HLT_H
+#define ARCH_HLT_H
+
+#ifdef __ROMCC__
+static void hlt(void)
+{
+	__builtin_hlt();
+}
+
+#endif
+
+#ifdef __GNUC__
+static inline void hlt(void)
+{
+	asm("hlt");
+	return;
+}
+#endif
+
+#endif /* ARCH_HLT_H */
diff --git a/src/arch/i386/include/arch/romcc_io.h b/src/arch/i386/include/arch/romcc_io.h
index 1a64635..c3a0ff7 100644
--- a/src/arch/i386/include/arch/romcc_io.h
+++ b/src/arch/i386/include/arch/romcc_io.h
@@ -1,11 +1,7 @@
 #ifndef ARCH_ROMCC_IO_H
 #define ARCH_ROMCC_IO_H 1
 
-
-static void hlt(void)
-{
-	__builtin_hlt();
-}
+#include <stdint.h>
 
 typedef __builtin_div_t div_t;
 typedef __builtin_ldiv_t ldiv_t;
@@ -59,6 +55,9 @@
 #define PCI_ID(VENDOR_ID, DEVICE_ID) \
 	((((DEVICE_ID) & 0xFFFF) << 16) | ((VENDOR_ID) & 0xFFFF))
 
+
+#define PNP_DEV(PORT, FUNC) (((PORT) << 8) | (FUNC))
+
 typedef unsigned device_t;
 
 static unsigned char pci_read_config8(device_t dev, unsigned where)
@@ -122,4 +121,52 @@
 	return PCI_DEV_INVALID;
 }
 
+
+/* Generic functions for pnp devices */
+static inline void pnp_write_config(device_t dev, uint8_t reg, uint8_t value)
+{
+	unsigned port = dev >> 8;
+	outb(reg, port );
+	outb(value, port +1);
+}
+
+static inline uint8_t pnp_read_config(device_t dev, uint8_t reg)
+{
+	unsigned port = dev >> 8;
+	outb(reg, port);
+	return inb(port +1);
+}
+
+static inline void pnp_set_logical_device(device_t dev)
+{
+	unsigned device = dev & 0xff;
+	pnp_write_config(dev, 0x07, device);
+}
+
+static inline void pnp_set_enable(device_t dev, int enable)
+{
+	pnp_write_config(dev, 0x30, enable?0x1:0x0);
+}
+
+static inline int pnp_read_enable(device_t dev)
+{
+	return !!pnp_read_config(dev, 0x30);
+}
+
+static inline void pnp_set_iobase(device_t dev, unsigned index, unsigned iobase)
+{
+	pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff);
+	pnp_write_config(dev, index + 1, iobase & 0xff);
+}
+
+static inline void pnp_set_irq(device_t dev, unsigned index, unsigned irq)
+{
+	pnp_write_config(dev, index, irq);
+}
+
+static inline void pnp_set_drq(device_t dev, unsigned index, unsigned drq)
+{
+	pnp_write_config(dev, index, drq & 0xff);
+}
+
 #endif /* ARCH_ROMCC_IO_H */
diff --git a/src/arch/i386/include/arch/smp/lapic.h b/src/arch/i386/include/arch/smp/lapic.h
new file mode 100644
index 0000000..0ac87aa
--- /dev/null
+++ b/src/arch/i386/include/arch/smp/lapic.h
@@ -0,0 +1,55 @@
+#ifndef ARCH_SMP_LAPIC_H
+#define ARCH_SMP_LAPIC_H
+
+#include <cpu/p6/msr.h>
+#include <cpu/p6/apic.h>
+#include <arch/hlt.h>
+
+static void enable_lapic(void)
+{
+
+	msr_t msr;
+	msr = rdmsr(0x1b);
+	msr.hi &= 0xffffff00;
+	msr.lo &= 0x000007ff;
+	msr.lo |= APIC_DEFAULT_BASE | (1 << 11);
+	wrmsr(0x1b, msr);
+}
+
+static void disable_lapic(void)
+{
+	msr_t msr;
+	msr = rdmsr(0x1b);
+	msr.lo &= ~ (1 << 11);
+	wrmsr(0x1b, msr);
+}
+
+static inline unsigned long lapicid(void)
+{
+	return apic_read(APIC_ID) >> 24;
+}
+
+static void stop_this_cpu(void)
+{
+	unsigned apicid;
+	apicid = lapicid();
+
+	/* Send an APIC INIT to myself */
+	apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+	apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT);
+	/* Wait for the ipi send to finish */
+	apic_wait_icr_idle();
+
+	/* Deassert the APIC INIT */
+	apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+	apic_write(APIC_ICR,  APIC_INT_LEVELTRIG | APIC_DM_INIT);
+	/* Wait for the ipi send to finish */
+	apic_wait_icr_idle();
+
+	/* If I haven't halted spin forever */
+	for(;;) {
+		hlt();
+	}
+}
+
+#endif /* ARCH_SMP_LAPIC_H */
diff --git a/src/arch/i386/lib/cpu.c b/src/arch/i386/lib/cpu.c
index ad982db..f459f3a 100644
--- a/src/arch/i386/lib/cpu.c
+++ b/src/arch/i386/lib/cpu.c
@@ -10,6 +10,7 @@
 #include <cpu/p6/msr.h>
 #include <cpu/p6/apic.h>
 #include <cpu/p5/cpuid.h>
+#include <arch/smp/lapic.h>
 #if 0
 #include <cpu/l2_cache.h>
 #endif
@@ -97,8 +98,7 @@
 			APIC_DELIVERY_MODE_NMI)
 		);
 
-	printk_debug(" apic_id: %d ",
-		apic_read(APIC_ID));
+	printk_debug(" apic_id: %d ", lapicid());
 
 #else /* APIC */
 #if i686==1
diff --git a/src/arch/i386/smp/start_stop.c b/src/arch/i386/smp/start_stop.c
index b404524..bf26437 100644
--- a/src/arch/i386/smp/start_stop.c
+++ b/src/arch/i386/smp/start_stop.c
@@ -4,16 +4,13 @@
 #include <delay.h>
 #include <string.h>
 #include <console/console.h>
+#include <arch/smp/lapic.h>
+#include <arch/hlt.h>
 
-static inline void hlt(void)
-{
-	asm("hlt");
-	return;
-}
 
 unsigned long this_processors_id(void)
 {
-	return apic_read(APIC_ID) >> 24;
+	return lapicid();
 }
 
 int processor_index(unsigned long apicid)
diff --git a/src/arch/ppc/boot/linuxbios_table.c b/src/arch/ppc/boot/linuxbios_table.c
index 20264c2..f199615 100644
--- a/src/arch/ppc/boot/linuxbios_table.c
+++ b/src/arch/ppc/boot/linuxbios_table.c
@@ -227,6 +227,9 @@
 	struct mem_range *ramp;
 	struct lb_header *head;
 	struct lb_memory *mem;
+#if HAVE_OPTION_TABLE == 1
+	struct lb_record *rec_dest, *rec_src;
+#endif	
 
 	head = lb_table_init(low_table_end);
 	low_table_end = (unsigned long)head;
diff --git a/src/config/Config.lb b/src/config/Config.lb
index 4a99d07..636e553 100644
--- a/src/config/Config.lb
+++ b/src/config/Config.lb
@@ -7,7 +7,7 @@
 makedefine GCC_INC_DIR := $(shell $(CC) -print-search-dirs | sed -ne "s/install: \(.*\)/\1include/gp")
 
 makedefine CPPFLAGS := -I$(TOP)/src/include -I$(TOP)/src/arch/$(ARCH)/include -I$(GCC_INC_DIR) $(CPUFLAGS)
-makedefine ROMCCPPFLAGS := -D__ROMCC__=0 -D__ROMCC_MINOR__=37
+makedefine ROMCCPPFLAGS := -D__ROMCC__=0 -D__ROMCC_MINOR__=38
 makedefine CFLAGS := $(CPU_OPT) $(CPPFLAGS) -Os -nostdinc -nostdlib -fno-builtin  -Wall
 
 makedefine HOSTCFLAGS:= -Os -Wall
@@ -116,12 +116,12 @@
 
 makerule ./romcc   
 	depends	"$(TOP)/util/romcc/romcc.c" 
-	action	"$(HOSTCC) -g $(HOSTCFLAGS) -DVERSION='\"0.37\"' -DRELEASE_DATE='\"21 October 2003\"' $< -o $@"
+	action	"$(HOSTCC) -g $(HOSTCFLAGS) -DVERSION='\"0.38\"' -DRELEASE_DATE='\"18 December 2003\"' $< -o $@"
 end
 
 makerule build_opt_tbl   
-	depends	"$(TOP)/util/options/build_opt_tbl.c $(TOP)/src/include/pc80/mc146818rtc.h $(TOP)/src/include/boot/linuxbios_tables.h" 
-	action	"$(HOSTCC) $(HOSTCFLAGS) $< -o $@"
+	depends	"$(TOP)/util/options/build_opt_tbl.c $(TOP)/src/include/pc80/mc146818rtc.h $(TOP)/src/include/boot/linuxbios_tables.h Makefile.settings Makefile"
+	action	"$(HOSTCC) $(HOSTCFLAGS) $(CPUFLAGS) $< -o $@" 
 end
 
 #makerule /$(TARGET_DIR)/option_table.c
@@ -131,7 +131,12 @@
 
 makerule option_table.c
 	depends	"build_opt_tbl $(MAINBOARD)/cmos.layout" 
-	action	"./build_opt_tbl -b  --config $(MAINBOARD)/cmos.layout"
+	action	"./build_opt_tbl -b  --config $(MAINBOARD)/cmos.layout --header option_table.h"
+end
+
+makerule option_table.h
+	depends	"build_opt_tbl $(MAINBOARD)/cmos.layout" 
+	action	"./build_opt_tbl -b  --config $(MAINBOARD)/cmos.layout --header option_table.h"
 end
 
 if HAVE_OPTION_TABLE
diff --git a/src/config/Options.lb b/src/config/Options.lb
index 936f9c3..a175f35 100644
--- a/src/config/Options.lb
+++ b/src/config/Options.lb
@@ -117,7 +117,7 @@
 	comment "Objcopy command"
 end
 define LINUXBIOS_VERSION
-	default "1.1.5"
+	default "1.1.6"
 	export always
 	comment "LinuxBIOS version"
 end
@@ -318,6 +318,12 @@
 	export always
 	comment "Set for uncompressed image"
 end
+define CONFIG_LB_MEM_TOPK
+	format "%d"
+	default 1024
+	export always
+	comment "Kilobytes of memory to initialized before executing code from RAM"
+end
 define HAVE_OPTION_TABLE
 	default 0
 	export always
@@ -331,6 +337,29 @@
 end
 
 ###############################################
+# CMOS variable options
+###############################################
+define LB_CKS_RANGE_START
+	default 49
+	format "%d"
+	export always
+	comment "First CMOS byte to use for LinuxBIOS options"
+end
+define LB_CKS_RANGE_END
+	default 125
+	format "%d"
+	export always
+	comment "Last CMOS byte to use for LinuxBIOS options"
+end
+define LB_CKS_LOC
+	default 126
+	format "%d"
+	export always
+	comment "Pair of bytes to use for CMOS checksum"
+end
+
+
+###############################################
 # Build targets
 ###############################################
 
@@ -427,16 +456,16 @@
 	export always
 	comment "Vendor of mainboard"
 end
+define MAINBOARD_POWER_ON_AFTER_POWER_FAIL
+	default none
+	export used
+	comment "Default power on after power fail setting"
+end
 define CONFIG_SYS_CLK_FREQ
 	default none
 	export used
 	comment "System clock frequency in MHz"
 end
-define CONFIG_KEYBOARD
-	default 0
-	export used
-	comment "Run PC keyboard enable code"
-end
 define CONFIG_LEGACY_VGABIOS
 	default 0
 	export used
diff --git a/src/cpu/i386/bist32.inc b/src/cpu/i386/bist32.inc
new file mode 100644
index 0000000..d2fb98c
--- /dev/null
+++ b/src/cpu/i386/bist32.inc
@@ -0,0 +1,4 @@
+
+	/* Carefully print the failure if the built in self test did not pass */
+	testl	%eax, %eax
+	jnz	bist32_fail
diff --git a/src/cpu/i386/bist32_fail.inc b/src/cpu/i386/bist32_fail.inc
new file mode 100644
index 0000000..f467b06
--- /dev/null
+++ b/src/cpu/i386/bist32_fail.inc
@@ -0,0 +1,44 @@
+
+
+	jmp bist32_fail_0
+bist32_fail:
+	movl	%eax, %ebp
+
+#if 1
+#define SIO_BASE  0x2e
+#define SIO_INDEX SIO_BASE
+#define SIO_DATA  SIO_BASE+1
+#define SIO_WRITE_CONFIG(value, reg) \
+	movb	reg, %al		; \
+	outb	%al, $(SIO_INDEX)	; \
+	movb	value, %al		; \
+	outb	%al, $(SIO_DATA)
+
+#define SIO_READ_CONFIG(reg) \
+	movb	reg, %al		; \
+	outb	%al, $(SIO_INDEX)	; \
+	inb	$(SIO_DATA), %al
+
+#define SIO_SET_LOGICAL_DEVICE(device) \
+	SIO_WRITE_CONFIG(device, $0x07)
+
+	/* Enable serial 1 */
+	SIO_SET_LOGICAL_DEVICE($3)
+	SIO_WRITE_CONFIG($1, $0x30)
+	SIO_WRITE_CONFIG($0x3, $0x60)
+	SIO_WRITE_CONFIG($0xf8, $0x61)
+
+#endif	
+	CALLSP(serial_init)
+	CONSOLE_DEBUG_TX_STRING($str_bist_failed)
+	CONSOLE_DEBUG_TX_HEX32(%ebp)
+	CONSOLE_DEBUG_TX_STRING($str_bist_newline)
+	jmp .Lhlt
+
+bist32_fail_0:
+
+.section ".rom.data"
+str_bist_failed:	.string "BIST failed: "
+str_bist_newline:	.string "\r\n"
+.previous
+
diff --git a/src/cpu/i386/entry16.inc b/src/cpu/i386/entry16.inc
index 7ab3ff3..f9e921f 100644
--- a/src/cpu/i386/entry16.inc
+++ b/src/cpu/i386/entry16.inc
@@ -33,6 +33,8 @@
 
 _start: 
 	cli
+	/* Save the BIST result */
+	movl	%eax, %ebp
 
 /* thanks to kmliu@sis.tw.com for this TBL fix ... */
 /**/
@@ -93,6 +95,9 @@
 	orl	$0x60000001, %eax /* CD, NW, PE = 1 */
 	movl	%eax, %cr0
 
+	/* Restore BIST to %eax */
+	movl	%ebp, %eax
+
 	/* Now that we are in protected mode jump to a 32 bit code segment. */
 	data32	ljmp	$ROM_CODE_SEG, $__protected_start
 
diff --git a/src/cpu/i386/entry32.inc b/src/cpu/i386/entry32.inc
index 6f55f00..3d30a3f 100644
--- a/src/cpu/i386/entry32.inc
+++ b/src/cpu/i386/entry32.inc
@@ -44,6 +44,9 @@
 	ljmp	$ROM_CODE_SEG, $__protected_start
 	
 __protected_start:
+	/* Save the BIST value */
+	movl	%eax, %ebp
+
 	intel_chip_post_macro(0x10)	/* post 10 */
 
 	movw	$ROM_DATA_SEG, %ax
@@ -53,3 +56,6 @@
 	movw	%ax, %fs
 	movw	%ax, %gs
 
+	/* Restore the BIST value to %eax */
+	movl	%ebp, %eax
+
diff --git a/src/cpu/k8/cpufixup.c b/src/cpu/k8/cpufixup.c
index 6aa6722..2d347de 100644
--- a/src/cpu/k8/cpufixup.c
+++ b/src/cpu/k8/cpufixup.c
@@ -4,8 +4,17 @@
 #include <cpu/p6/msr.h>
 #include <cpu/k8/mtrr.h>
 #include <device/device.h>
-#include "../../northbridge/amd/amdk8/cpu_rev.c"
 #include <device/chip.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <smp/start_stop.h>
+#include <string.h>
+#include <cpu/p6/msr.h>
+#include <cpu/p6/pgtbl.h>
+#include <pc80/mc146818rtc.h>
+#include <arch/smp/lapic.h>
+#include "../../northbridge/amd/amdk8/amdk8.h"
+#include "../../northbridge/amd/amdk8/cpu_rev.c"
 #include "chip.h"
 
 #define MCI_STATUS 0x401
@@ -14,7 +23,7 @@
 {
 	unsigned int tmp;
 	/* Disable cache */
-	/* Write back the cache and flush TLB */
+	/* Write back the cache */
 	asm volatile (
 		"movl  %%cr0, %0\n\t"
 		"orl  $0x40000000, %0\n\t"
@@ -57,6 +66,232 @@
                 );
 }
 
+
+
+#define MTRR_COUNT 8
+#define ZERO_CHUNK_KB 0x800UL /* 2M */
+#define TOLM_KB 0x400000UL
+
+struct mtrr {
+	msr_t base;
+	msr_t mask;
+};
+struct mtrr_state {
+	struct mtrr mtrrs[MTRR_COUNT];
+	msr_t top_mem, top_mem2;
+	msr_t def_type;
+};
+
+static void save_mtrr_state(struct mtrr_state *state)
+{
+	int i;
+	for(i = 0; i < MTRR_COUNT; i++) {
+		state->mtrrs[i].base = rdmsr(MTRRphysBase_MSR(i));
+		state->mtrrs[i].mask = rdmsr(MTRRphysMask_MSR(i));
+	}
+	state->top_mem  = rdmsr(TOP_MEM);
+	state->top_mem2 = rdmsr(TOP_MEM2);
+	state->def_type = rdmsr(MTRRdefType_MSR);
+}
+
+static void restore_mtrr_state(struct mtrr_state *state)
+{
+	int i;
+	disable_cache();
+
+	for(i = 0; i < MTRR_COUNT; i++) {
+		wrmsr(MTRRphysBase_MSR(i), state->mtrrs[i].base);
+		wrmsr(MTRRphysMask_MSR(i), state->mtrrs[i].mask);
+	}
+	wrmsr(TOP_MEM,         state->top_mem);
+	wrmsr(TOP_MEM2,        state->top_mem2);
+	wrmsr(MTRRdefType_MSR, state->def_type);
+
+	enable_cache();
+}
+
+
+#if 0
+static void print_mtrr_state(struct mtrr_state *state)
+{
+	int i;
+	for(i = 0; i < MTRR_COUNT; i++) {
+		printk_debug("var mtrr %d: %08x%08x mask: %08x%08x\n",
+			i,
+			state->mtrrs[i].base.hi, state->mtrrs[i].base.lo,
+			state->mtrrs[i].mask.hi, state->mtrrs[i].mask.lo);
+	}
+	printk_debug("top_mem:  %08x%08x\n",
+		state->top_mem.hi, state->top_mem.lo);
+	printk_debug("top_mem2: %08x%08x\n",
+		state->top_mem2.hi, state->top_mem2.lo);
+	printk_debug("def_type: %08x%08x\n",
+		state->def_type.hi, state->def_type.lo);
+}
+#endif
+
+static void set_init_ecc_mtrrs(void)
+{
+	msr_t msr;
+	int i;
+	disable_cache();
+
+	/* First clear all of the msrs to be safe */
+	for(i = 0; i < MTRR_COUNT; i++) {
+		msr_t zero;
+		zero.lo = zero.hi = 0;
+		wrmsr(MTRRphysBase_MSR(i), zero);
+		wrmsr(MTRRphysMask_MSR(i), zero);
+	}
+
+	/* Write back cache the first 1MB */
+	msr.hi = 0x00000000;
+	msr.lo = 0x00000000 | MTRR_TYPE_WRBACK;
+	wrmsr(MTRRphysBase_MSR(0), msr);
+	msr.hi = 0x000000ff;
+	msr.lo = ~((CONFIG_LB_MEM_TOPK << 10) - 1) | 0x800;
+	wrmsr(MTRRphysMask_MSR(0), msr);
+
+	/* Set the default type to write combining */
+	msr.hi = 0x00000000;
+	msr.lo = 0xc00 | MTRR_TYPE_WRCOMB;
+	wrmsr(MTRRdefType_MSR, msr);
+
+	/* Set TOP_MEM to 4G */
+	msr.hi = 0x00000001;
+	msr.lo = 0x00000000;
+	wrmsr(TOP_MEM, msr);
+
+	enable_cache();
+}
+
+
+static void init_ecc_memory(void)
+{
+	unsigned long startk, begink, endk;
+	unsigned long basek;
+	struct mtrr_state mtrr_state;
+	device_t f1_dev, f2_dev, f3_dev;
+	int cpu_index, cpu_id, node_id;
+	int enable_scrubbing;
+	uint32_t dcl;
+	cpu_id = this_processors_id();
+	cpu_index = processor_index(cpu_id);
+	/* For now there is a 1-1 mapping between node_id and cpu_id */
+	node_id = cpu_id;
+
+	f1_dev = dev_find_slot(0, PCI_DEVFN(0x18 + node_id, 1));
+	if (!f1_dev) {
+		die("Cannot find cpu function 1\n");
+	}
+	f2_dev = dev_find_slot(0, PCI_DEVFN(0x18 + node_id, 2));
+	if (!f2_dev) {
+		die("Cannot find cpu function 2\n");
+	}
+	f3_dev = dev_find_slot(0, PCI_DEVFN(0x18 + node_id, 3));
+	if (!f3_dev) {
+		die("Cannot find cpu function 3\n");
+	}
+
+	/* See if we scrubbing should be enabled */
+	enable_scrubbing = 1;
+	get_option(&enable_scrubbing, "hw_scrubber");
+
+	/* Enable cache scrubbing at the lowest possible rate */
+	if (enable_scrubbing) {
+		pci_write_config32(f3_dev, SCRUB_CONTROL,
+			(SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_NONE << 0));
+	} else {
+		pci_write_config32(f3_dev, SCRUB_CONTROL,
+			(SCRUB_NONE << 16) | (SCRUB_NONE << 8) | (SCRUB_NONE << 0));
+		printk_debug("Scrubbing Disabled\n");
+	}
+	
+
+	/* If ecc support is not enabled don't touch memory */
+	dcl = pci_read_config32(f2_dev, DRAM_CONFIG_LOW);
+	if (!(dcl & DCL_DimmEccEn)) {
+		return;
+	}
+
+	startk = (pci_read_config32(f1_dev, 0x40 + (node_id*8)) & 0xffff0000) >> 2;
+	endk   = ((pci_read_config32(f1_dev, 0x44 + (node_id*8)) & 0xffff0000) >> 2) + 0x4000;
+
+	/* Don't start too early */
+	begink = startk;
+	if (begink < CONFIG_LB_MEM_TOPK) {
+		begink = CONFIG_LB_MEM_TOPK;
+	}
+	printk_debug("Clearing memory %uK - %uK: ", startk, endk);
+
+	/* Save the normal state */
+	save_mtrr_state(&mtrr_state);
+
+	/* Switch to the init ecc state */
+	set_init_ecc_mtrrs();
+	disable_lapic();
+
+	/* Walk through 2M chunks and zero them */
+	for(basek = begink; basek < endk; basek = ((basek + ZERO_CHUNK_KB) & ~(ZERO_CHUNK_KB - 1))) {
+		unsigned long limitk;
+		unsigned long size;
+		void *addr;
+
+		/* Report every 64M */
+		if ((basek % (64*1024)) == 0) {
+			/* Restore the normal state */
+			map_2M_page(cpu_index, 0);
+			restore_mtrr_state(&mtrr_state);
+			enable_lapic();
+
+			/* Print a status message */
+			printk_debug("%c", (basek >= TOLM_KB)?'+':'-');
+
+			/* Return to the initialization state */
+			set_init_ecc_mtrrs();
+			disable_lapic();
+		}
+		limitk = (basek + ZERO_CHUNK_KB) & ~(ZERO_CHUNK_KB - 1);
+		if (limitk > endk) {
+			limitk = endk;
+		}
+		size = (limitk - basek) << 10;
+		addr = map_2M_page(cpu_index, basek >> 11);
+		addr = (void *)(((uint32_t)addr) | ((basek & 0x7ff) << 10));
+		if (addr == MAPPING_ERROR) {
+			continue;
+		}
+
+		/* clear memory 2M (limitk - basek) */
+		__asm__ volatile(
+			"1: \n\t"
+			"movl %0, (%1)\n\t"
+			"addl $4,%1\n\t"
+			"subl $4,%2\n\t"
+			"jnz 1b\n\t"
+			:
+			: "a" (0), "D" (addr),	"c" (size)
+			);
+	}
+	/* Restore the normal state */
+	map_2M_page(cpu_index, 0);
+	restore_mtrr_state(&mtrr_state);
+	enable_lapic();
+
+	/* Set the scrub base address registers */
+	pci_write_config32(f3_dev, SCRUB_ADDR_LOW,  startk << 10);
+	pci_write_config32(f3_dev, SCRUB_ADDR_HIGH, startk >> 22);
+
+	/* Enable the scrubber? */
+	if (enable_scrubbing) {
+		/* Enable scrubbing at the lowest possible rate */
+		pci_write_config32(f3_dev, SCRUB_CONTROL,
+			(SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_84ms << 0));
+	}
+
+	printk_debug(" done\n");
+}
+
 void k8_cpufixup(struct mem_range *mem)
 {
 	unsigned long mmio_basek, tomk;
@@ -83,7 +318,11 @@
 	if (mmio_basek > tomk) {
 		mmio_basek = tomk;
 	}
-
+	/* Round mmio_basek down to the nearst size that will fit in TOP_MEM */
+	mmio_basek = mmio_basek & ~TOP_MEM_MASK_KB;
+	/* Round tomk up to the next greater size that will fit in TOP_MEM */
+	tomk = (tomk + TOP_MEM_MASK_KB) & ~TOP_MEM_MASK_KB;
+		
 	/* Setup TOP_MEM */
 	msr.hi = mmio_basek >> 22;
 	msr.lo = mmio_basek << 10;
@@ -101,7 +340,7 @@
 	for(i = IORR_FIRST; i <= IORR_LAST; i++) {
 		wrmsr(i, msr);
 	}
-	
+
 	msr = rdmsr(SYSCFG_MSR);
 	msr.lo |= SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_TOM2En;
 	wrmsr(SYSCFG_MSR, msr);
@@ -118,33 +357,34 @@
 		msr = rdmsr(HWCR_MSR);
 		msr.lo |= (1 << 6);
 		wrmsr(HWCR_MSR, msr);
+
 		/* Erratum 69... */
-#if 1
 		msr = rdmsr_amd(BU_CFG_MSR);
 		msr.hi |= (1 << (45 - 32));
 		wrmsr_amd(BU_CFG_MSR, msr);
-#endif
+
 		/* Erratum 81... */
-#if 1
 		msr = rdmsr_amd(DC_CFG_MSR);
 		msr.lo |=  (1 << 10);
 		wrmsr_amd(DC_CFG_MSR, msr);
-#endif
 			
 	}
-	/* Erratum 89 ... */
-	msr = rdmsr(NB_CFG_MSR);
-	msr.lo |= 1 << 3;
+	/* I can't touch this msr on early buggy cpus */
+	if (!is_cpu_pre_b3()) {
 
-	if (!is_cpu_pre_c0()) {
-		/* Erratum 86 Disable data masking on C0 and 
-		 * later processor revs.
-		 * FIXME this is only needed if ECC is enabled.
-		 */
-		msr.hi |= 1 << (36 - 32);
-	}	
-	wrmsr(NB_CFG_MSR, msr);
-#if 1  /* The following erratum fixes reset the cpu ???? */
+		/* Erratum 89 ... */
+		msr = rdmsr(NB_CFG_MSR);
+		msr.lo |= 1 << 3;
+		
+		if (!is_cpu_pre_c0()) {
+			/* Erratum 86 Disable data masking on C0 and 
+			 * later processor revs.
+			 * FIXME this is only needed if ECC is enabled.
+			 */
+			msr.hi |= 1 << (36 - 32);
+		}	
+		wrmsr(NB_CFG_MSR, msr);
+	}
 	
 	/* Erratum 97 ... */
 	if (!is_cpu_pre_c0()) {
@@ -158,11 +398,14 @@
 	msr.lo |= 1 << 11;
 	wrmsr_amd(IC_CFG_MSR, msr);
 
-#endif
-
 	/* Erratum 91 prefetch miss is handled in the kernel */
 	
 	enable_cache();
+
+	/* Is this a bad location?  In particular can another node prefecth
+	 * data from this node before we have initialized it?
+	 */
+	init_ecc_memory();
 }
 
 static
diff --git a/src/cpu/k8/earlymtrr.c b/src/cpu/k8/earlymtrr.c
index 47ddd12..5fb63d2 100644
--- a/src/cpu/k8/earlymtrr.c
+++ b/src/cpu/k8/earlymtrr.c
@@ -6,7 +6,7 @@
 
 static void early_mtrr_init(void)
 {
-	static unsigned long mtrr_msrs[] = {
+	static const unsigned long mtrr_msrs[] = {
 		/* fixed mtrr */
 		0x250, 0x258, 0x259,
 		0x268, 0x269, 0x26A
@@ -25,46 +25,46 @@
 		0
 	};
 	msr_t msr;
-	unsigned long *msr_addr;
+	const unsigned long *msr_addr;
 
 	/* Inialize all of the relevant msrs to 0 */
 	msr.lo = 0;
 	msr.hi = 0;
-	for(msr_addr = &mtrr_msrs; *msr_addr; msr_addr++) {
+	for(msr_addr = mtrr_msrs; *msr_addr; msr_addr++) {
 		wrmsr(*msr_addr, msr);
 	}
 
-	/* Enable memory access for 0 - 8MB using top_mem */
+	/* Enable memory access for 0 - 1MB using top_mem */
 	msr.hi = 0;
-	msr.lo = 0x08000000;
+	msr.lo = ((CONFIG_LB_MEM_TOPK << 10) + TOP_MEM_MASK) & ~TOP_MEM_MASK;
 	wrmsr(TOP_MEM, msr);
 
-	/* Enable caching for 0 - 128MB using variable mtrr */
+	/* Enable caching for 0 - 1MB using variable mtrr */
 	msr = rdmsr(0x200);
 	msr.hi &= 0xfffffff0;
 	msr.hi |= 0x00000000;
 	msr.lo &= 0x00000f00;
-	msr.lo |= 0x00000006;
+	msr.lo |= 0x00000000 | MTRR_TYPE_WRBACK;
 	wrmsr(0x200, msr);
 
 	msr = rdmsr(0x201);
 	msr.hi &= 0xfffffff0;
 	msr.hi |= 0x0000000f;
 	msr.lo &= 0x000007ff;
-	msr.lo |= 0xf0000800;
+	msr.lo |= (~((CONFIG_LB_MEM_TOPK << 10) - 1)) | 0x800;
 	wrmsr(0x201, msr);
 
 #if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE)
-	/* enable write back caching so we can do execute in place
+	/* enable write through caching so we can do execute in place
 	 * on the flash rom.
 	 */
 	msr.hi = 0x00000000;
-	msr.lo = XIP_ROM_BASE | 0x005;
-	wrmsr(0x202);
+	msr.lo = XIP_ROM_BASE | MTRR_TYPE_WRTHROUGH;
+	wrmsr(0x202, msr);
 #error "FIXME verify the type of MTRR I have setup"
 	msr.hi = 0x0000000f;
 	msr.lo = ~(XIP_ROM_SIZE - 1) | 0x800;
-	wrmsr(0x203);
+	wrmsr(0x203, msr);
 #endif
 
 	/* Set the default memory type and enable fixed and variable MTRRs 
@@ -72,7 +72,7 @@
 	/* Enable Variable MTRRs */
 	msr.hi = 0x00000000;
 	msr.lo = 0x00000800;
-	wrmsr(0x2ff, msr);
+	wrmsr(MTRRdefType_MSR, msr);
 	
 	/* Enale the MTRRs in SYSCFG */
 	msr = rdmsr(SYSCFG_MSR);
diff --git a/src/cpu/k8/earlymtrr.inc b/src/cpu/k8/earlymtrr.inc
index d14afb1..acc917b 100644
--- a/src/cpu/k8/earlymtrr.inc
+++ b/src/cpu/k8/earlymtrr.inc
@@ -1,7 +1,11 @@
 #include <cpu/k8/mtrr.h>
 
+
+	/* Save off the BIST value */
+	movl	%eax, %ebp
+
 /* The fixed and variable MTRRs are powered-up with random values, clear them to
- * MTRR_TYPE_UNCACHABLE for safty reason 
+ * MTRR_TYPE_UNCACHEABLE for safty reason 
  */
 
 earlymtrr_start:
@@ -21,20 +25,20 @@
 	jmp	clear_fixed_var_mtrr
 clear_fixed_var_mtrr_out:
 
-/* enable memory access for 0 - 8MB using top_mem */
+/* enable memory access for 0 - 1MB using top_mem */
 	movl	$TOP_MEM, %ecx
 	xorl	%edx, %edx
-	movl	$0x0800000, %eax
+	movl	$(((CONFIG_LB_MEM_TOPK << 10) + TOP_MEM_MASK) & ~TOP_MEM_MASK) , %eax
 	wrmsr
 
 set_var_mtrr:
-	/* enable caching for 0 - 128MB using variable mtrr */
+	/* enable caching for 0 - 1MB using variable mtrr */
 	movl	$0x200, %ecx
 	rdmsr
 	andl	$0xfffffff0, %edx
 	orl	$0x00000000, %edx
 	andl	$0x00000f00, %eax
-	orl	$0x00000006, %eax
+	orl	$(0x00000000 | MTRR_TYPE_WRBACK), %eax
 	wrmsr
 
 	movl	$0x201, %ecx
@@ -42,7 +46,7 @@
 	andl	$0xfffffff0, %edx
 	orl	$0x0000000f, %edx
 	andl	$0x000007ff, %eax
-	orl	$0xf0000800, %eax
+	orl	$((~((CONFIG_LB_MEM_TOPK << 10) - 1)) | 0x800), %eax
 	wrmsr
 
 #if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE)
@@ -51,7 +55,7 @@
 	 */
 	movl	$0x202, %ecx
 	xorl	%edx, %edx
-	movl	$(XIP_ROM_BASE | 0x006), %eax
+	movl	$(XIP_ROM_BASE | MTRR_TYPE_WRBACK), %eax
 	wrmsr	
 
 	movl	$0x203, %ecx
@@ -62,7 +66,7 @@
 
 enable_mtrr:	
 	/* Set the default memory type and enable fixed and variable MTRRs */
-	movl	$0x2ff, %ecx
+	movl	$MTRRdefType_MSR, %ecx
 	xorl	%edx, %edx
 	/* Enable Variable MTRRs */
 	movl	$0x00000800, %eax
@@ -97,3 +101,5 @@
 	.long	0xC001001A, 0xC001001D
 	.long	0x000 /* NULL, end of table */
 earlymtrr_end:
+	/* Restore the BIST value */
+	movl	%ebp, %eax
\ No newline at end of file
diff --git a/src/cpu/k8/enable_mmx_sse.inc b/src/cpu/k8/enable_mmx_sse.inc
index 5551525..907e817 100644
--- a/src/cpu/k8/enable_mmx_sse.inc
+++ b/src/cpu/k8/enable_mmx_sse.inc
@@ -1,3 +1,6 @@
+	/* Save the BIST result */
+	movl	%eax, %ebp
+	
 	/*
 	 * Enabling mmx registers is a noop
 	 * Enable the use of the xmm registers
@@ -12,3 +15,6 @@
 	movl	%cr4, %eax
 	orl	$(1<<9), %eax
 	movl	%eax, %cr4
+
+	/* Restore the BIST result */
+	movl	%ebp, %eax
diff --git a/src/cpu/p6/Config.lb b/src/cpu/p6/Config.lb
index c9d4834..f6e9777 100644
--- a/src/cpu/p6/Config.lb
+++ b/src/cpu/p6/Config.lb
@@ -3,4 +3,5 @@
 dir /cpu/p5
 object cpufixup.o
 object mtrr.o
+object pgtbl.o
 #object l2_cache.o
diff --git a/src/cpu/p6/boot_cpu.c b/src/cpu/p6/boot_cpu.c
index 803eecd..77b060b 100644
--- a/src/cpu/p6/boot_cpu.c
+++ b/src/cpu/p6/boot_cpu.c
@@ -2,8 +2,6 @@
 
 int boot_cpu(void)
 {
-	volatile unsigned long *local_apic;
-	unsigned long apic_id;
 	int bsp;
 	msr_t msr;
 	msr = rdmsr(0x1b);
diff --git a/src/cpu/p6/earlymtrr.c b/src/cpu/p6/earlymtrr.c
index f352f3d..df74f90 100644
--- a/src/cpu/p6/earlymtrr.c
+++ b/src/cpu/p6/earlymtrr.c
@@ -51,7 +51,7 @@
 	/* Disable Variable MTRRs */
 	msr.hi = 0x00000000;
 	msr.lo = 0x00000000;
-	wrmsr(0x2ff, msr);
+	wrmsr(MTRRdefType_MSR, msr);
 
 	/* Invalidate the cache again */
 	asm volatile ("invd");
@@ -65,19 +65,19 @@
 		wrmsr(*msr_addr, msr);
 	}
 
-	/* Enable caching for 0 - 128MB using variable mtrr */
+	/* Enable caching for 0 - 1MB using variable mtrr */
 	msr = rdmsr(0x200);
 	msr.hi &= 0xfffffff0;
 	msr.hi |= 0x00000000;
 	msr.lo &= 0x00000f00;
-	msr.lo |= 0x00000006;
+	msr.lo |= 0x00000000 | MTRR_TYPE_WRBACK;
 	wrmsr(0x200, msr);
 
 	msr = rdmsr(0x201);
 	msr.hi &= 0xfffffff0;
 	msr.hi |= 0x0000000f;
 	msr.lo &= 0x000007ff;
-	msr.lo |= 0xf0000800;
+	msr.lo |= (~((CONFIG_LB_MEM_TOPK << 10) - 1)) | 0x800;
 	wrmsr(0x201, msr);
 
 #if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE)
@@ -98,7 +98,7 @@
 	/* Enable Variable MTRRs */
 	msr.hi = 0x00000000;
 	msr.lo = 0x00000800;
-	wrmsr(0x2ff, msr);
+	wrmsr(MTRRdefType_MSR, msr);
 
 	/* Enable the cache */
 	cr0 = read_cr0();
diff --git a/src/cpu/p6/mtrr.c b/src/cpu/p6/mtrr.c
index ac6fd1db..7e2eb06 100644
--- a/src/cpu/p6/mtrr.c
+++ b/src/cpu/p6/mtrr.c
@@ -104,7 +104,8 @@
 	if (sizek < 4*1024*1024) {
 		mask.hi = ADDRESS_MASK_HIGH;
 		mask.lo = ~((sizek << 10) -1);
-	} else {
+	}
+	else {
 		mask.hi = ADDRESS_MASK_HIGH & (~((sizek >> 22) -1));
 		mask.lo = 0;
 	}
@@ -131,6 +132,36 @@
 	enable_cache();
 }
 
+/* setting variable mtrr, comes from linux kernel source */
+void set_var_mtrr(unsigned int reg, unsigned long base, unsigned long size, unsigned char type)
+{
+	if (reg >= 8)
+		return;
+
+	// it is recommended that we disable and enable cache when we 
+	// do this. 
+	disable_cache();
+	if (size == 0) {
+		/* The invalid bit is kept in the mask, so we simply clear the
+		   relevant mask register to disable a range. */
+		msr_t zero;
+		zero.lo = zero.hi = 0;
+		wrmsr (MTRRphysMask_MSR(reg), zero);
+	} else {
+		/* Bit 32-35 of MTRRphysMask should be set to 1 */
+		msr_t basem, maskm;
+		basem.lo = base | type;
+		basem.hi = 0;
+		maskm.lo = ~(size - 1) | 0x800;
+		maskm.hi = 0x0F;
+		wrmsr (MTRRphysBase_MSR(reg), basem);
+		wrmsr (MTRRphysMask_MSR(reg), maskm);
+	}
+
+	// turn cache back on. 
+	enable_cache();
+}
+
 /* fms: find most sigificant bit set, stolen from Linux Kernel Source. */
 static inline unsigned int fms(unsigned int x)
 {
@@ -250,7 +281,7 @@
 		}
 		sizek = 1 << align;
 		printk_debug("Setting variable MTRR %d, base: %4dMB, range: %4dMB, type WB\n",
-			     reg, range_startk >>10, sizek >> 10);
+			reg, range_startk >>10, sizek >> 10);
 		intel_set_var_mtrr(reg++, range_startk, sizek, MTRR_TYPE_WRBACK);
 		range_startk += sizek;
 		range_sizek -= sizek;
@@ -274,7 +305,7 @@
 	/* Initialized the fixed_mtrrs to uncached */
 	printk_debug("Setting fixed MTRRs(%d-%d) type: UC\n", 
 		0, NUM_FIXED_RANGES);
-	set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHABLE);
+	set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHEABLE);
 
 	/* Now see which of the fixed mtrrs cover ram.
 	 */
diff --git a/src/cpu/p6/pgtbl.c b/src/cpu/p6/pgtbl.c
new file mode 100644
index 0000000..e996dd0e
--- /dev/null
+++ b/src/cpu/p6/pgtbl.c
@@ -0,0 +1,91 @@
+#include <console/console.h>
+#include <smp/start_stop.h>
+#include <cpu/p6/pgtbl.h>
+
+static void paging_off(void)
+{
+	__asm__ __volatile__ (
+		/* Disable paging */
+		"movl	%%cr0, %%eax\n\t"
+		"andl	$0x7FFFFFFF, %%eax\n\t"
+		"movl	%%eax, %%cr0\n\t"
+		/* Disable pae */
+		"movl	%%cr4, %%eax\n\t"
+		"andl	$0xFFFFFFDF, %%eax\n\t"
+		:
+		:
+		: "eax"
+		);
+}
+
+static void paging_on(void *pdp)
+{
+	__asm__ __volatile__(
+		/* Load the page table address */
+		"movl	%0, %%cr3\n\t"
+		/* Enable pae */
+		"movl	%%cr4, %%eax\n\t"
+		"orl	$0x00000020, %%eax\n\t"
+		"movl	%%eax, %%cr4\n\t"
+		/* Enable paging */
+		"movl	%%cr0, %%eax\n\t"
+		"orl	$0x80000000, %%eax\n\t"
+		"movl	%%eax, %%cr0\n\t"
+		:
+		: "r" (pdp)
+		: "eax"
+		);
+}
+
+void *map_2M_page(int cpu_index, unsigned long page) 
+{
+	struct pde {
+		uint32_t addr_lo;
+		uint32_t addr_hi;
+	} __attribute__ ((packed));
+	struct pg_table {
+		struct pde pd[2048];
+		struct pde pdp[512];
+	} __attribute__ ((packed));
+	static struct pg_table pgtbl[CONFIG_MAX_CPUS] __attribute__ ((aligned(4096)));
+	static unsigned long mapped_window[CONFIG_MAX_CPUS];
+	unsigned long window;
+	void *result;
+	int i;
+	if ((cpu_index < 0) || (cpu_index >= CONFIG_MAX_CPUS)) {
+		return MAPPING_ERROR;
+	}
+	window = page >> 10;
+	if (window != mapped_window[cpu_index]) {
+		paging_off();
+		if (window > 1) {
+			struct pde *pd, *pdp;
+			/* Point the page directory pointers at the page directories */
+			memset(&pgtbl[cpu_index].pdp, 0, sizeof(pgtbl[cpu_index].pdp));
+			pd = pgtbl[cpu_index].pd;
+			pdp = pgtbl[cpu_index].pdp;
+			pdp[0].addr_lo = ((uint32_t)&pd[512*0])|1;
+			pdp[1].addr_lo = ((uint32_t)&pd[512*1])|1;
+			pdp[2].addr_lo = ((uint32_t)&pd[512*2])|1;
+			pdp[3].addr_lo = ((uint32_t)&pd[512*3])|1;
+			/* The first half of the page table is identity mapped */
+			for(i = 0; i < 1024; i++) {
+				pd[i].addr_lo = ((i & 0x3ff) << 21)| 0xE3;
+				pd[i].addr_hi = 0;
+			}
+			/* The second half of the page table holds the mapped page */
+			for(i = 1024; i < 2048; i++) {
+				pd[i].addr_lo = ((window & 1) << 31) | ((i & 0x3ff) << 21) | 0xE3;
+				pd[i].addr_hi = (window >> 1);
+			}
+			paging_on(pdp);
+		}
+		mapped_window[cpu_index] = window;
+	}
+	if (window == 0) {
+		result = (void *)(page << 21);
+	} else {
+		result = (void *)(0x80000000 | ((page & 0x3ff) << 21));
+	}
+	return result;
+}
diff --git a/src/devices/Config.lb b/src/devices/Config.lb
index 6da04ee..50d0557 100644
--- a/src/devices/Config.lb
+++ b/src/devices/Config.lb
@@ -2,5 +2,6 @@
 object root_device.o
 object device_util.o
 object pci_device.o
+object pnp_device.o
 object hypertransport.o
 object chip.o
diff --git a/src/devices/chip.c b/src/devices/chip.c
index c9e1ac5..d8a59e3 100644
--- a/src/devices/chip.c
+++ b/src/devices/chip.c
@@ -80,6 +80,7 @@
 			link += 1;
 		}
 		if (dev) {
+			struct chip_resource *res, *res_limit;
 			printk_spew("path (%p) %s %s", dev, dev_path(dev), identical_paths?"identical":"");
 			printk_spew(" parent: (%p) %s\n",dev->bus->dev,  dev_path(dev->bus->dev));
 			dev->chip = chip;
@@ -90,6 +91,16 @@
 					child->bus = &dev->link[link];
 				}
 			}
+			res = &chip->path[i].resource[0];
+			res_limit = &chip->path[i].resource[MAX_RESOURCES];
+			for(; res < res_limit; res++) {
+				if (res->flags) {
+					struct resource *resource;
+					resource = get_resource(dev, res->index);
+					resource->flags = res->flags | IORESOURCE_FIXED | IORESOURCE_ASSIGNED;
+					resource->base = res->base;
+				}
+			}
 		}
 		if (dev && !chip->dev) {
 			chip->dev = dev;
diff --git a/src/devices/device.c b/src/devices/device.c
index 4f1cbb2..b54e770 100644
--- a/src/devices/device.c
+++ b/src/devices/device.c
@@ -23,9 +23,9 @@
 #include <string.h>
 
 /* Linked list of ALL devices */
-struct device *all_devices = 0;
+struct device *all_devices = &dev_root;
 /* pointer to the last device */
-static struct device **last_dev_p = &all_devices;
+static struct device **last_dev_p = &dev_root.next;
 
 #define DEVICE_MEM_HIGH  0xFEC00000UL /* Reserve 20M for the system */
 #define DEVICE_IO_START 0x1000
@@ -323,7 +323,8 @@
 			/* base must be aligned to size */
 			base = round(base, 1UL << align);
 			resource->base = base;
-			resource->flags |= IORESOURCE_SET;
+			resource->flags |= IORESOURCE_ASSIGNED;
+			resource->flags &= ~IORESOURCE_STORED;
 			base += size;
 			
 			printk_spew(
@@ -459,19 +460,24 @@
 	 * safe.
 	 */
 	root->resource[0].base = DEVICE_IO_START;
-	root->resource[0].flags |= IORESOURCE_SET;
+	root->resource[0].flags |= IORESOURCE_ASSIGNED;
+	root->resource[0].flags &= ~IORESOURCE_STORED;
 	/* Now reallocate the pci resources memory with the
 	 * highest addresses I can manage.
 	 */
 	root->resource[1].base = 
 		round_down(DEVICE_MEM_HIGH - root->resource[1].size,
 			1UL << root->resource[1].align);
-	root->resource[1].flags |= IORESOURCE_SET;
+	root->resource[1].flags |= IORESOURCE_ASSIGNED;
+	root->resource[1].flags &= ~IORESOURCE_STORED;
+
+	/* Allocate the VGA I/O resource..
+	 */
+	allocate_vga_resource(); 
+
 	// now just set things into registers ... we hope ...
 	root->ops->set_resources(root);
 
-	allocate_vga_resource();
-
 	printk_info("done.\n");
 }
 
diff --git a/src/devices/device_util.c b/src/devices/device_util.c
index c806726..0135014 100644
--- a/src/devices/device_util.c
+++ b/src/devices/device_util.c
@@ -34,7 +34,8 @@
 
 	result = 0;
 	for (dev = all_devices; dev; dev = dev->next) {
-		if ((dev->bus->secondary == bus) && 
+		if ((dev->path.type == DEVICE_PATH_PCI) &&
+			(dev->bus->secondary == bus) && 
 			(dev->path.u.pci.devfn == devfn)) {
 			result = dev;
 			break;
@@ -57,8 +58,9 @@
 		from = all_devices;
 	else
 		from = from->next;
-	while (from && (from->vendor != vendor || from->device != device))
+	while (from && (from->vendor != vendor || from->device != device)) {
 		from = from->next;
+	}
 	return from;
 }
 
@@ -142,3 +144,70 @@
 	}
 	return equal;
 }
+
+/**
+ * See if we have unused but allocated resource structures.
+ * If so remove the allocation.
+ * @param dev The device to find the resource on
+ */
+void compact_resources(device_t dev)
+{
+	struct resource *resource;
+	int i;
+	/* Move all of the free resources to the end */
+	for(i = 0; i < dev->resources;) {
+		resource = &dev->resource[i];
+		if (!resource->flags) {
+			memmove(resource, resource + 1, dev->resources - i);
+			dev->resources -= 1;
+			memset(&dev->resource[dev->resources], 0, sizeof(*resource));
+		} else {
+			i++;
+		}
+	}
+}
+
+/**
+ * See if a resource structure already exists for a given index and if
+ * not allocate one.
+ * @param dev The device to find the resource on
+ * @param index  The index of the resource on the device.
+ */
+struct resource *get_resource(device_t dev, unsigned index)
+{
+	struct resource *resource;
+	int i;
+
+	/* First move all of the free resources to the end */
+	compact_resources(dev);
+
+	/* See if there is a resource with the appropriate index */
+	resource = 0;
+	for(i = 0; i < dev->resources; i++) {
+		if (dev->resource[i].index == index) {
+			resource = &dev->resource[i];
+			break;
+		}
+	}
+	if (!resource) {
+		if (dev->resources == MAX_RESOURCES) {
+			die("MAX_RESOURCES exceeded.");
+		}
+		resource = &dev->resource[dev->resources];
+		memset(resource, 0, sizeof(*resource));
+		dev->resources++;
+	}
+	/* Initialize the resource values */
+	if (!(resource->flags & IORESOURCE_FIXED)) {
+		resource->flags = 0;
+		resource->base = 0;
+	}
+	resource->size  = 0;
+	resource->limit = 0;
+	resource->index = index;
+	resource->align = 0;
+	resource->gran  = 0;
+
+	return resource;
+}
+
diff --git a/src/devices/hypertransport.c b/src/devices/hypertransport.c
index b65f518..e50ebf6 100644
--- a/src/devices/hypertransport.c
+++ b/src/devices/hypertransport.c
@@ -3,6 +3,7 @@
 #include <device/device.h>
 #include <device/path.h>
 #include <device/pci.h>
+#include <device/pci_ids.h>
 #include <device/hypertransport.h>
 #include <device/chip.h>
 #include <part/hard_reset.h>
@@ -25,6 +26,30 @@
 	return first;
 }
 
+static unsigned ht_read_freq_cap(device_t dev, unsigned pos)
+{
+	/* Handle bugs in valid hypertransport frequency reporting */
+	unsigned freq_cap;
+
+	freq_cap = pci_read_config16(dev, pos);
+	freq_cap &= ~(1 << HT_FREQ_VENDOR); /* Ignore Vendor HT frequencies */
+
+	/* AMD 8131 Errata 48 */
+	if ((dev->vendor == PCI_VENDOR_ID_AMD) &&
+		(dev->device == PCI_DEVICE_ID_AMD_8131_PCIX)) {
+		freq_cap &= ~(1 << HT_FREQ_800Mhz);
+	}
+	/* AMD 8151 Errata 23 */
+	if ((dev->vendor == PCI_VENDOR_ID_AMD) &&
+		(dev->device == PCI_DEVICE_ID_AMD_8151_SYSCTRL)) {
+		freq_cap &= ~(1 << HT_FREQ_800Mhz);
+	}
+	/* AMD K8 Unsupported 1Ghz? */
+	if ((dev->vendor == PCI_VENDOR_ID_AMD) && (dev->device == 0x1100)) {
+		freq_cap &= ~(1 << HT_FREQ_1000Mhz);
+	}
+	return freq_cap;
+}
 
 struct prev_link {
 	struct device *dev;
@@ -48,18 +73,13 @@
 	reset_needed = 0;
 
 	/* Read the capabilities */
-	present_freq_cap   = pci_read_config16(dev, pos + PCI_HT_CAP_SLAVE_FREQ_CAP0);
-	upstream_freq_cap  = pci_read_config16(prev->dev, prev->pos + prev->freq_cap_off);
+	present_freq_cap   = ht_read_freq_cap(dev, pos + PCI_HT_CAP_SLAVE_FREQ_CAP0);
+	upstream_freq_cap  = ht_read_freq_cap(prev->dev, prev->pos + prev->freq_cap_off);
 	present_width_cap  = pci_read_config8(dev, pos + PCI_HT_CAP_SLAVE_WIDTH0);
 	upstream_width_cap = pci_read_config8(prev->dev, prev->pos + prev->config_off);
 	
 	/* Calculate the highest useable frequency */
-#if 0
 	freq = log2(present_freq_cap & upstream_freq_cap);
-#else
-	/* Errata for 8131 - freq 5 has hardware problems don't support it */
-	freq = log2(present_freq_cap & upstream_freq_cap & 0x1f);
-#endif
 
 	/* Calculate the highest width */
 	ln_upstream_width_in = link_width_to_pow2[upstream_width_cap & 7];
@@ -144,9 +164,7 @@
 				break;
 			}
 		}
-		if(pos) {
-			pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT);
-		}
+		pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT);
 	}
 	return pos;
 }
@@ -244,9 +262,12 @@
 		else {
 			/* Add this device to the pci bus chain */
 			*chain_last = dev;
-			/* Run the magice enable/disable sequence for the device */
+			/* Run the magice enable sequence for the device */
 			if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) {
+				int enable  = dev->enable;
+				dev->enable = 1;
 				dev->chip->control->enable_dev(dev);
+				dev->enable = enable;
 			}
 			/* Now read the vendor and device id */
 			id = pci_read_config32(dev, PCI_VENDOR_ID);
@@ -320,9 +341,11 @@
 #if HAVE_HARD_RESET == 1
 	if(reset_needed) {
 		printk_info("HyperT reset needed\n");
-// By LYH		hard_reset();
-	} else 
-	printk_debug("HyperT reset not needed\n");
+		hard_reset();
+	}
+	else {
+		printk_debug("HyperT reset not needed\n");
+	}
 #endif
 	if (next_unitid > 0x1f) {
 		next_unitid = 0x1f;
diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c
index 734b982..c3f1f6a 100644
--- a/src/devices/pci_device.c
+++ b/src/devices/pci_device.c
@@ -27,19 +27,14 @@
  * @param resource  Pointer to the resource structure
  * @param index     Address of the pci configuration register
  */
-static void pci_get_resource(struct device *dev, struct resource *resource, unsigned long index)
+static struct resource *pci_get_resource(struct device *dev, unsigned long index)
 {
+	struct resource *resource;
 	uint32_t addr, size, base;
 	unsigned long type;
 
 	/* Initialize the resources to nothing */
-	resource->base = 0;
-	resource->size = 0;
-	resource->align = 0;
-	resource->gran = 0;
-	resource->limit = 0;
-	resource->flags = 0;
-	resource->index = index;
+	resource = get_resource(dev, index);
 
 	addr = pci_read_config32(dev, index);
 
@@ -87,7 +82,7 @@
 		resource->size = (~((size | 0xffff0000) & PCI_BASE_ADDRESS_IO_MASK)) +1;
 		resource->align = log2(resource->size);
 		resource->gran = resource->align;
-		resource->flags = IORESOURCE_IO;
+		resource->flags |= IORESOURCE_IO;
 		resource->limit = 0xffff;
 	} 
 	else {
@@ -96,7 +91,7 @@
 		resource->size = (~(size &PCI_BASE_ADDRESS_MEM_MASK)) +1;
 		resource->align = log2(resource->size);
 		resource->gran = resource->align;
-		resource->flags = IORESOURCE_MEM;
+		resource->flags |= IORESOURCE_MEM;
 		if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
 			resource->flags |= IORESOURCE_PREFETCH;
 		}
@@ -145,7 +140,7 @@
 		}
 	}
 	/* dev->size holds the flags... */
-	return;
+	return resource;
 }
 
 /** Read the base address registers for a given device. 
@@ -154,75 +149,63 @@
  */
 static void pci_read_bases(struct device *dev, unsigned int howmany)
 {
-	unsigned int reg;
 	unsigned long index;
 
-	reg = dev->resources;
-	for(index = PCI_BASE_ADDRESS_0; 
-	    (reg < MAX_RESOURCES) && (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) {
+	for(index = PCI_BASE_ADDRESS_0; (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) {
 		struct resource *resource;
-		resource = &dev->resource[reg];
-		pci_get_resource(dev, resource, index);
-		reg += (resource->flags & (IORESOURCE_IO | IORESOURCE_MEM))? 1:0;
+		resource = pci_get_resource(dev, index);
 		index += (resource->flags & IORESOURCE_PCI64)?8:4;
 	}
-	dev->resources = reg;
+	compact_resources(dev);
 }
 
 
 static void pci_bridge_read_bases(struct device *dev)
 {
-	unsigned int reg = dev->resources;
+	struct resource *resource;
 
 	/* FIXME handle bridges without some of the optional resources */
 
 	/* Initialize the io space constraints on the current bus */
-	dev->resource[reg].base  = 0;
-	dev->resource[reg].size  = 0;
-	dev->resource[reg].align = log2(PCI_IO_BRIDGE_ALIGN);
-	dev->resource[reg].gran  = log2(PCI_IO_BRIDGE_ALIGN);
-	dev->resource[reg].limit = 0xffffUL;
-	dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_PCI_BRIDGE;
-	dev->resource[reg].index = PCI_IO_BASE;
-	compute_allocate_resource(&dev->link[0], &dev->resource[reg],
+	resource = get_resource(dev, PCI_IO_BASE);
+	resource->size  = 0;
+	resource->align = log2(PCI_IO_BRIDGE_ALIGN);
+	resource->gran  = log2(PCI_IO_BRIDGE_ALIGN);
+	resource->limit = 0xffffUL;
+	resource->flags |= IORESOURCE_IO | IORESOURCE_PCI_BRIDGE;
+	compute_allocate_resource(&dev->link[0], resource,
 		IORESOURCE_IO, IORESOURCE_IO);
-	reg++;
 
 	/* Initiliaze the prefetchable memory constraints on the current bus */
-	dev->resource[reg].base = 0;
-	dev->resource[reg].size = 0;
-	dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN);
-	dev->resource[reg].gran  = log2(PCI_MEM_BRIDGE_ALIGN);
-	dev->resource[reg].limit = 0xffffffffUL;
-	dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_PCI_BRIDGE;
-	dev->resource[reg].index = PCI_PREF_MEMORY_BASE;
-	compute_allocate_resource(&dev->link[0], &dev->resource[reg],
+	resource = get_resource(dev, PCI_PREF_MEMORY_BASE);
+	resource->size = 0;
+	resource->align = log2(PCI_MEM_BRIDGE_ALIGN);
+	resource->gran  = log2(PCI_MEM_BRIDGE_ALIGN);
+	resource->limit = 0xffffffffUL;
+	resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_PCI_BRIDGE;
+	resource->index = PCI_PREF_MEMORY_BASE;
+	compute_allocate_resource(&dev->link[0], resource,
 		IORESOURCE_MEM | IORESOURCE_PREFETCH, 
 		IORESOURCE_MEM | IORESOURCE_PREFETCH);
-	reg++;
 
 	/* Initialize the memory resources on the current bus */
-	dev->resource[reg].base = 0;
-	dev->resource[reg].size = 0;
-	dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN);
-	dev->resource[reg].gran  = log2(PCI_MEM_BRIDGE_ALIGN);
-	dev->resource[reg].limit = 0xffffffffUL;
-	dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PCI_BRIDGE;
-	dev->resource[reg].index = PCI_MEMORY_BASE;
-	compute_allocate_resource(&dev->link[0], &dev->resource[reg],
-		IORESOURCE_MEM | IORESOURCE_PREFETCH, 
+	resource = get_resource(dev, PCI_MEMORY_BASE);
+	resource->size = 0;
+	resource->align = log2(PCI_MEM_BRIDGE_ALIGN);
+	resource->gran  = log2(PCI_MEM_BRIDGE_ALIGN);
+	resource->limit = 0xffffffffUL;
+	resource->flags = IORESOURCE_MEM | IORESOURCE_PCI_BRIDGE;
+	compute_allocate_resource(&dev->link[0], resource,
+		IORESOURCE_MEM | IORESOURCE_PREFETCH,
 		IORESOURCE_MEM);
-	reg++;
 
-	dev->resources = reg;
+	compact_resources(dev);
 }
 
 
 void pci_dev_read_resources(struct device *dev)
 {
 	uint32_t addr;
-	dev->resources = 0;
-	memset(&dev->resource[0], 0, sizeof(dev->resource));
 	pci_read_bases(dev, 6);
 	addr = pci_read_config32(dev, PCI_ROM_ADDRESS);
 	dev->rom_address = (addr == 0xffffffff)? 0 : addr;
@@ -231,8 +214,6 @@
 void pci_bus_read_resources(struct device *dev)
 {
 	uint32_t addr;
-	dev->resources = 0;
-	memset(&dev->resource, 0, sizeof(dev->resource));
 	pci_bridge_read_bases(dev);
 	pci_read_bases(dev, 2);
 	
@@ -246,10 +227,10 @@
 {
 	unsigned long base, limit;
 	unsigned char buf[10];
-	unsigned long align;
+	unsigned long gran;
 
 	/* Make certain the resource has actually been set */
-	if (!(resource->flags & IORESOURCE_SET)) {
+	if (!(resource->flags & IORESOURCE_ASSIGNED)) {
 #if 1
 		printk_err("ERROR: %s %02x not allocated\n",
 			dev_path(dev), resource->index);
@@ -257,6 +238,11 @@
 		return;
 	}
 
+	/* If I have already stored this resource don't worry about it */
+	if (resource->flags & IORESOURCE_STORED) {
+		return;
+	}
+
 	/* Only handle PCI memory and IO resources for now */
 	if (!(resource->flags & (IORESOURCE_MEM |IORESOURCE_IO)))
 		return;
@@ -272,12 +258,20 @@
 	}
 	/* Get the base address */
 	base = resource->base;
-	/* Get the resource alignment */
-	align = 1UL << resource->align;
+	/* Get the resource granularity */
+	gran = 1UL << resource->gran;
+
+	/* For a non bridge resource granularity and alignment are the same.
+	 * For a bridge resource align is the largest needed alignment below
+	 * the bridge.  While the granularity is simply how many low bits of the
+	 * address cannot be set.
+	 */
 	
 	/* Get the limit (rounded up) */
-	limit = base + ((resource->size + align - 1UL) & ~(align - 1UL)) -1UL;
+	limit = base + ((resource->size + gran - 1UL) & ~(gran - 1UL)) -1UL;
 	
+	/* Now store the resource */
+	resource->flags |= IORESOURCE_STORED;
 	if (!(resource->flags & IORESOURCE_PCI_BRIDGE)) {
 		/*
 		 * some chipsets allow us to set/clear the IO bit. 
@@ -326,6 +320,8 @@
 		pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32, 0);
 	}
 	else {
+		/* Don't let me think I stored the resource */
+		resource->flags &= ~IORESOURCE_STORED;
 		printk_err("ERROR: invalid resource->index %x\n",
 			resource->index);
 	}
@@ -386,6 +382,7 @@
 	uint16_t command;
 	command = pci_read_config16(dev, PCI_COMMAND);
 	command |= dev->command;
+	command |= (PCI_COMMAND_PARITY + PCI_COMMAND_SERR); /* error check */
 	printk_debug("%s cmd <- %02x\n", dev_path(dev), command);
 	pci_write_config16(dev, PCI_COMMAND, command);
 
@@ -397,6 +394,7 @@
 	uint16_t ctrl;
 	ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL);
 	ctrl |= dev->link[0].bridge_ctrl;
+	ctrl |= (PCI_BRIDGE_CTL_PARITY + PCI_BRIDGE_CTL_SERR); /* error check */
 	printk_debug("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl);
 	pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl);
 
@@ -560,9 +558,12 @@
 			dev = alloc_dev(bus, &dummy.path);
 		}
 		else {
-			/* Run the magic enable/disable sequence for the device */
+			/* Run the magic enable sequence for the device */
 			if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) {
+				int enable  = dev->enable;
+				dev->enable = 1;
 				dev->chip->control->enable_dev(dev);
+				dev->enable = enable;
 			}
 			/* Now read the vendor and device id */
 			id = pci_read_config32(dev, PCI_VENDOR_ID);
@@ -584,7 +585,7 @@
 		 */
 		set_pci_ops(dev);
 		/* Error if we don't have some pci operations for it */
-		if (dev->enable && !dev->ops) {
+		if (!dev->ops) {
 			printk_err("%s No device operations\n",
 				dev_path(dev));
 			continue;
@@ -594,6 +595,9 @@
 		if (dev->ops && dev->ops->enable) {
 			dev->ops->enable(dev);
 		}
+		else if (dev->chip && dev->chip->control && dev->chip->control->enable_dev) {
+			dev->chip->control->enable_dev(dev);
+		}
 
 		printk_debug("%s [%04x/%04x] %s\n", 
 			dev_path(dev),
diff --git a/src/devices/pnp_device.c b/src/devices/pnp_device.c
new file mode 100644
index 0000000..0bccd7d
--- /dev/null
+++ b/src/devices/pnp_device.c
@@ -0,0 +1,217 @@
+/* Copyright 2004 Linux Networx  */
+/* This code is distrubted wihtout warrant under the GPL v2 (see COPYING) */
+
+#include <console/console.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <bitops.h>
+#include <string.h>
+#include <arch/io.h>
+#include <device/device.h>
+#include <device/pnp.h>
+
+
+/* PNP fundamental operations */
+
+void pnp_write_config(device_t dev, uint8_t reg, uint8_t value)
+{
+	outb(reg, dev->path.u.pnp.port);
+	outb(value, dev->path.u.pnp.port + 1);
+}
+
+uint8_t pnp_read_config(device_t dev, uint8_t reg)
+{
+	outb(reg, dev->path.u.pnp.port);
+	return inb(dev->path.u.pnp.port + 1);
+}
+
+void pnp_set_logical_device(device_t dev)
+{
+	pnp_write_config(dev, 0x07, dev->path.u.pnp.device);
+}
+
+void pnp_set_enable(device_t dev, int enable)
+{
+	pnp_write_config(dev, 0x30, enable?0x1:0x0);
+}
+
+int pnp_read_enable(device_t dev)
+{
+	return !!pnp_read_config(dev, 0x30);
+}
+
+void pnp_set_iobase(device_t dev, unsigned index, unsigned iobase)
+{
+	/* Index == 0x60 or 0x62 */
+	pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff);
+	pnp_write_config(dev, index + 1, iobase & 0xff);
+}
+
+void pnp_set_irq(device_t dev, unsigned index, unsigned irq)
+{
+	/* Index == 0x70 or 0x72 */
+	pnp_write_config(dev, index, irq);
+}
+
+
+void pnp_set_drq(device_t dev, unsigned drq, unsigned index)
+{
+	/* Index == 0x74 */
+	pnp_write_config(dev, index, drq & 0xff);
+}
+
+/* PNP device operations */
+
+void pnp_read_resources(device_t dev)
+{
+	return;
+}
+
+static void pnp_set_resource(device_t dev, struct resource *resource)
+{
+	if (!(resource->flags & IORESOURCE_ASSIGNED)) {
+#if 1
+		printk_err("ERROR: %s %02x not allocated\n",
+			dev_path(dev), resource->index);
+#endif
+		return;
+	}
+	/* Now store the resource */
+	resource->flags |= IORESOURCE_STORED;
+	if (resource->flags & IORESOURCE_IO) {
+		pnp_set_iobase(dev, resource->index, resource->base);
+	}
+	else if (resource->flags & IORESOURCE_DRQ) {
+		pnp_set_drq(dev, resource->index, resource->base);
+	}
+	else if (resource->flags  & IORESOURCE_IRQ) {
+		pnp_set_irq(dev, resource->index, resource->base);
+	}
+	else {
+		/* Don't let me think I stored the resource */
+		resource->flags &= IORESOURCE_STORED;
+		printk_err("ERROR: %s %02x unknown resource type\n",
+			dev_path(dev), resource->index);
+		return;
+	}
+
+	printk_debug(
+		"%s %02x <- [0x%08lx - 0x%08lx] %s\n",
+		dev_path(dev),
+		resource->index,
+		resource->base,  resource->base + resource->size - 1,
+		(resource->flags & IORESOURCE_IO)? "io":
+		(resource->flags & IORESOURCE_DRQ)? "drq":
+		(resource->flags & IORESOURCE_IRQ)? "irq":
+		(resource->flags & IORESOURCE_MEM)? "mem":
+		"???");
+}
+
+void pnp_set_resources(device_t dev)
+{
+	int i;
+
+	/* Select the device */
+	pnp_set_logical_device(dev);
+
+	/* Paranoia says I should disable the device here... */
+	for(i = 0; i < dev->resources; i++) {
+		pnp_set_resource(dev, &dev->resource[i]);
+	}
+}
+
+void pnp_enable_resources(device_t dev)
+{
+	pnp_set_logical_device(dev);
+	pnp_set_enable(dev, 1);
+
+}
+
+void pnp_enable(device_t dev)
+{
+	pnp_set_logical_device(dev);
+	if (!dev->enable) {
+		pnp_set_enable(dev, 0);
+	}
+}
+
+struct device_operations pnp_ops = {
+	.read_resources   = pnp_read_resources,
+	.set_resources    = pnp_set_resources,
+	.enable_resources = pnp_enable_resources,
+	.enable           = pnp_enable,
+};
+
+/* PNP chip opertations */
+
+static void pnp_get_ioresource(device_t dev, unsigned index, struct io_info *info)
+{
+	struct resource *resource;
+	uint32_t size;
+	resource = get_resource(dev, index);
+	
+	/* Initilize the resource */
+	resource->limit = 0xffff;
+	resource->flags |= IORESOURCE_IO;
+	
+	/* Set the resource size and alignment */
+	size = (0xffff & info->mask);
+	resource->size  = (~(size | 0xfffff800) + 1);
+	resource->align = log2(resource->size);
+	resource->gran  = resource->align;
+}
+
+static void get_resources(device_t dev, struct pnp_info *info)
+{
+	struct resource *resource;
+
+	pnp_set_logical_device(dev);
+
+	if (info->flags & PNP_IO0) {
+		pnp_get_ioresource(dev, PNP_IDX_IO0, &info->io0);
+	}
+	if (info->flags & PNP_IO1) {
+		pnp_get_ioresource(dev, PNP_IDX_IO1, &info->io1);
+	}
+	if (info->flags & PNP_IRQ0) {
+		resource = get_resource(dev, PNP_IDX_IRQ0);
+		resource->size = 1;
+		resource->flags |= IORESOURCE_IRQ;
+	}
+	if (info->flags & PNP_IRQ1) {
+		resource = get_resource(dev, PNP_IDX_IRQ1);
+		resource->size = 1;
+		resource->flags |= IORESOURCE_IRQ;
+	}
+	if (info->flags & PNP_DRQ0) {
+		resource = get_resource(dev, PNP_IDX_DRQ0);
+		resource->size = 1;
+		resource->flags |= IORESOURCE_DRQ;
+	}
+	if (info->flags & PNP_DRQ1) {
+		resource = get_resource(dev, PNP_IDX_DRQ1);
+		resource->size = 1;
+		resource->flags |= IORESOURCE_DRQ;
+	}
+	
+} 
+
+void pnp_enumerate(struct chip *chip, unsigned functions, 
+	struct device_operations *ops, struct pnp_info *info)
+{
+	struct device_path path;
+	device_t dev;
+	int i;
+
+	chip_enumerate(chip);
+	path.type       = DEVICE_PATH_PNP;
+	path.u.pnp.port = chip->dev->path.u.pnp.port;
+	
+	/* Setup the ops and resources on the newly allocated devices */
+	for(i = 0; i < functions; i++) {
+		path.u.pnp.device = info[i].function;
+		dev = alloc_find_dev(chip->bus, &path);
+		dev->ops = ops;
+		get_resources(dev, &info[i]);
+	}
+}
diff --git a/src/include/cpu/k8/mtrr.h b/src/include/cpu/k8/mtrr.h
index 5a965ee..890820b 100644
--- a/src/include/cpu/k8/mtrr.h
+++ b/src/include/cpu/k8/mtrr.h
@@ -35,4 +35,7 @@
 #define DC_CFG_MSR			0xC0011022
 #define BU_CFG_MSR			0xC0011023
 
+#define TOP_MEM_MASK			0x007fffff
+#define TOP_MEM_MASK_KB			(TOP_MEM_MASK >> 10)
+
 #endif /* CPU_K8_MTRR_H */
diff --git a/src/include/cpu/p6/mtrr.h b/src/include/cpu/p6/mtrr.h
index 16af10b..92bf62e 100644
--- a/src/include/cpu/p6/mtrr.h
+++ b/src/include/cpu/p6/mtrr.h
@@ -2,7 +2,7 @@
 #define __LINUXBIOS_CPU_P6_MTRR_H
 
 /*  These are the region types  */
-#define MTRR_TYPE_UNCACHABLE 0
+#define MTRR_TYPE_UNCACHEABLE 0
 #define MTRR_TYPE_WRCOMB     1
 /*#define MTRR_TYPE_         2*/
 /*#define MTRR_TYPE_         3*/
diff --git a/src/include/cpu/p6/pgtbl.h b/src/include/cpu/p6/pgtbl.h
new file mode 100644
index 0000000..68e327c
--- /dev/null
+++ b/src/include/cpu/p6/pgtbl.h
@@ -0,0 +1,7 @@
+#ifndef CPU_P6_PGTBL_H
+#define CPU_P6_PGTBL_H 
+
+#define MAPPING_ERROR ((void *)0xffffffffUL)
+void *map_2M_page(int cpu_index, unsigned long page);
+
+#endif /* CPU_P6_PGTBL_H  */
diff --git a/src/include/device/chip.h b/src/include/device/chip.h
index dc078a9..7dface8 100644
--- a/src/include/device/chip.h
+++ b/src/include/device/chip.h
@@ -1,6 +1,8 @@
 #ifndef DEVICE_CHIP_H
+#define DEVICE_CHIP_H
 
 #include <device/path.h>
+#include <device/device.h>
 
 /* chips are arbitrary chips (superio, southbridge, etc.)
  * They have private structures that define chip resources and default 
@@ -16,21 +18,6 @@
 #define CONFIGURE(pass)
 #endif
 
-struct com_ports {
-  unsigned int enable,baud, base, irq;
-};
-
-/* lpt port description. 
- * Note that for many chips you only really need to define the 
- * enable. 
- */
-struct lpt_ports {
-	unsigned int enable, // 1 if this port is enabled
-		     mode,   // pp mode
-		     base,   // IO base of the parallel port 
-                     irq;    // irq
-};
-
 enum chip_pass {
 	CONF_PASS_PRE_CONSOLE,
 	CONF_PASS_PRE_PCI,
@@ -60,11 +47,17 @@
 	void (*enable_dev)(struct device *dev);
 };
 
+struct chip_resource {
+	unsigned long flags;
+	unsigned long index;
+	unsigned long base;
+};
 
 struct chip_device_path {
 	struct device_path path;
 	unsigned channel;
 	int enable;
+	struct chip_resource resource[MAX_RESOURCES];
 };
 
 struct device;
diff --git a/src/include/device/device.h b/src/include/device/device.h
index 1b2b016..20d9c22 100644
--- a/src/include/device/device.h
+++ b/src/include/device/device.h
@@ -28,7 +28,7 @@
 	unsigned char   cap;		/* PCi capability offset */
 };
 
-#define MAX_RESOURCES 6
+#define MAX_RESOURCES 8
 #define MAX_LINKS     3
 /*
  * There is one device structure for each slot-number/function-number
@@ -49,18 +49,6 @@
 	unsigned int    enable : 1;	/* set if we should enable the device */
 
 	uint8_t command;
-	/*
-	 * In theory, the irq level can be read from configuration
-	 * space and all would be fine.  However, old PCI chips don't
-	 * support these registers and return 0 instead.  For example,
-	 * the Vision864-P rev 0 chip can uses INTA, but returns 0 in
-	 * the interrupt line and pin registers.  pci_init()
-	 * initializes this field with the value at PCI_INTERRUPT_LINE
-	 * and it is the job of pcibios_fixup() to change it if
-	 * necessary.  The field must not be 0 unless the device
-	 * cannot generate interrupts at all.
-	 */
-	unsigned int	irq;		/* irq generated by this device */
 
 	/* Base registers for this device, can be adjusted by
 	 * pcibios_fixup() as necessary.
@@ -94,6 +82,8 @@
 extern void enable_resources(struct device *dev);
 extern void enumerate_static_device(void);
 extern const char *dev_path(device_t dev);
+extern void compact_resources(device_t dev);
+extern struct resource *get_resource(device_t dev, unsigned index);
 
 /* Helper functions */
 device_t alloc_find_dev(struct bus *parent, struct device_path *path);
diff --git a/src/include/device/hypertransport.h b/src/include/device/hypertransport.h
index e342aeb..410495c 100644
--- a/src/include/device/hypertransport.h
+++ b/src/include/device/hypertransport.h
@@ -1,6 +1,8 @@
 #ifndef DEVICE_HYPERTRANSPORT_H
 #define DEVICE_HYPERTRANSPORT_H
 
+#include <device/hypertransport_def.h>
+
 unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max);
 
 #define HT_IO_HOST_ALIGN 4096
diff --git a/src/include/device/hypertransport_def.h b/src/include/device/hypertransport_def.h
new file mode 100644
index 0000000..0b44109
--- /dev/null
+++ b/src/include/device/hypertransport_def.h
@@ -0,0 +1,16 @@
+#ifndef DEVICE_HYPERTRANSPORT_DEF_H
+#define DEVICE_HYPERTRANSPORT_DEF_H
+
+#define HT_FREQ_200Mhz   0
+#define HT_FREQ_300Mhz   1
+#define HT_FREQ_400Mhz   2
+#define HT_FREQ_500Mhz   3
+#define HT_FREQ_600Mhz   4
+#define HT_FREQ_800Mhz   5
+#define HT_FREQ_1000Mhz  6
+#define HT_FREQ_1200Mhz  7
+#define HT_FREQ_1400Mhz  8
+#define HT_FREQ_1600Mhz  9
+#define HT_FREQ_VENDOR  15  /* AMD defines this to be 100Mhz */
+
+#endif /* DEVICE_HYPERTRANSPORT_DEF_H */
diff --git a/src/include/device/pci_def.h b/src/include/device/pci_def.h
index ad8f1e6..46229a1 100644
--- a/src/include/device/pci_def.h
+++ b/src/include/device/pci_def.h
@@ -179,7 +179,9 @@
 #define  PCI_CAP_ID_SLOTID	0x04	/* Slot Identification */
 #define  PCI_CAP_ID_MSI		0x05	/* Message Signalled Interrupts */
 #define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
-#define  PCI_CAP_ID_HT          0x08
+#define  PCI_CAP_ID_PCIX	0x07	/* PCIX  */
+#define  PCI_CAP_ID_HT          0x08	/* Hypertransport */
+#define  PCI_CAP_ID_PCIE	0x10	/* PCI Express */
 #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list */
 #define PCI_CAP_FLAGS		2	/* Capability defined flags (16 bits) */
 
diff --git a/src/include/device/pnp.h b/src/include/device/pnp.h
index 0d39fc1..508fac6 100644
--- a/src/include/device/pnp.h
+++ b/src/include/device/pnp.h
@@ -1,58 +1,49 @@
 #ifndef DEVICE_PNP_H
 #define DEVICE_PNP_H
 
-static inline void pnp_write_config(unsigned char port, unsigned char value, unsigned char reg)
-{
-	outb(reg, port);
-	outb(value, port +1);
-}
+#include <stdint.h>
+#include <device/device.h>
+#include <device/pnp_def.h>
+#include <device/chip.h>
 
-static inline unsigned char pnp_read_config(unsigned char port, unsigned char reg)
-{
-	outb(reg, port);
-	return inb(port +1);
-}
+/* Primitive pnp resource manipulation */
+void    pnp_write_config(device_t dev, uint8_t reg, uint8_t value);
+uint8_t pnp_read_config(device_t dev, uint8_t reg);
+void    pnp_set_logical_device(device_t dev);
+void    pnp_set_enable(device_t dev, int enable);
+int     pnp_read_enable(device_t dev);
+void    pnp_set_iobase(device_t dev, unsigned index, unsigned iobase);
+void    pnp_set_irq(device_t dev, unsigned index, unsigned irq);
+void    pnp_set_drq(device_t dev, unsigned index, unsigned drq);
 
-static inline void pnp_set_logical_device(unsigned char port, int device)
-{
-	pnp_write_config(port, device, 0x07);
-}
+/* PNP device operations */
+void pnp_read_resources(device_t dev);
+void pnp_set_resources(device_t dev);
+void pnp_enable_resources(device_t dev);
+void pnp_enable(device_t dev);
 
-static inline void pnp_set_enable(unsigned char port, int enable)
-{
-	pnp_write_config(port, enable?0x1:0x0, 0x30);
-}
+struct device_operations pnp_ops;
 
-static inline int pnp_read_enable(unsigned char port)
-{
-	return !!pnp_read_config(port, 0x30);
-}
+/* PNP helper operations */
 
-static inline void pnp_set_iobase0(unsigned char port, unsigned iobase)
-{
-	pnp_write_config(port, (iobase >> 8) & 0xff, 0x60);
-	pnp_write_config(port, iobase & 0xff, 0x61);
-}
+struct io_info {
+	unsigned mask, set;
+};
 
-static inline void pnp_set_iobase1(unsigned char port, unsigned iobase)
-{
-	pnp_write_config(port, (iobase >> 8) & 0xff, 0x62);
-	pnp_write_config(port, iobase & 0xff, 0x63);
-}
-
-static inline void pnp_set_irq0(unsigned char port, unsigned irq)
-{
-	pnp_write_config(port, irq, 0x70);
-}
-
-static inline void pnp_set_irq1(unsigned char port, unsigned irq)
-{
-	pnp_write_config(port, irq, 0x72);
-}
-
-static inline void pnp_set_drq(unsigned char port, unsigned drq)
-{
-	pnp_write_config(port, drq & 0xff, 0x74);
-}
+struct pnp_info {
+	struct device_operations *ops;
+	unsigned function;
+	unsigned flags;
+#define PNP_IO0  0x01
+#define PNP_IO1  0x02
+#define PNP_IRQ0 0x04
+#define PNP_IRQ1 0x08
+#define PNP_DRQ0 0x10
+#define PNP_DRQ1 0x20
+	struct io_info io0, io1;
+};
+struct resource *pnp_get_resource(device_t dev, unsigned index);
+void pnp_enumerate(struct chip *chip, unsigned functions, 
+	struct device_operations *ops, struct pnp_info *info);
 
 #endif /* DEVICE_PNP_H */
diff --git a/src/include/device/pnp_def.h b/src/include/device/pnp_def.h
new file mode 100644
index 0000000..b077837
--- /dev/null
+++ b/src/include/device/pnp_def.h
@@ -0,0 +1,12 @@
+#ifndef DEVICE_PNP_DEF_H
+#define DEVICE_PNP_DEF_H
+
+#define PNP_IDX_IO0  0x60
+#define PNP_IDX_IO1  0x62
+#define PNP_IDX_IRQ0 0x70
+#define PNP_IDX_IRQ1 0x72
+#define PNP_IDX_DRQ0 0x74
+#define PNP_IDX_DRQ1 0x75
+
+
+#endif /* DEVICE_PNP_DEF_H */
diff --git a/src/include/device/resource.h b/src/include/device/resource.h
index f90aba1..73a3f6e 100644
--- a/src/include/device/resource.h
+++ b/src/include/device/resource.h
@@ -18,9 +18,9 @@
 #define IORESOURCE_SUBTRACTIVE  0x00040000	/* This resource filters all of the unclaimed transactions
 						 * to the bus below.
 						 */
-
-#define IORESOURCE_SET		0x80000000	/* An IO resource that has been assigned a value */
-#define IORESOURCE_FIXED	0x40000000	/* An IO resource the allocator must not change */
+#define IORESOURCE_STORED	0x20000000	/* The IO resource assignment has been stored in the device */
+#define IORESOURCE_ASSIGNED	0x40000000	/* An IO resource that has been assigned a value */
+#define IORESOURCE_FIXED	0x80000000	/* An IO resource the allocator must not change */
 
 /* PCI specific resource bits */
 #define IORESOURCE_PCI64	(1<<0)	/* 64bit long pci resource */
diff --git a/src/include/pc80/keyboard.h b/src/include/pc80/keyboard.h
new file mode 100644
index 0000000..775dbee
--- /dev/null
+++ b/src/include/pc80/keyboard.h
@@ -0,0 +1,10 @@
+#ifndef PC80_KEYBOARD_H
+#define PC80_KEYBOARD_H
+
+struct pc_keyboard {
+	/* No initialization parameters for now */
+};
+
+void init_pc_keyboard(unsigned port0, unsigned port1, struct pc_keyboard *kbd);
+
+#endif /* PC80_KEYBOARD_H */
diff --git a/src/include/pc80/mc146818rtc.h b/src/include/pc80/mc146818rtc.h
index 1daf39a..e7e13c8 100644
--- a/src/include/pc80/mc146818rtc.h
+++ b/src/include/pc80/mc146818rtc.h
@@ -7,18 +7,6 @@
 
 #define RTC_PORT(x)	(RTC_BASE_PORT + (x))
 
-/* On PCs, the checksum is built only over bytes 16..45 */
-#define PC_CKS_RANGE_START	16
-#define PC_CKS_RANGE_END	45
-#define PC_CKS_LOC		46
-
-
-/* Linux bios checksum is built only over bytes 49..125 */
-#define LB_CKS_RANGE_START	49
-#define LB_CKS_RANGE_END	125
-#define LB_CKS_LOC		126
-
-
 /* control registers - Moto names
  */
 #define RTC_REG_A		10
@@ -88,22 +76,28 @@
 # define RTC_VRT 0x80		/* valid RAM and time */
 /**********************************************************************/
 
-
 /* On PCs, the checksum is built only over bytes 16..45 */
 #define PC_CKS_RANGE_START	16
 #define PC_CKS_RANGE_END	45
 #define PC_CKS_LOC		46
 
+/* Linux bios checksum is built only over bytes 49..125 */
+#ifndef LB_CKS_RANGE_START
 #define LB_CKS_RANGE_START	49
+#endif
+#ifndef LB_CKS_RANGE_END
 #define LB_CKS_RANGE_END	125
+#endif
+#ifndef LB_CKS_LOC
 #define LB_CKS_LOC		126
+#endif
 
 #if !defined(ASSEMBLY)
 void rtc_init(int invalid);
 #if USE_OPTION_TABLE == 1
 int get_option(void *dest, char *name);
 #else
-#define get_option(dest, name) (-2)
+static inline int get_option(void *dest, char *name) { return -2; }
 #endif
 #endif
 
diff --git a/src/include/string.h b/src/include/string.h
index cf9bbb1..111e23b 100644
--- a/src/include/string.h
+++ b/src/include/string.h
@@ -29,6 +29,7 @@
 }
 
 extern void *memcpy(void *dest, const void *src, size_t n);
+extern void *memmove(void *dest, const void *src, size_t n);
 extern void *memset(void *s, int c, size_t n);
 extern int memcmp(const void *s1, const void *s2, size_t n);
 
diff --git a/src/include/uart8250.h b/src/include/uart8250.h
index ae45615..f610026 100644
--- a/src/include/uart8250.h
+++ b/src/include/uart8250.h
@@ -1,7 +1,13 @@
 #ifndef UART8250_H
 #define UART8250_H
 
+struct uart8250 {
+	unsigned int baud;
+	/* Do I need an lcs parameter here? */
+};
+
 void uart8250_tx_byte(unsigned base_port, unsigned char data);
 void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs);
+void init_uart8250(unsigned base_port, struct uart8250 *uart);
 
 #endif /* UART8250_H */
diff --git a/src/lib/Config.lb b/src/lib/Config.lb
index a0de47c..bd6a2a9 100644
--- a/src/lib/Config.lb
+++ b/src/lib/Config.lb
@@ -6,10 +6,11 @@
 object memset.o
 object memcpy.o
 object memcmp.o
+object memmove.o
 object malloc.o
 object delay.o
 if HAVE_FALLBACK_BOOT
-  object fallback_boot.o
+	object fallback_boot.o
 end
 object compute_ip_checksum.o
 object version.o
diff --git a/src/lib/memcpy.c b/src/lib/memcpy.c
index ad8e8bd..16db677 100644
--- a/src/lib/memcpy.c
+++ b/src/lib/memcpy.c
@@ -1,11 +1,12 @@
 #include <string.h>
-void *memcpy(void *__dest, __const void *__src, size_t __n)
+void *memcpy(void *vdest, const void *vsrc, size_t bytes)
 {
+	const char *src = vsrc;
+	char *dest = vdest;
 	int i;
-	char *d = (char *) __dest, *s = (char *) __src;
 
-	for (i = 0; i < __n; i++)
-		d[i] = s[i];
+	for (i = 0; i < bytes; i++)
+		dest[i] = src[i];
 
-	return __dest;
+	return vdest;
 }
diff --git a/src/lib/memmove.c b/src/lib/memmove.c
new file mode 100644
index 0000000..0a49083
--- /dev/null
+++ b/src/lib/memmove.c
@@ -0,0 +1,20 @@
+#include <string.h>
+void *memmove(void *vdest, const void *vsrc, size_t count)
+{
+	const char *src = vsrc;
+	char *dest = vdest;
+	int i;
+
+	if (dest <= src) {
+		while (count--) {
+			*dest++ = *src++;
+		}
+	} else {
+		src  += count - 1;
+		dest += count - 1;
+		while(count--) {
+			*dest-- = *src--;
+		}
+	}
+	return vdest;
+}
diff --git a/src/lib/uart8250.c b/src/lib/uart8250.c
index ceb4e4a..67b0a95 100644
--- a/src/lib/uart8250.c
+++ b/src/lib/uart8250.c
@@ -58,3 +58,19 @@
 	outb((divisor >> 8) & 0xFF,    base_port + UART_DLM);
 	outb(lcs, base_port + UART_LCR);
 }
+
+/* Initialize a generic uart */
+void init_uart8250(unsigned base_port, struct uart8250 *uart)
+{
+	int divisor;
+	int lcs;
+	divisor = 115200/(uart->baud ? uart->baud: 1);
+	lcs = 3;
+	if (base_port == TTYS0_BASE) {
+		/* Don't reinitialize the console serial port,
+		 * This is espeically nasty in SMP.
+		 */
+		return;
+	}
+	uart8250_init(base_port, divisor, lcs);
+}
diff --git a/src/mainboard/amd/quartet/Config.lb b/src/mainboard/amd/quartet/Config.lb
index 1a2d8cd..d38ab96 100644
--- a/src/mainboard/amd/quartet/Config.lb
+++ b/src/mainboard/amd/quartet/Config.lb
@@ -251,19 +251,29 @@
 		pci 1:0.2 on
 		pci 1:1.0 on
 		superio NSC/pc87360 link 1
-			pnp 2e.0
-			pnp 2e.1
-			pnp 2e.2
-			pnp 2e.3
-			pnp 2e.4
-			pnp 2e.5
-			pnp 2e.6
-			pnp 2e.7
-			pnp 2e.8
-			pnp 2e.9
-			pnp 2e.a
-			register "com1" = "{1, 0, 0x3f8, 4}"
-			register "lpt" = "{1}"
+			pnp 2e.0 off  # Floppy 
+				 io 0x60 = 0x3f0
+				irq 0x70 = 6
+				drq 0x74 = 2
+			pnp 2e.1 off  # Parallel Port
+				 io 0x60 = 0x378
+				irq 0x70 = 7
+			pnp 2e.2 off # Com 2
+				 io 0x60 = 0x2f8
+				irq 0x70 = 3
+			pnp 2e.3 on  # Com 1
+				 io 0x60 = 0x3f8
+				irq 0x70 = 4
+			pnp 2e.4 off # SWC
+			pnp 2e.5 off # Mouse
+			pnp 2e.6 on  # Keyboard
+				 io 0x60 = 0x60
+				 io 0x62 = 0x64
+				irq 0x70 = 1
+			pnp 2e.7 off # GPIO
+			pnp 2e.8 off # ACB
+			pnp 2e.9 off # FSCM
+			pnp 2e.a off # WDT  
 		end
 	end
 end
diff --git a/src/mainboard/amd/solo/Config.lb b/src/mainboard/amd/solo/Config.lb
index 1372e46..bb9044e 100644
--- a/src/mainboard/amd/solo/Config.lb
+++ b/src/mainboard/amd/solo/Config.lb
@@ -23,6 +23,12 @@
 uses STACK_SIZE
 uses HEAP_SIZE
 uses USE_OPTION_TABLE
+uses LB_CKS_RANGE_START
+uses LB_CKS_RANGE_END
+uses LB_CKS_LOC
+uses MAINBOARD_PART_NUMBER
+uses MAINBOARD_VENDOR
+
 
 ## ROM_SIZE is the size of boot ROM that this board will use.
 default ROM_SIZE=262144
@@ -59,7 +65,14 @@
 default HAVE_OPTION_TABLE=1
 
 ##
-## AMD Solo is a 1cpu board 
+## Move the default LinuxBIOS cmos range off of AMD RTC registers
+##
+default LB_CKS_RANGE_START=49
+default LB_CKS_RANGE_END=122
+default LB_CKS_LOC=123
+
+##
+## AMD Solo is a 1cpu board
 ##
 default CONFIG_SMP=1
 default CONFIG_MAX_CPUS=1
@@ -152,7 +165,7 @@
 ## Romcc output
 ##
 makerule ./failover.E
-	depends "$(MAINBOARD)/failover.c" 
+	depends "$(MAINBOARD)/failover.c"
 	action "$(CPP) -I$(TOP)/src $(ROMCCPPFLAGS) $(CPPFLAGS) $(MAINBOARD)/failover.c > ./failover.E"
 end
 
@@ -161,13 +174,13 @@
 	action "./romcc -O -o failover.inc --label-prefix=failover ./failover.E"
 end
 
-makerule ./auto.E 
-	depends	"$(MAINBOARD)/auto.c" 
-	action	"$(CPP) -I$(TOP)/src $(ROMCCPPFLAGS) $(CPPFLAGS) $(MAINBOARD)/auto.c > ./auto.E"
+makerule ./auto.E
+	depends	"$(MAINBOARD)/auto.c option_table.h "
+	action	"$(CPP) -I$(TOP)/src -I. $(ROMCCPPFLAGS) $(CPPFLAGS) $(MAINBOARD)/auto.c > ./auto.E"
 end
-makerule ./auto.inc 
+makerule ./auto.inc
 	depends "./auto.E ./romcc"
-	action	"./romcc -mcpu=k8 -O ./auto.E > auto.inc"
+	action	"./romcc -mcpu=k8 -O2 ./auto.E > auto.inc"
 end
 
 ##
@@ -175,18 +188,19 @@
 ##
 mainboardinit cpu/i386/entry16.inc
 mainboardinit cpu/i386/entry32.inc
+#mainboardinit cpu/i386/bist32.inc
 ldscript /cpu/i386/entry16.lds
 ldscript /cpu/i386/entry32.lds
 
 ##
 ## Build our reset vector (This is where linuxBIOS is entered)
 ##
-if USE_FALLBACK_IMAGE 
-	mainboardinit cpu/i386/reset16.inc 
-	ldscript /cpu/i386/reset16.lds 
+if USE_FALLBACK_IMAGE
+	mainboardinit cpu/i386/reset16.inc
+	ldscript /cpu/i386/reset16.lds
 else
-	mainboardinit cpu/i386/reset32.inc 
-	ldscript /cpu/i386/reset32.lds 
+	mainboardinit cpu/i386/reset32.inc
+	ldscript /cpu/i386/reset32.lds
 end
 
 ### Should this be in the northbridge code?
@@ -204,12 +218,12 @@
 mainboardinit cpu/k8/earlymtrr.inc
 
 ###
-### This is the early phase of linuxBIOS startup 
+### This is the early phase of linuxBIOS startup
 ### Things are delicate and we test to see if we should
 ### failover to another image.
 ###
 if USE_FALLBACK_IMAGE
-	ldscript /arch/i386/lib/failover.lds 
+	ldscript /arch/i386/lib/failover.lds
 	mainboardinit ./failover.inc
 end
 
@@ -225,7 +239,7 @@
 mainboardinit cpu/k8/disable_mmx_sse.inc
 
 ##
-## Include the secondary Configuration files 
+## Include the secondary Configuration files
 ##
 dir /pc80
 config chip.h
@@ -254,19 +268,29 @@
 		pci 1:0.2 on
 		# pci 1:1.0 off
 		superio NSC/pc87360 link 1
-			pnp 2e.0
-			pnp 2e.1
-			pnp 2e.2
-			pnp 2e.3
-			pnp 2e.4
-			pnp 2e.5
-			pnp 2e.6
-			pnp 2e.7
-			pnp 2e.8
-			pnp 2e.9
-			pnp 2e.a
-			register "com1" = "{1, 0, 0x3f8, 4}"
-			register "lpt" = "{1}"
+			pnp 2e.0 off  # Floppy
+				 io 0x60 = 0x3f0
+				irq 0x70 = 6
+				drq 0x74 = 2
+			pnp 2e.1 off  # Parallel Port
+				 io 0x60 = 0x378
+				irq 0x70 = 7
+			pnp 2e.2 off # Com 2
+				 io 0x60 = 0x2f8
+				irq 0x70 = 3
+			pnp 2e.3 on  # Com 1
+				 io 0x60 = 0x3f8
+				irq 0x70 = 4
+			pnp 2e.4 off # SWC
+			pnp 2e.5 off # Mouse
+			pnp 2e.6 on  # Keyboard
+				 io 0x60 = 0x60
+				 io 0x62 = 0x64
+				irq 0x70 = 1
+			pnp 2e.7 off # GPIO
+			pnp 2e.8 off # ACB
+			pnp 2e.9 off # FSCM
+			pnp 2e.a off # WDT
 		end
 	end
 end
@@ -279,4 +303,5 @@
 ##
 mainboardinit pc80/serial.inc
 mainboardinit arch/i386/lib/console.inc
+#mainboardinit cpu/i386/bist32_fail.inc
 
diff --git a/src/mainboard/amd/solo/auto.c b/src/mainboard/amd/solo/auto.c
index 5963934..3a80e4c 100644
--- a/src/mainboard/amd/solo/auto.c
+++ b/src/mainboard/amd/solo/auto.c
@@ -1,14 +1,16 @@
 #define ASSEMBLY 1
 #include <stdint.h>
 #include <device/pci_def.h>
-#include <cpu/p6/apic.h>
 #include <arch/io.h>
 #include <device/pnp.h>
 #include <arch/romcc_io.h>
+#include <arch/smp/lapic.h>
+#include "option_table.h"
+#include "pc80/mc146818rtc_early.c"
 #include "pc80/serial.c"
 #include "arch/i386/lib/console.c"
 #include "ram/ramtest.c"
-#include "northbridge/amd/amdk8/early_ht.c"
+#include "northbridge/amd/amdk8/incoherent_ht.c"
 #include "southbridge/amd/amd8111/amd8111_early_smbus.c"
 #include "northbridge/amd/amdk8/raminit.h"
 #include "cpu/k8/apic_timer.c"
@@ -17,9 +19,26 @@
 #include "northbridge/amd/amdk8/reset_test.c"
 #include "debug.c"
 #include "northbridge/amd/amdk8/cpu_rev.c"
+#include "superio/NSC/pc87360/pc87360_early_serial.c"
 
 #define SIO_BASE 0x2e
 
+static void hard_reset(void)
+{
+	set_bios_reset();
+
+	/* enable cf9 */
+	pci_write_config8(PCI_DEV(0, 0x05, 3), 0x41, 0xf1);
+	/* reset */
+	outb(0x0e, 0x0cf9);
+}
+
+static void soft_reset(void)
+{
+	set_bios_reset();
+	pci_write_config8(PCI_DEV(0, 0x05, 0), 0x47, 1);
+}
+
 static void memreset_setup(void)
 {
 	if (is_cpu_pre_c0()) {
@@ -54,7 +73,7 @@
 
 static inline void activate_spd_rom(const struct mem_controller *ctrl)
 {
-	/* nothing here */
+	/* nothing to do */
 }
 
 static inline int spd_read_byte(unsigned device, unsigned address)
@@ -62,69 +81,11 @@
 	return smbus_read_byte(device, address);
 }
 
-/* no specific code here. this should go away completely */
-static void coherent_ht_mainboard(unsigned cpus)
-{
-}
 
 #include "northbridge/amd/amdk8/raminit.c"
 #include "northbridge/amd/amdk8/coherent_ht.c"
 #include "sdram/generic_sdram.c"
 
-static void enable_lapic(void)
-{
-
-	msr_t msr;
-	msr = rdmsr(0x1b);
-	msr.hi &= 0xffffff00;
-	msr.lo &= 0x000007ff;
-	msr.lo |= APIC_DEFAULT_BASE | (1 << 11);
-	wrmsr(0x1b, msr);
-}
-
-static void stop_this_cpu(void)
-{
-	unsigned apicid;
-	apicid = apic_read(APIC_ID) >> 24;
-
-	/* Send an APIC INIT to myself */
-	apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
-	apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT);
-	/* Wait for the ipi send to finish */
-	apic_wait_icr_idle();
-
-	/* Deassert the APIC INIT */
-	apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
-	apic_write(APIC_ICR,  APIC_INT_LEVELTRIG | APIC_DM_INIT);
-	/* Wait for the ipi send to finish */
-	apic_wait_icr_idle();
-
-	/* If I haven't halted spin forever */
-	for(;;) {
-		hlt();
-	}
-}
-
-#define PC87360_FDC  0x00
-#define PC87360_PP   0x01
-#define PC87360_SP2  0x02
-#define PC87360_SP1  0x03
-#define PC87360_SWC  0x04
-#define PC87360_KBCM 0x05
-#define PC87360_KBCK 0x06
-#define PC87360_GPIO 0x07
-#define PC87360_ACB  0x08
-#define PC87360_FSCM 0x09
-#define PC87360_WDT  0x0A
-
-/* FIXME: Do we really need this on Solo boards? */
-static void pc87360_enable_serial(void)
-{
-	pnp_set_logical_device(SIO_BASE, PC87360_SP1);
-	pnp_set_enable(SIO_BASE, 1);
-	pnp_set_iobase0(SIO_BASE, 0x3f8);
-}
-
 static void main(void)
 {
 	static const struct mem_controller cpu[] = {
@@ -138,26 +99,29 @@
 			.channel1 = { 0, 0, 0, 0 },
 		}
 	};
+	int needs_reset;
+	enable_lapic();
+	init_timer();
 	if (cpu_init_detected()) {
 		asm("jmp __cpu_reset");
 	}
 	enable_lapic();
 	init_timer();
-
-#if 0
-	/* Enabling this will make romcc segfault - 2003/10/13 */
+	distinguish_cpu_resets();
 	if (!boot_cpu()) {
 		print_err("This LinuxBIOS image is built for UP only.\n");
+		stop_this_cpu();
 	}
-#endif
-	pc87360_enable_serial();
+	pc87360_enable_serial(SIO_BASE, TTYS0_BASE);
 	uart_init();
 	console_init();
 	setup_default_resource_map();
-	setup_coherent_ht_domain();
-	enumerate_ht_chain(0);
-	distinguish_cpu_resets(0);
-	
+	needs_reset = setup_coherent_ht_domain();
+	needs_reset = ht_setup_chain(PCI_DEV(0, 0x18, 0), 0x80);
+	if (needs_reset) {
+		print_info("ht reset -");
+		soft_reset();
+	}
 #if 0
 	print_pci_devices();
 #endif
diff --git a/src/mainboard/amd/solo/cmos.layout b/src/mainboard/amd/solo/cmos.layout
index 5ba4c03..247715e 100644
--- a/src/mainboard/amd/solo/cmos.layout
+++ b/src/mainboard/amd/solo/cmos.layout
@@ -29,6 +29,9 @@
 386          1       e       1        ECC_memory
 388          4       r       0        reboot_bits
 392          3       e       5        baud_rate
+395          1       e       1        hw_scrubber
+396          1       e       1        interleave_chip_selects
+397          2       e       8        max_mem_clock
 400          1       e       1        power_on_after_fail
 412          4       e       6        debug_level
 416          4       e       7        boot_first
@@ -36,7 +39,14 @@
 424          4       e       7        boot_third
 428          4       h       0        boot_index
 432	     8       h       0        boot_countdown
-1008         16      h       0        check_sum
+440          4       e       9        slow_cpu
+444          1       e       1        nmi
+728        256       h       0        user_data
+984         16       h       0        check_sum
+# Reserve the extended AMD configuration registers
+1000        24       r       0        reserved_memory
+
+
 
 enumerations
 
@@ -66,9 +76,21 @@
 7     9     Fallback_HDD
 7     10    Fallback_Floppy
 #7     3     ROM
+8     0     200Mhz
+8     1     166Mhz
+8     2     133Mhz
+8     3     100Mhz
+9     0     off
+9     1     87.5%
+9     2     75.0%
+9     3     62.5%
+9     4     50.0%
+9     5     37.5%
+9     6     25.0%
+9     7     12.5%
 
 checksums
 
-checksum 392 1007 1008
+checksum 392 983 984
 
 
diff --git a/src/mainboard/amd/solo/failover.c b/src/mainboard/amd/solo/failover.c
index bd9c170..bd5869f 100644
--- a/src/mainboard/amd/solo/failover.c
+++ b/src/mainboard/amd/solo/failover.c
@@ -3,40 +3,78 @@
 #include <device/pci_def.h>
 #include <device/pci_ids.h>
 #include <arch/io.h>
-#include "arch/romcc_io.h"
+#include <arch/romcc_io.h>
+#include <arch/smp/lapic.h>
 #include "pc80/mc146818rtc_early.c"
 #include "southbridge/amd/amd8111/amd8111_enable_rom.c"
 #include "northbridge/amd/amdk8/early_ht.c"
 #include "cpu/p6/boot_cpu.c"
 #include "northbridge/amd/amdk8/reset_test.c"
 
+#define HAVE_REGPARM_SUPPORT 0
+#if HAVE_REGPARM_SUPPORT
+static unsigned long main(unsigned long bist)
+{
+#else
 static void main(void)
 {
+	unsigned long bist = 0;
+#endif
+	/* Make cerain my local apic is useable */
+	enable_lapic();
+
+	/* Is this a cpu only reset? */
+	if (cpu_init_detected()) {
+		if (last_boot_normal()) {
+			goto normal_image;
+		} else {
+			goto cpu_reset;
+		}
+	}
+	/* Is this a secondary cpu? */
+	if (!boot_cpu()) {
+		if (last_boot_normal()) {
+			goto normal_image;
+		} else {
+			goto fallback_image;
+		}
+	}
+	
+
 	/* Nothing special needs to be done to find bus 0 */
 	/* Allow the HT devices to be found */
 	enumerate_ht_chain(0);
-
+	
 	/* Setup the 8111 */
 	amd8111_enable_rom();
 
-	/* Is this a cpu reset? */
-	if (cpu_init_detected()) {
-		if (last_boot_normal()) {
-			asm("jmp __normal_image");
-		} else {
-			asm("jmp __cpu_reset");
-		}
-	}
 	/* Is this a deliberate reset by the bios */
-	else if (bios_reset_detected() && last_boot_normal()) {
-		asm("jmp __normal_image");
-	}
-	/* Is this a secondary cpu? */
-	else if (!boot_cpu() && last_boot_normal()) {
-		asm("jmp __normal_image");
+	if (bios_reset_detected() && last_boot_normal()) {
+		goto normal_image;
 	}
 	/* This is the primary cpu how should I boot? */
 	else if (do_normal_boot()) {
-		asm("jmp __normal_image");
+		goto normal_image;
 	}
+	else {
+		goto fallback_image;
+	}
+ normal_image:
+	asm("jmp __normal_image" 
+		: /* outputs */ 
+		: "a" (bist) /* inputs */
+		: /* clobbers */
+		);
+ cpu_reset:
+	asm("jmp __cpu_reset"
+		: /* outputs */ 
+		: "a"(bist) /* inputs */
+		: /* clobbers */
+		);
+ fallback_image:
+#if HAVE_REGPARM_SUPPORT
+	return bist;
+#else
+	return;
+#endif
 }
diff --git a/src/mainboard/amd/solo/mptable.c b/src/mainboard/amd/solo/mptable.c
index dfe4320..42c2e6b 100644
--- a/src/mainboard/amd/solo/mptable.c
+++ b/src/mainboard/amd/solo/mptable.c
@@ -178,7 +178,6 @@
 		1, (5<<2)|1, 0x02, 0x11);
 	
 
-	
 	/* There is no extension information... */
 
 	/* Compute the checksums */
diff --git a/src/mainboard/arima/hdama/Config.lb b/src/mainboard/arima/hdama/Config.lb
index 60d74da..fbb1a2b 100644
--- a/src/mainboard/arima/hdama/Config.lb
+++ b/src/mainboard/arima/hdama/Config.lb
@@ -23,6 +23,12 @@
 uses STACK_SIZE
 uses HEAP_SIZE
 uses USE_OPTION_TABLE
+uses LB_CKS_RANGE_START
+uses LB_CKS_RANGE_END
+uses LB_CKS_LOC
+uses MAINBOARD_PART_NUMBER
+uses MAINBOARD_VENDOR
+
 
 ## ROM_SIZE is the size of boot ROM that this board will use.
 default ROM_SIZE=524288
@@ -59,6 +65,13 @@
 default HAVE_OPTION_TABLE=1
 
 ##
+## Move the default LinuxBIOS cmos range off of AMD RTC registers
+##
+default LB_CKS_RANGE_START=49
+default LB_CKS_RANGE_END=122
+default LB_CKS_LOC=123
+
+##
 ## Build code for SMP support
 ## Only worry about 2 micro processors
 ##
@@ -73,8 +86,8 @@
 ##
 ## Clean up the motherboard id strings
 ##
-#default MAINBOARD_PART_NUMBER="HDAMA"
-#default MAINBOARD_VENDOR="ARIMA"
+default MAINBOARD_PART_NUMBER="HDAMA"
+default MAINBOARD_VENDOR="ARIMA"
 
 ###
 ### LinuxBIOS layout values
@@ -144,9 +157,7 @@
 ## Build the objects we have code for in this directory.
 ##
 
-#object mainboard.o
 driver mainboard.o
-#object static_devices.o
 if HAVE_MP_TABLE object mptable.o end
 if HAVE_PIRQ_TABLE object irq_tables.o end
 object reset.o
@@ -165,8 +176,8 @@
 end
 
 makerule ./auto.E 
-	depends	"$(MAINBOARD)/auto.c" 
-	action	"$(CPP) -I$(TOP)/src $(ROMCCPPFLAGS) $(CPPFLAGS) $(MAINBOARD)/auto.c > ./auto.E"
+	depends	"$(MAINBOARD)/auto.c option_table.h " 
+	action	"$(CPP) -I$(TOP)/src -I. $(ROMCCPPFLAGS) $(CPPFLAGS) $(MAINBOARD)/auto.c > ./auto.E"
 end
 makerule ./auto.inc 
 	depends "./auto.E ./romcc"
@@ -178,6 +189,7 @@
 ##
 mainboardinit cpu/i386/entry16.inc
 mainboardinit cpu/i386/entry32.inc
+mainboardinit cpu/i386/bist32.inc
 ldscript /cpu/i386/entry16.lds
 ldscript /cpu/i386/entry32.lds
 
@@ -259,19 +271,29 @@
 		pci 1:0.2 on
 		pci 1:1.0 off
 		superio NSC/pc87360 link 1
-			pnp 2e.0
-			pnp 2e.1
-			pnp 2e.2
-			pnp 2e.3
-			pnp 2e.4
-			pnp 2e.5
-			pnp 2e.6
-			pnp 2e.7
-			pnp 2e.8
-			pnp 2e.9
-			pnp 2e.a
-			register "com1" = "{1, 0, 0x3f8, 4}"
-			register "lpt" = "{1}"
+			pnp 2e.0 off  # Floppy 
+				 io 0x60 = 0x3f0
+				irq 0x70 = 6
+				drq 0x74 = 2
+			pnp 2e.1 off  # Parallel Port
+				 io 0x60 = 0x378
+				irq 0x70 = 7
+			pnp 2e.2 off # Com 2
+				 io 0x60 = 0x2f8
+				irq 0x70 = 3
+			pnp 2e.3 on  # Com 1
+				 io 0x60 = 0x3f8
+				irq 0x70 = 4
+			pnp 2e.4 off # SWC
+			pnp 2e.5 off # Mouse
+			pnp 2e.6 on  # Keyboard
+				 io 0x60 = 0x60
+				 io 0x62 = 0x64
+				irq 0x70 = 1
+			pnp 2e.7 off # GPIO
+			pnp 2e.8 off # ACB
+			pnp 2e.9 off # FSCM
+			pnp 2e.a off # WDT  
 		end
 	end
 end
@@ -297,4 +319,5 @@
 ##
 mainboardinit pc80/serial.inc
 mainboardinit arch/i386/lib/console.inc
+mainboardinit cpu/i386/bist32_fail.inc
 
diff --git a/src/mainboard/arima/hdama/auto.c b/src/mainboard/arima/hdama/auto.c
index 689346e..e011809 100644
--- a/src/mainboard/arima/hdama/auto.c
+++ b/src/mainboard/arima/hdama/auto.c
@@ -1,14 +1,16 @@
 #define ASSEMBLY 1
 #include <stdint.h>
 #include <device/pci_def.h>
-#include <cpu/p6/apic.h>
 #include <arch/io.h>
-#include <device/pnp.h>
+#include <device/pnp_def.h>
 #include <arch/romcc_io.h>
+#include <arch/smp/lapic.h>
+#include "option_table.h"
+#include "pc80/mc146818rtc_early.c"
 #include "pc80/serial.c"
 #include "arch/i386/lib/console.c"
 #include "ram/ramtest.c"
-#include "northbridge/amd/amdk8/early_ht.c"
+#include "northbridge/amd/amdk8/incoherent_ht.c"
 #include "southbridge/amd/amd8111/amd8111_early_smbus.c"
 #include "northbridge/amd/amdk8/raminit.h"
 #include "cpu/k8/apic_timer.c"
@@ -17,8 +19,25 @@
 #include "northbridge/amd/amdk8/reset_test.c"
 #include "debug.c"
 #include "northbridge/amd/amdk8/cpu_rev.c"
+#include "superio/NSC/pc87360/pc87360_early_serial.c"
 
-#define SIO_BASE 0x2e
+#define SERIAL_DEV PNP_DEV(0x2e, PC87360_SP1)
+
+static void hard_reset(void)
+{
+	set_bios_reset();
+
+	/* enable cf9 */
+	pci_write_config8(PCI_DEV(0, 0x04, 3), 0x41, 0xf1);
+	/* reset */
+	outb(0x0e, 0x0cf9);
+}
+
+static void soft_reset(void)
+{
+	set_bios_reset();
+	pci_write_config8(PCI_DEV(0, 0x04, 0), 0x47, 1);
+}
 
 static void memreset_setup(void)
 {
@@ -75,13 +94,13 @@
 		{ 0x00010404, 0x00050101 }
 	};
 
-	if(maxnodes>2) {
+	if(maxnodes > 2) {
 		print_debug("this mainboard is only designed for 2 cpus\r\n");
 		maxnodes=2;
 	}
 
 
-	if (!(node>=maxnodes || row>=maxnodes)) {
+	if (!(node >= maxnodes || row >= maxnodes)) {
 		ret=rows_2p[node][row];
 	}
 
@@ -98,67 +117,12 @@
 	return smbus_read_byte(device, address);
 }
 
-/* no specific code here. this should go away completely */
-static void coherent_ht_mainboard(unsigned cpus)
-{
-}
-
 #include "northbridge/amd/amdk8/raminit.c"
 #include "northbridge/amd/amdk8/coherent_ht.c"
 #include "sdram/generic_sdram.c"
 
-static void enable_lapic(void)
-{
 
-	msr_t msr;
-	msr = rdmsr(0x1b);
-	msr.hi &= 0xffffff00;
-	msr.lo &= 0x000007ff;
-	msr.lo |= APIC_DEFAULT_BASE | (1 << 11);
-	wrmsr(0x1b, msr);
-}
 
-static void stop_this_cpu(void)
-{
-	unsigned apicid;
-	apicid = apic_read(APIC_ID) >> 24;
-
-	/* Send an APIC INIT to myself */
-	apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
-	apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT);
-	/* Wait for the ipi send to finish */
-	apic_wait_icr_idle();
-
-	/* Deassert the APIC INIT */
-	apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
-	apic_write(APIC_ICR,  APIC_INT_LEVELTRIG | APIC_DM_INIT);
-	/* Wait for the ipi send to finish */
-	apic_wait_icr_idle();
-
-	/* If I haven't halted spin forever */
-	for(;;) {
-		hlt();
-	}
-}
-
-#define PC87360_FDC  0x00
-#define PC87360_PP   0x01
-#define PC87360_SP2  0x02
-#define PC87360_SP1  0x03
-#define PC87360_SWC  0x04
-#define PC87360_KBCM 0x05
-#define PC87360_KBCK 0x06
-#define PC87360_GPIO 0x07
-#define PC87360_ACB  0x08
-#define PC87360_FSCM 0x09
-#define PC87360_WDT  0x0A
-
-static void pc87360_enable_serial(void)
-{
-	pnp_set_logical_device(SIO_BASE, PC87360_SP1);
-	pnp_set_enable(SIO_BASE, 1);
-	pnp_set_iobase0(SIO_BASE, 0x3f8);
-}
 
 #define FIRST_CPU  1
 #define SECOND_CPU 1
@@ -193,22 +157,26 @@
 		},
 #endif
 	};
+	int needs_reset;
+	enable_lapic();
+	init_timer();
 	if (cpu_init_detected()) {
 		asm("jmp __cpu_reset");
 	}
-	enable_lapic();
-	init_timer();
+	distinguish_cpu_resets();
 	if (!boot_cpu()) {
 		stop_this_cpu();
 	}
-	pc87360_enable_serial();
+	pc87360_enable_serial(SERIAL_DEV, TTYS0_BASE);
 	uart_init();
 	console_init();
 	setup_default_resource_map();
-	setup_coherent_ht_domain();
-	enumerate_ht_chain(0);
-	distinguish_cpu_resets(0);
-	
+	needs_reset = setup_coherent_ht_domain();
+	needs_reset |= ht_setup_chain(PCI_DEV(0, 0x18, 0), 0x80);
+	if (needs_reset) {
+		print_info("ht reset -");
+		soft_reset();
+	}
 #if 0
 	print_pci_devices();
 #endif
@@ -219,39 +187,15 @@
 	memreset_setup();
 	sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu);
 
-#if 1
+#if 0
 	dump_pci_devices();
 #endif
 #if 0
 	dump_pci_device(PCI_DEV(0, 0x18, 2));
 #endif
 
-	/* Check all of memory */
 #if 0
-	msr_t msr;
-	msr = rdmsr(TOP_MEM);
-	print_debug("TOP_MEM: ");
-	print_debug_hex32(msr.hi);
-	print_debug_hex32(msr.lo);
-	print_debug("\r\n");
-#endif
-#if 0
-	ram_check(0x00000000, msr.lo);
-#endif
-#if 0
-	static const struct {
-		unsigned long lo, hi;
-	} check_addrs[] = {
-		/* Check 16MB of memory @ 0*/
-		{ 0x00000000, 0x01000000 },
-#if TOTAL_CPUS > 1
-		/* Check 16MB of memory @ 2GB */
-		{ 0x80000000, 0x81000000 },
-#endif
-	};
-	int i;
-	for(i = 0; i < sizeof(check_addrs)/sizeof(check_addrs[0]); i++) {
-		ram_check(check_addrs[i].lo, check_addrs[i].hi);
-	}
+	/* Check the first 1M */
+	ram_check(0x00000000, 0x000100000);
 #endif
 }
diff --git a/src/mainboard/arima/hdama/cmos.layout b/src/mainboard/arima/hdama/cmos.layout
index 5ba4c03..247715e 100644
--- a/src/mainboard/arima/hdama/cmos.layout
+++ b/src/mainboard/arima/hdama/cmos.layout
@@ -29,6 +29,9 @@
 386          1       e       1        ECC_memory
 388          4       r       0        reboot_bits
 392          3       e       5        baud_rate
+395          1       e       1        hw_scrubber
+396          1       e       1        interleave_chip_selects
+397          2       e       8        max_mem_clock
 400          1       e       1        power_on_after_fail
 412          4       e       6        debug_level
 416          4       e       7        boot_first
@@ -36,7 +39,14 @@
 424          4       e       7        boot_third
 428          4       h       0        boot_index
 432	     8       h       0        boot_countdown
-1008         16      h       0        check_sum
+440          4       e       9        slow_cpu
+444          1       e       1        nmi
+728        256       h       0        user_data
+984         16       h       0        check_sum
+# Reserve the extended AMD configuration registers
+1000        24       r       0        reserved_memory
+
+
 
 enumerations
 
@@ -66,9 +76,21 @@
 7     9     Fallback_HDD
 7     10    Fallback_Floppy
 #7     3     ROM
+8     0     200Mhz
+8     1     166Mhz
+8     2     133Mhz
+8     3     100Mhz
+9     0     off
+9     1     87.5%
+9     2     75.0%
+9     3     62.5%
+9     4     50.0%
+9     5     37.5%
+9     6     25.0%
+9     7     12.5%
 
 checksums
 
-checksum 392 1007 1008
+checksum 392 983 984
 
 
diff --git a/src/mainboard/arima/hdama/failover.c b/src/mainboard/arima/hdama/failover.c
index bd9c170..b22abfe 100644
--- a/src/mainboard/arima/hdama/failover.c
+++ b/src/mainboard/arima/hdama/failover.c
@@ -3,40 +3,78 @@
 #include <device/pci_def.h>
 #include <device/pci_ids.h>
 #include <arch/io.h>
-#include "arch/romcc_io.h"
+#include <arch/romcc_io.h>
+#include <arch/smp/lapic.h>
 #include "pc80/mc146818rtc_early.c"
 #include "southbridge/amd/amd8111/amd8111_enable_rom.c"
 #include "northbridge/amd/amdk8/early_ht.c"
 #include "cpu/p6/boot_cpu.c"
 #include "northbridge/amd/amdk8/reset_test.c"
 
+#define HAVE_REGPARM_SUPPORT 0
+#if HAVE_REGPARM_SUPPORT
+static unsigned long main(unsigned long bist)
+{
+#else
 static void main(void)
 {
+	unsigned long bist = 0;
+#endif
+	/* Make cerain my local apic is useable */
+	enable_lapic();
+
+	/* Is this a cpu only reset? */
+	if (cpu_init_detected()) {
+		if (last_boot_normal()) {
+			goto normal_image;
+		} else {
+			goto cpu_reset;
+		}
+	}
+	/* Is this a secondary cpu? */
+	if (!boot_cpu()) {
+		if (last_boot_normal()) {
+			goto normal_image;
+		} else {
+			goto fallback_image;
+		}
+	}
+	
+
 	/* Nothing special needs to be done to find bus 0 */
 	/* Allow the HT devices to be found */
-	enumerate_ht_chain(0);
-
+	enumerate_ht_chain();
+	
 	/* Setup the 8111 */
 	amd8111_enable_rom();
 
-	/* Is this a cpu reset? */
-	if (cpu_init_detected()) {
-		if (last_boot_normal()) {
-			asm("jmp __normal_image");
-		} else {
-			asm("jmp __cpu_reset");
-		}
-	}
 	/* Is this a deliberate reset by the bios */
-	else if (bios_reset_detected() && last_boot_normal()) {
-		asm("jmp __normal_image");
-	}
-	/* Is this a secondary cpu? */
-	else if (!boot_cpu() && last_boot_normal()) {
-		asm("jmp __normal_image");
+	if (bios_reset_detected() && last_boot_normal()) {
+		goto normal_image;
 	}
 	/* This is the primary cpu how should I boot? */
 	else if (do_normal_boot()) {
-		asm("jmp __normal_image");
+		goto normal_image;
 	}
+	else {
+		goto fallback_image;
+	}
+ normal_image:
+	asm("jmp __normal_image" 
+		: /* outputs */ 
+		: "a" (bist) /* inputs */
+		: /* clobbers */
+		);
+ cpu_reset:
+	asm("jmp __cpu_reset"
+		: /* outputs */ 
+		: "a"(bist) /* inputs */
+		: /* clobbers */
+		);
+ fallback_image:
+#if HAVE_REGPARM_SUPPORT
+	return bist;
+#else
+	return;
+#endif
 }
diff --git a/src/mainboard/arima/hdama/irq_tables.c b/src/mainboard/arima/hdama/irq_tables.c
index 9be2d1c..c54d43b 100644
--- a/src/mainboard/arima/hdama/irq_tables.c
+++ b/src/mainboard/arima/hdama/irq_tables.c
@@ -17,36 +17,28 @@
 
 const struct irq_routing_table intel_irq_routing_table = {
 	PIRQ_SIGNATURE,		/* u32 signature */
-	PIRQ_VERSION,		/* u16 version   */
-	32+16*IRQ_SLOT_COUNT,	/* there can be total IRQ_SLOT_COUNT 
-				 * devices on the bus */
+	PIRQ_VERSION,           /* u16 version   */
+	32+16*IRQ_SLOT_COUNT,	/* there can be total IRQ_SLOT_COUNT table entries */
 	IRQ_ROUTER_BUS,		/* Where the interrupt router lies (bus) */
 	IRQ_ROUTER_DEVFN,	/* Where the interrupt router lies (dev) */
 	0x00,			/* IRQs devoted exclusively to PCI usage */
 	IRQ_ROUTER_VENDOR,	/* Vendor */
 	IRQ_ROUTER_DEVICE,	/* Device */
 	0x00,			/* Crap (miniport) */
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* u8 rfu[11] */
-	0x00,			/*  u8 checksum , mod 256 checksum must give
-				 *  zero, will be corrected later 
-				 */
-	{
-
-		/* slot(0=onboard), devfn, irqlinks (line id, 0=not routed) */
-
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */
+	0xb0,           /*  u8 checksum , mod 256 checksum must give zero */
+	{	/* slot(0=onboard), devfn, irqlinks (line id, 0=not routed) */
 		/* PCI Slot 1-6 */
-		IRQ_SLOT (1, 3,1,0, 2,3,4,1 ),
-		IRQ_SLOT (2, 3,2,0, 3,4,1,2 ),
-		IRQ_SLOT (3, 2,1,0, 2,3,4,1 ),
-		IRQ_SLOT (4, 2,2,0, 3,4,1,2 ),
-		IRQ_SLOT (5, 4,5,0, 2,3,4,1 ),
-		IRQ_SLOT (6, 4,4,0, 1,2,3,4 ),
-
+		IRQ_SLOT(1, 3,1,0, 2,3,4,1 ),
+		IRQ_SLOT(2, 3,2,0, 3,4,1,2 ),
+		IRQ_SLOT(3, 2,1,0, 2,3,4,1 ),
+		IRQ_SLOT(4, 2,2,0, 3,4,1,2 ),
+		IRQ_SLOT(5, 4,5,0, 2,3,4,1 ),
+		IRQ_SLOT(6, 4,4,0, 1,2,3,4 ),
 		/* Onboard NICs */
-		IRQ_SLOT (0, 2,3,0, 4,0,0,0 ),
-		IRQ_SLOT (0, 2,4,0, 4,0,0,0 ),
-
+		IRQ_SLOT(0, 2,3,0, 4,0,0,0 ),
+		IRQ_SLOT(0, 2,4,0, 4,0,0,0 ),
 		/* Let Linux know about bus 1 */
-		IRQ_SLOT (0, 1,4,3, 0,0,0,0 ),
+		IRQ_SLOT(0, 1,4,3, 0,0,0,0 ),
 	}
 };
diff --git a/src/mainboard/arima/hdama/mainboard.c b/src/mainboard/arima/hdama/mainboard.c
index 8204128..bbc6f53 100644
--- a/src/mainboard/arima/hdama/mainboard.c
+++ b/src/mainboard/arima/hdama/mainboard.c
@@ -3,23 +3,268 @@
 #include <device/pci.h>
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
+#include <cpu/p6/msr.h>
 
 #include <arch/io.h>
 #include <device/chip.h>
 #include "../../../northbridge/amd/amdk8/northbridge.h"
 #include "chip.h"
 
+#include "pc80/mc146818rtc.h"
+
+
 
 unsigned long initial_apicid[CONFIG_MAX_CPUS] =
 {
 	0, 1,
 };
 
+#define SMBGSTATUS 0xe0
+#define SMBGCTL    0xe2
+#define SMBHSTADDR 0xe4
+#define SMBHSTDAT  0xe6
+#define SMBHSTCMD  0xe8
+#define SMBHSTFIFO 0xe9
+
+#define SMBUS_TIMEOUT (100*1000*10)
+
+static inline void smbus_delay(void)
+{
+	outb(0x80, 0x80);
+}
+
+static int smbus_wait_until_ready(unsigned smbus_io_base)
+{
+	unsigned long loops;
+	loops = SMBUS_TIMEOUT;
+	do {
+		unsigned short val;
+		smbus_delay();
+		val = inw(smbus_io_base + SMBGSTATUS);
+		if ((val & 0x800) == 0) {
+			break;
+		}
+		if(loops == (SMBUS_TIMEOUT / 2)) {
+			outw(inw(smbus_io_base + SMBGSTATUS), 
+				smbus_io_base + SMBGSTATUS);
+		}
+	} while(--loops);
+	return loops?0:-2;
+}
+
+static int smbus_wait_until_done(unsigned smbus_io_base)
+{
+	unsigned long loops;
+	loops = SMBUS_TIMEOUT;
+	do {
+		unsigned short val;
+		smbus_delay();
+		
+		val = inw(smbus_io_base + SMBGSTATUS);
+		if (((val & 0x8) == 0) | ((val & 0x437) != 0)) {
+			break;
+		}
+	} while(--loops);
+	return loops?0:-3;
+}
+
+static int smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned value)
+{
+	unsigned char global_status_register;
+
+	if (smbus_wait_until_ready(smbus_io_base) < 0) {
+		return -2;
+	}
+	
+	/* setup transaction */
+	/* disable interrupts */
+	outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
+	/* set the device I'm talking too */
+	outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
+	/* set the command/address... */
+	outb(0, smbus_io_base + SMBHSTCMD);
+	/* set up for a send byte */
+	outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL);
+
+	/* clear any lingering errors, so the transaction will run */
+	/* Do I need to write the bits to a 1 to clear an error? */
+	outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
+
+	/* set the data word...*/
+	outw(value, smbus_io_base + SMBHSTDAT);
+
+	/* start the command */
+	outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
+
+
+	/* poll for transaction completion */
+	if (smbus_wait_until_done(smbus_io_base) < 0) {
+		return -3;
+	}
+	global_status_register = inw(smbus_io_base + SMBGSTATUS);
+
+	if (global_status_register != (1 << 4)) {
+		return -1;
+	}
+	return 0;
+}
+
+static int smbus_recv_byte(unsigned smbus_io_base, unsigned device)
+{
+	unsigned char global_status_register;
+	unsigned char byte;
+
+	if (smbus_wait_until_ready(smbus_io_base) < 0) {
+		return -2;
+	}
+	
+	/* setup transaction */
+	/* disable interrupts */
+	outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
+	/* set the device I'm talking too */
+	outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
+	/* set the command/address... */
+	outb(0, smbus_io_base + SMBHSTCMD);
+	/* set up for a send byte */
+	outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL);
+
+	/* clear any lingering errors, so the transaction will run */
+	/* Do I need to write the bits to a 1 to clear an error? */
+	outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
+
+	/* set the data word...*/
+	outw(0, smbus_io_base + SMBHSTDAT);
+
+	/* start the command */
+	outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
+
+
+	/* poll for transaction completion */
+	if (smbus_wait_until_done(smbus_io_base) < 0) {
+		return -3;
+	}
+
+	global_status_register = inw(smbus_io_base + SMBGSTATUS);
+
+	/* read results of transaction */
+	byte = inw(smbus_io_base + SMBHSTDAT) & 0xff;
+
+	if (global_status_register != (1 << 4)) {
+		return -1;
+	}
+	return byte;
+}
+
+#if 0
+static int smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
+{
+	unsigned char global_status_register;
+	unsigned char byte;
+
+	if (smbus_wait_until_ready(smbus_io_base) < 0) {
+		return -2;
+	}
+	
+	/* setup transaction */
+	/* disable interrupts */
+	outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
+	/* set the device I'm talking too */
+	outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
+	/* set the command/address... */
+	outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
+	/* set up for a byte data read */
+	outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x2), smbus_io_base + SMBGCTL);
+
+	/* clear any lingering errors, so the transaction will run */
+	/* Do I need to write the bits to a 1 to clear an error? */
+	outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
+
+	/* clear the data word...*/
+	outw(0, smbus_io_base + SMBHSTDAT);
+
+	/* start the command */
+	outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
+
+
+	/* poll for transaction completion */
+	if (smbus_wait_until_done(smbus_io_base) < 0) {
+		return -3;
+	}
+
+	global_status_register = inw(smbus_io_base + SMBGSTATUS);
+
+	/* read results of transaction */
+	byte = inw(smbus_io_base + SMBHSTDAT) & 0xff;
+
+	if (global_status_register != (1 << 4)) {
+		return -1;
+	}
+	return byte;
+}
+
+static int smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val)
+{
+	if (smbus_wait_until_ready(smbus_io_base) < 0) {
+		return -2;
+	}
+
+	/* setup transaction */
+	/* disable interrupts */
+	outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)),
+			smbus_io_base + SMBGCTL);
+	/* set the device I'm talking too */
+	outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
+	outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
+	/* set up for a byte data write */ /* FIXME */
+	outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL);
+	/* clear any lingering errors, so the transaction will run */
+	/* Do I need to write the bits to a 1 to clear an error? */
+	outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
+
+	/* clear the data word...*/
+	outw(val, smbus_io_base + SMBHSTDAT);
+
+	/* start the command */
+	outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
+
+	/* poll for transaction completion */
+	if (smbus_wait_until_done(smbus_io_base) < 0) {
+		return -3;
+	}
+	return 0;
+}
+#endif
+
+#define SMBUS_MUX 0x70
+static void mainboard_init(device_t dev)
+{
+	/* Set the mux to see the temperature sensors */
+	dev = dev_find_device(0x1022, 0x746b, 0);
+	if (dev) {
+		unsigned smbus_io_base;
+		unsigned device;
+		int result;
+		int mux_setting;
+		device = SMBUS_MUX;
+		mux_setting = 1;
+		smbus_io_base = pci_read_config32(dev, 0x58) & ~1;;
+		result = smbus_send_byte(smbus_io_base, device, mux_setting);
+		if ((result < 0) || 
+			(smbus_recv_byte(smbus_io_base, device) != mux_setting)) {
+			printk_err("SMBUS mux would not set to %d\n", mux_setting);
+		}
+		
+	}
+	else {
+		printk_err("SMBUS_controller not found\n");
+	}
+}
+
 static struct device_operations mainboard_operations = {
 	.read_resources   = root_dev_read_resources,
 	.set_resources    = root_dev_set_resources,
 	.enable_resources = enable_childrens_resources,
-	.init             = 0,
+	.init             = mainboard_init,
 	.scan_bus         = amdk8_scan_root_bus,
 	.enable           = 0,
 };
diff --git a/src/mainboard/newisys/khepri/Config.lb b/src/mainboard/newisys/khepri/Config.lb
index 6deb361..f0ffeb4 100644
--- a/src/mainboard/newisys/khepri/Config.lb
+++ b/src/mainboard/newisys/khepri/Config.lb
@@ -252,19 +252,29 @@
 		pci 1:0.2 on
 		pci 1:1.0 on
 		superio NSC/pc87360 link 1
-			pnp 2e.0
-			pnp 2e.1
-			pnp 2e.2
-			pnp 2e.3
-			pnp 2e.4
-			pnp 2e.5
-			pnp 2e.6
-			pnp 2e.7
-			pnp 2e.8
-			pnp 2e.9
-			pnp 2e.a
-			register "com1" = "{1, 0, 0x3f8, 4}"
-			register "lpt" = "{1}"
+			pnp 2e.0 off  # Floppy 
+				 io 0x60 = 0x3f0
+				irq 0x70 = 6
+				drq 0x74 = 2
+			pnp 2e.1 off  # Parallel Port
+				 io 0x60 = 0x378
+				irq 0x70 = 7
+			pnp 2e.2 off # Com 2
+				 io 0x60 = 0x2f8
+				irq 0x70 = 3
+			pnp 2e.3 on  # Com 1
+				 io 0x60 = 0x3f8
+				irq 0x70 = 4
+			pnp 2e.4 off # SWC
+			pnp 2e.5 off # Mouse
+			pnp 2e.6 on  # Keyboard
+				 io 0x60 = 0x60
+				 io 0x62 = 0x64
+				irq 0x70 = 1
+			pnp 2e.7 off # GPIO
+			pnp 2e.8 off # ACB
+			pnp 2e.9 off # FSCM
+			pnp 2e.a off # WDT  
 		end
 	end
 end
diff --git a/src/mainboard/newisys/khepri/auto.c b/src/mainboard/newisys/khepri/auto.c
index df6ad6c..44f128a 100644
--- a/src/mainboard/newisys/khepri/auto.c
+++ b/src/mainboard/newisys/khepri/auto.c
@@ -2,17 +2,19 @@
 #define MAXIMUM_CONSOLE_LOGLEVEL 9
 #define DEFAULT_CONSOLE_LOGLEVEL 9
 
-
 #include <stdint.h>
 #include <device/pci_def.h>
 #include <cpu/p6/apic.h>
 #include <arch/io.h>
 #include <device/pnp.h>
 #include <arch/romcc_io.h>
+#include <arch/smp/lapic.h>
+#include "option_table.h"
+#include "pc80/mc146818rtc_early.c"
 #include "pc80/serial.c"
 #include "arch/i386/lib/console.c"
 #include "ram/ramtest.c"
-#include "northbridge/amd/amdk8/early_ht.c"
+#include "northbridge/amd/amdk8/incoherent_ht.c"
 #include "southbridge/amd/amd8111/amd8111_early_smbus.c"
 #include "northbridge/amd/amdk8/raminit.h"
 #include "cpu/k8/apic_timer.c"
@@ -21,8 +23,25 @@
 #include "northbridge/amd/amdk8/reset_test.c"
 #include "debug.c"
 #include "northbridge/amd/amdk8/cpu_rev.c"
+#include "superio/NSC/pc87360/pc87360_early_serial.c"
 
-#define SIO_BASE 0x2e
+#define SERIAL_DEV PNP_DEV(0x2e, PC87360_SP1)
+
+static void hard_reset(void)
+{
+	set_bios_reset();
+
+	/* enable cf9 */
+	pci_write_config8(PCI_DEV(0, 0x04, 3), 0x41, 0xf1);
+	/* reset */
+	outb(0x0e, 0x0cf9);
+}
+
+static void soft_reset(void)
+{
+	set_bios_reset();
+	pci_write_config8(PCI_DEV(0, 0x04, 0), 0x47, 1);
+}
 
 static void memreset_setup(void)
 {
@@ -102,11 +121,6 @@
 	return smbus_read_byte(device, address);
 }
 
-/* no specific code here. this should go away completely */
-static void coherent_ht_mainboard(unsigned cpus)
-{
-}
-
 #include "northbridge/amd/amdk8/raminit.c"
 
 #define CONNECTION_0_1 DOWN
@@ -116,59 +130,6 @@
 
 #include "resourcemap.c" /* newisys khepri does not want the default */
 
-static void enable_lapic(void)
-{
-
-	msr_t msr;
-	msr = rdmsr(0x1b);
-	msr.hi &= 0xffffff00;
-	msr.lo &= 0x000007ff;
-	msr.lo |= APIC_DEFAULT_BASE | (1 << 11);
-	wrmsr(0x1b, msr);
-}
-
-static void stop_this_cpu(void)
-{
-	unsigned apicid;
-	apicid = apic_read(APIC_ID) >> 24;
-
-	/* Send an APIC INIT to myself */
-	apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
-	apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT);
-	/* Wait for the ipi send to finish */
-	apic_wait_icr_idle();
-
-	/* Deassert the APIC INIT */
-	apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
-	apic_write(APIC_ICR,  APIC_INT_LEVELTRIG | APIC_DM_INIT);
-	/* Wait for the ipi send to finish */
-	apic_wait_icr_idle();
-
-	/* If I haven't halted spin forever */
-	for(;;) {
-		hlt();
-	}
-}
-
-#define PC87360_FDC  0x00
-#define PC87360_PP   0x01
-#define PC87360_SP2  0x02
-#define PC87360_SP1  0x03
-#define PC87360_SWC  0x04
-#define PC87360_KBCM 0x05
-#define PC87360_KBCK 0x06
-#define PC87360_GPIO 0x07
-#define PC87360_ACB  0x08
-#define PC87360_FSCM 0x09
-#define PC87360_WDT  0x0A
-
-static void pc87360_enable_serial(void)
-{
-	pnp_set_logical_device(SIO_BASE, PC87360_SP1);
-	pnp_set_enable(SIO_BASE, 1);
-	pnp_set_iobase0(SIO_BASE, 0x3f8);
-}
-
 static void main(void)
 {
 	/*
@@ -195,21 +156,26 @@
 			.channel1 = { (0xa<<3)|5, (0xa<<3)|7, 0, 0 },
 		},
 	};
+	int needs_reset;
+	enable_lapic();
+	init_timer();
 	if (cpu_init_detected()) {
 		asm("jmp __cpu_reset");
 	}
-	enable_lapic();
-	init_timer();
+	distinguish_cpu_resets();
 	if (!boot_cpu()) {
 		stop_this_cpu();
 	}
-	pc87360_enable_serial();
+	pc87360_enable_serial(SERIAL_DEV, TTYS0_BASE);
 	uart_init();
 	console_init();
 	setup_khepri_resource_map();
-	setup_coherent_ht_domain();
-	enumerate_ht_chain(0);
-	distinguish_cpu_resets(0);
+	needs_reset = setup_coherent_ht_domain();
+	needs_reset |= ht_setup_chain(PCI_DEV(0, 0x18, 0), 0x80);
+	if (needs_reset) {
+		print_info("ht reset -");
+		soft_reset();
+	}
 	
 #if 0
 	print_pci_devices();
@@ -230,30 +196,7 @@
 
 	/* Check all of memory */
 #if 0
-	msr_t msr;
-	msr = rdmsr(TOP_MEM);
-	print_debug("TOP_MEM: ");
-	print_debug_hex32(msr.hi);
-	print_debug_hex32(msr.lo);
-	print_debug("\r\n");
-#endif
-#if 0
-	ram_check(0x00000000, msr.lo);
-#endif
-#if 0
-	static const struct {
-		unsigned long lo, hi;
-	} check_addrs[] = {
-		/* Check 16MB of memory @ 0*/
-		{ 0x00000000, 0x01000000 },
-#if TOTAL_CPUS > 1
-		/* Check 16MB of memory @ 2GB */
-		{ 0x80000000, 0x81000000 },
-#endif
-	};
-	int i;
-	for(i = 0; i < sizeof(check_addrs)/sizeof(check_addrs[0]); i++) {
-		ram_check(check_addrs[i].lo, check_addrs[i].hi);
-	}
+	/* Check the first 1M */
+	ram_check(0x00000000, 0x000100000);
 #endif
 }
diff --git a/src/northbridge/amd/amdk8/Config.lb b/src/northbridge/amd/amdk8/Config.lb
index 0110e21..3b24916 100644
--- a/src/northbridge/amd/amdk8/Config.lb
+++ b/src/northbridge/amd/amdk8/Config.lb
@@ -1,4 +1,9 @@
 config chip.h
 object northbridge.o
 driver misc_control.o
-driver mcf0_control.o
+
+makerule raminit_test
+	depends "$(TOP)/src/northbridge/amd/amdk8/raminit_test.c"
+	depends "$(TOP)/src/northbridge/amd/amdk8/raminit.c"
+	action "$(HOSTCC) $(HOSTCFLAGS) $(CPUFLAGS) -Wno-unused-function -I$(TOP)/src/include -g  $< -o $@"
+end
diff --git a/src/northbridge/amd/amdk8/amdk8.h b/src/northbridge/amd/amdk8/amdk8.h
index c8ae95e..ca8e8dc 100644
--- a/src/northbridge/amd/amdk8/amdk8.h
+++ b/src/northbridge/amd/amdk8/amdk8.h
@@ -38,6 +38,15 @@
 #define  HTTC_HI_PRI_BYP_CNT_MASK   3
 
 
+/* Function 1 */
+#define PCI_IO_BASE0       0xc0
+#define PCI_IO_BASE1       0xc8
+#define PCI_IO_BASE2       0xd0
+#define PCI_IO_BASE3       0xd8
+#define PCI_IO_BASE_VGA_EN (1 << 4)
+#define PCI_IO_BASE_NO_ISA (1 << 5)
+
+
 /* Function 2 */
 #define DRAM_CSBASE	   0x40
 #define DRAM_CSMASK	   0x60
@@ -124,6 +133,9 @@
 #define	 DCL_UnBufDimm	   (1<<18)
 #define	 DCL_32ByteEn	   (1<<19)
 #define	 DCL_x4DIMM_SHIFT  20
+#define	 DCL_DisInRcvrs    (1<<24)
+#define	 DCL_BypMax_SHIFT  25
+#define	 DCL_En2T          (1<<28)
 #define DRAM_CONFIG_HIGH   0x94
 #define	 DCH_ASYNC_LAT_SHIFT  0
 #define	 DCH_ASYNC_LAT_MASK   0xf
diff --git a/src/northbridge/amd/amdk8/coherent_ht.c b/src/northbridge/amd/amdk8/coherent_ht.c
index 83fbd40..5b6ea16 100644
--- a/src/northbridge/amd/amdk8/coherent_ht.c
+++ b/src/northbridge/amd/amdk8/coherent_ht.c
@@ -14,7 +14,10 @@
  */
 
 #include <device/pci_def.h>
+#include <device/pci_ids.h>
+#include <device/hypertransport_def.h>
 #include "arch/romcc_io.h"
+#include "amdk8.h"
 
 /*
  * Until we have a completely dynamic setup we want
@@ -39,10 +42,6 @@
 #define CONNECTION_0_2 UP
 #endif
 
-#ifndef CONNECTION_1_0 
-#define CONNECTION_1_0 ACROSS
-#endif
-
 #ifndef CONNECTION_1_3 
 #define CONNECTION_1_3 UP
 #endif
@@ -63,7 +62,7 @@
 
 typedef uint8_t u8;
 typedef uint32_t u32;
-typedef int8_t bool;
+typedef int bool;
 
 #define TRUE  (-1)
 #define FALSE (0)
@@ -95,51 +94,15 @@
 
 	u32 val;
 
-	print_debug("Disabling read/write/fill probes for UP... ");
+	print_spew("Disabling read/write/fill probes for UP... ");
 
 	val=pci_read_config32(NODE_HT(0), 0x68);
 	val |= (1<<10)|(1<<9)|(1<<8)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1 << 0);
 	pci_write_config32(NODE_HT(0), 0x68, val);
 
-	print_debug("done.\r\n");
+	print_spew("done.\r\n");
 
 }
-//BY LYH
-#if 0
-#define WAIT_TIMES 1000
-static void wait_ap_stop(u8 node)
-{
-        unsigned long reg;
-        unsigned long i;
-        for(i=0;i<WAIT_TIMES;i++) {
-                unsigned long regx;
-                regx = pci_read_config32(NODE_HT(node),0x6c);
-                if((regx & (1<<4))==1) break;
-        }
-        reg = pci_read_config32(NODE_HT(node),0x6c);
-        reg &= ~(1<<4);  // clear it
-        pci_write_config32(NODE_HT(node), 0x6c, reg);
-
-}
-static void notify_bsp_ap_is_stopped(void)
-{
-        unsigned long reg;
-        unsigned long apic_id;
-        apic_id = *((volatile unsigned long *)(APIC_DEFAULT_BASE+APIC_ID));
-        apic_id >>= 24;
-/*      print_debug("applicaton cpu apic_id: ");
-        print_debug_hex32(apic_id);
-        }*/
-        if(apic_id!=0) { //AP  apic_id == node_id ??
-//              set the ColdResetbit to notify BSP that AP is stopped
-                reg = pci_read_config32(NODE_HT(apic_id), 0x6C);
-                reg |= 1<<4;
-                pci_write_config32(NODE_HT(apic_id),  0x6C, reg);
-        }
-
-}
-#endif
-//BY LYH END
 
 static void enable_routing(u8 node)
 {
@@ -168,14 +131,14 @@
 	 */
 
 	/* Enable routing table */
-	print_debug("Enabling routing table for node ");
-	print_debug_hex32(node);
+	print_spew("Enabling routing table for node ");
+	print_spew_hex32(node);
 
 	val=pci_read_config32(NODE_HT(node), 0x6c);
-	val &= ~((1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0));
+	val &= ~((1<<1)|(1<<0));
 	pci_write_config32(NODE_HT(node), 0x6c, val);
 
-	print_debug(" done.\r\n");
+	print_spew(" done.\r\n");
 }
 
 #if CONFIG_MAX_CPUS > 1
@@ -184,84 +147,97 @@
 {
 	uint32_t val;
 
-	print_debug("Renaming current temp node to ");
-	print_debug_hex32(node);
+	print_spew("Renaming current temp node to ");
+	print_spew_hex32(node);
 
 	val=pci_read_config32(NODE_HT(7), 0x60);
 	val &= (~7);  /* clear low bits. */
         val |= node;   /* new node        */
 	pci_write_config32(NODE_HT(7), 0x60, val);
 
-//BY LYH
-#if 0
-        if(node!=0) {
-                wait_ap_stop(node);
-        }
-#endif
-//BY LYH END
-
-
-	print_debug(" done.\r\n");
-
-
+	print_spew(" done.\r\n");
 }
 
 static bool check_connection(u8 src, u8 dest, u8 link)
 {
-	/* this function does 2 things:
-	 * 1) detect whether the coherent HT link is connected.
-	 * 2) verify that the coherent hypertransport link
-	 *    is established and actually working by reading the
-	 *    remote node's vendor/device id
-	 */
-
+	/* See if we have a valid connection to dest */
 	u32 val;
 	
-	/* 1) */
-	val=pci_read_config32(NODE_HT(src), 0x98+link);
+	/* Detect if the coherent HT link is connected. */
+	val = pci_read_config32(NODE_HT(src), 0x98+link);
 	if ( (val&0x17) != 0x03)
 		return 0;
 
-	/* 2) */
-        val=pci_read_config32(NODE_HT(dest),0);
+	/* Verify that the coherent hypertransport link is
+	 * established and actually working by reading the
+	 * remode node's vendor/device id
+	 */
+        val = pci_read_config32(NODE_HT(dest),0);
 	if(val != 0x11001022)
 		return 0;
 
 	return 1;
 }
 
-static void optimize_connection(u8 node1, u8 link1, u8 node2, u8 link2)
+static unsigned read_freq_cap(device_t dev, unsigned pos)
+{
+	/* Handle bugs in valid hypertransport frequency reporting */
+	unsigned freq_cap;
+	uint32_t id;
+
+	freq_cap = pci_read_config16(dev, pos);
+	freq_cap &= ~(1 << HT_FREQ_VENDOR); /* Ignore Vendor HT frequencies */
+
+	id = pci_read_config32(dev, 0);
+
+	/* AMD 8131 Errata 48 */
+	if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8131_PCIX << 16))) {
+		freq_cap &= ~(1 << HT_FREQ_800Mhz);
+	}
+	/* AMD 8151 Errata 23 */
+	if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8151_SYSCTRL << 16))) {
+		freq_cap &= ~(1 << HT_FREQ_800Mhz);
+	}
+	/* AMD K8 Unsupported 1Ghz? */
+	if (id == (PCI_VENDOR_ID_AMD | (0x1100 << 16))) {
+		freq_cap &= ~(1 << HT_FREQ_1000Mhz);
+	}
+	return freq_cap;
+}
+
+static int optimize_connection(device_t node1, uint8_t link1, device_t node2, uint8_t link2)
 {
 	static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 };
 	static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 };
 	uint16_t freq_cap1, freq_cap2, freq_cap, freq_mask;
-	uint8_t width_cap1, width_cap2, width_cap, width, ln_width1, ln_width2;
-	uint8_t freq;
+	uint8_t width_cap1, width_cap2, width_cap, width, old_width, ln_width1, ln_width2;
+	uint8_t freq, old_freq;
+	int needs_reset;
 	/* Set link width and frequency */
 
+	/* Initially assume everything is already optimized and I don't need a reset */
+	needs_reset = 0;
+
 	/* Get the frequency capabilities */
-	freq_cap1  = pci_read_config16(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_FREQ_CAP);
-	freq_cap2  = pci_read_config16(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_FREQ_CAP);
+	freq_cap1 = read_freq_cap(node1, link1 + PCI_HT_CAP_HOST_FREQ_CAP);
+	freq_cap2 = read_freq_cap(node2, link2 + PCI_HT_CAP_HOST_FREQ_CAP);
 
 	/* Calculate the highest possible frequency */
-#if 1
-	/* FIXME!!!!!!! 
-	 * This method of computing the fastes frequency is broken.
-	 * Because the frequencies (i.e. 100Mhz) are not ordered.
-	 */
-	freq = log2(freq_cap1 & freq_cap2 & 0xff);
-#else
-	/* Only allow supported frequencies 800Mhz and below */
-	freq = log2(freq_cap1 & freq_cap2 & 0x3f);
-#endif
+	freq = log2(freq_cap1 & freq_cap2);
+
+	/* See if I am changing the link freqency */
+	old_freq = pci_read_config8(node1, link1 + PCI_HT_CAP_HOST_FREQ);
+	needs_reset |= old_freq != freq;
+	old_freq = pci_read_config8(node2, link2 + PCI_HT_CAP_HOST_FREQ);
+	needs_reset |= old_freq != freq;
 
 	/* Set the Calulcated link frequency */
-	pci_write_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_FREQ, freq);
-	pci_write_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_FREQ, freq);
+	pci_write_config8(node1, link1 + PCI_HT_CAP_HOST_FREQ, freq);
+	pci_write_config8(node2, link2 + PCI_HT_CAP_HOST_FREQ, freq);
 
 	/* Get the width capabilities */
-	width_cap1 = pci_read_config8(NODE_HT(node1),  0x80 + link1 + PCI_HT_CAP_HOST_WIDTH);
-	width_cap2 = pci_read_config8(NODE_HT(node2),  0x80 + link2 + PCI_HT_CAP_HOST_WIDTH);
+	width_cap1 = pci_read_config8(node1, link1 + PCI_HT_CAP_HOST_WIDTH);
+	width_cap2 = pci_read_config8(node2, link2 + PCI_HT_CAP_HOST_WIDTH);
 
 	/* Calculate node1's input width */
 	ln_width1 = link_width_to_pow2[width_cap1 & 7];
@@ -278,45 +254,38 @@
 	}
 	width |= pow2_to_link_width[ln_width1] << 4;
 	
+	/* See if I am changing node1's width */
+	old_width = pci_read_config8(node1, link1 + PCI_HT_CAP_HOST_WIDTH + 1);
+	needs_reset |= old_width != width;
+
 	/* Set node1's widths */
-	pci_write_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_WIDTH + 1, width);
+	pci_write_config8(node1, link1 + PCI_HT_CAP_HOST_WIDTH + 1, width);
+
+	/* Calculate node2's width */
+	width = ((width & 0x70) >> 4) | ((width & 0x7) << 4);
+
+	/* See if I am changing node2's width */
+	old_width = pci_read_config8(node2, link2 + PCI_HT_CAP_HOST_WIDTH + 1);
+	needs_reset |= old_width != width;
 
 	/* Set node2's widths */
-	width = ((width & 0x70) >> 4) | ((width & 0x7) << 4);
-	pci_write_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_WIDTH + 1, width);
+	pci_write_config8(node2, link2 + PCI_HT_CAP_HOST_WIDTH + 1, width);
+
+	return needs_reset;
 }
 
 static void fill_row(u8 node, u8 row, u32 value)
 {
-#if 0
-	print_debug("fill_row: pci_write_config32(");
-	print_debug_hex32(NODE_HT(node));
-	print_debug_char(',');
-	print_debug_hex32(0x40 + (row << 2));
-	print_debug_char(',');
-	print_debug_hex32(value);
-	print_debug(")\r\n");
-#endif	
 	pci_write_config32(NODE_HT(node), 0x40+(row<<2), value);
 }
 
 static void setup_row(u8 source, u8 dest, u8 cpus)
 {
-#if 0
-	printk_spew("setting up link from node %d to %d (%d cpus)\r\n",
-		source, dest, cpus);
-#endif
-
 	fill_row(source,dest,generate_row(source,dest,cpus));
 }
 
 static void setup_temp_row(u8 source, u8 dest, u8 cpus)
 {
-#if 0
-	printk_spew("setting up temp. link from node %d to %d (%d cpus)\r\n",
-		source, dest, cpus);
-#endif
-
 	fill_row(source,7,generate_temp_row(source,dest,cpus));
 }
 
@@ -345,9 +314,8 @@
 	};
 	uint8_t row;
 	int i;
-#if 1
-	print_debug("setup_remote_node\r\n");
-#endif
+
+	print_spew("setup_remote_node\r\n");
 	for(row=0; row<cpus; row++)
 		setup_remote_row(node, row, cpus);
 
@@ -356,18 +324,11 @@
 		uint32_t value;
 		uint8_t reg;
 		reg = pci_reg[i];
-#if 0
-		print_debug("copying reg: ");
-		print_debug_hex8(reg);
-		print_debug("\r\n");
-#endif
 		value = pci_read_config32(NODE_MP(0), reg);
 		pci_write_config32(NODE_MP(7), reg, value);
 
 	}
-#if 1
-	print_debug("setup_remote_done\r\n");
-#endif
+	print_spew("setup_remote_done\r\n");
 }
 
 #endif
@@ -381,79 +342,91 @@
 }
 #endif
 
-static u8 setup_uniprocessor(void)
+static void setup_uniprocessor(void)
 {
-	print_debug("Enabling UP settings\r\n");
+	print_spew("Enabling UP settings\r\n");
 	disable_probes();
-	return 1;
 }
 
+struct setup_smp_result {
+	int cpus;
+	int needs_reset;
+};
+
 #if CONFIG_MAX_CPUS > 1
-static u8 setup_smp(void)
+static struct setup_smp_result setup_smp(void)
 {
-	u8 cpus=2;
+	struct setup_smp_result result;
+	result.cpus = 2;
+	result.needs_reset = 0;
 
-	print_debug("Enabling SMP settings\r\n");
+	print_spew("Enabling SMP settings\r\n");
 
-	setup_row(0,0,cpus);
+	setup_row(0, 0, result.cpus);
 	/* Setup and check a temporary connection to node 1 */
-	setup_temp_row(0,1,cpus);
+	setup_temp_row(0, 1, result.cpus);
 	
 	if (!check_connection(0, 7, CONNECTION_0_1)) {
-		print_debug("No connection to Node 1.\r\n");
+		print_spew("No connection to Node 1.\r\n");
 		clear_temp_row(0);	/* delete temp connection */
 		setup_uniprocessor();	/* and get up working     */
-		return 1;
+		result.cpus = 1;
+		return result;
 	}
 
 	/* We found 2 nodes so far */
-	optimize_connection(0, CONNECTION_0_1, 7, CONNECTION_1_0);
-	setup_node(0, cpus);	/* Node 1 is there. Setup Node 0 correctly */
-	setup_remote_node(1, cpus);  /* Setup the routes on the remote node */
+	result.needs_reset = 
+		optimize_connection(NODE_HT(0), 0x80 + CONNECTION_0_1, NODE_HT(7), 0x80 + CONNECTION_0_1);
+	setup_node(0, result.cpus);	/* Node 1 is there. Setup Node 0 correctly */
+	setup_remote_node(1, result.cpus);  /* Setup the routes on the remote node */
         rename_temp_node(1);    /* Rename Node 7 to Node 1  */
         enable_routing(1);      /* Enable routing on Node 1 */
   	
 	clear_temp_row(0);	/* delete temporary connection */
 	
 #if CONFIG_MAX_CPUS > 2
-	cpus=4;
+	result.cpus=4;
 	
 	/* Setup and check temporary connection from Node 0 to Node 2 */
-	setup_temp_row(0,2,cpus);
+	setup_temp_row(0,2, result.cpus);
 
 	if (!check_connection(0, 7, CONNECTION_0_2)) {
-		print_debug("No connection to Node 2.\r\n");
+		print_spew("No connection to Node 2.\r\n");
 		clear_temp_row(0);	 /* delete temp connection */
-		return 2;
+		result.cpus = 2;
+		return result;
 	}
 
 	/* We found 3 nodes so far. Now setup a temporary
 	 * connection from node 0 to node 3 via node 1
 	 */
 
-	setup_temp_row(0,1,cpus); /* temp. link between nodes 0 and 1 */
-	setup_temp_row(1,3,cpus); /* temp. link between nodes 1 and 3 */
+	setup_temp_row(0,1, result.cpus); /* temp. link between nodes 0 and 1 */
+	setup_temp_row(1,3, result.cpus); /* temp. link between nodes 1 and 3 */
 
 	if (!check_connection(1, 7, CONNECTION_1_3)) {
-		print_debug("No connection to Node 3.\r\n");
+		print_spew("No connection to Node 3.\r\n");
 		clear_temp_row(0);	 /* delete temp connection */
 		clear_temp_row(1);	 /* delete temp connection */
-		return 2;
+		result.cpus = 2;
+		return result;
 	}
 
+#warning "FIXME optimize the physical connections"
+
 	/* We found 4 nodes so far. Now setup all nodes for 4p */
 
-	setup_node(0, cpus);  /* The first 2 nodes are configured    */
-	setup_node(1, cpus);  /* already. Just configure them for 4p */
+	setup_node(0, result.cpus);  /* The first 2 nodes are configured    */
+	setup_node(1, result.cpus);  /* already. Just configure them for 4p */
 	
-	setup_temp_row(0,2,cpus);
-	setup_temp_node(2,cpus);
+	setup_temp_row(0,2, result.cpus);
+	setup_temp_node(2, result.cpus);
         rename_temp_node(2);
         enable_routing(2);
   
-	setup_temp_row(0,1,cpus);
-	setup_temp_row(1,3,cpus);
-	setup_temp_node(3,cpus);
+	setup_temp_row(0,1, result.cpus);
+	setup_temp_row(1,3, result.cpus);
+	setup_temp_node(3, result.cpus);
         rename_temp_node(3);
         enable_routing(3);      /* enable routing on node 3 (temp.) */
 	
@@ -463,52 +436,52 @@
 	clear_temp_row(3);
 
 #endif
-	print_debug_hex32(cpus);
+	print_debug_hex32(result.cpus);
 	print_debug(" nodes initialized.\r\n");
-	return cpus;
+	return result;
 }
 #endif
 
 #if CONFIG_MAX_CPUS > 1
-static unsigned detect_mp_capabilities(unsigned cpus)
+static unsigned verify_mp_capabilities(unsigned cpus)
 {
 	unsigned node, row, mask;
 	bool mp_cap=TRUE;
 
-#if 1
-	print_debug("detect_mp_capabilities: ");
-	print_debug_hex32(cpus);
-	print_debug("\r\n");
-#endif
-	if (cpus>2)
+	if (cpus > 2) {
 		mask=0x06;	/* BigMPCap */
-	else
+	} else {
 		mask=0x02;	/* MPCap    */
-
-	for (node=0; node<cpus; node++) {
-		if ((pci_read_config32(NODE_MC(node), 0xe8) & mask)!=mask)
-			mp_cap=FALSE;
 	}
 
-	if (mp_cap)
+	for (node=0; node<cpus; node++) {
+		if ((pci_read_config32(NODE_MC(node), 0xe8) & mask) != mask) {
+			mp_cap = FALSE;
+		}
+	}
+
+	if (mp_cap) {
 		return cpus;
+	}
 
 	/* one of our cpus is not mp capable */
 
-	print_debug("One of the CPUs is not MP capable. Going back to UP\r\n");
+	print_err("One of the CPUs is not MP capable. Going back to UP\r\n");
 
-	for (node=cpus; node>0; node--)
-	    for (row=cpus; row>0; row--)
-		fill_row(NODE_HT(node-1), row-1, DEFAULT);
-	
-	return setup_uniprocessor();
+	for (node = cpus; node > 0; node--) {
+		for (row = cpus; row > 0; row--) {
+			fill_row(NODE_HT(node-1), row-1, DEFAULT);
+		}
+	}
+	setup_uniprocessor();
+	return 1;
 }
 
 #endif
 
 static void coherent_ht_finalize(unsigned cpus)
 {
-	int node;
+	unsigned node;
 	bool rev_a0;
 	
 	/* set up cpu count and node count and enable Limit
@@ -517,53 +490,149 @@
 	 * registers on Hammer A0 revision.
 	 */
 
-#if 1
+#if 0
 	print_debug("coherent_ht_finalize\r\n");
 #endif
-	rev_a0= is_cpu_rev_a0();
+	rev_a0 = is_cpu_rev_a0();
+	for (node = 0; node < cpus; node++) {
+		device_t dev;
+		uint32_t val;
+		dev = NODE_HT(node);
 
-	for (node=0; node<cpus; node++) {
-		u32 val;
-		val=pci_read_config32(NODE_HT(node), 0x60);
+		/* Set the Total CPU and Node count in the system */
+		val = pci_read_config32(dev, 0x60);
 		val &= (~0x000F0070);
 		val |= ((cpus-1)<<16)|((cpus-1)<<4);
-		pci_write_config32(NODE_HT(node),0x60,val);
+		pci_write_config32(dev, 0x60, val);
 
-		val=pci_read_config32(NODE_HT(node), 0x68);
-#if 1
-		val |= 0x00008000;
-#else
-		val |= 0x0f00c800;  // 0x00008000->0f00c800 BY LYH
-#endif
-		pci_write_config32(NODE_HT(node),0x68,val);
+		/* Only respond to real cpu pci configuration cycles
+		 * and optimize the HT settings 
+		 */
+		val=pci_read_config32(dev, 0x68);
+		val &= ~((HTTC_BUF_REL_PRI_MASK << HTTC_BUF_REL_PRI_SHIFT) |
+			(HTTC_MED_PRI_BYP_CNT_MASK << HTTC_MED_PRI_BYP_CNT_SHIFT) |
+			(HTTC_HI_PRI_BYP_CNT_MASK << HTTC_HI_PRI_BYP_CNT_SHIFT));
+		val |= HTTC_LIMIT_CLDT_CFG | 
+			(HTTC_BUF_REL_PRI_8 << HTTC_BUF_REL_PRI_SHIFT) |
+			HTTC_RSP_PASS_PW |
+			(3 << HTTC_MED_PRI_BYP_CNT_SHIFT) |
+			(3 << HTTC_HI_PRI_BYP_CNT_SHIFT);
+		pci_write_config32(dev, 0x68, val);
 
 		if (rev_a0) {
-			pci_write_config32(NODE_HT(node),0x94,0);
-			pci_write_config32(NODE_HT(node),0xb4,0);
-			pci_write_config32(NODE_HT(node),0xd4,0);
+			pci_write_config32(dev, 0x94, 0);
+			pci_write_config32(dev, 0xb4, 0);
+			pci_write_config32(dev, 0xd4, 0);
 		}
+
+
 	}
-#if 1
+
+#if 0
 	print_debug("done\r\n");
 #endif
 }
 
+static int apply_cpu_errata_fixes(unsigned cpus, int needs_reset)
+{
+	unsigned node;
+	for(node = 0; node < cpus; node++) {
+		device_t dev;
+		uint32_t cmd;
+		dev = NODE_MC(node);
+		if (is_cpu_pre_c0()) {
+
+			/* Errata 66
+			 * Limit the number of downstream posted requests to 1 
+			 */
+			cmd = pci_read_config32(dev, 0x70);
+			if ((cmd & (3 << 0)) != 2) {
+				cmd &= ~(3<<0);
+				cmd |= (2<<0);
+				pci_write_config32(dev, 0x70, cmd );
+				needs_reset = 1;
+			}
+			cmd = pci_read_config32(dev, 0x7c);
+			if ((cmd & (3 << 4)) != 0) {
+				cmd &= ~(3<<4);
+				cmd |= (0<<4);
+				pci_write_config32(dev, 0x7c, cmd );
+				needs_reset = 1;
+			}
+			/* Clock Power/Timing Low */
+			cmd = pci_read_config32(dev, 0xd4);
+			if (cmd != 0x000D0001) {
+				cmd = 0x000D0001;
+				pci_write_config32(dev, 0xd4, cmd);
+				needs_reset = 1; /* Needed? */
+			}
+
+		}
+		else {
+			uint32_t cmd_ref;
+			/* Errata 98 
+			 * Set Clk Ramp Hystersis to 7
+			 * Clock Power/Timing Low
+			 */
+			cmd_ref = 0x04e20707; /* Registered */
+			cmd = pci_read_config32(dev, 0xd4);
+			if(cmd != cmd_ref) {
+				pci_write_config32(dev, 0xd4, cmd_ref );
+				needs_reset = 1; /* Needed? */
+			}
+		}
+	}
+	return needs_reset;
+}
+
+static int optimize_link_read_pointers(unsigned cpus, int needs_reset)
+{
+	unsigned node;
+	for(node = 0; node < cpus; node = node + 1) {
+		device_t f0_dev, f3_dev;
+		uint32_t cmd_ref, cmd;
+		int link;
+		f0_dev = NODE_HT(node);
+		f3_dev = NODE_MC(node);
+		cmd_ref = cmd = pci_read_config32(f3_dev, 0xdc);
+		for(link = 0; link < 3; link = link + 1) {
+			uint32_t link_type;
+			unsigned reg;
+			reg = 0x98 + (link * 0x20);
+			link_type = pci_read_config32(f0_dev, reg);
+			if (link_type & LinkConnected) {
+				cmd &= 0xff << (link *8);
+				/* FIXME this assumes the device on the other side is an AMD device */
+				cmd |= 0x25 << (link *8);
+			}
+		}
+		if (cmd != cmd_ref) {
+			pci_write_config32(f3_dev, 0xdc, cmd);
+			needs_reset = 1;
+		}
+	}
+	return needs_reset;
+}
+
 static int setup_coherent_ht_domain(void)
 {
-	unsigned cpus;
-	int reset_needed = 0;
+	struct setup_smp_result result;
+	result.cpus = 1;
+	result.needs_reset = 0;
 
 	enable_bsp_routing();
 
 #if CONFIG_MAX_CPUS == 1
-	cpus=setup_uniprocessor();
+	setup_uniprocessor();
 #else
-	cpus=setup_smp();
-	cpus=detect_mp_capabilities(cpus);
+	result = setup_smp();
+	result.cpus = verify_mp_capabilities(result.cpus);
 #endif
-	coherent_ht_finalize(cpus);
+	coherent_ht_finalize(result.cpus);
+	result.needs_reset = apply_cpu_errata_fixes(result.cpus, result.needs_reset);
+#if CONFIG_MAX_CPUS > 1 /* Why doesn't this work on the solo? */
+	result.needs_reset = optimize_link_read_pointers(result.cpus, result.needs_reset);
+#endif
 
-	/* FIXME this should probably go away again. */
-	coherent_ht_mainboard(cpus);
-	return reset_needed;
+	return result.needs_reset;
 }
diff --git a/src/northbridge/amd/amdk8/cpu_rev.c b/src/northbridge/amd/amdk8/cpu_rev.c
index 51f2359..0c4c5f8 100644
--- a/src/northbridge/amd/amdk8/cpu_rev.c
+++ b/src/northbridge/amd/amdk8/cpu_rev.c
@@ -16,10 +16,15 @@
 
 static int is_cpu_rev_a0(void)
 {
-	return (cpuid(1) & 0xffff) == 0x0f10;
+	return (cpuid(1) & 0xffef) == 0x0f00;
 }
 
 static int is_cpu_pre_c0(void)
 {
 	return (cpuid(1) & 0xffef) < 0x0f48;
 }
+
+static int is_cpu_pre_b3(void)
+{
+	return (cpuid(1) & 0xffef) < 0x0f41;
+}
diff --git a/src/northbridge/amd/amdk8/early_ht.c b/src/northbridge/amd/amdk8/early_ht.c
index 4de8fa1..90f258e 100644
--- a/src/northbridge/amd/amdk8/early_ht.c
+++ b/src/northbridge/amd/amdk8/early_ht.c
@@ -1,4 +1,4 @@
-static int enumerate_ht_chain(unsigned link)
+static int enumerate_ht_chain(void)
 {
 	/* Assumption the HT chain that is bus 0 has the HT I/O Hub on it.
 	 * On most boards this just happens.  If a cpu has multiple
@@ -49,3 +49,4 @@
 	} while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
 	return reset_needed;
 }
+
diff --git a/src/northbridge/amd/amdk8/incoherent_ht.c b/src/northbridge/amd/amdk8/incoherent_ht.c
new file mode 100644
index 0000000..711100a
--- /dev/null
+++ b/src/northbridge/amd/amdk8/incoherent_ht.c
@@ -0,0 +1,244 @@
+#include <device/pci_def.h>
+#include <device/pci_ids.h>
+#include <device/hypertransport_def.h>
+
+static unsigned ht_lookup_slave_capability(device_t dev)
+{
+	unsigned pos;
+	uint8_t hdr_type;
+
+	hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
+	pos = 0;
+	hdr_type &= 0x7f;
+
+	if ((hdr_type == PCI_HEADER_TYPE_NORMAL) ||
+		(hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
+		pos = PCI_CAPABILITY_LIST;
+	}
+	if (pos > PCI_CAP_LIST_NEXT) {
+		pos = pci_read_config8(dev, pos);
+	}
+	while(pos != 0) { /* loop through the linked list */
+		uint8_t cap;
+		cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID);
+		if (cap == PCI_CAP_ID_HT) {
+			uint16_t flags;
+
+			flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
+			if ((flags >> 13) == 0) {
+				/* Entry is a Slave secondary, success... */
+				break;
+			}
+		}
+		pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT);
+	}
+	return pos;
+}
+
+static void ht_collapse_previous_enumeration(unsigned bus)
+{
+	device_t dev;
+	
+	/* Spin through the devices and collapse any previous
+	 * hypertransport enumeration.
+	 */
+	for(dev = PCI_DEV(bus, 0, 0); dev <= PCI_DEV(bus, 0x1f, 0x7); dev += PCI_DEV(0, 1, 0)) {
+		uint32_t id;
+		unsigned pos, flags;
+		
+		id = pci_read_config32(dev, PCI_VENDOR_ID);
+		if ((id == 0xffffffff) || (id == 0x00000000) ||
+			(id == 0x0000ffff) || (id == 0xffff0000)) {
+			continue;
+		}
+		pos = ht_lookup_slave_capability(dev);
+		if (!pos) {
+			continue;
+		}
+		
+		/* Clear the unitid */
+		flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
+		flags &= ~0x1f;
+		pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags);
+	}
+}
+
+
+static unsigned ht_read_freq_cap(device_t dev, unsigned pos)
+{
+	/* Handle bugs in valid hypertransport frequency reporting */
+	unsigned freq_cap;
+	uint32_t id;
+
+	freq_cap = pci_read_config16(dev, pos);
+	freq_cap &= ~(1 << HT_FREQ_VENDOR); /* Ignore Vendor HT frequencies */
+
+	id = pci_read_config32(dev, 0);
+
+	/* AMD 8131 Errata 48 */
+	if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8131_PCIX << 16))) {
+		freq_cap &= ~(1 << HT_FREQ_800Mhz);
+	}
+	/* AMD 8151 Errata 23 */
+	if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8151_SYSCTRL << 16))) {
+		freq_cap &= ~(1 << HT_FREQ_800Mhz);
+	}
+	/* AMD K8 Unsupported 1Ghz? */
+	if (id == (PCI_VENDOR_ID_AMD | (0x1100 << 16))) {
+		freq_cap &= ~(1 << HT_FREQ_1000Mhz);
+	}
+	return freq_cap;
+}
+
+#define LINK_OFFS(WIDTH,FREQ,FREQ_CAP) \
+	(((WIDTH & 0xff) << 16) | ((FREQ & 0xff) << 8) | (FREQ_CAP & 0xFF))
+
+#define LINK_WIDTH(OFFS)    ((OFFS >> 16) & 0xFF)
+#define LINK_FREQ(OFFS)     ((OFFS >> 8) & 0xFF)
+#define LINK_FREQ_CAP(OFFS) ((OFFS) & 0xFF)
+
+#define PCI_HT_HOST_OFFS LINK_OFFS( \
+	PCI_HT_CAP_HOST_WIDTH, \
+	PCI_HT_CAP_HOST_FREQ, \
+	PCI_HT_CAP_HOST_FREQ_CAP)
+
+#define PCI_HT_SLAVE0_OFFS LINK_OFFS( \
+	PCI_HT_CAP_SLAVE_WIDTH0, \
+	PCI_HT_CAP_SLAVE_FREQ0, \
+	PCI_HT_CAP_SLAVE_FREQ_CAP0)
+
+#define PCI_HT_SLAVE1_OFFS LINK_OFFS( \
+	PCI_HT_CAP_SLAVE_WIDTH1, \
+	PCI_HT_CAP_SLAVE_FREQ1, \
+	PCI_HT_CAP_SLAVE_FREQ_CAP1)
+
+static int ht_optimize_link(
+	device_t dev1, uint8_t pos1, unsigned offs1,
+	device_t dev2, uint8_t pos2, unsigned offs2)
+{
+	static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 };
+	static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 };
+	uint16_t freq_cap1, freq_cap2, freq_cap, freq_mask;
+	uint8_t width_cap1, width_cap2, width_cap, width, old_width, ln_width1, ln_width2;
+	uint8_t freq, old_freq;
+	int needs_reset;
+	/* Set link width and frequency */
+
+	/* Initially assume everything is already optimized and I don't need a reset */
+	needs_reset = 0;
+
+	/* Get the frequency capabilities */
+	freq_cap1 = ht_read_freq_cap(dev1, pos1 + LINK_FREQ_CAP(offs1));
+	freq_cap2 = ht_read_freq_cap(dev2, pos2 + LINK_FREQ_CAP(offs2));
+
+	/* Calculate the highest possible frequency */
+	freq = log2(freq_cap1 & freq_cap2);
+
+	/* See if I am changing the link freqency */
+	old_freq = pci_read_config8(dev1, pos1 + LINK_FREQ(offs1));
+	needs_reset |= old_freq != freq;
+	old_freq = pci_read_config8(dev2, pos2 + LINK_FREQ(offs2));
+	needs_reset |= old_freq != freq;
+
+	/* Set the Calulcated link frequency */
+	pci_write_config8(dev1, pos1 + LINK_FREQ(offs1), freq);
+	pci_write_config8(dev2, pos2 + LINK_FREQ(offs2), freq);
+
+	/* Get the width capabilities */
+	width_cap1 = pci_read_config8(dev1, pos1 + LINK_WIDTH(offs1));
+	width_cap2 = pci_read_config8(dev2, pos2 + LINK_WIDTH(offs2));
+
+	/* Calculate dev1's input width */
+	ln_width1 = link_width_to_pow2[width_cap1 & 7];
+	ln_width2 = link_width_to_pow2[(width_cap2 >> 4) & 7];
+	if (ln_width1 > ln_width2) {
+		ln_width1 = ln_width2;
+	}
+	width = pow2_to_link_width[ln_width1];
+	/* Calculate dev1's output width */
+	ln_width1 = link_width_to_pow2[(width_cap1 >> 4) & 7];
+	ln_width2 = link_width_to_pow2[width_cap2 & 7];
+	if (ln_width1 > ln_width2) {
+		ln_width1 = ln_width2;
+	}
+	width |= pow2_to_link_width[ln_width1] << 4;
+
+	/* See if I am changing dev1's width */
+	old_width = pci_read_config8(dev1, pos1 + LINK_WIDTH(offs1) + 1);
+	needs_reset |= old_width != width;
+
+	/* Set dev1's widths */
+	pci_write_config8(dev1, pos1 + LINK_WIDTH(offs1) + 1, width);
+
+	/* Calculate dev2's width */
+	width = ((width & 0x70) >> 4) | ((width & 0x7) << 4);
+
+	/* See if I am changing dev2's width */
+	old_width = pci_read_config8(dev2, pos2 + LINK_WIDTH(offs2) + 1);
+	needs_reset |= old_width != width;
+
+	/* Set dev2's widths */
+	pci_write_config8(dev2, pos2 + LINK_WIDTH(offs2) + 1, width);
+
+	return needs_reset;
+}
+
+static int ht_setup_chain(device_t udev, unsigned upos)
+{
+	/* Assumption the HT chain that is bus 0 has the HT I/O Hub on it.
+	 * On most boards this just happens.  If a cpu has multiple
+	 * non Coherent links the appropriate bus registers for the
+	 * links needs to be programed to point at bus 0.
+	 */
+	unsigned next_unitid, last_unitid;
+	int reset_needed;
+	unsigned uoffs;
+
+#warning "FIXME handle multiple chains!"
+
+	/* Make certain the HT bus is not enumerated */
+	ht_collapse_previous_enumeration(0);
+
+	reset_needed = 0;
+	uoffs = PCI_HT_HOST_OFFS;
+	next_unitid = 1;
+	do {
+		uint32_t id;
+		uint8_t pos;
+		unsigned flags, count;
+		device_t dev = PCI_DEV(0, 0, 0);
+		last_unitid = next_unitid;
+
+		id = pci_read_config32(dev, PCI_VENDOR_ID);
+		/* If the chain is enumerated quit */
+		if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+			(((id >> 16) & 0xffff) == 0xffff) ||
+			(((id >> 16) & 0xffff) == 0x0000)) {
+			break;
+		}
+		pos = ht_lookup_slave_capability(dev);
+		if (!pos) {
+			print_err("HT link capability not found\r\n");
+			break;
+		}
+		/* Setup the Hypertransport link */
+		reset_needed |= ht_optimize_link(udev, upos, uoffs, dev, pos, PCI_HT_SLAVE0_OFFS);
+
+		/* Update the Unitid of the current device */
+		flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
+		flags &= ~0x1f; /* mask out the bse Unit ID */
+		flags |= next_unitid & 0x1f;
+		pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags);
+
+		/* Remeber the location of the last device */
+		udev = PCI_DEV(0, next_unitid, 0);
+		upos = pos;
+		uoffs = PCI_HT_SLAVE1_OFFS;
+
+		/* Compute the number of unitids consumed */
+		count = (flags >> 5) & 0x1f;
+		next_unitid += count;
+
+	} while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
+	return reset_needed;
+}
diff --git a/src/northbridge/amd/amdk8/misc_control.c b/src/northbridge/amd/amdk8/misc_control.c
index fe797aa..df28bd0 100644
--- a/src/northbridge/amd/amdk8/misc_control.c
+++ b/src/northbridge/amd/amdk8/misc_control.c
@@ -14,21 +14,96 @@
 #include <device/pci.h>
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
+#include <part/hard_reset.h>
 #include "./cpu_rev.c"
+#include "amdk8.h"
 
-static cpu_reset_count = 0;
+#define IOMMU_APETURE_SIZE (64*1024*1024) /* 64M */
+static void mcf3_read_resources(device_t dev)
+{
+	struct resource *resource;
+	/* Read the generic PCI resources */
+	pci_dev_read_resources(dev);
+
+	/* If we are not the first processor don't allocate the gart apeture */
+	if (dev->path.u.pci.devfn != PCI_DEVFN(24, 3)) {
+		return;
+	}
+		
+	/* Add a 64M Gart apeture resource */
+	if (dev->resources < MAX_RESOURCES) {
+		resource = &dev->resource[dev->resources];
+		dev->resources++;
+		resource->base  = 0;
+		resource->size  = IOMMU_APETURE_SIZE;
+		resource->align = log2(resource->size);
+		resource->gran  = log2(resource->size);
+		resource->limit = 0xffffffff; /* 4G */
+		resource->flags = IORESOURCE_MEM;
+		resource->index = 0x94;
+	}
+	else {
+		printk_err("%s Unexpeted resource shortage\n", dev_path(dev));
+	}
+}
+
+static void mcf3_set_resources(device_t dev)
+{
+	struct resource *resource, *last;
+	last = &dev->resource[dev->resources];
+	for(resource = &dev->resource[0]; resource < last; resource++) {
+		if (resource->index == 0x94) {
+			device_t pdev;
+			uint32_t base;
+			uint32_t size;
+			
+			size = (0<<6)|(0<<5)|(0<<4)|((log2(resource->size) - 25) << 1)|(0<<0);
+			base = ((resource->base) >> 25) & 0x00007fff;
+			
+			pdev = 0;
+			while(pdev = dev_find_device(PCI_VENDOR_ID_AMD, 0x1103, pdev)) {
+				/* I want a 64M GART apeture */
+				pci_write_config32(pdev, 0x90, (0<<6)|(0<<5)|(0<<4)|(1<<1)|(0<<0));
+				/* Store the GART base address */
+				pci_write_config32(pdev, 0x94, base);
+				/* Don't set the GART Table base address */
+				pci_write_config32(pdev, 0x98, 0);
+
+				printk_debug(
+					"%s %02x <- [0x%08lx - 0x%08lx] mem <gart>\n",
+					dev_path(pdev),
+					resource->index, 
+					resource->base, resource->base + resource->size - 1);
+			}
+			/* Remember this resource has been stored */
+			resource->flags |= IORESOURCE_STORED;
+
+		}
+	}
+	/* Set the generic PCI resources */
+	pci_dev_set_resources(dev);
+}
+
 static void misc_control_init(struct device *dev)
 {
-	uint32_t cmd;
+	uint32_t cmd, cmd_ref;
+	int needs_reset;
+	struct device *f0_dev, *f2_dev;
 	
 	printk_debug("NB: Function 3 Misc Control.. ");
-	
-	/* disable error reporting */
+	needs_reset = 0;
+
+	/* Disable Machine checks from Invalid Locations.
+	 * This is needed for PC backwards compatibility.
+	 */
 	cmd = pci_read_config32(dev, 0x44);
 	cmd |= (1<<6) | (1<<25);
 	pci_write_config32(dev, 0x44, cmd );
 	if (is_cpu_pre_c0()) {
-		/* errata 58 */
+
+		/* Errata 58
+		 * Disable CPU low power states C2, C1 and throttling 
+		 */
 		cmd = pci_read_config32(dev, 0x80);
 		cmd &= ~(1<<0);
 		pci_write_config32(dev, 0x80, cmd );
@@ -36,62 +111,86 @@
 		cmd &= ~(1<<24);
 		cmd &= ~(1<<8);
 		pci_write_config32(dev, 0x84, cmd );
-		/* errata 66 */
+
+		/* Errata 66
+		 * Limit the number of downstream posted requests to 1 
+		 */
 		cmd = pci_read_config32(dev, 0x70);
-		cmd &= ~(1<<0);
-		cmd |= (1<<1);
-		pci_write_config32(dev, 0x70, cmd );
+		if ((cmd & (3 << 0)) != 2) {
+			cmd &= ~(3<<0);
+			cmd |= (2<<0);
+			pci_write_config32(dev, 0x70, cmd );
+			needs_reset = 1;
+		}
 		cmd = pci_read_config32(dev, 0x7c);
-		cmd &= ~(3<<4);
-		pci_write_config32(dev, 0x7c, cmd );
+		if ((cmd & (3 << 4)) != 0) {
+			cmd &= ~(3<<4);
+			cmd |= (0<<4);
+			pci_write_config32(dev, 0x7c, cmd );
+			needs_reset = 1;
+		}
+		/* Clock Power/Timing Low */
+		cmd = pci_read_config32(dev, 0xd4);
+		if (cmd != 0x000D0001) {
+			cmd = 0x000D0001;
+			pci_write_config32(dev, 0xd4, cmd);
+			needs_reset = 1; /* Needed? */
+		}
 	}
 	else {
-		/* errata 98 */
-#if 0		
+		uint32_t dcl;
+		f2_dev = dev_find_slot(0, dev->path.u.pci.devfn - 3 + 2);
+		/* Errata 98 
+		 * Set Clk Ramp Hystersis to 7
+		 * Clock Power/Timing Low
+		 */
+		cmd_ref = 0x04e20707; /* Registered */
+		dcl = pci_read_config32(f2_dev, DRAM_CONFIG_LOW);
+		if (dcl & DCL_UnBufDimm) {
+			cmd_ref = 0x000D0701; /* Unbuffered */
+		}
 		cmd = pci_read_config32(dev, 0xd4);
-		if(cmd != 0x04e20707) {
-			cmd = 0x04e20707;
-			pci_write_config32(dev, 0xd4, cmd );
-			hard_reset();
+		if(cmd != cmd_ref) {
+			pci_write_config32(dev, 0xd4, cmd_ref );
+			needs_reset = 1; /* Needed? */
 		}
-#endif
-
-		cmd = 0x04e20707;
-		pci_write_config32(dev, 0xd4, cmd );
 	}
-
-/*
- * FIXME: This preprocessor check is a mere workaround. 
- * The right fix is to walk over all links on all nodes
- * and set the FIFO read pointer optimization value to
- * 0x25 for each link connected to an AMD HT device.
- *
- * The reason this is only enabled for machines with more 
- * than one CPU is that Athlon64 machines don't have the
- * link at all that is optimized in the code.
- */
-
-#if CONFIG_MAX_CPUS > 1	
-#if HAVE_HARD_RESET==1
-	cpu_reset_count++;
-	cmd = pci_read_config32(dev, 0xdc);
-	if((cmd & 0x0000ff00) != 0x02500) {
-		cmd &= 0xffff00ff;
-		cmd |= 0x00002500;
-		pci_write_config32(dev, 0xdc, cmd );
-	        if(cpu_reset_count==CONFIG_MAX_CPUS) {
-			printk_debug("resetting cpu\n");
-			hard_reset();
+	/* Optimize the Link read pointers */
+	f0_dev = dev_find_slot(0, dev->path.u.pci.devfn - 3);
+	if (f0_dev) {
+		int link;
+		cmd_ref = cmd = pci_read_config32(dev, 0xdc);
+		for(link = 0; link < 3; link++) {
+			uint32_t link_type;
+			unsigned reg;
+			/* This works on an Athlon64 because unimplemented links return 0 */
+			reg = 0x98 + (link * 0x20);
+			link_type = pci_read_config32(f0_dev, reg);
+			if (link_type & LinkConnected) {
+				cmd &= 0xff << (link *8);
+				/* FIXME this assumes the device on the other side is an AMD device */
+				cmd |= 0x25 << (link *8);
+			}
 		}
-	} 
-#endif
-#endif	
+		if (cmd != cmd_ref) {
+			pci_write_config32(dev, 0xdc, cmd);
+			needs_reset = 1;
+		}
+	}
+	else {
+		printk_err("Missing f0 device!\n");
+	}
+	if (needs_reset) {
+		printk_debug("resetting cpu\n");
+		hard_reset();
+	}
 	printk_debug("done.\n");
 }
 
+
 static struct device_operations mcf3_ops  = {
-	.read_resources   = pci_dev_read_resources,
-	.set_resources    = pci_dev_set_resources,
+	.read_resources   = mcf3_read_resources,
+	.set_resources    = mcf3_set_resources,
 	.enable_resources = pci_dev_enable_resources,
 	.init             = misc_control_init,
 	.scan_bus         = 0,
@@ -102,4 +201,3 @@
 	.vendor = PCI_VENDOR_ID_AMD,
 	.device = 0x1103,
 };
-
diff --git a/src/northbridge/amd/amdk8/northbridge.c b/src/northbridge/amd/amdk8/northbridge.c
index e62aded..12d8f73 100644
--- a/src/northbridge/amd/amdk8/northbridge.c
+++ b/src/northbridge/amd/amdk8/northbridge.c
@@ -38,7 +38,7 @@
 	mmio_basek &= ~((256*1024) - 1);
 #endif
 
-#if 1
+#if 0
 	printk_debug("mmio_base: %dKB\n", mmio_basek);
 #endif
 
@@ -383,8 +383,14 @@
 {
 	unsigned long rbase, rlimit;
 	unsigned reg, link;
+
 	/* Make certain the resource has actually been set */
-	if (!(resource->flags & IORESOURCE_SET)) {
+	if (!(resource->flags & IORESOURCE_ASSIGNED)) {
+		return;
+	}
+
+	/* If I have already stored this resource don't worry about it */
+	if (resource->flags & IORESOURCE_STORED) {
 		return;
 	}
 	
@@ -401,7 +407,7 @@
 	/* Get the register and link */
 	reg  = resource->index & ~3;
 	link = resource->index & 3;
-	
+
 	if (resource->flags & IORESOURCE_IO) {
 		uint32_t base, limit;
 		compute_allocate_resource(&dev->link[link], resource,
@@ -415,13 +421,14 @@
 		limit |= rlimit & 0x01fff000;
 		limit |= (link & 3) << 4;
 		limit |= (nodeid & 7);
-		if (reg == 0xc8){
-			/* hack to set vga for test */
-			/* factory: b0: 03 0a 00 00 00 0b 00 00 */
-			f1_write_config32(0xb0, 0xa03);
-			f1_write_config32(0xb4, 0xb00);
-			base |= 0x30;
+
+		if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
+			base |= PCI_IO_BASE_VGA_EN;
 		}
+		if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_NO_ISA) {
+			base |= PCI_IO_BASE_NO_ISA;
+		}
+		
 		f1_write_config32(reg + 0x4, limit);
 		f1_write_config32(reg, base);
 	}
@@ -441,6 +448,7 @@
 		f1_write_config32(reg + 0x4, limit);
 		f1_write_config32(reg, base);
 	}
+	resource->flags |= IORESOURCE_STORED;
 	printk_debug(
 		"%s %02x <- [0x%08lx - 0x%08lx] node %d link %d %s\n",
 		dev_path(dev),
@@ -483,51 +491,46 @@
 	return max;
 }
 
-void amdk8_enable_resources(struct device *dev)
+static void mcf0_control_init(struct device *dev)
 {
-  uint16_t ctrl;
-  unsigned link;
-  unsigned int vgalink = -1;
+	uint32_t cmd;
 
-  ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL);
-  ctrl |= dev->link[0].bridge_ctrl;
-  printk_debug("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl);
-  printk_err("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl);
-  pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl);
-
-#if 0
-  /* let's see what link VGA is on */
-  for(link = 0; link < dev->links; link++) {
-    device_t child;
-    printk_err("Kid %d of k8: bridge ctrl says: 0x%x\n", link, dev->link[link].bridge_ctrl);
-    if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA)
-	vgalink = link;
-  }
-
-  if (vgalink != =1) {
-  /* now find the IOPAIR that goes to vgalink and set the  vga enable in the base part (0x30) */
-  /* now allocate an MMIOPAIR and point it to the CPU0, LINK=vgalink */
-  /* now set IORR1 so it has a hole for the 0xa0000-0xcffff region */
-  }
+#if 1	
+	printk_debug("NB: Function 0 Misc Control.. ");
+	/* improve latency and bandwith on HT */
+	cmd = pci_read_config32(dev, 0x68);
+	cmd &= 0xffff80ff;
+	cmd |= 0x00004800;
+	pci_write_config32(dev, 0x68, cmd );
 #endif
 
-  pci_dev_enable_resources(dev);
-  //enable_childrens_resources(dev);
+#if 0	
+	/* over drive the ht port to 1000 Mhz */
+	cmd = pci_read_config32(dev, 0xa8);
+	cmd &= 0xfffff0ff;
+	cmd |= 0x00000600;
+	pci_write_config32(dev, 0xdc, cmd );
+#endif	
+	printk_debug("done.\n");
 }
 
-
-
 static struct device_operations northbridge_operations = {
 	.read_resources   = amdk8_read_resources,
 	.set_resources    = amdk8_set_resources,
-//	.enable_resources = pci_dev_enable_resources,
-        .enable_resources = amdk8_enable_resources,
-	.init             = 0,
+	.enable_resources = pci_dev_enable_resources,
+	.init             = mcf0_control_init,
 	.scan_bus         = amdk8_scan_chains,
 	.enable           = 0,
 };
 
 
+static struct pci_driver mcf0_driver __pci_driver = {
+	.ops    = &northbridge_operations,
+	.vendor = PCI_VENDOR_ID_AMD,
+	.device = 0x1100,
+};
+
+
 static void enumerate(struct chip *chip)
 {
 	chip_enumerate(chip);
@@ -538,4 +541,3 @@
 	.name   = "AMD K8 Northbridge",
 	.enumerate = enumerate,
 };
-
diff --git a/src/northbridge/amd/amdk8/raminit.c b/src/northbridge/amd/amdk8/raminit.c
index 006ab19..bc73fcb 100644
--- a/src/northbridge/amd/amdk8/raminit.c
+++ b/src/northbridge/amd/amdk8/raminit.c
@@ -1,202 +1,21 @@
 #include <cpu/k8/mtrr.h>
 #include "raminit.h"
+#include "amdk8.h"
 
-#define ENABLE_IOMMU 1
-
-/* Function 2 */
-#define DRAM_CSBASE	   0x40
-#define DRAM_CSMASK	   0x60
-#define DRAM_BANK_ADDR_MAP 0x80
-#define DRAM_TIMING_LOW	   0x88
-#define	 DTL_TCL_SHIFT	   0
-#define	 DTL_TCL_MASK	   0x7
-#define	  DTL_CL_2	   1
-#define	  DTL_CL_3	   2
-#define	  DTL_CL_2_5	   5
-#define	 DTL_TRC_SHIFT	   4
-#define	 DTL_TRC_MASK	   0xf
-#define	  DTL_TRC_BASE	   7
-#define	  DTL_TRC_MIN	   7
-#define	  DTL_TRC_MAX	   22
-#define	 DTL_TRFC_SHIFT	   8
-#define	 DTL_TRFC_MASK	   0xf
-#define	  DTL_TRFC_BASE	   9
-#define	  DTL_TRFC_MIN	   9
-#define	  DTL_TRFC_MAX	   24
-#define	 DTL_TRCD_SHIFT	   12
-#define	 DTL_TRCD_MASK	   0x7
-#define	  DTL_TRCD_BASE	   0
-#define	  DTL_TRCD_MIN	   2
-#define	  DTL_TRCD_MAX	   6
-#define	 DTL_TRRD_SHIFT	   16
-#define	 DTL_TRRD_MASK	   0x7
-#define	  DTL_TRRD_BASE	   0
-#define	  DTL_TRRD_MIN	   2
-#define	  DTL_TRRD_MAX	   4
-#define	 DTL_TRAS_SHIFT	   20
-#define	 DTL_TRAS_MASK	   0xf
-#define	  DTL_TRAS_BASE	   0
-#define	  DTL_TRAS_MIN	   5
-#define	  DTL_TRAS_MAX	   15
-#define	 DTL_TRP_SHIFT	   24
-#define	 DTL_TRP_MASK	   0x7
-#define	  DTL_TRP_BASE	   0
-#define	  DTL_TRP_MIN	   2
-#define	  DTL_TRP_MAX	   6
-#define	 DTL_TWR_SHIFT	   28
-#define	 DTL_TWR_MASK	   0x1
-#define	  DTL_TWR_BASE	   2
-#define	  DTL_TWR_MIN	   2
-#define	  DTL_TWR_MAX	   3
-#define DRAM_TIMING_HIGH   0x8c
-#define	 DTH_TWTR_SHIFT	   0
-#define	 DTH_TWTR_MASK	   0x1
-#define	  DTH_TWTR_BASE	   1
-#define	  DTH_TWTR_MIN	   1
-#define	  DTH_TWTR_MAX	   2
-#define	 DTH_TRWT_SHIFT	   4
-#define	 DTH_TRWT_MASK	   0x7
-#define	  DTH_TRWT_BASE	   1
-#define	  DTH_TRWT_MIN	   1
-#define	  DTH_TRWT_MAX	   6
-#define	 DTH_TREF_SHIFT	   8
-#define	 DTH_TREF_MASK	   0x1f
-#define	  DTH_TREF_100MHZ_4K 0x00
-#define	  DTH_TREF_133MHZ_4K 0x01
-#define	  DTH_TREF_166MHZ_4K 0x02
-#define	  DTH_TREF_200MHZ_4K 0x03
-#define	  DTH_TREF_100MHZ_8K 0x08
-#define	  DTH_TREF_133MHZ_8K 0x09
-#define	  DTH_TREF_166MHZ_8K 0x0A
-#define	  DTH_TREF_200MHZ_8K 0x0B
-#define	 DTH_TWCL_SHIFT	    20
-#define	 DTH_TWCL_MASK	    0x7
-#define	  DTH_TWCL_BASE	    1
-#define	  DTH_TWCL_MIN	    1
-#define	  DTH_TWCL_MAX	    2
-#define DRAM_CONFIG_LOW	   0x90
-#define	 DCL_DLL_Disable   (1<<0)
-#define	 DCL_D_DRV	   (1<<1)
-#define	 DCL_QFC_EN	   (1<<2)
-#define	 DCL_DisDqsHys	   (1<<3)
-#define	 DCL_DramInit	   (1<<8)
-#define	 DCL_DramEnable	   (1<<10)
-#define	 DCL_MemClrStatus  (1<<11)
-#define	 DCL_ESR	   (1<<12)
-#define	 DCL_SRS	   (1<<13)
-#define	 DCL_128BitEn	   (1<<16)
-#define	 DCL_DimmEccEn	   (1<<17)
-#define	 DCL_UnBufDimm	   (1<<18)
-#define	 DCL_32ByteEn	   (1<<19)
-#define	 DCL_x4DIMM_SHIFT  20
-#define DRAM_CONFIG_HIGH   0x94
-#define	 DCH_ASYNC_LAT_SHIFT  0
-#define	 DCH_ASYNC_LAT_MASK   0xf
-#define	  DCH_ASYNC_LAT_BASE  0
-#define	  DCH_ASYNC_LAT_MIN   0
-#define	  DCH_ASYNC_LAT_MAX   15
-#define	 DCH_RDPREAMBLE_SHIFT 8
-#define	 DCH_RDPREAMBLE_MASK  0xf
-#define	  DCH_RDPREAMBLE_BASE ((2<<1)+0) /* 2.0 ns */
-#define	  DCH_RDPREAMBLE_MIN  ((2<<1)+0) /* 2.0 ns */
-#define	  DCH_RDPREAMBLE_MAX  ((9<<1)+1) /* 9.5 ns */
-#define	 DCH_IDLE_LIMIT_SHIFT 16
-#define	 DCH_IDLE_LIMIT_MASK  0x7
-#define	  DCH_IDLE_LIMIT_0    0
-#define	  DCH_IDLE_LIMIT_4    1
-#define	  DCH_IDLE_LIMIT_8    2
-#define	  DCH_IDLE_LIMIT_16   3
-#define	  DCH_IDLE_LIMIT_32   4
-#define	  DCH_IDLE_LIMIT_64   5
-#define	  DCH_IDLE_LIMIT_128  6
-#define	  DCH_IDLE_LIMIT_256  7
-#define	 DCH_DYN_IDLE_CTR_EN (1 << 19)
-#define	 DCH_MEMCLK_SHIFT     20
-#define	 DCH_MEMCLK_MASK      0x7
-#define	  DCH_MEMCLK_100MHZ   0
-#define	  DCH_MEMCLK_133MHZ   2
-#define	  DCH_MEMCLK_166MHZ   5
-#define	  DCH_MEMCLK_200MHZ   7
-#define	 DCH_MEMCLK_VALID     (1 << 25)
-#define	 DCH_MEMCLK_EN0	      (1 << 26) 
-#define	 DCH_MEMCLK_EN1	      (1 << 27) 
-#define	 DCH_MEMCLK_EN2	      (1 << 28) 
-#define	 DCH_MEMCLK_EN3	      (1 << 29) 
-
-/* Function 3 */
-#define MCA_NB_CONFIG      0x44
-#define   MNC_ECC_EN       (1 << 22)
-#define   MNC_CHIPKILL_EN  (1 << 23)
-#define SCRUB_CONTROL	   0x58
-#define	  SCRUB_NONE	    0
-#define	  SCRUB_40ns	    1
-#define	  SCRUB_80ns	    2
-#define	  SCRUB_160ns	    3
-#define	  SCRUB_320ns	    4
-#define	  SCRUB_640ns	    5
-#define	  SCRUB_1_28us	    6
-#define	  SCRUB_2_56us	    7
-#define	  SCRUB_5_12us	    8
-#define	  SCRUB_10_2us	    9
-#define	  SCRUB_20_5us	   10
-#define	  SCRUB_41_0us	   11
-#define	  SCRUB_81_9us	   12
-#define	  SCRUB_163_8us	   13
-#define	  SCRUB_327_7us	   14
-#define	  SCRUB_655_4us	   15
-#define	  SCRUB_1_31ms	   16
-#define	  SCRUB_2_62ms	   17
-#define	  SCRUB_5_24ms	   18 
-#define	  SCRUB_10_49ms	   19
-#define	  SCRUB_20_97ms	   20
-#define	  SCRUB_42ms	   21
-#define	  SCRUB_84ms	   22
-#define	 SC_DRAM_SCRUB_RATE_SHFIT  0
-#define	 SC_DRAM_SCRUB_RATE_MASK   0x1f
-#define	 SC_L2_SCRUB_RATE_SHIFT	   8
-#define	 SC_L2_SCRUB_RATE_MASK	   0x1f
-#define	 SC_L1D_SCRUB_RATE_SHIFT   16
-#define	 SC_L1D_SCRUB_RATE_MASK	   0x1f
-#define SCRUB_ADDR_LOW	   0x5C
-#define SCRUB_ADDR_HIGH	   0x60
-#define NORTHBRIDGE_CAP	   0xE8
-#define	 NBCAP_128Bit	      0x0001
-#define	 NBCAP_MP	      0x0002
-#define	 NBCAP_BIG_MP	      0x0004
-#define	 NBCAP_ECC	      0x0004
-#define	 NBCAP_CHIPKILL_ECC   0x0010
-#define	 NBCAP_MEMCLK_SHIFT   5
-#define	 NBCAP_MEMCLK_MASK    3
-#define	 NBCAP_MEMCLK_100MHZ  3
-#define	 NBCAP_MEMCLK_133MHZ  2
-#define	 NBCAP_MEMCLK_166MHZ  1
-#define	 NBCAP_MEMCLK_200MHZ  0
-#define	 NBCAP_MEMCTRL	      0x0100
-
-
+#if (CONFIG_LB_MEM_TOPK & (CONFIG_LB_MEM_TOPK -1)) != 0
+# error "CONFIG_LB_MEM_TOPK must be a power of 2"
+#endif
 static void setup_resource_map(const unsigned int *register_values, int max)
 {
 	int i;
-
-    unsigned int amd8111_link_nr;
-
-    print_debug("setting up resource map....\r\n");
-    /*
-     * determine the HT link number the southbridge is connected to
-     * bits 8-9 of the Unit ID register
-     */
-    amd8111_link_nr = (pci_read_config32(PCI_DEV(0, 0x18, 0), 0x64) & 0x00000300) >> 8;
-    print_debug(" AMD8111 southbridge is connected to HT link ");
-    print_debug_hex32(amd8111_link_nr);
-    print_debug("\r\n");
-			
-	
-	print_debug("setting up resource map....\r\n");
+	print_debug("setting up resource map....");
+#if 0
+	print_debug("\r\n");
+#endif
 	for(i = 0; i < max; i += 3) {
 		device_t dev;
 		unsigned where;
 		unsigned long reg;
-
 #if 0
 		print_debug_hex32(register_values[i]);
 		print_debug(" <-");
@@ -208,19 +27,6 @@
 		reg = pci_read_config32(dev, where);
 		reg &= register_values[i+1];
 		reg |= register_values[i+2];
-
-        /*
-	 * set correct HT link to the southbridge
-	 * otherwise we cut of the acces to the flash we are from
-	 *
-	 */
-	if (where == 0xBC)
-	  reg |= amd8111_link_nr << 4;
-	if (where == 0xC4)
-	  reg |= amd8111_link_nr << 4;
-	if (where == 0xE0)
-	  reg |= amd8111_link_nr << 8;				
-		
 		pci_write_config32(dev, where, reg);
 #if 0
 		reg = pci_read_config32(register_values[i]);
@@ -952,29 +758,22 @@
 	 * [31: 8] Reserved
 	 */
 	PCI_ADDR(0, 0x18, 3, 0x60), 0xffffff00, 0x00000000,
-
-#if ENABLE_IOMMU != 0
-	/* BY LYH  add IOMMU 64M APERTURE */
-	PCI_ADDR(0, 0x18, 3, 0x94), 0xffff8000, 0x00000f70,
-	PCI_ADDR(0, 0x18, 3, 0x90), 0xffffff80, 0x00000002,
-	PCI_ADDR(0, 0x18, 3, 0x98), 0x0000000f, 0x00068300,
-#endif
 	};
 	int i;
 	int max;
-	print_debug("setting up CPU");
-	print_debug_hex8(ctrl->node_id);
-	print_debug(" northbridge registers\r\n");
+	print_spew("setting up CPU");
+	print_spew_hex8(ctrl->node_id);
+	print_spew(" northbridge registers\r\n");
 	max = sizeof(register_values)/sizeof(register_values[0]);
 	for(i = 0; i < max; i += 3) {
 		device_t dev;
 		unsigned where;
 		unsigned long reg;
 #if 0
-		print_debug_hex32(register_values[i]);
-		print_debug(" <-");
-		print_debug_hex32(register_values[i+2]);
-		print_debug("\r\n");
+		print_spew_hex32(register_values[i]);
+		print_spew(" <-");
+		print_spew_hex32(register_values[i+2]);
+		print_spew("\r\n");
 #endif
 		dev = (register_values[i] & ~0xff) - PCI_DEV(0, 0x18, 0) + ctrl->f0;
 		where = register_values[i] & 0xff;
@@ -990,10 +789,26 @@
 		pci_write_config32(register_values[i], reg);
 #endif
 	}
-	print_debug("done.\r\n");
+	print_spew("done.\r\n");
 }
 
 
+static void hw_enable_ecc(const struct mem_controller *ctrl)
+{
+	uint32_t dcl, nbcap;
+	nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
+	dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW);
+	dcl &= ~DCL_DimmEccEn;
+	if (nbcap & NBCAP_ECC) {
+		dcl |= DCL_DimmEccEn;
+	}
+	if (read_option(CMOS_VSTART_ECC_memory, CMOS_VLEN_ECC_memory, 1) == 0) {
+		dcl &= ~DCL_DimmEccEn;
+	}
+	pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
+	
+}
+
 static int is_dual_channel(const struct mem_controller *ctrl)
 {
 	uint32_t dcl;
@@ -1042,46 +857,60 @@
 	 * sides of an assymetric dimm.
 	 */
 	value = spd_read_byte(device, 3);	/* rows */
-	if (value < 0) goto out;
+	if (value < 0) goto hw_err;
+	if ((value & 0xf) == 0) goto val_err;
 	sz.side1 += value & 0xf;
 
 	value = spd_read_byte(device, 4);	/* columns */
-	if (value < 0) goto out;
+	if (value < 0) goto hw_err;
+	if ((value & 0xf) == 0) goto val_err;
 	sz.side1 += value & 0xf;
 
 	value = spd_read_byte(device, 17);	/* banks */
-	if (value < 0) goto out;
+	if (value < 0) goto hw_err;
+	if ((value & 0xff) == 0) goto val_err;
 	sz.side1 += log2(value & 0xff);
 
 	/* Get the module data width and convert it to a power of two */
 	value = spd_read_byte(device, 7);	/* (high byte) */
-	if (value < 0) goto out;
+	if (value < 0) goto hw_err;
 	value &= 0xff;
 	value <<= 8;
 	
 	low = spd_read_byte(device, 6);	/* (low byte) */
-	if (low < 0) goto out;
+	if (low < 0) goto hw_err;
 	value = value | (low & 0xff);
+	if ((value != 72) && (value &= 64)) goto val_err;
 	sz.side1 += log2(value);
 
 	/* side 2 */
 	value = spd_read_byte(device, 5);	/* number of physical banks */
-	if (value <= 1) goto out;
+	if (value < 0) goto hw_err;
+	if (value == 1) goto out;
+	if (value != 2) goto val_err;
 
 	/* Start with the symmetrical case */
 	sz.side2 = sz.side1;
 
 	value = spd_read_byte(device, 3);	/* rows */
-	if (value < 0) goto out;
+	if (value < 0) goto hw_err;
 	if ((value & 0xf0) == 0) goto out;	/* If symmetrical we are done */
 	sz.side2 -= (value & 0x0f);		/* Subtract out rows on side 1 */
 	sz.side2 += ((value >> 4) & 0x0f);	/* Add in rows on side 2 */
 
 	value = spd_read_byte(device, 4);	/* columns */
-	if (value < 0) goto out;
+	if (value < 0) goto hw_err;
+	if ((value & 0xff) == 0) goto val_err;
 	sz.side2 -= (value & 0x0f);		/* Subtract out columns on side 1 */
 	sz.side2 += ((value >> 4) & 0x0f);	/* Add in columsn on side 2 */
+	goto out;
 
+ val_err:
+	die("Bad SPD value\r\n");
+	/* If an hw_error occurs report that I have no memory */
+hw_err:
+	sz.side1 = 0;
+	sz.side2 = 0;
  out:
 	return sz;
 }
@@ -1091,15 +920,6 @@
 	uint32_t base0, base1, map;
 	uint32_t dch;
 
-#if 0
-	print_debug("set_dimm_size: (");
-	print_debug_hex32(sz.side1);
-	print_debug_char(',');
-	print_debug_hex32(sz.side2);
-	print_debug_char(',');
-	print_debug_hex32(index);
-	print_debug(")\r\n");
-#endif
 	if (sz.side1 != sz.side2) {
 		sz.side2 = 0;
 	}
@@ -1147,15 +967,22 @@
 	}
 }
 
-static void spd_set_ram_size(const struct mem_controller *ctrl)
+static long spd_set_ram_size(const struct mem_controller *ctrl, long dimm_mask)
 {
 	int i;
 	
-	for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+	for(i = 0; i < DIMM_SOCKETS; i++) {
 		struct dimm_size sz;
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
 		sz = spd_get_dimm_size(ctrl->channel0[i]);
+		if (sz.side1 == 0) {
+			return -1; /* Report SPD error */
+		}
 		set_dimm_size(ctrl, sz, i);
 	}
+	return dimm_mask;
 }
 
 static void route_dram_accesses(const struct mem_controller *ctrl,
@@ -1191,20 +1018,13 @@
 {
 	/* Error if I don't have memory */
 	if (!tom_k) {
-		set_bios_reset();
-		print_debug("No memory - reset");
-		/* enable cf9 */
-		pci_write_config8(PCI_DEV(0, 0x04, 3), 0x41, 0xf1);
-		/* reset */
-		outb(0x0e, 0x0cf9);
+		die("No memory?");
 	}
 
-#if 1
 	/* Report the amount of memory. */
-	print_debug("RAM: 0x");
-	print_debug_hex32(tom_k);
-	print_debug(" KB\r\n");
-#endif
+	print_spew("RAM: 0x");
+	print_spew_hex32(tom_k);
+	print_spew(" KB\r\n");
 
 	/* Now set top of memory */
 	msr_t msr;
@@ -1238,7 +1058,6 @@
 	uint32_t csbase_inc;
 	int chip_selects, index;
 	int bits;
-	int dual_channel;
 	unsigned common_size;
 	uint32_t csbase, csmask;
 
@@ -1306,9 +1125,8 @@
 		csbase += csbase_inc;
 	}
 	
-#if 1
-	print_debug("Interleaved\r\n");
-#endif	
+	print_spew("Interleaved\r\n");
+
 	/* Return the memory size in K */
 	return common_size << (15 + bits);
 }
@@ -1368,7 +1186,6 @@
 		/* Compute the memory mask */
 		csmask = ((size -1) << 21);
 		csmask |= 0xfe00;		/* For now don't optimize */
-#warning "Don't forget to optimize the DIMM size"
 
 		/* Write the new base register */
 		pci_write_config32(ctrl->f2, DRAM_CSBASE + (canidate << 2), csbase);
@@ -1380,18 +1197,13 @@
 	return (tom & ~0xff000000) << 15;
 }
 
-static void order_dimms(const struct mem_controller *ctrl)
+unsigned long memory_end_k(const struct mem_controller *ctrl, int max_node_id)
 {
-	unsigned long tom, tom_k, base_k;
 	unsigned node_id;
-
-	tom_k = interleave_chip_selects(ctrl);
-	if (!tom_k) {
-		tom_k = order_chip_selects(ctrl);
-	}
-	/* Compute the memory base address */
-	base_k = 0;
-	for(node_id = 0; node_id < ctrl->node_id; node_id++) {
+	unsigned end_k;
+	/* Find the last memory address used */
+	end_k = 0;
+	for(node_id = 0; node_id < max_node_id; node_id++) {
 		uint32_t limit, base;
 		unsigned index;
 		index = node_id << 3;
@@ -1399,32 +1211,44 @@
 		/* Only look at the limit if the base is enabled */
 		if ((base & 3) == 3) {
 			limit = pci_read_config32(ctrl->f1, 0x44 + index);
-			base_k = ((limit + 0x00010000) & 0xffff0000) >> 2;
+			end_k = ((limit + 0x00010000) & 0xffff0000) >> 2;
 		}
 	}
+	return end_k;
+}
+
+static void order_dimms(const struct mem_controller *ctrl)
+{
+	unsigned long tom_k, base_k;
+
+	if (read_option(CMOS_VSTART_interleave_chip_selects, CMOS_VLEN_interleave_chip_selects, 1) != 0) {
+		tom_k = interleave_chip_selects(ctrl);
+	} else {
+		print_debug("Interleaving disabled\r\n");
+		tom_k = 0;
+	}
+	if (!tom_k) {
+		tom_k = order_chip_selects(ctrl);
+	}
+	/* Compute the memory base address */
+	base_k = memory_end_k(ctrl, ctrl->node_id);
 	tom_k += base_k;
-#if 0
-	print_debug("base_k: ");
-	print_debug_hex32(base_k);
-	print_debug(" tom_k: ");
-	print_debug_hex32(tom_k);
-	print_debug("\r\n");
-#endif
 	route_dram_accesses(ctrl, base_k, tom_k);
 	set_top_mem(tom_k);
 }
 
-static void disable_dimm(const struct mem_controller *ctrl, unsigned index)
+static long disable_dimm(const struct mem_controller *ctrl, unsigned index, long dimm_mask)
 {
 	print_debug("disabling dimm"); 
 	print_debug_hex8(index); 
 	print_debug("\r\n");
 	pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+0)<<2), 0);
 	pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+1)<<2), 0);
+	dimm_mask &= ~(1 << index);
+	return dimm_mask;
 }
 
-
-static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl)
+static long spd_handle_unbuffered_dimms(const struct mem_controller *ctrl, long dimm_mask)
 {
 	int i;
 	int registered;
@@ -1432,12 +1256,14 @@
 	uint32_t dcl;
 	unbuffered = 0;
 	registered = 0;
-	for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+	for(i = 0; (i < DIMM_SOCKETS); i++) {
 		int value;
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
 		value = spd_read_byte(ctrl->channel0[i], 21);
 		if (value < 0) {
-			disable_dimm(ctrl, i);
-			continue;
+			return -1;
 		}
 		/* Registered dimm ? */
 		if (value & (1 << 1)) {
@@ -1468,15 +1294,40 @@
 		print_debug("Unbuffered\r\n");
 	}
 #endif
+	return dimm_mask;
 }
 
-static void spd_enable_2channels(const struct mem_controller *ctrl)
+static unsigned int spd_detect_dimms(const struct mem_controller *ctrl)
+{
+	unsigned dimm_mask;
+	int i;
+	dimm_mask = 0;
+	for(i = 0; i < DIMM_SOCKETS; i++) {
+		int byte;
+		unsigned device;
+		device = ctrl->channel0[i];
+		if (device) {
+			byte = spd_read_byte(ctrl->channel0[i], 2);  /* Type */
+			if (byte == 7) {
+				dimm_mask |= (1 << i);
+			}
+		}
+		device = ctrl->channel1[i];
+		if (device) {
+			byte = spd_read_byte(ctrl->channel1[i], 2);
+			if (byte == 7) {
+				dimm_mask |= (1 << (i + DIMM_SOCKETS));
+			}
+		}
+	}
+	return dimm_mask;
+}
+
+static long spd_enable_2channels(const struct mem_controller *ctrl, long dimm_mask)
 {
 	int i;
 	uint32_t nbcap;
 	/* SPD addresses to verify are identical */
-#warning "FINISHME review and see if these are the bytes I need"
-	/* FINISHME review and see if these are the bytes I need */
 	static const unsigned addresses[] = {
 		2,	/* Type should be DDR SDRAM */
 		3,	/* *Row addresses */
@@ -1499,40 +1350,52 @@
 		41,	/* *Minimum Active to Active/Auto Refresh Time(Trc) */
 		42,	/* *Minimum Auto Refresh Command Time(Trfc) */
 	};
+	/* If the dimms are not in pairs do not do dual channels */
+	if ((dimm_mask & ((1 << DIMM_SOCKETS) - 1)) !=
+		((dimm_mask >> DIMM_SOCKETS) & ((1 << DIMM_SOCKETS) - 1))) { 
+		goto single_channel;
+	}
+	/* If the cpu is not capable of doing dual channels don't do dual channels */
 	nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
 	if (!(nbcap & NBCAP_128Bit)) {
-		return;
+		goto single_channel;
 	}
 	for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
 		unsigned device0, device1;
 		int value0, value1;
 		int j;
+		/* If I don't have a dimm skip this one */
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
 		device0 = ctrl->channel0[i];
 		device1 = ctrl->channel1[i];
-		if (!device1)
-			return;
 		for(j = 0; j < sizeof(addresses)/sizeof(addresses[0]); j++) {
 			unsigned addr;
 			addr = addresses[j];
 			value0 = spd_read_byte(device0, addr);
 			if (value0 < 0) {
-				break;
+				return -1;
 			}
 			value1 = spd_read_byte(device1, addr);
 			if (value1 < 0) {
-				return;
+				return -1;
 			}
 			if (value0 != value1) {
-				return;
+				goto single_channel;
 			}
 		}
 	}
-	print_debug("Enabling dual channel memory\r\n");
+	print_spew("Enabling dual channel memory\r\n");
 	uint32_t dcl;
 	dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW);
 	dcl &= ~DCL_32ByteEn;
 	dcl |= DCL_128BitEn;
 	pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
+	return dimm_mask;
+ single_channel:
+	dimm_mask &= ~((1 << (DIMM_SOCKETS *2)) - (1 << DIMM_SOCKETS));
+	return dimm_mask;
 }
 
 struct mem_param {
@@ -1606,17 +1469,22 @@
 	if (!param->cycle_time) {
 		die("min_cycle_time to low");
 	}
-#if 1
+	print_spew(param->name);
+#ifdef DRAM_MIN_CYCLE_TIME
 	print_debug(param->name);
 #endif
 	return param;
 }
 
-static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl)
+struct spd_set_memclk_result {
+	const struct mem_param *param;
+	long dimm_mask;
+};
+static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *ctrl, long dimm_mask)
 {
 	/* Compute the minimum cycle time for these dimms */
-	const struct mem_param *param;
-	unsigned min_cycle_time, min_latency;
+	struct spd_set_memclk_result result;
+	unsigned min_cycle_time, min_latency, bios_cycle_time;
 	int i;
 	uint32_t value;
 
@@ -1631,25 +1499,26 @@
 
 	value = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
 	min_cycle_time = min_cycle_times[(value >> NBCAP_MEMCLK_SHIFT) & NBCAP_MEMCLK_MASK];
+	bios_cycle_time = min_cycle_times[
+		read_option(CMOS_VSTART_max_mem_clock, CMOS_VLEN_max_mem_clock, 0)];
+	if (bios_cycle_time > min_cycle_time) {
+		min_cycle_time = bios_cycle_time;
+	}
 	min_latency = 2;
 
-#if 0
-	print_debug("min_cycle_time: "); 
-	print_debug_hex8(min_cycle_time); 
-	print_debug(" min_latency: ");
-	print_debug_hex8(min_latency);
-	print_debug("\r\n");
-#endif
-
 	/* Compute the least latency with the fastest clock supported
 	 * by both the memory controller and the dimms.
 	 */
-	for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+	for(i = 0; i < DIMM_SOCKETS; i++) {
 		int new_cycle_time, new_latency;
 		int index;
 		int latencies;
 		int latency;
 
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
+
 		/* First find the supported CAS latencies
 		 * Byte 18 for DDR SDRAM is interpreted:
 		 * bit 0 == CAS Latency = 1.0
@@ -1679,7 +1548,7 @@
 			}
 			value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]);
 			if (value < 0) {
-				continue;
+				goto hw_error;
 			}
 
 			/* Only increase the latency if we decreas the clock */
@@ -1699,15 +1568,6 @@
 		if (new_latency > min_latency) {
 			min_latency = new_latency;
 		}
-#if 0
-		print_debug("i: ");
-		print_debug_hex8(i);
-		print_debug(" min_cycle_time: "); 
-		print_debug_hex8(min_cycle_time); 
-		print_debug(" min_latency: ");
-		print_debug_hex8(min_latency);
-		print_debug("\r\n");
-#endif
 	}
 	/* Make a second pass through the dimms and disable
 	 * any that cannot support the selected memclk and cas latency.
@@ -1718,9 +1578,12 @@
 		int latency;
 		int index;
 		int value;
-		int dimm;
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
 		latencies = spd_read_byte(ctrl->channel0[i], 18);
-		if (latencies <= 0) {
+		if (latencies < 0) goto hw_error;
+		if (latencies == 0) {
 			goto dimm_err;
 		}
 
@@ -1742,6 +1605,7 @@
 		
 		/* Read the min_cycle_time for this latency */
 		value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]);
+		if (value < 0) goto hw_error;
 		
 		/* All is good if the selected clock speed 
 		 * is what I need or slower.
@@ -1751,22 +1615,15 @@
 		}
 		/* Otherwise I have an error, disable the dimm */
 	dimm_err:
-		disable_dimm(ctrl, i);
+		dimm_mask = disable_dimm(ctrl, i, dimm_mask);
 	}
-#if 0
-	print_debug("min_cycle_time: "); 
-	print_debug_hex8(min_cycle_time); 
-	print_debug(" min_latency: ");
-	print_debug_hex8(min_latency);
-	print_debug("\r\n");
-#endif
 	/* Now that I know the minimum cycle time lookup the memory parameters */
-	param = get_mem_param(min_cycle_time);
+	result.param = get_mem_param(min_cycle_time);
 
 	/* Update DRAM Config High with our selected memory speed */
 	value = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH);
 	value &= ~(DCH_MEMCLK_MASK << DCH_MEMCLK_SHIFT);
-	value |= param->dch_memclk;
+	value |= result.param->dch_memclk;
 	pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, value);
 
 	static const unsigned latencies[] = { DTL_CL_2, DTL_CL_2_5, DTL_CL_3 };
@@ -1776,7 +1633,12 @@
 	value |= latencies[min_latency - 2] << DTL_TCL_SHIFT;
 	pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, value);
 	
-	return param;
+	result.dimm_mask = dimm_mask;
+	return result;
+ hw_error:
+	result.param = (const struct mem_param *)0;
+	result.dimm_mask = -1;
+	return result;
 }
 
 
@@ -1795,7 +1657,7 @@
 		clocks = DTL_TRC_MIN;
 	}
 	if (clocks > DTL_TRC_MAX) {
-		return -1;
+		return 0;
 	}
 
 	dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
@@ -1806,7 +1668,7 @@
 	dtl &= ~(DTL_TRC_MASK << DTL_TRC_SHIFT);
 	dtl |=	((clocks - DTL_TRC_BASE) << DTL_TRC_SHIFT);
 	pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
-	return 0;
+	return 1;
 }
 
 static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_param *param, int i)
@@ -1824,7 +1686,7 @@
 		clocks = DTL_TRFC_MIN;
 	}
 	if (clocks > DTL_TRFC_MAX) {
-		return -1;
+		return 0;
 	}
 	dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
 	old_clocks = ((dtl >> DTL_TRFC_SHIFT) & DTL_TRFC_MASK) + DTL_TRFC_BASE;
@@ -1834,7 +1696,7 @@
 	dtl &= ~(DTL_TRFC_MASK << DTL_TRFC_SHIFT);
 	dtl |= ((clocks - DTL_TRFC_BASE) << DTL_TRFC_SHIFT);
 	pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
-	return 0;
+	return 1;
 }
 
 
@@ -1845,16 +1707,12 @@
 	int value;
 	value = spd_read_byte(ctrl->channel0[i], 29);
 	if (value < 0) return -1;
-#if 0
 	clocks = (value + (param->divisor << 1) -1)/(param->divisor << 1);
-#else
-	clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1);
-#endif
 	if (clocks < DTL_TRCD_MIN) {
 		clocks = DTL_TRCD_MIN;
 	}
 	if (clocks > DTL_TRCD_MAX) {
-		return -1;
+		return 0;
 	}
 	dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
 	old_clocks = ((dtl >> DTL_TRCD_SHIFT) & DTL_TRCD_MASK) + DTL_TRCD_BASE;
@@ -1864,7 +1722,7 @@
 	dtl &= ~(DTL_TRCD_MASK << DTL_TRCD_SHIFT);
 	dtl |= ((clocks - DTL_TRCD_BASE) << DTL_TRCD_SHIFT);
 	pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
-	return 0;
+	return 1;
 }
 
 static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_param *param, int i)
@@ -1874,12 +1732,12 @@
 	int value;
 	value = spd_read_byte(ctrl->channel0[i], 28);
 	if (value < 0) return -1;
-	clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1);
+	clocks = (value + (param->divisor << 1) -1)/(param->divisor << 1);
 	if (clocks < DTL_TRRD_MIN) {
 		clocks = DTL_TRRD_MIN;
 	}
 	if (clocks > DTL_TRRD_MAX) {
-		return -1;
+		return 0;
 	}
 	dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
 	old_clocks = ((dtl >> DTL_TRRD_SHIFT) & DTL_TRRD_MASK) + DTL_TRRD_BASE;
@@ -1889,7 +1747,7 @@
 	dtl &= ~(DTL_TRRD_MASK << DTL_TRRD_SHIFT);
 	dtl |= ((clocks - DTL_TRRD_BASE) << DTL_TRRD_SHIFT);
 	pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
-	return 0;
+	return 1;
 }
 
 static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_param *param, int i)
@@ -1904,7 +1762,7 @@
 		clocks = DTL_TRAS_MIN;
 	}
 	if (clocks > DTL_TRAS_MAX) {
-		return -1;
+		return 0;
 	}
 	dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
 	old_clocks = ((dtl >> DTL_TRAS_SHIFT) & DTL_TRAS_MASK) + DTL_TRAS_BASE;
@@ -1914,7 +1772,7 @@
 	dtl &= ~(DTL_TRAS_MASK << DTL_TRAS_SHIFT);
 	dtl |= ((clocks - DTL_TRAS_BASE) << DTL_TRAS_SHIFT);
 	pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
-	return 0;
+	return 1;
 }
 
 static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_param *param, int i)
@@ -1924,25 +1782,12 @@
 	int value;
 	value = spd_read_byte(ctrl->channel0[i], 27);
 	if (value < 0) return -1;
-#if 0
 	clocks = (value + (param->divisor << 1) - 1)/(param->divisor << 1);
-#else
-	clocks = (value + ((param->divisor & 0xff) << 1) - 1)/((param->divisor & 0xff) << 1);
-#endif
-#if 0
-	print_debug("Trp: ");
-	print_debug_hex8(clocks);
-	print_debug(" spd value: ");
-	print_debug_hex8(value);
-	print_debug(" divisor: ");
-	print_debug_hex8(param->divisor);
-	print_debug("\r\n");
-#endif
 	if (clocks < DTL_TRP_MIN) {
 		clocks = DTL_TRP_MIN;
 	}
 	if (clocks > DTL_TRP_MAX) {
-		return -1;
+		return 0;
 	}
 	dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
 	old_clocks = ((dtl >> DTL_TRP_SHIFT) & DTL_TRP_MASK) + DTL_TRP_BASE;
@@ -1952,7 +1797,7 @@
 	dtl &= ~(DTL_TRP_MASK << DTL_TRP_SHIFT);
 	dtl |= ((clocks - DTL_TRP_BASE) << DTL_TRP_SHIFT);
 	pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
-	return 0;
+	return 1;
 }
 
 static void set_Twr(const struct mem_controller *ctrl, const struct mem_param *param)
@@ -1998,7 +1843,7 @@
 	dth &= ~(DTH_TREF_MASK << DTH_TREF_SHIFT);
 	dth |= (tref << DTH_TREF_SHIFT);
 	pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth);
-	return 0;
+	return 1;
 }
 
 
@@ -2019,7 +1864,7 @@
 		dcl |= (1 << dimm);
 	}
 	pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
-	return 0;
+	return 1;
 }
 
 static int update_dimm_ecc(const struct mem_controller *ctrl, const struct mem_param *param, int i)
@@ -2035,7 +1880,7 @@
 		dcl &= ~DCL_DimmEccEn;
 		pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
 	}
-	return 0;
+	return 1;
 }
 
 static int count_dimms(const struct mem_controller *ctrl)
@@ -2045,7 +1890,7 @@
 	dimms = 0;
 	for(index = 0; index < 8; index += 2) {
 		uint32_t csbase;
-		csbase = pci_read_config32(ctrl->f2, (DRAM_CSBASE + index << 2));
+		csbase = pci_read_config32(ctrl->f2, (DRAM_CSBASE + (index << 2)));
 		if (csbase & 1) {
 			dimms += 1;
 		}
@@ -2126,7 +1971,7 @@
 		}
 	}
 	if ((clocks < DTH_TRWT_MIN) || (clocks > DTH_TRWT_MAX)) {
-		die("Unknown Trwt");
+		die("Unknown Trwt\r\n");
 	}
 	
 	dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH);
@@ -2240,7 +2085,6 @@
 static void set_max_async_latency(const struct mem_controller *ctrl, const struct mem_param *param)
 {
 	uint32_t dch;
-	int i;
 	unsigned async_lat;
 	int dimms;
 
@@ -2287,33 +2131,37 @@
 	pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch);
 }
 
-static void spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param)
+static long spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param, long dimm_mask)
 {
-	int dimms;
 	int i;
-	int rc;
 	
 	init_Tref(ctrl, param);
-	for(i = 0; (i < 4) && ctrl->channel0[i]; i++) {
+	for(i = 0; i < DIMM_SOCKETS; i++) {
 		int rc;
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
 		/* DRAM Timing Low Register */
-		if (update_dimm_Trc (ctrl, param, i) < 0) goto dimm_err;
-		if (update_dimm_Trfc(ctrl, param, i) < 0) goto dimm_err;
-		if (update_dimm_Trcd(ctrl, param, i) < 0) goto dimm_err;
-		if (update_dimm_Trrd(ctrl, param, i) < 0) goto dimm_err;
-		if (update_dimm_Tras(ctrl, param, i) < 0) goto dimm_err;
-		if (update_dimm_Trp (ctrl, param, i) < 0) goto dimm_err;
+		if ((rc = update_dimm_Trc (ctrl, param, i)) <= 0) goto dimm_err;
+		if ((rc = update_dimm_Trfc(ctrl, param, i)) <= 0) goto dimm_err;
+		if ((rc = update_dimm_Trcd(ctrl, param, i)) <= 0) goto dimm_err;
+		if ((rc = update_dimm_Trrd(ctrl, param, i)) <= 0) goto dimm_err;
+		if ((rc = update_dimm_Tras(ctrl, param, i)) <= 0) goto dimm_err;
+		if ((rc = update_dimm_Trp (ctrl, param, i)) <= 0) goto dimm_err;
 
 		/* DRAM Timing High Register */
-		if (update_dimm_Tref(ctrl, param, i) < 0) goto dimm_err;
+		if ((rc = update_dimm_Tref(ctrl, param, i)) <= 0) goto dimm_err;
+	
 
 		/* DRAM Config Low */
-		if (update_dimm_x4 (ctrl, param, i) < 0) goto dimm_err;
-		if (update_dimm_ecc(ctrl, param, i) < 0) goto dimm_err;
+		if ((rc = update_dimm_x4 (ctrl, param, i)) <= 0) goto dimm_err;
+		if ((rc = update_dimm_ecc(ctrl, param, i)) <= 0) goto dimm_err;
 		continue;
 	dimm_err:
-		disable_dimm(ctrl, i);
-		
+		if (rc < 0) {
+			return -1;
+		}
+		dimm_mask = disable_dimm(ctrl, i, dimm_mask);
 	}
 	/* DRAM Timing Low Register */
 	set_Twr(ctrl, param);
@@ -2327,18 +2175,45 @@
 	set_read_preamble(ctrl, param);
 	set_max_async_latency(ctrl, param);
 	set_idle_cycle_limit(ctrl, param);
+	return dimm_mask;
 }
 
 static void sdram_set_spd_registers(const struct mem_controller *ctrl) 
 {
+	struct spd_set_memclk_result result;
 	const struct mem_param *param;
+	long dimm_mask;
+	hw_enable_ecc(ctrl);
 	activate_spd_rom(ctrl);
-	spd_enable_2channels(ctrl);
-	spd_set_ram_size(ctrl);
-	spd_handle_unbuffered_dimms(ctrl);
-	param = spd_set_memclk(ctrl);
-	spd_set_dram_timing(ctrl, param);
+	dimm_mask = spd_detect_dimms(ctrl);
+	if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) {
+		print_debug("No memory for this cpu\r\n");
+		return;
+	}
+	dimm_mask = spd_enable_2channels(ctrl, dimm_mask);        
+	if (dimm_mask < 0) 
+		goto hw_spd_err;
+	dimm_mask = spd_set_ram_size(ctrl , dimm_mask);           
+	if (dimm_mask < 0) 
+		goto hw_spd_err;
+	dimm_mask = spd_handle_unbuffered_dimms(ctrl, dimm_mask); 
+	if (dimm_mask < 0) 
+		goto hw_spd_err;
+	result = spd_set_memclk(ctrl, dimm_mask);
+	param     = result.param;
+	dimm_mask = result.dimm_mask;
+	if (dimm_mask < 0) 
+		goto hw_spd_err;
+	dimm_mask = spd_set_dram_timing(ctrl, param , dimm_mask);
+	if (dimm_mask < 0)
+		goto hw_spd_err;
 	order_dimms(ctrl);
+	return;
+ hw_spd_err:
+	/* Unrecoverable error reading SPD data */
+	print_err("SPD error - reset\r\n");
+	hard_reset();
+	return;
 }
 
 #define TIMEOUT_LOOPS 300000
@@ -2346,29 +2221,44 @@
 {
 	int i;
 
+	/* Error if I don't have memory */
+	if (memory_end_k(ctrl, controllers) == 0) {
+		die("No memory\r\n");
+	}
+
 	/* Before enabling memory start the memory clocks */
 	for(i = 0; i < controllers; i++) {
 		uint32_t dch;
 		dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH);
-		dch |= DCH_MEMCLK_VALID;
-		pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH, dch);
+		if (dch & (DCH_MEMCLK_EN0|DCH_MEMCLK_EN1|DCH_MEMCLK_EN2|DCH_MEMCLK_EN3)) {
+			dch |= DCH_MEMCLK_VALID;
+			pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH, dch);
+		}
+		else {
+			/* Disable dram receivers */
+			uint32_t dcl;
+			dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
+			dcl |= DCL_DisInRcvrs;
+			pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl);
+		}
 	}
 
 	/* And if necessary toggle the the reset on the dimms by hand */
 	memreset(controllers, ctrl);
 
 	for(i = 0; i < controllers; i++) {
-		uint32_t dcl;
+		uint32_t dcl, dch;
+		/* Skip everything if I don't have any memory on this controller */
+		dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH);
+		if (!(dch & DCH_MEMCLK_VALID)) {
+			continue;
+		}
+
 		/* Toggle DisDqsHys to get it working */
 		dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
-#if 0
-		print_debug("dcl: ");
-		print_debug_hex32(dcl);
-		print_debug("\r\n");
-#endif
 		if (dcl & DCL_DimmEccEn) {
 			uint32_t mnc;
-			print_debug("ECC enabled\r\n");
+			print_spew("ECC enabled\r\n");
 			mnc = pci_read_config32(ctrl[i].f3, MCA_NB_CONFIG);
 			mnc |= MNC_ECC_EN;
 			if (dcl & DCL_128BitEn) {
@@ -2387,7 +2277,13 @@
 
 	}
 	for(i = 0; i < controllers; i++) {
-		uint32_t dcl;
+		uint32_t dcl, dch;
+		/* Skip everything if I don't have any memory on this controller */
+		dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH);
+		if (!(dch & DCH_MEMCLK_VALID)) {
+			continue;
+		}
+
 		print_debug("Initializing memory: ");
 		int loops = 0;
 		do {
@@ -2399,151 +2295,98 @@
 		} while(((dcl & DCL_DramInit) != 0) && (loops < TIMEOUT_LOOPS));
 		if (loops >= TIMEOUT_LOOPS) {
 			print_debug(" failed\r\n");
-		} else {
-			print_debug(" done\r\n");
+			continue;
 		}
-		if (dcl & DCL_DimmEccEn) {
-			print_debug("Clearing memory: ");
-			if (!is_cpu_pre_c0()) {
-				/* Wait until the automatic ram scrubber is finished */
-				dcl &= ~(DCL_MemClrStatus | DCL_DramEnable);
-				pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl);
-				do {
-					dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
-				} while(((dcl & DCL_MemClrStatus) == 0) || ((dcl & DCL_DramEnable) == 0) );
-			}
-			uint32_t base, last_scrub_k, scrub_k;
-			uint32_t cnt,zstart,zend;
-			msr_t msr,msr_201;
-
-			/* First make certain the scrubber is disabled */
-			pci_write_config32(ctrl[i].f3, SCRUB_CONTROL,
-				(SCRUB_NONE << 16) | (SCRUB_NONE << 8) | (SCRUB_NONE << 0));
-
-			/* load the start and end for the memory block to clear */
-			msr_201 = rdmsr(0x201);
-			zstart = pci_read_config32(ctrl[0].f1, 0x40 + (i*8));
-			zend = pci_read_config32(ctrl[0].f1, 0x44 + (i*8));
-			zstart >>= 16;
-			zend >>=16;
-#if 1
-			print_debug("addr ");
-			print_debug_hex32(zstart);
-			print_debug("-");
-			print_debug_hex32(zend);
-			print_debug("\r\n");
-#endif
-			
-			/* Disable fixed mtrrs */
-			msr = rdmsr(MTRRdefType_MSR);
-			msr.lo &= ~(1<<10);
-			wrmsr(MTRRdefType_MSR, msr);
-
-			/* turn on the wrap 32 disable */
-			msr = rdmsr(0xc0010015);
-			msr.lo |= (1<<17);
-			wrmsr(0xc0010015,msr);
-
-			for(;zstart<zend;zstart+=4) {
-
-				/* test for the last 64 meg of 4 gig space */
-				if(zstart == 0x0fc)
-					continue;
-				
-				/* disable cache */
-				__asm__ volatile(
-					"movl  %%cr0, %0\n\t"
-					"orl  $0x40000000, %0\n\t"
-					"movl  %0, %%cr0\n\t"
-					:"=r" (cnt)
-					);
-				
-				/* Set the variable mtrrs to write combine */
-				msr.lo = 1 + ((zstart&0x0ff)<<24);
-				msr.hi = (zstart&0x0ff00)>>8;
-				wrmsr(0x200,msr);
-
-				/* Set the limit to 64 meg of ram */
-				msr.hi = 0x000000ff;
-				msr.lo = 0xfc000800;
-				wrmsr(0x201,msr);
-
-				/* enable cache */
-				__asm__ volatile(
-					"movl  %%cr0, %0\n\t"
-					"andl  $0x9fffffff, %0\n\t"
-					"movl  %0, %%cr0\n\t"	
-					:"=r" (cnt)	
-					);
-				/* Set fs base address */
-				msr.lo = (zstart&0xff) << 24;
-				msr.hi = (zstart&0xff00) >> 8;
-				wrmsr(0xc0000100,msr);
-
-				print_debug_char((zstart > 0x0ff)?'+':'-');	
-					
-				/* clear memory 64meg */
-				__asm__ volatile(
-					"1: \n\t"
-					"movl %0, %%fs:(%1)\n\t"
-					"addl $4,%1\n\t"
-					"subl $1,%2\n\t"
-					"jnz 1b\n\t"
-					:
-					: "a" (0), "D" (0), "c" (0x01000000)
-					);			
-			}
-			
-			/* disable cache */
-			__asm__ volatile(
-				"movl  %%cr0, %0\n\t"
-				"orl  $0x40000000, %0\n\t"
-				"movl  %0, %%cr0\n\t"
-				:"=r" (cnt)	
-				);
-		
-			/* restore msr registers */	
-			msr = rdmsr(MTRRdefType_MSR);
-			msr.lo |= 0x0400;
-			wrmsr(MTRRdefType_MSR, msr);
-
-			/* Restore the variable mtrrs */
-			msr.lo = 6;
-			msr.hi = 0;
-			wrmsr(0x200,msr);
-			wrmsr(0x201,msr_201);
-
-			/* Set fs base to 0 */
-			msr.lo = 0;
-			msr.hi = 0;
-			wrmsr(0xc0000100,msr);
-
-			/* enable cache */
-			__asm__ volatile(
-				"movl  %%cr0, %0\n\t"
-				"andl  $0x9fffffff, %0\n\t"
-				"movl  %0, %%cr0\n\t"	
-				:"=r" (cnt)	
-				);
-			
-			/* turn off the wrap 32 disable */
-			msr = rdmsr(0xc0010015);
-			msr.lo &= ~(1<<17);
-			wrmsr(0xc0010015,msr);
-
-			/* Find the Srub base address for this cpu */
-			base = pci_read_config32(ctrl[i].f1, 0x40 + (ctrl[i].node_id << 3));
-			base &= 0xffff0000;
-
-			/* Set the scrub base address registers */
-			pci_write_config32(ctrl[i].f3, SCRUB_ADDR_LOW, base << 8);
-			pci_write_config32(ctrl[i].f3, SCRUB_ADDR_HIGH, base >> 24);
-
-			/* Enable scrubbing at the lowest possible rate */
-			pci_write_config32(ctrl[i].f3, SCRUB_CONTROL, 
-				(SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_84ms << 0));
-
-			print_debug("done\r\n");
+		if (!is_cpu_pre_c0()) {
+			/* Wait until it is safe to touch memory */
+			dcl &= ~(DCL_MemClrStatus | DCL_DramEnable);
+			pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl);
+			do {
+				dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
+			} while(((dcl & DCL_MemClrStatus) == 0) || ((dcl & DCL_DramEnable) == 0) );
 		}
+		print_debug(" done\r\n");
 	}
+
+	/* Make certain the first 1M of memory is intialized */
+	msr_t msr, msr_201;
+	uint32_t cnt;
+	
+	/* Save the value of msr_201 */
+	msr_201 = rdmsr(0x201);
+	
+	print_debug("Clearing LinuxBIOS memory: ");
+	
+	/* disable cache */
+	__asm__ volatile(
+		"movl  %%cr0, %0\n\t"
+		"orl  $0x40000000, %0\n\t"
+		"movl  %0, %%cr0\n\t"
+		:"=r" (cnt)
+		);
+	
+	/* Disable fixed mtrrs */
+	msr = rdmsr(MTRRdefType_MSR);
+	msr.lo &= ~(1<<10);
+	wrmsr(MTRRdefType_MSR, msr);
+	
+	
+	/* Set the variable mtrrs to write combine */
+	msr.hi = 0;
+	msr.lo = 0 | MTRR_TYPE_WRCOMB;
+	wrmsr(0x200, msr);
+	
+	/* Set the limit to 1M of ram */
+	msr.hi = 0x000000ff;
+	msr.lo = (~((CONFIG_LB_MEM_TOPK << 10) - 1)) | 0x800;
+	wrmsr(0x201, msr);
+	
+	/* enable cache */
+	__asm__ volatile(
+		"movl  %%cr0, %0\n\t"
+		"andl  $0x9fffffff, %0\n\t"
+		"movl  %0, %%cr0\n\t"	
+		:"=r" (cnt)	
+		);
+	
+	/* clear memory 1meg */
+	__asm__ volatile(
+		"1: \n\t"
+		"movl %0, %%fs:(%1)\n\t"
+		"addl $4,%1\n\t"
+		"subl $4,%2\n\t"
+		"jnz 1b\n\t"
+		:
+		: "a" (0), "D" (0), "c" (1024*1024)
+		);			
+	
+	/* disable cache */
+	__asm__ volatile(
+		"movl  %%cr0, %0\n\t"
+		"orl  $0x40000000, %0\n\t"
+		"movl  %0, %%cr0\n\t"
+		:"=r" (cnt)
+		);
+	
+	/* restore msr registers */
+	msr = rdmsr(MTRRdefType_MSR);
+	msr.lo |= 0x0400;
+	wrmsr(MTRRdefType_MSR, msr);
+	
+	
+	/* Restore the variable mtrrs */
+	msr.hi = 0;
+	msr.lo = MTRR_TYPE_WRBACK;
+	wrmsr(0x200, msr);
+	wrmsr(0x201, msr_201);
+	
+	/* enable cache */
+	__asm__ volatile(
+		"movl  %%cr0, %0\n\t"
+		"andl  $0x9fffffff, %0\n\t"
+		"movl  %0, %%cr0\n\t"	
+		:"=r" (cnt)	
+		);
+	
+	print_debug(" done\r\n");
 }
diff --git a/src/northbridge/amd/amdk8/raminit.h b/src/northbridge/amd/amdk8/raminit.h
index 7622cb7..157dd13 100644
--- a/src/northbridge/amd/amdk8/raminit.h
+++ b/src/northbridge/amd/amdk8/raminit.h
@@ -1,11 +1,12 @@
 #ifndef RAMINIT_H
 #define RAMINIT_H
 
+#define DIMM_SOCKETS 4
 struct mem_controller {
 	unsigned node_id;
 	device_t f0, f1, f2, f3;
-	uint16_t channel0[4]; //By LYH
-	uint16_t channel1[4]; //By LYH
+	uint16_t channel0[DIMM_SOCKETS];
+	uint16_t channel1[DIMM_SOCKETS];
 };
 
 
diff --git a/src/northbridge/amd/amdk8/raminit_test.c b/src/northbridge/amd/amdk8/raminit_test.c
new file mode 100644
index 0000000..8e323ea
--- /dev/null
+++ b/src/northbridge/amd/amdk8/raminit_test.c
@@ -0,0 +1,442 @@
+#include <unistd.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include <setjmp.h>
+#include <device/pci_def.h>
+#include "amdk8.h"
+
+jmp_buf end_buf;
+
+static int is_cpu_pre_c0(void)
+{
+	return 0;
+}
+
+#define PCI_ADDR(BUS, DEV, FN, WHERE) ( \
+	(((BUS) & 0xFF) << 16) | \
+	(((DEV) & 0x1f) << 11) | \
+	(((FN) & 0x07) << 8) | \
+	((WHERE) & 0xFF))
+
+#define PCI_DEV(BUS, DEV, FN) ( \
+	(((BUS) & 0xFF) << 16) | \
+	(((DEV) & 0x1f) << 11) | \
+	(((FN)  & 0x7) << 8))
+
+#define PCI_ID(VENDOR_ID, DEVICE_ID) \
+	((((DEVICE_ID) & 0xFFFF) << 16) | ((VENDOR_ID) & 0xFFFF))
+
+typedef unsigned device_t;
+
+unsigned char pci_register[256*5*3*256];
+
+static uint8_t pci_read_config8(device_t dev, unsigned where)
+{
+	unsigned addr;
+	addr = dev | where;
+	return pci_register[addr];
+}
+
+static uint16_t pci_read_config16(device_t dev, unsigned where)
+{
+	unsigned addr;
+	addr = dev | where;
+	return pci_register[addr] | (pci_register[addr + 1]  << 8);
+}
+
+static uint32_t pci_read_config32(device_t dev, unsigned where)
+{
+	unsigned addr;
+	uint32_t value;
+	addr = dev | where;
+	value =  pci_register[addr] | 
+		(pci_register[addr + 1]  << 8) |
+		(pci_register[addr + 2]  << 16) |
+		(pci_register[addr + 3]  << 24);
+
+#if 0
+	print_debug("pcir32(");
+	print_debug_hex32(addr);
+	print_debug("):");
+	print_debug_hex32(value);
+	print_debug("\n");
+#endif
+	return value;
+
+}
+
+static void pci_write_config8(device_t dev, unsigned where, uint8_t value)
+{
+	unsigned addr;
+	addr = dev | where;
+	pci_register[addr] = value;
+}
+
+static void pci_write_config16(device_t dev, unsigned where, uint16_t value)
+{
+	unsigned addr;
+	addr = dev | where;
+	pci_register[addr] = value & 0xff;
+	pci_register[addr + 1] = (value >> 8) & 0xff;
+}
+
+static void pci_write_config32(device_t dev, unsigned where, uint32_t value)
+{
+	unsigned addr;
+	addr = dev | where;
+	pci_register[addr] = value & 0xff;
+	pci_register[addr + 1] = (value >> 8) & 0xff;
+	pci_register[addr + 2] = (value >> 16) & 0xff;
+	pci_register[addr + 3] = (value >> 24) & 0xff;
+
+#if 0
+	print_debug("pciw32(");
+	print_debug_hex32(addr);
+	print_debug(", ");
+	print_debug_hex32(value);
+	print_debug(")\n");
+#endif
+}
+
+#define PCI_DEV_INVALID (0xffffffffU)
+static device_t pci_locate_device(unsigned pci_id, device_t dev)
+{
+	for(; dev <= PCI_DEV(255, 31, 7); dev += PCI_DEV(0,0,1)) {
+		unsigned int id;
+		id = pci_read_config32(dev, 0);
+		if (id == pci_id) {
+			return dev;
+		}
+	}
+	return PCI_DEV_INVALID;
+}
+
+
+
+
+static void uart_tx_byte(unsigned char data)
+{
+	write(STDOUT_FILENO, &data, 1);
+}
+static void hlt(void)
+{
+	longjmp(end_buf, 2);
+}
+#include "../../../arch/i386/lib/console.c"
+
+unsigned long log2(unsigned long x)
+{
+        // assume 8 bits per byte.
+        unsigned long i = 1 << (sizeof(x)*8 - 1);
+        unsigned long pow = sizeof(x) * 8 - 1;
+
+        if (! x) {
+		static const char errmsg[] = " called with invalid parameter of 0\n";
+		write(STDERR_FILENO, __func__, sizeof(__func__) - 1);
+		write(STDERR_FILENO, errmsg, sizeof(errmsg) - 1);
+                hlt();
+        }
+        for(; i > x; i >>= 1, pow--)
+                ;
+
+        return pow;
+}
+
+typedef struct msr_struct 
+{
+	unsigned lo;
+	unsigned hi;
+} msr_t;
+
+static inline msr_t rdmsr(unsigned index)
+{
+	msr_t result;
+	result.lo = 0;
+	result.hi = 0;
+	return result;
+}
+
+static inline void wrmsr(unsigned index, msr_t msr)
+{
+}
+
+#include "raminit.h"
+
+#define SIO_BASE 0x2e
+
+static void hard_reset(void)
+{
+	/* FIXME implement the hard reset case... */
+	longjmp(end_buf, 3);
+}
+
+static void memreset_setup(void)
+{
+	/* Nothing to do */
+}
+
+static void memreset(int controllers, const struct mem_controller *ctrl)
+{
+	/* Nothing to do */
+}
+
+static inline void activate_spd_rom(const struct mem_controller *ctrl)
+{
+	/* nothing to do */
+}
+
+
+static uint8_t spd_mt4lsdt464a[256] = 
+{
+	0x80, 0x08, 0x04, 0x0C, 0x08, 0x01, 0x40, 0x00, 0x01, 0x70, 
+	0x54, 0x00, 0x80, 0x10, 0x00, 0x01, 0x8F, 0x04, 0x06, 0x01, 
+	0x01, 0x00, 0x0E, 0x75, 0x54, 0x00, 0x00, 0x0F, 0x0E, 0x0F,
+
+	0x25, 0x08, 0x15, 0x08, 0x15, 0x08, 0x00, 0x12, 0x01, 0x4E,
+	0x9C, 0xE4, 0xB7, 0x46, 0x2C, 0xFF, 0x01, 0x02, 0x03, 0x04,
+	0x05, 0x06, 0x07, 0x08, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05,
+	0x06, 0x07, 0x08, 0x09, 0x00,
+};
+
+static uint8_t spd_micron_512MB_DDR333[256] = 
+{
+	0x80, 0x08, 0x07, 0x0d, 0x0b, 0x02, 0x48, 0x00, 0x04, 0x60, 
+	0x70, 0x02, 0x82, 0x04, 0x04, 0x01, 0x0e, 0x04, 0x0c, 0x01, 
+	0x02, 0x26, 0xc0, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 
+	0x2a, 0x80, 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x3c, 0x48, 0x30, 0x28, 0x50, 0x00, 0x01, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x10, 0x6f, 0x2c, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0x01, 0x33, 0x36, 0x56, 0x44, 0x44, 0x46, 0x31, 
+	0x32, 0x38, 0x37, 0x32, 0x47, 0x2d, 0x33, 0x33, 0x35, 0x43, 
+	0x33, 0x03, 0x00, 0x03, 0x23, 0x17, 0x07, 0x5a, 0xb2, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff 
+};
+
+static uint8_t spd_micron_256MB_DDR333[256] = 
+{
+	0x80, 0x08, 0x07, 0x0d, 0x0b, 0x01, 0x48, 0x00, 0x04, 0x60, 
+	0x70, 0x02, 0x82, 0x04, 0x04, 0x01, 0x0e, 0x04, 0x0c, 0x01, 
+	0x02, 0x26, 0xc0, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 
+	0x2a, 0x80, 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x3c, 0x48, 0x30, 0x23, 0x50, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x58, 0x2c, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x01, 0x31, 0x38, 0x56, 0x44, 0x44, 0x46, 0x36, 
+	0x34, 0x37, 0x32, 0x47, 0x2d, 0x33, 0x33, 0x35, 0x43, 0x31,
+	0x20, 0x01, 0x00, 0x03, 0x19, 0x17, 0x05, 0xb2, 0xf4, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+};
+
+#define MAX_DIMMS 16
+static uint8_t spd_data[MAX_DIMMS*256];
+
+static unsigned spd_count, spd_fail_count;
+static int spd_read_byte(unsigned device, unsigned address)
+{
+	int result;
+	spd_count++;
+	if ((device < 0x50) || (device >= (0x50 +MAX_DIMMS))) {
+		result = -1;
+	}
+	else {
+		device -= 0x50;
+		
+		if (address > 256) {
+			result = -1;
+		}
+		else if (spd_data[(device << 8) | 2] != 7) {
+			result = -1;
+		}
+		else {
+			result = spd_data[(device << 8) | address];
+		}
+	}
+#if 0
+	print_debug("spd_read_byte(");
+	print_debug_hex32(device);
+	print_debug(", ");
+	print_debug_hex32(address);
+	print_debug(") -> ");
+	print_debug_hex32(result);
+	print_debug("\n");
+#endif
+	if (spd_count >= spd_fail_count) {
+		result = -1;
+	}
+	return result;
+}
+
+/* no specific code here. this should go away completely */
+static void coherent_ht_mainboard(unsigned cpus)
+{
+}
+
+#include "raminit.c"
+#include "../../../sdram/generic_sdram.c"
+
+#define FIRST_CPU  1
+#define SECOND_CPU 1
+#define TOTAL_CPUS (FIRST_CPU + SECOND_CPU)
+static void raminit_main(void)
+{
+	/*
+	 * GPIO28 of 8111 will control H0_MEMRESET_L
+	 * GPIO29 of 8111 will control H1_MEMRESET_L
+	 */
+	static const struct mem_controller cpu[] = {
+#if FIRST_CPU
+		{
+			.node_id = 0,
+			.f0 = PCI_DEV(0, 0x18, 0),
+			.f1 = PCI_DEV(0, 0x18, 1),
+			.f2 = PCI_DEV(0, 0x18, 2),
+			.f3 = PCI_DEV(0, 0x18, 3),
+			.channel0 = { 0x50+0, 0x50+2, 0x50+4, 0x50+6 },
+			.channel1 = { 0x50+1, 0x50+3, 0x50+5, 0x50+7 },
+		},
+#endif
+#if SECOND_CPU
+		{
+			.node_id = 1,
+			.f0 = PCI_DEV(0, 0x19, 0),
+			.f1 = PCI_DEV(0, 0x19, 1),
+			.f2 = PCI_DEV(0, 0x19, 2),
+			.f3 = PCI_DEV(0, 0x19, 3),
+			.channel0 = { 0x50+8, 0x50+10, 0x50+12, 0x50+14 },
+			.channel1 = { 0x50+9, 0x50+11, 0x50+13, 0x50+15 },
+		},
+#endif
+	};
+	console_init();
+	memreset_setup();
+	sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu);
+
+}
+
+static void reset_tests(void)
+{
+	/* Clear the results of any previous tests */
+	memset(pci_register, 0, sizeof(pci_register));
+	memset(spd_data, 0, sizeof(spd_data));
+	spd_count = 0;
+	spd_fail_count = UINT_MAX;
+
+	pci_write_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP,
+		NBCAP_128Bit |
+		NBCAP_MP|  NBCAP_BIG_MP |
+		/* NBCAP_ECC | NBCAP_CHIPKILL_ECC | */
+		(NBCAP_MEMCLK_200MHZ << NBCAP_MEMCLK_SHIFT) |
+		NBCAP_MEMCTRL);
+
+	pci_write_config32(PCI_DEV(0, 0x19, 3), NORTHBRIDGE_CAP,
+		NBCAP_128Bit |
+		NBCAP_MP|  NBCAP_BIG_MP |
+		/* NBCAP_ECC | NBCAP_CHIPKILL_ECC | */
+		(NBCAP_MEMCLK_200MHZ << NBCAP_MEMCLK_SHIFT) |
+		NBCAP_MEMCTRL);
+
+#if 0
+	pci_read_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP);
+#endif
+}
+
+static void test1(void)
+{
+	reset_tests();
+
+	memcpy(&spd_data[0*256], spd_micron_512MB_DDR333, 256);
+	memcpy(&spd_data[1*256], spd_micron_512MB_DDR333, 256);
+#if 0
+	memcpy(&spd_data[2*256], spd_micron_512MB_DDR333, 256);
+	memcpy(&spd_data[3*256], spd_micron_512MB_DDR333, 256);
+
+	memcpy(&spd_data[8*256], spd_micron_512MB_DDR333, 256);
+	memcpy(&spd_data[9*256], spd_micron_512MB_DDR333, 256);
+	memcpy(&spd_data[10*256], spd_micron_512MB_DDR333, 256);
+	memcpy(&spd_data[11*256], spd_micron_512MB_DDR333, 256);
+#endif
+
+	raminit_main();
+	
+#if 0
+	print_debug("spd_count: ");
+	print_debug_hex32(spd_count);
+	print_debug("\r\n");
+#endif
+	
+}
+
+
+static void do_test2(int i)
+{
+	jmp_buf tmp_buf;
+	memcpy(&tmp_buf, &end_buf, sizeof(end_buf));
+	if (setjmp(end_buf) != 0) {
+		goto done;
+	}
+	reset_tests();
+	spd_fail_count = i;
+
+	print_debug("\r\nSPD will fail after: ");
+	print_debug_hex32(spd_fail_count);
+	print_debug(" accesses.\r\n");
+	
+	memcpy(&spd_data[0*256], spd_micron_512MB_DDR333, 256);
+	memcpy(&spd_data[1*256], spd_micron_512MB_DDR333, 256);
+	
+	raminit_main();
+
+ done:
+	memcpy(&end_buf, &tmp_buf, sizeof(end_buf));
+}
+
+static void test2(void)
+{
+	int i;
+	for(i = 0; i < 0x48; i++) {
+		do_test2(i);
+	}
+	
+}
+
+int main(int argc, char **argv)
+{
+	if (setjmp(end_buf) != 0) {
+		return -1;
+	}
+	test1();
+	test2();
+	return 0;
+}
diff --git a/src/northbridge/amd/amdk8/reset_test.c b/src/northbridge/amd/amdk8/reset_test.c
index 9105324..7f4336c 100644
--- a/src/northbridge/amd/amdk8/reset_test.c
+++ b/src/northbridge/amd/amdk8/reset_test.c
@@ -1,4 +1,5 @@
 #include <stdint.h>
+#include <arch/smp/lapic.h>
 #define NODE_ID		0x60
 #define	HT_INIT_CONTROL 0x6c
 
@@ -6,11 +7,13 @@
 #define HTIC_BIOSR_Detect  (1<<5)
 #define HTIC_INIT_Detect   (1<<6)
 
-
 static int cpu_init_detected(void)
 {
 	unsigned long htic;
-	htic = pci_read_config32(PCI_DEV(0, 0x18, 0), HT_INIT_CONTROL);
+	device_t dev;
+
+	dev = PCI_DEV(0, 0x18 + lapicid(), 0);
+	htic = pci_read_config32(dev, HT_INIT_CONTROL);
 
 	return !!(htic & HTIC_INIT_Detect);
 }
@@ -31,11 +34,11 @@
 	return !(htic & HTIC_ColdR_Detect);
 }
 
-static void distinguish_cpu_resets(unsigned node_id)
+static void distinguish_cpu_resets(void)
 {
 	uint32_t htic;
 	device_t device;
-	device = PCI_DEV(0, 0x18 + node_id, 0);
+	device = PCI_DEV(0, 0x18 + lapicid(), 0);
 	htic = pci_read_config32(device, HT_INIT_CONTROL);
 	htic |= HTIC_ColdR_Detect | HTIC_BIOSR_Detect | HTIC_INIT_Detect;
 	pci_write_config32(device, HT_INIT_CONTROL, htic);
diff --git a/src/pc80/Config.lb b/src/pc80/Config.lb
index 0237fa9..26d548b 100644
--- a/src/pc80/Config.lb
+++ b/src/pc80/Config.lb
@@ -1,9 +1,8 @@
 uses CONFIG_IDE_STREAM
-uses CONFIG_KEYBOARD
 uses CONFIG_LEGACY_VGABIOS
 
 object mc146818rtc.o
-#object isa-dma.o
+object isa-dma.o
 #object i8259.o CONFIG_I8259
 #object udelay_timer2.o CONFIG_UDELAY_TIMER2
 #object beep.o CONFIG_BEEP
@@ -16,9 +15,7 @@
 	dir ide
 end
 
-if CONFIG_KEYBOARD
-	object keyboard.o
-end
+object keyboard.o
 
 if CONFIG_LEGACY_VGABIOS
 	object vgabios.o
diff --git a/src/pc80/isa-dma.c b/src/pc80/isa-dma.c
new file mode 100644
index 0000000..45cfb88
--- /dev/null
+++ b/src/pc80/isa-dma.c
@@ -0,0 +1,43 @@
+#include <arch/io.h>
+
+/* DMA controller registers */
+#define DMA1_CMD_REG		0x08	/* command register (w) */
+#define DMA1_STAT_REG		0x08	/* status register (r) */
+#define DMA1_REQ_REG            0x09    /* request register (w) */
+#define DMA1_MASK_REG		0x0A	/* single-channel mask (w) */
+#define DMA1_MODE_REG		0x0B	/* mode register (w) */
+#define DMA1_CLEAR_FF_REG	0x0C	/* clear pointer flip-flop (w) */
+#define DMA1_TEMP_REG           0x0D    /* Temporary Register (r) */
+#define DMA1_RESET_REG		0x0D	/* Master Clear (w) */
+#define DMA1_CLR_MASK_REG       0x0E    /* Clear Mask */
+#define DMA1_MASK_ALL_REG       0x0F    /* all-channels mask (w) */
+
+#define DMA2_CMD_REG		0xD0	/* command register (w) */
+#define DMA2_STAT_REG		0xD0	/* status register (r) */
+#define DMA2_REQ_REG            0xD2    /* request register (w) */
+#define DMA2_MASK_REG		0xD4	/* single-channel mask (w) */
+#define DMA2_MODE_REG		0xD6	/* mode register (w) */
+#define DMA2_CLEAR_FF_REG	0xD8	/* clear pointer flip-flop (w) */
+#define DMA2_TEMP_REG           0xDA    /* Temporary Register (r) */
+#define DMA2_RESET_REG		0xDA	/* Master Clear (w) */
+#define DMA2_CLR_MASK_REG       0xDC    /* Clear Mask */
+#define DMA2_MASK_ALL_REG       0xDE    /* all-channels mask (w) */
+
+#define DMA_MODE_READ	0x44	/* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE	0x48	/* memory to I/O, no autoinit, increment, single mode */
+#define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
+
+#define DMA_AUTOINIT	0x10
+
+
+void isa_dma_init(void)
+{
+	/* slave at 0x00 - 0x0f */
+	/* master at 0xc0 - 0xdf */
+	/* 0x80 - 0x8f DMA page registers */
+	/* DMA: 0x00, 0x02, 0x4, 0x06 base address for DMA channel */
+	outb(0, DMA1_RESET_REG);
+	outb(0, DMA2_RESET_REG);
+	outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
+	outb(0, DMA2_MASK_REG);
+}
diff --git a/src/pc80/keyboard.c b/src/pc80/keyboard.c
index a7ecf8c..d293f71 100644
--- a/src/pc80/keyboard.c
+++ b/src/pc80/keyboard.c
@@ -1,8 +1,11 @@
+#include <console/console.h>
+#include <pc80/keyboard.h>
+#include <device/device.h>
 #include <arch/io.h>
 
 /* much better keyboard init courtesy ollie@sis.com.tw 
    TODO: Typematic Setting, the keyboard is too slow for me */
-void pc_keyboard_init()
+static void pc_keyboard_init(struct pc_keyboard *keyboard)
 {
 	volatile unsigned char regval;
 
@@ -49,3 +52,9 @@
 		return;
 }
 
+void init_pc_keyboard(unsigned port0, unsigned port1, struct pc_keyboard *kbd)
+{
+	if ((port0 == 0x60) && (port1 == 0x64)) {
+		pc_keyboard_init(kbd);
+	}
+}
diff --git a/src/pc80/mc146818rtc_early.c b/src/pc80/mc146818rtc_early.c
index 35f3f59..0c7d822 100644
--- a/src/pc80/mc146818rtc_early.c
+++ b/src/pc80/mc146818rtc_early.c
@@ -97,3 +97,14 @@
 
 	return (byte & (1<<1));
 }
+
+static unsigned read_option(unsigned start, unsigned size, unsigned def)
+{
+#if USE_OPTION_TABLE == 1
+	unsigned byte;
+	byte = cmos_read(start/8);
+	return (byte >> (start & 7U)) & ((1U << size) - 1U);
+#else
+	return def;
+#endif
+}
diff --git a/src/pc80/serial.c b/src/pc80/serial.c
index c2788d6..89ac425 100644
--- a/src/pc80/serial.c
+++ b/src/pc80/serial.c
@@ -77,8 +77,7 @@
 #if USE_OPTION_TABLE == 1
 	static const unsigned char divisor[] = { 1,2,3,6,12,24,48,96 };
 	unsigned ttys0_div, ttys0_index;
-	outb(RTC_BOOT_BYTE + 1, 0x70);
-	ttys0_index = inb(0x71);
+	ttys0_index = read_option(CMOS_VSTART_baud_rate, CMOS_VLEN_baud_rate, 0);
 	ttys0_index &= 7;
 	ttys0_div = divisor[ttys0_index];
 	outb(ttys0_div & 0xff, TTYS0_BASE + UART_DLL);
diff --git a/src/pc80/serial.inc b/src/pc80/serial.inc
index b0f1269..7b80697 100644
--- a/src/pc80/serial.inc
+++ b/src/pc80/serial.inc
@@ -67,8 +67,7 @@
 	mov	%ah, %al	; \
 	outb	%al, %dx
 
-
-serial0:
+serial_init:
 	/* Set 115.2Kbps,8n1 */
 	/* Set 8bit, 1 stop bit, no parity, DLAB */
 	mov	$TTYS0_LCR, %dx
@@ -102,5 +101,7 @@
 	mov	$TTYS0_LCR, %dx
 	mov	$(TTYS0_LCS & 0x7f), %al
 	out	%al, %dx
+	RETSP
 
-
+serial0:
+	CALLSP(serial_init)
diff --git a/src/southbridge/amd/amd8111/Config.lb b/src/southbridge/amd/amd8111/Config.lb
index 904b099..5bbbaba 100644
--- a/src/southbridge/amd/amd8111/Config.lb
+++ b/src/southbridge/amd/amd8111/Config.lb
@@ -5,5 +5,6 @@
 driver amd8111_ide.o
 driver amd8111_acpi.o
 driver amd8111_usb2.o
-#driver amd8111_ac97.o
-#driver amd8111_nic.o
+driver amd8111_ac97.o
+driver amd8111_nic.o
+driver amd8111_pci.o
diff --git a/src/southbridge/amd/amd8111/amd8111.c b/src/southbridge/amd/amd8111/amd8111.c
index 8dde5f1..d3fdf3b 100644
--- a/src/southbridge/amd/amd8111/amd8111.c
+++ b/src/southbridge/amd/amd8111/amd8111.c
@@ -26,27 +26,24 @@
 		lpc_dev = dev_find_slot(dev->bus->secondary, devfn);
 		index = dev->path.u.pci.devfn & 7;
 	}
-	if ((!lpc_dev) || (index >= 16) ||
-		(lpc_dev->vendor != PCI_VENDOR_ID_AMD) ||
-		(lpc_dev->device != PCI_DEVICE_ID_AMD_8111_ISA)) {
+	if ((!lpc_dev) || (index >= 16)) {
 		return;
 	}
-
+	if ((lpc_dev->vendor != PCI_VENDOR_ID_AMD) ||
+		(lpc_dev->device != PCI_DEVICE_ID_AMD_8111_ISA)) {
+		uint32_t id;
+		id = pci_read_config32(lpc_dev, PCI_VENDOR_ID);
+		if (id != (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8111_ISA << 16))) {
+			return;
+		}
+	}
 	reg = reg_old = pci_read_config16(lpc_dev, 0x48);
 	reg &= ~(1 << index);
 	if (dev->enable) {
 		reg |= (1 << index);
 	}
 	if (reg != reg_old) {
-#if 1
-		printk_warning("amd8111_enable dev: %s", dev_path(dev));
-		printk_warning(" lpc_dev: %s index: %d reg: %04x -> %04x ", 
-			dev_path(lpc_dev), index, reg_old, reg);
-#endif
 		pci_write_config16(lpc_dev, 0x48, reg);
-#if 1
-		printk_warning("done\n");
-#endif
 	}
 }
 
diff --git a/src/southbridge/amd/amd8111/amd8111_acpi.c b/src/southbridge/amd/amd8111/amd8111_acpi.c
index 3a5a594..e3b7038 100644
--- a/src/southbridge/amd/amd8111/amd8111_acpi.c
+++ b/src/southbridge/amd/amd8111/amd8111_acpi.c
@@ -4,11 +4,15 @@
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
 #include <pc80/mc146818rtc.h>
+#include <bitops.h>
+#include <arch/io.h>
 #include "amd8111.h"
 
 #define PREVIOUS_POWER_STATE 0x43
 #define MAINBOARD_POWER_OFF 0
 #define MAINBOARD_POWER_ON 1
+#define SLOW_CPU_OFF 0
+#define SLOW_CPU__ON 1
 
 #ifndef MAINBOARD_POWER_ON_AFTER_POWER_FAIL
 #define MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
@@ -19,6 +23,8 @@
 {
 	uint8_t byte;
 	uint16_t word;
+	uint16_t pm10_bar;
+	uint32_t dword;
 	int on;
 
 #if 0
@@ -57,10 +63,43 @@
 	pci_write_config8(dev, PREVIOUS_POWER_STATE, byte);
 	printk_info("set power %s after power fail\n", on?"on":"off");
 
+	/* Throttle the CPU speed down for testing */
+	on = SLOW_CPU_OFF;
+	get_option(&on, "slow_cpu");
+	if(on) {
+		pm10_bar = (pci_read_config16(dev, 0x58)&0xff00);
+		outl(((on<<1)+0x10)  ,(pm10_bar + 0x10));
+		dword = inl(pm10_bar + 0x10);
+		on = 8-on;
+		printk_debug("Throttling CPU %2d.%1.1d percent.\n",
+				(on*12)+(on>>1),(on&1)*5);
+	}
+}
+
+static void acpi_read_resources(device_t dev)
+{
+	/* Handle the generic bars */
+	pci_dev_read_resources(dev);
+
+	if ((dev->resources + 1) < MAX_RESOURCES) {
+		struct resource *resource = &dev->resource[dev->resources];
+		dev->resources++;
+		resource->base  = 0;
+		resource->size  = 256;
+		resource->align = log2(256);
+		resource->gran  = log2(256);
+		resource->limit = 65536;
+		resource->flags = IORESOURCE_IO;
+		resource->index = 0x58;
+	}
+	else {
+		printk_err("%s Unexpected resource shortage\n",
+			dev_path(dev));
+	}
 }
 
 static struct device_operations acpi_ops  = {
-	.read_resources   = pci_dev_read_resources,
+	.read_resources   = acpi_read_resources,
 	.set_resources    = pci_dev_set_resources,
 	.enable_resources = pci_dev_enable_resources,
 	.init             = acpi_init,
diff --git a/src/southbridge/amd/amd8111/amd8111_early_smbus.c b/src/southbridge/amd/amd8111/amd8111_early_smbus.c
index 4bc515c..5157609 100644
--- a/src/southbridge/amd/amd8111/amd8111_early_smbus.c
+++ b/src/southbridge/amd/amd8111/amd8111_early_smbus.c
@@ -17,7 +17,7 @@
 		die("SMBUS controller not found\r\n");
 	}
 	uint8_t enable;
-	print_debug("SMBus controller enabled\r\n");
+	print_spew("SMBus controller enabled\r\n");
 	pci_write_config32(dev, 0x58, SMBUS_IO_BASE | 1);
 	enable = pci_read_config8(dev, 0x41);
 	pci_write_config8(dev, 0x41, enable | (1 << 7));
@@ -134,6 +134,5 @@
 
 	/* poll for transaction completion */
 	smbus_wait_until_done();
-
 	return;
 }
diff --git a/src/southbridge/amd/amd8111/amd8111_ide.c b/src/southbridge/amd/amd8111/amd8111_ide.c
index 4502bb3..6f8e018 100644
--- a/src/southbridge/amd/amd8111/amd8111_ide.c
+++ b/src/southbridge/amd/amd8111/amd8111_ide.c
@@ -12,9 +12,6 @@
 	uint16_t word;
 	int enable_a=1, enable_b=1;
 
-
-        printk_debug("ide_init\n");
-
 	word = pci_read_config16(dev, 0x40);
 	/* Ensure prefetch is disabled */
 	word &= ~((1 << 15) | (1 << 13));
diff --git a/src/southbridge/amd/amd8111/amd8111_lpc.c b/src/southbridge/amd/amd8111/amd8111_lpc.c
index 535cbec..b6e25d2 100644
--- a/src/southbridge/amd/amd8111/amd8111_lpc.c
+++ b/src/southbridge/amd/amd8111/amd8111_lpc.c
@@ -7,8 +7,10 @@
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
 #include <device/chip.h>
+#include <pc80/mc146818rtc.h>
 #include "amd8111.h"
 
+#define NMI_OFF 0
 
 struct ioapicreg {
 	unsigned int reg;
@@ -100,8 +102,7 @@
 {
 	uint8_t byte;
 	int pwr_on=-1;
-
-	printk_debug("lpc_init\n");
+	int nmi_option;
 
 	/* IO APIC initialization */
 	byte = pci_read_config8(dev, 0x4B);
@@ -127,6 +128,31 @@
 	byte |= (1 << 5);
 	pci_write_config8(dev, 0x41, byte);
 
+	/* Enable Error reporting */
+	/* Set up sync flood detected */
+	byte = pci_read_config8(dev, 0x47);
+	byte |= (1 << 1);
+	pci_write_config8(dev, 0x47, byte);
+
+	/* Set up NMI on errors */
+	byte = pci_read_config8(dev, 0x40);
+	byte |= (1 << 1); /* clear PW2LPC error */
+	byte |= (1 << 6); /* clear LPCERR */
+	pci_write_config8(dev, 0x40, byte);
+	nmi_option = NMI_OFF;
+	get_option(&nmi_option, "nmi");
+	if(nmi_option) {			
+		byte |= (1 << 7); /* set NMI */
+		pci_write_config8(dev, 0x40, byte);
+	}
+	
+	/* Initialize the real time clock */
+	rtc_init(0);
+
+	/* Initialize isa dma */
+	isa_dma_init();
+
+	/* Initialize the High Precision Event Timers */
 	enable_hpet(dev);
 }
 
@@ -146,7 +172,7 @@
 	dev->resource[reg].align = 0;
 	dev->resource[reg].gran  = 0;
 	dev->resource[reg].limit = 0;
-	dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_SET;
+	dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
 	dev->resource[reg].index = 0;
 	reg++;
 	
@@ -155,7 +181,7 @@
 	dev->resource[reg].align = 0;
 	dev->resource[reg].gran  = 0;
 	dev->resource[reg].limit = 0;
-	dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_SET;
+	dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
 	dev->resource[reg].index = 0;
 	reg++;
 	
@@ -176,4 +202,3 @@
 	.vendor = PCI_VENDOR_ID_AMD,
 	.device = PCI_DEVICE_ID_AMD_8111_ISA,
 };
-
diff --git a/src/southbridge/amd/amd8111/amd8111_pci.c b/src/southbridge/amd/amd8111/amd8111_pci.c
new file mode 100644
index 0000000..29d3fb8
--- /dev/null
+++ b/src/southbridge/amd/amd8111/amd8111_pci.c
@@ -0,0 +1,61 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "amd8111.h"
+
+static void pci_init(struct device *dev)
+{
+
+	/* Enable pci error detecting */
+	uint32_t dword;
+
+	/* System error enable */
+	dword = pci_read_config32(dev, 0x04);
+	dword |= (1<<8); /* System error enable */
+	dword |= (7<<28); /* Clear possible errors */
+	pci_write_config32(dev, 0x04, dword);
+
+	/* System,Parity,timer,and abort error enable */
+	dword = pci_read_config32(dev, 0x3c);
+	dword |= (1<<16); /* Parity */
+	dword |= (1<<17); /* System */
+	dword |= (1<<21); /* Master abort */
+//	dword &= ~(1<<21); /* Master abort */
+	dword |= (1<<27); /* Discard timer */
+	dword |= (1<<26); /* DTSTAT error clear  */
+	pci_write_config32(dev, 0x3c, dword);
+
+	/* CRC flood enable */
+	dword = pci_read_config32(dev, 0xc4);
+	dword |= (1<<1); /* CRC Flood enable */
+	dword |= (1<<8); /* Clear any CRC errors */
+	dword |= (1<<4); /* Clear any LKFAIL errors */
+	pci_write_config32(dev, 0xc4, dword);
+
+	/* Clear possible errors */
+	dword = pci_read_config32(dev, 0x1c);
+	dword |= (1<<27); /* STA */
+	dword |= (1<<28); /* RTA */
+	dword |= (1<<29); /* RMA */
+	dword |= (1<<30); /* RSE */
+	dword |= (1<<31); /* DPE */
+	dword |= (1<<24); /* MDPE */
+	pci_write_config32(dev, 0x1c, dword);
+}
+
+static struct device_operations pci_ops  = {
+	.read_resources   = pci_bus_read_resources,
+	.set_resources    = pci_dev_set_resources,
+	.enable_resources = pci_bus_enable_resources,
+	.init             = pci_init,
+	.scan_bus         = pci_scan_bridge,
+};
+
+static struct pci_driver pci_driver __pci_driver = {
+	.ops    = &pci_ops,
+	.vendor = PCI_VENDOR_ID_AMD,
+	.device = PCI_DEVICE_ID_AMD_8111_PCI,
+};
+
diff --git a/src/southbridge/amd/amd8111/amd8111_usb.c b/src/southbridge/amd/amd8111/amd8111_usb.c
index 46cfabb..407729a 100644
--- a/src/southbridge/amd/amd8111/amd8111_usb.c
+++ b/src/southbridge/amd/amd8111/amd8111_usb.c
@@ -9,6 +9,7 @@
 {
 	uint32_t cmd;
 
+#if 0
 	printk_debug("USB: Setting up controller.. ");
 	cmd = pci_read_config32(dev, PCI_COMMAND);
 	pci_write_config32(dev, PCI_COMMAND, 
@@ -17,6 +18,7 @@
 
 
 	printk_debug("done.\n");
+#endif
 
 }
 
diff --git a/src/southbridge/amd/amd8111/amd8111_usb2.c b/src/southbridge/amd/amd8111/amd8111_usb2.c
index 15ed69b..e6dd1e9 100644
--- a/src/southbridge/amd/amd8111/amd8111_usb2.c
+++ b/src/southbridge/amd/amd8111/amd8111_usb2.c
@@ -13,6 +13,7 @@
 {
 	uint32_t cmd;
 
+#if 0
 	printk_debug("USB: Setting up controller.. ");
 	cmd = pci_read_config32(dev, PCI_COMMAND);
 	pci_write_config32(dev, PCI_COMMAND, 
@@ -21,7 +22,7 @@
 
 
 	printk_debug("done.\n");
-
+#endif
 }
 
 static struct device_operations usb2_ops  = {
diff --git a/src/southbridge/amd/amd8131/amd8131_bridge.c b/src/southbridge/amd/amd8131/amd8131_bridge.c
index e730997..b96f46d 100644
--- a/src/southbridge/amd/amd8131/amd8131_bridge.c
+++ b/src/southbridge/amd/amd8131/amd8131_bridge.c
@@ -6,11 +6,16 @@
 #include <device/pci.h>
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
+#include <pc80/mc146818rtc.h>
+
+#define NMI_OFF 0
 
 static void pcix_init(device_t dev)
 {
+	uint32_t dword;
 	uint16_t word;
 	uint8_t byte;
+	int nmi_option;
 
 	/* Enable memory write and invalidate ??? */
 	byte = pci_read_config8(dev, 0x04);
@@ -40,6 +45,37 @@
         pci_write_config16(dev, 0xaa, word);
 	word = pci_read_config16(dev, 0xac);
         pci_write_config16(dev, 0xae, word);
+
+	/* Set up error reporting, enable all */
+	/* system error enable */
+	dword = pci_read_config32(dev, 0x04);
+        dword |= (1<<8);
+        pci_write_config32(dev, 0x04, dword);
+ 	
+	/* system and error parity enable */
+	dword = pci_read_config32(dev, 0x3c);
+        dword |= (3<<16);
+        pci_write_config32(dev, 0x3c, dword);
+ 	
+	/* NMI enable */
+	nmi_option = NMI_OFF;
+	get_option(&nmi_option, "nmi");
+	if(nmi_option) {
+		dword = pci_read_config32(dev, 0x44);
+        	dword |= (1<<0);
+        	pci_write_config32(dev, 0x44, dword);
+	}
+ 	
+	/* Set up CRC flood enable */
+	dword = pci_read_config32(dev, 0xc0);
+	if(dword) {  /* do device A only */
+		dword = pci_read_config32(dev, 0xc4);
+		dword |= (1<<1);
+		pci_write_config32(dev, 0xc4, dword);
+		dword = pci_read_config32(dev, 0xc8);
+		dword |= (1<<1);
+		pci_write_config32(dev, 0xc8, dword);
+	}
 	
 	return;
 }
@@ -69,13 +105,6 @@
 		value &= ~((1 << 1) | (1 << 0));
 	}
 	pci_write_config32(dev, 0x44, value);
-
-//BY LYH
-        value = pci_read_config32(dev, 0x4);
-        value |= 6;
-        pci_write_config32(dev, 0x4, value);
-//BY LYH END
-
 }
 
 static struct device_operations ioapic_ops = {
diff --git a/src/superio/NSC/pc87360/chip.h b/src/superio/NSC/pc87360/chip.h
index 5578756..9e0ef6f 100644
--- a/src/superio/NSC/pc87360/chip.h
+++ b/src/superio/NSC/pc87360/chip.h
@@ -1,9 +1,3 @@
-#ifndef PNP_INDEX_REG
-#define PNP_INDEX_REG   0x15C
-#endif
-#ifndef PNP_DATA_REG
-#define PNP_DATA_REG    0x15D
-#endif
 #ifndef SIO_COM1
 #define SIO_COM1_BASE   0x3F8
 #endif
@@ -13,8 +7,10 @@
 
 extern struct chip_control superio_NSC_pc87360_control;
 
+#include <pc80/keyboard.h>
+#include <uart8250.h>
+
 struct superio_NSC_pc87360_config {
-	struct com_ports com1;
-	struct lpt_ports lpt;
-	int port;
+	struct uart8250 com1, com2;
+	struct pc_keyboard keyboard;
 };
diff --git a/src/superio/NSC/pc87360/pc87360.h b/src/superio/NSC/pc87360/pc87360.h
new file mode 100644
index 0000000..201da8e
--- /dev/null
+++ b/src/superio/NSC/pc87360/pc87360.h
@@ -0,0 +1,11 @@
+#define PC87360_FDC  0x00 /* Floppy */
+#define PC87360_PP   0x01 /* Parallel port */
+#define PC87360_SP2  0x02 /* Com2 */
+#define PC87360_SP1  0x03 /* Com1 */
+#define PC87360_SWC  0x04
+#define PC87360_KBCM 0x05 /* Mouse */
+#define PC87360_KBCK 0x06 /* Keyboard */
+#define PC87360_GPIO 0x07
+#define PC87360_ACB  0x08
+#define PC87360_FSCM 0x09
+#define PC87360_WDT  0x0A
diff --git a/src/superio/NSC/pc87360/pc87360_early_serial.c b/src/superio/NSC/pc87360/pc87360_early_serial.c
new file mode 100644
index 0000000..696d3a0
--- /dev/null
+++ b/src/superio/NSC/pc87360/pc87360_early_serial.c
@@ -0,0 +1,11 @@
+#include <arch/romcc_io.h>
+#include "pc87360.h"
+
+
+static void pc87360_enable_serial(device_t dev, unsigned iobase)
+{
+	pnp_set_logical_device(dev);
+	pnp_set_enable(dev, 0);
+	pnp_set_iobase(dev, PNP_IDX_IO0, iobase);
+	pnp_set_enable(dev, 1);
+}
diff --git a/src/superio/NSC/pc87360/superio.c b/src/superio/NSC/pc87360/superio.c
index 8765eb3..50d71ea 100644
--- a/src/superio/NSC/pc87360/superio.c
+++ b/src/superio/NSC/pc87360/superio.c
@@ -1,324 +1,77 @@
 /* Copyright 2000  AG Electronics Ltd. */
+/* Copyright 2003-2004 Linux Networx */
 /* This code is distributed without warranty under the GPL v2 (see COPYING) */
 
 #include <arch/io.h>
 #include <device/device.h>
+#include <device/pnp.h>
 #include <device/chip.h>
 #include <console/console.h>
 #include <string.h>
 #include <bitops.h>
+#include <uart8250.h>
+#include <pc80/keyboard.h>
 #include "chip.h"
+#include "pc87360.h"
 
-void pnp_output(char address, char data)
+static void init(device_t dev)
 {
-	outb(address, PNP_INDEX_REG);
-	outb(data, PNP_DATA_REG);
-}
-
-static void sio_enable(struct chip *chip, enum chip_pass pass)
-{
-
-	struct superio_NSC_pc87360_config *conf = (struct superio_NSC_pc87360_config *)chip->chip_info;
-
-	switch (pass) {
-	case CONF_PASS_PRE_CONSOLE:
-		/* Enable Super IO Chip */
-		pnp_output(0x07, 6); /* LD 6 = UART1 */
-		pnp_output(0x30, 0); /* Dectivate */
-		pnp_output(0x60, conf->port >> 8); /* IO Base */
-		pnp_output(0x61, conf->port & 0xFF); /* IO Base */
-		pnp_output(0x30, 1); /* Activate */
-		break;
-	default:
-		/* nothing yet */
-		break;
-	}
-}
-
-static void pnp_write_config(device_t dev, unsigned char value, unsigned char reg)
-{
-	outb(reg, dev->path.u.pnp.port);
-	outb(value, dev->path.u.pnp.port + 1);
-}
-
-static unsigned char pnp_read_config(device_t dev, unsigned char reg)
-{
-	outb(reg, dev->path.u.pnp.port);
-	return inb(dev->path.u.pnp.port + 1);
-}
-
-static void pnp_set_logical_device(device_t dev)
-{
-	pnp_write_config(dev, dev->path.u.pnp.device, 0x07);
-}
-
-static void pnp_set_enable(device_t dev, int enable)
-{
-	pnp_write_config(dev, enable?0x1:0x0, 0x30);
-}
-
-static int pnp_read_enable(device_t dev)
-{
-	return !!pnp_read_config(dev, 0x30);
-}
-
-#define FLOPPY_DEVICE   0
-#define PARALLEL_DEVICE 1
-#define COM2_DEVICE     2
-#define COM1_DEVICE     3
-#define SWC_DEVICE      4
-#define MOUSE_DEVICE    5
-#define KBC_DEVICE      6
-#define GPIO_DEVICE     7
-#define ACB_DEVICE      8
-#define FSCM_DEVICE     9
-#define WDT_DEVICE     10
-
-struct io_info {
-	unsigned mask, set;
-};
-struct pnp_info {
-	unsigned flags;
-#define PNP_IO0  0x01
-#define PNP_IO1  0x02
-#define PNP_IRQ0 0x04
-#define PNP_IRQ1 0x08
-#define PNP_DRQ0 0x10
-#define PNP_DRQ1 0x20
-	struct io_info io0, io1;
-};
-
-static struct pnp_info pnp_dev_info[] = {
-	[ 0] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x07fa, 0}, },
-	[ 1] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x04f8, 0}, },
-	[ 2] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0 | PNP_DRQ1, { 0x7f8, 0 }, },
-	[ 3] = { PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, },
-	[ 4] = { PNP_IO0 | PNP_IRQ0, { 0xfff0, 0 }, },
-	[ 5] = { PNP_IRQ0 },
-	[ 6] = { PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x7f8, 0 }, { 0x7f8, 0x4}, },
-	[ 7] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
-	[ 8] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
-	[ 9] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
-	[10] = { PNP_IO0 | PNP_IRQ0, { 0xfffc, 0 } },
-};
-
-static struct resource *get_resource(device_t dev, unsigned index)
-{
-	struct resource *resource;
-	int i;
-	resource = 0;
-	for(i = 0; i < dev->resources; i++) {
-		resource = &dev->resource[i];
-		if (resource->index == index) {
-			break;
-		}
-	}
-	if (!resource || (resource->index != index)) {
-		resource = &dev->resource[dev->resources];
-		memset(resource, 0, sizeof(*resource));
-		dev->resources++;
-	}
-	/* Initialize the resource values */
-	if (!(resource->flags & IORESOURCE_FIXED)) {
-		resource->flags = 0;
-		resource->base = 0;
-	}
-	resource->size  = 0;
-	resource->limit = 0;
-	resource->flags = 0;
-	resource->index = index;
-	resource->align = 0;
-	resource->gran  = 0;
-
-	return resource;
-}
-
-static void pnp_read_ioresource(device_t dev, unsigned index, struct io_info *info)
-{
-	struct resource *resource;
-	uint32_t size;
-	resource = get_resource(dev, index);
-	
-	/* Initilize the resource */
-	resource->limit = 0xffff;
-	resource->flags |= IORESOURCE_IO;
-	
-	/* Set the resource size and alignment */
-	size = (0xffff & info->mask);
-	resource->size  = (~(size | 0xfffff800) + 1);
-	resource->align = log2(resource->size);
-	resource->gran  = resource->align;
-}
-
-
-static void pnp_read_resources(device_t dev)
-{
-	struct pnp_info *info;
-	struct resource *resource;
-	pnp_set_logical_device(dev);
-
-	info = &pnp_dev_info[dev->path.u.pnp.device];
-
-	if (info->flags & PNP_IO0) {
-		pnp_read_ioresource(dev, 0x60, &info->io0);
-	}
-	if (info->flags & PNP_IO1) {
-		pnp_read_ioresource(dev, 0x62, &info->io1);
-	}
-	if (info->flags & PNP_IRQ0) {
-		resource = get_resource(dev, 0x70);
-		resource->size = 1;
-		resource->flags |= IORESOURCE_IRQ;
-	}
-	if (info->flags & PNP_IRQ1) {
-		resource = get_resource(dev, 0x72);
-		resource->size = 1;
-		resource->flags |= IORESOURCE_IRQ;
-	}
-	if (info->flags & PNP_DRQ0) {
-		resource = get_resource(dev, 0x74);
-		resource->size = 1;
-		resource->flags |= IORESOURCE_DRQ;
-	}
-	if (info->flags & PNP_DRQ1) {
-		resource = get_resource(dev, 0x75);
-		resource->size = 1;
-		resource->flags |= IORESOURCE_DRQ;
-	}
-}
-
-static void pnp_set_iobase(device_t dev, unsigned iobase, unsigned index)
-{
-	/* Index == 0x60 or 0x62 */
-	pnp_write_config(dev, (iobase >> 8) & 0xff, index);
-	pnp_write_config(dev, iobase & 0xff, index + 1);
-}
-
-static void pnp_set_irq(device_t dev, unsigned irq, unsigned index)
-{
-	/* Index == 0x70 or 0x72 */
-	pnp_write_config(dev, irq, index);
-}
-
-static void pnp_set_drq(device_t dev, unsigned drq, unsigned index)
-{
-	/* Index == 0x74 */
-	pnp_write_config(dev, drq & 0xff, index);
-}
-
-
-static void pnp_set_resource(device_t dev, struct resource *resource)
-{
-	if (!(resource->flags & IORESOURCE_SET)) {
-#if 1
-		printk_err("ERROR: %s %02x not allocated\n",
-			dev_path(dev), resource->index);
-#endif
-		return;
-	}
-	if (resource->flags & IORESOURCE_IO) {
-		pnp_set_iobase(dev, resource->base, resource->index);
-	}
-	else if (resource->flags & IORESOURCE_DRQ) {
-		pnp_set_drq(dev, resource->base, resource->index);
-	}
-	else if (resource->flags  & IORESOURCE_IRQ) {
-		pnp_set_irq(dev, resource->base, resource->index);
-	}
-	else {
-		printk_err("ERROR: %s %02x unknown resource type\n",
-			dev_path(dev), resource->index);
-		return;
-	}
-	printk_debug(
-		"%s %02x <- [0x%08lx - 0x%08lx %s\n",
-		dev_path(dev),
-		resource->index,
-		resource->base,  resource->base + resource->size - 1,
-		(resource->flags & IORESOURCE_IO)? "io":
-		(resource->flags & IORESOURCE_DRQ)? "drq":
-		(resource->flags & IORESOURCE_IRQ)? "irq":
-		(resource->flags & IORESOURCE_MEM)? "mem":
-		"???");
-}
-
-static void pnp_set_resources(device_t dev)
-{
-	int i;
-	pnp_set_logical_device(dev);
-	for(i = 0; i < dev->resources; i++) {
-		pnp_set_resource(dev, &dev->resource[i]);
-	}
-
-}
-static void pnp_enable_resources(device_t dev)
-{
-	pnp_set_logical_device(dev);
-	pnp_set_enable(dev, 1);
-
-}
-static void pnp_enable(device_t dev)
-{
-	pnp_set_logical_device(dev);
+	struct superio_NSC_pc87360_config *conf;
+	struct resource *res0, *res1;
+	/* Wishlist handle well known programming interfaces more
+	 * generically.
+	 */
 	if (!dev->enable) {
-		pnp_set_enable(dev, 0);
+		return;
+	}
+	conf = dev->chip->chip_info;
+	switch(dev->path.u.pnp.device) {
+	case PC87360_SP1: 
+		res0 = get_resource(dev, PNP_IDX_IO0);
+		init_uart8250(res0->base, &conf->com1);
+		break;
+	case PC87360_SP2:
+		res0 = get_resource(dev, PNP_IDX_IO0);
+		init_uart8250(res0->base, &conf->com2);
+		break;
+	case PC87360_KBCK:
+		res0 = get_resource(dev, PNP_IDX_IO0);
+		res1 = get_resource(dev, PNP_IDX_IO1);
+		init_pc_keyboard(res0->base, res1->base, &conf->keyboard);
+		break;
 	}
 }
 
-static struct device_operations pnp_ops = {
+static struct device_operations ops = {
 	.read_resources   = pnp_read_resources,
 	.set_resources    = pnp_set_resources,
 	.enable_resources = pnp_enable_resources,
 	.enable           = pnp_enable,
+	.init             = init,
 };
 
-#define MAX_FUNCTION 10
+static struct pnp_info pnp_dev_info[] = {
+ { &ops, PC87360_FDC,  PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x07fa, 0}, },
+ { &ops, PC87360_PP,   PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x04f8, 0}, },
+ { &ops, PC87360_SP2,  PNP_IO0 | PNP_IRQ0 | PNP_DRQ0 | PNP_DRQ1, { 0x7f8, 0 }, },
+ { &ops, PC87360_SP1,  PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, },
+ { &ops, PC87360_SWC,  PNP_IO0 | PNP_IRQ0, { 0xfff0, 0 }, },
+ { &ops, PC87360_KBCM, PNP_IRQ0 },
+ { &ops, PC87360_KBCK, PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x7f8, 0 }, { 0x7f8, 0x4}, },
+ { &ops, PC87360_GPIO, PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
+ { &ops, PC87360_ACB,  PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
+ { &ops, PC87360_FSCM, PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
+ { &ops, PC87360_WDT,  PNP_IO0 | PNP_IRQ0, { 0xfffc, 0 } },
+};
+
+
 static void enumerate(struct chip *chip)
 {
-	struct superio_NSC_pc87360_config *conf = (struct superio_NSC_pc87360_config *)chip->chip_info;
-	struct resource *resource;
-	struct device_path path;
-	device_t dev;
-	int i;
-
-	chip_enumerate(chip);
-	path.type       = DEVICE_PATH_PNP;
-	path.u.pnp.port = chip->dev->path.u.pnp.port;
-
-	/* Set the ops on the newly allocated devices */
-	for(i = 0; i <= WDT_DEVICE; i++) {
-		path.u.pnp.device = i;
-		dev = alloc_find_dev(chip->bus, &path);
-		dev->ops = &pnp_ops;
-	}
-
-	/* Processes the hard codes for com1 */
-	path.u.pnp.device = COM1_DEVICE;
-	dev = alloc_find_dev(chip->bus, &path);
-	resource = get_resource(dev, 0x60);
-	if (conf->com1.base) {
-		resource->base = conf->com1.base;
-		resource->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_SET;
-	}
-	resource = get_resource(dev, 0x70);
-	if (conf->com1.irq) {
-		resource->base = conf->com1.irq;
-		resource->flags = IORESOURCE_IRQ | IORESOURCE_FIXED | IORESOURCE_SET;
-	}
-
-	/* Process the hard codes for the keyboard controller */
-	path.u.pnp.device = KBC_DEVICE;
-	dev = alloc_find_dev(dev, &path);
-	resource = get_resource(dev, 0x60);
-	resource->base = 0x60;
-	resource->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_SET;
-	resource = get_resource(dev, 0x62);
-	resource->base = 0x64;
-	resource->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_SET;
+	pnp_enumerate(chip, sizeof(pnp_dev_info)/sizeof(pnp_dev_info[0]), 
+		&pnp_ops, pnp_dev_info);
 }
 
 struct chip_control superio_NSC_pc87360_control = {
-	.enable    = sio_enable,
 	.enumerate = enumerate,
 	.name      = "NSC 87360"
 };