2008-05-22 21:44:14 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2008 Nuovation System Designs, LLC
|
|
|
|
* Grant Erickson <gerickson@nuovations.com>
|
|
|
|
*
|
2009-09-28 15:33:45 +00:00
|
|
|
* (C) Copyright 2005-2009
|
2008-05-22 21:44:14 +00:00
|
|
|
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
|
|
|
*
|
|
|
|
* (C) Copyright 2002
|
|
|
|
* Jun Gu, Artesyn Technology, jung@artesyncp.com
|
|
|
|
*
|
|
|
|
* (C) Copyright 2001
|
|
|
|
* Bill Hunter, Wave 7 Optics, williamhunter@attbi.com
|
|
|
|
*
|
2013-07-08 07:37:19 +00:00
|
|
|
* SPDX-License-Identifier: GPL-2.0+
|
2008-05-22 21:44:14 +00:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* This file implements generic DRAM ECC initialization for
|
|
|
|
* PowerPC processors using a SDRAM DDR/DDR2 controller,
|
|
|
|
* including the 405EX(r), 440GP/GX/EP/GR, 440SP(E), and
|
|
|
|
* 460EX/GT.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <common.h>
|
2010-09-09 17:18:00 +00:00
|
|
|
#include <asm/ppc4xx.h>
|
2008-05-22 21:44:14 +00:00
|
|
|
#include <ppc_asm.tmpl>
|
|
|
|
#include <ppc_defs.h>
|
|
|
|
#include <asm/processor.h>
|
|
|
|
#include <asm/io.h>
|
2009-09-28 15:33:45 +00:00
|
|
|
#include <asm/mmu.h>
|
|
|
|
#include <asm/cache.h>
|
2008-05-22 21:44:14 +00:00
|
|
|
|
|
|
|
#include "ecc.h"
|
|
|
|
|
2008-06-02 15:22:11 +00:00
|
|
|
#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR) || \
|
|
|
|
defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
|
2008-05-22 21:44:14 +00:00
|
|
|
#if defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC)
|
2009-09-28 15:33:45 +00:00
|
|
|
|
|
|
|
#if defined(CONFIG_405EX)
|
2008-05-22 21:44:14 +00:00
|
|
|
/*
|
2009-09-28 15:33:45 +00:00
|
|
|
* Currently only 405EX uses 16bit data bus width as an alternative
|
|
|
|
* option to 32bit data width (SDRAM0_MCOPT1_WDTH)
|
2008-05-22 21:44:14 +00:00
|
|
|
*/
|
2009-09-28 15:33:45 +00:00
|
|
|
#define SDRAM_DATA_ALT_WIDTH 2
|
|
|
|
#else
|
|
|
|
#define SDRAM_DATA_ALT_WIDTH 8
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void wait_ddr_idle(void)
|
2008-05-22 21:44:14 +00:00
|
|
|
{
|
2009-09-28 15:33:45 +00:00
|
|
|
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;
|
2008-05-22 21:44:14 +00:00
|
|
|
unsigned long mcopt1;
|
2009-09-28 15:33:45 +00:00
|
|
|
char str[] = "ECC generation -";
|
|
|
|
char slash[] = "\\|/-\\|/-";
|
|
|
|
int loop = 0;
|
|
|
|
int loopi = 0;
|
2008-05-22 21:44:14 +00:00
|
|
|
|
2009-09-28 15:33:45 +00:00
|
|
|
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);
|
2008-05-22 21:44:14 +00:00
|
|
|
|
2009-09-28 15:33:45 +00:00
|
|
|
#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;
|
2008-05-22 21:44:14 +00:00
|
|
|
|
2009-09-28 15:33:45 +00:00
|
|
|
while (current_address < end_address) {
|
|
|
|
*((unsigned long *)current_address) = 0;
|
|
|
|
current_address += address_increment;
|
2008-05-22 21:44:14 +00:00
|
|
|
|
2009-09-28 15:33:45 +00:00
|
|
|
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 */
|
2008-05-22 21:44:14 +00:00
|
|
|
|
2009-09-28 15:33:45 +00:00
|
|
|
blank_string(strlen(str));
|
2008-05-22 21:44:14 +00:00
|
|
|
|
2009-09-28 15:33:45 +00:00
|
|
|
sync();
|
|
|
|
eieio();
|
|
|
|
wait_ddr_idle();
|
|
|
|
|
|
|
|
/* clear ECC error repoting registers */
|
|
|
|
mtsdram(SDRAM_ECCES, 0xffffffff);
|
2010-07-21 09:08:27 +00:00
|
|
|
#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)
|
|
|
|
/*
|
|
|
|
* IBM DDR(1) core (440GX):
|
|
|
|
* Clear Mx bits in SDRAM0_BESR0/1
|
|
|
|
*/
|
|
|
|
mtsdram(SDRAM0_BESR0, 0xffffffff);
|
|
|
|
mtsdram(SDRAM0_BESR1, 0xffffffff);
|
|
|
|
#elif defined(CONFIG_440)
|
|
|
|
/*
|
|
|
|
* 440/460 DDR2 core:
|
|
|
|
* Clear EMID (Error PLB Master ID) in MQ0_ESL
|
|
|
|
*/
|
|
|
|
mtdcr(SDRAM_ERRSTATLL, 0xfff00000);
|
|
|
|
#else
|
|
|
|
/*
|
|
|
|
* 405EX(r) DDR2 core:
|
|
|
|
* Clear M0ID (Error PLB Master ID) in SDRAM_BESR
|
|
|
|
*/
|
|
|
|
mtsdram(SDRAM_BESR, 0xf0000000);
|
|
|
|
#endif
|
2009-09-28 15:33:45 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2008-05-22 21:44:14 +00:00
|
|
|
/*
|
2009-09-28 15:33:45 +00:00
|
|
|
* Init ECC with cache disabled (on PPC's with IBM DDR
|
|
|
|
* controller (non DDR2), not tested with cache enabled yet
|
2008-05-22 21:44:14 +00:00
|
|
|
*/
|
2009-09-28 15:33:45 +00:00
|
|
|
program_ecc_addr((u32)start, size, TLB_WORD2_I_ENABLE);
|
|
|
|
}
|
|
|
|
#endif
|
2008-05-22 21:44:14 +00:00
|
|
|
|
2009-09-28 15:33:45 +00:00
|
|
|
#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();
|
2008-05-22 21:44:14 +00:00
|
|
|
|
2009-09-28 15:33:45 +00:00
|
|
|
if (memsize > CONFIG_MAX_MEM_MAPPED) {
|
|
|
|
printf("\nWarning: Can't enable ECC on systems with more than 2GB of SDRAM!\n");
|
|
|
|
return;
|
2008-05-22 21:44:14 +00:00
|
|
|
}
|
|
|
|
|
2009-09-28 15:33:45 +00:00
|
|
|
mfsdram(SDRAM_MCOPT1, mcopt1);
|
|
|
|
mfsdram(SDRAM_MCOPT2, mcopt2);
|
2008-05-22 21:44:14 +00:00
|
|
|
|
2009-09-28 15:33:45 +00:00
|
|
|
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))) {
|
2008-05-22 21:44:14 +00:00
|
|
|
|
2009-09-28 15:33:45 +00:00
|
|
|
program_ecc_addr(0, memsize, tlb_word2_i_value);
|
|
|
|
}
|
|
|
|
}
|
2008-05-22 21:44:14 +00:00
|
|
|
}
|
2009-09-28 15:33:45 +00:00
|
|
|
#endif
|
|
|
|
|
2008-05-22 21:44:14 +00:00
|
|
|
#endif /* defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC) */
|
2008-06-02 15:22:11 +00:00
|
|
|
#endif /* defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)... */
|