Author: uwe
Date: Sat Mar  6 19:16:25 2010
New Revision: 5194
URL: http://tracker.coreboot.org/trac/coreboot/changeset/5194

Log:
440BX: Do not hardcode DIMM number + size anymore.

The code currently assumes a 4-DIMM-slots board, this will be fixed soon.

Signed-off-by: Keith Hui <[email protected]>
Acked-by: Uwe Hermann <[email protected]>

Modified:
   trunk/src/northbridge/intel/i440bx/i440bx.h
   trunk/src/northbridge/intel/i440bx/raminit.c

Modified: trunk/src/northbridge/intel/i440bx/i440bx.h
==============================================================================
--- trunk/src/northbridge/intel/i440bx/i440bx.h Sat Mar  6 17:19:11 2010        
(r5193)
+++ trunk/src/northbridge/intel/i440bx/i440bx.h Sat Mar  6 19:16:25 2010        
(r5194)
@@ -32,11 +32,27 @@
  * Any addresses between 0x00 and 0xff not listed below are either
  * Reserved or Intel Reserved and should not be touched.
  */
+
 #define NBXCFG  0x50 /* 440BX Configuration (0x0000:00S0_0000_000S_0S00b). */
 #define DRAMC   0x57 /* DRAM Control (00S0_0000b). */
 #define DRAMT   0x58 /* DRAM Timing (0x03). */
 #define PAM     0x59 /* Programmable Attribute Map, 7 registers (0x00). */
+#define PAM0    0x59
+#define PAM1    0x5a
+#define PAM2    0x5b
+#define PAM3    0x5c
+#define PAM4    0x5d
+#define PAM5    0x5e
+#define PAM6    0x5f
 #define DRB     0x60 /* DRAM Row Boundary, 8 registers (0x01). */
+#define DRB0    0x60
+#define DRB1    0x61
+#define DRB2    0x62
+#define DRB3    0x63
+#define DRB4    0x64
+#define DRB5    0x65
+#define DRB6    0x66
+#define DRB7    0x67
 #define FDHC    0x68 /* Fixed SDRAM Hole Control (0x00). */
 #define MBSC    0x69 /* Memory Buffer Strength Control (0x0000-0000-0000). */
 #define SMRAM   0x72 /* System Management RAM Control (0x02). */
@@ -50,27 +66,24 @@
 #define ERRCMD  0x90 /* Error Command Register (0x80). */
 #define ERRSTS  0x91 /* Error Status (0x0000). */
 // TODO: AGP stuff.
+#define ACAPID  0xa0 /* AGP Capability Identifier (0x00100002 or 0x00000000) */
+#define AGPSTAT 0xa4 /* AGP Status Register (0x1f000203, read only) */
+#define AGPCMD  0xa8 /* AGP Command Register (0x00000000) */
+#define AGPCTRL 0xb0 /* AGP Control Register (0x00000000) */
+#define APSIZE  0xb4 /* Aperture Size Control Register (0x00) */
+#define ATTBASE 0xb8 /* Aperture Translation Table (0x00000000) */
+ 
 #define MBFS    0xca /* Memory Buffer Frequency Select (0x000000). */
 #define BSPAD   0xd0 /* BIOS Scratch Pad (0x000..000). */
+#define BSPAD0  0xd0 /* These are free for our use. */ 
+#define BSPAD1  0xd1
+#define BSPAD2  0xd2
+#define BSPAD3  0xd3
+#define BSPAD4  0xd4
+#define BSPAD5  0xd5
+#define BSPAD6  0xd6
+#define BSPAD7  0xd7
 #define DWTC    0xe0 /* DRAM Write Thermal Throttling Control (0x000..000). */
 #define DRTC    0xe8 /* DRAM Read Thermal Throttling Control (0x000..000). */
 #define BUFFC   0xf0 /* Buffer Control Register (0x0000). */
 
-/* For convenience: */
-#define DRB0    0x60
-#define DRB1    0x61
-#define DRB2    0x62
-#define DRB3    0x63
-#define DRB4    0x64
-#define DRB5    0x65
-#define DRB6    0x66
-#define DRB7    0x67
-
-#define PAM0    0x59
-#define PAM1    0x5a
-#define PAM2    0x5b
-#define PAM3    0x5c
-#define PAM4    0x5d
-#define PAM5    0x5e
-#define PAM6    0x5f
-

Modified: trunk/src/northbridge/intel/i440bx/raminit.c
==============================================================================
--- trunk/src/northbridge/intel/i440bx/raminit.c        Sat Mar  6 17:19:11 
2010        (r5193)
+++ trunk/src/northbridge/intel/i440bx/raminit.c        Sat Mar  6 19:16:25 
2010        (r5194)
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2007-2008 Uwe Hermann <[email protected]>
+ * Copyright (C) 2010 Keith Hui <[email protected]>
  *
  * 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
@@ -23,6 +24,7 @@
 #include <delay.h>
 #include <stdlib.h>
 #include "i440bx.h"
+#include "raminit.h"
 
 /*-----------------------------------------------------------------------------
 Macros and definitions.
@@ -185,14 +187,23 @@
         * 10 = Write Only (Writes to DRAM, reads to memory mapped I/O space)
         * 11 = Read/Write (all access goes to DRAM)
         */
-       // TODO
-       PAM0, 0x00, 0x00,
-       PAM1, 0x00, 0x00,
-       PAM2, 0x00, 0x00,
-       PAM3, 0x00, 0x00,
-       PAM4, 0x00, 0x00,
-       PAM5, 0x00, 0x00,
-       PAM6, 0x00, 0x00,
+
+       /*
+        * 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
+        * registers are not set here appropriately, the RAM in that region
+        * will not be accessible, thus a RAM check of it will also fail.
+        *
+        * TODO: This was set in sdram_set_spd_registers().
+        * Test if it still works when set here.
+        */
+       PAM0, 0x00, 0x30,
+       PAM1, 0x00, 0x33,
+       PAM2, 0x00, 0x33,
+       PAM3, 0x00, 0x33,
+       PAM4, 0x00, 0x33,
+       PAM5, 0x00, 0x33,
+       PAM6, 0x00, 0x33,
 
        /* DRB[0:7] - DRAM Row Boundary Registers
         * 0x60 - 0x67
@@ -340,6 +351,9 @@
        // PMCR, 0x00, 0x14,
        // PMCR, 0x00, 0x10,
        PMCR, 0x00, 0x00,
+
+       /* Enable SCRR.SRRAEN and let BX choose the SRR. */
+       SCRR + 1, 0x00, 0x10,
 };
 
 /*-----------------------------------------------------------------------------
@@ -374,8 +388,8 @@
        /* Send the RAM command to each row of memory. */
        dimm_start = 0;
        for (i = 0; i < (DIMM_SOCKETS * 2); i++) {
-                addr_offset = 0;
-                caslatency = 3; /* TODO: Dynamically get CAS latency later. */
+               addr_offset = 0;
+               caslatency = 3; /* TODO: Dynamically get CAS latency later. */
                if (command == RAM_COMMAND_MRS) {
                        /*
                         * MAA[12:11,9:0] must be inverted when sent to DIMM
@@ -411,6 +425,19 @@
        }
 }
 
+static void set_dram_buffer_strength(void)
+{
+       /* TODO: This needs to be set 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
+        *
+        * Relevant registers: MBSC, MBFS, BUFFC.
+        */
+
+       pci_write_config8(NB, MBSC, 0x03);
+}
+
 /*-----------------------------------------------------------------------------
 DIMM-independant configuration functions.
 -----------------------------------------------------------------------------*/
@@ -458,69 +485,311 @@
                reg &= register_values[i + 1];
                reg |= register_values[i + 2] & ~(register_values[i + 1]);
                pci_write_config8(NB, register_values[i], reg);
-
+#if 0
                PRINT_DEBUG("    Set register 0x");
                PRINT_DEBUG_HEX8(register_values[i]);
                PRINT_DEBUG(" to 0x");
                PRINT_DEBUG_HEX8(reg);
                PRINT_DEBUG("\r\n");
+#endif
        }
 }
 
-static void sdram_set_spd_registers(void)
+struct dimm_size {
+       unsigned long side1;
+       unsigned long side2;
+};
+
+static struct dimm_size spd_get_dimm_size(unsigned int device)
 {
-       /* TODO: Don't hardcode the values here, get info via SPD. */
+       struct dimm_size sz;
+       int i, module_density, dimm_banks;
+       sz.side1 = 0;
+       module_density = spd_read_byte(device, 
SPD_DENSITY_OF_EACH_ROW_ON_MODULE);
+       dimm_banks = spd_read_byte(device, SPD_NUM_DIMM_BANKS);
+
+       /* Find the size of side1. */
+       /* Find the larger value. The larger value is always side1. */
+       for (i = 512; i >= 0; i >>= 1) {
+               if ((module_density & i) == i) {
+                       sz.side1 = i;
+                       break;
+               }
+       }
 
-       /* 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
-        * registers are not set here appropriately, the RAM in that region
-        * will not be accessible, thus a RAM check of it will also fail.
+       /* Set to 0 in case it's single sided. */
+       sz.side2 = 0;
+
+       /* Test if it's a dual-sided DIMM. */
+       if (dimm_banks > 1) {
+               /* Test if there's a second value. If so it's asymmetrical. */
+               if (module_density != i) {
+                       /*
+                        * Find second value, picking up where we left off.
+                        * i >>= 1 done initially to make sure we don't get
+                        * the same value again.
+                        */
+                       for (i >>= 1; i >= 0; i >>= 1) {
+                               if (module_density == (sz.side1 | i)) {
+                                       sz.side2 = i;
+                                       break;
+                               }
+                       }
+                       /* If not, it's symmetrical. */
+               } else {
+                       sz.side2 = sz.side1;
+               }
+       }
+
+       /*
+        * SPD byte 31 is the memory size divided by 4 so we
+        * need to muliply by 4 to get the total size.
         */
-       pci_write_config8(NB, PAM0, 0x30);
-       pci_write_config8(NB, PAM1, 0x33);
-       pci_write_config8(NB, PAM2, 0x33);
-       pci_write_config8(NB, PAM3, 0x33);
-       pci_write_config8(NB, PAM4, 0x33);
-       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);
+       sz.side1 *= 4;
+       sz.side2 *= 4;
+
+       return sz;
+}
+/*
+ * Sets DRAM attributes one DIMM at a time, based on SPD data.
+ * Northbridge settings that are set: NBXCFG[31:24], DRB0-DRB7, RPS, DRAMC.
+ */
+static void set_dram_row_attributes(void)
+{
+       int i, dra, drb, col, width, value, rps, edosd, ecc, nbxecc;
+       u8 bpr; /* Top 8 bits of PGPOL */
 
-       /* TODO: Set DRAMC. Don't enable refresh for now. */
-       pci_write_config8(NB, DRAMC, 0x08);
+       edosd = 0;
+       rps = 0;
+       drb = 0;
+       bpr = 0;
+       nbxecc = 0xff;
 
-       /* TODO: Set RPS. Needs to be fixed for multiple DIMM support. */
-       pci_write_config16(NB, RPS, 0x0001);
+       for (i = 0; i < DIMM_SOCKETS; i++) {
+               unsigned int device;
+               device = DIMM_SPD_BASE + i;
+               bpr >>= 2;
+
+               /* First check if a DIMM is actually present. */
+               value = spd_read_byte(device, SPD_MEMORY_TYPE);
+               /* This is 440BX! We do EDO too! */
+               if (value == SPD_MEMORY_TYPE_EDO
+                       || value == SPD_MEMORY_TYPE_SDRAM) {
+
+                       PRINT_DEBUG("Found ");
+                       if (value == SPD_MEMORY_TYPE_EDO) {
+                               edosd |= 0x02; 
+                       } else if (value == SPD_MEMORY_TYPE_SDRAM) { 
+                               edosd |= 0x04; 
+                       }
+                       PRINT_DEBUG("DIMM in slot ");
+                       PRINT_DEBUG_HEX8(i);
+                       PRINT_DEBUG("\r\n");
+
+                       if (edosd == 0x06) { 
+                               print_err("Mixing EDO/SDRAM unsupported!\r\n");
+                               die("HALT\r\n");
+                       }
+
+                       /* "DRA" is our RPS for the two rows on this DIMM. */
+                       dra = 0;
+
+                       /* Columns */
+                       col = spd_read_byte(device, SPD_NUM_COLUMNS);
+
+                       /*
+                        * Is this an ECC DIMM? Actually will be a 2 if so.
+                        * TODO: Other register than NBXCFG also needs this
+                        * ECC information.
+                        */
+                       ecc = spd_read_byte(device, SPD_DIMM_CONFIG_TYPE);
+
+                       /* Data width */
+                       width = spd_read_byte(device, 
SPD_MODULE_DATA_WIDTH_LSB);
+                       
+                       /* Exclude error checking data width from page size 
calculations */
+                       if (ecc) {
+                               value = spd_read_byte(device,
+                                       SPD_ERROR_CHECKING_SDRAM_WIDTH);
+                               width -= value;
+                               /* ### ECC */
+                               /* Clear top 2 bits to help set up NBXCFG. */
+                               ecc &= 0x3f;
+                       } else {
+                               /* Without ECC, top 2 bits should be 11. */
+                               ecc |= 0xc0;
+                       }
+
+                       /* Calculate page size in bits. */
+                       value = ((1 << col) * width);
+
+                       /* Convert to KB. */
+                       dra = (value >> 13);
+
+                       /* Number of banks of DIMM (single or double sided). */
+                       value = spd_read_byte(device, SPD_NUM_DIMM_BANKS);
+
+                       /* Once we have dra, col is done and can be reused.
+                        * So it's reused for number of banks.
+                        */
+                       col = spd_read_byte(device, SPD_NUM_BANKS_PER_SDRAM);
+
+                       if (value == 1) {
+                               /*
+                                * Second bank of 1-bank DIMMs "doesn't have
+                                * ECC" - or anything.
+                                */
+                               ecc |= 0x80;
+                               if (dra == 2) {
+                                       dra = 0x0; /* 2KB */
+                               } else if (dra == 4) {
+                                       dra = 0x1; /* 4KB */
+                               } else if (dra == 8) {
+                                       dra = 0x2; /* 8KB */
+                               } else {
+                                       dra = -1;
+                               }
+                               /*
+                                * Sets a flag in PGPOL[BPR] if this DIMM has
+                                * 4 banks per row.
+                                */
+                               if (col == 4)
+                                       bpr |= 0x40;
+                       } else if (value == 2) {
+                               if (dra == 2) {
+                                       dra = 0x0; /* 2KB */
+                               } else if (dra == 4) {
+                                       dra = 0x05; /* 4KB */
+                               } else if (dra == 8) {
+                                       dra = 0x0a; /* 8KB */
+                               } else {
+                                       dra = -1;
+                               }
+                               /* Ditto */
+                               if (col == 4)
+                                       bpr |= 0xc0;
+                       } else {
+                               print_err("# of banks of DIMM 
unsupported!\r\n");
+                               die("HALT\r\n");
+                       }
+                       if (dra == -1) {
+                               print_err("Page size not supported\r\n");
+                               die("HALT\r\n");
+                       }
+
+                       /*
+                        * 440BX supports asymmetrical dual-sided DIMMs,
+                        * but can't handle DIMMs smaller than 8MB per
+                        * side or larger than 128MB per side.
+                        */
+                       struct dimm_size sz = spd_get_dimm_size(device);
+                       if ((sz.side1 < 8)) {
+                               print_err("DIMMs smaller than 8MB per side\r\n"
+                                         "are not supported on this NB.\r\n");
+                               die("HALT\r\n");
+                       }
+                       if ((sz.side1 > 128)) {
+                               print_err ("DIMMs > 128MB per side\r\n"
+                                          "are not supported on this NB\r\n");
+                               die("HALT\r\n");
+                       }
+
+                       /* Divide size by 8 to set up the DRB registers. */
+                       drb += (sz.side1 / 8);
+
+                       /*
+                        * Build the DRB for the next row in MSB so it gets
+                        * placed in DRB[n+1] where it belongs when written
+                        * as a 16-bit word.
+                        */
+                       drb &= 0xff;
+                       drb |= (drb + (sz.side2 / 8)) << 8;
+               } else {
+#if 0
+                       PRINT_DEBUG("No DIMM found in slot ");
+                       PRINT_DEBUG_HEX8(i);
+                       PRINT_DEBUG("\r\n");
+#endif
+
+                       /* If there's no DIMM in the slot, set dra to 0x00. */
+                       dra = 0x00;
+                       ecc = 0xc0;
+                       /* Still have to propagate DRB over. */
+                       drb &= 0xff;
+                       drb |= (drb << 8);
+               }
+
+               pci_write_config16(NB, DRB + (2 * i), drb);
+#if 0
+               PRINT_DEBUG("DRB has been set to 0x");
+               PRINT_DEBUG_HEX16(drb);
+               PRINT_DEBUG("\r\n");
+#endif
+
+               /* Brings the upper DRB back down to be base for
+                * DRB calculations for the next two rows.
+                */
+               drb >>= 8;
+
+               rps |= (dra & 0x0f) << (i * 4);
+               nbxecc = (nbxecc >> 2) | (ecc & 0xc0);
+       }
+
+       /* Set paging policy register. */
+       pci_write_config8(NB, PGPOL + 1, bpr);
+       PRINT_DEBUG("PGPOL[BPR] has been set to 0x");
+       PRINT_DEBUG_HEX8(bpr);
+       PRINT_DEBUG("\r\n");
+
+       /* Set DRAM row page size register. */
+       pci_write_config16(NB, RPS, rps);
+       PRINT_DEBUG("RPS has been set to 0x");
+       PRINT_DEBUG_HEX16(rps);
+       PRINT_DEBUG("\r\n");
+
+       /* ### ECC */
+       pci_write_config8(NB, NBXCFG + 3, nbxecc);
+       PRINT_DEBUG("NBXECC[31:24] has been set to 0x");
+       PRINT_DEBUG_HEX8(nbxecc);
+       PRINT_DEBUG("\r\n");
+
+       /* Set DRAMC[4:3] to proper memory type (EDO/SDRAM).
+        * TODO: Registered SDRAM support.
+        */
+       edosd &= 0x07;
+       if (edosd & 0x02) {
+               edosd |= 0x00;
+       } else if (edosd & 0x04) {
+               edosd |= 0x08;
+       }
+       edosd &= 0x18;
+
+       /* edosd is now in the form needed for DRAMC[4:3]. */
+       value = pci_read_config8(NB, DRAMC) & 0xe7;
+       value |= edosd;
+       pci_write_config8(NB, DRAMC, value);
+       PRINT_DEBUG("DRAMC has been set to 0x");
+       PRINT_DEBUG_HEX8(value);
+       PRINT_DEBUG("\r\n");
+}
+
+static void sdram_set_spd_registers(void)
+{
+       /* Setup DRAM row boundary registers and other attributes. */
+       set_dram_row_attributes();
 
        /* TODO: Set SDRAMC. */
        pci_write_config16(NB, SDRAMC, 0x0010); /* SDRAMPWR=1: 4 DIMM config */
 
-       /* TODO: Set PGPOL. */
-       // pci_write_config16(NB, PGPOL, 0x0107);
-       pci_write_config16(NB, PGPOL, 0x0123);
-
-       /* TODO: Set NBXCFG. */
-       // pci_write_config32(NB, NBXCFG, 0x0100220c); // FIXME?
-       pci_write_config32(NB, NBXCFG, 0xff00800c);
+       /* TODO */
+       set_dram_buffer_strength();
 
        /* TODO: Set PMCR? */
        // pci_write_config8(NB, PMCR, 0x14);
        pci_write_config8(NB, PMCR, 0x10);
 
        /* TODO? */
-       pci_write_config8(NB, PCI_LATENCY_TIMER, 0x40);
        pci_write_config8(NB, DRAMT, 0x03);
-       pci_write_config8(NB, MBSC, 0x03);
-       pci_write_config8(NB, SCRR, 0x38);
 }
 
 static void sdram_enable(void)

-- 
coreboot mailing list: [email protected]
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to