Index: coreboot-v2/src/northbridge/intel/i82810/raminit.c
===================================================================
--- coreboot-v2/src/northbridge/intel/i82810/raminit.c	(revision 3698)
+++ coreboot-v2/src/northbridge/intel/i82810/raminit.c	(working copy)
@@ -29,7 +29,7 @@
 -----------------------------------------------------------------------------*/
 
 /* Uncomment this to enable debugging output. */
-// #define DEBUG_RAM_SETUP 1
+//#define DEBUG_RAM_SETUP 1
 
 /* Debugging macros. */
 #if defined(DEBUG_RAM_SETUP)
@@ -69,10 +69,10 @@
 static void do_ram_command(const struct mem_controller *ctrl, uint32_t command,
 			   uint32_t addr_offset, uint32_t row_offset)
 {
+	uint16_t dimm_size, dimm_start, dimm_banks;
 	uint8_t reg;
+	int i;
 
-	/* TODO: Support for multiple DIMMs. */
-
 	/* Configure the RAM command. */
 	reg = pci_read_config8(ctrl->d0, DRAMT);
 	reg &= 0x1f;		/* Clear bits 7-5. */
@@ -83,21 +83,38 @@
 	   doesn't need to be "sent" to the DIMMs. */
 	/* if (command == RAM_COMMAND_NORMAL) return; */
 
-	PRINT_DEBUG("    Sending RAM command 0x");
-	PRINT_DEBUG_HEX8(reg);
-	PRINT_DEBUG(" to 0x");
-	PRINT_DEBUG_HEX32(0 + addr_offset);	// FIXME
-	PRINT_DEBUG("\r\n");
+	dimm_start = 0;
 
-	/* Read from (DIMM start address + addr_offset). */
-	read32(0 + addr_offset);	//first offset is always 0
-	read32(row_offset + addr_offset);
+	for (i = 0; i < DIMM_SOCKETS ; i++) {
+		dimm_size = smbus_read_byte(ctrl->channel0[i], 31);
+		dimm_banks = smbus_read_byte(ctrl->channel0[i], 5);
+		if (dimm_size) {
+			PRINT_DEBUG("    Sending RAM command 0x");
+			PRINT_DEBUG_HEX8(reg);
+			PRINT_DEBUG(" to 0x");
+			PRINT_DEBUG_HEX32((dimm_start * 4 * 1024 * 1024) + addr_offset);
+			PRINT_DEBUG("\r\n");
+			read32((dimm_start * 4 * 1024 * 1024) + addr_offset);
+			if (dimm_banks > 1) {
+				/* send command to bank #2 of the DIMM */
+				dimm_start += dimm_size;
+				read32((dimm_start * 4 * 1024 * 1024) + addr_offset);
+			}
+		}
+		dimm_start += dimm_size;
+	}
+	/* TODO */
+	//read32((dimm_start * 4 * 1024 * 1024) + addr_offset);
 }
 
+
 /*-----------------------------------------------------------------------------
 DIMM-independant configuration functions.
 -----------------------------------------------------------------------------*/
 
+/*
+ * Setting DRP - DRAM Row Population Register (Device 0)
+ */
 static void spd_set_dram_size(const struct mem_controller *ctrl,
 			      uint32_t row_offset)
 {
@@ -105,6 +122,7 @@
 	 * SMBus-related functions return ints, and its just easier this way.
 	 */
 	int i, drp, dimm_size;
+	//struct dimm_size_s sz;
 
 	drp = 0x00;
 
@@ -118,7 +136,7 @@
 			dimm_size = smbus_read_byte(ctrl->channel0[i], 31);
 
 			/* WISHLIST: would be nice to display it as decimal? */
-			print_debug("DIMM is 0x");
+			print_debug("   DIMM is 0x");
 			print_debug_hex8(dimm_size * 4);
 			print_debug("MB\r\n");
 
@@ -126,14 +144,15 @@
 			 * side. This will fail if the DIMM uses a
 			 * non-supported DRAM tech, and can't be used until
 			 * buffers are done dynamically.
-			 * Note: the factory BIOS just dies if it spots this :D
+			 * Note: old factory BIOS just dies if it spots this :D
+			 *    and new ones treat it as 128MB.
 			 */
 			if (dimm_size > 32) {
-				print_err("DIMM row sizes larger than 128MB not"
-					  "supported on i810\r\n");
-				print_err
-				    ("Attempting to treat as 128MB DIMM\r\n");
-				dimm_size = 32;
+			        print_err("DIMM row sizes larger than 128MB not"
+			                  "supported on i810\r\n");
+			        print_err
+			            ("Attempting to treat as 128MB DIMM\r\n");
+			        dimm_size = 32;
 			}
 
 			/* Set the row offset, in KBytes (should this be
@@ -142,47 +161,47 @@
 			 */
 			row_offset = (dimm_size * 4 * 1024);
 
-			/* This is the way I was doing this, it's provided
-			 * mainly as an alternative to the "new" way.
-			 */
 
-#if 0
-			/* 8MB */
-			if (dimm_size == 0x2)
-				dimm_size = 0x1;
-			/* 16MB */
-			else if (dimm_size == 0x4)
-				dimm_size = 0x4;
-			/* 32MB */
-			else if (dimm_size == 0x8)
-				dimm_size = 0x7;
-			/* 64 MB */
-			else if (dimm_size == 0x10)
-				dimm_size = 0xa;
-			/* 128 MB */
-			else if (dimm_size == 0x20)
-				dimm_size = 0xd;
-			else
-				print_debug("Ram Size not supported\r\n");
-#endif
-
 			/* This array is provided in raminit.h, because it got
-			 * extremely messy. The above way is cleaner, but
+			 * extremely messy. The old way is cleaner, but
 			 * doesn't support any asymetrical/odd configurations.
 			 */
 			dimm_size = translate_spd_to_i82810[dimm_size];
 
-			print_debug("After translation, dimm_size is 0x");
-			print_debug_hex8(dimm_size);
-			print_debug("\r\n");
-
 			/* If the DIMM is dual-sided, the DRP value is +2 */
 			/* TODO: Figure out asymetrical configurations. */
-			if ((smbus_read_byte(ctrl->channel0[i], 127) | 0xf) ==
-			    0xff) {
-				print_debug("DIMM is dual-sided\r\n");
-				dimm_size += 2;
+			
+			/* this doesn't always recognize dual-sided DIMM */
+			/*
+			if ((smbus_read_byte(ctrl->channel0[i], 127) | 0xf) == 0xff) {
+			        print_debug("   DIMM is dual-sided\r\n");
+			        dimm_size += 2;
 			}
+			*/
+			/* the correct way to check if DIMM is dual-side
+			 * using byte 5. 
+
+			 * FROM INTEL DATASHEET:
+			 * The GMCH supports 2 DIMM slots with each slot 
+			 * supporting two rows of memory. Slots are numbered 0
+			 * through 1. Rows of Slots 0 are numbered 0 through 1. 
+			 * Rows of Slot 1 are numbed 2 through 3. The
+			 * DIMM’s SPD Byte 5 describes the number of sides in a 
+			 * DIMM; SPD Byte 13 provides information on
+			 * the DRAM width (x8, x16, or x32). BIOS uses these 
+			 * two SPD bytes to calculate loads on memory signals. 
+			 * Load calculation is made based on populated memory 
+			 * rows.
+
+			 */
+			if (smbus_read_byte(ctrl->channel0[i], 5) > 1) {
+			        print_debug("   DIMM is dual-sided\r\n");
+			        dimm_size += 2;
+			}
+
+			print_debug("   After translation, dimm_size is 0x");
+			print_debug_hex8(dimm_size);
+			print_debug("\r\n");
 		} else {
 			print_debug("No DIMM found in slot ");
 			print_debug_hex8(i);
@@ -199,7 +218,6 @@
 	print_debug("DRP calculated to 0x");
 	print_debug_hex8(drp);
 	print_debug("\r\n");
-
 	pci_write_config8(ctrl->d0, DRP, drp);
 }
 
@@ -207,16 +225,35 @@
 {
 	/* TODO, for now using default, hopefully safe values. */
 	// pci_write_config8(ctrl->d0, DRAMT, 0x00);
+	uint8_t val;
+	val = pci_read_config8(ctrl->d0, DRAMT);
+	val |= 0x18;
+	pci_write_config8(ctrl->d0, DRAMT, val);
 }
 
 static void set_dram_buffer_strength(const struct mem_controller *ctrl)
 {
-	/* TODO: This needs to be set according to the DRAM tech
+	/* TODO: This needs to be calculated according to the DRAM tech
 	 * (x8, x16, or x32). Argh, Intel provides no docs on this!
 	 * Currently, it needs to be pulled from the output of
 	 * lspci -xxx Rx92
+	 * here are some common results:
+	 * value:   tom:    config:
+	 * 0x3356   256MB   1 x 256MB DIMM(s), dual sided
+	 * 0x0001   512MB   2 x 256MB DIMM(s), dual sided
+	 * 0x77da   128MB   1 x 128MB DIMM(s), single sided
+	 * 0x55c6   128MB   2 x 128MB DIMM(s), single sided
+	 * 0x3356   128MB   1 x 128MB DIMM(s), dual sided
+	 * 0x0001   256MB   2 x 128MB DIMM(s), dual sided
 	 */
-	pci_write_config16(ctrl->d0, BUFF_SC, 0x77da);
+	/* use 2 dual sided DIMMs - this also works with only 1 DIMM */
+	pci_write_config16(ctrl->d0, BUFF_SC, 0x0001);
+
+	/* use 1 single sided DIMM - max 128MB */
+	//pci_write_config16(ctrl->d0, BUFF_SC, 0x77da);
+
+	/* or we can use defaults - bad idea... */
+	//pci_write_config16(ctrl->d0, BUFF_SC, 0x0ffff);
 }
 
 /*-----------------------------------------------------------------------------
@@ -230,10 +267,17 @@
  */
 static void sdram_set_registers(const struct mem_controller *ctrl)
 {
+	uint8_t value;
 	unsigned long val;
 
 	/* TODO */
-	pci_write_config8(ctrl->d0, GMCHCFG, 0x60);
+	//pci_write_config8(ctrl->d0, GMCHCFG, 0x60);
+	value = pci_read_config8(ctrl->d0, GMCHCFG);
+	/* Preserve reserved bits. */
+	val &= 0xa4;
+	/* set the GMCH to prechange all during the service of a page miss */
+	val |= 0x28;
+	pci_write_config8(ctrl->d0, GMCHCFG, val);
 
 	/* PAMR: Programmable Attributes Register
 	 * Every pair of bits controls an address range:
@@ -251,24 +295,54 @@
 
 	/* Ideally, this should be R/W for as many ranges as possible. */
 	pci_write_config8(ctrl->d0, PAM, 0xff);
+	/* or we can use sane defaults, but VGA won't work for unknown reason */
+	//pci_write_config8(ctrl->d0, PAM, 0x41);
+	
+	/* PCICMD PCI Command Register (Device 1) */
+	val = pci_read_config16(ctrl->d0, 4);
+	/* vga ? */
+	val |= 3;
+	pci_write_config16(ctrl->d0, 4, val);
 
-	/* Enabling the VGA Framebuffer currently screws up the rest of the boot.
-	 * Disable for now */
-	
+	/* set System Management RAM Control Register / Graphics Mode Select */
+	value = pci_read_config8(ctrl->d0, SMRAM);
 	/* Enable 1MB framebuffer. */
-	//pci_write_config8(ctrl->d0, SMRAM, 0xC0);
+	value |= 0xC0;
+	/* set AB segment Enabled as SMM RAM */
+	value |= 0x0C;
+	pci_write_config8(ctrl->d0, SMRAM, value);
 
-	//val = pci_read_config16(ctrl->d0, MISSC);
+	/* Set the value for Fixed DRAM Hole Control Register */
+	pci_write_config8(ctrl->d0, FDHC, 0x00);
+
+	val = pci_read_config16(ctrl->d0, MISSC);
 	/* Preserve reserved bits. */
-	//val &= 0xff06;
-	/* Set graphics cache window to 32MB, no power throttling. */
+	val &= 0xff06;
+	/* Set graphics cache window to 32MB, no power throttling. 0 for 64MB.*/
 	//val |= 0x0001;
-	//pci_write_config16(ctrl->d0, MISSC, val);
+	pci_write_config16(ctrl->d0, MISSC, val);
 
-	//val = pci_read_config8(ctrl->d0, MISSC2);
+	val = 0;
+	val = pci_read_config8(ctrl->d0, MISSC2);
+	/* Preserve reserved bits. */
+	val &= 0xf9;
 	/* Enable graphics palettes and clock gating (not optional!) */
-	//val |= 0x06;
-	//pci_write_config8(ctrl->d0, MISSC2, val);
+	val |= 0x06;
+	
+	val |= 0xc6;
+	pci_write_config8(ctrl->d0, MISSC2, val);
+
+	/* setting Vendor/Device ids - there must be a better way of doing
+	 * this...
+	 */
+	/* set vendor id */
+	val = pci_read_config16(ctrl->d0, 0);
+	pci_write_config16(ctrl->d0, 0x2c, val);
+	/* set device id */
+	val = pci_read_config16(ctrl->d0, 2);
+	pci_write_config16(ctrl->d0, 0x2e, val);
+
+	print_debug("i810 Initial registers have been set.\r\n");
 }
 
 /**
@@ -295,10 +369,47 @@
 static void sdram_enable(int controllers, const struct mem_controller *ctrl)
 {
 	int i;
+	uint8_t reg8;
 
-	/* Todo: this will currently work with either one dual sided or two
-	 * single sided DIMMs. Needs to work with 2 dual sided DIMMs in the
-	 * long run.
+	/* TODO: this currently works with one DIMM only, dual or single sided.
+	 * Must figure out how to activate the 2nd DIMM (coreboot recognizes
+	 * the tomk properly but the system restart itself when the payload is 
+	 * trying to relocate its code to the end of tomk which is in DIMM 2. 
+	 * something like this :
+	 * 
+	 * Jumping to boot code at 0x100084
+	 * entry    = 0x00100084
+	 * lb_start = 0x00004000
+	 * lb_size  = 0x00026000
+	 * adjust   = 0x17dd6000
+	 * buffer   = 0x17db4000
+	 *      elf_boot_notes = 0x00020920
+	 * adjusted_boot_notes = 0x17df6920
+	 * FILO version 0.6.0rc1 (ziggy@pc) Wed Nov 12 06:57:33 IST 2008
+	 * Bootloader: elfboot
+	 * Version: 1.3
+	 * Current location: 0x100000-0x498cf7
+	 * Relocating to 0x17a67000-0x17dffcf7... 
+	 * 
+	 * coreboot-2.0.0.0Fallback Mon Nov 17 03:08:18 IST 2008 starting...
+	 * ...
+	 * 
+	 * 
+	 * and sometimes something like this :
+	 * 
+	 * Jumping to boot code at 0x100084
+	 * entry    = 0x00100084
+	 * lb_start = 0x00004000
+	 * lb_size  = 0x00026000
+	 * adjust   = 0x1fdd6000
+	 * buffer   = 0x1fdb4000
+	 *      elf_boot_notes = 0x00020920
+	 * adjusted_boot_notes = 0x1fdf6920
+	 * Unexpected Exception: 6 @ 10:4b8415d5 - Halting
+	 * Code: 0 eflags: 00010086
+	 * eax: 1fde229f ebx: 1fdd6000 ecx: 00000000 edx: 00026000
+	 * edi: 00004000 esi: 1fdb4000 ebp: 00025ebc esp: 1fdfbe70
+	 * 
 	 */
 	uint32_t row_offset;
 
@@ -316,8 +427,9 @@
 
 	/* 3. Perform 8 refresh cycles. Wait tRC each time. */
 	PRINT_DEBUG("RAM Enable 3: CBR\r\n");
-	do_ram_command(ctrl, RAM_COMMAND_CBR, 0, row_offset);
 	for (i = 0; i < 8; i++) {
+		do_ram_command(ctrl, RAM_COMMAND_CBR, 0, row_offset);
+		/* FIXME: are those read32() needed? */
 		read32(0);
 		read32(row_offset);
 		udelay(1);
@@ -333,6 +445,19 @@
 	do_ram_command(ctrl, RAM_COMMAND_NORMAL, 0, row_offset);
 	udelay(1);
 
+	/* 6. Enable refresh */
+	PRINT_DEBUG("RAM Enable 6: Enable Refresh\r\n");
+	reg8 = pci_read_config8(ctrl->d0, DRAMT);
+	/* set SDRAM Mode Select for Normal Operation, refresh 15.6usec */
+	reg8 |= 0x20;
+	pci_write_config8(ctrl->d0, DRAMT, reg8);
+
+	/* Intel reserved, which seems to be needed */
+	pci_write_config8(ctrl->d0, 0x81, 0x78);
+	pci_write_config8(ctrl->d0, 0x82, 0x1d);
+
 	PRINT_DEBUG("Northbridge following SDRAM init:\r\n");
 	DUMPNORTH();
+
 }
+
