On 03/02/2010 11:19 PM, Keith Hui wrote:
Hi all,

This thing is now ready for more exposure. Scratch my previous "patch" -
this is my first real deal.

- Adds Asus P2B-LS mainboard
- Adds RAM detection for i440bx (based on i82830 code). We're no longer
hard coded for 64MB on one row!
- Adds a proper Slot 1 cpu under src/cpu/intel/slot_1. It's a stub
copied from slot_2 but addresses a few FIXMEs. My P2B-LS code refers to
this.
- Adds microcode for Intel Tualatin CPUs, cpuid 6B1 and 6B4.* Actually
loading them is pending.

Signed-off-by: Keith Hui <[email protected] <mailto:[email protected]>>

Enjoy.

Keith

* Microcodes for all Intel CPUs can be downloaded from Intel -
downloadcenter.intel.com <http://downloadcenter.intel.com>. So TODO for
me is to add all microcode updates from Klamath to Tualatin as the Asus
P2B family, with the right mods and/or adapter, can run anything in
between that can fit either Slot 1 or Socket 370.


I would not worry about the microcode updates right now. CAR for Intel 6bx is coming real soon and the microcode updates will be included :-)

See other comments below.


Index: src/northbridge/intel/i440bx/raminit.c
===================================================================
--- src/northbridge/intel/i440bx/raminit.c      (revision 5184)
+++ 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 <[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.
@@ -65,12 +67,24 @@
  * [4] == Extended(4x)    62.5 us ->  62.4 us
  * [5] == Extended(8x)     125 us -> 124.8 us
  */
-static const uint32_t refresh_rate_map[] = {
-       1, 5, 5, 2, 3, 4
+static const unsigned int refresh_rate_map[] = {
+       1, 1, 1, 2, 3, 4
 };

 /* Table format: register, bitmask, value. */
 static const long register_values[] = {
+       /* MLT - Master Latency Timer Register
+        * 0x0d
+        *
+        * [07:03] Master Latency Timer Count Value for PCI Bus Access.
+        *         MLT is an 8-bit register that controls the amount of
+        *                 time the 82443BX, as a PCI bus master, can burst data
+        *                 on the PCI Bus. The default value of MLT is 00h and
+        *                 disables this function. For example, if the MLT is
+        *                 programmed to 18h, then the value is 24 PCI clocks.
+        * [02:00] Reserved
+        */
+       MLT, 0x00, 0x40,
        /* NBXCFG - NBX Configuration Register
         * 0x50 - 0x53
         *
@@ -188,14 +202,21 @@
         * 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
@@ -343,6 +364,8 @@
        // PMCR, 0x00, 0x14,
        // PMCR, 0x00, 0x10,
        PMCR, 0x00, 0x00,
+       /* Enable SCRR.SRRAEN and let BX choose the SRR */
+       SCRR+1, 0x00, 0x10,
 };


/*-----------------------------------------------------------------------------
@@ -396,7 +419,7 @@

                dimm_end = pci_read_config8(NB, DRB + i);

-               addr = (dimm_start * 8 * 1024 * 1024) + addr_offset;
+               addr = (dimm_start * 8 * 1048576) + addr_offset;
                if (dimm_end > dimm_start) {
 #if 0
                        PRINT_DEBUG("    Sending RAM command 0x");
@@ -414,6 +437,22 @@
        }
 }

+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.

-----------------------------------------------------------------------------*/
@@ -461,71 +500,305 @@
                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)
+/* Copied from i82830 northbridge code */
+struct dimm_size {
+       unsigned long side1;
+       unsigned long side2;
+};
+
+static struct dimm_size spd_get_dimm_size(unsigned 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);

-       /* 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.
+       /* 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;
+               }
+       }
+
+       /* 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 to see if there's a second value, if so it's 
asymmetrical. */
+               if (module_density != i) {
+                       /* Find the 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);
+       sz.side1 *= 4;
+       sz.side2 *= 4;
+       return sz;
+}
+/*
+   Sets DRAM attributes one DIMM at a time, based on SPD data
+   Northbridge settings that got set here:
+
+   NBXCFG[31:24]
+   DRB0-DRB7
+   RPS
+   DRAMC
+ */
+static void set_dram_row_attributes(void)


**********You are setting alot more than just dra here, I would rename this function something like sdram_setup_registers().



+{
+       int i, dra, drb, col, width, value, rps, edosd, ecc, nbxecc;
+       u8 bpr; // Top 8 bits of PGPOL
+       
+       edosd = 0;
+       rps = 0;
+       drb = 0;
+       bpr = 0;
+       nbxecc=0xff;
+       
+       for (i = 0; i < DIMM_SOCKETS; i++) {
+               unsigned device;
+               device = DIMM_SPD_BASE + i;
+               bpr >>= 2;

-       /* 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);
+               /* First check if a DIMM is actually present. */
+               value = spd_read_byte(device, SPD_MEMORY_TYPE);
+               /* This is BX! We do EDO too! */
+               if (value == SPD_MEMORY_TYPE_EDO || value == 
SPD_MEMORY_TYPE_SDRAM) {

-       /* TODO: Set DRAMC. Don't enable refresh for now. */
-       pci_write_config8(NB, DRAMC, 0x08);
+                       PRINT_DEBUG("Found ");
+                       if (value == SPD_MEMORY_TYPE_EDO) {
+                               edosd |= 0x02;
+                       } else if (value == SPD_MEMORY_TYPE_SDRAM) {
+                               edosd = edosd | 0x04;
+                       }
+                       PRINT_DEBUG("DIMM in slot ");
+                       PRINT_DEBUG_HEX8(i);
+                       PRINT_DEBUG("\r\n");

-       /* TODO: Set RPS. Needs to be fixed for multiple DIMM support. */
-       pci_write_config16(NB, RPS, 0x0001);
+                       if (edosd == 0x06) {
+                               print_err("Mixing EDO/SDRAM not supported\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 this 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 */
+                          /* Top 2 bits are clear to help set up NBXCFG */
+                          ecc &= 0x3f;
+                       } else {
+                          /* Without ECC, these top 2 bits should be 11 */
+                          ecc |= 0xc0;
+                       }
+                       
+                       /* calculate page size in bits */
+                       value = ((1 << col) * width);
+
+                       /* convert to Kilobytes */
+                       dra = (value >> 13);
+
+                       /* # 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 not 
supported\r\n");
+                               die("HALT\r\n");
+                       }
+                       if (dra == -1) {
+                               print_err("Page size not supported\r\n");
+                               die("HALT\r\n");
+                       }
+
+ /* The 440BX supports asymmetrical dual-sided dimms (I can't test though)
+                        * 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\nare not supported on this northbridge\r\n");
+                               die("HALT\r\n");
+                       }
+                       if ((sz.side1 > 128)) {
+ print_err ("DIMMs larger than 128MB per side\r\nare not supported on this northbridge\r\n");
+                               die("HALT\r\n");
+                       }
+                       /* - End Memory compatibility checks - */
+
+                       /* We need to divide size by 8 to set up the
+                        * DRB registers.
+                        */
+                       drb += (sz.side1 / 8);
+                       /* Builds 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 value 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: Account for registered SDRAM
+        */
+       edosd &= 0x07;
+       if (edosd & 0x02) {
+          edosd |= 0x00;
+       } else if (edosd & 0x04) {
+          edosd |= 0x08;
+       }
+       edosd &= 0x18;
+       /* edosd by now has been transformed to the value 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_set_timing(unsigned int mhz) {
+          /* TODO */
+
+}
+
 static void sdram_enable(void)
 {
        int i;

************I also noticed you did not use the memory initialize each row/side code from the i830. That code is extremely important for multiple memory sticks. Besides that everything else looks really good, great work!



--
Thanks,
Joseph Smith
Set-Top-Linux
www.settoplinux.org

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

Reply via email to