Merge with /home/wd/git/u-boot/custodian/u-boot-74xx-7xx
[platform/kernel/u-boot.git] / cpu / ppc4xx / 44x_spd_ddr2.c
index d7177c9..2ecd3e4 100644 (file)
 #define CALC_ODT_RW(n) (CALC_ODT_R(n) | CALC_ODT_W(n))
 
 /* Defines for the Read Cycle Delay test */
-#define NUMMEMTESTS 8
-#define NUMMEMWORDS 8
+#define NUMMEMTESTS    8
+#define NUMMEMWORDS    8
+#define NUMLOOPS       256             /* memory test loops */
 
-#define CONFIG_ECC_ERROR_RESET         /* test-only: see description below, at check_ecc() */
+#undef 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
@@ -584,10 +585,23 @@ static void get_spd_info(unsigned long *dimm_populated,
 #ifdef CONFIG_ADD_RAM_INFO
 void board_add_ram_info(int use_default)
 {
+       PPC440_SYS_INFO board_cfg;
+       u32 val;
+
        if (is_ecc_enabled())
-               puts(" (ECC enabled)");
+               puts(" (ECC");
        else
-               puts(" (ECC not enabled)");
+               puts(" (ECC not");
+
+       get_sys_info(&board_cfg);
+
+       mfsdr(SDR0_DDR0, val);
+       val = MULDIV64((board_cfg.freqPLB), SDR0_DDR0_DDRM_DECODE(val), 1);
+       printf(" enabled, %d MHz", (val * 2) / 1000000);
+
+       mfsdram(SDRAM_MMODE, val);
+       val = (val & SDRAM_MMODE_DCL_MASK) >> 4;
+       printf(", CL%d)", val);
 }
 #endif
 
@@ -731,6 +745,7 @@ static void check_frequency(unsigned long *dimm_populated,
                        else
                                cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) +
                                        ((tcyc_reg & 0x0F)*10);
+                       debug("cycle_time=%d [10 picoseconds]\n", cycle_time);
 
                        if  (cycle_time > (calc_cycle_time + 10)) {
                                /*
@@ -1315,6 +1330,7 @@ static void program_mode(unsigned long *dimm_populated,
 
        mfsdr(SDR0_DDR0, sdr_ddrpll);
        sdram_freq = MULDIV64((board_cfg.freqPLB), SDR0_DDR0_DDRM_DECODE(sdr_ddrpll), 1);
+       debug("sdram_freq=%d\n", sdram_freq);
 
        /*------------------------------------------------------------------
         * Handle the timing.  We need to find the worst case timing of all
@@ -1344,6 +1360,7 @@ static void program_mode(unsigned long *dimm_populated,
 
                        /* t_wr_ns = max(t_wr_ns, (unsigned long)dimm_spd[dimm_num][36] >> 2); */ /*  not used in this loop. */
                        cas_bit = spd_read(iic0_dimm_addr[dimm_num], 18);
+                       debug("cas_bit[SPD byte 18]=%02x\n", cas_bit);
 
                        /* For a particular DIMM, grab the three CAS values it supports */
                        for (cas_index = 0; cas_index < 3; cas_index++) {
@@ -1362,7 +1379,8 @@ static void program_mode(unsigned long *dimm_populated,
                                if ((tcyc_reg & 0x0F) >= 10) {
                                        if ((tcyc_reg & 0x0F) == 0x0D) {
                                                /* Convert from hex to decimal */
-                                               cycle_time_ns_x_100[cas_index] = (((tcyc_reg & 0xF0) >> 4) * 100) + 75;
+                                               cycle_time_ns_x_100[cas_index] =
+                                                       (((tcyc_reg & 0xF0) >> 4) * 100) + 75;
                                        } else {
                                                printf("ERROR: SPD reported Tcyc is incorrect for DIMM "
                                                       "in slot %d\n", (unsigned int)dimm_num);
@@ -1370,9 +1388,12 @@ static void program_mode(unsigned long *dimm_populated,
                                        }
                                } else {
                                        /* Convert from hex to decimal */
-                                       cycle_time_ns_x_100[cas_index] = (((tcyc_reg & 0xF0) >> 4) * 100) +
+                                       cycle_time_ns_x_100[cas_index] =
+                                               (((tcyc_reg & 0xF0) >> 4) * 100) +
                                                ((tcyc_reg & 0x0F)*10);
                                }
+                               debug("cas_index=%d: cycle_time_ns_x_100=%d\n", cas_index,
+                                     cycle_time_ns_x_100[cas_index]);
                        }
 
                        /* The rest of this routine determines if CAS 2.0, 2.5, 3.0, 4.0 and 5.0 are */
@@ -1385,8 +1406,10 @@ static void program_mode(unsigned long *dimm_populated,
                                 *  Bit   7    6    5    4    3    2    1    0
                                 *       TBD  4.0  3.5  3.0  2.5  2.0  1.5  1.0
                                 */
-                               if (((cas_bit & 0x40) == 0x40) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
-                                       max_4_0_tcyc_ns_x_100 = max(max_4_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+                               if (((cas_bit & 0x40) == 0x40) && (cas_index < 3) &&
+                                   (cycle_time_ns_x_100[cas_index] != 0)) {
+                                       max_4_0_tcyc_ns_x_100 = max(max_4_0_tcyc_ns_x_100,
+                                                                   cycle_time_ns_x_100[cas_index]);
                                        cas_index++;
                                } else {
                                        if (cas_index != 0)
@@ -1394,8 +1417,10 @@ static void program_mode(unsigned long *dimm_populated,
                                        cas_4_0_available = FALSE;
                                }
 
-                               if (((cas_bit & 0x10) == 0x10) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
-                                       max_3_0_tcyc_ns_x_100 = max(max_3_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+                               if (((cas_bit & 0x10) == 0x10) && (cas_index < 3) &&
+                                   (cycle_time_ns_x_100[cas_index] != 0)) {
+                                       max_3_0_tcyc_ns_x_100 = max(max_3_0_tcyc_ns_x_100,
+                                                                   cycle_time_ns_x_100[cas_index]);
                                        cas_index++;
                                } else {
                                        if (cas_index != 0)
@@ -1403,8 +1428,10 @@ static void program_mode(unsigned long *dimm_populated,
                                        cas_3_0_available = FALSE;
                                }
 
-                               if (((cas_bit & 0x08) == 0x08) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
-                                       max_2_5_tcyc_ns_x_100 = max(max_2_5_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+                               if (((cas_bit & 0x08) == 0x08) && (cas_index < 3) &&
+                                   (cycle_time_ns_x_100[cas_index] != 0)) {
+                                       max_2_5_tcyc_ns_x_100 = max(max_2_5_tcyc_ns_x_100,
+                                                                   cycle_time_ns_x_100[cas_index]);
                                        cas_index++;
                                } else {
                                        if (cas_index != 0)
@@ -1412,8 +1439,10 @@ static void program_mode(unsigned long *dimm_populated,
                                        cas_2_5_available = FALSE;
                                }
 
-                               if (((cas_bit & 0x04) == 0x04) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
-                                       max_2_0_tcyc_ns_x_100 = max(max_2_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+                               if (((cas_bit & 0x04) == 0x04) && (cas_index < 3) &&
+                                   (cycle_time_ns_x_100[cas_index] != 0)) {
+                                       max_2_0_tcyc_ns_x_100 = max(max_2_0_tcyc_ns_x_100,
+                                                                   cycle_time_ns_x_100[cas_index]);
                                        cas_index++;
                                } else {
                                        if (cas_index != 0)
@@ -1426,8 +1455,10 @@ static void program_mode(unsigned long *dimm_populated,
                                 *  Bit   7    6    5    4    3    2    1    0
                                 *       TBD  6.0  5.0  4.0  3.0  2.0  TBD  TBD
                                 */
-                               if (((cas_bit & 0x20) == 0x20) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
-                                       max_5_0_tcyc_ns_x_100 = max(max_5_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+                               if (((cas_bit & 0x20) == 0x20) && (cas_index < 3) &&
+                                   (cycle_time_ns_x_100[cas_index] != 0)) {
+                                       max_5_0_tcyc_ns_x_100 = max(max_5_0_tcyc_ns_x_100,
+                                                                   cycle_time_ns_x_100[cas_index]);
                                        cas_index++;
                                } else {
                                        if (cas_index != 0)
@@ -1435,8 +1466,10 @@ static void program_mode(unsigned long *dimm_populated,
                                        cas_5_0_available = FALSE;
                                }
 
-                               if (((cas_bit & 0x10) == 0x10) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
-                                       max_4_0_tcyc_ns_x_100 = max(max_4_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+                               if (((cas_bit & 0x10) == 0x10) && (cas_index < 3) &&
+                                   (cycle_time_ns_x_100[cas_index] != 0)) {
+                                       max_4_0_tcyc_ns_x_100 = max(max_4_0_tcyc_ns_x_100,
+                                                                   cycle_time_ns_x_100[cas_index]);
                                        cas_index++;
                                } else {
                                        if (cas_index != 0)
@@ -1444,8 +1477,10 @@ static void program_mode(unsigned long *dimm_populated,
                                        cas_4_0_available = FALSE;
                                }
 
-                               if (((cas_bit & 0x08) == 0x08) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
-                                       max_3_0_tcyc_ns_x_100 = max(max_3_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+                               if (((cas_bit & 0x08) == 0x08) && (cas_index < 3) &&
+                                   (cycle_time_ns_x_100[cas_index] != 0)) {
+                                       max_3_0_tcyc_ns_x_100 = max(max_3_0_tcyc_ns_x_100,
+                                                                   cycle_time_ns_x_100[cas_index]);
                                        cas_index++;
                                } else {
                                        if (cas_index != 0)
@@ -1468,6 +1503,9 @@ static void program_mode(unsigned long *dimm_populated,
        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;
+       debug("cycle_3_0_clk=%d\n", cycle_3_0_clk);
+       debug("cycle_4_0_clk=%d\n", cycle_4_0_clk);
+       debug("cycle_5_0_clk=%d\n", cycle_5_0_clk);
 
        if (sdram_ddr1 == TRUE) { /* DDR1 */
                if ((cas_2_0_available == TRUE) && (sdram_freq <= cycle_2_0_clk)) {
@@ -1486,6 +1524,9 @@ static void program_mode(unsigned long *dimm_populated,
                        hang();
                }
        } else { /* DDR2 */
+               debug("cas_3_0_available=%d\n", cas_3_0_available);
+               debug("cas_4_0_available=%d\n", cas_4_0_available);
+               debug("cas_5_0_available=%d\n", cas_5_0_available);
                if ((cas_3_0_available == TRUE) && (sdram_freq <= cycle_3_0_clk)) {
                        mmode |= SDRAM_MMODE_DCL_DDR2_3_0_CLK;
                        *selected_cas = DDR_CAS_3;
@@ -2137,6 +2178,18 @@ static unsigned long is_ecc_enabled(void)
        return ecc;
 }
 
+static void blank_string(int size)
+{
+       int i;
+
+       for (i=0; i<size; i++)
+               putc('\b');
+       for (i=0; i<size; i++)
+               putc(' ');
+       for (i=0; i<size; i++)
+               putc('\b');
+}
+
 #ifdef CONFIG_DDR_ECC
 /*-----------------------------------------------------------------------------+
  * program_ecc.
@@ -2233,8 +2286,10 @@ static void program_ecc_addr(unsigned long start_address,
        unsigned long end_address;
        unsigned long address_increment;
        unsigned long mcopt1;
-       char str[] = "ECC generation...";
-       int i;
+       char str[] = "ECC generation -";
+       char slash[] = "\\|/-\\|/-";
+       int loop = 0;
+       int loopi = 0;
 
        current_address = start_address;
        mfsdram(SDRAM_MCOPT1, mcopt1);
@@ -2257,14 +2312,20 @@ static void program_ecc_addr(unsigned long start_address,
                        while (current_address < end_address) {
                                *((unsigned long *)current_address) = 0x00000000;
                                current_address += address_increment;
+
+                               if ((loop++ % (2 << 20)) == 0) {
+                                       putc('\b');
+                                       putc(slash[loopi++ % 8]);
+                               }
                        }
+
                } else {
                        /* ECC bit set method for cached memory */
                        dcbz_area(start_address, num_bytes);
                        dflush();
                }
-               for (i=0; i<strlen(str); i++)
-                       putc('\b');
+
+               blank_string(strlen(str));
 
                sync();
                eieio();
@@ -2347,7 +2408,7 @@ static void program_DQS_calibration(unsigned long *dimm_populated,
 #endif
 }
 
-static u32 short_mem_test(void)
+static int short_mem_test(void)
 {
        u32 *membase;
        u32 bxcr_num;
@@ -2371,42 +2432,41 @@ static u32 short_mem_test(void)
                 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA},
                {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
                 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55} };
+       int l;
 
        for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) {
                mfsdram(SDRAM_MB0CF + (bxcr_num << 2), bxcf);
 
                /* Banks enabled */
                if ((bxcf & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
-
                        /* Bank is enabled */
-                       membase = (u32 *)(SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+bxcr_num)));
 
                        /*------------------------------------------------------------------
                         * Run the short memory test.
                         *-----------------------------------------------------------------*/
+                       membase = (u32 *)(SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+bxcr_num)));
+
                        for (i = 0; i < NUMMEMTESTS; i++) {
                                for (j = 0; j < NUMMEMWORDS; j++) {
                                        membase[j] = test[i][j];
                                        ppcDcbf((u32)&(membase[j]));
                                }
                                sync();
-                               for (j = 0; j < NUMMEMWORDS; j++) {
-                                       if (membase[j] != test[i][j]) {
+                               for (l=0; l<NUMLOOPS; l++) {
+                                       for (j = 0; j < NUMMEMWORDS; j++) {
+                                               if (membase[j] != test[i][j]) {
+                                                       ppcDcbf((u32)&(membase[j]));
+                                                       return 0;
+                                               }
                                                ppcDcbf((u32)&(membase[j]));
-                                               break;
                                        }
-                                       ppcDcbf((u32)&(membase[j]));
+                                       sync();
                                }
-                               sync();
-                               if (j < NUMMEMWORDS)
-                                       break;
                        }
-                       if (i < NUMMEMTESTS)
-                               break;
                }       /* if bank enabled */
        }               /* for bxcf_num */
 
-       return bxcr_num;
+       return 1;
 }
 
 #ifndef HARD_CODED_DQS
@@ -2415,12 +2475,10 @@ static u32 short_mem_test(void)
  *-----------------------------------------------------------------------------*/
 static void DQS_calibration_process(void)
 {
-       unsigned long ecc_temp;
        unsigned long rfdc_reg;
        unsigned long rffd;
        unsigned long rqdc_reg;
        unsigned long rqfd;
-       unsigned long bxcr_num;
        unsigned long val;
        long rqfd_average;
        long rffd_average;
@@ -2440,6 +2498,10 @@ static void DQS_calibration_process(void)
        long max_end;
        unsigned char fail_found;
        unsigned char pass_found;
+       u32 rqfd_start;
+       char str[] = "Auto calibration -";
+       char slash[] = "\\|/-\\|/-";
+       int loopi = 0;
 
        /*------------------------------------------------------------------
         * Test to determine the best read clock delay tuning bits.
@@ -2464,11 +2526,16 @@ static void DQS_calibration_process(void)
         * we can clock the DDR interface at is 200 MHz (2x 100 MHz PLB speed),
         * from experimentation it is safe to say you will always have a failure.
         *-----------------------------------------------------------------*/
-       mfsdram(SDRAM_MCOPT1, ecc_temp);
-       ecc_temp &= SDRAM_MCOPT1_MCHK_MASK;
-       mfsdram(SDRAM_MCOPT1, val);
-       mtsdram(SDRAM_MCOPT1, (val & ~SDRAM_MCOPT1_MCHK_MASK) |
-               SDRAM_MCOPT1_MCHK_NON);
+
+       /* first fix RQDC[RQFD] to an average of 80 degre phase shift to find RFDC[RFFD] */
+       rqfd_start = 64; /* test-only: don't know if this is the _best_ start value */
+
+       puts(str);
+
+calibration_loop:
+       mfsdram(SDRAM_RQDC, rqdc_reg);
+       mtsdram(SDRAM_RQDC, (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) |
+               SDRAM_RQDC_RQFD_ENCODE(rqfd_start));
 
        max_start = 0;
        min_end = 0;
@@ -2492,9 +2559,6 @@ static void DQS_calibration_process(void)
        fail_found = FALSE;
        pass_found = FALSE;
 
-       /* first fix RQDC[RQFD] to an average of 80 degre phase shift to find RFDC[RFFD] */
-       /* rqdc_reg = mfsdram(SDRAM_RQDC) & ~(SDRAM_RQDC_RQFD_MASK); */
-
        /*
         * get the delay line calibration register value
         */
@@ -2510,13 +2574,10 @@ static void DQS_calibration_process(void)
                 *-----------------------------------------------------------------*/
                mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd));
 
-               /* do the small memory test */
-               bxcr_num = short_mem_test();
-
                /*------------------------------------------------------------------
                 * See if the rffd value passed.
                 *-----------------------------------------------------------------*/
-               if (bxcr_num == MAXBXCF) {
+               if (short_mem_test()) {
                        if (fail_found == TRUE) {
                                pass_found = TRUE;
                                if (current_pass_length == 0)
@@ -2578,13 +2639,10 @@ static void DQS_calibration_process(void)
                 *-----------------------------------------------------------------*/
                mtsdram(SDRAM_RQDC, rqdc_reg | SDRAM_RQDC_RQFD_ENCODE(rqfd));
 
-               /* do the small memory test */
-               bxcr_num = short_mem_test();
-
                /*------------------------------------------------------------------
                 * See if the rffd value passed.
                 *-----------------------------------------------------------------*/
-               if (bxcr_num == MAXBXCF) {
+               if (short_mem_test()) {
                        if (fail_found == TRUE) {
                                pass_found = TRUE;
                                if (current_pass_length == 0)
@@ -2612,17 +2670,28 @@ static void DQS_calibration_process(void)
                }
        }
 
+       rqfd_average = ((max_start + max_end) >> 1);
+
        /*------------------------------------------------------------------
         * Make sure we found the valid read passing window.  Halt if not
         *-----------------------------------------------------------------*/
        if (window_found == FALSE) {
-               printf("ERROR: Cannot determine a common read delay for the "
+               if (rqfd_start < SDRAM_RQDC_RQFD_MAX) {
+                       putc('\b');
+                       putc(slash[loopi++ % 8]);
+
+                       /* try again from with a different RQFD start value */
+                       rqfd_start++;
+                       goto calibration_loop;
+               }
+
+               printf("\nERROR: Cannot determine a common read delay for the "
                       "DIMM(s) installed.\n");
                debug("%s[%d] ERROR : \n", __FUNCTION__,__LINE__);
                hang();
        }
 
-       rqfd_average = ((max_start + max_end) >> 1);
+       blank_string(strlen(str));
 
        if (rqfd_average < 0)
                rqfd_average = 0;
@@ -2630,12 +2699,6 @@ static void DQS_calibration_process(void)
        if (rqfd_average > SDRAM_RQDC_RQFD_MAX)
                rqfd_average = SDRAM_RQDC_RQFD_MAX;
 
-       /*------------------------------------------------------------------
-        * Restore the ECC variable to what it originally was
-        *-----------------------------------------------------------------*/
-       mfsdram(SDRAM_MCOPT1, val);
-       mtsdram(SDRAM_MCOPT1, (val & ~SDRAM_MCOPT1_MCHK_MASK) | ecc_temp);
-
        mtsdram(SDRAM_RQDC,
                (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) |
                SDRAM_RQDC_RQFD_ENCODE(rqfd_average));