uboot/arch/powerpc/cpu/ppc4xx/ecc.c
<<
>>
Prefs
   1/*
   2 *    Copyright (c) 2008 Nuovation System Designs, LLC
   3 *      Grant Erickson <gerickson@nuovations.com>
   4 *
   5 *    (C) Copyright 2005-2009
   6 *    Stefan Roese, DENX Software Engineering, sr@denx.de.
   7 *
   8 *    (C) Copyright 2002
   9 *    Jun Gu, Artesyn Technology, jung@artesyncp.com
  10 *
  11 *    (C) Copyright 2001
  12 *    Bill Hunter, Wave 7 Optics, williamhunter@attbi.com
  13 *
  14 * SPDX-License-Identifier:     GPL-2.0+
  15 *
  16 *    Description:
  17 *      This file implements generic DRAM ECC initialization for
  18 *      PowerPC processors using a SDRAM DDR/DDR2 controller,
  19 *      including the 405EX(r), 440GP/GX/EP/GR, 440SP(E), and
  20 *      460EX/GT.
  21 */
  22
  23#include <common.h>
  24#include <asm/ppc4xx.h>
  25#include <ppc_asm.tmpl>
  26#include <ppc_defs.h>
  27#include <asm/processor.h>
  28#include <asm/io.h>
  29#include <asm/mmu.h>
  30#include <asm/cache.h>
  31
  32#include "ecc.h"
  33
  34#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR) || \
  35    defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
  36#if defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC)
  37
  38#if defined(CONFIG_405EX)
  39/*
  40 * Currently only 405EX uses 16bit data bus width as an alternative
  41 * option to 32bit data width (SDRAM0_MCOPT1_WDTH)
  42 */
  43#define SDRAM_DATA_ALT_WIDTH    2
  44#else
  45#define SDRAM_DATA_ALT_WIDTH    8
  46#endif
  47
  48static void wait_ddr_idle(void)
  49{
  50        u32 val;
  51
  52        do {
  53                mfsdram(SDRAM_MCSTAT, val);
  54        } while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT);
  55}
  56
  57static void program_ecc_addr(unsigned long start_address,
  58                             unsigned long num_bytes,
  59                             unsigned long tlb_word2_i_value)
  60{
  61        unsigned long current_address;
  62        unsigned long end_address;
  63        unsigned long address_increment;
  64        unsigned long mcopt1;
  65        char str[] = "ECC generation -";
  66        char slash[] = "\\|/-\\|/-";
  67        int loop = 0;
  68        int loopi = 0;
  69
  70        current_address = start_address;
  71        mfsdram(SDRAM_MCOPT1, mcopt1);
  72        if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) {
  73                mtsdram(SDRAM_MCOPT1,
  74                        (mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_GEN);
  75                sync();
  76                eieio();
  77                wait_ddr_idle();
  78
  79                puts(str);
  80
  81#ifdef CONFIG_440
  82                if (tlb_word2_i_value == TLB_WORD2_I_ENABLE) {
  83#endif
  84                        /* ECC bit set method for non-cached memory */
  85                        if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32)
  86                                address_increment = 4;
  87                        else
  88                                address_increment = SDRAM_DATA_ALT_WIDTH;
  89                        end_address = current_address + num_bytes;
  90
  91                        while (current_address < end_address) {
  92                                *((unsigned long *)current_address) = 0;
  93                                current_address += address_increment;
  94
  95                                if ((loop++ % (2 << 20)) == 0) {
  96                                        putc('\b');
  97                                        putc(slash[loopi++ % 8]);
  98                                }
  99                        }
 100#ifdef CONFIG_440
 101                } else {
 102                        /* ECC bit set method for cached memory */
 103                        dcbz_area(start_address, num_bytes);
 104                        /* Write modified dcache lines back to memory */
 105                        clean_dcache_range(start_address, start_address + num_bytes);
 106                }
 107#endif /* CONFIG_440 */
 108
 109                blank_string(strlen(str));
 110
 111                sync();
 112                eieio();
 113                wait_ddr_idle();
 114
 115                /* clear ECC error repoting registers */
 116                mtsdram(SDRAM_ECCES, 0xffffffff);
 117#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)
 118                /*
 119                 * IBM DDR(1) core (440GX):
 120                 * Clear Mx bits in SDRAM0_BESR0/1
 121                 */
 122                mtsdram(SDRAM0_BESR0, 0xffffffff);
 123                mtsdram(SDRAM0_BESR1, 0xffffffff);
 124#elif defined(CONFIG_440)
 125                /*
 126                 * 440/460 DDR2 core:
 127                 * Clear EMID (Error PLB Master ID) in MQ0_ESL
 128                 */
 129                mtdcr(SDRAM_ERRSTATLL, 0xfff00000);
 130#else
 131                /*
 132                 * 405EX(r) DDR2 core:
 133                 * Clear M0ID (Error PLB Master ID) in SDRAM_BESR
 134                 */
 135                mtsdram(SDRAM_BESR, 0xf0000000);
 136#endif
 137
 138                mtsdram(SDRAM_MCOPT1,
 139                        (mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_CHK_REP);
 140                sync();
 141                eieio();
 142                wait_ddr_idle();
 143        }
 144}
 145
 146#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)
 147void ecc_init(unsigned long * const start, unsigned long size)
 148{
 149        /*
 150         * Init ECC with cache disabled (on PPC's with IBM DDR
 151         * controller (non DDR2), not tested with cache enabled yet
 152         */
 153        program_ecc_addr((u32)start, size, TLB_WORD2_I_ENABLE);
 154}
 155#endif
 156
 157#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
 158void do_program_ecc(unsigned long tlb_word2_i_value)
 159{
 160        unsigned long mcopt1;
 161        unsigned long mcopt2;
 162        unsigned long mcstat;
 163        phys_size_t memsize = sdram_memsize();
 164
 165        if (memsize > CONFIG_MAX_MEM_MAPPED) {
 166                printf("\nWarning: Can't enable ECC on systems with more than 2GB of SDRAM!\n");
 167                return;
 168        }
 169
 170        mfsdram(SDRAM_MCOPT1, mcopt1);
 171        mfsdram(SDRAM_MCOPT2, mcopt2);
 172
 173        if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) {
 174                /* DDR controller must be enabled and not in self-refresh. */
 175                mfsdram(SDRAM_MCSTAT, mcstat);
 176                if (((mcopt2 & SDRAM_MCOPT2_DCEN_MASK) == SDRAM_MCOPT2_DCEN_ENABLE)
 177                    && ((mcopt2 & SDRAM_MCOPT2_SREN_MASK) == SDRAM_MCOPT2_SREN_EXIT)
 178                    && ((mcstat & (SDRAM_MCSTAT_MIC_MASK | SDRAM_MCSTAT_SRMS_MASK))
 179                        == (SDRAM_MCSTAT_MIC_COMP | SDRAM_MCSTAT_SRMS_NOT_SF))) {
 180
 181                        program_ecc_addr(0, memsize, tlb_word2_i_value);
 182                }
 183        }
 184}
 185#endif
 186
 187#endif /* defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC) */
 188#endif /* defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)... */
 189