Commit d24bd251 authored by Felix Radensky's avatar Felix Radensky Committed by Stefan Roese
Browse files

ppc4xx: Reorganize DDR2 ECC handling



Reorganize DDR2 ECC handling to use common code for
SPD DIMMs and soldered SDRAM. Also, use common code
to display SDRAM info (ECC, CAS latency) for SPD and
soldered SDRAM variants.
Signed-off-by: default avatarFelix Radensky <felix@embedded-sol.com>
Signed-off-by: default avatarStefan Roese <sr@denx.de>
parent 1d96cfe8
......@@ -48,8 +48,6 @@
#include <asm/mmu.h>
#include <asm/cache.h>
#include "ecc.h"
#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
#define PPC4xx_IBM_DDR2_DUMP_REGISTER(mnemonic) \
......@@ -86,8 +84,240 @@
/* disable caching on SDRAM */
#define MY_TLB_WORD2_I_ENABLE TLB_WORD2_I_ENABLE
#endif /* CONFIG_4xx_DCACHE */
void dcbz_area(u32 start_address, u32 num_bytes);
#endif /* CONFIG_440 */
#define MAXRANKS 4
#define MAXBXCF 4
#define MULDIV64(m1, m2, d) (u32)(((u64)(m1) * (u64)(m2)) / (u64)(d))
static unsigned long is_ecc_enabled(void);
/*-----------------------------------------------------------------------------+
* wait_ddr_idle
*-----------------------------------------------------------------------------*/
static void wait_ddr_idle(void)
{
u32 val;
do {
mfsdram(SDRAM_MCSTAT, val);
} while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT);
}
/*-----------------------------------------------------------------------------+
* sdram_memsize
*-----------------------------------------------------------------------------*/
static phys_size_t sdram_memsize(void)
{
phys_size_t mem_size;
unsigned long mcopt2;
unsigned long mcstat;
unsigned long mb0cf;
unsigned long sdsz;
unsigned long i;
mem_size = 0;
mfsdram(SDRAM_MCOPT2, mcopt2);
mfsdram(SDRAM_MCSTAT, mcstat);
/* DDR controller must be enabled and not in self-refresh. */
/* Otherwise memsize is zero. */
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))) {
for (i = 0; i < MAXBXCF; i++) {
mfsdram(SDRAM_MB0CF + (i << 2), mb0cf);
/* Banks enabled */
if ((mb0cf & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
#if defined(CONFIG_440)
sdsz = mfdcr_any(SDRAM_R0BAS + i) & SDRAM_RXBAS_SDSZ_MASK;
#else
sdsz = mb0cf & SDRAM_RXBAS_SDSZ_MASK;
#endif
switch(sdsz) {
case SDRAM_RXBAS_SDSZ_8:
mem_size+=8;
break;
case SDRAM_RXBAS_SDSZ_16:
mem_size+=16;
break;
case SDRAM_RXBAS_SDSZ_32:
mem_size+=32;
break;
case SDRAM_RXBAS_SDSZ_64:
mem_size+=64;
break;
case SDRAM_RXBAS_SDSZ_128:
mem_size+=128;
break;
case SDRAM_RXBAS_SDSZ_256:
mem_size+=256;
break;
case SDRAM_RXBAS_SDSZ_512:
mem_size+=512;
break;
case SDRAM_RXBAS_SDSZ_1024:
mem_size+=1024;
break;
case SDRAM_RXBAS_SDSZ_2048:
mem_size+=2048;
break;
case SDRAM_RXBAS_SDSZ_4096:
mem_size+=4096;
break;
default:
printf("WARNING: Unsupported bank size (SDSZ=0x%lx)!\n"
, sdsz);
mem_size=0;
break;
}
}
}
}
return mem_size << 20;
}
/*-----------------------------------------------------------------------------+
* board_add_ram_info
*-----------------------------------------------------------------------------*/
void board_add_ram_info(int use_default)
{
PPC4xx_SYS_INFO board_cfg;
u32 val;
if (is_ecc_enabled())
puts(" (ECC");
else
puts(" (ECC not");
get_sys_info(&board_cfg);
#if defined(CONFIG_440)
mfsdr(SDR0_DDR0, val);
val = MULDIV64((board_cfg.freqPLB), SDR0_DDR0_DDRM_DECODE(val), 1);
#else
mfsdr(SDR0_SDSTP0, val);
val = MULDIV64((board_cfg.freqPLB), SDR0_SDSTP0_PLB2xDV0_DECODE(val), 1);
#endif
printf(" enabled, %d MHz", (val * 2) / 1000000);
mfsdram(SDRAM_MMODE, val);
val = (val & SDRAM_MMODE_DCL_MASK) >> 4;
printf(", CL%d)", val);
}
#ifdef CONFIG_DDR_ECC
/*-----------------------------------------------------------------------------+
* program_ecc_addr.
*-----------------------------------------------------------------------------*/
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;
char str[] = "ECC generation -";
char slash[] = "\\|/-\\|/-";
int loop = 0;
int loopi = 0;
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);
#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 = 8;
end_address = current_address + num_bytes;
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]);
}
}
#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 */
blank_string(strlen(str));
sync();
eieio();
wait_ddr_idle();
/* clear ECC error repoting registers */
mtsdram(SDRAM_ECCCR, 0xffffffff);
mtdcr(0x4c, 0xffffffff);
mtsdram(SDRAM_MCOPT1,
(mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_CHK_REP);
sync();
eieio();
wait_ddr_idle();
}
}
/*-----------------------------------------------------------------------------+
* do_program_ecc.
*-----------------------------------------------------------------------------*/
static 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();
if (memsize > CONFIG_MAX_MEM_MAPPED) {
printf("\nWarning: Can't enable ECC on systems with more than 2GB of SDRAM!\n");
return;
}
mfsdram(SDRAM_MCOPT1, mcopt1);
mfsdram(SDRAM_MCOPT2, mcopt2);
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))) {
program_ecc_addr(0, memsize, tlb_word2_i_value);
}
}
}
#endif /* CONFIG_DDR_ECC */
#if defined(CONFIG_SPD_EEPROM)
/*-----------------------------------------------------------------------------+
......@@ -105,14 +335,10 @@
#define SDRAM_NONE 0
#define MAXDIMMS 2
#define MAXRANKS 4
#define MAXBXCF 4
#define MAX_SPD_BYTES 256 /* Max number of bytes on the DIMM's SPD EEPROM */
#define ONE_BILLION 1000000000
#define MULDIV64(m1, m2, d) (u32)(((u64)(m1) * (u64)(m2)) / (u64)(d))
#define CMD_NOP (7 << 19)
#define CMD_PRECHARGE (2 << 19)
#define CMD_REFRESH (1 << 19)
......@@ -257,15 +483,11 @@ static void program_initplr(unsigned long *dimm_populated,
unsigned long num_dimm_banks,
ddr_cas_id_t selected_cas,
int write_recovery);
static unsigned long is_ecc_enabled(void);
#ifdef CONFIG_DDR_ECC
static void program_ecc(unsigned long *dimm_populated,
unsigned char *iic0_dimm_addr,
unsigned long num_dimm_banks,
unsigned long tlb_word2_i_value);
static void program_ecc_addr(unsigned long start_address,
unsigned long num_bytes,
unsigned long tlb_word2_i_value);
#endif
#if !defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
static void program_DQS_calibration(unsigned long *dimm_populated,
......@@ -278,7 +500,6 @@ static void DQS_calibration_process(void);
#endif
#endif
int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
void dcbz_area(u32 start_address, u32 num_bytes);
static unsigned char spd_read(uchar chip, uint addr)
{
......@@ -291,79 +512,6 @@ static unsigned char spd_read(uchar chip, uint addr)
return 0;
}
/*-----------------------------------------------------------------------------+
* sdram_memsize
*-----------------------------------------------------------------------------*/
static phys_size_t sdram_memsize(void)
{
phys_size_t mem_size;
unsigned long mcopt2;
unsigned long mcstat;
unsigned long mb0cf;
unsigned long sdsz;
unsigned long i;
mem_size = 0;
mfsdram(SDRAM_MCOPT2, mcopt2);
mfsdram(SDRAM_MCSTAT, mcstat);
/* DDR controller must be enabled and not in self-refresh. */
/* Otherwise memsize is zero. */
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))) {
for (i = 0; i < MAXBXCF; i++) {
mfsdram(SDRAM_MB0CF + (i << 2), mb0cf);
/* Banks enabled */
if ((mb0cf & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
sdsz = mfdcr_any(SDRAM_R0BAS + i) & SDRAM_RXBAS_SDSZ_MASK;
switch(sdsz) {
case SDRAM_RXBAS_SDSZ_8:
mem_size+=8;
break;
case SDRAM_RXBAS_SDSZ_16:
mem_size+=16;
break;
case SDRAM_RXBAS_SDSZ_32:
mem_size+=32;
break;
case SDRAM_RXBAS_SDSZ_64:
mem_size+=64;
break;
case SDRAM_RXBAS_SDSZ_128:
mem_size+=128;
break;
case SDRAM_RXBAS_SDSZ_256:
mem_size+=256;
break;
case SDRAM_RXBAS_SDSZ_512:
mem_size+=512;
break;
case SDRAM_RXBAS_SDSZ_1024:
mem_size+=1024;
break;
case SDRAM_RXBAS_SDSZ_2048:
mem_size+=2048;
break;
case SDRAM_RXBAS_SDSZ_4096:
mem_size+=4096;
break;
default:
printf("WARNING: Unsupported bank size (SDSZ=0x%lx)!\n"
, sdsz);
mem_size=0;
break;
}
}
}
}
return mem_size << 20;
}
/*-----------------------------------------------------------------------------+
* initdram. Initializes the 440SP Memory Queue and DDR SDRAM controller.
* Note: This routine runs from flash with a stack set up in the chip's
......@@ -643,26 +791,6 @@ static void get_spd_info(unsigned long *dimm_populated,
}
}
void board_add_ram_info(int use_default)
{
PPC4xx_SYS_INFO board_cfg;
u32 val;
if (is_ecc_enabled())
puts(" (ECC");
else
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);
}
/*------------------------------------------------------------------
* For the memory DIMMs installed, this routine verifies that they
......@@ -2305,9 +2433,6 @@ static void program_ecc(unsigned long *dimm_populated,
unsigned long num_dimm_banks,
unsigned long tlb_word2_i_value)
{
unsigned long mcopt1;
unsigned long mcopt2;
unsigned long mcstat;
unsigned long dimm_num;
unsigned long ecc;
......@@ -2321,105 +2446,7 @@ static void program_ecc(unsigned long *dimm_populated,
if (ecc == 0)
return;
if (sdram_memsize() > CONFIG_MAX_MEM_MAPPED) {
printf("\nWarning: Can't enable ECC on systems with more than 2GB of SDRAM!\n");
return;
}
mfsdram(SDRAM_MCOPT1, mcopt1);
mfsdram(SDRAM_MCOPT2, mcopt2);
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))) {
program_ecc_addr(0, sdram_memsize(), tlb_word2_i_value);
}
}
return;
}
static void wait_ddr_idle(void)
{
u32 val;
do {
mfsdram(SDRAM_MCSTAT, val);
} while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT);
}
/*-----------------------------------------------------------------------------+
* program_ecc_addr.
*-----------------------------------------------------------------------------*/
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;
char str[] = "ECC generation -";
char slash[] = "\\|/-\\|/-";
int loop = 0;
int loopi = 0;
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);
if (tlb_word2_i_value == TLB_WORD2_I_ENABLE) {
/* ECC bit set method for non-cached memory */
if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32)
address_increment = 4;
else
address_increment = 8;
end_address = current_address + num_bytes;
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);
/* Write modified dcache lines back to memory */
clean_dcache_range(start_address, start_address + num_bytes);
}
blank_string(strlen(str));
sync();
eieio();
wait_ddr_idle();
/* clear ECC error repoting registers */
mtsdram(SDRAM_ECCCR, 0xffffffff);
mtdcr(0x4c, 0xffffffff);
mtsdram(SDRAM_MCOPT1,
(mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_CHK_REP);
sync();
eieio();
wait_ddr_idle();
}
do_program_ecc(tlb_word2_i_value);
}
#endif
......@@ -2962,6 +2989,21 @@ static void test(void)
#else /* CONFIG_SPD_EEPROM */
/*-----------------------------------------------------------------------------+
* is_ecc_enabled
*-----------------------------------------------------------------------------*/
static unsigned long is_ecc_enabled(void)
{
unsigned long ecc;
unsigned long val;
ecc = 0;
mfsdram(SDRAM_MCOPT1, val);
ecc = max(ecc, SDRAM_MCOPT1_MCHK_CHK_DECODE(val));
return ecc;
}
/*-----------------------------------------------------------------------------
* Function: initdram
* Description: Configures the PPC4xx IBM DDR1/DDR2 SDRAM memory controller.
......@@ -3106,7 +3148,7 @@ phys_size_t initdram(int board_type)
#endif /* CONFIG_PPC4xx_DDR_AUTOCALIBRATION */
#if defined(CONFIG_DDR_ECC)
ecc_init(CONFIG_SYS_SDRAM_BASE, CONFIG_SYS_MBYTES_SDRAM << 20);
do_program_ecc(0);
#endif /* defined(CONFIG_DDR_ECC) */
#if defined(CONFIG_440)
......
......@@ -768,6 +768,10 @@
#define SDR0_SDCS_SDD (0x80000000 >> 31)
/* SDR0_SDSTP0 Serial Device Strap Register0 */
#define SDR0_SDSTP0 0x0020
#define SDR0_SDSTP0_PLB2xDV0_DECODE(n) ((((unsigned long)(n)) & 0x07))
/* CUST0 Customer Configuration Register0 */
#define SDR0_CUST0 0x4000
#define SDR0_CUST0_MUX_E_N_G_MASK 0xC0000000 /* Mux_Emac_NDFC_GPIO */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment