[coreboot] Patch set updated for coreboot: f9cf7e3 Add code to set the clock speed for Winbond W83627THF/THG.

Idwer Vollering (vidwer@gmail.com) gerrit at coreboot.org
Sat Nov 5 18:09:17 CET 2011


Idwer Vollering (vidwer at gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/411

-gerrit

commit f9cf7e33e64fe399a77aff25b105132cf90990ab
Author: Idwer Vollering <vidwer at gmail.com>
Date:   Sat Nov 5 18:08:08 2011 +0100

    Add code to set the clock speed for Winbond W83627THF/THG.
    
    Change-Id: If92d96d117683cc59081061d5ac93aa23cb87327
    Signed-off-by: Idwer Vollering <vidwer at gmail.com>
---
 src/cpu/intel/model_f2x/Kconfig              |    3 +
 src/cpu/intel/model_f2x/Makefile.inc         |    1 +
 src/cpu/intel/model_f2x/cache_as_ram.inc     |  376 ++++++++++
 src/cpu/intel/socket_mPGA478/Kconfig         |    1 +
 src/cpu/intel/socket_mPGA478/Makefile.inc    |    2 +-
 src/include/device/pci_ids.h                 |    6 +-
 src/mainboard/asrock/Kconfig                 |    5 +-
 src/mainboard/asrock/p4i65gv/Kconfig         |   53 ++
 src/mainboard/asrock/p4i65gv/Makefile.inc    |    1 +
 src/mainboard/asrock/p4i65gv/chip.h          |   22 +
 src/mainboard/asrock/p4i65gv/devicetree.cb   |   49 ++
 src/mainboard/asrock/p4i65gv/irq_tables.c    |   63 ++
 src/mainboard/asrock/p4i65gv/mainboard.c     |   26 +
 src/mainboard/asrock/p4i65gv/romstage.c      |   84 +++
 src/mainboard/asrock/p4i65gv/rtl8139.c       |   46 ++
 src/mainboard/asrock/p4i65gv/watchdog.c      |   36 +
 src/mainboard/asus/Kconfig                   |    4 +-
 src/mainboard/asus/p4p800-vm/Kconfig         |   53 ++
 src/mainboard/asus/p4p800-vm/Makefile.inc    |    1 +
 src/mainboard/asus/p4p800-vm/chip.h          |   22 +
 src/mainboard/asus/p4p800-vm/devicetree.cb   |   49 ++
 src/mainboard/asus/p4p800-vm/e100.c          |   46 ++
 src/mainboard/asus/p4p800-vm/irq_tables.c    |   63 ++
 src/mainboard/asus/p4p800-vm/mainboard.c     |   26 +
 src/mainboard/asus/p4p800-vm/romstage.c      |   84 +++
 src/mainboard/asus/p4p800-vm/watchdog.c      |   36 +
 src/northbridge/intel/Kconfig                |    1 +
 src/northbridge/intel/Makefile.inc           |    1 +
 src/northbridge/intel/i865/Kconfig           |   25 +
 src/northbridge/intel/i865/Makefile.inc      |    2 +
 src/northbridge/intel/i865/TODO              |   16 +
 src/northbridge/intel/i865/chip.h            |   25 +
 src/northbridge/intel/i865/debug.c           |  139 ++++
 src/northbridge/intel/i865/i865.h            |   89 +++
 src/northbridge/intel/i865/northbridge.c     |  171 +++++
 src/northbridge/intel/i865/raminit.c         | 1031 ++++++++++++++++++++++++++
 src/northbridge/intel/i865/raminit.h         |  181 +++++
 src/northbridge/intel/i865/reset_test.c      |   38 +
 src/southbridge/intel/i82801ex/early_smbus.c |    4 +-
 src/southbridge/intel/i82801ex/smbus.h       |    3 +
 src/superio/winbond/w83627thg/early_serial.c |   11 +
 41 files changed, 2888 insertions(+), 7 deletions(-)

diff --git a/src/cpu/intel/model_f2x/Kconfig b/src/cpu/intel/model_f2x/Kconfig
index 50cac79..ca57343 100644
--- a/src/cpu/intel/model_f2x/Kconfig
+++ b/src/cpu/intel/model_f2x/Kconfig
@@ -1,3 +1,6 @@
 config CPU_INTEL_MODEL_F2X
 	bool
 	select SMP
+        select MMX
+        select SSE
+	select CACHE_AS_RAM
diff --git a/src/cpu/intel/model_f2x/Makefile.inc b/src/cpu/intel/model_f2x/Makefile.inc
index c393343..d4ddb7b 100644
--- a/src/cpu/intel/model_f2x/Makefile.inc
+++ b/src/cpu/intel/model_f2x/Makefile.inc
@@ -1 +1,2 @@
+cpu_incs += $(src)/cpu/intel/model_f2x/cache_as_ram.inc
 driver-y += model_f2x_init.c
diff --git a/src/cpu/intel/model_f2x/cache_as_ram.inc b/src/cpu/intel/model_f2x/cache_as_ram.inc
new file mode 100644
index 0000000..7742a68
--- /dev/null
+++ b/src/cpu/intel/model_f2x/cache_as_ram.inc
@@ -0,0 +1,376 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2000, 2007 Ronald G. Minnich <rminnich at gmail.com>
+ * Copyright (C) 2005 Eswar Nallusamy, LANL
+ * Copyright (C) 2005 Tyan (written by Yinghai Lu for Tyan)
+ * Copyright (C) 2007-2010 coresystems GmbH
+ * Copyright (C) 2007 Carl-Daniel Hailfinger
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <cpu/x86/stack.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/lapic_def.h>
+#include <cpu/x86/post_code.h>
+
+#define CacheSize		CONFIG_DCACHE_RAM_SIZE
+#define CacheBase		(0xd0000 - CacheSize)
+
+	/* Save the BIST result. */
+	movl	%eax, %ebp
+
+CacheAsRam:
+	/* Check whether the processor has HT capability. */
+	movl	$01, %eax
+	cpuid
+	btl	$28, %edx
+	jnc	NotHtProcessor
+	bswapl	%ebx
+	cmpb	$01, %bh
+	jbe	NotHtProcessor
+
+	/*
+	 * It is a HT processor. Send SIPI to the other logical processor
+	 * within this processor so that the CAR related common system
+	 * registers are programmed accordingly.
+	 */
+
+	/*
+	 * Use some register that is common to both logical processors
+	 * as semaphore. Refer Appendix B, Vol.3.
+	 */
+	xorl	%eax, %eax
+	xorl	%edx, %edx
+	movl	$MTRRfix64K_00000_MSR, %ecx
+	wrmsr
+
+	/*
+	 * Figure out the logical AP's APIC ID; the following logic will
+	 * work only for processors with 2 threads.
+	 * Refer to Vol 3. Table 7-1 for details about this logic.
+	 */
+	movl	$0xFEE00020, %esi
+	movl	(%esi), %ebx
+	andl	$0xFF000000, %ebx
+	bswapl	%ebx
+	btl	$0, %ebx
+	jnc	LogicalAP0
+	andb	$0xFE, %bl
+	jmp	Send_SIPI
+LogicalAP0:
+	orb	$0x01, %bl
+Send_SIPI:
+	bswapl	%ebx	/* EBX - logical AP's APIC ID. */
+
+	/*
+	 * Fill up the IPI command registers in the Local APIC mapped to
+	 * default address and issue SIPI to the other logical processor
+	 * within this processor die.
+	 */
+Retry_SIPI:
+	movl	%ebx, %eax
+	movl	$0xFEE00310, %esi
+	movl	%eax, (%esi)
+
+	/* SIPI vector - F900:0000 */
+	movl	$0x000006F9, %eax
+	movl	$0xFEE00300, %esi
+	movl	%eax, (%esi)
+
+	movl	$0x30, %ecx
+SIPI_Delay:
+	pause
+	decl	%ecx
+	jnz	SIPI_Delay
+
+	movl	(%esi), %eax
+	andl	$0x00001000, %eax
+	jnz	Retry_SIPI
+
+	/* Wait for the Logical AP to complete initialization. */
+LogicalAP_SIPINotdone:
+	movl	$MTRRfix64K_00000_MSR, %ecx
+	rdmsr
+	orl	%eax, %eax
+	jz	LogicalAP_SIPINotdone
+
+NotHtProcessor:
+	/* Set the default memory type and enable fixed and variable MTRRs. */
+	movl	$MTRRdefType_MSR, %ecx
+	xorl	%edx, %edx
+	movl	$(MTRRdefTypeEn | MTRRdefTypeFixEn), %eax
+	wrmsr
+
+	/* Clear all MTRRs. */
+	xorl	%edx, %edx
+	movl	$all_mtrr_msrs, %esi
+
+clear_fixed_var_mtrr:
+	lodsl	(%esi), %eax
+	testl	%eax, %eax
+	jz	clear_fixed_var_mtrr_out
+
+	movl	%eax, %ecx
+	xorl	%eax, %eax
+	wrmsr
+
+	jmp	clear_fixed_var_mtrr
+
+all_mtrr_msrs:
+	/* fixed MTRR MSRs */
+	.long	MTRRfix64K_00000_MSR
+	.long	MTRRfix16K_80000_MSR
+	.long	MTRRfix16K_A0000_MSR
+	.long	MTRRfix4K_C0000_MSR
+	.long	MTRRfix4K_C8000_MSR
+	.long	MTRRfix4K_D0000_MSR
+	.long	MTRRfix4K_D8000_MSR
+	.long	MTRRfix4K_E0000_MSR
+	.long	MTRRfix4K_E8000_MSR
+	.long	MTRRfix4K_F0000_MSR
+	.long	MTRRfix4K_F8000_MSR
+
+	/* var MTRR MSRs */
+	.long	MTRRphysBase_MSR(0)
+	.long	MTRRphysMask_MSR(0)
+	.long	MTRRphysBase_MSR(1)
+	.long	MTRRphysMask_MSR(1)
+	.long	MTRRphysBase_MSR(2)
+	.long	MTRRphysMask_MSR(2)
+	.long	MTRRphysBase_MSR(3)
+	.long	MTRRphysMask_MSR(3)
+	.long	MTRRphysBase_MSR(4)
+	.long	MTRRphysMask_MSR(4)
+	.long	MTRRphysBase_MSR(5)
+	.long	MTRRphysMask_MSR(5)
+	.long	MTRRphysBase_MSR(6)
+	.long	MTRRphysMask_MSR(6)
+	.long	MTRRphysBase_MSR(7)
+	.long	MTRRphysMask_MSR(7)
+
+	.long	0x000 /* NULL, end of table */
+
+clear_fixed_var_mtrr_out:
+
+/*
+ * 0x06 is the WB IO type for a given 4k segment.
+ * segs is the number of 4k segments in the area of the particular
+ *      register we want to use for CAR.
+ * reg  is the register where the IO type should be stored.
+ */
+.macro extractmask segs, reg
+.if \segs <= 0
+	/*
+	 * The xorl here is superfluous because at the point of first execution
+	 * of this macro, %eax and %edx are cleared. Later invocations of this
+	 * macro will have a monotonically increasing segs parameter.
+	 */
+	xorl \reg, \reg
+.elseif \segs == 1
+	movl	$0x06000000, \reg /* WB IO type */
+.elseif \segs == 2
+	movl	$0x06060000, \reg /* WB IO type */
+.elseif \segs == 3
+	movl	$0x06060600, \reg /* WB IO type */
+.elseif \segs >= 4
+	movl	$0x06060606, \reg /* WB IO type */
+.endif
+.endm
+
+/*
+ * carsize is the cache size in bytes we want to use for CAR.
+ * windowoffset is the 32k-aligned window into CAR size.
+ */
+.macro simplemask carsize, windowoffset
+	.set gas_bug_workaround,(((\carsize - \windowoffset) / 0x1000) - 4)
+	extractmask gas_bug_workaround, %eax
+	.set gas_bug_workaround,(((\carsize - \windowoffset) / 0x1000))
+	extractmask gas_bug_workaround, %edx
+	/*
+	 * Without the gas bug workaround, the entire macro would consist
+	 * only of the two lines below:
+	 *   extractmask (((\carsize - \windowoffset) / 0x1000) - 4), %eax
+	 *   extractmask (((\carsize - \windowoffset) / 0x1000)), %edx
+	 */
+.endm
+
+#if CacheSize > 0x10000
+#error Invalid CAR size, must be at most 64k.
+#endif
+#if CacheSize < 0x1000
+#error Invalid CAR size, must be at least 4k. This is a processor limitation.
+#endif
+#if (CacheSize & (0x1000 - 1))
+#error Invalid CAR size, is not a multiple of 4k. This is a processor limitation.
+#endif
+
+#if CacheSize > 0x8000
+	/* Enable caching for 32K-64K using fixed MTRR. */
+	movl	$MTRRfix4K_C0000_MSR, %ecx
+	simplemask CacheSize, 0x8000
+	wrmsr
+#endif
+
+	/* Enable caching for 0-32K using fixed MTRR. */
+	movl	$MTRRfix4K_C8000_MSR, %ecx
+	simplemask CacheSize, 0
+	wrmsr
+
+#if CONFIG_XIP_ROM_SIZE
+
+	/*
+	 * Enable write base caching so we can do execute in place (XIP)
+	 * on the flash ROM.
+	 */
+	movl	$MTRRphysBase_MSR(1), %ecx
+	xorl	%edx, %edx
+	/*
+	 * IMPORTANT: The following calculation _must_ be done at runtime. See
+	 * http://www.coreboot.org/pipermail/coreboot/2010-October/060855.html
+	 */
+	movl	$copy_and_run, %eax
+	andl	$(~(CONFIG_XIP_ROM_SIZE - 1)), %eax
+	orl	$MTRR_TYPE_WRBACK, %eax
+	wrmsr
+
+	movl	$MTRRphysMask_MSR(1), %ecx
+	movl	$0x0000000f, %edx
+	movl	$(~(CONFIG_XIP_ROM_SIZE - 1) | MTRRphysMaskValid), %eax
+	wrmsr
+#endif /* CONFIG_XIP_ROM_SIZE */
+
+	/* Enable cache. */
+	movl	%cr0, %eax
+	andl	$(~((1 << 30) | (1 << 29))), %eax
+	movl	%eax, %cr0
+
+	/* Read the range with lodsl. */
+	movl	$CacheBase, %esi
+	cld
+	movl	$(CacheSize >> 2), %ecx
+	rep	lodsl
+
+	/* Clear the range. */
+	movl	$CacheBase, %edi
+	movl	$(CacheSize >> 2), %ecx
+	xorl	%eax, %eax
+	rep	stosl
+
+#if 0
+	/* Check the cache as ram. */
+	movl	$CacheBase, %esi
+	movl	$(CacheSize >> 2), %ecx
+.xin1:
+	movl	%esi, %eax
+	movl	%eax, (%esi)
+	decl	%ecx
+	je	.xout1
+	add	$4, %esi
+	jmp	.xin1
+.xout1:
+
+	movl	$CacheBase, %esi
+	// movl	$(CacheSize >> 2), %ecx
+	movl	$4, %ecx
+.xin1x:
+	movl	%esi, %eax
+
+	movl	$0x4000, %edx
+	movb	%ah, %al
+.testx1:
+	outb	%al, $0x80
+	decl	%edx
+	jnz	.testx1
+
+	movl	(%esi), %eax
+	cmpb	0xff, %al
+	je	.xin2	/* Don't show. */
+
+	movl	$0x4000, %edx
+.testx2:
+	outb	%al, $0x80
+	decl	%edx
+	jnz	.testx2
+
+.xin2:
+	decl	%ecx
+	je	.xout1x
+	add	$4, %esi
+	jmp	.xin1x
+.xout1x:
+#endif
+
+	movl	$(CacheBase + CacheSize - 4), %eax
+	movl	%eax, %esp
+lout:
+	/* Restore the BIST result. */
+	movl	%ebp, %eax
+
+	/* We need to set EBP? No need. */
+	movl	%esp, %ebp
+	pushl	%eax  /* BIST */
+	call	main
+
+	/* We don't need CAR from now on. */
+
+	/* Disable cache. */
+	movl	%cr0, %eax
+	orl	$(1 << 30), %eax
+	movl	%eax, %cr0
+
+	/* Clear sth. */
+	movl	$MTRRfix4K_C8000_MSR, %ecx
+	xorl	%edx, %edx
+	xorl	%eax, %eax
+	wrmsr
+
+#if CONFIG_DCACHE_RAM_SIZE > 0x8000
+	movl	$MTRRfix4K_C0000_MSR, %ecx
+	wrmsr
+#endif
+
+	/*
+	 * Set the default memory type and disable fixed
+	 * and enable variable MTRRs.
+	 */
+	movl	$MTRRdefType_MSR, %ecx
+	xorl	%edx, %edx
+	movl	$MTRRdefTypeEn, %eax /* Enable variable and disable fixed MTRRs. */
+	wrmsr
+
+	/* Enable cache. */
+	movl	%cr0, %eax
+	andl	$(~((1 << 30) | (1 << 29))), %eax
+	movl	%eax, %cr0
+
+	/* Clear boot_complete flag. */
+	xorl	%ebp, %ebp
+__main:
+	post_code(POST_PREPARE_RAMSTAGE)
+	cld			/* Clear direction flag. */
+
+	movl	%ebp, %esi
+
+	movl	$ROMSTAGE_STACK, %esp
+	movl	%esp, %ebp
+	pushl	%esi
+	call	copy_and_run
+
+.Lhlt:
+	post_code(POST_DEAD_CODE)
+	hlt
+	jmp	.Lhlt
+
diff --git a/src/cpu/intel/socket_mPGA478/Kconfig b/src/cpu/intel/socket_mPGA478/Kconfig
index 8c447c9..c17780f 100644
--- a/src/cpu/intel/socket_mPGA478/Kconfig
+++ b/src/cpu/intel/socket_mPGA478/Kconfig
@@ -2,3 +2,4 @@ config CPU_INTEL_SOCKET_MPGA478
 	bool
 	select CPU_INTEL_MODEL_69X
 	select CPU_INTEL_MODEL_6DX
+	select CPU_INTEL_MODEL_F2X
diff --git a/src/cpu/intel/socket_mPGA478/Makefile.inc b/src/cpu/intel/socket_mPGA478/Makefile.inc
index ba2f13c..c3742f3 100644
--- a/src/cpu/intel/socket_mPGA478/Makefile.inc
+++ b/src/cpu/intel/socket_mPGA478/Makefile.inc
@@ -1,6 +1,7 @@
 ramstage-y += socket_mPGA478.c
 subdirs-y += ../model_69x
 subdirs-y += ../model_6dx
+subdirs-y += ../model_f2x
 subdirs-y += ../../x86/tsc
 subdirs-y += ../../x86/mtrr
 subdirs-y += ../../x86/lapic
@@ -8,4 +9,3 @@ subdirs-y += ../../x86/cache
 subdirs-y += ../../x86/smm
 subdirs-y += ../microcode
 subdirs-y += ../hyperthreading
-
diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h
index d16f85e..37b5848 100644
--- a/src/include/device/pci_ids.h
+++ b/src/include/device/pci_ids.h
@@ -2142,7 +2142,8 @@
 #define PCI_DEVICE_ID_INTEL_82801DBM_EHCI	0x24cd
 
 /* Intel 82801EB (ICH5) */
-#define PCI_DEVICE_ID_INTEL_82801EB_LAN		0x1051
+#define PCI_DEVICE_ID_INTEL_82801EB_LAN1	0x1050
+#define PCI_DEVICE_ID_INTEL_82801EB_LAN2	0x1051
 #define PCI_DEVICE_ID_INTEL_82801EB_PCI		0x244e
 #define PCI_DEVICE_ID_INTEL_82801EB_LPC		0x24d0
 #define PCI_DEVICE_ID_INTEL_82801EB_SATA	0x24d1
@@ -2157,7 +2158,8 @@
 #define PCI_DEVICE_ID_INTEL_82801EB_USB4	0x24de
 
 /* Intel 82801ER (ICH5R) */
-#define PCI_DEVICE_ID_INTEL_82801ER_LAN		0x1051
+#define PCI_DEVICE_ID_INTEL_82801ER_LAN1	0x1050
+#define PCI_DEVICE_ID_INTEL_82801ER_LAN2	0x1051
 #define PCI_DEVICE_ID_INTEL_82801ER_PCI		0x244e
 #define PCI_DEVICE_ID_INTEL_82801ER_LPC		0x24d0
 #define PCI_DEVICE_ID_INTEL_82801ER_USB1	0x24d2
diff --git a/src/mainboard/asrock/Kconfig b/src/mainboard/asrock/Kconfig
index 1e4fff9..260f048 100644
--- a/src/mainboard/asrock/Kconfig
+++ b/src/mainboard/asrock/Kconfig
@@ -25,11 +25,14 @@ config BOARD_ASROCK_939A785GMH
 	bool "939A785GMH/128M"
 config BOARD_ASROCK_E350M1
 	bool "E350M1"
+config BOARD_ASROCK_P4I65GV
+	bool "P4i65GV"
 
 endchoice
 
-source "src/mainboard/asrock/939a785gmh/Kconfig"
+source "src/mainboard/asrock/939a785gmh/Kconfig"
 source "src/mainboard/asrock/e350m1/Kconfig"
+source "src/mainboard/asrock/p4i65gv/Kconfig"
 
 config MAINBOARD_VENDOR
 	string
diff --git a/src/mainboard/asrock/p4i65gv/Kconfig b/src/mainboard/asrock/p4i65gv/Kconfig
new file mode 100644
index 0000000..21e2b3d
--- /dev/null
+++ b/src/mainboard/asrock/p4i65gv/Kconfig
@@ -0,0 +1,53 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe at hermann-uwe.de>
+##
+## This program is free software; you can redistribute it and/or modify it under the terms of the GNU General 
+## Public License as published by the Free Software Foundation; version 2 of the License.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the 
+## implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
+## for more details.
+##
+## You should have received a copy of the GNU General Public License along with this program; if not, write to 
+## the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+##
+if BOARD_ASROCK_P4I65GV
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+	def_bool y
+	select ARCH_X86
+	select CPU_INTEL_SOCKET_MPGA478
+	select NORTHBRIDGE_INTEL_I865
+	select SOUTHBRIDGE_INTEL_I82801EX
+	select SUPERIO_WINBOND_W83627HF
+	select HAVE_HARD_RESET
+#	select HAVE_PIRQ_TABLE
+	select UDELAY_TSC
+	select BOARD_ROMSIZE_KB_512
+	select USE_WATCHDOG_ON_BOOT
+#	select HAVE_ACPI_TABLES
+#	select CACHE_AS_RAM # inherited from the socket option
+
+config MAINBOARD_DIR
+	string
+	default asrock/p4i65gv
+
+config MAINBOARD_PART_NUMBER
+	string
+	default "P4i65GV"
+
+config DCACHE_RAM_BASE
+	hex
+	default 0xfff00000
+
+config DCACHE_RAM_SIZE
+	hex
+	default 0x8000 # ok?
+
+config IRQ_SLOT_COUNT
+	int
+	default 6 # no idea
+
+endif # BOARD_ASROCK_P4I65GV
diff --git a/src/mainboard/asrock/p4i65gv/Makefile.inc b/src/mainboard/asrock/p4i65gv/Makefile.inc
new file mode 100644
index 0000000..03e044d
--- /dev/null
+++ b/src/mainboard/asrock/p4i65gv/Makefile.inc
@@ -0,0 +1 @@
+driver-y += rtl8139.c
diff --git a/src/mainboard/asrock/p4i65gv/chip.h b/src/mainboard/asrock/p4i65gv/chip.h
new file mode 100644
index 0000000..e77b136
--- /dev/null
+++ b/src/mainboard/asrock/p4i65gv/chip.h
@@ -0,0 +1,22 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2007 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+extern struct chip_operations mainboard_ops;
+struct mainboard_config {};
diff --git a/src/mainboard/asrock/p4i65gv/devicetree.cb b/src/mainboard/asrock/p4i65gv/devicetree.cb
new file mode 100644
index 0000000..992463c
--- /dev/null
+++ b/src/mainboard/asrock/p4i65gv/devicetree.cb
@@ -0,0 +1,49 @@
+chip northbridge/intel/i865
+	device lapic_cluster 0 on
+		chip cpu/intel/socket_mPGA478
+			device lapic 0 on end
+		end
+	end
+	device pci_domain 0 on
+		device pci 0.0 on end # northbridge
+		device pci 0.1 off end # agp
+		device pci 0.2 on end # igd
+		device pnp 0.3 off end # csa
+		device pci 0.6 on end # overflow device
+		
+		chip southbridge/intel/i82801ex
+			device pci 1d.0 on end # uhci #1
+			device pci 1d.1 on end # uhci #2
+			device pci 1d.2 on end # uhci #3
+			device pci 1d.3 on end # uhci #4
+			device pci 1d.7 on end # ehci
+			device pci 1e.0 on # pci bridge
+				# 01:05.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL-8139/8139C/8139C+ [10ec:8139] (rev 10)
+				device pci 05.0 on end
+			end
+			
+			device pci 1f.0 on # lpc bridge
+				chip superio/winbond/w83627hf
+					device pnp 2e.0 off end # floppy
+					device pnp 2e.1 off end # parallel
+					device pnp 2e.2 on
+						io 0x60 = 0x3f8
+						irq 0x70 = 4
+					end # com1
+					device pnp 2e.3 off end # com2
+					device pnp 2e.5 on end # keyboard
+					device pnp 2e.6 off end # ir
+					device pnp 2e.7 on end # game/gpio 1
+					device pnp 2e.8 on end # gpio 2
+					device pnp 2e.9 on end # gpio 3
+					device pnp 2e.a on end # acpi
+					device pnp 2e.b on end # hardware monitor
+				end # superio
+			end # 1f.0
+			device pci 1f.1 on end # pata
+			device pci 1f.2 on end # sata
+			device pci 1f.3 on end # smbus
+			device pci 1f.5 off end # ac97
+		end # southbridge
+	end # pci_domain
+end # northbridge
diff --git a/src/mainboard/asrock/p4i65gv/irq_tables.c b/src/mainboard/asrock/p4i65gv/irq_tables.c
new file mode 100644
index 0000000..240ab23
--- /dev/null
+++ b/src/mainboard/asrock/p4i65gv/irq_tables.c
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 200x TODO <TODO at TODO>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifdef GETPIR			/* TODO: Drop this when copying to coreboot. */
+#include "pirq_routing.h"	/* TODO: Drop this when copying to coreboot. */
+#else				/* TODO: Drop this when copying to coreboot. */
+#include <arch/pirq_routing.h>
+#endif				/* TODO: Drop this when copying to coreboot. */
+
+const struct irq_routing_table intel_irq_routing_table = {
+	PIRQ_SIGNATURE,		/* u32 signature */
+	PIRQ_VERSION,		/* u16 version */
+	32 + 16 * 13,		/* Max. number of devices on the bus */
+	0x00,			/* Interrupt router bus */
+	(0x1f << 3) | 0x0,	/* Interrupt router dev */
+	0,			/* IRQs devoted exclusively to PCI usage */
+	0x8086,			/* Vendor */
+	0x24d0,			/* Device */
+	0,			/* Miniport */
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */
+	0x3e,			/* Checksum (has to be set to some value that
+				 * would give 0 after the sum of all bytes
+				 * for this structure (including checksum).
+                                 */
+	{
+		/* bus,        dev | fn,   {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu */
+		{0x01, (0x08 << 3) | 0x0, {{0x68, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0},
+		{0x00, (0x1f << 3) | 0x0, {{0x62, 0xdcf8}, {0x61, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0},
+		{0x00, (0x1d << 3) | 0x0, {{0x60, 0xdcf8}, {0x63, 0xdcf8}, {0x62, 0xdcf8}, {0x6b, 0xdcf8}}, 0x0, 0x0},
+		{0x00, (0x01 << 3) | 0x0, {{0x60, 0xdcf8}, {0x61, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0},
+		{0x00, (0x02 << 3) | 0x0, {{0x60, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0},
+		{0x00, (0x03 << 3) | 0x0, {{0x00, 0x0000}, {0x62, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0},
+		{0x01, (0x03 << 3) | 0x0, {{0x68, 0xdcf8}, {0x69, 0xdcf8}, {0x6a, 0xdcf8}, {0x6b, 0xdcf8}}, 0x1, 0x0},
+		{0x01, (0x01 << 3) | 0x0, {{0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}, {0x69, 0xdcf8}}, 0x2, 0x0},
+		{0x01, (0x02 << 3) | 0x0, {{0x6b, 0xdcf8}, {0x68, 0xdcf8}, {0x69, 0xdcf8}, {0x6a, 0xdcf8}}, 0x3, 0x0},
+		{0x01, (0x00 << 3) | 0x0, {{0x69, 0xdcf8}, {0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}}, 0x4, 0x0},
+		{0x01, (0x04 << 3) | 0x0, {{0x69, 0xdcf8}, {0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}}, 0x5, 0x0},
+		{0x01, (0x0a << 3) | 0x0, {{0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}, {0x69, 0xdcf8}}, 0x6, 0x0},
+		{0x01, (0x05 << 3) | 0x0, {{0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0},
+	}
+};
+
+unsigned long write_pirq_routing_table(unsigned long addr)
+{
+	return copy_pirq_routing_table(addr);
+}
diff --git a/src/mainboard/asrock/p4i65gv/mainboard.c b/src/mainboard/asrock/p4i65gv/mainboard.c
new file mode 100644
index 0000000..78aec29
--- /dev/null
+++ b/src/mainboard/asrock/p4i65gv/mainboard.c
@@ -0,0 +1,26 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2007 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <device/device.h>
+#include "chip.h"
+
+struct chip_operations mainboard_ops = {
+	CHIP_NAME("ASRock P4i65GV Mainboard")
+};
diff --git a/src/mainboard/asrock/p4i65gv/romstage.c b/src/mainboard/asrock/p4i65gv/romstage.c
new file mode 100644
index 0000000..7f70ca0
--- /dev/null
+++ b/src/mainboard/asrock/p4i65gv/romstage.c
@@ -0,0 +1,84 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2007 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <device/pci_def.h>
+#include <arch/io.h>
+#include <device/pnp_def.h>
+#include <arch/romcc_io.h>
+#include <arch/hlt.h>
+#include <stdlib.h>
+#include <console/console.h>
+#include <lib.h>
+#include <cpu/x86/lapic.h>
+#include "pc80/udelay_io.c"
+//#include "lib/delay.c"
+#include "cpu/x86/bist.h"
+
+//#include "southbridge/intel/i82801ex/i82801ex.h"
+#include "southbridge/intel/i82801ex/early_smbus.c"
+#include "northbridge/intel/i865/debug.c"
+#include "northbridge/intel/i865/raminit.c"
+//#include "northbridge/intel/i865/reset_test.c"
+#include "northbridge/intel/i865/i865.h"
+#include "superio/winbond/w83627hf/early_serial.c"
+#include "watchdog.c"
+
+#define SERIAL_DEV PNP_DEV(0x2e, W83627HF_SP1)
+
+//int spd_read_byte(unsigned int device, unsigned int address)
+//static inline int spd_read_byte(unsigned device, unsigned address)
+//{
+//	return smbus_read_byte(device, address);
+//}
+
+void main(unsigned long bist) {
+
+	// TODO
+	// copied from dell/s1850/romstage.c
+	/*
+	static const struct mem_controller memctrl[] = {
+		{
+			// node id?
+			.channel0 = { DIMM0, DIMM1, DIMM2, DIMM3, },
+			.channel1 = { DIMM4, DIMM5, DIMM6, DIMM7, },
+		}
+	};
+*/
+	if (bist == 0)
+		enable_lapic();
+
+	w83627hf_set_clksel_48(SERIAL_DEV);
+	w83627hf_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE);
+	console_init();
+	report_bist_failure(bist);
+
+//	if (!bios_reset_detected()) /* board doesn't boot when using bios_rest_detected() */
+//	{
+		enable_smbus();
+		dump_spd_registers();
+
+		disable_ich5_watchdog();
+
+		// TODO: dual-channel, e.g.:
+		// sdram_initialize(ARRAY_SIZE(memctrl), memctrl); // copied from dell/s1850/romstage.c
+		sdram_initialize();
+//	}
+}
diff --git a/src/mainboard/asrock/p4i65gv/rtl8139.c b/src/mainboard/asrock/p4i65gv/rtl8139.c
new file mode 100644
index 0000000..d909af7
--- /dev/null
+++ b/src/mainboard/asrock/p4i65gv/rtl8139.c
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008 coresystems GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This code should work for all ICH* southbridges with a NIC. */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+
+static void nic_init(struct device *dev)
+{
+	printk(BIOS_DEBUG, "Initializing RTL8139 Fast Ethernet\n");
+	// Nothing to do yet, but this has to be here to keep
+	// coreboot from trying to execute an option ROM.
+}
+static struct device_operations nic_ops = {
+	.read_resources		= pci_dev_read_resources,
+	.set_resources		= pci_dev_set_resources,
+	.enable_resources	= pci_dev_enable_resources,
+	.init			= nic_init,
+	.scan_bus		= 0,
+};
+
+static const struct pci_driver rtl8139_nic __pci_driver = {
+	.ops	= &nic_ops,
+	.vendor = PCI_VENDOR_ID_REALTEK,
+	.device = PCI_DEVICE_ID_REALTEK_8139,
+};
diff --git a/src/mainboard/asrock/p4i65gv/watchdog.c b/src/mainboard/asrock/p4i65gv/watchdog.c
new file mode 100644
index 0000000..8c7b0f6
--- /dev/null
+++ b/src/mainboard/asrock/p4i65gv/watchdog.c
@@ -0,0 +1,36 @@
+/* copied and adapted from src/mainboard/dell/s1850/watchdog.c */
+
+#define ICH5_WDBASE 0x800 /* PMBASE */
+#define ICH5_GPIOBASE 0x480
+
+static void disable_ich5_watchdog(void)
+{
+	/* FIXME move me somewhere more appropriate */
+	device_t dev;
+	unsigned long value, base;
+	dev = pci_locate_device(PCI_ID(0x8086, 0x24d0), 0); /* LPC bridge */
+	if (dev == PCI_DEV_INVALID) {
+		die("Missing ich5?");
+	}
+
+	/* Enable I/O space */
+	value = pci_read_config16(dev, 0x04); /* PCICMD */
+	value |= (1 << 10); /* reserved? */
+	pci_write_config16(dev, 0x04, value);
+
+	/* Set and enable acpibase */
+	pci_write_config32(dev, 0x40, ICH5_WDBASE | 1); /* PMBASE */
+	pci_write_config8(dev, 0x44, 0x10); /* ACPI_CNTL = ACPI_EN */
+	base = ICH5_WDBASE + 0x60; /* TCO offset, ich5 datasheet ch9.11 */
+
+	/* Set bit 11 in TCO1_CNT */
+	value = inw(base + 0x08);
+	value |= 1 << 11; /* enable TCO_TMR_HLT */
+	outw(value, base + 0x08);
+
+	/* Clear TCO timeout status */
+	outw(0x0008, base + 0x04); /* TCO1_STS, raise bit 3: TIMEOUT */
+	outw(0x0002, base + 0x06); /* TCO2_STS, raise bit 2: SECOND_TO_STS */
+
+	printk(BIOS_DEBUG, "Board-specific ICH5 watchdog disabled\n");
+}
diff --git a/src/mainboard/asus/Kconfig b/src/mainboard/asus/Kconfig
index 77b7997..1369a4b 100644
--- a/src/mainboard/asus/Kconfig
+++ b/src/mainboard/asus/Kconfig
@@ -55,7 +55,8 @@ config BOARD_ASUS_P2B_LS
 	bool "P2B-LS"
 config BOARD_ASUS_P3B_F
 	bool "P3B-F"
-
+config BOARD_ASUS_P4P800_VM
+	bool "P4P800-VM"
 endchoice
 
 source "src/mainboard/asus/a8n_e/Kconfig"
@@ -75,6 +76,7 @@ source "src/mainboard/asus/p2b-ds/Kconfig"
 source "src/mainboard/asus/p2b-f/Kconfig"
 source "src/mainboard/asus/p2b-ls/Kconfig"
 source "src/mainboard/asus/p3b-f/Kconfig"
+source "src/mainboard/asus/p4p800-vm/Kconfig"
 
 config MAINBOARD_VENDOR
 	string
diff --git a/src/mainboard/asus/p4p800-vm/Kconfig b/src/mainboard/asus/p4p800-vm/Kconfig
new file mode 100644
index 0000000..ef93089
--- /dev/null
+++ b/src/mainboard/asus/p4p800-vm/Kconfig
@@ -0,0 +1,53 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe at hermann-uwe.de>
+##
+## This program is free software; you can redistribute it and/or modify it under the terms of the GNU General 
+## Public License as published by the Free Software Foundation; version 2 of the License.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the 
+## implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
+## for more details.
+##
+## You should have received a copy of the GNU General Public License along with this program; if not, write to 
+## the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+##
+if BOARD_ASUS_P4P800_VM
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+	def_bool y
+	select ARCH_X86
+	select CPU_INTEL_SOCKET_MPGA478
+	select NORTHBRIDGE_INTEL_I865
+	select SOUTHBRIDGE_INTEL_I82801EX
+	select SUPERIO_WINBOND_W83627THG
+	select HAVE_HARD_RESET
+#	select HAVE_PIRQ_TABLE
+	select UDELAY_TSC
+	select BOARD_ROMSIZE_KB_512
+	select USE_WATCHDOG_ON_BOOT
+#	select HAVE_ACPI_TABLES
+#	select CACHE_AS_RAM # inherited from the socket option
+
+config MAINBOARD_DIR
+	string
+	default asus/p4p800-vm
+
+config MAINBOARD_PART_NUMBER
+	string
+	default "P4P800-VM"
+
+config DCACHE_RAM_BASE
+	hex
+	default 0xfff00000
+
+config DCACHE_RAM_SIZE
+	hex
+	default 0x8000 # ok?
+
+config IRQ_SLOT_COUNT
+	int
+	default 6 # no idea
+
+endif # BOARD_ASUS_P4P800_VM
diff --git a/src/mainboard/asus/p4p800-vm/Makefile.inc b/src/mainboard/asus/p4p800-vm/Makefile.inc
new file mode 100644
index 0000000..93aefe9
--- /dev/null
+++ b/src/mainboard/asus/p4p800-vm/Makefile.inc
@@ -0,0 +1 @@
+driver-y += e100.c
diff --git a/src/mainboard/asus/p4p800-vm/chip.h b/src/mainboard/asus/p4p800-vm/chip.h
new file mode 100644
index 0000000..e77b136
--- /dev/null
+++ b/src/mainboard/asus/p4p800-vm/chip.h
@@ -0,0 +1,22 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2007 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+extern struct chip_operations mainboard_ops;
+struct mainboard_config {};
diff --git a/src/mainboard/asus/p4p800-vm/devicetree.cb b/src/mainboard/asus/p4p800-vm/devicetree.cb
new file mode 100644
index 0000000..cf80f53
--- /dev/null
+++ b/src/mainboard/asus/p4p800-vm/devicetree.cb
@@ -0,0 +1,49 @@
+chip northbridge/intel/i865
+	device lapic_cluster 0 on
+		chip cpu/intel/socket_mPGA478
+			device lapic 0 on end
+		end
+	end
+	device pci_domain 0 on
+		device pci 0.0 on end # northbridge
+		device pci 0.1 off end # agp
+		device pci 0.2 on end # igd
+		device pnp 0.3 off end # csa
+		device pci 0.6 on end # overflow device
+		
+		chip southbridge/intel/i82801ex
+			device pci 1d.0 on end # uhci #1
+			device pci 1d.1 on end # uhci #2
+			device pci 1d.2 on end # uhci #3
+			device pci 1d.3 on end # uhci #4
+			device pci 1d.7 on end # ehci
+			device pci 1e.0 on # pci bridge
+				# 01:08.0 Ethernet controller: Intel Corporation 82562EZ 10/100 Ethernet Controller (rev 02)
+				device pci 08.0 on end
+			end
+			
+			device pci 1f.0 on # lpc bridge
+				chip superio/winbond/w83627thg
+					device pnp 2e.0 off end # floppy
+					device pnp 2e.1 off end # parallel
+					device pnp 2e.2 on
+						io 0x60 = 0x3f8
+						irq 0x70 = 4
+					end # com1
+					device pnp 2e.3 off end # com2
+					device pnp 2e.5 on end # keyboard
+					device pnp 2e.6 off end # ir
+					device pnp 2e.7 on end # game/gpio 1
+					device pnp 2e.8 on end # gpio 2
+					device pnp 2e.9 on end # gpio 3
+					device pnp 2e.a on end # acpi
+					device pnp 2e.b on end # hardware monitor
+				end # superio
+			end # 1f.0
+			device pci 1f.1 on end # pata
+			device pci 1f.2 on end # sata
+			device pci 1f.3 on end # smbus
+			device pci 1f.5 off end # ac97
+		end # southbridge
+	end # pci_domain
+end # northbridge
diff --git a/src/mainboard/asus/p4p800-vm/e100.c b/src/mainboard/asus/p4p800-vm/e100.c
new file mode 100644
index 0000000..d3c0e07
--- /dev/null
+++ b/src/mainboard/asus/p4p800-vm/e100.c
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008 coresystems GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This code should work for all ICH* southbridges with a NIC. */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+
+static void nic_init(struct device *dev)
+{
+	printk(BIOS_DEBUG, "Initializing Intel 82562EZ 10/100 Ethernet\n");
+	// Nothing to do yet, but this has to be here to keep
+	// coreboot from trying to execute an option ROM.
+}
+static struct device_operations nic_ops = {
+	.read_resources		= pci_dev_read_resources,
+	.set_resources		= pci_dev_set_resources,
+	.enable_resources	= pci_dev_enable_resources,
+	.init			= nic_init,
+	.scan_bus		= 0,
+};
+
+static const struct pci_driver intel_e100_nic __pci_driver = {
+	.ops	= &nic_ops,
+	.vendor = PCI_VENDOR_ID_INTEL,
+	.device = PCI_DEVICE_ID_INTEL_82801EB_LAN1, /* 8086:1050 */
+};
diff --git a/src/mainboard/asus/p4p800-vm/irq_tables.c b/src/mainboard/asus/p4p800-vm/irq_tables.c
new file mode 100644
index 0000000..240ab23
--- /dev/null
+++ b/src/mainboard/asus/p4p800-vm/irq_tables.c
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 200x TODO <TODO at TODO>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifdef GETPIR			/* TODO: Drop this when copying to coreboot. */
+#include "pirq_routing.h"	/* TODO: Drop this when copying to coreboot. */
+#else				/* TODO: Drop this when copying to coreboot. */
+#include <arch/pirq_routing.h>
+#endif				/* TODO: Drop this when copying to coreboot. */
+
+const struct irq_routing_table intel_irq_routing_table = {
+	PIRQ_SIGNATURE,		/* u32 signature */
+	PIRQ_VERSION,		/* u16 version */
+	32 + 16 * 13,		/* Max. number of devices on the bus */
+	0x00,			/* Interrupt router bus */
+	(0x1f << 3) | 0x0,	/* Interrupt router dev */
+	0,			/* IRQs devoted exclusively to PCI usage */
+	0x8086,			/* Vendor */
+	0x24d0,			/* Device */
+	0,			/* Miniport */
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */
+	0x3e,			/* Checksum (has to be set to some value that
+				 * would give 0 after the sum of all bytes
+				 * for this structure (including checksum).
+                                 */
+	{
+		/* bus,        dev | fn,   {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu */
+		{0x01, (0x08 << 3) | 0x0, {{0x68, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0},
+		{0x00, (0x1f << 3) | 0x0, {{0x62, 0xdcf8}, {0x61, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0},
+		{0x00, (0x1d << 3) | 0x0, {{0x60, 0xdcf8}, {0x63, 0xdcf8}, {0x62, 0xdcf8}, {0x6b, 0xdcf8}}, 0x0, 0x0},
+		{0x00, (0x01 << 3) | 0x0, {{0x60, 0xdcf8}, {0x61, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0},
+		{0x00, (0x02 << 3) | 0x0, {{0x60, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0},
+		{0x00, (0x03 << 3) | 0x0, {{0x00, 0x0000}, {0x62, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0},
+		{0x01, (0x03 << 3) | 0x0, {{0x68, 0xdcf8}, {0x69, 0xdcf8}, {0x6a, 0xdcf8}, {0x6b, 0xdcf8}}, 0x1, 0x0},
+		{0x01, (0x01 << 3) | 0x0, {{0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}, {0x69, 0xdcf8}}, 0x2, 0x0},
+		{0x01, (0x02 << 3) | 0x0, {{0x6b, 0xdcf8}, {0x68, 0xdcf8}, {0x69, 0xdcf8}, {0x6a, 0xdcf8}}, 0x3, 0x0},
+		{0x01, (0x00 << 3) | 0x0, {{0x69, 0xdcf8}, {0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}}, 0x4, 0x0},
+		{0x01, (0x04 << 3) | 0x0, {{0x69, 0xdcf8}, {0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}}, 0x5, 0x0},
+		{0x01, (0x0a << 3) | 0x0, {{0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}, {0x69, 0xdcf8}}, 0x6, 0x0},
+		{0x01, (0x05 << 3) | 0x0, {{0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0},
+	}
+};
+
+unsigned long write_pirq_routing_table(unsigned long addr)
+{
+	return copy_pirq_routing_table(addr);
+}
diff --git a/src/mainboard/asus/p4p800-vm/mainboard.c b/src/mainboard/asus/p4p800-vm/mainboard.c
new file mode 100644
index 0000000..5b47989
--- /dev/null
+++ b/src/mainboard/asus/p4p800-vm/mainboard.c
@@ -0,0 +1,26 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2007 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <device/device.h>
+#include "chip.h"
+
+struct chip_operations mainboard_ops = {
+	CHIP_NAME("ASUS P4P800-VM Mainboard")
+};
diff --git a/src/mainboard/asus/p4p800-vm/romstage.c b/src/mainboard/asus/p4p800-vm/romstage.c
new file mode 100644
index 0000000..fad3aca
--- /dev/null
+++ b/src/mainboard/asus/p4p800-vm/romstage.c
@@ -0,0 +1,84 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2007 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <device/pci_def.h>
+#include <arch/io.h>
+#include <device/pnp_def.h>
+#include <arch/romcc_io.h>
+#include <arch/hlt.h>
+#include <stdlib.h>
+#include <console/console.h>
+#include <lib.h>
+#include <cpu/x86/lapic.h>
+#include "pc80/udelay_io.c"
+//#include "lib/delay.c"
+#include "cpu/x86/bist.h"
+
+//#include "southbridge/intel/i82801ex/i82801ex.h"
+#include "southbridge/intel/i82801ex/early_smbus.c"
+#include "northbridge/intel/i865/debug.c"
+#include "northbridge/intel/i865/raminit.c"
+//#include "northbridge/intel/i865/reset_test.c"
+#include "northbridge/intel/i865/i865.h"
+#include "superio/winbond/w83627thg/early_serial.c"
+#include "watchdog.c"
+
+#define SERIAL_DEV PNP_DEV(0x2e, W83627THG_SP1)
+
+//int spd_read_byte(unsigned int device, unsigned int address)
+//static inline int spd_read_byte(unsigned device, unsigned address)
+//{
+//	return smbus_read_byte(device, address);
+//}
+
+void main(unsigned long bist) {
+
+	// TODO
+	// copied from dell/s1850/romstage.c
+	/*
+	static const struct mem_controller memctrl[] = {
+		{
+			// node id?
+			.channel0 = { DIMM0, DIMM1, DIMM2, DIMM3, },
+			.channel1 = { DIMM4, DIMM5, DIMM6, DIMM7, },
+		}
+	};
+*/
+	if (bist == 0)
+		enable_lapic();
+
+	w83627thg_set_clksel_48(SERIAL_DEV);
+	w83627thg_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE);
+	console_init();
+	report_bist_failure(bist);
+
+//	if (!bios_reset_detected()) /* board doesn't boot when using bios_rest_detected() */
+//	{
+		enable_smbus();
+		dump_spd_registers();
+
+		disable_ich5_watchdog();
+
+		// TODO: dual-channel, e.g.:
+		// sdram_initialize(ARRAY_SIZE(memctrl), memctrl); // copied from dell/s1850/romstage.c
+		sdram_initialize();
+//	}
+}
diff --git a/src/mainboard/asus/p4p800-vm/watchdog.c b/src/mainboard/asus/p4p800-vm/watchdog.c
new file mode 100644
index 0000000..8c7b0f6
--- /dev/null
+++ b/src/mainboard/asus/p4p800-vm/watchdog.c
@@ -0,0 +1,36 @@
+/* copied and adapted from src/mainboard/dell/s1850/watchdog.c */
+
+#define ICH5_WDBASE 0x800 /* PMBASE */
+#define ICH5_GPIOBASE 0x480
+
+static void disable_ich5_watchdog(void)
+{
+	/* FIXME move me somewhere more appropriate */
+	device_t dev;
+	unsigned long value, base;
+	dev = pci_locate_device(PCI_ID(0x8086, 0x24d0), 0); /* LPC bridge */
+	if (dev == PCI_DEV_INVALID) {
+		die("Missing ich5?");
+	}
+
+	/* Enable I/O space */
+	value = pci_read_config16(dev, 0x04); /* PCICMD */
+	value |= (1 << 10); /* reserved? */
+	pci_write_config16(dev, 0x04, value);
+
+	/* Set and enable acpibase */
+	pci_write_config32(dev, 0x40, ICH5_WDBASE | 1); /* PMBASE */
+	pci_write_config8(dev, 0x44, 0x10); /* ACPI_CNTL = ACPI_EN */
+	base = ICH5_WDBASE + 0x60; /* TCO offset, ich5 datasheet ch9.11 */
+
+	/* Set bit 11 in TCO1_CNT */
+	value = inw(base + 0x08);
+	value |= 1 << 11; /* enable TCO_TMR_HLT */
+	outw(value, base + 0x08);
+
+	/* Clear TCO timeout status */
+	outw(0x0008, base + 0x04); /* TCO1_STS, raise bit 3: TIMEOUT */
+	outw(0x0002, base + 0x06); /* TCO2_STS, raise bit 2: SECOND_TO_STS */
+
+	printk(BIOS_DEBUG, "Board-specific ICH5 watchdog disabled\n");
+}
diff --git a/src/northbridge/intel/Kconfig b/src/northbridge/intel/Kconfig
index 1809d11..e5c8ed5 100644
--- a/src/northbridge/intel/Kconfig
+++ b/src/northbridge/intel/Kconfig
@@ -8,5 +8,6 @@ source src/northbridge/intel/i440lx/Kconfig
 source src/northbridge/intel/i82810/Kconfig
 source src/northbridge/intel/i82830/Kconfig
 source src/northbridge/intel/i855/Kconfig
+source src/northbridge/intel/i865/Kconfig
 source src/northbridge/intel/i945/Kconfig
 source src/northbridge/intel/sch/Kconfig
diff --git a/src/northbridge/intel/Makefile.inc b/src/northbridge/intel/Makefile.inc
index 0d116d0..9d333b6 100644
--- a/src/northbridge/intel/Makefile.inc
+++ b/src/northbridge/intel/Makefile.inc
@@ -8,6 +8,7 @@ subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I440LX) += i440lx
 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I82810) += i82810
 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I82830) += i82830
 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I855) += i855
+subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I865) += i865
 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I945GC) += i945
 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I945GM) += i945
 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_SCH) += sch
diff --git a/src/northbridge/intel/i865/Kconfig b/src/northbridge/intel/i865/Kconfig
new file mode 100644
index 0000000..944f701
--- /dev/null
+++ b/src/northbridge/intel/i865/Kconfig
@@ -0,0 +1,25 @@
+config NORTHBRIDGE_INTEL_I865
+	bool
+	select HAVE_DEBUG_RAM_SETUP
+choice
+prompt "Onboard graphics"
+	default I865_VIDEO_MB_8MB
+	depends on NORTHBRIDGE_INTEL_I865
+
+config I865_VIDEO_MB_OFF
+	bool "Disabled, 0KB"
+config I865_VIDEO_MB_1MB
+	bool "Enabled, 1MB"
+config I865_VIDEO_MB_8MB
+	bool "Enabled, 8MB"
+config I865_VIDEO_MB_16MB
+	bool "Enabled, 16MB"
+endchoice
+
+config VIDEO_MB
+	int
+	default 0	if I865_VIDEO_MB_OFF
+	default 1	if I865_VIDEO_MB_1MB
+	default 8	if I865_VIDEO_MB_8MB
+	default 16	if I865_VIDEO_MB_16MB
+	depends on NORTHBRIDGE_INTEL_I865
diff --git a/src/northbridge/intel/i865/Makefile.inc b/src/northbridge/intel/i865/Makefile.inc
new file mode 100644
index 0000000..8cec43f
--- /dev/null
+++ b/src/northbridge/intel/i865/Makefile.inc
@@ -0,0 +1,2 @@
+ramstage-y += northbridge.c
+#romstage-y += early_init.c
diff --git a/src/northbridge/intel/i865/TODO b/src/northbridge/intel/i865/TODO
new file mode 100644
index 0000000..2f28af0
--- /dev/null
+++ b/src/northbridge/intel/i865/TODO
@@ -0,0 +1,16 @@
+TODO (probably incomplete)
+
+raminit.c:
+	* re-use the mchbar macro from i945 and read/write from/to it like its raminit code does
+	* GPL headers everywhere
+	* includes (is assert.h really needed?)
+	* set TOUD (from northbridge.c?)
+	* set SMFREQ and FSBFREQ (in GMCHCFG) (from northbridge.c?)?
+	* AGP (device 1) code
+	* VGA/IGD (device 2) code
+	* CSA (device 3) code?
+	* clean up/trim northbridge_set_registers()
+	* dual-channel code (and don't forget romstage.c)
+
+DONE
+* raise bits 0 (IOAE, I/O access enable) and 1 (MAE, memory access enable) in PCICMD6 (from northbridge.c?)
diff --git a/src/northbridge/intel/i865/chip.h b/src/northbridge/intel/i865/chip.h
new file mode 100644
index 0000000..6e7b21e
--- /dev/null
+++ b/src/northbridge/intel/i865/chip.h
@@ -0,0 +1,25 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2006 Jon Dufresne <jon.dufresne at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+struct northbridge_intel_i865_config
+{
+};
+
+extern struct chip_operations northbridge_intel_i865_ops;
diff --git a/src/northbridge/intel/i865/debug.c b/src/northbridge/intel/i865/debug.c
new file mode 100644
index 0000000..a7935ce
--- /dev/null
+++ b/src/northbridge/intel/i865/debug.c
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2003 Ronald G. Minnich
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <spd.h>
+static void print_debug_pci_dev(unsigned dev) {
+	print_debug("PCI: ");
+	print_debug_hex8((dev >> 20) & 0xff);
+	print_debug_char(':');
+	print_debug_hex8((dev >> 15) & 0x1f);
+	print_debug_char('.');
+	print_debug_hex8((dev >> 12) & 0x07);
+}
+static inline void print_pci_devices(void) {
+	device_t dev;
+	for(dev = PCI_DEV(0, 0, 0);
+		dev <= PCI_DEV(0, 0x1f, 0x7);
+		dev += PCI_DEV(0,0,1)) {
+		uint32_t id;
+		id = pci_read_config32(dev, PCI_VENDOR_ID);
+		if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+			(((id >> 16) & 0xffff) == 0xffff) ||
+			(((id >> 16) & 0xffff) == 0x0000)) {
+			continue;
+		}
+		print_debug_pci_dev(dev);
+		print_debug("\n");
+	}
+}
+static void dump_pci_device(unsigned dev) {
+	int i;
+	print_debug_pci_dev(dev);
+	print_debug("\n");
+	for(i = 0; i <= 255; i++) {
+		unsigned char val;
+		if ((i & 0x0f) == 0) {
+			print_debug_hex8(i);
+			print_debug_char(':');
+		}
+		val = pci_read_config8(dev, i);
+		print_debug_char(' ');
+		print_debug_hex8(val);
+		if ((i & 0x0f) == 0x0f) {
+			print_debug("\n");
+		}
+	}
+}
+static inline void dump_pci_devices(void) {
+	device_t dev;
+	for(dev = PCI_DEV(0, 0, 0);
+		dev <= PCI_DEV(0, 0x1f, 0x7);
+		dev += PCI_DEV(0,0,1)) {
+		uint32_t id;
+		id = pci_read_config32(dev, PCI_VENDOR_ID);
+		if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+			(((id >> 16) & 0xffff) == 0xffff) ||
+			(((id >> 16) & 0xffff) == 0x0000)) {
+			continue;
+		}
+		dump_pci_device(dev);
+	}
+}
+static inline void dump_spd_registers(void) {
+	int i;
+	print_debug("\n");
+	for(i = 0; i < 2; i++) {
+		unsigned device;
+		device = DIMM0 + i;
+		if (device) {
+			int j;
+			print_debug("dimm: ");
+			print_debug_hex8(i);
+			print_debug(".0: ");
+			print_debug_hex8(device);
+			for(j = 0; j < 256; j++) {
+				int status;
+				unsigned char byte;
+				if ((j & 0xf) == 0) {
+					print_debug("\n");
+					print_debug_hex8(j);
+					print_debug(": ");
+				}
+				status = smbus_read_byte(device, j);
+				if (status < 0) {
+					print_debug("bad device\n");
+					break;
+				}
+				byte = status & 0xff;
+				print_debug_hex8(byte);
+				print_debug_char(' ');
+			}
+			print_debug("\n");
+		}
+	}
+}
+static inline void dump_smbus_registers(void) {
+        int i;
+        print_debug("\n");
+        for(i = 1; i < 0x80; i++) {
+                unsigned device;
+                device = i;
+                int j;
+                print_debug("smbus: ");
+                print_debug_hex8(device);
+                for(j = 0; j < 256; j++) {
+                	int status;
+                        unsigned char byte;
+                        if ((j & 0xf) == 0) {
+                	        print_debug("\n");
+                                print_debug_hex8(j);
+                                print_debug(": ");
+                        }
+                        status = smbus_read_byte(device, j);
+                        if (status < 0) {
+                                print_debug("bad device\n");
+                                break;
+                        }
+                        byte = status & 0xff;
+                        print_debug_hex8(byte);
+                        print_debug_char(' ');
+                }
+                print_debug("\n");
+	}
+}
diff --git a/src/northbridge/intel/i865/i865.h b/src/northbridge/intel/i865/i865.h
new file mode 100644
index 0000000..51cf0bc
--- /dev/null
+++ b/src/northbridge/intel/i865/i865.h
@@ -0,0 +1,89 @@
+/* TODO:
+ * AGP #defines
+ * GPL header
+ */
+
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Travelping GmbH <info at travelping.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* size, default value */
+/* DRAM Controller (device 0) */
+#define APBASE		0x10 /* 32 bit, 0x8 */
+// #define AGPM		0x51 /* 8 bit, 0x0 */
+// #define ESMRAMC		0x9e /* 8 bit, 0x38 */
+// #define ACAPID		0xa0 /* 32bit, 0x300002 (RO) */
+// #define AGPSTAT		0xa4 /* 32bit, AGP 2.0: 0x1f004217 (RO) or AGP 3.0: 0x1f004a13 (RO) */
+// #define AGPCMD		0xa8 /* 32bit, AGP 2.0: 0x0 or AGP 3.0: 0xa00 */
+// #define AGPCTRL		0xb0 /* 32bit, 0x0 */
+#define AMTT		0xbc /* 8 bit, 0x10 */
+#define APSIZE		0xb4 /* 8 bit, 0x0 */
+// #define ATTBASE		0xb8 /* 32 bit, 0x0 */
+#define TOUD		0xc4 /* 16 bit, 0x400 */
+#define GMCHCFG		0xc6 /* 16 bit, 0x0 */
+#define ERRSTS		0xc8 /* 16 bit, 0x0 */
+// #define ERRCMD		0xca /* 16 bit, 0x0 */
+// #define FDHC		0x97 /* 8 bit, 0x0 */
+// #define FPLLCONT	0x60 /* 8 bit, 0x0 */
+#define GC			0x52 /* 8 bit (looks wrong), 0x1000 */
+#define LPTT		0xbd /* 8 bit, 0x10 */
+#define PCISTS		0x10 /* 16 bit, 0x90 */
+// #define SMRAM		0x9D /* 8 bit, 0x2 */
+#define SVID		0x2c /* 16 bit, 0x0 */
+#define SID		0x2e /* 16 bit, 0x0 */
+// #define CSABCONT	0x53 /* 8 bit, 0x0 */
+#define VID 0x0 /* 16 bit, 0x8086 */
+#define DID 0x2 /* 16 bit, 0x2570 */
+/* PCI-to-AGP bridge (device 1) */
+// #define PCICMD1		0x04 /* 16 bit, 0x0 */
+// #define SMLT1		0x0d /* 8 bit, 0x0 */
+// #define SBUSN1		0x19 /* 8 bit, 0x0 */
+// #define SUBUSN1		0x1a /* 8 bit, 0x0 */
+// #define PMBASE1		0x24 /* 16 bit, 0xfff0 */
+// #define PMLIMIT1	0x26 /* 16 bit, 0x0 */
+// #define BCTRL1		0x3e /* 8 bit, 0x0 */
+// #define ERRCMD1		0x40 /* 8 bit, 0x0 */
+
+/* Integrated Graphics Device (device 2) */
+// #define PCICMD2		0x04 /* 16 bit, 0x0 */
+// #define GMADR		0x10 /* 32 bit, 0x8 */
+// #define MMADR		0x14 /* 32 bit, 0x0 */
+// #define IOBAR		0x18 /* 32 bit, 0x1 */
+// #define SVID2		0x2c /* 16 bit, 0x0 */
+// #define SID2		0x2e /* 16 bit, 0x0 */
+// #define INTRLINE	0x3c /* 8 bit, 0x0 */
+// #define PMCS		0xd4 /* 16 bit, 0x0 */
+// #define SWSMI		0xe0 /* 16 bit, 0x0 */
+
+/* PCI-to-CSA bridge (device 3) */
+// #define PCICMD3		0x04 /* 16 bit, 0x0 */
+// #define IOBASE3		0x1c /* 8 bit, 0xf0 */
+// #define IOLIMIT3	0x1d /* 8 bit, 0x0 */
+// #define MBASE3		0x20 /* 16 bit, 0xfff0 */
+// #define MLIMIT3		0x22 /* 16 bit, 0x0 */
+// #define PMBASE3		0x24 /* 16 bit, 0xfff0 */
+// #define PMLIMIT3	0x26 /* 16 bit, 0x0 */
+// #define BCTRL3		0x3e /* 8 bit, 0x0 */
+// #define CSACNTRL	0x50 /* 32 bit, 0xe042802 */
+
+/* Overflow device (device 6) */
+#define PCICMD6		0x04 /* 16 bit (looks wrong), 0x0 */
+#define BAR6		0x10 /* 32 bit, 0x0 */
+// #define SVID6		0x2c /* 16 bit, 0x0 */
+// #define SID6		0x2e /* 16 bit, 0x0 */
diff --git a/src/northbridge/intel/i865/northbridge.c b/src/northbridge/intel/i865/northbridge.c
new file mode 100644
index 0000000..c249be3
--- /dev/null
+++ b/src/northbridge/intel/i865/northbridge.c
@@ -0,0 +1,171 @@
+/* TODO:
+ * CSA (device 3) code
+ * set all subsytem IDs (SID*, SVID*)
+ */
+
+ /*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2003 Ronald G. Minnich
+ * Copyright (C) 2003-2004 Eric W. Biederman
+ * Copyright (C) 2006 Jon Dufresne <jon.dufresne at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <stdlib.h>
+#include <string.h>
+#include <bitops.h>
+#include <cpu/x86/cache.h>
+#include <cpu/cpu.h>
+#include "chip.h"
+#include "i865.h"
+#include "raminit.h"
+
+static void northbridge_init(device_t dev)
+{
+        printk(BIOS_SPEW, "Northbridge init\n");
+}
+
+static struct device_operations northbridge_operations = {
+        .read_resources = pci_dev_read_resources,
+        .set_resources = pci_dev_set_resources,
+        .enable_resources = pci_dev_enable_resources,
+        .init = northbridge_init,
+        .enable = 0,
+        .ops_pci = 0,
+};
+
+static const struct pci_driver northbridge_driver __pci_driver = {
+        .ops = &northbridge_operations,
+        .vendor = PCI_VENDOR_ID_INTEL,
+        .device = 0x2570,
+};
+
+#if CONFIG_WRITE_HIGH_TABLES==1
+#define HIGH_TABLES_SIZE 64    // maximum size of high tables in KB
+extern uint64_t high_tables_base, high_tables_size;
+#endif
+static void pci_domain_set_resources(device_t dev)
+{
+	device_t mc_dev;
+	uint32_t pci_tolm;
+
+	printk(BIOS_DEBUG, "Entered with dev vid = %x\n", dev->vendor);
+	printk(BIOS_DEBUG, "Entered with dev did = %x\n", dev->device);
+
+	pci_tolm = find_pci_tolm(dev->link_list);
+	mc_dev = dev->link_list->children->sibling;
+	printk(BIOS_DEBUG, "MC dev vendor = %x\n", mc_dev->vendor);
+	printk(BIOS_DEBUG, "MC dev device = %x\n", mc_dev->device);
+
+	if (mc_dev) {
+               /* Figure out which areas are/should be occupied by RAM.
+                * This is all computed in kilobytes and converted to/from
+                * the memory controller right at the edges.
+                * Having different variables in different units is
+                * too confusing to get right.  Kilobytes are good up to
+                * 4 Terabytes of RAM...
+                */
+               unsigned long tomk, tolmk;
+               int idx;
+
+               /* Get the value of the highest DRB. This tells the end of
+                * the physical memory. The units are ticks of 64 MB
+                * i.e. 1 means 64 MB.
+                */
+		//tomk = (unsigned long)pci_read_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), DRB + 7);
+//		tomk = BAR6_8(DRB + 7);
+		tomk = MCHBAR8(DRB + 7);
+               tomk = tomk * 64 * 1024;
+               /* add vga_mem detection */
+               tomk = tomk - 16 * 1024; // 16 MB, graphics mode select (GMS)
+               /* Compute the top of Low memory */
+               tolmk = pci_tolm >> 10;
+               if (tolmk >= tomk) {
+                       /* The PCI hole does not overlap memory
+                        */
+                       tolmk = tomk;
+               }
+               /* Write the ram configuration registers,
+                * preserving the reserved bits.
+                */
+
+               /* Report the memory regions */
+               printk(BIOS_DEBUG, "tomk = %ld\n", tomk);
+               printk(BIOS_DEBUG, "tolmk = %ld\n", tolmk);
+
+               idx = 10;
+               /* avoid pam region */
+               ram_resource(dev, idx++, 0, 640);
+               /* ram_resource(dev, idx++, 1024, tolmk - 1024); */
+               ram_resource(dev, idx++, 768, tolmk - 768);
+
+#if CONFIG_WRITE_HIGH_TABLES==1
+               /* Leave some space for ACPI, PIRQ and MP tables */
+               high_tables_base = (tomk - HIGH_TABLES_SIZE) * 1024;
+               high_tables_size = HIGH_TABLES_SIZE * 1024;
+#endif
+       }
+       assign_resources(dev->link_list);
+}
+
+static struct device_operations pci_domain_ops = {
+        .read_resources   = pci_domain_read_resources,
+        .set_resources    = pci_domain_set_resources,
+        .enable_resources = NULL,
+        .init             = NULL,
+        .scan_bus         = pci_domain_scan_bus,
+};
+
+static void cpu_bus_init(device_t dev)
+{
+        initialize_cpus(dev->link_list);
+}
+
+static void cpu_bus_noop(device_t dev)
+{
+}
+
+static struct device_operations cpu_bus_ops = {
+        .read_resources   = cpu_bus_noop,
+        .set_resources    = cpu_bus_noop,
+        .enable_resources = cpu_bus_noop,
+        .init             = cpu_bus_init,
+        .scan_bus         = 0,
+};
+
+static void enable_dev(struct device *dev)
+{
+        /* Set the operations if it is a special bus type */
+        if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
+                dev->ops = &pci_domain_ops;
+               pci_set_method(dev);
+        }
+        else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) {
+                dev->ops = &cpu_bus_ops;
+        }
+}
+
+struct chip_operations northbridge_intel_i865_ops = {
+        CHIP_NAME("Intel 865 Northbridge")
+       .enable_dev = enable_dev,
+};
diff --git a/src/northbridge/intel/i865/raminit.c b/src/northbridge/intel/i865/raminit.c
new file mode 100644
index 0000000..91e3144
--- /dev/null
+++ b/src/northbridge/intel/i865/raminit.c
@@ -0,0 +1,1031 @@
+#include <spd.h>
+#include <stdlib.h>
+#include <sdram_mode.h>
+
+#include "i865.h"
+#include "raminit.h"
+
+struct dimm_size {
+	unsigned int side1;
+	unsigned int side2;
+};
+
+static const uint32_t refresh_frequency[] = {
+	/* Relative frequency (array value) of each E7501 Refresh Mode Select
+	 * (RMS) value (array index)
+	 * 0 == least frequent refresh (longest interval between refreshes)
+	 * [0] disabled  -> 0
+	 * [1] 15.6 usec -> 2
+	 * [2]  7.8 usec -> 3
+	 * [3] 64   usec -> 1
+	 * [4] reserved  -> 0
+	 * [5] reserved  -> 0
+	 * [6] reserved  -> 0
+	 * [7] 64 clocks -> 4
+	 */
+	0, 2, 3, 1, 0, 0, 0, 4
+};
+
+static const uint32_t refresh_rate_map[] = {
+	/* Map the JEDEC spd refresh rates (array index) to i855 Refresh Mode
+	 * Select values (array value)
+	 * These are all the rates defined by JESD21-C Appendix D, Rev. 1.0
+	 * The i855 supports only 15.6 us (1), 7.8 us (2) and
+	 * 64 clock (481 ns) (7) refresh.
+	 * [0] ==  15.625 us -> 15.6 us
+	 * [1] ==   3.9   us -> 481  ns
+	 * [2] ==   7.8   us ->  7.8 us
+	 * [3] ==  31.3   us -> 15.6 us
+	 * [4] ==  62.5   us -> 15.6 us
+	 * [5] == 125     us -> 15.6 us
+	 */
+	1, 7, 2, 1, 1, 1
+};
+
+#define MAX_SPD_REFRESH_RATE ((sizeof(refresh_rate_map) / sizeof(uint32_t)) - 1)
+
+static inline int spd_read_byte(unsigned device, unsigned address)
+//static int spd_read_byte(unsigned device, unsigned address)
+{
+        return smbus_read_byte(device, address);
+}
+
+static void set_initialization_complete(void)
+{
+	printk(BIOS_DEBUG, "Setting initialization complete (DRC bit 29)\n");
+	MCHBAR32(DRC) |= RAM_INITIALIZATION_COMPLETE;
+}
+
+//static void do_ram_command(u32 command)
+static void do_ram_command(uint8_t command, uint16_t jedec_mode_bits)
+{
+	int i;
+	u32 reg32;
+//	uint8_t dimm_start_32M_multiple = 0;
+	uint8_t dimm_start_64M_multiple = 0;
+	uint16_t i855_mode_bits = jedec_mode_bits;
+
+	/* Configure the RAM command. */
+//	reg32 = pci_read_config32(NORTHBRIDGE_MMC, DRC);
+	reg32 = MCHBAR32(DRC);
+	reg32 &= ~(7 << 4);
+	reg32 |= (command << 4);
+	printk(BIOS_DEBUG, "  Sending RAM command 0x%08x\n", reg32);
+//	pci_write_config32(NORTHBRIDGE_MMC, DRC, reg32);
+	MCHBAR32(DRC) = reg32;
+
+        // RAM_COMMAND_NORMAL is an exception.
+        // It affects only the memory controller and does not need to be "sent" to the DIMMs.
+
+        if (command != RAM_COMMAND_NORMAL) {
+
+                // Send the command to all DIMMs by accessing a memory location within each
+                // NOTE: for mode select commands, some of the location address bits
+                // are part of the command
+
+                // Map JEDEC mode bits to i855
+                if (command == RAM_COMMAND_MRS || command == RAM_COMMAND_EMRS) {
+			/* Host address lines [13:3] map to DIMM address lines [11, 9:0] */
+			// i855_mode_bits = ((jedec_mode_bits & 0x800) << (13 - 11)) | ((jedec_mode_bits & 0x3ff) << (12 - 9));
+			/* Host address lines [13:3] map to DIMM address lines [5:1] */
+			// i855_mode_bits = ((jedec_mode_bits & 0x800) << (13 - 11)) | ((jedec_mode_bits & 0x3ff) << (6 - 1));
+			i855_mode_bits = ((jedec_mode_bits & 0x800) << (13 - 11)) | ((jedec_mode_bits & 0x3f) << (6 - 1));
+                }
+
+                for (i = 0; i < (DIMM_SOCKETS * 2); ++i) {
+//                        uint8_t dimm_end_32M_multiple = pci_read_config8(NORTHBRIDGE_MMC, DRB + i);
+			/* i865 uses a granularity of 64 megabyte */
+                        uint8_t dimm_end_64M_multiple = MCHBAR8(DRB + i);
+//                        if (dimm_end_32M_multiple > dimm_start_32M_multiple) {
+                        if (dimm_end_64M_multiple > dimm_start_64M_multiple) {
+
+//                                uint32_t dimm_start_address = dimm_start_32M_multiple << 25;
+                                uint32_t dimm_start_address = dimm_start_64M_multiple << 25;
+				printk(BIOS_DEBUG, "  Sending RAM command to 0x%08x\n", dimm_start_address + i855_mode_bits);
+                                //read32(dimm_start_address + i855_mode_bits);
+								printk(BIOS_DEBUG, "  /* skipping read32() */\n");
+								printk(BIOS_DEBUG, "  Sent. dimm_start_address = 0x%x and i855_mode_bits = 0x%x\n", dimm_start_address, i855_mode_bits);
+
+                                // Set the start of the next DIMM
+//                                dimm_start_32M_multiple = dimm_end_32M_multiple;
+                                dimm_start_64M_multiple = dimm_end_64M_multiple;
+                        }
+		}
+	}
+}
+
+static void sdram_enable(void)
+{
+	int i;
+
+	print_debug("Ram enable 1\n");
+	delay();
+	delay();
+
+	/* NOP command */
+	printk(BIOS_DEBUG, " NOP\n");
+	do_ram_command(RAM_COMMAND_NOP, 0);
+	delay();
+	delay();
+	delay();
+
+	/* Pre-charge all banks (at least 200 us after NOP) */
+	printk(BIOS_DEBUG, " Pre-charging all banks\n");
+	do_ram_command(RAM_COMMAND_PRECHARGE, 0);
+	delay();
+	delay();
+	delay();
+
+	printk(BIOS_DEBUG, "Ram enable 4\n");
+	do_ram_command(RAM_COMMAND_EMRS, SDRAM_EXTMODE_DLL_ENABLE);
+	delay();
+	delay();
+	delay();
+
+	print_debug("Ram enable 5\n");
+	do_ram_command(RAM_COMMAND_MRS, VG85X_MODE | SDRAM_MODE_DLL_RESET);
+
+	print_debug("Ram enable 6\n");
+	do_ram_command(RAM_COMMAND_PRECHARGE, 0);
+	delay();
+	delay();
+	delay();
+
+	/* 8 CBR refreshes (Auto Refresh) */
+	printk(BIOS_DEBUG, " 8 CBR refreshes\n");
+	for(i = 0; i < 8; i++) {
+		do_ram_command(RAM_COMMAND_CBR, 0);
+		delay();
+		delay();
+		delay();
+	}
+
+	printk(BIOS_DEBUG, "Ram enable 8\n");
+	do_ram_command(RAM_COMMAND_MRS, VG85X_MODE | SDRAM_MODE_NORMAL);
+
+	/* Set GME-M Mode Select bits back to NORMAL operation mode */
+	printk(BIOS_DEBUG, " Normal operation mode\n");
+	do_ram_command(RAM_COMMAND_NORMAL, 0);
+/*	delay();
+	delay();
+	delay();
+
+	print_debug("Ram enable 9\n");
+	set_initialize_complete();
+
+	delay();
+	delay();
+	delay();
+	delay();
+	delay();
+
+	print_debug("After configuration:\n");
+*/
+	/* dump_pci_devices(); */
+
+	/*
+	print_debug("\n\n***** RAM TEST *****\n");
+	ram_check(0, 0xa0000);
+	ram_check(0x100000, 0x40000000);
+	*/
+}
+
+//static void ram_read32(u8 dimm_start, u32 offset)
+//{
+	/* not implemented */
+//}
+
+//static void initialize_dimm_rows(void)
+//{
+	/* copied from i82830/raminit.c */
+	/* not implemented */
+//}
+
+static void die_on_spd_error(int spd_return_value)
+{
+	if (spd_return_value < 0)
+		printk(BIOS_DEBUG, "Error reading SPD info: got %d\n", spd_return_value);
+/*
+	if (spd_return_value < 0)
+		die("Error reading SPD info\n");
+*/
+}
+
+static struct dimm_size sdram_spd_get_page_size(u8 dimm_socket_address)
+{
+	uint16_t module_data_width;
+	int value;
+	struct dimm_size pgsz;
+
+	pgsz.side1 = 0;
+	pgsz.side2 = 0;
+
+	// Side 1
+	value = spd_read_byte(dimm_socket_address, SPD_NUM_COLUMNS);
+	die_on_spd_error(value);
+
+	pgsz.side1 = value & 0xf;	// # columns in bank 1
+
+	/* Get the module data width and convert it to a power of two */
+	value = spd_read_byte(dimm_socket_address, SPD_MODULE_DATA_WIDTH_MSB);
+	die_on_spd_error(value);
+
+	module_data_width = (value & 0xff) << 8;
+
+	value = spd_read_byte(dimm_socket_address, SPD_MODULE_DATA_WIDTH_LSB);
+	die_on_spd_error(value);
+
+	module_data_width |= (value & 0xff);
+
+	pgsz.side1 += log2(module_data_width);
+
+	/* side two */
+	value = spd_read_byte(dimm_socket_address, SPD_NUM_DIMM_BANKS);
+	die_on_spd_error(value);
+
+	if (value > 2)
+		printk(BIOS_DEBUG, "Bad SPD value\n");
+
+	if (value == 2) {
+		pgsz.side2 = pgsz.side1;	// Assume symmetric banks until we know differently
+		value = spd_read_byte(dimm_socket_address, SPD_NUM_COLUMNS);
+		die_on_spd_error(value);
+
+		if ((value & 0xf0) != 0) {
+			// Asymmetric banks
+			pgsz.side2 -= value & 0xf;	/* Subtract out columns on side 1 */
+			pgsz.side2 += (value >> 4) & 0xf;	/* Add in columns on side 2 */
+		}
+	}
+
+	return pgsz;
+}
+
+/**
+ * Read the width in bits of each DIMM side's DRAMs via SPD (i.e. 4, 8, 16).
+ *
+ * @param dimm_socket_address SMBus address of DIMM socket to interrogate.
+ * @return Width in bits of each DIMM side's DRAMs.
+ */
+static struct dimm_size sdram_spd_get_width(u8 dimm_socket_address)
+{
+	int value;
+	struct dimm_size width;
+
+	width.side1 = 0;
+	width.side2 = 0;
+
+	value = spd_read_byte(dimm_socket_address, SPD_PRIMARY_SDRAM_WIDTH);
+	die_on_spd_error(value);
+
+	width.side1 = value & 0x7f;	// Mask off bank 2 flag
+
+	if (value & 0x80) {
+		width.side2 = width.side1 << 1;	// Bank 2 exists and is double-width
+	} else {
+		// If bank 2 exists, it's the same width as bank 1
+		value = spd_read_byte(dimm_socket_address, SPD_NUM_DIMM_BANKS);
+		die_on_spd_error(value);
+
+		switch (value) {
+		case 2:
+			width.side2 = width.side1;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	return width;
+}
+
+/**
+ * Calculate the log base 2 size in bits of both DIMM sides.
+ *
+ * log2(# bits) = (# columns) + log2(data width) +
+ *                (# rows) + log2(banks per SDRAM)
+ *
+ * Note that it might be easier to use SPD byte 31 here, it has the DIMM size
+ * as a multiple of 4MB. The way we do it now we can size both sides of an
+ * asymmetric DIMM.
+ *
+ * @param dimm SMBus address of DIMM socket to interrogate.
+ * @return log2(number of bits) for each side of the DIMM.
+ */
+static struct dimm_size spd_get_dimm_size(unsigned dimm)
+{
+	int value;
+
+	// Start with log2(page size)
+	struct dimm_size sz = sdram_spd_get_page_size(dimm);
+
+	if (sz.side1 > 0) {
+		value = spd_read_byte(dimm, SPD_NUM_ROWS);
+		die_on_spd_error(value);
+
+		sz.side1 += value & 0xf;
+
+		if (sz.side2 > 0) {
+			// Double-sided DIMM
+			if (value & 0xF0)
+				sz.side2 += value >> 4;	// Asymmetric
+			else
+				sz.side2 += value;	// Symmetric
+		}
+
+		value = spd_read_byte(dimm, SPD_NUM_BANKS_PER_SDRAM);
+		die_on_spd_error(value);
+
+		value = log2(value);
+		sz.side1 += value;
+		if (sz.side2 > 0)
+			sz.side2 += value;
+	}
+
+	return sz;
+}
+
+// static void set_dram_row_boundaries(void) { /* TODO */ }
+// static void set_dram_row_attributes(void) { /* TODO */ }
+// static void set_dram_timing(void) { /* TODO */ }
+// static void sdram_set_registers(void) { /* TODO */ }
+
+static uint8_t spd_get_supported_dimms(void)
+{
+	int i;
+	uint8_t dimm_mask = 0;
+
+//	for (i = 0; i < DIMM_SOCKETS; i++) {
+	for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
+		u8 dimm = DIMM0 + i;
+
+		struct dimm_size page_size;
+		struct dimm_size sdram_width;
+
+		int spd_value;
+
+		if (dimm == 0)
+			continue;
+
+		if (spd_read_byte(dimm, SPD_MEMORY_TYPE) != SPD_MEMORY_TYPE_SDRAM_DDR)
+			// print a little warning, maybe?
+			continue;
+
+		if ((spd_value = spd_read_byte(dimm, SPD_MODULE_VOLTAGE)) != SPD_VOLTAGE_SSTL2) {
+			printk(BIOS_DEBUG, "Skipping DIMM with unsupported voltage: %02x\n", spd_value);
+			continue;
+		}
+
+		page_size = sdram_spd_get_page_size(dimm);
+		sdram_width = sdram_spd_get_width(dimm);
+
+		// Validate DIMM page size
+		// The i855 only supports page sizes of 4, 8, 16 KB per channel
+		// NOTE:  4 KB =  32 Kb = 2^15
+		//       16 KB = 128 Kb = 2^17
+
+		if ((page_size.side1 < 15) || (page_size.side1 > 17)) {
+			printk(BIOS_DEBUG, "Skipping DIMM with unsupported page size: %d\n", page_size.side1);
+			continue;
+		}
+
+		// If DIMM is double-sided, verify side2 page size
+		if (page_size.side2 != 0) {
+			if ((page_size.side2 < 15) || (page_size.side2 > 17)) {
+				printk(BIOS_DEBUG, "Skipping DIMM with unsupported page size: %d\n", page_size.side2);
+				continue;
+			}
+		}
+		// Validate SDRAM width
+		// The i855 only supports x8 and x16 devices
+		if ((sdram_width.side1 != 8) && (sdram_width.side1 != 16)) {
+			printk(BIOS_DEBUG, "Skipping DIMM with unsupported width: %d\n", sdram_width.side2);
+			continue;
+		}
+
+		// If DIMM is double-sided, verify side2 width
+		if (sdram_width.side2 != 0) {
+			if ((sdram_width.side2 != 8)
+			    && (sdram_width.side2 != 16)) {
+				printk(BIOS_DEBUG, "Skipping DIMM with unsupported width: %d\n", sdram_width.side2);
+				continue;
+			}
+		}
+		// Made it through all the checks, this DIMM is usable
+		dimm_mask |= (1 << i);
+	}
+
+	return dimm_mask;
+}
+
+static void spd_set_row_attributes(uint8_t dimm_mask)
+{
+	int i;
+	uint16_t row_attributes = 0;
+
+	for (i = 0; i < DIMM_SOCKETS; i++) {
+		u8 dimm = DIMM0 + i;
+		struct dimm_size page_size;
+		struct dimm_size sdram_width;
+
+		if (!(dimm_mask & (1 << i))) {
+//			row_attributes |= 0x77 << (i << 3);
+			row_attributes |= 0x0 << (i << 3); // default value of DRA on i865 is 0x0
+			continue;	// This DIMM not usable
+		}
+
+		// Get the relevant parameters via SPD
+		page_size = sdram_spd_get_page_size(dimm);
+		sdram_width = sdram_spd_get_width(dimm);
+
+		// Update the DRAM Row Attributes.
+		// Page size is encoded as log2(page size in bits) - log2(2 KB) or 4 KB == 1, 8 KB == 3, 16KB == 3
+// i865: Page size is encoded as log2(page size in bits) - log2(2 KB) or 4 KB == 0, 8 KB == 1, 16KB == 2, 32KB == 3
+		// NOTE:  2 KB =  16 Kb = 2^14
+//		row_attributes |= (page_size.side1 - 14) << (i << 3);	// Side 1 of each DIMM is an EVEN row
+		// i865: NOTE:  4 KB =  32 Kb = 2^15
+		row_attributes |= (page_size.side1 - 15) << (i << 3);	// Side 1 of each DIMM is an EVEN row
+
+		if (sdram_width.side2 > 0)
+//			row_attributes |= (page_size.side2 - 14) << ((i << 3) + 4);	// Side 2 is ODD
+			row_attributes |= (page_size.side2 - 15) << ((i << 3) + 4);	// Side 2 is ODD
+//		else
+//			row_attributes |= 7 << ((i << 3) + 4); // "not populated", i865 doesn't have that bit
+
+		/* on the asrock pi465gv (rev g/a 1.11),
+		physical ram slots "DDR2" and "DDR1"
+		are logically slots 2 and 1 (or 1 and 0) */
+//		printk(BIOS_DEBUG, "DRA%d: 0x%x\n", i, row_attributes);
+//		printk(BIOS_DEBUG, "DRA: row %d,%d: 0x%x\n", i, i + 1, row_attributes);
+		printk(BIOS_DEBUG, "DRA: row %d,%d: 0x%x\n", i * 2, i * 2 + 1, row_attributes);
+		MCHBAR8(DRA + i) = row_attributes;
+
+		/* go to the next DIMM */
+	}
+
+//	PRINTK_DEBUG("DRA: %04x\n", row_attributes);
+
+	/* Write the new row attributes register */
+//	pci_write_config16(NORTHBRIDGE_MMC, DRA, row_attributes);
+}
+
+static void spd_set_dram_controller_mode(uint8_t dimm_mask)
+{
+	int i;
+
+	// Initial settings
+//	u32 controller_mode = pci_read_config32(NORTHBRIDGE_MMC, DRC);
+	u32 controller_mode = MCHBAR32(DRC);
+//	u32 system_refresh_mode = (controller_mode >> 7) & 7;
+	u32 system_refresh_mode = (controller_mode >> 8) & 7; // i865: RMS is at bits 10:8
+
+//	controller_mode |= (1 << 20);  // ECC
+//	controller_mode |= (1 << 15);  // RAS lockout
+//	controller_mode |= (1 << 12);  // Address Tri-state enable (ADRTRIEN), FIXME: how is this detected?????
+//	controller_mode |= (2 << 10);  // FIXME: Undocumented, really needed?????
+
+//	for (i = 0; i < DIMM_SOCKETS; i++) {
+	for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
+		u8 dimm = DIMM0 + i;
+		uint32_t dimm_refresh_mode;
+		int value;
+//		u8 tRCD, tRP;
+
+		if (!(dimm_mask & (1 << i))) {
+			continue;	// This DIMM not usable
+		}
+
+		// Disable ECC mode if any one of the DIMMs does not support ECC
+// no ECC on i865, disabling
+//		value = spd_read_byte(dimm, SPD_DIMM_CONFIG_TYPE);
+//		die_on_spd_error(value);
+//		if (value != ERROR_SCHEME_ECC)
+//			controller_mode &= ~(3 << 20);
+
+		value = spd_read_byte(dimm, SPD_REFRESH);
+		die_on_spd_error(value);
+		value &= 0x7f;	// Mask off self-refresh bit
+		if (value > MAX_SPD_REFRESH_RATE) {
+			print_err("unsupported refresh rate\n");
+			continue;
+		}
+		// Get the appropriate i855 refresh mode for this DIMM
+		dimm_refresh_mode = refresh_rate_map[value];
+		if (dimm_refresh_mode > 7) {
+			print_err("unsupported refresh rate\n");
+			continue;
+		}
+		// If this DIMM requires more frequent refresh than others,
+		// update the system setting
+		if (refresh_frequency[dimm_refresh_mode] >
+		    refresh_frequency[system_refresh_mode])
+			system_refresh_mode = dimm_refresh_mode;
+
+		/* FIXME: is this correct? */
+//		tRCD = spd_read_byte(dimm, SPD_tRCD);
+//		tRP = spd_read_byte(dimm, SPD_tRP);
+// no RAS lockout on i865
+//		if (tRCD != tRP) {
+//			PRINTK_DEBUG(" Disabling RAS lockouk due to tRCD (%d) != tRP (%d)\n", tRCD, tRP);
+//			printk(BIOS_DEBUG, " Disabling RAS lockouk due to tRCD (%d) != tRP (%d)\n", tRCD, tRP);
+//			controller_mode &= ~(1 << 15);
+//		}
+
+		/* go to the next DIMM */
+	}
+
+//	controller_mode &= ~(7 << 7);
+//	controller_mode |= (system_refresh_mode << 7);
+	controller_mode &= ~(7 << 8);
+	controller_mode |= (system_refresh_mode << 8);
+//	PRINTK_DEBUG("DRC: %08x\n", controller_mode);
+	printk(BIOS_DEBUG, "DRC: %08x\n", controller_mode);
+
+//	pci_write_config32(NORTHBRIDGE_MMC, DRC, controller_mode);
+	MCHBAR32(DRC) = controller_mode;
+}
+
+static void spd_set_dram_timing(uint8_t dimm_mask)
+{
+	int i;
+	u32 dram_timing;
+
+	// CAS# latency bitmasks in SPD_ACCEPTABLE_CAS_LATENCIES format
+	// NOTE: i82822 supports only 2.0 and 2.5
+//	uint32_t system_compatible_cas_latencies = SPD_CAS_LATENCY_2_0 | SPD_CAS_LATENCY_2_5;
+
+/*  SPD_CAS_LATENCY_2_0 | SPD_CAS_LATENCY_2_5 | SPD_CAS_LATENCY_3_0 == 0x1c */
+	uint32_t system_compatible_cas_latencies = SPD_CAS_LATENCY_2_0 | SPD_CAS_LATENCY_2_5 | SPD_CAS_LATENCY_3_0;
+//	uint32_t system_compatible_cas_latencies = DRT_CAS_2_0 | DRT_CAS_2_5 | DRT_CAS_3_0;
+	uint8_t slowest_row_precharge = 0;
+	uint8_t slowest_ras_cas_delay = 0;
+	uint8_t slowest_active_to_precharge_delay = 0;
+
+//	for (i = 0; i < DIMM_SOCKETS; i++) {
+	for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
+		u8 dimm = DIMM0 + i;
+		int value;
+		uint32_t current_cas_latency;
+		uint32_t dimm_compatible_cas_latencies;
+		if (!(dimm_mask & (1 << i)))
+			continue;	// This DIMM not usable
+
+		value = spd_read_byte(dimm, SPD_ACCEPTABLE_CAS_LATENCIES);
+		printk(BIOS_DEBUG, "SPD_ACCEPTABLE_CAS_LATENCIES: %d\n", value);
+		die_on_spd_error(value);
+
+		dimm_compatible_cas_latencies = value & 0x7f;	// Start with all supported by DIMM
+		printk(BIOS_DEBUG, "dimm_compatible_cas_latencies #1: %d\n", dimm_compatible_cas_latencies);
+
+		current_cas_latency = 1 << log2(dimm_compatible_cas_latencies);	// Max supported by DIMM
+		printk(BIOS_DEBUG, "current_cas_latency: %d\n", current_cas_latency);
+
+		// Can we support the highest CAS# latency?
+		value = spd_read_byte(dimm, SPD_MIN_CYCLE_TIME_AT_CAS_MAX);
+		die_on_spd_error(value);
+		printk(BIOS_DEBUG, "SPD_MIN_CYCLE_TIME_AT_CAS_MAX: %d.%d\n", value >> 4, value & 0xf);
+
+		// NOTE: At 133 MHz, 1 clock == 7.52 ns
+		if (value > 0x75) {
+			// Our bus is too fast for this CAS# latency
+			// Remove it from the bitmask of those supported by the DIMM that are compatible
+			dimm_compatible_cas_latencies &= ~current_cas_latency;
+			printk(BIOS_DEBUG, "dimm_compatible_cas_latencies #2: %d\n", dimm_compatible_cas_latencies);
+		}
+		// Can we support the next-highest CAS# latency (max - 0.5)?
+
+		current_cas_latency >>= 1;
+		if (current_cas_latency != 0) {
+			value = spd_read_byte(dimm, SPD_SDRAM_CYCLE_TIME_2ND);
+			die_on_spd_error(value);
+			printk(BIOS_DEBUG, "SPD_SDRAM_CYCLE_TIME_2ND: %d.%d\n", value >> 4, value & 0xf);
+			if (value > 0x75) {
+				dimm_compatible_cas_latencies &= ~current_cas_latency;
+				printk(BIOS_DEBUG, "dimm_compatible_cas_latencies #2: %d\n", dimm_compatible_cas_latencies);
+			}
+		}
+		// Can we support the next-highest CAS# latency (max - 1.0)?
+		current_cas_latency >>= 1;
+		if (current_cas_latency != 0) {
+			value = spd_read_byte(dimm, SPD_SDRAM_CYCLE_TIME_3RD);
+			printk(BIOS_DEBUG, "SPD_SDRAM_CYCLE_TIME_3RD: %d.%d\n", value >> 4, value & 0xf);
+			die_on_spd_error(value);
+			if (value > 0x75) {
+				dimm_compatible_cas_latencies &= ~current_cas_latency;
+				printk(BIOS_DEBUG, "dimm_compatible_cas_latencies #2: %d\n", dimm_compatible_cas_latencies);
+			}
+		}
+		// Restrict the system to CAS# latencies compatible with this DIMM
+		system_compatible_cas_latencies &= dimm_compatible_cas_latencies;
+
+		value = spd_read_byte(dimm, SPD_MIN_ROW_PRECHARGE_TIME);
+		die_on_spd_error(value);
+		if (value > slowest_row_precharge)
+			slowest_row_precharge = value;
+
+		value = spd_read_byte(dimm, SPD_MIN_RAS_TO_CAS_DELAY);
+		die_on_spd_error(value);
+		if (value > slowest_ras_cas_delay)
+			slowest_ras_cas_delay = value;
+
+		value = spd_read_byte(dimm, SPD_MIN_ACTIVE_TO_PRECHARGE_DELAY);
+		die_on_spd_error(value);
+		if (value > slowest_active_to_precharge_delay)
+			slowest_active_to_precharge_delay = value;
+
+		/* go to the next DIMM */
+	}
+	printk(BIOS_DEBUG, "CAS latency: %d\n", system_compatible_cas_latencies);
+
+//	dram_timing = pci_read_config32(NORTHBRIDGE_MMC, DRT);
+	dram_timing = MCHBAR32(DRT);
+//	dram_timing &= ~(DRT_CAS_MASK | DRT_TRP_MASK | DRT_RCD_MASK);
+	dram_timing &= ~(DRT_CAS_MASK | DRT_TRP_MASK | DRT_TRCD_MASK);
+	printk(BIOS_DEBUG, "DRT: %08x\n", dram_timing);
+
+	if (system_compatible_cas_latencies & SPD_CAS_LATENCY_2_0) {
+		dram_timing |= DRT_CAS_2_0;
+	} else if (system_compatible_cas_latencies & SPD_CAS_LATENCY_2_5) {
+		dram_timing |= DRT_CAS_2_5;
+	} else if (system_compatible_cas_latencies & SPD_CAS_LATENCY_3_0) {
+		dram_timing |= DRT_CAS_3_0;
+	} else
+		die("No CAS# latencies compatible with all DIMMs!!\n");
+
+//	uint32_t current_cas_latency = dram_timing & DRT_CAS_MASK;
+
+	/* tRP */
+
+	printk(BIOS_DEBUG, "slowest_row_precharge: %d.%d\n", slowest_row_precharge >> 2, slowest_row_precharge & 0x3);
+	// i855 supports only 2, 3 or 4 clocks for tRP
+	if (slowest_row_precharge > (30 << 2)) // 30 = 11110b = tRCD = 2 dram clocks, tCL = reserved
+		die("unsupported DIMM tRP");	//  > 30.0 ns: 5 or more clocks
+	else if (slowest_row_precharge > ( (22 << 2) | (2 << 0) ))
+	// 22 = 10110b = tRCD = 2 dram clocks, tCL = 2
+	// 2 = 10b = 2 dram clocks (tRP)
+		dram_timing |= DRT_TRP_4;	//  > 22.5 ns: 4 or more clocks
+	else if (slowest_row_precharge > (15 << 2)) // 15 = 1111b = tRCD = reserved, tCL = 2
+		dram_timing |= DRT_TRP_3;	//  > 15.0 ns: 3 clocks
+	else
+		dram_timing |= DRT_TRP_2;	// <= 15.0 ns: 2 clocks
+
+	/*  tRCD */
+
+	printk(BIOS_DEBUG, "slowest_ras_cas_delay: %d.%d\n", slowest_ras_cas_delay >> 2, slowest_ras_cas_delay & 0x3);
+	// i855 supports only 2, 3 or 4 clocks for tRCD
+	if (slowest_ras_cas_delay > ((30 << 2)))
+		die("unsupported DIMM tRCD");	//  > 30.0 ns: 5 or more clocks
+	else if (slowest_ras_cas_delay > ((22 << 2) | (2 << 0)))
+//		dram_timing |= DRT_RCD_4;	//  > 22.5 ns: 4 or more clocks
+		dram_timing |= DRT_TRCD_4;	//  > 22.5 ns: 4 or more clocks
+	else if (slowest_ras_cas_delay > (15 << 2))
+//		dram_timing |= DRT_RCD_3;	//  > 15.0 ns: 3 clocks
+		dram_timing |= DRT_TRCD_3;	//  > 15.0 ns: 3 clocks
+	else
+//		dram_timing |= DRT_RCD_2;	// <= 15.0 ns: 2 clocks
+		dram_timing |= DRT_TRCD_2;	// <= 15.0 ns: 2 clocks
+
+	/* tRAS, min */
+
+	printk(BIOS_DEBUG, "slowest_active_to_precharge_delay: %d\n", slowest_active_to_precharge_delay);
+	// i855 supports only 5, 6, 7 or 8 clocks for tRAS
+	// 5 clocks ~= 37.6 ns, 6 clocks ~= 45.1 ns, 7 clocks ~= 52.6 ns, 8 clocks ~= 60.1 ns
+	// TODO
+	if (slowest_active_to_precharge_delay > 60)
+		die("unsupported DIMM tRAS");	// > 52 ns:      8 or more clocks
+	else if (slowest_active_to_precharge_delay > 52)
+		dram_timing |= DRT_TRAS_MIN_8;	// 46-52 ns:     7 clocks
+	else if (slowest_active_to_precharge_delay > 45)
+		dram_timing |= DRT_TRAS_MIN_7;	// 46-52 ns:     7 clocks
+	else if (slowest_active_to_precharge_delay > 37)
+		dram_timing |= DRT_TRAS_MIN_6;	// 38-45 ns:     6 clocks
+	else
+		dram_timing |= DRT_TRAS_MIN_5;	// < 38 ns:      5 clocks
+
+	/* FIXME: guess work starts here...
+	 *
+	 * Intel refers to DQ turn-arround values for back to calculate the values,
+	 * but i have no idea what this means
+	 */
+
+	/*
+	 * Back to Back Read-Write command spacing (DDR, different Rows/Bank)
+	 */
+	/* Set to a 3 clock back to back read to write turn around.
+	 *  2 is a good delay if the CAS latency is 2.0 */
+//	dram_timing &= ~(3 << 28);
+//	if (current_cas_latency == DRT_CAS_2_0)
+//		dram_timing |= (2 << 28);	// 2 clocks
+//	else
+//		dram_timing |= (1 << 28);	// 3 clocks
+
+	/*
+	 * Back to Back Read-Write command spacing (DDR, same or different Rows/Bank)
+	 */
+//	dram_timing &= ~(3 << 26);
+//	if (current_cas_latency == DRT_CAS_2_0)
+//		dram_timing |= (2 << 26);	// 5 clocks
+//	else
+//		dram_timing |= (1 << 26);	// 6 clocks
+
+	/*
+	 * Back To Back Read-Read commands spacing (DDR, different Rows):
+	 */
+//	dram_timing &= ~(1 << 25);
+//	dram_timing |= (1 << 25);	// 3 clocks
+
+	printk(BIOS_DEBUG, "DRT: %08x\n", dram_timing);
+//	pci_write_config32(NORTHBRIDGE_MMC, DRT, dram_timing);
+	MCHBAR32(DRT) = dram_timing;
+}
+
+static void spd_set_dram_size(uint8_t dimm_mask)
+{
+	int i;
+	int total_dram = 0;
+	uint32_t drb_reg = 0;
+
+//	for (i = 0; i < DIMM_SOCKETS; i++) {
+	for (i = 0; i < (2 * DIMM_SOCKETS); i++) {
+		u8 dimm = DIMM0 + i;
+		struct dimm_size sz;
+
+		if (!(dimm_mask & (1 << i))) {
+			/* fill values even for not present DIMMs */
+//			drb_reg |= (total_dram << (i * 16));
+//			drb_reg |= (total_dram << ((i * 16) + 8));
+			drb_reg |= (total_dram << (i * 32));
+			drb_reg |= (total_dram << ((i * 32) + 8));
+
+			continue;	// This DIMM not usable
+		}
+		sz = spd_get_dimm_size(dimm);
+
+//		total_dram += (1 << (sz.side1 - 28));
+//		drb_reg |= (total_dram << (i * 16));
+		total_dram += (1 << (sz.side1 - 30));
+		drb_reg |= (total_dram << (i * 32));
+
+//		total_dram += (1 << (sz.side2 - 28));
+//		drb_reg |= (total_dram << ((i * 16) + 8));
+		total_dram += (1 << (sz.side2 - 30));
+		drb_reg |= (total_dram << ((i * 32) + 8));
+
+		printk(BIOS_DEBUG, "DRB: %08x\n", drb_reg);
+		MCHBAR8(DRB + i) = drb_reg;
+	}
+//	printk(BIOS_DEBUG, "DRB: %08x\n", drb_reg);
+//	pci_write_config32(NORTHBRIDGE_MMC, DRB, drb_reg);
+}
+
+static void enable_refresh(void)
+{
+	printk(BIOS_DEBUG, "Enabling refresh (RAM_COMMAND_REFRESH)\n");
+	MCHBAR32(DRC) |= RAM_COMMAND_REFRESH << 8;
+}
+
+/* from src/northbridge/intel/i945/raminit.c and util/inteltool/memory.c */
+static void sdram_dump_mchbar_registers(void)
+{
+	int i;
+
+	printk(BIOS_DEBUG, "Dumping MCHBAR registers:\n");
+	for (i = 0; i < 0xffff; i += 4) {
+		if ( (MCHBAR32(i) == 0) || (MCHBAR32(i) == 0xffffffff) )
+			continue;
+		switch (i) {
+		case (DRB + 0):
+			printk(BIOS_DEBUG, " DRB0: 0x%x\n", MCHBAR32(i));
+		case (DRB + 1):
+			printk(BIOS_DEBUG, " DRB1: 0x%x\n", MCHBAR32(i));
+		case (DRB + 2):
+			printk(BIOS_DEBUG, " DRB2: 0x%x\n", MCHBAR32(i));
+		case (DRB + 3):
+			printk(BIOS_DEBUG, " DRB3: 0x%x\n", MCHBAR32(i));
+		case (DRB + 4):
+			printk(BIOS_DEBUG, " DRB4: 0x%x\n", MCHBAR32(i));
+		case (DRB + 5):
+			printk(BIOS_DEBUG, " DRB5: 0x%x\n", MCHBAR32(i));
+		case (DRB + 6):
+			printk(BIOS_DEBUG, " DRB6: 0x%x\n", MCHBAR32(i));
+		case (DRB + 7):
+			printk(BIOS_DEBUG, " DRB7: 0x%x\n", MCHBAR32(i));
+
+		case (DRA + 0):
+			printk(BIOS_DEBUG, " DRA0: 0x%x\n", MCHBAR32(i));
+		case (DRA + 1):
+			printk(BIOS_DEBUG, " DRA1: 0x%x\n", MCHBAR32(i));
+		case (DRA + 2):
+			printk(BIOS_DEBUG, " DRA2: 0x%x\n", MCHBAR32(i));
+		case (DRA + 3):
+			printk(BIOS_DEBUG, " DRA3: 0x%x\n", MCHBAR32(i));
+		case (DRA + 4):
+			printk(BIOS_DEBUG, " DRA4: 0x%x\n", MCHBAR32(i));
+		case (DRA + 5):
+			printk(BIOS_DEBUG, " DRA5: 0x%x\n", MCHBAR32(i));
+		case (DRA + 6):
+			printk(BIOS_DEBUG, " DRA6: 0x%x\n", MCHBAR32(i));
+		case (DRA + 7):
+			printk(BIOS_DEBUG, " DRA7: 0x%x\n", MCHBAR32(i));
+
+		case DRT:
+			printk(BIOS_DEBUG, " DRT: 0x%x\n", MCHBAR32(i));
+		case DRC:
+			printk(BIOS_DEBUG, " DRC: 0x%x\n", MCHBAR32(i));
+		default:
+			printk(BIOS_DEBUG, "0x%x: 0x%x\n", i, MCHBAR32(i));
+		}
+	}
+}
+
+static void early_northbridge_set_registers(void)
+{
+	u8 reg8;
+
+	/* Undocumented register */
+	reg8 = pci_read_config8(NORTHBRIDGE, 0xf4);
+
+	/*
+	Writing 0x2 to northbridge register 0xf4
+	exposes the PCI registers of device 6.
+	*/
+	//reg8 |= 0x2; /* guesswork: the default value is 0x0 */
+	reg8 = 0x2;
+
+	printk(BIOS_DEBUG, "Enabling access to (the registers of) device 6\n");
+	pci_write_config8(NORTHBRIDGE, 0xf4, reg8);
+
+	printk(BIOS_DEBUG, "Configuring BAR6 as 0x%x\n", DEFAULT_MCHBAR);
+	pci_write_config32(NORTHBRIDGE_MMC, BAR6, DEFAULT_MCHBAR);
+
+	printk(BIOS_DEBUG, "Enabling Memory Access Enable (MAE) in PCICMD6\n");
+	pci_write_config16(NORTHBRIDGE_MMC, PCICMD6, 0x2);
+}
+
+static void northbridge_set_pam(void)
+{
+	printk(BIOS_DEBUG, "Configuring PAM0..PAM6\n");
+	pci_write_config8(NORTHBRIDGE, PAM0, 0x10);
+	pci_write_config8(NORTHBRIDGE, PAM1, 0x11);
+	pci_write_config8(NORTHBRIDGE, PAM2, 0x1);
+	pci_write_config8(NORTHBRIDGE, PAM3, 0x0);
+	pci_write_config8(NORTHBRIDGE, PAM4, 0x0);
+	pci_write_config8(NORTHBRIDGE, PAM5, 0x33);
+	pci_write_config8(NORTHBRIDGE, PAM6, 0x33);
+}
+
+static void northbridge_set_registers(void)
+{
+	printk(BIOS_DEBUG, "Configuring APBASE\n");
+	pci_write_config32(NORTHBRIDGE, APBASE, 0xfe800008);
+
+	printk(BIOS_DEBUG, "Configuring APSIZE\n");
+	pci_write_config8(NORTHBRIDGE, APSIZE, 0x3f);
+
+	printk(BIOS_DEBUG, "Configuring GC\n"); /* IVD=0, IGDIS=0, GMS=8 megabyte */
+	pci_write_config8(NORTHBRIDGE, GC, 0x34);
+
+	printk(BIOS_DEBUG, "Configuring AMTT\n");
+	pci_write_config8(NORTHBRIDGE, AMTT, 0x20);
+
+	printk(BIOS_DEBUG, "Configuring LPTT\n");
+	pci_write_config8(NORTHBRIDGE, LPTT, 0x10);
+
+	printk(BIOS_DEBUG, "Configuring GMCHCFG\n");
+	pci_write_config16(NORTHBRIDGE, GMCHCFG, 0x40d);
+
+	printk(BIOS_DEBUG, "Configuring TOUD\n");
+	pci_write_config16(NORTHBRIDGE, TOUD, 0x1f80);
+
+	printk(BIOS_DEBUG, "Configuring PCISTS\n");
+	pci_write_config16(NORTHBRIDGE, PCISTS, 0x2009);
+
+	printk(BIOS_DEBUG, "Writing SVID and SID\n");
+	pci_write_config16(NORTHBRIDGE, SVID, 0x1849);
+	pci_write_config16(NORTHBRIDGE, SID, 0x2570);
+
+	printk(BIOS_DEBUG, "Configuring ERRSTS\n");
+	pci_write_config16(NORTHBRIDGE, ERRSTS, 0x100);
+}
+
+static void northbridge_set_undocumented_registers(void)
+{
+	u8 reg8;
+
+	printk(BIOS_DEBUG, "Configuring undocumented register 0x54\n");
+	/*
+	guesswork, the default value is 0x18 and 0x1c is the value from lspci -nnvvvxxx.
+	conclusion: add 0x4 */
+	reg8 = pci_read_config8(NORTHBRIDGE, 0x54);
+	reg8 |= 0x4;
+	pci_write_config8(NORTHBRIDGE, 0x54, reg8);
+
+	printk(BIOS_DEBUG, "Configuring undocumented register 0x9d\n");
+	reg8 = pci_read_config8(NORTHBRIDGE, 0xc9d);
+	reg8 |= 0x8;
+	pci_write_config8(NORTHBRIDGE, 0x9d, reg8);
+}
+
+//static void hardcoded_initialization(void)
+//{
+	// int i;
+
+//	printk(BIOS_DEBUG, "Configuring DRT\n");
+//	MCHBAR32(DRT) = 0x56e40d00; /* single-channel, 512MB in the first (physical) slot */
+//	printk(BIOS_DEBUG, "  DRT after configuring (should be 0x56e40d00): 0x%x\n", MCHBAR32(DRT));
+
+//	printk(BIOS_DEBUG, "Configuring DRB0..DRB7\n");
+
+	/* single-channel, 512MB in the first (physical) slot */
+//	MCHBAR8(DRB + 0) = 0x4;
+//	MCHBAR8(DRB + 1) = 0x8;
+//	MCHBAR8(DRB + 2) = 0x8;
+//	MCHBAR8(DRB + 3) = 0x8;
+//	MCHBAR8(DRB + 4) = 0x8;
+//	MCHBAR8(DRB + 5) = 0x8;
+//	MCHBAR8(DRB + 6) = 0x8;
+//	MCHBAR8(DRB + 7) = 0x8;
+	// for (i = 0; i < 8; i++) {
+		// printk(BIOS_DEBUG, "  DRB%i after configuring (should be 0x4 for DRB0, 0x8 for DRB1-7): 0x%x\n", i, MCHBAR8(DRB + i));
+	// }
+
+//	printk(BIOS_DEBUG, "Configuring DRA0..DRA7\n");
+
+	/* single-channel, 512MB in the first (physical) slot */
+//	MCHBAR8(DRA + 0) = 0x0;
+//	MCHBAR8(DRA + 1) = 0x11; // 8 kilobyte on each row
+//	MCHBAR8(DRA + 2) = 0x0;
+//	MCHBAR8(DRA + 3) = 0x0;
+	// for (i = 0; i < 8; i++) {
+		// printk(BIOS_DEBUG, "  DRA%i after configuring (should be 0x0 for DRA0, DRA2 and DRA3, 0x11 for DRA1: 0x%x\n",
+			// i, MCHBAR8(DRA + i));
+	// }
+
+	// BAR6_32(DRC) = 0x20104271;
+
+	// printk(BIOS_DEBUG, "All aboard the undocumented registers train :(\n");
+
+/*
+	MCHBAR32(0x6c) = 0xa801;
+	MCHBAR32(0xb0) = 0x40830;
+	MCHBAR32(0x100) = 0x89b;
+	MCHBAR32(0x104) = 0x4ad;
+	MCHBAR32(0x130) = 0x88d;
+	MCHBAR32(0x138) = 0x210843c;
+	MCHBAR32(0x140) = 0x1721c;
+	MCHBAR32(0x144) = 0xe380fff;
+	MCHBAR32(0x170) = 0x1a00018b;
+	MCHBAR32(0x1a0) = 0x3d0524fd;
+	MCHBAR32(0x200) = 0x1;
+	MCHBAR32(0x208) = 0x3937;
+	MCHBAR32(0x300) = 0x32;
+	MCHBAR32(0x800) = 0xdddddddd;
+*/
+	// sdram_dump_mchbar_registers(); // from i945
+//}
+
+static void sdram_initialize(void)
+//void sdram_initialize(void)
+{
+	/* First things first. */
+	early_northbridge_set_registers();
+
+	uint8_t dimm_mask;
+
+	printk(BIOS_DEBUG, "Reading SPD data...\n");
+	dimm_mask = spd_get_supported_dimms();
+
+	if (dimm_mask == 0) {
+		printk(BIOS_DEBUG, "No usable memory for this controller\n");
+	}
+	else {
+		printk(BIOS_DEBUG, "DIMM mask: 0x%x\n", dimm_mask);
+
+		spd_set_row_attributes(dimm_mask); // done?
+		spd_set_dram_controller_mode(dimm_mask); // TODO
+		spd_set_dram_timing(dimm_mask); // TODO: tRAS
+		spd_set_dram_size(dimm_mask); // TODO
+	}
+
+	sdram_enable();
+
+	enable_refresh();
+
+	set_initialization_complete();
+
+	/* Setup Initial Northbridge Registers */
+	northbridge_set_pam();
+	northbridge_set_registers();
+	northbridge_set_undocumented_registers();
+
+	sdram_dump_mchbar_registers();
+
+	printk(BIOS_DEBUG, "Northbridge following SDRAM init:\n");
+
+	dump_pci_device(NORTHBRIDGE);
+	dump_pci_device(NORTHBRIDGE_MMC);
+//	dump_pci_device(PCI_DEV(0, 0x1e, 0));
+//	dump_pci_device(PCI_DEV(0, 0x1f, 0));
+//	dump_pci_device(PCI_DEV(0, 0x1f, 3));
+}
diff --git a/src/northbridge/intel/i865/raminit.h b/src/northbridge/intel/i865/raminit.h
new file mode 100644
index 0000000..bf47053
--- /dev/null
+++ b/src/northbridge/intel/i865/raminit.h
@@ -0,0 +1,181 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2006 Jon Dufresne <jon.dufresne at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+// #ifndef NORTHBRIDGE_INTEL_I865_RAMINIT_H
+// #define NORTHBRIDGE_INTEL_I865_RAMINIT_H
+#ifndef RAMINIT_H
+#define RAMINIT_H
+
+#define DIMM_SOCKETS 4
+
+/* i865 Northbridge PCI devices */
+#define NORTHBRIDGE			PCI_DEV(0, 0, 0)
+#define NORTHBRIDGE_MMC		PCI_DEV(0, 6, 0) // Overflow device
+
+/*-----------------------------------------------------------------------------
+Macros and definitions:
+-----------------------------------------------------------------------------*/
+//#define VALIDATE_DIMM_COMPATIBILITY
+
+#define delay() udelay(200)
+
+/* should dispose of this. */
+// burst length can be 4 or 8 in single-channel or 8 in dual-channel
+// interleaved bursts versus sequential bursts.. no idea about the capabilities of i865, so I left it out
+//#define VG86X_MODE (SDRAM_BURST_4 | SDRAM_BURST_INTERLEAVED | SDRAM_CAS_2_5)
+//#define VG86X_MODE (SDRAM_BURST_4 | SDRAM_CAS_3) // SDRAM_CAS_* == tCL?
+#define VG85X_MODE (SDRAM_BURST_4 | SDRAM_BURST_INTERLEAVED | SDRAM_CAS_2_5)
+
+/* Main Memory Control */
+#define DEFAULT_MCHBAR 0xfecf0000 /* ? KB */
+
+#define MCHBAR8(x) *((volatile u8 *)(DEFAULT_MCHBAR + x))
+//#define MCHBAR16(x) *((volatile u16 *)(DEFAULT_MCHBAR + x)) // unused
+#define MCHBAR32(x) *((volatile u32 *)(DEFAULT_MCHBAR + x))
+
+/* Memory mapped registers */
+#define DRB 0x0  /* DRAM Row 0-7 Boundary */
+#define DRA 0x10 /* DRAM Row 0-7 Attribute */
+#define DRT 0x60 /* DRAM Timing */
+#define DRC 0x68 /* DRAM Controller Mode */
+
+/* Northbridge (device 0) */
+#define PAM0 0x90 /* Programmable Attribute Map #0 */
+#define PAM1 0x91 /* Programmable Attribute Map #1 */
+#define PAM2 0x92 /* Programmable Attribute Map #2 */
+#define PAM3 0x93 /* Programmable Attribute Map #3 */
+#define PAM4 0x94 /* Programmable Attribute Map #4 */
+#define PAM5 0x95 /* Programmable Attribute Map #5 */
+#define PAM6 0x96 /* Programmable Attribute Map #6 */
+
+/* DRC[29] - Initialization Complete (IC) */
+//#define RAM_COMMAND_IC	0x1
+//#define DRC_DONE		(RAM_COMMAND_IC << 29)
+#define RAM_INITIALIZATION_COMPLETE (1 << 29)
+
+/* DRC[22:21] - Number of Channels (CHAN) */
+// TODO: rename to DRC_*_CHANNEL_* ?
+#define RAM_SINGLE_CHANNEL		0x0
+#define RAM_DUAL_CHANNEL_LINEAR	0x1
+#define RAM_DUAL_CHANNEL_TILEAR	0x2
+
+/* DRC[10:8] - Refresh Mode Select (RMS)
+ * 0x1 for Refresh interval 15.6 us
+ * 0x2 for Refresh interval 7.8 us
+ * 0x3 for Refresh interval 64 usec
+ * 0x7 for Refresh interval 64 Clocks. (Fast Refresh Mode)
+ */
+// TODO: rename to DRC_RMS_* ?
+// #define RAM_RMS_15_6	0x1 /* usec */
+// #define RAM_RMS_7_8		0x2 /* usec */
+// #define RAM_RMS_64		0x3 /* usec */
+// #define RAM_RMS_FAST	0x7 /* clocks */
+#define RAM_COMMAND_REFRESH 0x1
+
+/* DRC[6:4] - Mode Select (SMS) */
+// TODO: mask?
+// TODO: rename to DRC_SMS_* ?
+#define RAM_COMMAND_POST_RESET		0x0
+#define RAM_COMMAND_NOP				0x1
+#define RAM_COMMAND_PRECHARGE		0x2
+#define RAM_COMMAND_MRS				0x3
+#define RAM_COMMAND_EMRS			0x4
+#define RAM_COMMAND_CBR				0x6
+#define RAM_COMMAND_NORMAL			0x7
+
+/* Activate to Precharge delay (tRAS) */
+#define DRT_TRAS_MAX_70		(1 << 10)
+#define DRT_TRAS_MAX_120	(0 << 10)
+#define DRT_TRAS_MIN_MASK	(5 << 7) // conflicts with DRT_TRAS_MIN_5
+#define DRT_TRAS_MIN_10		(0 << 7)
+#define DRT_TRAS_MIN_9		(1 << 7)
+#define DRT_TRAS_MIN_8		(2 << 7)
+#define DRT_TRAS_MIN_7		(3 << 7)
+#define DRT_TRAS_MIN_6		(4 << 7)
+#define DRT_TRAS_MIN_5		(5 << 7)
+
+/* CAS# latency (tCL) */
+#define DRT_TCL_MASK	(3 << 5)
+#define DRT_TCL_2_0		(1 << 5)
+#define DRT_TCL_2_5		(0 << 5)
+#define DRT_TCL_3_0		(2 << 5)
+
+/* DRAM RAS# to CAS delay (tRCD) */
+#define DRT_TRCD_MASK	(3 << 2)
+#define DRT_TRCD_4		(0 << 2)
+#define DRT_TRCD_3		(1 << 2)
+#define DRT_TRCD_2		(2 << 2)
+
+/* DRAM RAS# precharge (tRP) */
+#define DRT_TRP_MASK	3
+#define DRT_TRP_4		0
+#define DRT_TRP_3		1
+#define DRT_TRP_2		2
+
+// moved from i855.h
+#define DRT_CAS_MASK    (3 << 5)
+#define DRT_CAS_2_0     (1 << 5)
+#define DRT_CAS_2_5     (0 << 5)
+#define DRT_CAS_3_0		(2 << 5)
+
+struct sys_info { // copied from i945, not yet used
+	u16 memory_frequency;	/* 400, 533 or 667 */
+	u16 fsb_frequency;	/* 400, 533 or 667 */
+
+	u8 trp;			/* calculated by sdram_detect_smallest_tRP() */
+	u8 trcd;		/* calculated by sdram_detect_smallest_tRCD() */
+	u8 tras;		/* calculated by sdram_detect_smallest_tRAS() */
+	// u8 trfc;		/* calculated by sdram_detect_smallest_tRFC() */
+	// u8 twr;			/* calculated by sdram_detect_smallest_tWR() */
+
+	u8 cas;			/* 3, 4 or 5 */
+	u8 refresh;		/* 0 = 15.6us, 1 = 7.8us */
+
+	u8 dual_channel;	/* 0 or 1 */
+	u8 interleaved;
+
+	// u8 mvco4x;		/* 0 (8x) or 1 (4x) */
+	// u8 clkcfg_bit7;
+	// u8 boot_path;
+// #define BOOT_PATH_NORMAL	0
+// #define BOOT_PATH_RESET		1
+// #define BOOT_PATH_RESUME	2
+
+	// u8 package;		/* 0 = planar, 1 = stacked */
+// #define SYSINFO_PACKAGE_PLANAR		0x00
+// #define SYSINFO_PACKAGE_STACKED		0x01
+	u8 dimm[2 * DIMM_SOCKETS];
+#define SYSINFO_DIMM_X16DS		0x00
+#define SYSINFO_DIMM_X8DS		0x01
+#define SYSINFO_DIMM_X16SS		0x02
+#define SYSINFO_DIMM_X8DDS		0x03
+#define SYSINFO_DIMM_NOT_POPULATED	0x04
+
+	u8 banks[2 * DIMM_SOCKETS];
+
+	u8 banksize[2 * 2 * DIMM_SOCKETS];
+	const u8 *spd_addresses;
+
+} __attribute__ ((packed));
+
+
+//void sdram_initialize(void);
+
+#endif /* NORTHBRIDGE_INTEL_I865_RAMINIT_H */
diff --git a/src/northbridge/intel/i865/reset_test.c b/src/northbridge/intel/i865/reset_test.c
new file mode 100644
index 0000000..c465c53
--- /dev/null
+++ b/src/northbridge/intel/i865/reset_test.c
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2006 Jon Dufresne <jon.dufresne at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "raminit.h"
+
+	/* If I have already booted once skip a bunch of initialization */
+	/* To see if I have already booted I check to see if memory
+	 * has been enabled.
+	 */
+static int bios_reset_detected(void)
+{
+	uint32_t dword;
+
+	dword = BAR6_32(DRC);
+
+	if( (dword & DRC_DONE) != 0 ) {
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/src/southbridge/intel/i82801ex/early_smbus.c b/src/southbridge/intel/i82801ex/early_smbus.c
index cdf1f62..1c67c51 100644
--- a/src/southbridge/intel/i82801ex/early_smbus.c
+++ b/src/southbridge/intel/i82801ex/early_smbus.c
@@ -1,6 +1,6 @@
 #include "smbus.h"
 
-#define SMBUS_IO_BASE 0x0f00
+//#define SMBUS_IO_BASE 0x0f00
 
 static void enable_smbus(void)
 {
@@ -9,7 +9,7 @@ static void enable_smbus(void)
 	print_spew("SMBus controller enabled\n");
 
 	pci_write_config32(dev, 0x20, SMBUS_IO_BASE | 1);
-	print_debug_hex32(pci_read_config32(dev, 0x20));
+	printk(BIOS_DEBUG, "SMB_BASE = 0x%x\n", pci_read_config32(dev, SMB_BASE));
 	/* Set smbus enable */
 	pci_write_config8(dev, 0x40, 1);
 	/* Set smbus iospace enable */
diff --git a/src/southbridge/intel/i82801ex/smbus.h b/src/southbridge/intel/i82801ex/smbus.h
index f330c0a..0fa6b84 100644
--- a/src/southbridge/intel/i82801ex/smbus.h
+++ b/src/southbridge/intel/i82801ex/smbus.h
@@ -1,5 +1,8 @@
 #include <device/smbus_def.h>
 
+#define SMBUS_IO_BASE 0x400
+#define SMB_BASE 0x20
+
 #define SMBHSTSTAT 0x0
 #define SMBHSTCTL  0x2
 #define SMBHSTCMD  0x3
diff --git a/src/superio/winbond/w83627thg/early_serial.c b/src/superio/winbond/w83627thg/early_serial.c
index 559e982..a54139f 100644
--- a/src/superio/winbond/w83627thg/early_serial.c
+++ b/src/superio/winbond/w83627thg/early_serial.c
@@ -45,3 +45,14 @@ static void inline w83627thg_enable_serial(device_t dev, u16 iobase)
 	pnp_set_enable(dev, 1);
 	pnp_exit_ext_func_mode(dev);
 }
+
+static void w83627thg_set_clksel_48(device_t dev)
+{
+        u8 reg8;
+
+        pnp_enter_ext_func_mode(dev);
+        reg8 = pnp_read_config(dev, 0x24);
+        reg8 |= (1 << 6); /* Set CLKSEL (clock input on pin 1) to 48MHz. */
+        pnp_write_config(dev, 0x24, reg8);
+        pnp_exit_ext_func_mode(dev);
+}




More information about the coreboot mailing list