
The primary goal of these changes is to unify some of the low-level SDRAM and ECC initialization code for the PPC4xx processors that use a common DDR2 SDRAM controller.
In particular, in the case of the 405EX[r], it must initialize SDRAM before a primordial stack is available since OCM doesn't exist and the data cache does not work for such a purpose. As a consequence, the ECC (and SDRAM) initialization code must be stack-free.
This change creates such a stack-free ecc_init() routine that should, nonetheless, still be compatiable from a C runtime environment.
In addition, the change cleans-up the Kilauea and Makalu SDRAM initialization code by polling SDRAM0_MCSTAT[MIC} as recommended by the AMCC AN2131 rather than just waiting some arbitrary period of time. Also, the final controller initialization is generalized by ORing in SDRAM_MCOPT2_DCEN_ENBALE rather than just slamming 0x28000000 into the register. This is to make way for a future patch that uses CFG_SDRAM0_* values for boards that use such low-level initialization so they might share this SDRAM init code. Finally, while niether Kilauea nor Makalu have ECC memory, code is added to init.S for each to demonstrate how ecc_init() would be called if it were available as a reference.
Signed-off-by: Grant Erickson gerickson@nuovations.com
--- board/amcc/kilauea/init.S | 53 +++++++++++-- board/amcc/makalu/init.S | 53 +++++++++++-- cpu/ppc4xx/Makefile | 1 + cpu/ppc4xx/ecc.S | 195 +++++++++++++++++++++++++++++++++++++++++++++ cpu/ppc4xx/sdram.c | 47 +---------- 5 files changed, 292 insertions(+), 57 deletions(-)
diff --git a/board/amcc/kilauea/init.S b/board/amcc/kilauea/init.S index 053fe19..7603fcf 100644 --- a/board/amcc/kilauea/init.S +++ b/board/amcc/kilauea/init.S @@ -36,6 +36,10 @@ ori r4,r4,value@l ; \ mtdcr memcfgd,r4 ;
+#if defined(CONFIG_SDRAM_ECC) + .extern ecc_init +#endif /* defined(CONFIG_SDRAM_ECC) */ + .globl ext_bus_cntlr_init ext_bus_cntlr_init: #if !defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SPL) @@ -126,12 +130,19 @@ ext_bus_cntlr_init: /* SDRAM0_MCOPT2 (0X21) Start initialization */ mtsdram_as(SDRAM_MCOPT2, 0x20000000);
- /* Step 5 */ - lis r3,0x1 /* 400000 = wait 100ms */ - mtctr r3 + /* + * Step 5: Poll SDRAM0_MCSTAT[MIC] for assertion to indicate the + * completion of initialization. + */
-pll_wait: - bdnz pll_wait + li r4,SDRAM_MCSTAT + lis r2,SDRAM_MCSTAT_MIC_COMP@h + ori r2,r2,SDRAM_MCSTAT_MIC_COMP@l +0: mtdcr memcfga,r4 + mfdcr r3,memcfgd + clrrwi r3,r3,31 // Clear all bits except MCSTAT[MIC]. + cmpw cr7,r3,r2 // Check if MCSTAT[MIC] = 1. + bne+ cr7,0b // No, not ready yet, keep polling.
/* Step 6 */
@@ -147,8 +158,36 @@ pll_wait: /* SDRAM_RFDC */ mtsdram_as(SDRAM_RFDC, 0x00000209);
- /* Enable memory controller */ - mtsdram_as(SDRAM_MCOPT2, 0x28000000); + /* + * Enable Controller by SDRAM0_MCOPT2[DCEN] = 1: + * + * mcopt2 = mfsdram(SDRAM_MCOPT2) + */ + + li r4,SDRAM_MCOPT2 + mtdcr memcfga,r4 + mfdcr r3,memcfgd + + /* + * mtsdram(SDRAM_MCOPT2, mcopt2 | SDRAM_MCOPT2_DCEN_ENABLE) + */ + + mtdcr memcfga,r4 + oris r3,r3,SDRAM_MCOPT2_DCEN_ENABLE@h + ori r3,r3,SDRAM_MCOPT2_DCEN_ENABLE@l + mtdcr memcfgd,r3 + +#if defined(CONFIG_SDRAM_ECC) + mflr r13 + lis r3,CFG_SDRAM_BASE@h + ori r3,r3,CFG_SDRAM_BASE@l + lis r4,(CFG_MBYTES_SDRAM << 20)@h + ori r4,r4,(CFG_MBYTES_SDRAM << 20)@l + bl ecc_init + mtlr r13 +#endif /* defined(CONFIG_SDRAM_ECC) */ #endif /* #ifndef CONFIG_NAND_U_BOOT */ + + /* SDRAM is now ready for use. Return to the caller. */
blr diff --git a/board/amcc/makalu/init.S b/board/amcc/makalu/init.S index 5e9a5e0..c40d8d1 100644 --- a/board/amcc/makalu/init.S +++ b/board/amcc/makalu/init.S @@ -36,6 +36,10 @@ ori r4,r4,value@l ; \ mtdcr memcfgd,r4 ;
+#if defined(CONFIG_SDRAM_ECC) + .extern ecc_init +#endif /* defined(CONFIG_SDRAM_ECC) */ + .globl ext_bus_cntlr_init ext_bus_cntlr_init:
@@ -121,12 +125,19 @@ ext_bus_cntlr_init: /* SDRAM0_MCOPT2 (0X21) Start initialization */ mtsdram_as(SDRAM_MCOPT2, 0x20000000);
- /* Step 5 */ - lis r3,0x1 /* 400000 = wait 100ms */ - mtctr r3 + /* + * Step 5: Poll SDRAM0_MCSTAT[MIC] for assertion to indicate the + * completion of initialization. + */
-pll_wait: - bdnz pll_wait + li r4,SDRAM_MCSTAT + lis r2,SDRAM_MCSTAT_MIC_COMP@h + ori r2,r2,SDRAM_MCSTAT_MIC_COMP@l +0: mtdcr memcfga,r4 + mfdcr r3,memcfgd + clrrwi r3,r3,31 // Clear all bits except MCSTAT[MIC]. + cmpw cr7,r3,r2 // Check if MCSTAT[MIC] = 1. + bne+ cr7,0b // No, not ready yet, keep polling.
/* Step 6 */
@@ -142,7 +153,35 @@ pll_wait: /* SDRAM_RFDC */ mtsdram_as(SDRAM_RFDC, 0x00000209);
- /* Enable memory controller */ - mtsdram_as(SDRAM_MCOPT2, 0x28000000); + /* + * Enable Controller by SDRAM0_MCOPT2[DCEN] = 1: + * + * mcopt2 = mfsdram(SDRAM_MCOPT2) + */ + + li r4,SDRAM_MCOPT2 + mtdcr memcfga,r4 + mfdcr r3,memcfgd + + /* + * mtsdram(SDRAM_MCOPT2, mcopt2 | SDRAM_MCOPT2_DCEN_ENABLE) + */ + + mtdcr memcfga,r4 + oris r3,r3,SDRAM_MCOPT2_DCEN_ENABLE@h + ori r3,r3,SDRAM_MCOPT2_DCEN_ENABLE@l + mtdcr memcfgd,r3 + +#if defined(CONFIG_SDRAM_ECC) + mflr r13 + lis r3,CFG_SDRAM_BASE@h + ori r3,r3,CFG_SDRAM_BASE@l + lis r4,(CFG_MBYTES_SDRAM << 20)@h + ori r4,r4,(CFG_MBYTES_SDRAM << 20)@l + bl ecc_init + mtlr r13 +#endif /* defined(CONFIG_SDRAM_ECC) */ + + /* SDRAM is now ready for use. Return to the caller. */
blr diff --git a/cpu/ppc4xx/Makefile b/cpu/ppc4xx/Makefile index 178c5c6..f1e7ad2 100644 --- a/cpu/ppc4xx/Makefile +++ b/cpu/ppc4xx/Makefile @@ -31,6 +31,7 @@ START += start.o SOBJS := cache.o SOBJS += dcr.o SOBJS += kgdb.o +SOBJS += ecc.o
COBJS := 40x_spd_sdram.o COBJS += 44x_spd_ddr.o diff --git a/cpu/ppc4xx/ecc.S b/cpu/ppc4xx/ecc.S new file mode 100644 index 0000000..f56d246 --- /dev/null +++ b/cpu/ppc4xx/ecc.S @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2008 Nuovation System Designs, LLC + * Grant Erickson gerickson@nuovations.com + * + * Copyright (c) 2007 DENX Software Engineering, GmbH + * Stefan Roese sr@denx.de + * + * 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 abe 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 + * + * Description: + * This file implements ECC initialization for PowerPC processors + * using the SDRAM DDR2 controller, including the 405EX(r), + * 440SP(E), 460EX and 460GT. + * + * The implementation is in assembler since processors such as + * the 405EX(r) need to initialize their SDRAM controller and ECC + * prior to the availability of a primordial stack since they + * have neither On-chip Memory (OCM) nor can they use the data + * cache for such a use. + */ + +#include <config.h> +#include <ppc4xx.h> + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> + +#if !defined(CFG_SDRAM_ECC_PATTERN) +#define CFG_SDRAM_ECC_PATTERN 0x00000000 +#endif /* !defined(CFG_SDRAM_ECC_PATTERN) */ + + +/* + * void ecc_init() + * + * Description: + * This routine initializes a range of SDRAM ECC memory with known + * data and enabled ECC generation and checking. + * + * Input(s): + * start - A pointer to the start of memory covered by ECC requiring + * initialization. + * size - The size, in bytes, of the memory covered by ECC requiring + * initialization. + * + * Output(s): + * start - A pointer to the start of memory covered by ECC with + * CFG_SDRAM_ECC_PATTERN written to all locations and ECC + * data primed. + * + * Returns: + * N/A + * + */ + .globl ecc_init +ecc_init: +#if defined(CONFIG_SDRAM_ECC) + /* + * volatile ulong * const end = (volatile ulong * const)((ptrdiff_t)start + size) + */ + + add r8,r3,r4 + + /* + * if (start >= end) { + * return; + * } + */ + + cmplw cr7,r3,r8 + bge- cr7,3f + + /* + * Read the current Memory Controller Options 1 (SDRAM0_MCOPT1) + * value: + * + * mcopt1 = mfsdram(SDRAM0_MCOPT1) + */ + + li r0,SDRAM_MCOPT1 + mtdcr memcfga,r0 + mfdcr r9,memcfgd + + /* + * Enable ECC generation without checking or reporting: + * + * mtsdram(SDRAM_MCOPT1, ((mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | + * SDRAM_MCOPT1_MCHK_GEN)); + */ + + mtdcr memcfga,r0 + lis r0,(~SDRAM_MCOPT1_MCHK_MASK)@h + ori r0,r0,(~SDRAM_MCOPT1_MCHK_MASK)@l + and r7,r9,r0 + oris r0,r7,SDRAM_MCOPT1_MCHK_GEN@h + ori r0,r0,SDRAM_MCOPT1_MCHK_GEN@l + mtdcr memcfgd,r0 + +#if defined(CONFIG_440) + /* + * Look at the geometry of SDRAM (data width) to determine whether we + * can skip words when writing: + * + * if ((mcopt1 & DMWD_MASK) != DMWD_32) { + * increment = sizeof (u64); + * } + */ + + lis r0,SDRAM_MCOPT1_DMWD_MASK@h + ori r0,r0,SDRAM_MCOPT1_DMWD_MASK@l + lis r5,SDRAM_MCOPT1_DMWD_32@h + ori r5,r5,SDRAM_MCOPT1_DMWD_32@l + and r9,r9,r0 + cmplw cr7,r9,r5 + beq cr7,0f + li r10,8 +#endif /* defined(CONFIG_440) */ + + /* + * increment = sizeof (u32); + */ + +0: li r10,4 + + /* + * const ulong pattern = CFG_SDRAM_ECC_PATTERN; + */ + + lis r0,CFG_SDRAM_ECC_PATTERN@h + ori r0,r0,CFG_SDRAM_ECC_PATTERN@l + + /* + * volatile ulong * current = start; + */ + + mr r11,r3 + + /* + * while (current < end) { + * *current = pattern; + * + * current = (volatile ulong *)((ptrdiff_t)current + increment); + * } + */ + +1: stw r0,0(r11) + add r11,r11,r10 + cmplw cr7,r8,r11 + bgt+ cr7,1b + + /* + * while (*(volatile ulong *)((ptrdiff_t)current - increment) != pattern); + */ + +2: subf r9,r10,r11 + lwz r9,0(r9) + cmpw cr7,r9,r0 + bne+ cr7,2b + + /* + * Enable ECC generation with checking and no reporting at this + * time: + * + * mtsdram(SDRAM_MCOPT1, (mcopt1 & ~MCHK_MASK) | MCHK_CHK); + */ + + li r0,SDRAM_MCOPT1 + mtdcr memcfga,r0 + oris r0,r7,SDRAM_MCOPT1_MCHK_CHK@h + ori r0,r0,SDRAM_MCOPT1_MCHK_CHK@l + mtdcr memcfgd,r0 + + /* + * ECC is now initialized, return to the caller. + */ +#endif /* defined(CONFIG_SDRAM_ECC) */ + +3: blr + diff --git a/cpu/ppc4xx/sdram.c b/cpu/ppc4xx/sdram.c index 2724d91..66d9ae8 100644 --- a/cpu/ppc4xx/sdram.c +++ b/cpu/ppc4xx/sdram.c @@ -32,6 +32,10 @@ #include <asm/processor.h> #include "sdram.h"
+#if defined(CONFIG_SDRAM_ECC) +extern void ecc_init(volatile ulong * const start, ulong size); +#endif + #ifdef CONFIG_SDRAM_BANK0
#ifndef CONFIG_440 @@ -332,49 +336,6 @@ static void sdram_tr1_set(int ram_address, int* tr1_value) *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 *