|
|
|
@ -1,7 +1,10 @@ |
|
|
|
|
/*
|
|
|
|
|
* (C) Copyright 2005 |
|
|
|
|
* (C) Copyright 2005-2006 |
|
|
|
|
* Stefan Roese, DENX Software Engineering, sr@denx.de. |
|
|
|
|
* |
|
|
|
|
* (C) Copyright 2006 |
|
|
|
|
* DAVE Srl <www.dave-tech.it> |
|
|
|
|
* |
|
|
|
|
* (C) Copyright 2002-2004 |
|
|
|
|
* Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com |
|
|
|
|
* |
|
|
|
@ -27,28 +30,19 @@ |
|
|
|
|
#include <common.h> |
|
|
|
|
#include <ppc4xx.h> |
|
|
|
|
#include <asm/processor.h> |
|
|
|
|
#include "sdram.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SDRAM_BANK0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define mtsdram0(reg, data) mtdcr(memcfga,reg);mtdcr(memcfgd,data) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct sdram_conf_s { |
|
|
|
|
unsigned long size; |
|
|
|
|
unsigned long reg; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
typedef struct sdram_conf_s sdram_conf_t; |
|
|
|
|
|
|
|
|
|
#ifndef CFG_SDRAM_TABLE |
|
|
|
|
sdram_conf_t mb0cf[] = { |
|
|
|
|
{(128 << 20), 0x000A4001}, /* (0-128MB) Address Mode 3, 13x10(4) */ |
|
|
|
|
{(64 << 20), 0x00084001}, /* (0-64MB) Address Mode 3, 13x9(4) */ |
|
|
|
|
{(32 << 20), 0x00062001}, /* (0-32MB) Address Mode 2, 12x9(4) */ |
|
|
|
|
{(16 << 20), 0x00046001}, /* (0-16MB) Address Mode 4, 12x8(4) */ |
|
|
|
|
{(4 << 20), 0x00008001}, /* (0-4MB) Address Mode 5, 11x8(2) */ |
|
|
|
|
{(128 << 20), 13, 0x000A4001}, /* (0-128MB) Address Mode 3, 13x10(4) */ |
|
|
|
|
{(64 << 20), 13, 0x00084001}, /* (0-64MB) Address Mode 3, 13x9(4) */ |
|
|
|
|
{(32 << 20), 12, 0x00062001}, /* (0-32MB) Address Mode 2, 12x9(4) */ |
|
|
|
|
{(16 << 20), 12, 0x00046001}, /* (0-16MB) Address Mode 4, 12x8(4) */ |
|
|
|
|
{(4 << 20), 11, 0x00008001}, /* (0-4MB) Address Mode 5, 11x8(2) */ |
|
|
|
|
}; |
|
|
|
|
#else |
|
|
|
|
sdram_conf_t mb0cf[] = CFG_SDRAM_TABLE; |
|
|
|
@ -59,31 +53,138 @@ sdram_conf_t mb0cf[] = CFG_SDRAM_TABLE; |
|
|
|
|
|
|
|
|
|
#ifndef CONFIG_440 |
|
|
|
|
|
|
|
|
|
#ifdef CFG_SDRAM_CASL |
|
|
|
|
static ulong ns2clks(ulong ns) |
|
|
|
|
{ |
|
|
|
|
ulong bus_period_x_10 = ONE_BILLION / (get_bus_freq(0) / 10); |
|
|
|
|
|
|
|
|
|
return ((ns * 10) + bus_period_x_10) / bus_period_x_10; |
|
|
|
|
} |
|
|
|
|
#endif /* CFG_SDRAM_CASL */ |
|
|
|
|
|
|
|
|
|
static ulong compute_sdtr1(ulong speed) |
|
|
|
|
{ |
|
|
|
|
#ifdef CFG_SDRAM_CASL |
|
|
|
|
ulong tmp; |
|
|
|
|
ulong sdtr1 = 0; |
|
|
|
|
|
|
|
|
|
/* CASL */ |
|
|
|
|
if (CFG_SDRAM_CASL < 2) |
|
|
|
|
sdtr1 |= (1 << SDRAM0_TR_CASL); |
|
|
|
|
else |
|
|
|
|
if (CFG_SDRAM_CASL > 4) |
|
|
|
|
sdtr1 |= (3 << SDRAM0_TR_CASL); |
|
|
|
|
else |
|
|
|
|
sdtr1 |= ((CFG_SDRAM_CASL-1) << SDRAM0_TR_CASL); |
|
|
|
|
|
|
|
|
|
/* PTA */ |
|
|
|
|
tmp = ns2clks(CFG_SDRAM_PTA); |
|
|
|
|
if ((tmp >= 2) && (tmp <= 4)) |
|
|
|
|
sdtr1 |= ((tmp-1) << SDRAM0_TR_PTA); |
|
|
|
|
else |
|
|
|
|
sdtr1 |= ((4-1) << SDRAM0_TR_PTA); |
|
|
|
|
|
|
|
|
|
/* CTP */ |
|
|
|
|
tmp = ns2clks(CFG_SDRAM_CTP); |
|
|
|
|
if ((tmp >= 2) && (tmp <= 4)) |
|
|
|
|
sdtr1 |= ((tmp-1) << SDRAM0_TR_CTP); |
|
|
|
|
else |
|
|
|
|
sdtr1 |= ((4-1) << SDRAM0_TR_CTP); |
|
|
|
|
|
|
|
|
|
/* LDF */ |
|
|
|
|
tmp = ns2clks(CFG_SDRAM_LDF); |
|
|
|
|
if ((tmp >= 2) && (tmp <= 4)) |
|
|
|
|
sdtr1 |= ((tmp-1) << SDRAM0_TR_LDF); |
|
|
|
|
else |
|
|
|
|
sdtr1 |= ((2-1) << SDRAM0_TR_LDF); |
|
|
|
|
|
|
|
|
|
/* RFTA */ |
|
|
|
|
tmp = ns2clks(CFG_SDRAM_RFTA); |
|
|
|
|
if ((tmp >= 4) && (tmp <= 10)) |
|
|
|
|
sdtr1 |= ((tmp-4) << SDRAM0_TR_RFTA); |
|
|
|
|
else |
|
|
|
|
sdtr1 |= ((10-4) << SDRAM0_TR_RFTA); |
|
|
|
|
|
|
|
|
|
/* RCD */ |
|
|
|
|
tmp = ns2clks(CFG_SDRAM_RCD); |
|
|
|
|
if ((tmp >= 2) && (tmp <= 4)) |
|
|
|
|
sdtr1 |= ((tmp-1) << SDRAM0_TR_RCD); |
|
|
|
|
else |
|
|
|
|
sdtr1 |= ((4-1) << SDRAM0_TR_RCD); |
|
|
|
|
|
|
|
|
|
return sdtr1; |
|
|
|
|
#else /* CFG_SDRAM_CASL */ |
|
|
|
|
/*
|
|
|
|
|
* If no values are configured in the board config file |
|
|
|
|
* use the default values, which seem to be ok for most |
|
|
|
|
* boards. |
|
|
|
|
* |
|
|
|
|
* REMARK: |
|
|
|
|
* For new board ports we strongly recommend to define the |
|
|
|
|
* correct values for the used SDRAM chips in your board |
|
|
|
|
* config file (see PPChameleonEVB.h) |
|
|
|
|
*/ |
|
|
|
|
if (speed > 100000000) { |
|
|
|
|
/*
|
|
|
|
|
* 133 MHz SDRAM |
|
|
|
|
*/ |
|
|
|
|
return 0x01074015; |
|
|
|
|
} else { |
|
|
|
|
/*
|
|
|
|
|
* default: 100 MHz SDRAM |
|
|
|
|
*/ |
|
|
|
|
return 0x0086400d; |
|
|
|
|
} |
|
|
|
|
#endif /* CFG_SDRAM_CASL */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* refresh is expressed in ms */ |
|
|
|
|
static ulong compute_rtr(ulong speed, ulong rows, ulong refresh) |
|
|
|
|
{ |
|
|
|
|
#ifdef CFG_SDRAM_CASL |
|
|
|
|
ulong tmp; |
|
|
|
|
|
|
|
|
|
tmp = ((refresh*1000*1000) / (1 << rows)) * (speed / 1000); |
|
|
|
|
tmp /= 1000000; |
|
|
|
|
|
|
|
|
|
return ((tmp & 0x00003FF8) << 16); |
|
|
|
|
#else /* CFG_SDRAM_CASL */ |
|
|
|
|
if (speed > 100000000) { |
|
|
|
|
/*
|
|
|
|
|
* 133 MHz SDRAM |
|
|
|
|
*/ |
|
|
|
|
return 0x07f00000; |
|
|
|
|
} else { |
|
|
|
|
/*
|
|
|
|
|
* default: 100 MHz SDRAM |
|
|
|
|
*/ |
|
|
|
|
return 0x05f00000; |
|
|
|
|
} |
|
|
|
|
#endif /* CFG_SDRAM_CASL */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Autodetect onboard SDRAM on 405 platforms |
|
|
|
|
*/ |
|
|
|
|
void sdram_init(void) |
|
|
|
|
{ |
|
|
|
|
ulong speed; |
|
|
|
|
ulong sdtr1; |
|
|
|
|
ulong rtr; |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Support for 100MHz and 133MHz SDRAM |
|
|
|
|
*/ |
|
|
|
|
if (get_bus_freq(0) > 100000000) { |
|
|
|
|
/*
|
|
|
|
|
* 133 MHz SDRAM |
|
|
|
|
*/ |
|
|
|
|
sdtr1 = 0x01074015; |
|
|
|
|
rtr = 0x07f00000; |
|
|
|
|
} else { |
|
|
|
|
/*
|
|
|
|
|
* default: 100 MHz SDRAM |
|
|
|
|
*/ |
|
|
|
|
sdtr1 = 0x0086400d; |
|
|
|
|
rtr = 0x05f00000; |
|
|
|
|
} |
|
|
|
|
/*
|
|
|
|
|
* Determine SDRAM speed |
|
|
|
|
*/ |
|
|
|
|
speed = get_bus_freq(0); /* parameter not used on ppc4xx */ |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* sdtr1 (register SDRAM0_TR) must take into account timings listed |
|
|
|
|
* in SDRAM chip datasheet. rtr (register SDRAM0_RTR) must take into |
|
|
|
|
* account actual SDRAM size. So we can set up sdtr1 according to what |
|
|
|
|
* is specified in board configuration file while rtr dependds on SDRAM |
|
|
|
|
* size we are assuming before detection. |
|
|
|
|
*/ |
|
|
|
|
sdtr1 = compute_sdtr1(speed); |
|
|
|
|
|
|
|
|
|
for (i=0; i<N_MB0CF; i++) { |
|
|
|
|
/*
|
|
|
|
@ -96,7 +197,7 @@ void sdram_init(void) |
|
|
|
|
*/ |
|
|
|
|
mtsdram0(mem_mb0cf, mb0cf[i].reg); |
|
|
|
|
mtsdram0(mem_sdtr1, sdtr1); |
|
|
|
|
mtsdram0(mem_rtr, rtr); |
|
|
|
|
mtsdram0(mem_rtr, compute_rtr(speed, mb0cf[i].rows, 64)); |
|
|
|
|
|
|
|
|
|
udelay(200); |
|
|
|
|
|
|
|
|
@ -120,6 +221,124 @@ void sdram_init(void) |
|
|
|
|
|
|
|
|
|
#else /* CONFIG_440 */ |
|
|
|
|
|
|
|
|
|
#define NUM_TRIES 64 |
|
|
|
|
#define NUM_READS 10 |
|
|
|
|
|
|
|
|
|
static void sdram_tr1_set(int ram_address, int* tr1_value) |
|
|
|
|
{ |
|
|
|
|
int i; |
|
|
|
|
int j, k; |
|
|
|
|
volatile unsigned int* ram_pointer = (unsigned int *)ram_address; |
|
|
|
|
int first_good = -1, last_bad = 0x1ff; |
|
|
|
|
|
|
|
|
|
unsigned long test[NUM_TRIES] = { |
|
|
|
|
0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, |
|
|
|
|
0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, |
|
|
|
|
0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, |
|
|
|
|
0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, |
|
|
|
|
0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, |
|
|
|
|
0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, |
|
|
|
|
0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, |
|
|
|
|
0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, |
|
|
|
|
0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, |
|
|
|
|
0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, |
|
|
|
|
0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, |
|
|
|
|
0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, |
|
|
|
|
0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, |
|
|
|
|
0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, |
|
|
|
|
0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, |
|
|
|
|
0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55 }; |
|
|
|
|
|
|
|
|
|
/* go through all possible SDRAM0_TR1[RDCT] values */ |
|
|
|
|
for (i=0; i<=0x1ff; i++) { |
|
|
|
|
/* set the current value for TR1 */ |
|
|
|
|
mtsdram(mem_tr1, (0x80800800 | i)); |
|
|
|
|
|
|
|
|
|
/* write values */ |
|
|
|
|
for (j=0; j<NUM_TRIES; j++) { |
|
|
|
|
ram_pointer[j] = test[j]; |
|
|
|
|
|
|
|
|
|
/* clear any cache at ram location */ |
|
|
|
|
__asm__("dcbf 0,%0": :"r" (&ram_pointer[j])); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* read values back */ |
|
|
|
|
for (j=0; j<NUM_TRIES; j++) { |
|
|
|
|
for (k=0; k<NUM_READS; k++) { |
|
|
|
|
/* clear any cache at ram location */ |
|
|
|
|
__asm__("dcbf 0,%0": :"r" (&ram_pointer[j])); |
|
|
|
|
|
|
|
|
|
if (ram_pointer[j] != test[j]) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* read error */ |
|
|
|
|
if (k != NUM_READS) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* we have a SDRAM0_TR1[RDCT] that is part of the window */ |
|
|
|
|
if (j == NUM_TRIES) { |
|
|
|
|
if (first_good == -1) |
|
|
|
|
first_good = i; /* found beginning of window */ |
|
|
|
|
} else { /* bad read */ |
|
|
|
|
/* if we have not had a good read then don't care */ |
|
|
|
|
if (first_good != -1) { |
|
|
|
|
/* first failure after a good read */ |
|
|
|
|
last_bad = i-1; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* return the current value for TR1 */ |
|
|
|
|
*tr1_value = (first_good + last_bad) / 2; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SDRAM_ECC |
|
|
|
|
static void ecc_init(ulong start, ulong size) |
|
|
|
|
{ |
|
|
|
|
ulong current_addr; /* current byte address */ |
|
|
|
|
ulong end_addr; /* end of memory region */ |
|
|
|
|
ulong addr_inc; /* address skip between writes */ |
|
|
|
|
ulong cfg0_reg; /* for restoring ECC state */ |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* TODO: Enable dcache before running this test (speedup) |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
mfsdram(mem_cfg0, cfg0_reg); |
|
|
|
|
mtsdram(mem_cfg0, (cfg0_reg & ~SDRAM_CFG0_MEMCHK) | SDRAM_CFG0_MEMCHK_GEN); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* look at geometry of SDRAM (data width) to determine whether we |
|
|
|
|
* can skip words when writing |
|
|
|
|
*/ |
|
|
|
|
if ((cfg0_reg & SDRAM_CFG0_DRAMWDTH) == SDRAM_CFG0_DRAMWDTH_32) |
|
|
|
|
addr_inc = 4; |
|
|
|
|
else |
|
|
|
|
addr_inc = 8; |
|
|
|
|
|
|
|
|
|
current_addr = start; |
|
|
|
|
end_addr = start + size; |
|
|
|
|
|
|
|
|
|
while (current_addr < end_addr) { |
|
|
|
|
*((ulong *)current_addr) = 0x00000000; |
|
|
|
|
current_addr += addr_inc; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* TODO: Flush dcache and disable it again |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Enable ecc checking and parity errors |
|
|
|
|
*/ |
|
|
|
|
mtsdram(mem_cfg0, (cfg0_reg & ~SDRAM_CFG0_MEMCHK) | SDRAM_CFG0_MEMCHK_CHK); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Autodetect onboard DDR SDRAM on 440 platforms |
|
|
|
|
* |
|
|
|
@ -130,6 +349,7 @@ void sdram_init(void) |
|
|
|
|
long int initdram(int board_type) |
|
|
|
|
{ |
|
|
|
|
int i; |
|
|
|
|
int tr1_bank1; |
|
|
|
|
|
|
|
|
|
for (i=0; i<N_MB0CF; i++) { |
|
|
|
|
/*
|
|
|
|
@ -164,6 +384,16 @@ long int initdram(int board_type) |
|
|
|
|
|
|
|
|
|
if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) { |
|
|
|
|
/*
|
|
|
|
|
* Optimize TR1 to current hardware environment |
|
|
|
|
*/ |
|
|
|
|
sdram_tr1_set(0x00000000, &tr1_bank1); |
|
|
|
|
mtsdram(mem_tr1, (tr1_bank1 | 0x80800800)); |
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SDRAM_ECC |
|
|
|
|
ecc_init(0, mb0cf[i].size); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* OK, size detected -> all done |
|
|
|
|
*/ |
|
|
|
|
return mb0cf[i].size; |
|
|
|
|