]> git.sur5r.net Git - u-boot/blobdiff - cpu/ppc4xx/44x_spd_ddr2.c
ppc4xx: Update 440SP/440SPe DDR SPD setup code to support 440SP
[u-boot] / cpu / ppc4xx / 44x_spd_ddr2.c
index ab421196b944569767137b9bc88f10dfb22e1edd..c4da739607cc6154d1a323f4263e5d203be4fe2c 100644 (file)
@@ -34,6 +34,7 @@
 #endif
 
 #include <common.h>
+#include <command.h>
 #include <ppc4xx.h>
 #include <i2c.h>
 #include <asm/io.h>
@@ -43,6 +44,9 @@
 #if defined(CONFIG_SPD_EEPROM) &&                              \
        (defined(CONFIG_440SP) || defined(CONFIG_440SPE))
 
+/*-----------------------------------------------------------------------------+
+ * Defines
+ *-----------------------------------------------------------------------------*/
 #ifndef        TRUE
 #define TRUE           1
 #endif
 
 #define MULDIV64(m1, m2, d)    (u32)(((u64)(m1) * (u64)(m2)) / (u64)(d))
 
-#if defined(DEBUG)
-static void ppc440sp_sdram_register_dump(void);
-#endif
+#define CMD_NOP                (7 << 19)
+#define CMD_PRECHARGE  (2 << 19)
+#define CMD_REFRESH    (1 << 19)
+#define CMD_EMR                (0 << 19)
+#define CMD_READ       (5 << 19)
+#define CMD_WRITE      (4 << 19)
+
+#define SELECT_MR      (0 << 16)
+#define SELECT_EMR     (1 << 16)
+#define SELECT_EMR2    (2 << 16)
+#define SELECT_EMR3    (3 << 16)
+
+/* MR */
+#define DLL_RESET      0x00000100
+
+#define WRITE_RECOV_2  (1 << 9)
+#define WRITE_RECOV_3  (2 << 9)
+#define WRITE_RECOV_4  (3 << 9)
+#define WRITE_RECOV_5  (4 << 9)
+#define WRITE_RECOV_6  (5 << 9)
+
+#define BURST_LEN_4    0x00000002
+
+/* EMR */
+#define ODT_0_OHM      0x00000000
+#define ODT_50_OHM     0x00000044
+#define ODT_75_OHM     0x00000004
+#define ODT_150_OHM    0x00000040
+
+#define ODS_FULL       0x00000000
+#define ODS_REDUCED    0x00000002
+
+/* defines for ODT (On Die Termination) of the 440SP(e) DDR2 controller */
+#define ODT_EB0R       (0x80000000 >> 8)
+#define ODT_EB0W       (0x80000000 >> 7)
+#define CALC_ODT_R(n)  (ODT_EB0R << (n << 1))
+#define CALC_ODT_W(n)  (ODT_EB0W << (n << 1))
+#define CALC_ODT_RW(n) (CALC_ODT_R(n) | CALC_ODT_W(n))
 
-/*-----------------------------------------------------------------------------+
- * Defines
- *-----------------------------------------------------------------------------*/
 /* Defines for the Read Cycle Delay test */
 #define NUMMEMTESTS 8
 #define NUMMEMWORDS 8
 
+#define CONFIG_ECC_ERROR_RESET         /* test-only: see description below, at check_ecc() */
+
+/*
+ * This DDR2 setup code can dynamically setup the TLB entries for the DDR2 memory
+ * region. Right now the cache should still be disabled in U-Boot because of the
+ * EMAC driver, that need it's buffer descriptor to be located in non cached
+ * memory.
+ *
+ * If at some time this restriction doesn't apply anymore, just define
+ * CFG_ENABLE_SDRAM_CACHE in the board config file and this code should setup
+ * everything correctly.
+ */
+#ifdef CFG_ENABLE_SDRAM_CACHE
+#define MY_TLB_WORD2_I_ENABLE  0                       /* enable caching on SDRAM */
+#else
+#define MY_TLB_WORD2_I_ENABLE  TLB_WORD2_I_ENABLE      /* disable caching on SDRAM */
+#endif
+
 /* Private Structure Definitions */
 
 /* enum only to ease code for cas latency setting */
@@ -89,7 +143,7 @@ typedef enum ddr_cas_id {
  * Prototypes
  *-----------------------------------------------------------------------------*/
 static unsigned long sdram_memsize(void);
-void program_tlb(u32 start, u32 size);
+void program_tlb(u32 start, u32 size, u32 tlb_word2_i_value);
 static void get_spd_info(unsigned long *dimm_populated,
                         unsigned char *iic0_dimm_addr,
                         unsigned long num_dimm_banks);
@@ -114,7 +168,8 @@ static void program_codt(unsigned long *dimm_populated,
 static void program_mode(unsigned long *dimm_populated,
                         unsigned char *iic0_dimm_addr,
                         unsigned long num_dimm_banks,
-                        ddr_cas_id_t *selected_cas);
+                         ddr_cas_id_t *selected_cas,
+                         int *write_recovery);
 static void program_tr(unsigned long *dimm_populated,
                       unsigned char *iic0_dimm_addr,
                       unsigned long num_dimm_banks);
@@ -130,22 +185,32 @@ static void program_copt1(unsigned long *dimm_populated,
 static void program_initplr(unsigned long *dimm_populated,
                            unsigned char *iic0_dimm_addr,
                            unsigned long num_dimm_banks,
-                           ddr_cas_id_t selected_cas);
+                            ddr_cas_id_t selected_cas,
+                           int write_recovery);
 static unsigned long is_ecc_enabled(void);
+#ifdef CONFIG_DDR_ECC
 static void program_ecc(unsigned long *dimm_populated,
                        unsigned char *iic0_dimm_addr,
-                       unsigned long num_dimm_banks);
+                       unsigned long num_dimm_banks,
+                       unsigned long tlb_word2_i_value);
 static void program_ecc_addr(unsigned long start_address,
-                            unsigned long num_bytes);
-
+                            unsigned long num_bytes,
+                            unsigned long tlb_word2_i_value);
+#endif
+static void program_DQS_calibration(unsigned long *dimm_populated,
+                                   unsigned char *iic0_dimm_addr,
+                                   unsigned long num_dimm_banks);
 #ifdef HARD_CODED_DQS /* calibration test with hardvalues */
 static void    test(void);
 #else
 static void    DQS_calibration_process(void);
 #endif
-static void program_DQS_calibration(unsigned long *dimm_populated,
-                                   unsigned char *iic0_dimm_addr,
-                                   unsigned long num_dimm_banks);
+#if defined(DEBUG)
+static void ppc440sp_sdram_register_dump(void);
+#endif
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+void dcbz_area(u32 start_address, u32 num_bytes);
+void dflush(void);
 
 static u32 mfdcr_any(u32 dcr)
 {
@@ -192,15 +257,6 @@ static void mtdcr_any(u32 dcr, u32 val)
        }
 }
 
-static void wait_ddr_idle(void)
-{
-       u32 val;
-
-       do {
-               mfsdram(SDRAM_MCSTAT, val);
-       } while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT);
-}
-
 static unsigned char spd_read(uchar chip, uint addr)
 {
        unsigned char data[2];
@@ -235,7 +291,7 @@ static unsigned long sdram_memsize(void)
            && ((mcopt2 & SDRAM_MCOPT2_SREN_MASK) == SDRAM_MCOPT2_SREN_EXIT)
            && ((mcstat & (SDRAM_MCSTAT_MIC_MASK | SDRAM_MCSTAT_SRMS_MASK))
                == (SDRAM_MCSTAT_MIC_COMP | SDRAM_MCSTAT_SRMS_NOT_SF))) {
-               for (i = 0; i < 4; i++) {
+               for (i = 0; i < MAXBXCF; i++) {
                        mfsdram(SDRAM_MB0CF + (i << 2), mb0cf);
                        /* Banks enabled */
                        if ((mb0cf & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
@@ -300,14 +356,15 @@ static unsigned long sdram_memsize(void)
  *-----------------------------------------------------------------------------*/
 long int initdram(int board_type)
 {
+       unsigned char iic0_dimm_addr[] = SPD_EEPROM_ADDRESS;
        unsigned char spd0[MAX_SPD_BYTES];
        unsigned char spd1[MAX_SPD_BYTES];
        unsigned char *dimm_spd[MAXDIMMS];
        unsigned long dimm_populated[MAXDIMMS];
-       unsigned char iic0_dimm_addr[MAXDIMMS];
        unsigned long num_dimm_banks;               /* on board dimm banks */
        unsigned long val;
        ddr_cas_id_t  selected_cas;
+       int write_recovery;
        unsigned long dram_size = 0;
 
        num_dimm_banks = sizeof(iic0_dimm_addr);
@@ -318,16 +375,10 @@ long int initdram(int board_type)
        dimm_spd[0] = spd0;
        dimm_spd[1] = spd1;
 
-       /*------------------------------------------------------------------
-        * Set up an array of iic0 dimm addresses.
-        *-----------------------------------------------------------------*/
-       iic0_dimm_addr[0] = IIC0_DIMM0_ADDR;
-       iic0_dimm_addr[1] = IIC0_DIMM1_ADDR;
-
        /*------------------------------------------------------------------
         * Reset the DDR-SDRAM controller.
         *-----------------------------------------------------------------*/
-       mtsdr(SDR0_SRST, 0x00200000);
+       mtsdr(SDR0_SRST, (0x80000000 >> 10));
        mtsdr(SDR0_SRST, 0x00000000);
 
        /*
@@ -399,7 +450,8 @@ long int initdram(int board_type)
        /*------------------------------------------------------------------
         * Program SDRAM mode register.
         *-----------------------------------------------------------------*/
-       program_mode(dimm_populated, iic0_dimm_addr, num_dimm_banks, &selected_cas);
+       program_mode(dimm_populated, iic0_dimm_addr, num_dimm_banks,
+                    &selected_cas, &write_recovery);
 
        /*------------------------------------------------------------------
         * Set the SDRAM Write Data/DM/DQS Clock Timing Reg
@@ -432,13 +484,13 @@ long int initdram(int board_type)
                (val & ~(SDRAM_MEMODE_DIC_MASK  | SDRAM_MEMODE_DLL_MASK |
                         SDRAM_MEMODE_RTT_MASK | SDRAM_MEMODE_DQS_MASK)) |
                (SDRAM_MEMODE_DIC_NORMAL | SDRAM_MEMODE_DLL_ENABLE
-                | SDRAM_MEMODE_RTT_75OHM | SDRAM_MEMODE_DQS_ENABLE));
+                | SDRAM_MEMODE_RTT_150OHM | SDRAM_MEMODE_DQS_ENABLE));
 
        /*------------------------------------------------------------------
         * Program Initialization preload registers.
         *-----------------------------------------------------------------*/
        program_initplr(dimm_populated, iic0_dimm_addr, num_dimm_banks,
-                       selected_cas);
+                       selected_cas, write_recovery);
 
        /*------------------------------------------------------------------
         * Delay to ensure 200usec have elapsed since reset.
@@ -471,19 +523,19 @@ long int initdram(int board_type)
        dram_size = sdram_memsize();
 
        /* and program tlb entries for this size (dynamic) */
-       program_tlb(0, dram_size);
+       program_tlb(0, dram_size, MY_TLB_WORD2_I_ENABLE);
 
-#if 1 /* TODO: ECC support will come later */
        /*------------------------------------------------------------------
-        * If ecc is enabled, initialize the parity bits.
+        * DQS calibration.
         *-----------------------------------------------------------------*/
-       program_ecc(dimm_populated, iic0_dimm_addr, num_dimm_banks);
-#endif
+       program_DQS_calibration(dimm_populated, iic0_dimm_addr, num_dimm_banks);
 
+#ifdef CONFIG_DDR_ECC
        /*------------------------------------------------------------------
-        * DQS calibration.
+        * If ecc is enabled, initialize the parity bits.
         *-----------------------------------------------------------------*/
-       program_DQS_calibration(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+       program_ecc(dimm_populated, iic0_dimm_addr, num_dimm_banks, MY_TLB_WORD2_I_ENABLE);
+#endif
 
 #ifdef DEBUG
        ppc440sp_sdram_register_dump();
@@ -645,7 +697,7 @@ static void check_frequency(unsigned long *dimm_populated,
         *-----------------------------------------------------------------*/
        get_sys_info(&board_cfg);
 
-       mfsdr(sdr_ddr0, sdr_ddrpll);
+       mfsdr(SDR0_DDR0, sdr_ddrpll);
        sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
 
        /*
@@ -820,7 +872,11 @@ static void program_copt1(unsigned long *dimm_populated,
        unsigned long ddrtype;
        unsigned long val;
 
+#ifdef CONFIG_DDR_ECC
        ecc_enabled = TRUE;
+#else
+       ecc_enabled = FALSE;
+#endif
        dimm_32bit = FALSE;
        dimm_64bit = FALSE;
        buf0 = FALSE;
@@ -996,8 +1052,8 @@ static void program_codt(unsigned long *dimm_populated,
                                dimm_type = SDRAM_DDR1;
                        }
 
-                       total_rank +=  dimm_rank;
-                       total_dimm ++;
+                       total_rank += dimm_rank;
+                       total_dimm++;
                        if ((dimm_num == 0) && (total_dimm == 1))
                                firstSlot = TRUE;
                        else
@@ -1008,49 +1064,49 @@ static void program_codt(unsigned long *dimm_populated,
                codt |= SDRAM_CODT_DQS_1_8_V_DDR2;
                if ((total_dimm == 1) && (firstSlot == TRUE)) {
                        if (total_rank == 1) {
-                               codt |= 0x00800000;
-                               modt0 = 0x01000000;
+                               codt |= CALC_ODT_R(0);
+                               modt0 = CALC_ODT_W(0);
                                modt1 = 0x00000000;
                                modt2 = 0x00000000;
                                modt3 = 0x00000000;
                        }
                        if (total_rank == 2) {
-                               codt |= 0x02800000;
-                               modt0 = 0x06000000;
-                               modt1 = 0x01800000;
+                               codt |= CALC_ODT_R(0) | CALC_ODT_R(1);
+                               modt0 = CALC_ODT_W(0);
+                               modt1 = CALC_ODT_W(0);
                                modt2 = 0x00000000;
                                modt3 = 0x00000000;
                        }
-               } else {
+               } else if ((total_dimm == 1) && (firstSlot != TRUE)) {
                        if (total_rank == 1) {
-                               codt |= 0x00800000;
-                               modt0 = 0x01000000;
+                               codt |= CALC_ODT_R(2);
+                               modt0 = 0x00000000;
                                modt1 = 0x00000000;
-                               modt2 = 0x00000000;
+                               modt2 = CALC_ODT_W(2);
                                modt3 = 0x00000000;
                        }
                        if (total_rank == 2) {
-                               codt |= 0x02800000;
-                               modt0 = 0x06000000;
-                               modt1 = 0x01800000;
-                               modt2 = 0x00000000;
-                               modt3 = 0x00000000;
+                               codt |= CALC_ODT_R(2) | CALC_ODT_R(3);
+                               modt0 = 0x00000000;
+                               modt1 = 0x00000000;
+                               modt2 = CALC_ODT_W(2);
+                               modt3 = CALC_ODT_W(2);
                        }
                }
                if (total_dimm == 2) {
                        if (total_rank == 2) {
-                               codt |= 0x08800000;
-                               modt0 = 0x18000000;
+                               codt |= CALC_ODT_R(0) | CALC_ODT_R(2);
+                               modt0 = CALC_ODT_RW(2);
                                modt1 = 0x00000000;
-                               modt2 = 0x01800000;
+                               modt2 = CALC_ODT_RW(0);
                                modt3 = 0x00000000;
                        }
                        if (total_rank == 4) {
-                               codt |= 0x2a800000;
-                               modt0 = 0x18000000;
-                               modt1 = 0x18000000;
-                               modt2 = 0x01800000;
-                               modt3 = 0x01800000;
+                               codt |= CALC_ODT_R(0) | CALC_ODT_R(1) | CALC_ODT_R(2) | CALC_ODT_R(3);
+                               modt0 = CALC_ODT_RW(2);
+                               modt1 = 0x00000000;
+                               modt2 = CALC_ODT_RW(0);
+                               modt3 = 0x00000000;
                        }
                }
        } else {
@@ -1092,9 +1148,19 @@ static void program_codt(unsigned long *dimm_populated,
 static void program_initplr(unsigned long *dimm_populated,
                            unsigned char *iic0_dimm_addr,
                            unsigned long num_dimm_banks,
-                           ddr_cas_id_t selected_cas)
+                            ddr_cas_id_t selected_cas,
+                           int write_recovery)
 {
-       unsigned long MR_CAS_value = 0;
+       u32 cas = 0;
+       u32 odt = 0;
+       u32 ods = 0;
+       u32 mr;
+       u32 wr;
+       u32 emr;
+       u32 emr2;
+       u32 emr3;
+       int dimm_num;
+       int total_dimm = 0;
 
        /******************************************************
         ** Assumption: if more than one DIMM, all DIMMs are the same
@@ -1112,41 +1178,90 @@ static void program_initplr(unsigned long *dimm_populated,
                mtsdram(SDRAM_INITPLR7, 0x81000062);
        } else if ((dimm_populated[0] == SDRAM_DDR2) || (dimm_populated[1] == SDRAM_DDR2)) {
                switch (selected_cas) {
-                       /*
-                        * The CAS latency is a field of the Mode Reg
-                        * that need to be set from caller input.
-                        * CAS bits in Mode Reg are starting at bit 4 at least for the Micron DDR2
-                        * this is the reason of the shift.
-                        */
                case DDR_CAS_3:
-                       MR_CAS_value = 3 << 4;
+                       cas = 3 << 4;
                        break;
                case DDR_CAS_4:
-                       MR_CAS_value = 4 << 4;
+                       cas = 4 << 4;
                        break;
                case DDR_CAS_5:
-                       MR_CAS_value = 5 << 4;
+                       cas = 5 << 4;
                        break;
                default:
-                       printf("ERROR: ucode error on selected_cas value %d", (unsigned char)selected_cas);
+                       printf("ERROR: ucode error on selected_cas value %d", selected_cas);
                        hang();
                        break;
                }
 
-               mtsdram(SDRAM_INITPLR0,  0xB5380000);                   /* NOP */
-               mtsdram(SDRAM_INITPLR1,  0x82100400);                   /* precharge 8 DDR clock cycle */
-               mtsdram(SDRAM_INITPLR2,  0x80820000);                   /* EMR2 */
-               mtsdram(SDRAM_INITPLR3,  0x80830000);                   /* EMR3 */
-               mtsdram(SDRAM_INITPLR4,  0x80810000);                   /* EMR DLL ENABLE */
-               mtsdram(SDRAM_INITPLR5,  0x80800502 | MR_CAS_value);    /* MR w/ DLL reset */
-               mtsdram(SDRAM_INITPLR6,  0x82100400);                   /* precharge 8 DDR clock cycle */
-               mtsdram(SDRAM_INITPLR7,  0x8a080000);                   /* Refresh  50 DDR clock cycle */
-               mtsdram(SDRAM_INITPLR8,  0x8a080000);                   /* Refresh  50 DDR clock cycle */
-               mtsdram(SDRAM_INITPLR9,  0x8a080000);                   /* Refresh  50 DDR clock cycle */
-               mtsdram(SDRAM_INITPLR10, 0x8a080000);                   /* Refresh  50 DDR clock cycle */
-               mtsdram(SDRAM_INITPLR11, 0x80800402 | MR_CAS_value);    /* MR w/o DLL reset */
-               mtsdram(SDRAM_INITPLR12, 0x80810380);                   /* EMR OCD Default */
-               mtsdram(SDRAM_INITPLR13, 0x80810000);                   /* EMR OCD Exit */
+#if 0
+               /*
+                * ToDo - Still a problem with the write recovery:
+                * On the Corsair CM2X512-5400C4 module, setting write recovery
+                * in the INITPLR reg to the value calculated in program_mode()
+                * results in not correctly working DDR2 memory (crash after
+                * relocation).
+                *
+                * So for now, set the write recovery to 3. This seems to work
+                * on the Corair module too.
+                *
+                * 2007-03-01, sr
+                */
+               switch (write_recovery) {
+               case 3:
+                       wr = WRITE_RECOV_3;
+                       break;
+               case 4:
+                       wr = WRITE_RECOV_4;
+                       break;
+               case 5:
+                       wr = WRITE_RECOV_5;
+                       break;
+               case 6:
+                       wr = WRITE_RECOV_6;
+                       break;
+               default:
+                       printf("ERROR: write recovery not support (%d)", write_recovery);
+                       hang();
+                       break;
+               }
+#else
+               wr = WRITE_RECOV_3; /* test-only, see description above */
+#endif
+
+               for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++)
+                       if (dimm_populated[dimm_num] != SDRAM_NONE)
+                               total_dimm++;
+               if (total_dimm == 1) {
+                       odt = ODT_150_OHM;
+                       ods = ODS_FULL;
+               } else if (total_dimm == 2) {
+                       odt = ODT_75_OHM;
+                       ods = ODS_REDUCED;
+               } else {
+                       printf("ERROR: Unsupported number of DIMM's (%d)", total_dimm);
+                       hang();
+               }
+
+               mr = CMD_EMR | SELECT_MR | BURST_LEN_4 | wr | cas;
+               emr = CMD_EMR | SELECT_EMR | odt | ods;
+               emr2 = CMD_EMR | SELECT_EMR2;
+               emr3 = CMD_EMR | SELECT_EMR3;
+               mtsdram(SDRAM_INITPLR0,  0xB5000000 | CMD_NOP);         /* NOP */
+               udelay(1000);
+               mtsdram(SDRAM_INITPLR1,  0x82000400 | CMD_PRECHARGE);   /* precharge 8 DDR clock cycle */
+               mtsdram(SDRAM_INITPLR2,  0x80800000 | emr2);            /* EMR2 */
+               mtsdram(SDRAM_INITPLR3,  0x80800000 | emr3);            /* EMR3 */
+               mtsdram(SDRAM_INITPLR4,  0x80800000 | emr);             /* EMR DLL ENABLE */
+               mtsdram(SDRAM_INITPLR5,  0x80800000 | mr | DLL_RESET);  /* MR w/ DLL reset */
+               udelay(1000);
+               mtsdram(SDRAM_INITPLR6,  0x82000400 | CMD_PRECHARGE);   /* precharge 8 DDR clock cycle */
+               mtsdram(SDRAM_INITPLR7,  0x8a000000 | CMD_REFRESH);     /* Refresh  50 DDR clock cycle */
+               mtsdram(SDRAM_INITPLR8,  0x8a000000 | CMD_REFRESH);     /* Refresh  50 DDR clock cycle */
+               mtsdram(SDRAM_INITPLR9,  0x8a000000 | CMD_REFRESH);     /* Refresh  50 DDR clock cycle */
+               mtsdram(SDRAM_INITPLR10, 0x8a000000 | CMD_REFRESH);     /* Refresh  50 DDR clock cycle */
+               mtsdram(SDRAM_INITPLR11, 0x80000000 | mr);              /* MR w/o DLL reset */
+               mtsdram(SDRAM_INITPLR12, 0x80800380 | emr);             /* EMR OCD Default */
+               mtsdram(SDRAM_INITPLR13, 0x80800000 | emr);             /* EMR OCD Exit */
        } else {
                printf("ERROR: ucode error as unknown DDR type in program_initplr");
                hang();
@@ -1161,7 +1276,8 @@ static void program_initplr(unsigned long *dimm_populated,
 static void program_mode(unsigned long *dimm_populated,
                         unsigned char *iic0_dimm_addr,
                         unsigned long num_dimm_banks,
-                        ddr_cas_id_t *selected_cas)
+                        ddr_cas_id_t *selected_cas,
+                        int *write_recovery)
 {
        unsigned long dimm_num;
        unsigned long sdram_ddr1;
@@ -1197,7 +1313,7 @@ static void program_mode(unsigned long *dimm_populated,
         *-----------------------------------------------------------------*/
        get_sys_info(&board_cfg);
 
-       mfsdr(sdr_ddr0, sdr_ddrpll);
+       mfsdr(SDR0_DDR0, sdr_ddrpll);
        sdram_freq = MULDIV64((board_cfg.freqPLB), SDR0_DDR0_DDRM_DECODE(sdr_ddrpll), 1);
 
        /*------------------------------------------------------------------
@@ -1346,11 +1462,12 @@ static void program_mode(unsigned long *dimm_populated,
        mfsdram(SDRAM_MMODE, mmode);
        mmode = mmode & ~(SDRAM_MMODE_WR_MASK | SDRAM_MMODE_DCL_MASK);
 
-       cycle_2_0_clk = MULDIV64(ONE_BILLION, 100, max_2_0_tcyc_ns_x_100);
-       cycle_2_5_clk = MULDIV64(ONE_BILLION, 100, max_2_5_tcyc_ns_x_100);
-       cycle_3_0_clk = MULDIV64(ONE_BILLION, 100, max_3_0_tcyc_ns_x_100);
-       cycle_4_0_clk = MULDIV64(ONE_BILLION, 100, max_4_0_tcyc_ns_x_100);
-       cycle_5_0_clk = MULDIV64(ONE_BILLION, 100, max_5_0_tcyc_ns_x_100);
+       /* add 10 here because of rounding problems */
+       cycle_2_0_clk = MULDIV64(ONE_BILLION, 100, max_2_0_tcyc_ns_x_100) + 10;
+       cycle_2_5_clk = MULDIV64(ONE_BILLION, 100, max_2_5_tcyc_ns_x_100) + 10;
+       cycle_3_0_clk = MULDIV64(ONE_BILLION, 100, max_3_0_tcyc_ns_x_100) + 10;
+       cycle_4_0_clk = MULDIV64(ONE_BILLION, 100, max_4_0_tcyc_ns_x_100) + 10;
+       cycle_5_0_clk = MULDIV64(ONE_BILLION, 100, max_5_0_tcyc_ns_x_100) + 10;
 
        if (sdram_ddr1 == TRUE) { /* DDR1 */
                if ((cas_2_0_available == TRUE) && (sdram_freq <= cycle_2_0_clk)) {
@@ -1381,7 +1498,11 @@ static void program_mode(unsigned long *dimm_populated,
                } else {
                        printf("ERROR: Cannot find a supported CAS latency with the installed DIMMs.\n");
                        printf("Only DIMMs DDR2 with CAS latencies of 3.0, 4.0, and 5.0 are supported.\n");
-                       printf("Make sure the PLB speed is within the supported range of the DIMMs.\n\n");
+                       printf("Make sure the PLB speed is within the supported range of the DIMMs.\n");
+                       printf("cas3=%d cas4=%d cas5=%d\n",
+                              cas_3_0_available, cas_4_0_available, cas_5_0_available);
+                       printf("sdram_freq=%d cycle3=%d cycle4=%d cycle5=%d\n\n",
+                              sdram_freq, cycle_3_0_clk, cycle_4_0_clk, cycle_5_0_clk);
                        hang();
                }
        }
@@ -1424,8 +1545,12 @@ static void program_mode(unsigned long *dimm_populated,
                        mmode |= SDRAM_MMODE_WR_DDR2_6_CYC;
                        break;
                }
+               *write_recovery = t_wr_clk;
        }
 
+       debug("CAS latency = %d\n", *selected_cas);
+       debug("Write recovery = %d\n", *write_recovery);
+
        mtsdram(SDRAM_MMODE, mmode);
 }
 
@@ -1454,7 +1579,7 @@ static void program_rtr(unsigned long *dimm_populated,
        /*------------------------------------------------------------------
         * Set the SDRAM Refresh Timing Register, SDRAM_RTR
         *-----------------------------------------------------------------*/
-       mfsdr(sdr_ddr0, sdr_ddrpll);
+       mfsdr(SDR0_DDR0, sdr_ddrpll);
        sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
 
        max_refresh_rate = 0;
@@ -1540,7 +1665,7 @@ static void program_tr(unsigned long *dimm_populated,
         *-----------------------------------------------------------------*/
        get_sys_info(&board_cfg);
 
-       mfsdr(sdr_ddr0, sdr_ddrpll);
+       mfsdr(SDR0_DDR0, sdr_ddrpll);
        sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
 
        /*------------------------------------------------------------------
@@ -1948,7 +2073,7 @@ static void program_memory_queue(unsigned long *dimm_populated,
                         * Set the sizes
                         *-----------------------------------------------------------------*/
                        baseadd_size = 0;
-                       rank_size_bytes = 1024 * 1024 * rank_size_id;
+                       rank_size_bytes = 4 * 1024 * 1024 * rank_size_id;
                        switch (rank_size_id) {
                        case 0x02:
                                baseadd_size |= SDRAM_RXBAS_SDSZ_8;
@@ -1985,8 +2110,8 @@ static void program_memory_queue(unsigned long *dimm_populated,
 
                        for (i = 0; i < num_ranks; i++) {
                                mtdcr_any(rank_reg+i+dimm_num+bank_0_populated,
-                                         (rank_base_addr & SDRAM_RXBAS_SDBA_MASK) |
-                                         baseadd_size);
+                                         (SDRAM_RXBAS_SDBA_ENCODE(rank_base_addr) |
+                                          baseadd_size));
                                rank_base_addr += rank_size_bytes;
                        }
                }
@@ -2009,15 +2134,17 @@ static unsigned long is_ecc_enabled(void)
                ecc = max(ecc, SDRAM_MCOPT1_MCHK_CHK_DECODE(val));
        }
 
-       return(ecc);
+       return ecc;
 }
 
+#ifdef CONFIG_DDR_ECC
 /*-----------------------------------------------------------------------------+
  * program_ecc.
  *-----------------------------------------------------------------------------*/
 static void program_ecc(unsigned long *dimm_populated,
                        unsigned char *iic0_dimm_addr,
-                       unsigned long num_dimm_banks)
+                       unsigned long num_dimm_banks,
+                       unsigned long tlb_word2_i_value)
 {
        unsigned long mcopt1;
        unsigned long mcopt2;
@@ -2046,23 +2173,68 @@ static void program_ecc(unsigned long *dimm_populated,
                    && ((mcstat & (SDRAM_MCSTAT_MIC_MASK | SDRAM_MCSTAT_SRMS_MASK))
                        == (SDRAM_MCSTAT_MIC_COMP | SDRAM_MCSTAT_SRMS_NOT_SF))) {
 
-                       program_ecc_addr(0, sdram_memsize());
+                       program_ecc_addr(0, sdram_memsize(), tlb_word2_i_value);
                }
        }
 
        return;
 }
 
+#ifdef CONFIG_ECC_ERROR_RESET
+/*
+ * Check for ECC errors and reset board upon any error here
+ *
+ * On the Katmai 440SPe eval board, from time to time, the first
+ * lword write access after DDR2 initializazion with ECC checking
+ * enabled, leads to an ECC error. I couldn't find a configuration
+ * without this happening. On my board with the current setup it
+ * happens about 1 from 10 times.
+ *
+ * The ECC modules used for testing are:
+ * - Kingston ValueRAM KVR667D2E5/512 (tested with 1 and 2 DIMM's)
+ *
+ * This has to get fixed for the Katmai and tested for the other
+ * board (440SP/440SPe) that will eventually use this code in the
+ * future.
+ *
+ * 2007-03-01, sr
+ */
+static void check_ecc(void)
+{
+       u32 val;
+
+       mfsdram(SDRAM_ECCCR, val);
+       if (val != 0) {
+               printf("\nECC error: MCIF0_ECCES=%08lx MQ0_ESL=%08lx address=%08lx\n",
+                      val, mfdcr(0x4c), mfdcr(0x4e));
+               printf("ECC error occured, resetting board...\n");
+               do_reset(NULL, 0, 0, NULL);
+       }
+}
+#endif
+
+static void wait_ddr_idle(void)
+{
+       u32 val;
+
+       do {
+               mfsdram(SDRAM_MCSTAT, val);
+       } while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT);
+}
+
 /*-----------------------------------------------------------------------------+
  * program_ecc_addr.
  *-----------------------------------------------------------------------------*/
 static void program_ecc_addr(unsigned long start_address,
-                            unsigned long num_bytes)
+                            unsigned long num_bytes,
+                            unsigned long tlb_word2_i_value)
 {
        unsigned long current_address;
        unsigned long end_address;
        unsigned long address_increment;
        unsigned long mcopt1;
+       char str[] = "ECC generation...";
+       int i;
 
        current_address = start_address;
        mfsdram(SDRAM_MCOPT1, mcopt1);
@@ -2073,28 +2245,52 @@ static void program_ecc_addr(unsigned long start_address,
                eieio();
                wait_ddr_idle();
 
-               /* ECC bit set method for non-cached memory */
-               if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32)
-                       address_increment = 4;
-               else
-                       address_increment = 8;
-               end_address = current_address + num_bytes;
+               puts(str);
+               if (tlb_word2_i_value == TLB_WORD2_I_ENABLE) {
+                       /* ECC bit set method for non-cached memory */
+                       if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32)
+                               address_increment = 4;
+                       else
+                               address_increment = 8;
+                       end_address = current_address + num_bytes;
 
-               while (current_address < end_address) {
-                       *((unsigned long *)current_address) = 0x00000000;
-                       current_address += address_increment;
+                       while (current_address < end_address) {
+                               *((unsigned long *)current_address) = 0x00000000;
+                               current_address += address_increment;
+                       }
+               } else {
+                       /* ECC bit set method for cached memory */
+                       dcbz_area(start_address, num_bytes);
+                       dflush();
                }
+               for (i=0; i<strlen(str); i++)
+                       putc('\b');
+
                sync();
                eieio();
                wait_ddr_idle();
 
+               /* clear ECC error repoting registers */
+               mtsdram(SDRAM_ECCCR, 0xffffffff);
+               mtdcr(0x4c, 0xffffffff);
+
                mtsdram(SDRAM_MCOPT1,
-                       (mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_CHK);
+                       (mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_CHK_REP);
                sync();
                eieio();
                wait_ddr_idle();
+
+#ifdef CONFIG_ECC_ERROR_RESET
+               /*
+                * One write to 0 is enough to trigger this ECC error
+                * (see description above)
+                */
+               out_be32(0, 0x12345678);
+               check_ecc();
+#endif
        }
 }
+#endif
 
 /*-----------------------------------------------------------------------------+
  * program_DQS_calibration.
@@ -2350,7 +2546,6 @@ static void DQS_calibration_process(void)
                }
        }               /* for rffd */
 
-
        /*------------------------------------------------------------------
         * Set the average RFFD value
         *-----------------------------------------------------------------*/