]> git.sur5r.net Git - u-boot/blobdiff - cpu/ppc4xx/44x_spd_ddr2.c
TQM85xx: Support for Intel 82527 compatible CAN controller
[u-boot] / cpu / ppc4xx / 44x_spd_ddr2.c
index e19929437e2d4d0c389ada193fa64274da40c6be..ec76b718bccb1f2b86215259bc16f20f80f9d8fc 100644 (file)
@@ -1,9 +1,12 @@
 /*
  * cpu/ppc4xx/44x_spd_ddr2.c
  * This SPD SDRAM detection code supports AMCC PPC44x cpu's with a
- * DDR2 controller (non Denali Core). Those are 440SP/SPe.
+ * DDR2 controller (non Denali Core). Those currently are:
  *
- * (C) Copyright 2007
+ * 405:                405EX
+ * 440/460:    440SP/440SPe/460EX/460GT
+ *
+ * (C) Copyright 2007-2008
  * Stefan Roese, DENX Software Engineering, sr@denx.de.
  *
  * COPYRIGHT   AMCC   CORPORATION 2004
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/mmu.h>
+#include <asm/cache.h>
 
 #if defined(CONFIG_SPD_EEPROM) &&                              \
-       (defined(CONFIG_440SP) || defined(CONFIG_440SPE))
+       (defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+        defined(CONFIG_460EX) || defined(CONFIG_460GT))
 
 /*-----------------------------------------------------------------------------+
  * Defines
 #define NUMMEMWORDS    8
 #define NUMLOOPS       64              /* memory test loops */
 
-#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
  * region. Right now the cache should still be disabled in U-Boot because of the
@@ -238,7 +241,6 @@ static void DQS_calibration_process(void);
 static void ppc440sp_sdram_register_dump(void);
 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)
 {
@@ -389,9 +391,9 @@ long int initdram(int board_type)
        unsigned char spd1[MAX_SPD_BYTES];
        unsigned char *dimm_spd[MAXDIMMS];
        unsigned long dimm_populated[MAXDIMMS];
-       unsigned long num_dimm_banks;               /* on board dimm banks */
+       unsigned long num_dimm_banks;           /* on board dimm banks */
        unsigned long val;
-       ddr_cas_id_t  selected_cas;
+       ddr_cas_id_t selected_cas = DDR_CAS_5;  /* preset to silence compiler */
        int write_recovery;
        unsigned long dram_size = 0;
 
@@ -581,6 +583,13 @@ long int initdram(int board_type)
 
        ppc440sp_sdram_register_dump();
 
+       /*
+        * Clear potential errors resulting from auto-calibration.
+        * If not done, then we could get an interrupt later on when
+        * exceptions are enabled.
+        */
+       set_mcsr(get_mcsr());
+
        return dram_size;
 }
 
@@ -2072,7 +2081,7 @@ static void program_bxcf(unsigned long *dimm_populated,
                                if (num_banks == 4)
                                        ind = 0;
                                else
-                                       ind = 5;
+                                       ind = 5 << 8;
                                switch (num_col_addr) {
                                case 0x08:
                                        mode |= (SDRAM_BXCF_M_AM_0 + ind);
@@ -2127,6 +2136,7 @@ static void program_memory_queue(unsigned long *dimm_populated,
        unsigned long baseadd_size;
        unsigned long i;
        unsigned long bank_0_populated = 0;
+       unsigned long total_size = 0;
 
        /*------------------------------------------------------------------
         * Reset the rank_base_address.
@@ -2149,28 +2159,38 @@ static void program_memory_queue(unsigned long *dimm_populated,
                         * Set the sizes
                         *-----------------------------------------------------------------*/
                        baseadd_size = 0;
-                       rank_size_bytes = 4 * 1024 * 1024 * rank_size_id;
                        switch (rank_size_id) {
+                       case 0x01:
+                               baseadd_size |= SDRAM_RXBAS_SDSZ_1024;
+                               total_size = 1024;
+                               break;
                        case 0x02:
-                               baseadd_size |= SDRAM_RXBAS_SDSZ_8;
+                               baseadd_size |= SDRAM_RXBAS_SDSZ_2048;
+                               total_size = 2048;
                                break;
                        case 0x04:
-                               baseadd_size |= SDRAM_RXBAS_SDSZ_16;
+                               baseadd_size |= SDRAM_RXBAS_SDSZ_4096;
+                               total_size = 4096;
                                break;
                        case 0x08:
                                baseadd_size |= SDRAM_RXBAS_SDSZ_32;
+                               total_size = 32;
                                break;
                        case 0x10:
                                baseadd_size |= SDRAM_RXBAS_SDSZ_64;
+                               total_size = 64;
                                break;
                        case 0x20:
                                baseadd_size |= SDRAM_RXBAS_SDSZ_128;
+                               total_size = 128;
                                break;
                        case 0x40:
                                baseadd_size |= SDRAM_RXBAS_SDSZ_256;
+                               total_size = 256;
                                break;
                        case 0x80:
                                baseadd_size |= SDRAM_RXBAS_SDSZ_512;
+                               total_size = 512;
                                break;
                        default:
                                printf("DDR-SDRAM: DIMM %d memory queue configuration.\n",
@@ -2180,6 +2200,7 @@ static void program_memory_queue(unsigned long *dimm_populated,
                                printf("Replace the DIMM module with a supported DIMM.\n\n");
                                spd_ddr_init_hang ();
                        }
+                       rank_size_bytes = total_size << 20;
 
                        if ((dimm_populated[dimm_num] != SDRAM_NONE) && (dimm_num == 1))
                                bank_0_populated = 1;
@@ -2192,6 +2213,19 @@ static void program_memory_queue(unsigned long *dimm_populated,
                        }
                }
        }
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+       /*
+        * Enable high bandwidth access on 460EX/GT.
+        * This should/could probably be done on other
+        * PPC's too, like 440SPe.
+        * This is currently not used, but with this setup
+        * it is possible to use it later on in e.g. the Linux
+        * EMAC driver for performance gain.
+        */
+       mtdcr(SDRAM_PLBADDULL, 0x00000000); /* MQ0_BAUL */
+       mtdcr(SDRAM_PLBADDUHB, 0x00000008); /* MQ0_BAUH */
+#endif
 }
 
 /*-----------------------------------------------------------------------------+
@@ -2268,39 +2302,6 @@ static void program_ecc(unsigned long *dimm_populated,
        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;
@@ -2357,7 +2358,8 @@ static void program_ecc_addr(unsigned long start_address,
                } else {
                        /* ECC bit set method for cached memory */
                        dcbz_area(start_address, num_bytes);
-                       dflush();
+                       /* Write modified dcache lines back to memory */
+                       clean_dcache_range(start_address, start_address + num_bytes);
                }
 
                blank_string(strlen(str));
@@ -2375,15 +2377,6 @@ static void program_ecc_addr(unsigned long start_address,
                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
@@ -2409,17 +2402,10 @@ static void program_DQS_calibration(unsigned long *dimm_populated,
         * Read sample cycle auto-update enable
         *-----------------------------------------------------------------*/
 
-       /*
-        * Modified for the Katmai platform:  with some DIMMs, the DDR2
-        * controller automatically selects the T2 read cycle, but this
-        * proves unreliable.  Go ahead and force the DDR2 controller
-        * to use the T4 sample and disable the automatic update of the
-        * RDSS field.
-        */
        mfsdram(SDRAM_RDCC, val);
        mtsdram(SDRAM_RDCC,
                (val & ~(SDRAM_RDCC_RDSS_MASK | SDRAM_RDCC_RSAE_MASK))
-               | (SDRAM_RDCC_RDSS_T4 | SDRAM_RDCC_RSAE_DISABLE));
+               | SDRAM_RDCC_RSAE_ENABLE);
 
        /*------------------------------------------------------------------
         * Program RQDC register
@@ -2512,10 +2498,7 @@ static void DQS_calibration_process(void)
 {
        unsigned long rfdc_reg;
        unsigned long rffd;
-       unsigned long rqdc_reg;
-       unsigned long rqfd;
        unsigned long val;
-       long rqfd_average;
        long rffd_average;
        long max_start;
        long min_end;
@@ -2533,10 +2516,14 @@ static void DQS_calibration_process(void)
        long max_end;
        unsigned char fail_found;
        unsigned char pass_found;
+#if !defined(CONFIG_DDR_RQDC_FIXED)
+       u32 rqdc_reg;
+       u32 rqfd;
        u32 rqfd_start;
+       u32 rqfd_average;
+       int loopi = 0;
        char str[] = "Auto calibration -";
        char slash[] = "\\|/-\\|/-";
-       int loopi = 0;
 
        /*------------------------------------------------------------------
         * Test to determine the best read clock delay tuning bits.
@@ -2571,6 +2558,16 @@ calibration_loop:
        mfsdram(SDRAM_RQDC, rqdc_reg);
        mtsdram(SDRAM_RQDC, (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) |
                SDRAM_RQDC_RQFD_ENCODE(rqfd_start));
+#else /* CONFIG_DDR_RQDC_FIXED */
+       /*
+        * On Katmai the complete auto-calibration somehow doesn't seem to
+        * produce the best results, meaning optimal values for RQFD/RFFD.
+        * This was discovered by GDA using a high bandwidth scope,
+        * analyzing the DDR2 signals. GDA provided a fixed value for RQFD,
+        * so now on Katmai "only" RFFD is auto-calibrated.
+        */
+       mtsdram(SDRAM_RQDC, CONFIG_DDR_RQDC_FIXED);
+#endif /* CONFIG_DDR_RQDC_FIXED */
 
        max_start = 0;
        min_end = 0;
@@ -2655,6 +2652,7 @@ calibration_loop:
        /* now fix RFDC[RFFD] found and find RQDC[RQFD] */
        mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average));
 
+#if !defined(CONFIG_DDR_RQDC_FIXED)
        max_pass_length = 0;
        max_start = 0;
        max_end = 0;
@@ -2727,8 +2725,6 @@ calibration_loop:
                spd_ddr_init_hang ();
        }
 
-       blank_string(strlen(str));
-
        if (rqfd_average < 0)
                rqfd_average = 0;
 
@@ -2739,12 +2735,31 @@ calibration_loop:
                (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) |
                SDRAM_RQDC_RQFD_ENCODE(rqfd_average));
 
+       blank_string(strlen(str));
+#endif /* CONFIG_DDR_RQDC_FIXED */
+
+       /*
+        * Now complete RDSS configuration as mentioned on page 7 of the AMCC
+        * PowerPC440SP/SPe DDR2 application note:
+        * "DDR1/DDR2 Initialization Sequence and Dynamic Tuning"
+        */
+       mfsdram(SDRAM_RTSR, val);
+       if ((val & SDRAM_RTSR_TRK1SM_MASK) == SDRAM_RTSR_TRK1SM_ATPLS1) {
+               mfsdram(SDRAM_RDCC, val);
+               if ((val & SDRAM_RDCC_RDSS_MASK) != SDRAM_RDCC_RDSS_T4) {
+                       val += 0x40000000;
+                       mtsdram(SDRAM_RDCC, val);
+               }
+       }
+
        mfsdram(SDRAM_DLCR, val);
        debug("%s[%d] DLCR: 0x%08X\n", __FUNCTION__, __LINE__, val);
        mfsdram(SDRAM_RQDC, val);
        debug("%s[%d] RQDC: 0x%08X\n", __FUNCTION__, __LINE__, val);
        mfsdram(SDRAM_RFDC, val);
        debug("%s[%d] RFDC: 0x%08X\n", __FUNCTION__, __LINE__, val);
+       mfsdram(SDRAM_RDCC, val);
+       debug("%s[%d] RDCC: 0x%08X\n", __FUNCTION__, __LINE__, val);
 }
 #else /* calibration test with hardvalues */
 /*-----------------------------------------------------------------------------+