summaryrefslogtreecommitdiffstats
path: root/cpu
diff options
context:
space:
mode:
authorStefan Roese <sr@denx.de>2006-03-17 10:28:24 +0100
committerStefan Roese <sr@denx.de>2006-03-31 14:32:07 +0200
commit62534beb2fdd67490c3723f22b8982e7d64fc104 (patch)
tree3843bdce63bfeb6b9df290121b2650533397ed7f /cpu
parent05d8dce9d07cf4073ea15fbc448c1ce22b6baf0f (diff)
downloadbarebox-62534beb2fdd67490c3723f22b8982e7d64fc104.tar.gz
barebox-62534beb2fdd67490c3723f22b8982e7d64fc104.tar.xz
Updates to common PPC4xx onboard (DDR)SDRAM init code (405 and 440)
405 SDRAM: - The SDRAM parameters can now be defined in the board config file and the 405 SDRAM controller values will be calculated upon bootup (see PPChameleonEVB). When those settings are not defined in the board config file, the register setup will be as it is now, so this implementation should not break any current design using this code. Thanks to Andrea Marson from DAVE for this patch. 440 DDR: - Added function sdram_tr1_set to auto calculate the TR1 value for the DDR. - Added ECC support (see p3p440). Patch by Stefan Roese, 17 Mar 2006
Diffstat (limited to 'cpu')
-rw-r--r--cpu/ppc4xx/sdram.c298
-rw-r--r--cpu/ppc4xx/sdram.h78
2 files changed, 342 insertions, 34 deletions
diff --git a/cpu/ppc4xx/sdram.c b/cpu/ppc4xx/sdram.c
index e9548cdcf3..c5ab01738c 100644
--- a/cpu/ppc4xx/sdram.c
+++ b/cpu/ppc4xx/sdram.c
@@ -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;
diff --git a/cpu/ppc4xx/sdram.h b/cpu/ppc4xx/sdram.h
new file mode 100644
index 0000000000..62b5442f3b
--- /dev/null
+++ b/cpu/ppc4xx/sdram.h
@@ -0,0 +1,78 @@
+/*
+ * (C) Copyright 2006
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * (C) Copyright 2006
+ * DAVE Srl <www.dave-tech.it>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _SDRAM_H_
+#define _SDRAM_H_
+
+#include <config.h>
+
+#define mtsdram0(reg, data) mtdcr(memcfga,reg);mtdcr(memcfgd,data)
+
+#define ONE_BILLION 1000000000
+
+struct sdram_conf_s {
+ unsigned long size;
+ int rows;
+ unsigned long reg;
+};
+
+typedef struct sdram_conf_s sdram_conf_t;
+
+/* Bitfields offsets */
+#define SDRAM0_TR_CASL (31 - 8)
+#define SDRAM0_TR_PTA (31 - 13)
+#define SDRAM0_TR_CTP (31 - 15)
+#define SDRAM0_TR_LDF (31 - 17)
+#define SDRAM0_TR_RFTA (31 - 29)
+#define SDRAM0_TR_RCD (31 - 31)
+
+#ifdef CFG_SDRAM_CL
+/* SDRAM timings [ns] according to AMCC/IBM names (see SDRAM_faq.doc) */
+#define CFG_SDRAM_CASL CFG_SDRAM_CL
+#define CFG_SDRAM_PTA CFG_SDRAM_tRP
+#define CFG_SDRAM_CTP (CFG_SDRAM_tRC - CFG_SDRAM_tRCD - CFG_SDRAM_tRP)
+#define CFG_SDRAM_LDF 0
+#ifdef CFG_SDRAM_tRFC
+#define CFG_SDRAM_RFTA CFG_SDRAM_tRFC
+#else
+#define CFG_SDRAM_RFTA CFG_SDRAM_tRC
+#endif
+#define CFG_SDRAM_RCD CFG_SDRAM_tRCD
+#endif /* #ifdef CFG_SDRAM_CL */
+
+/*
+ * Some defines for the 440 DDR controller
+ */
+#define SDRAM_CFG0_DC_EN 0x80000000 /* SDRAM Controller Enable */
+#define SDRAM_CFG0_MEMCHK 0x30000000 /* Memory data error checking mask*/
+#define SDRAM_CFG0_MEMCHK_NON 0x00000000 /* No ECC generation */
+#define SDRAM_CFG0_MEMCHK_GEN 0x20000000 /* ECC generation */
+#define SDRAM_CFG0_MEMCHK_CHK 0x30000000 /* ECC generation and checking */
+#define SDRAM_CFG0_DRAMWDTH 0x02000000 /* DRAM width mask */
+#define SDRAM_CFG0_DRAMWDTH_32 0x00000000 /* 32 bits */
+#define SDRAM_CFG0_DRAMWDTH_64 0x02000000 /* 64 bits */
+
+#endif