Some more DIMM0 related cleanups and deduplication.
[coreboot.git] / src / northbridge / via / vt8601 / raminit.c
index 6f85189a601cbad1d68e976cb311e3804c9eabac..5e7611a3c0d87be98422fea5ec34ea8751fcc323 100644 (file)
@@ -1,6 +1,6 @@
-#include <cpu/p6/mtrr.h>
+#include <cpu/x86/mtrr.h>
 #include "raminit.h"
-#if 0
+
 /*
 This software and ancillary information (herein called SOFTWARE )
 called LinuxBIOS          is made available under the terms described
@@ -13,7 +13,7 @@ U.S. Government has rights to use, reproduce, and distribute this
 SOFTWARE.  The public may copy, distribute, prepare derivative works
 and publicly display this SOFTWARE without charge, provided that this
 Notice and any statement of authorship are reproduced on all copies.
-Neither the Government nor the University makes any warranty, express 
+Neither the Government nor the University makes any warranty, express
 or implied, or assumes any liability or responsibility for the use of
 this SOFTWARE.  If SOFTWARE is modified to produce derivative works,
 such modified SOFTWARE should be clearly marked, so as not to confuse
@@ -32,580 +32,361 @@ it with the version available from LANL.
  * (Rest of configuration is done in C)
  * 5/19/03 by SONE Takeshi <ts1@tsn.or.jp>
  */
+/* converted to C 9/2003 Ron Minnich */
 
+#include <spd.h>
 
-/* Stable ~1 usec delay by hitting unused ISA port. */
-#define UDELAY(x) movl $x,%ecx; 9: outb %al,$0x81; loop 9b
+/* Set to 1 if your DIMMs are PC133 Note that I'm assuming CPU's FSB
+ * frequency is 133MHz. If your CPU runs at another bus speed, you
+ * might need to change some of register values.
+ */
+#ifndef DIMM_PC133
+#define DIMM_PC133 0
+#endif
 
-#define DIMMS_READ(x) \
-        movl 0x00000000+x, %eax; \
-        movl 0x10000000+x, %eax; \
-        movl 0x20000000+x, %eax; \
-        movl 0x30000000+x, %eax; \
-        movl 0x40000000+x, %eax; \
-        movl 0x50000000+x, %eax
+// Set to 1 if your DIMMs are CL=2
+#ifndef DIMM_CL2
+#define DIMM_CL2 0
+#endif
 
-#define DIMMS_WRITE(x) \
-        movl %eax, 0x00000000+x; \
-        movl %eax, 0x10000000+x; \
-        movl %eax, 0x20000000+x; \
-        movl %eax, 0x30000000+x; \
-        movl %eax, 0x40000000+x; \
-        movl %eax, 0x50000000+x
+static void dimms_read(unsigned long x)
+{
+       uint8_t c;
+       unsigned long eax;
+       volatile unsigned long y;
+       eax = x;
+       for (c = 0; c < 6; c++) {
+               y = *(volatile unsigned long *) eax;
+               eax += 0x10000000;
+       }
+}
+
+static void dimms_write(int x)
+{
+       uint8_t c;
+       unsigned long eax = x;
+       for (c = 0; c < 6; c++) {
+               *(volatile unsigned long *) eax = 0;
+               eax += 0x10000000;
+       }
+}
+
+#if CONFIG_DEBUG_RAM_SETUP
+static void dumpnorth(device_t north)
+{
+       unsigned int r, c;
+       for (r = 0;; r += 16) {
+               print_debug_hex8(r);
+               print_debug(":");
+               for (c = 0; c < 16; c++) {
+                       print_debug_hex8(pci_read_config8(north, r + c));
+                       print_debug(" ");
+               }
+               print_debug("\n");
+               if (r >= 240)
+                       break;
+       }
+}
+#endif
 
-raminit:
-       intel_chip_post_macro(0x35)
+static void sdram_set_registers(const struct mem_controller *ctrl)
+{
+       device_t north = (device_t) PCI_DEV(0, 0, 0);
+
+       print_err("vt8601 init starting\n");
+       print_debug_hex32(north);
+       print_debug(" is the north\n");
+       print_debug_hex16(pci_read_config16(north, 0));
+       print_debug(" ");
+       print_debug_hex16(pci_read_config16(north, 2));
+       print_debug("\n");
+
+       /* All we are doing now is setting initial known-good values that will
+        * be revised later as we read SPD
+        */
 
        // memory clk enable. We are not using ECC
-       CS_WRITE($0x78, $0x01)
-       // dram control, see the book. 
+       pci_write_config8(north, 0x78, 0x01);
+       print_debug_hex8(pci_read_config8(north, 0x78));
+
+       // dram control, see the book.
 #if DIMM_PC133
-       CS_WRITE($0x68, $0x52)
+       pci_write_config8(north, 0x68, 0x52);
 #else
-        CS_WRITE($0x68, $0x42)
+       pci_write_config8(north, 0x68, 0x42);
 #endif
-       // dram control, see the book. 
-       CS_WRITE($0x6B, $0x0c)
+
+       // dram control, see the book.
+       pci_write_config8(north, 0x6B, 0x0c);
+
        // Initial setting, 256MB in each bank, will be rewritten later.
-       CS_WRITE($0x5A, $0x20)
-       CS_WRITE($0x5B, $0x40)
-       CS_WRITE($0x5C, $0x60)
-       CS_WRITE($0x5D, $0x80)
-       CS_WRITE($0x5E, $0xA0)
-       CS_WRITE($0x5F, $0xC0)
-        // It seems we have to take care of these 2 registers as if 
-        // they are bank 6 and 7.
-        CS_WRITE($0x56, $0xC0)
-        CS_WRITE($0x57, $0xC0)
+       pci_write_config8(north, 0x5A, 0x20);
+       print_debug_hex8(pci_read_config8(north, 0x5a));
+       pci_write_config8(north, 0x5B, 0x40);
+       pci_write_config8(north, 0x5C, 0x60);
+       pci_write_config8(north, 0x5D, 0x80);
+       pci_write_config8(north, 0x5E, 0xA0);
+       pci_write_config8(north, 0x5F, 0xC0);
+       // It seems we have to take care of these 2 registers as if
+       // they are bank 6 and 7.
+       pci_write_config8(north, 0x56, 0xC0);
+       pci_write_config8(north, 0x57, 0xC0);
 
        // SDRAM in all banks
-       CS_WRITE($0x60, $0x3F)
+       pci_write_config8(north, 0x60, 0x3F);
+
        // DRAM timing. I'm suspicious of this
        // This is for all banks, 64 is 0,1.  65 is 2,3. 66 is 4,5.
        // ras precharge 4T, RAS pulse 5T
        // cas2 is 0xd6, cas3 is 0xe6
        // we're also backing off write pulse width to 2T, so result is 0xee
 #if DIMM_CL2
-       CS_WRITE($0x64, $0xd4)
-       CS_WRITE($0x65, $0xd4)
-       CS_WRITE($0x66, $0xd4)
-#else // CL=3
-       CS_WRITE($0x64, $0xe4)
-       CS_WRITE($0x65, $0xe4)
-       CS_WRITE($0x66, $0xe4)
+       pci_write_config8(north, 0x64, 0xd4);
+       pci_write_config8(north, 0x65, 0xd4);
+       pci_write_config8(north, 0x66, 0xd4);
+#else                          // CL=3
+       pci_write_config8(north, 0x64, 0xe4);
+       pci_write_config8(north, 0x65, 0xe4);
+       pci_write_config8(north, 0x66, 0xe4);
 #endif
 
        // dram frequency select.
-       // enable 4K pages for 64M dram. 
+       // enable 4K pages for 64M dram.
 #if DIMM_PC133
-       CS_WRITE($0x69, $0x3c)
+       pci_write_config8(north, 0x69, 0x3c);
 #else
-        CS_WRITE($0x69, $0xac)
+       pci_write_config8(north, 0x69, 0xac);
 #endif
+
+       /* IMPORTANT -- disable refresh counter */
        // refresh counter, disabled.
-       CS_WRITE($0x6A, $0x00)
+       pci_write_config8(north, 0x6A, 0x00);
+
        // clkenable configuration. kevinh FIXME - add precharge
-       CS_WRITE($0x6C, $0x00)
+       pci_write_config8(north, 0x6C, 0x00);
        // dram read latch delay of 1 ns, MD drive 8 mA,
-       // high drive strength on MA[2: 13], we#, cas#, ras#
+       // high drive strength on MA[2: 13], we#, cas#, ras#
        // As per Cindy Lee, set to 0x37, not 0x57
-       CS_WRITE($0x6D, $0x7f)
-
-        /* Initialize all banks at once */
-
-/* begin to initialize*/
-       // I forget why we need this, but we do
-       mov $0xa55a5aa5, %eax
-        DIMMS_WRITE(0)
-       
-/* set NOP*/
-       CS_WRITE($0x6C, $0x01)
-
-/* wait 200us*/
-       // You need to do the memory reference. That causes the nop cycle. 
-        DIMMS_READ(0)
-       UDELAY(400)
-
-/* set precharge */
-       CS_WRITE($0x6C, $0x02)
-
-/* dummy reads*/
-        DIMMS_READ(0)
-       UDELAY(200)
-
-/* set CBR*/
-       CS_WRITE($0x6C, $0x04)
-       
-/* do 8 reads and wait >100us between each - from via*/
-        DIMMS_READ(0)
-       UDELAY(200)
-        DIMMS_READ(0)
-       UDELAY(200)
-        DIMMS_READ(0)
-       UDELAY(200)
-        DIMMS_READ(0)
-       UDELAY(200)
-        DIMMS_READ(0)
-       UDELAY(200)
-        DIMMS_READ(0)
-       UDELAY(200)
-        DIMMS_READ(0)
-       UDELAY(200)
-        DIMMS_READ(0)
-       UDELAY(200)
-
-/* set MRS*/
-       CS_WRITE($0x6c, $0x03)
-#if DIMM_CL2
-        DIMMS_READ(0x150)
-#else // CL=3
-        DIMMS_READ(0x1d0)
-#endif
-       UDELAY(200)
-
-/* set to normal mode */
-       CS_WRITE($0x6C, $0x08)
-       movl $0x55aa55aa, %eax
-        DIMMS_WRITE(0)
-        DIMMS_READ(0)
-       UDELAY(200)
-
-       // Set the refresh rate. 
-#if DIMM_PC133
-       CS_WRITE($0x6A, $0x86)
-#else
-       CS_WRITE($0x6A, $0x65)
-#endif
-       // enable multi-page open
-       CS_WRITE($0x6B, $0x0d)
-
-        /* Begin auto-detection
-         * Find the first bank with DIMM equipped. */
-
-        /* Maximum possible memory in bank 0, none in other banks.
-         * Starting from bank 0, we's fill 0 in these registers
-         * until memory is found. */
-       CS_WRITE($0x5A, $0xff)
-       CS_WRITE($0x5B, $0xff)
-       CS_WRITE($0x5C, $0xff)
-       CS_WRITE($0x5D, $0xff)
-       CS_WRITE($0x5E, $0xff)
-       CS_WRITE($0x5F, $0xff)
-       CS_WRITE($0x56, $0xff)
-       CS_WRITE($0x57, $0xff)
-
-        movl $0x5A, %ebx // first bank
-1:
-        /* Write different values to 0 and 8, then read from 0.
-         * If values of address 0 match, we have something there. */
-        movl $0x12345678, %eax
-        movl %eax, 0
-        movl $0x87654321, %edx
-        movl %edx, 8
-        movl 0, %edx
-        cmpl %eax, %edx
-        je 2f
-        /* No memory in this bank. Tell it to the bridge. */
-        movl %ebx, %eax
-        xorl %edx, %edx
-        PCI_WRITE_CONFIG_BYTE
-        incl %ebx
-        cmpl $0x60, %ebx
-        jne 1b
-        /* No memory at all! */
-       CONSOLE_EMERG_TX_STRING($msg_nomem)
-1:
-        hlt
-        jmp 1b
-2:
-
-        /* Detect MA mapping type of the first bank. */
-
-        jmp raminit_ma
-raminit_ma_reg_table:
-        /* Values for MA type register to try */
-        .word 0x0000, 0x8088, 0xe0ee
-        .word 0xffff // end mark
-
-raminit_ma:
-        xorl %esi, %esi // highest address
-        movl $raminit_ma_reg_table, %ebx
-1:
-        movw (%ebx), %cx
-        cmpw $0xffff, %cx
-        je raminit_ma_done
-        movl $0x58, %eax
-        PCI_WRITE_CONFIG_WORD
-
-        xorl %eax, %eax
-        movl %eax, (%eax)
-
-        // Write to addresses with only one address bit on,
-        // from 0x80000000 to 0x00000008 (lower 3 bits are ignored, assuming 
-        // 64-bit bus).
-        // Then what is read at address 0 is the value written to the lowest
-        // address where it gets wrap-around. That address is either the size
-        // of the bank, or a missing bit due to incorrect MA mapping.
-        movl $0x80000000, %eax
-2:
-        movl %eax, (%eax)
-        shrl $1, %eax
-        cmpl $4, %eax
-        jne 2b
-
-        movl 0, %eax
-        cmpl %eax, %esi
-        jnc 3f
-
-        // This is the current best MA mapping.
-        // Save the address and its MA mapping value.
-        movl %eax, %esi
-        movl %ecx, %edi
-3:
-        incl %ebx
-        incl %ebx
-        jmp 1b
-
-
-raminit_ma_done:
-        // Set the best (hopefully correct) MA mapping type.
-        movl $0x58, %eax
-        movl %edi, %ecx
-        PCI_WRITE_CONFIG_WORD
-
-       CONSOLE_DEBUG_TX_STRING($msg_enabled)
-       CONSOLE_DEBUG_TX_HEX32(%esi)
-       CONSOLE_DEBUG_TX_STRING($msg_bytes)
-
-        /*
-         * We have the size of first bank in %esi, but throwing it away.
-         * Sizing will again be done in C, because we'll configure the rest
-         * of banks in there anyway.
-         */
-
-        //CALLSP(dumpnorth)
-
-       intel_chip_post_macro(0x36)
-
-
-        .section ".rom.data"
-msg_nomem:
-        .asciz "No memory\r\n"
-msg_enabled:
-        .asciz "Enabled first bank of RAM: 0x"
-msg_bytes:
-        .asciz " bytes\r\n"
-        .previous
-#endif
+       pci_write_config8(north, 0x6D, 0x7f);
+}
 
-       /* this is an early hack. We're going to just try to get memory
-        * working as it was before. I need help for SPD! RGM
+/* slot is the dram slot. Return size of side0 in lower 16-bit,
+ * side1 in upper 16-bit, in units of 8MB */
+static unsigned long spd_module_size(unsigned char slot)
+{
+       /* for all the DRAMS, see if they are there and get the size of each
+        * module. This is just a very early first cut at sizing.
         */
-// Set to 1 if your DIMMs are PC133
-// Note that I'm assuming CPU's FSB frequency is 133MHz. If your CPU runs
-// at another bus speed, you might need to change some of register values.
-#ifndef DIMM_PC133
-#define DIMM_PC133 0
-#endif
+       /* we may run out of registers ... */
+       unsigned int banks, rows, cols;
+       unsigned int value = 0;
+       /* unsigned int module = ((DIMM0 + slot) << 1) + 1; */
+       unsigned int module = DIMM0 + slot;
+
+       /* is the module there? if byte 2 is not 4, then we'll assume it
+        * is useless.
+        */
+       print_info("Slot ");
+       print_info_hex8(slot);
+       if (smbus_read_byte(module, 2) != 4) {
+               print_info(" is empty\n");
+               return 0;
+       }
+       print_info(" is SDRAM ");
+
+       banks = smbus_read_byte(module, 17);
+
+       /* we're going to assume symmetric banks. Sorry. */
+       cols = smbus_read_byte(module, 4) & 0xf;
+       rows = smbus_read_byte(module, 3) & 0xf;
+
+       /* grand total. You have rows+cols addressing, * times of banks, times
+        * width of data in bytes */
+       /* Width is assumed to be 64 bits == 8 bytes */
+       value = (1 << (cols + rows));
+       value *= banks * 8;
+       print_info_hex32(value);
+       print_info(" bytes ");
+       /* Return in 8MB units */
+       value >>= 23;
+
+       /* We should have single or double side */
+       if (smbus_read_byte(module, 5) == 2) {
+               print_info("x2");
+               value = (value << 16) | value;
+       }
+       print_info("\n");
+       return value;
+}
 
-// Set to 1 if your DIMMs are CL=2
-#ifndef DIMM_CL2
-#define DIMM_CL2 0
+#if 0
+static int spd_num_chips(unsigned char slot)
+{
+       unsigned int module = DIMM0 + slot;
+       unsigned int width;
+
+       width = smbus_read_byte(module, 13);
+       if (width == 0)
+               width = 8;
+       return 64 / width;
+}
 #endif
 
-         void dimms_read(unsigned long x) {
-         uint8_t c;
-         unsigned long eax; 
-         volatile unsigned long y;
-         eax =  x;
-         for(c = 0; c < 6; c++) {
-           
-           print_err("dimms_read: ");
-           print_err_hex32(eax);
-           print_err("\r\n");
-           y = * (volatile unsigned long *) eax;
-           eax += 0x10000000;
-         }
+static void sdram_set_spd_registers(const struct mem_controller *ctrl)
+{
+#define T133 7
+       unsigned char Trp = 1, Tras = 1, casl = 2, val;
+       unsigned char timing = 0xe4;
+       /* read Trp */
+       val = smbus_read_byte(DIMM0, 27);
+       if (val < 2 * T133)
+               Trp = 1;
+       val = smbus_read_byte(DIMM0, 30);
+       if (val < 5 * T133)
+               Tras = 0;
+       val = smbus_read_byte(DIMM0, 18);
+       if (val < 8)
+               casl = 1;
+       if (val < 4)
+               casl = 0;
+
+       val = (Trp << 7) | (Tras << 6) | (casl << 4) | 4;
+
+       print_debug_hex8(val);
+       print_debug(" is the computed timing\n");
+       /* don't set it. Experience shows that this screwy chipset should just
+        * be run with the most conservative timing.
+        * pci_write_config8(0, 0x64, val);
+        */
 }
 
-void dimms_write(int x) {
-  uint8_t c;
-  unsigned long eax = x;
-  for(c = 0; c < 6; c++) {
-    print_err("dimms_write: ");
-    print_err_hex32(eax);
-    print_err("\r\n");
-    *(volatile unsigned long *) eax = 0;
-    eax += 0x10000000;
-  }
+static void set_ma_mapping(device_t north, int slot, int type)
+{
+       unsigned char reg, val;
+       int shift;
+
+       reg = 0x58 + slot / 2;
+       if (slot % 2 >= 1)
+               shift = 0;
+       else
+               shift = 4;
+
+       val = pci_read_config8(north, reg);
+       val &= ~(0xf << shift);
+       val |= type << shift;
+       pci_write_config8(north, reg, val);
 }
 
-#define setnorthb pci_write_config8
-#if 0
-void setnorthb(device_t north, uint8_t reg, uint8_t val) {
-  print_err("setnorth: reg ");
-    print_err_hex8(reg);
-  print_err(" to ");
-  print_err_hex8(val);
-  print_err("\r\n");
-  pci_write_config8(north, reg, val);
-}
-#endif
 
-void
-dumpnorth(device_t north) {
-  uint8_t r, c;
-  for(r = 0; r < 256; r += 16) {
-    print_err_hex8(r);
-    print_err(":");
-    for(c = 0; c < 16; c++) {
-      print_err_hex8(pci_read_config8(north, r+c));
-      print_err(" ");
-    }
-    print_err("\r\n");
-  }
-}
-static void sdram_set_registers(const struct mem_controller *ctrl) {
-  static const uint16_t raminit_ma_reg_table[] = {
-    /* Values for MA type register to try */
-    0x0000, 0x8088, 0xe0ee,
-    0xffff // end mark
-  };
-  static const uint8_t ramregs[] = {0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 
-                                       0x56, 0x57};
-
-  device_t north = 0;
-  uint8_t c, r;
-
-  print_err("vt8601 init starting\n");
-  north = pci_locate_device(PCI_ID(0x1106, 0x8601), 0);
-  north = 0;
-  print_err_hex32(north);
-  print_err(" is the north\n");
-  print_err_hex16(pci_read_config16(north, 0));
-  print_err(" ");
-  print_err_hex16(pci_read_config16(north, 2));
-  print_err("\r\n");
-       
-  // memory clk enable. We are not using ECC
-  pci_write_config8(north,0x78, 0x01);
-  print_err_hex8(pci_read_config8(north, 0x78));
-  // dram control, see the book. 
-#if DIMM_PC133
-  pci_write_config8(north,0x68, 0x52);
-#else
-  pci_write_config8(north,0x68, 0x42);
-#endif
-  // dram control, see the book. 
-  pci_write_config8(north,0x6B, 0x0c);
-  // Initial setting, 256MB in each bank, will be rewritten later.
-  pci_write_config8(north,0x5A, 0x20);
-  print_err_hex8(pci_read_config8(north, 0x5a));
-  pci_write_config8(north,0x5B, 0x40);
-  pci_write_config8(north,0x5C, 0x60);
-  pci_write_config8(north,0x5D, 0x80);
-  pci_write_config8(north,0x5E, 0xA0);
-  pci_write_config8(north,0x5F, 0xC0);
-  // It seems we have to take care of these 2 registers as if 
-  // they are bank 6 and 7.
-  pci_write_config8(north,0x56, 0xC0);
-  pci_write_config8(north,0x57, 0xC0);
-
-  // SDRAM in all banks
-  pci_write_config8(north,0x60, 0x3F);
-  // DRAM timing. I'm suspicious of this
-  // This is for all banks, 64 is 0,1.  65 is 2,3. 66 is 4,5.
-  // ras precharge 4T, RAS pulse 5T
-  // cas2 is 0xd6, cas3 is 0xe6
-  // we're also backing off write pulse width to 2T, so result is 0xee
-#if DIMM_CL2
-  pci_write_config8(north,0x64, 0xd4);
-  pci_write_config8(north,0x65, 0xd4);
-  pci_write_config8(north,0x66, 0xd4);
-#else // CL=3
-  pci_write_config8(north,0x64, 0xe4);
-  pci_write_config8(north,0x65, 0xe4);
-  pci_write_config8(north,0x66, 0xe4);
-#endif
+static void sdram_enable(int controllers, const struct mem_controller *ctrl)
+{
+       static const uint8_t ramregs[] = {
+               0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x56, 0x57
+       };
+       device_t north = 0;
+       uint32_t size, base, slot, ma;
+       /* begin to initialize */
 
-  // dram frequency select.
-  // enable 4K pages for 64M dram. 
-#if DIMM_PC133
-  pci_write_config8(north,0x69, 0x3c);
-#else
-  pci_write_config8(north,0x69, 0xac);
-#endif
-  // refresh counter, disabled.
-  pci_write_config8(north,0x6A, 0x00);
-  // clkenable configuration. kevinh FIXME - add precharge
-  pci_write_config8(north,0x6C, 0x00);
-  // dram read latch delay of 1 ns, MD drive 8 mA,
-  // high drive strength on MA[2:      13], we#, cas#, ras#
-  // As per Cindy Lee, set to 0x37, not 0x57
-  pci_write_config8(north,0x6D, 0x7f);
-
-  /* Initialize all banks at once */
-
-  /* begin to initialize*/
-  // I forget why we need this, but we do
-  dimms_write(0xa55a5aa5);
-
-  /* set NOP*/
-  pci_write_config8(north,0x6C, 0x01);
-  print_err("NOP\r\n");
-  /* wait 200us*/
-  // You need to do the memory reference. That causes the nop cycle. 
-  dimms_read(0);
-  udelay(400);
-  print_err("PRECHARGE\r\n");
-  /* set precharge */
-  pci_write_config8(north,0x6C, 0x02);
-  print_err("DUMMY READS\r\n");
-  /* dummy reads*/
-  dimms_read(0);
-  udelay(200);
-  print_err("CBR\r\n");
-  /* set CBR*/
-  pci_write_config8(north,0x6C, 0x04);
-       
-  /* do 8 reads and wait >100us between each - from via*/
-  dimms_read(0);
-  udelay(200);
-  dimms_read(0);
-  udelay(200);
-  dimms_read(0);
-  udelay(200);
-  dimms_read(0);
-  udelay(200);
-  dimms_read(0);
-  udelay(200);
-  dimms_read(0);
-  udelay(200);
-  dimms_read(0);
-  udelay(200);
-  dimms_read(0);
-  udelay(200);
-  print_err("MRS\r\n");
-  /* set MRS*/
-  pci_write_config8(north,0x6c, 0x03);
+       // I forget why we need this, but we do
+       dimms_write(0xa55a5aa5);
+
+       /* set NOP */
+       pci_write_config8(north, 0x6C, 0x01);
+       print_debug("NOP\n");
+       /* wait 200us */
+       // You need to do the memory reference. That causes the nop cycle.
+       dimms_read(0);
+       udelay(400);
+       print_debug("PRECHARGE\n");
+       /* set precharge */
+       pci_write_config8(north, 0x6C, 0x02);
+       print_debug("DUMMY READS\n");
+       /* dummy reads */
+       dimms_read(0);
+       udelay(200);
+       print_debug("CBR\n");
+       /* set CBR */
+       pci_write_config8(north, 0x6C, 0x04);
+
+       /* do 8 reads and wait >100us between each - from via */
+       dimms_read(0);
+       udelay(200);
+       dimms_read(0);
+       udelay(200);
+       dimms_read(0);
+       udelay(200);
+       dimms_read(0);
+       udelay(200);
+       dimms_read(0);
+       udelay(200);
+       dimms_read(0);
+       udelay(200);
+       dimms_read(0);
+       udelay(200);
+       dimms_read(0);
+       udelay(200);
+       print_debug("MRS\n");
+       /* set MRS */
+       pci_write_config8(north, 0x6c, 0x03);
 #if DIMM_CL2
-  dimms_read(0x150);
-#else // CL=3
-  dimms_read(0x1d0);
+       dimms_read(0x150);
+#else                          // CL=3
+       dimms_read(0x1d0);
 #endif
-  udelay(200);
-  print_err("NORMAL\r\n");
-  /* set to normal mode */
-  pci_write_config8(north,0x6C, 0x08);
-
-  dimms_write(0x55aa55aa);
-  dimms_read(0);
-  udelay(200);
-  print_err("set ref. rate\r\n");
-  // Set the refresh rate. 
+       udelay(200);
+       print_debug("NORMAL\n");
+       /* set to normal mode */
+       pci_write_config8(north, 0x6C, 0x08);
+
+       dimms_write(0x55aa55aa);
+       dimms_read(0);
+       udelay(200);
+       print_debug("set ref. rate\n");
+       // Set the refresh rate.
 #if DIMM_PC133
-  pci_write_config8(north,0x6A, 0x86);
+       pci_write_config8(north, 0x6A, 0x86);
 #else
-  pci_write_config8(north,0x6A, 0x65);
+       pci_write_config8(north, 0x6A, 0x65);
 #endif
-  print_err("enable multi-page open\r\n");
-  // enable multi-page open
-  pci_write_config8(north,0x6B, 0x0d);
-
-  /* Begin auto-detection
-   * Find the first bank with DIMM equipped. */
-
-  /* Maximum possible memory in bank 0, none in other banks.
-   * Starting from bank 0, we fill 0 in these registers
-   * until memory is found. */
-  pci_write_config8(north,0x5A, 0xff);
-  pci_write_config8(north,0x5B, 0xff);
-  pci_write_config8(north,0x5C, 0xff);
-  pci_write_config8(north,0x5D, 0xff);
-  pci_write_config8(north,0x5E, 0xff);
-  pci_write_config8(north,0x5F, 0xff);
-  pci_write_config8(north,0x56, 0xff);
-  pci_write_config8(north,0x57, 0xff);
-  dumpnorth(north);
-  print_err("MA\r\n");
-  for(c = 0; c < 8; c++) {
-    /* Write different values to 0 and 8, then read from 0.
-     * If values of address 0 match, we have something there. */
-    print_err("write to 0\r\n");
-    *(volatile unsigned long *) 0 = 0x12345678;
-
-    /* LEAVE THIS HERE. IT IS ESSENTIAL. OTHERWISE BUFFERING
-     * WILL FOOL YOU!
-     */
-    print_err("write to 8\r\n");
-    *(volatile unsigned long *) 8 = 0x87654321;
-
-    if (*(volatile unsigned long *) 0 != 0x12345678) {
-      print_err("no memory in this bank\r\n");
-      /* No memory in this bank. Tell it to the bridge. */
-      pci_write_config8(north,ramregs[c], 0);
-    } 
-    /* found something */
-    {
-      uint8_t best = 0;
-
-      /* Detect MA mapping type of the bank. */
-
-      for(r = 0; r < 3; r++) {
-       volatile unsigned long esi = 0;
-       volatile unsigned long eax = 0;
-       pci_write_config8(north,0x58, raminit_ma_reg_table[r]);
-
-       * (volatile unsigned long *) eax = 0;
-       print_err(" done write to eax\r\n");
-       // Write to addresses with only one address bit
-       // on, from 0x80000000 to 0x00000008 (lower 3 bits
-       // are ignored, assuming 64-bit bus).  Then what
-       // is read at address 0 is the value written to
-       // the lowest address where it gets
-       // wrap-around. That address is either the size of
-       // the bank, or a missing bit due to incorrect MA
-       // mapping.
-       eax = 0x80000000;
-       while (eax !=  4) {
-         * (volatile unsigned long *) eax = eax;
-         //print_err_hex32(eax);
-         outb(eax&0xff, 0x80);
-         eax >>= 1;
-       }
-       print_err(" done read to eax\r\n");
-       eax = * (unsigned long *)0;
-       /* oh boy ... what is this. 
-          movl 0, %eax
-          cmpl %eax, %esi
-          jnc 3f
-       */
-       print_err("eax and esi: ");
-       print_err_hex32(eax); print_err(" ");
-       print_err_hex32(esi); print_err("\r\n");
-
-       if (eax > esi) { /* ??*/
-                     
-         // This is the current best MA mapping.
-         // Save the address and its MA mapping value.
-         best = r;
-         esi = eax;
+       print_debug("enable multi-page open\n");
+       // enable multi-page open
+       pci_write_config8(north, 0x6B, 0x0d);
+
+       base = 0;
+       for (slot = 0; slot < 4; slot++) {
+               size = spd_module_size(slot);
+               /* side 0 */
+               base += size & 0xffff;
+               pci_write_config8(north, ramregs[2 * slot], base);
+               /* side 1 */
+               base += size >> 16;
+               if (base > 0xff)
+                       base = 0xff;
+               pci_write_config8(north, ramregs[2 * slot + 1], base);
+
+               if (!size)
+                       continue;
+
+               /* Read the row densities */
+               size = smbus_read_byte(DIMM0 + slot, 0x1f);
+
+               /* Set the MA map type.
+                *
+                * 0xa should be another option, but when
+                * it would be used is unknown.
+                */
+
+               if (size < 16 ) /* less than 64 MB per side */
+                       ma = 0x0;
+               else if (size < 32) /* less than 128MB per side */
+                       ma = 0x8;
+               else if ( size < 64) /* less than 256MB per side */
+                       ma = 0xc;
+               else /* 256MB or more per side */
+                       ma = 0xe;
+               print_debug_hex16(ma);
+               print_debug(" is the MA type\n");
+               set_ma_mapping(north, slot, ma);
        }
-      }
-                 
-      pci_write_config8(north,0x58, raminit_ma_reg_table[best]);
-      print_err("enabled first bank of ram ... ma is ");
-      print_err_hex8(pci_read_config8(north, 0x58));
-      print_err("\r\n");
-    }
-  }
-  print_err("vt8601 done\n");
-  dumpnorth(north);
-  udelay(1000);
-}
-
-static void sdram_set_spd_registers(const struct mem_controller *ctrl) {
-}
-
-static void sdram_enable(int controllers, const struct mem_controller *ctrl) {
+       print_err("vt8601 done\n");
 }