u-boot/arch/powerpc/cpu/ppc4xx/sdram.c
Simon Glass 52c411805c board_f: Drop board_type parameter from initdram()
It looks like only cm5200 and tqm8xx use this feature, so we don't really
need it in generic code. Drop it and have the users access gd->board_type
directly.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Stefan Roese <sr@denx.de>
2017-04-05 13:58:44 -04:00

452 lines
11 KiB
C

/*
* (C) Copyright 2005-2007
* 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
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/ppc4xx.h>
#include <asm/processor.h>
#include "sdram.h"
#include "ecc.h"
#ifdef CONFIG_SDRAM_BANK0
#ifndef CONFIG_440
#ifndef CONFIG_SYS_SDRAM_TABLE
sdram_conf_t mb0cf[] = {
{(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[] = CONFIG_SYS_SDRAM_TABLE;
#endif
#define N_MB0CF (ARRAY_SIZE(mb0cf))
#ifdef CONFIG_SYS_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 /* CONFIG_SYS_SDRAM_CASL */
static ulong compute_sdtr1(ulong speed)
{
#ifdef CONFIG_SYS_SDRAM_CASL
ulong tmp;
ulong sdtr1 = 0;
/* CASL */
if (CONFIG_SYS_SDRAM_CASL < 2)
sdtr1 |= (1 << SDRAM0_TR_CASL);
else
if (CONFIG_SYS_SDRAM_CASL > 4)
sdtr1 |= (3 << SDRAM0_TR_CASL);
else
sdtr1 |= ((CONFIG_SYS_SDRAM_CASL-1) << SDRAM0_TR_CASL);
/* PTA */
tmp = ns2clks(CONFIG_SYS_SDRAM_PTA);
if ((tmp >= 2) && (tmp <= 4))
sdtr1 |= ((tmp-1) << SDRAM0_TR_PTA);
else
sdtr1 |= ((4-1) << SDRAM0_TR_PTA);
/* CTP */
tmp = ns2clks(CONFIG_SYS_SDRAM_CTP);
if ((tmp >= 2) && (tmp <= 4))
sdtr1 |= ((tmp-1) << SDRAM0_TR_CTP);
else
sdtr1 |= ((4-1) << SDRAM0_TR_CTP);
/* LDF */
tmp = ns2clks(CONFIG_SYS_SDRAM_LDF);
if ((tmp >= 2) && (tmp <= 4))
sdtr1 |= ((tmp-1) << SDRAM0_TR_LDF);
else
sdtr1 |= ((2-1) << SDRAM0_TR_LDF);
/* RFTA */
tmp = ns2clks(CONFIG_SYS_SDRAM_RFTA);
if ((tmp >= 4) && (tmp <= 10))
sdtr1 |= ((tmp-4) << SDRAM0_TR_RFTA);
else
sdtr1 |= ((10-4) << SDRAM0_TR_RFTA);
/* RCD */
tmp = ns2clks(CONFIG_SYS_SDRAM_RCD);
if ((tmp >= 2) && (tmp <= 4))
sdtr1 |= ((tmp-1) << SDRAM0_TR_RCD);
else
sdtr1 |= ((4-1) << SDRAM0_TR_RCD);
return sdtr1;
#else /* CONFIG_SYS_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 /* CONFIG_SYS_SDRAM_CASL */
}
/* refresh is expressed in ms */
static ulong compute_rtr(ulong speed, ulong rows, ulong refresh)
{
#ifdef CONFIG_SYS_SDRAM_CASL
ulong tmp;
tmp = ((refresh*1000*1000) / (1 << rows)) * (speed / 1000);
tmp /= 1000000;
return ((tmp & 0x00003FF8) << 16);
#else /* CONFIG_SYS_SDRAM_CASL */
if (speed > 100000000) {
/*
* 133 MHz SDRAM
*/
return 0x07f00000;
} else {
/*
* default: 100 MHz SDRAM
*/
return 0x05f00000;
}
#endif /* CONFIG_SYS_SDRAM_CASL */
}
/*
* Autodetect onboard SDRAM on 405 platforms
*/
phys_size_t initdram(void)
{
ulong speed;
ulong sdtr1;
int i;
/*
* 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++) {
/*
* Disable memory controller.
*/
mtsdram(SDRAM0_CFG, 0x00000000);
/*
* Set MB0CF for bank 0.
*/
mtsdram(SDRAM0_B0CR, mb0cf[i].reg);
mtsdram(SDRAM0_TR, sdtr1);
mtsdram(SDRAM0_RTR, compute_rtr(speed, mb0cf[i].rows, 64));
udelay(200);
/*
* Set memory controller options reg, MCOPT1.
* Set DC_EN to '1' and BRD_PRF to '01' for 16 byte PLB Burst
* read/prefetch.
*/
mtsdram(SDRAM0_CFG, 0x80800000);
udelay(10000);
if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) {
phys_size_t size = mb0cf[i].size;
/*
* OK, size detected. Enable second bank if
* defined (assumes same type as bank 0)
*/
#ifdef CONFIG_SDRAM_BANK1
mtsdram(SDRAM0_CFG, 0x00000000);
mtsdram(SDRAM0_B1CR, mb0cf[i].size | mb0cf[i].reg);
mtsdram(SDRAM0_CFG, 0x80800000);
udelay(10000);
/*
* Check if 2nd bank is really available.
* If the size not equal to the size of the first
* bank, then disable the 2nd bank completely.
*/
if (get_ram_size((long *)mb0cf[i].size, mb0cf[i].size) !=
mb0cf[i].size) {
mtsdram(SDRAM0_B1CR, 0);
mtsdram(SDRAM0_CFG, 0);
} else {
/*
* We have two identical banks, so the size
* is twice the bank size
*/
size = 2 * size;
}
#endif
/*
* OK, size detected -> all done
*/
return size;
}
}
return 0;
}
#else /* CONFIG_440 */
/*
* Define some default values. Those can be overwritten in the
* board config file.
*/
#ifndef CONFIG_SYS_SDRAM_TABLE
sdram_conf_t mb0cf[] = {
{(256 << 20), 13, 0x000C4001}, /* 256MB mode 3, 13x10(4) */
{(128 << 20), 13, 0x000A4001}, /* 128MB mode 3, 13x10(4) */
{(64 << 20), 12, 0x00082001} /* 64MB mode 2, 12x9(4) */
};
#else
sdram_conf_t mb0cf[] = CONFIG_SYS_SDRAM_TABLE;
#endif
#ifndef CONFIG_SYS_SDRAM0_TR0
#define CONFIG_SYS_SDRAM0_TR0 0x41094012
#endif
#ifndef CONFIG_SYS_SDRAM0_WDDCTR
#define CONFIG_SYS_SDRAM0_WDDCTR 0x00000000 /* wrcp=0 dcd=0 */
#endif
#ifndef CONFIG_SYS_SDRAM0_RTR
#define CONFIG_SYS_SDRAM0_RTR 0x04100000 /* 7.8us @ 133MHz PLB */
#endif
#ifndef CONFIG_SYS_SDRAM0_CFG0
#define CONFIG_SYS_SDRAM0_CFG0 0x82000000 /* DCEN=1, PMUD=0, 64-bit */
#endif
#define N_MB0CF (ARRAY_SIZE(mb0cf))
#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(SDRAM0_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;
}
/*
* Autodetect onboard DDR SDRAM on 440 platforms
*
* NOTE: Some of the hardcoded values are hardware dependant,
* so this should be extended for other future boards
* using this routine!
*/
phys_size_t initdram(void)
{
int i;
int tr1_bank1;
#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || \
defined(CONFIG_440GR) || defined(CONFIG_440SP)
/*
* Soft-reset SDRAM controller.
*/
mtsdr(SDR0_SRST, SDR0_SRST_DMC);
mtsdr(SDR0_SRST, 0x00000000);
#endif
for (i=0; i<N_MB0CF; i++) {
/*
* Disable memory controller.
*/
mtsdram(SDRAM0_CFG0, 0x00000000);
/*
* Setup some default
*/
mtsdram(SDRAM0_UABBA, 0x00000000); /* ubba=0 (default) */
mtsdram(SDRAM0_SLIO, 0x00000000); /* rdre=0 wrre=0 rarw=0 */
mtsdram(SDRAM0_DEVOPT, 0x00000000); /* dll=0 ds=0 (normal) */
mtsdram(SDRAM0_WDDCTR, CONFIG_SYS_SDRAM0_WDDCTR);
mtsdram(SDRAM0_CLKTR, 0x40000000); /* clkp=1 (90 deg wr) dcdt=0 */
/*
* Following for CAS Latency = 2.5 @ 133 MHz PLB
*/
mtsdram(SDRAM0_B0CR, mb0cf[i].reg);
mtsdram(SDRAM0_TR0, CONFIG_SYS_SDRAM0_TR0);
mtsdram(SDRAM0_TR1, 0x80800800); /* SS=T2 SL=STAGE 3 CD=1 CT=0x00*/
mtsdram(SDRAM0_RTR, CONFIG_SYS_SDRAM0_RTR);
mtsdram(SDRAM0_CFG1, 0x00000000); /* Self-refresh exit, disable PM*/
udelay(400); /* Delay 200 usecs (min) */
/*
* Enable the controller, then wait for DCEN to complete
*/
mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0);
udelay(10000);
if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) {
phys_size_t size = mb0cf[i].size;
/*
* Optimize TR1 to current hardware environment
*/
sdram_tr1_set(0x00000000, &tr1_bank1);
mtsdram(SDRAM0_TR1, (tr1_bank1 | 0x80800800));
/*
* OK, size detected. Enable second bank if
* defined (assumes same type as bank 0)
*/
#ifdef CONFIG_SDRAM_BANK1
mtsdram(SDRAM0_CFG0, 0);
mtsdram(SDRAM0_B1CR, mb0cf[i].size | mb0cf[i].reg);
mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0);
udelay(10000);
/*
* Check if 2nd bank is really available.
* If the size not equal to the size of the first
* bank, then disable the 2nd bank completely.
*/
if (get_ram_size((long *)mb0cf[i].size, mb0cf[i].size)
!= mb0cf[i].size) {
mtsdram(SDRAM0_CFG0, 0);
mtsdram(SDRAM0_B1CR, 0);
mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0);
udelay(10000);
} else {
/*
* We have two identical banks, so the size
* is twice the bank size
*/
size = 2 * size;
}
#endif
#ifdef CONFIG_SDRAM_ECC
ecc_init(0, size);
#endif
/*
* OK, size detected -> all done
*/
return size;
}
}
return 0; /* nothing found ! */
}
#endif /* CONFIG_440 */
#endif /* CONFIG_SDRAM_BANK0 */