Index: src/northbridge/intel/i440bx/raminit.c
===================================================================
--- src/northbridge/intel/i440bx/raminit.c      (revision 5153)
+++ src/northbridge/intel/i440bx/raminit.c      (working copy)
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2007-2008 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2010 Keith Hui <buurin@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
@@ -66,7 +67,7 @@
  * [5] == Extended(8x)     125 us -> 124.8 us
  */
 static const uint32_t refresh_rate_map[] = {
-	1, 5, 5, 2, 3, 4
+	1, 1, 1, 2, 3, 4
 };
 
 /* Table format: register, bitmask, value. */
@@ -472,7 +473,8 @@
 
 static void sdram_set_spd_registers(void)
 {
-	/* TODO: Don't hardcode the values here, get info via SPD. */
+	uint8_t drb;
+	unsigned int i;
 
 	/* Map all legacy regions to RAM (read/write). This is required if
 	 * you want to use the RAM area from 768 KB - 1 MB. If the PAM
@@ -487,22 +489,93 @@
 	pci_write_config8(NB, PAM5, 0x33);
 	pci_write_config8(NB, PAM6, 0x33);
 
-	/* TODO: Set DRB0-DRB7. */
-	/* Currently this is hardcoded to one 64 MB DIMM in slot 0. */
-	pci_write_config8(NB, DRB0, 0x08);
-	pci_write_config8(NB, DRB1, 0x08);
-	pci_write_config8(NB, DRB2, 0x08);
-	pci_write_config8(NB, DRB3, 0x08);
-	pci_write_config8(NB, DRB4, 0x08);
-	pci_write_config8(NB, DRB5, 0x08);
-	pci_write_config8(NB, DRB6, 0x08);
-	pci_write_config8(NB, DRB7, 0x08);
+	/* Set DRB0-DRB7. */
+	/* The info we want from SPD for RAM size is byte 31 - row density in bytes per row
+	and also byte 5 - number of module rows
+	If only one bit is set, all rows are of that size
 
+	NOTE: Here DRB is set according to SPD data. P2B-LS vendor BIOS hard codes for a 128MB
+	DRB and probes the memory head
+
+	TODO: How to handle 4MB, 256MB and 512MB rows? 
+	440BX probably can't handle 256MB and 512MB rows anyway, but 4MB is below DRB granularity!
+	TODO: Also for now we will assume the first row on the DIMM is of higher density
+	*/
+
+	drb = 0;
+
+	for(i = 0; i < DIMM_SOCKETS; i++) {
+		unsigned int status;
+		unsigned char byte;
+		unsigned int device;
+		unsigned char row0div8;
+		unsigned char row1div8;
+		device = DIMM_SPD_BASE + i;
+                if (device) {
+			PRINT_DEBUG("dimm: ");
+			PRINT_DEBUG_HEX8(i);
+                        PRINT_DEBUG(": ");
+                        PRINT_DEBUG_HEX8(device);
+			status = spd_read_byte(device, SPD_NUM_DIMM_BANKS);
+			/* This DIMM slot is bad or not populated */
+			if (status < 0) {
+				PRINT_DEBUG("bad device\r\n");
+				device = 0;
+			}
+		}
+		/* Good SPD read, we can continue */
+		if (device) {
+			/* First byte read tells how many banks we got (see above) */
+			unsigned int banks;
+			banks = status & 0xff;
+			status = spd_read_byte(device, SPD_DENSITY_OF_EACH_ROW_ON_MODULE);
+			byte = status & 0xff;
+			/* See if multiple bits of SPD_DENSITY_OF_EACH... is set */
+			
+			unsigned char rowden;
+			unsigned char bitmask;
+			unsigned char bits_set;
+
+			row0div8 = row1div8 = bits_set = 0;
+			/* Start with MSB - "512MB" */
+			bitmask = 0x80;
+			/* This is 512/8, required by 440BX. With this, row[01]div8 will have the right
+			   value needed for DRBx registers */
+			rowden = 64;
+			/* Walk all the bits in byte 31. Log the highest density in this 
+			while (bitmask) {
+				if (byte && bitmask) {
+					bits_set++;
+					if (row0div8==0) {
+						row0div8 = rowden;
+					} else {
+						row1div8 = rowden;
+					}
+				}
+				bitmask = bitmask >> 1;
+				rowden = rowden >> 1;
+			}
+			/* TODO: Properly handle SDRAMs with >2 rows? */
+			/* If we didn't log two density bits and there are more than 1 rows,
+			   use the first row's density for the second row */
+			if (row1div8 == 0 && banks > 1) {
+				row1div8 = row0div8;
+			}
+			/* TODO: Set the ECC flags in NBXCFG */
+                }
+		/* Write the DRB */
+		/* The bitwise & is just to be safe */
+		drb = (drb + row0div8) & 0xff; 
+		pci_write_config8(NB, DRB0+(i<<1), drb);
+		drb = (drb + row1div8) & 0xff;
+		pci_write_config8(NB, DRB1+(i<<1), drb);
+        }
+
 	/* TODO: Set DRAMC. Don't enable refresh for now. */
 	pci_write_config8(NB, DRAMC, 0x08);
 
-	/* TODO: Set RPS. Needs to be fixed for multiple DIMM support. */
-	pci_write_config16(NB, RPS, 0x0001);
+	/* TODO: Set RPS. This hard code all SDRAM pages to 8KB. At least the vendor BIOS for Asus P2B-LS does it this way */
+	pci_write_config16(NB, RPS, 0xaaaa);
 
 	/* TODO: Set SDRAMC. */
 	pci_write_config16(NB, SDRAMC, 0x0010);	/* SDRAMPWR=1: 4 DIMM config */
@@ -512,7 +585,6 @@
 	pci_write_config16(NB, PGPOL, 0x0123);
 
 	/* TODO: Set NBXCFG. */
-	// pci_write_config32(NB, NBXCFG, 0x0100220c); // FIXME?
 	pci_write_config32(NB, NBXCFG, 0xff00800c);
 
 	/* TODO: Set PMCR? */
