]> git.sur5r.net Git - u-boot/blobdiff - cpu/ppc4xx/ecc.c
ppc4xx: Fix reporting of bootstrap options G and F on 460EX/GT
[u-boot] / cpu / ppc4xx / ecc.c
index a2eb07bd755cbafc6fa8123aadaa469f57699b0a..f105605459d5aec6490d70dccc111e8633e23968 100644 (file)
@@ -2,7 +2,7 @@
  *    Copyright (c) 2008 Nuovation System Designs, LLC
  *      Grant Erickson <gerickson@nuovations.com>
  *
- *    (C) Copyright 2005-2007
+ *    (C) Copyright 2005-2009
  *    Stefan Roese, DENX Software Engineering, sr@denx.de.
  *
  *    (C) Copyright 2002
 #include <ppc_defs.h>
 #include <asm/processor.h>
 #include <asm/io.h>
+#include <asm/mmu.h>
+#include <asm/cache.h>
 
 #include "ecc.h"
 
 #if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR) || \
     defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
 #if defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC)
+
+#if defined(CONFIG_405EX)
 /*
- *  void ecc_init()
- *
- *  Description:
- *    This routine initializes a range of DRAM ECC memory with known
- *    data and enables ECC checking.
- *
- *  TO DO:
- *    - Improve performance by utilizing cache.
- *    - Further generalize to make usable by other 4xx variants (e.g.
- *      440EPx, et al).
- *
- *  Input(s):
- *    start - A pointer to the start of memory covered by ECC requiring
- *           initialization.
- *    size  - The size, in bytes, of the memory covered by ECC requiring
- *           initialization.
- *
- *  Output(s):
- *    start - A pointer to the start of memory covered by ECC with
- *           CFG_ECC_PATTERN written to all locations and ECC data
- *           primed.
- *
- *  Returns:
- *    N/A
+ * Currently only 405EX uses 16bit data bus width as an alternative
+ * option to 32bit data width (SDRAM0_MCOPT1_WDTH)
  */
-void ecc_init(unsigned long * const start, unsigned long size)
+#define SDRAM_DATA_ALT_WIDTH   2
+#else
+#define SDRAM_DATA_ALT_WIDTH   8
+#endif
+
+static void wait_ddr_idle(void)
 {
-       const unsigned long pattern = CFG_ECC_PATTERN;
-       unsigned long * const end = (unsigned long * const)((long)start + size);
-       unsigned long * current = start;
+       u32 val;
+
+       do {
+               mfsdram(SDRAM_MCSTAT, val);
+       } while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT);
+}
+
+static void program_ecc_addr(unsigned long start_address,
+                            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;
-       long increment;
+       char str[] = "ECC generation -";
+       char slash[] = "\\|/-\\|/-";
+       int loop = 0;
+       int loopi = 0;
 
-       if (start >= end)
-               return;
+       current_address = start_address;
+       mfsdram(SDRAM_MCOPT1, mcopt1);
+       if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) {
+               mtsdram(SDRAM_MCOPT1,
+                       (mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_GEN);
+               sync();
+               eieio();
+               wait_ddr_idle();
+
+               puts(str);
 
-       mfsdram(SDRAM_ECC_CFG, mcopt1);
+#ifdef CONFIG_440
+               if (tlb_word2_i_value == TLB_WORD2_I_ENABLE) {
+#endif
+                       /* ECC bit set method for non-cached memory */
+                       if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32)
+                               address_increment = 4;
+                       else
+                               address_increment = SDRAM_DATA_ALT_WIDTH;
+                       end_address = current_address + num_bytes;
 
-       /* Enable ECC generation without checking or reporting */
+                       while (current_address < end_address) {
+                               *((unsigned long *)current_address) = 0;
+                               current_address += address_increment;
 
-       mtsdram(SDRAM_ECC_CFG, ((mcopt1 & ~SDRAM_ECC_CFG_MCHK_MASK) |
-                               SDRAM_ECC_CFG_MCHK_GEN));
+                               if ((loop++ % (2 << 20)) == 0) {
+                                       putc('\b');
+                                       putc(slash[loopi++ % 8]);
+                               }
+                       }
+#ifdef CONFIG_440
+               } else {
+                       /* ECC bit set method for cached memory */
+                       dcbz_area(start_address, num_bytes);
+                       /* Write modified dcache lines back to memory */
+                       clean_dcache_range(start_address, start_address + num_bytes);
+               }
+#endif /* CONFIG_440 */
 
-       increment = sizeof(u32);
+               blank_string(strlen(str));
 
-#if defined(CONFIG_440)
+               sync();
+               eieio();
+               wait_ddr_idle();
+
+               /* clear ECC error repoting registers */
+               mtsdram(SDRAM_ECCES, 0xffffffff);
+               mtdcr(0x4c, 0xffffffff);
+
+               mtsdram(SDRAM_MCOPT1,
+                       (mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_CHK_REP);
+               sync();
+               eieio();
+               wait_ddr_idle();
+       }
+}
+
+#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)
+void ecc_init(unsigned long * const start, unsigned long size)
+{
        /*
-        * Look at the geometry of SDRAM (data width) to determine whether we
-        * can skip words when writing.
+        * Init ECC with cache disabled (on PPC's with IBM DDR
+        * controller (non DDR2), not tested with cache enabled yet
         */
+       program_ecc_addr((u32)start, size, TLB_WORD2_I_ENABLE);
+}
+#endif
 
-       if ((mcopt1 & SDRAM_ECC_CFG_DMWD_MASK) != SDRAM_ECC_CFG_DMWD_32)
-               increment = sizeof(u64);
-#endif /* defined(CONFIG_440) */
+#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
+void do_program_ecc(unsigned long tlb_word2_i_value)
+{
+       unsigned long mcopt1;
+       unsigned long mcopt2;
+       unsigned long mcstat;
+       phys_size_t memsize = sdram_memsize();
 
-       while (current < end) {
-               *current = pattern;
-                current = (unsigned long *)((long)current + increment);
+       if (memsize > CONFIG_MAX_MEM_MAPPED) {
+               printf("\nWarning: Can't enable ECC on systems with more than 2GB of SDRAM!\n");
+               return;
        }
 
-       /* Wait until the writes are finished. */
+       mfsdram(SDRAM_MCOPT1, mcopt1);
+       mfsdram(SDRAM_MCOPT2, mcopt2);
 
-       sync();
+       if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) {
+               /* DDR controller must be enabled and not in self-refresh. */
+               mfsdram(SDRAM_MCSTAT, mcstat);
+               if (((mcopt2 & SDRAM_MCOPT2_DCEN_MASK) == SDRAM_MCOPT2_DCEN_ENABLE)
+                   && ((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))) {
 
-       /* Enable ECC generation with checking and no reporting */
-
-       mtsdram(SDRAM_ECC_CFG, ((mcopt1 & ~SDRAM_ECC_CFG_MCHK_MASK) |
-                               SDRAM_ECC_CFG_MCHK_CHK));
+                       program_ecc_addr(0, memsize, tlb_word2_i_value);
+               }
+       }
 }
+#endif
+
 #endif /* defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC) */
 #endif /* defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)... */