Index: src/northbridge/intel/i440bx/raminit.c
===================================================================
--- src/northbridge/intel/i440bx/raminit.c	(revision 2621)
+++ src/northbridge/intel/i440bx/raminit.c	(working copy)
@@ -377,7 +377,348 @@
 DIMM-independant configuration functions.
 -----------------------------------------------------------------------------*/
 
+/* Performs Bit Scan Right (MSB) Function (for SPD code) */
+static inline uint8_t bsr(uint16_t val)
+{
+#if ASSEMBLY
+	__asm__ __volatile__ ("bsr %1, %%ax;" : "=a"(val) : "a"(val));
+
+	return (uint8_t)val;
+#else
+	uint8_t i;
+
+	for (i = 15; i > 0; i--)
+	{
+		if (val & 0x8000) break;
+		val <<= 1;
+	}
+	return i;
+#endif
+}
+
+
 /**
+ * Set the DRAM Row Boundary Registers for all DIMMs.
+ *
+ * @param Memory controller
+ */
+static void spd_set_drb(const struct mem_controller *ctrl)
+{
+	uint8_t i, size = 0, addr = 0;
+	uint16_t tmp;
+
+	for( i = 0; i < DIMM_SOCKETS; i++ )
+	{
+		size = (smbus_read_byte(ctrl->channel0[i], SPD_NUM_ROWS) & 0xf);
+		size += (smbus_read_byte(ctrl->channel0[i], 
+			SPD_NUM_COLUMNS) & 0xf);
+
+		/* Skip calculations if SPD returns undefined data */
+		if (size)
+		{
+			tmp = smbus_read_byte(ctrl->channel0[i], 
+				SPD_NUM_BANKS_PER_SDRAM) & 0xff;
+			size += bsr(tmp);
+
+			/* Get the module data width and convert it 
+			 * to a power of two */
+			tmp = (smbus_read_byte(ctrl->channel0[i], 
+				SPD_MODULE_DATA_WIDTH_MSB) << 8) | 
+				(smbus_read_byte(ctrl->channel0[i], 
+				 SPD_MODULE_DATA_WIDTH_LSB) & 0xff);
+			size += bsr(tmp);
+
+			/* Now we have ram size as a power of two (less 1) */
+			/* 2^23 = 8MBit: seems like it should be MBits not MB */
+			size -= (23 - 1); /* Make it multiples of 8MBits */
+		}
+		addr += (size << 1);
+
+		PRINT_DEBUG("DRB");
+		PRINT_DEBUG_HEX8(i<<1);
+		PRINT_DEBUG(": ");
+		PRINT_DEBUG_HEX8(addr);
+		PRINT_DEBUG("\r\n");
+
+		/* Ignore the dimm if it is over 2GB */
+		if (size >= 8)
+			pci_write_config8(ctrl->d0, DRB+(i<<1), 0);
+		else
+			pci_write_config8(ctrl->d0, DRB+(i<<1), addr);
+
+
+		/* side two */
+		if (smbus_read_byte(ctrl->channel0[i], SPD_NUM_DIMM_BANKS) > 1)
+		{
+
+#if 0			/* Asymmetric code doesn't seem to work */
+			size = (smbus_read_byte(ctrl->channel0[i], 
+				SPD_NUM_ROWS) & 0xf0) >> 4;
+			size += (smbus_read_byte(ctrl->channel0[i], 
+				SPD_NUM_COLUMNS) & 0xf0) >> 4;
+
+			if (size)
+			{
+				tmp = smbus_read_byte(ctrl->channel0[i], 
+					SPD_NUM_BANKS_PER_SDRAM) & 0xff;
+				size += bsr(tmp);
+
+				/* Get the module data width and convert it 
+				 * to a power of two */
+				tmp = (smbus_read_byte(ctrl->channel0[i], 
+					SPD_MODULE_DATA_WIDTH_MSB) << 8) |
+					(smbus_read_byte(ctrl->channel0[i], 
+					 SPD_MODULE_DATA_WIDTH_LSB) & 0x1f);
+				size += bsr(tmp);
+
+				/* Make it multiples of 8MBits */
+				size -= (23 - 1);
+			}
+#endif
+			addr += (size << 1);
+
+			PRINT_DEBUG("DRB");
+			PRINT_DEBUG_HEX8((i<<1)+1);
+			PRINT_DEBUG(": ");
+			PRINT_DEBUG_HEX8(addr);
+			PRINT_DEBUG("\r\n");
+
+			/* Ignore the dimm if it is over 2GB (possible?) */
+			if (size >= 8)
+				pci_write_config8(ctrl->d0, DRB+(i<<1)+1, 0);
+			else
+				pci_write_config8(ctrl->d0, DRB+(i<<1)+1, addr);
+		}
+
+	}
+}
+
+/**
+ * Set the DRAM Control Register.
+ *
+ * @param Memory controller
+ */
+static void spd_set_dramc(const struct mem_controller *ctrl)
+{
+	uint8_t i, memid;
+	uint8_t dram_reg = 0;
+
+	/* Auto detect if RAM is registered or not. */
+	/* The DRAMC register also controls the refresh rate but we can't
+	 * set that here because we must leave refresh disabled.
+	 */
+
+	/* Find the first dimm and assume the rest are the same (dangerous?) */
+	for (i = 0; i < DIMM_SOCKETS; i++) 
+	{
+		/* This was changed from SPD_MODULE_ATTRIBUTES because
+		 * it can be equal to zero for an existing DIMM */
+		memid = smbus_read_byte(ctrl->channel0[i], SPD_MEMORY_TYPE);
+
+		if (memid == SPD_MEMORY_TYPE_SDRAM) break;
+	}
+
+	if (memid != SPD_MEMORY_TYPE_SDRAM)
+	{
+		/* no SDRAM memory! */
+		die("No memory found!");
+	}
+
+	memid = smbus_read_byte(ctrl->channel0[i], SPD_MODULE_ATTRIBUTES);
+
+	if (memid & 0x12)
+		dram_reg |= 0x10; /* registered DRAM */
+	else
+		dram_reg |= 0x08; /* unregistered DRAM */
+
+	/* Write DRAM control register (without refresh) */
+	PRINT_DEBUG("DRAMC: ");
+	PRINT_DEBUG_HEX8(dram_reg);
+	PRINT_DEBUG("\r\n");
+	pci_write_config8(ctrl->d0, DRAMC, dram_reg);
+}
+
+/**
+ * Set the SDRAM Row Page Size Register.
+ *
+ * @param Memory controller
+ */
+static void spd_set_rps(const struct mem_controller *ctrl)
+{
+	uint16_t page, reg = 0;
+	uint8_t i, cnt = 0;
+
+	/* The RPS register holds the size of a "page" of DRAM on each DIMM */
+	/* default all page sizes to 2KB */
+	for (i = 0; i < DIMM_SOCKETS; i++ )
+	{
+		page = (smbus_read_byte(ctrl->channel0[i], 
+			SPD_NUM_COLUMNS) & 0xf);
+
+		/* FIXME: do something with page sizes greater than 8KB!! */
+		/* This workaround seems to generate valid values */
+		if (page > 8) page = 8;
+
+		if (page <= 8)
+		{
+			page <<= cnt;
+			reg |= page & 0xf;
+
+			/* Only handling the symmetric case */
+			if ( smbus_read_byte(ctrl->channel0[i], 
+				SPD_NUM_DIMM_BANKS) > 1)
+				reg |= ((page & 0xf) << 4);
+		}
+		cnt += 4;
+	}
+
+	/* Next block is for Ron's attempt to get registered to work.
+	 * We have just verified that we have to have this code. It appears that
+	 * the registered SDRAMs do indeed set the RPS wrong. Sheesh.
+	 *
+	 * We have verified that for registered DRAM the values are
+	 * 1/2 the size they should be. So we test for registered
+	 * and then double the sizes if needed.
+	 */
+
+	if (pci_read_config8(ctrl->d0, DRAMC) & 0x10)
+	{
+		/* BIOS makes weird page size for registered!
+		 * what we have found is you need to set the EVEN banks to
+		 * twice the size. Fortunately there is a very easy way to
+		 * do this. First, read the WORD value of the RPS register
+		 * and double the size of the EVEN banks we only need to add 1
+		 * because the size is log2
+        	 */
+		reg += 0x1111;
+	}
+
+	/* now write that final value into RPS register */
+	PRINT_DEBUG("RPS: ");
+	PRINT_DEBUG_HEX16(reg);
+	PRINT_DEBUG("\r\n");
+	pci_write_config16(ctrl->d0, RPS, reg);
+}
+
+/**
+ * Set the Paging Policy Register.
+ *
+ * @param Memory controller
+ */
+static void spd_set_pgpol(const struct mem_controller *ctrl)
+{
+	uint16_t policy = 0;
+	uint8_t i, cnt = 0;
+
+	/* The PGPOL register stores the number of logical banks per DIMM,
+	 * and number of clocks the DRAM controller waits in the idle
+	 * state.
+	 */
+	for (i = 0; i < DIMM_SOCKETS; i++ )
+	{
+		if (smbus_read_byte(ctrl->channel0[i], 
+			SPD_NUM_BANKS_PER_SDRAM) >= 4)
+		{
+			policy |= (0x1 << cnt);
+
+			/* for now only handle the symmtrical case */
+			if (smbus_read_byte(ctrl->channel0[i], 
+				SPD_NUM_DIMM_BANKS) > 1)
+				policy |= (0x2 << cnt);
+		}
+		cnt += 2;
+	}
+
+	/* 32 clocks DRAM idle time (change back to 0 after MRS?) */
+	policy = (policy << 8) | 0x7;
+
+	PRINT_DEBUG("PGPOL: ");
+	PRINT_DEBUG_HEX16(policy);
+	PRINT_DEBUG("\r\n");
+	pci_write_config16(ctrl->d0, PGPOL, policy);
+}
+
+/**
+ * Set the SDRAM Control Register.
+ *
+ * @param Memory controller
+ */
+static void spd_set_sdramc(const struct mem_controller *ctrl)
+{
+	uint8_t i;
+	uint16_t reg = 0x0100;
+
+	for (i = 0; i < DIMM_SOCKETS; i++ )
+	{
+		/* Default settings are OK if only CAS=3 is supported */
+		if (smbus_read_byte(ctrl->channel0[i], 
+			SPD_ACCEPTABLE_CAS_LATENCIES) & 0x2)
+		{
+			PRINT_DEBUG("DIMM bank ");
+			PRINT_DEBUG_HEX8(i);
+			PRINT_DEBUG(" supports CAS=2\r\n");
+			pci_write_config8(ctrl->d0, SDRAMC, reg | 0x4);
+			break;
+		}
+	}
+}
+
+/**
+ * Set the NBX Configuration Register.
+ *
+ * @param Memory controller
+ */
+static inline void spd_set_nbxcfg(const struct mem_controller *ctrl)
+{
+	uint8_t i, cnt = 24;
+	uint32_t reg;
+
+	/* Say all dimms have no ECC support */
+	reg = pci_read_config32(ctrl->d0, NBXCFG) | 0xff000000;
+
+	for (i = 0; i < DIMM_SOCKETS; i++)
+	{
+		/* Module error correction type: 
+		 * 0 == None, 1 == Parity, 2 == ECC */
+		if (smbus_read_byte(ctrl->channel0[i], 
+			SPD_DIMM_CONFIG_TYPE) & 0x2)
+		{
+			reg ^= (0x1 << cnt);
+
+			/* TODO: Set Data Integrity Mode for ECC Mode */
+			/* Is this right? What about other EC modes? */
+			/* reg |= 0x10; */
+
+			if (smbus_read_byte(ctrl->channel0[i], 
+				SPD_NUM_DIMM_BANKS) > 1)
+			{
+				/* only the symmetric case is possible */
+				reg ^= (0x2 << cnt);
+			}
+		}
+		cnt += 2;
+	}
+
+	/* set correct DRAM bus speed */
+	for (i = 0; i < DIMM_SOCKETS; i++)
+	{
+		/* set to 66MHz if at least one DIMM is 66MHz only */
+		if (smbus_read_byte(ctrl->channel0[i], 
+			SPD_INTEL_SPEC_FOR_FREQUENCY) == 0x66)
+		{
+			/* TODO: need to handle?: 66Mhz->CL2 / 100MHz->CL3 */
+			reg |= 0x2000;
+			break;
+		}
+	}
+
+	PRINT_DEBUG("NBXCFG: ");
+	PRINT_DEBUG_HEX32(reg);
+	PRINT_DEBUG("\r\n");
+	pci_write_config32(ctrl->d0, NBXCFG, reg);
+}
+
+/**
  * TODO.
  *
  * @param Memory controller
@@ -387,6 +728,9 @@
 	int i, value;
 	uint8_t reg;
 
+	/* Set DRAM idle time to 0 after MRS (needed?) */
+	pci_write_config8(ctrl->d0, PGPOL, 0);
+
 	reg = pci_read_config8(ctrl->d0, DRAMC);
 
 	for (i = 0; i < DIMM_SOCKETS; i++) {
@@ -446,32 +790,25 @@
  */
 static void sdram_set_spd_registers(const struct mem_controller *ctrl)
 {
-	/* TODO: Don't hardcode the values here, get info via SPD. */
+	PRINT_DEBUG("Reading SPD Registers...\r\n");
 
-	/* TODO: Set DRB0-DRB7. */
-	pci_write_config8(ctrl->d0, DRB0, 0x08);
-	pci_write_config8(ctrl->d0, DRB1, 0x08);
-	pci_write_config8(ctrl->d0, DRB2, 0x08);
-	pci_write_config8(ctrl->d0, DRB3, 0x08);
-	pci_write_config8(ctrl->d0, DRB4, 0x08);
-	pci_write_config8(ctrl->d0, DRB5, 0x08);
-	pci_write_config8(ctrl->d0, DRB6, 0x08);
-	pci_write_config8(ctrl->d0, DRB7, 0x08);
+	/* Set DRB0-DRB7. */
+	spd_set_drb(ctrl);
 
-	/* TODO: Set DRAMC. Don't enable refresh for now. */
-	pci_write_config8(ctrl->d0, DRAMC, 0x08);
+	/* Set DRAMC. Don't enable refresh for now. */
+	spd_set_dramc(ctrl);
 
-	/* TODO: Set RPS. */
-	pci_write_config16(ctrl->d0, RPS, 0x0001);
+	/* Set RPS. */
+	spd_set_rps(ctrl);
 
-	/* TODO: Set SDRAMC. */
-	// pci_write_config16(ctrl->d0, SDRAMC, 0x0000);
+	/* Set SDRAMC. */
+	spd_set_sdramc(ctrl);
 
-	/* TODO: Set PGPOL. */
-	pci_write_config16(ctrl->d0, PGPOL, 0x0107);
+	/* Set PGPOL. */
+	spd_set_pgpol(ctrl);
 
-	/* TODO: Set NBXCFG. */
-	// pci_write_config32(ctrl->d0, NBXCFG, 0x0100220c);
+	/* Set NBXCFG. */
+	spd_set_nbxcfg(ctrl);
 
 	/* TODO: Set PMCR? */
 	// pci_write_config8(ctrl->d0, PMCR, 0x14);
@@ -495,45 +832,51 @@
 	int i;
 
 	/* TODO: Use a delay here? Needed? */
-	mdelay(200);
+	/* Wait at least 1msec after device deselect (when is that?) */
+	mdelay(1);
 
-	/* TODO: How long should the delays be? Fix later. */
+	/* RAM Timings (tRP, tRC, tMRD) from SPD are on the order or 
+	 * nanoseconds (max=255ns) so 1usec should be more than enough 
+	 * time for any given SDRAM. */
 
 	/* 1. Apply NOP. */
 	PRINT_DEBUG("RAM Enable 1: Apply NOP\r\n");
 	do_ram_command(ctrl, RAM_COMMAND_NOP, 0);
-	mdelay(10);
+	udelay(200); /* minimum pause of 200usec after the NOP */
 
 	/* 2. Precharge all. Wait tRP. */
 	PRINT_DEBUG("RAM Enable 2: Precharge all\r\n");
-	do_ram_command(ctrl, RAM_COMMAND_PRECHARGE, 0);
-	mdelay(10);
+	do_ram_command(ctrl, RAM_COMMAND_PRECHARGE, 0x2000);
+	udelay(1);
 
 	/* 3. Perform 8 refresh cycles. Wait tRC each time. */
 	PRINT_DEBUG("RAM Enable 3: CBR\r\n");
 	for (i = 0; i < 8; i++) {
 		do_ram_command(ctrl, RAM_COMMAND_CBR, 0);
-		mdelay(10);
+		udelay(1);
 	}
 
 	/* 4. Mode register set. Wait two memory cycles. */
 	PRINT_DEBUG("RAM Enable 4: Mode register set\r\n");
-	do_ram_command(ctrl, RAM_COMMAND_MRS, 0x1d0);
-	// TODO: Is 0x1d0 correct?
-	// do_ram_command(ctrl, RAM_COMMAND_MRS, 0x1d0000);
-	mdelay(10);
-	mdelay(10);
+	/* Compute MRS Opcode (Burst length = 4, Interleaved) */
+	i = 0x2a;
+	/* If CAS = 3, modify opcode */
+	if (pci_read_config8(ctrl->d0, SDRAMC) & 0x4 == 0) 
+		i |= 0x10;
+	i <<= 3;
+	do_ram_command(ctrl, RAM_COMMAND_MRS, i); //0x1d0
+	udelay(1);
 
 	/* 5. Normal operation. */
 	PRINT_DEBUG("RAM Enable 5: Normal operation\r\n");
 	do_ram_command(ctrl, RAM_COMMAND_NORMAL, 0);
-	mdelay(10);
+	udelay(1);
 
 	/* 6. Finally enable refresh. */
 	PRINT_DEBUG("RAM Enable 6: Enable refresh\r\n");
 	// pci_write_config8(ctrl->d0, PMCR, 0x10);
 	spd_enable_refresh(ctrl);
-	mdelay(10);
+	udelay(1);
 
 	PRINT_DEBUG("Northbridge following SDRAM init:\r\n");
 	DUMPNORTH();
