[U-Boot-Users] [PATCH v2] PPC405EX(r) ECC and SDRAM Initialization Clean-ups

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 *

--- 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 *

In message 1209401636-9846-2-git-send-email-gerickson@nuovations.com you wrote:
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(-)
There are a couple of problems with your posting:
- there is no signed-off-by line - there is no explanation what you're actually trying to add or to fix. - there are coding style violations: C++ comments, trailing white space, ... - the code contains way too many empty lines / vertical white space. - even in pseudo code, the Coding style requirements apply; i. e. instead of + /* + * if (start >= end) { + * return; + * } + */ please write + /* + * if (start >= end) + * return; + */ etc.
Best regards,
Wolfgang Denk

In message 1209401636-9846-1-git-send-email-gerickson@nuovations.com you wrote:
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.
Stefan already asked this... I would also like to understand why the data cache cannot be used for initial RAM as we do on so many other systems?
I hesitate to throw away good C code in favour of hard to read, hard to maintain assembly, especially if this also breaks with some of the U-Boot design principles.
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(-)
There are coding style violations: C++ comments, trailing white space, indentation not consequently by TABs.
Best regards,
Wolfgang Denk

On 4/28/08 2:27 PM, Wolfgang Denk wrote:
In message 1209401636-9846-1-git-send-email-gerickson@nuovations.com you wrote:
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.
Stefan already asked this... I would also like to understand why the data cache cannot be used for initial RAM as we do on so many other systems?
Agreed. The changes were based on the comments in the Kilauea and Makalu board ports indicating that this had been attempted--twice--and didn't work.
I am escalating with AMCC to find out if this is a processor errata, board issue or just a programming issue that needs to be investigated further.
I hesitate to throw away good C code in favour of hard to read, hard to maintain assembly, especially if this also breaks with some of the U-Boot design principles.
Again, agreed wholeheartedly though I have to remark that I made a particular effort to make the assembly as readable and as generalized as possible.
Regards,
Grant

On Mon, 2008-04-28 at 14:47 -0700, Grant Erickson wrote:
On 4/28/08 2:27 PM, Wolfgang Denk wrote:
In message 1209401636-9846-1-git-send-email-gerickson@nuovations.com you wrote:
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.
Stefan already asked this... I would also like to understand why the data cache cannot be used for initial RAM as we do on so many other systems?
Agreed. The changes were based on the comments in the Kilauea and Makalu board ports indicating that this had been attempted--twice--and didn't work.
I am escalating with AMCC to find out if this is a processor errata, board issue or just a programming issue that needs to be investigated further.
The cache trick works fine on 405CR/405GP. Is the cache redesigned for 405EX. Why would they still call it a 405 if the core was redesigned?

On Tuesday 29 April 2008, kenneth johansson wrote:
Stefan already asked this... I would also like to understand why the data cache cannot be used for initial RAM as we do on so many other systems?
Agreed. The changes were based on the comments in the Kilauea and Makalu board ports indicating that this had been attempted--twice--and didn't work.
I am escalating with AMCC to find out if this is a processor errata, board issue or just a programming issue that needs to be investigated further.
The cache trick works fine on 405CR/405GP. Is the cache redesigned for 405EX. Why would they still call it a 405 if the core was redesigned?
I already sent an update to Grant privately on this. Here again:
The main problem is that the board crashes with an exception (0x200: Data machine check) when init RAM in dcache is used. This happens upon calling trap_init() in board_init_r(). The exception must be pending and is "activated" upon the trap_init() call. Either Grant (or somebody else?) will look into this, or I will try to look into is (again) in a few days.
Thanks.
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

On 4/29/08 2:42 AM, Stefan Roese wrote:
On Tuesday 29 April 2008, kenneth johansson wrote:
Stefan already asked this... I would also like to understand why the data cache cannot be used for initial RAM as we do on so many other systems?
Agreed. The changes were based on the comments in the Kilauea and Makalu board ports indicating that this had been attempted--twice--and didn't work.
I am escalating with AMCC to find out if this is a processor errata, board issue or just a programming issue that needs to be investigated further.
The cache trick works fine on 405CR/405GP. Is the cache redesigned for 405EX. Why would they still call it a 405 if the core was redesigned?
I already sent an update to Grant privately on this. Here again:
The main problem is that the board crashes with an exception (0x200: Data machine check) when init RAM in dcache is used. This happens upon calling trap_init() in board_init_r(). The exception must be pending and is "activated" upon the trap_init() call. Either Grant (or somebody else?) will look into this, or I will try to look into is (again) in a few days.
Thanks.
Best regards, Stefan
For those following this thread, here are the result of my investigations today:
When using the Haleakala board and configuring include/configs/kilauea.h as follows:
#define CFG_SDRAM_BASE 0x00000000 #define CFG_INIT_DCACHE_CS 3 #define CFG_INIT_RAM_ADDR (CFG_SDRAM_BASE + (1 << 30))
I find the following results while tracking the various exception-related registers:
1) At _start + 0:
MSR : 0x0000 0000 ESR (0x3D4) : 0x0000 0000 DEAR (0x3D5) : 0x0000 0000 SRR0 (0x01A) : 0x0000 0700 SRR1 (0x01B) : 0x0000 0000 SRR2 (0x3DE) : 0xFFFA 8678 (NfsStart + 0x2c) SRR3 (0x3DF) : 0x0000 0000 MCSR (0x23C) : 0x0000 0000 MCAR (0x23D) : 0x0000 0000 MCSRR0 (0x23A): 0x0000 0000 MCSRR1 (0x23B): 0x0000 0000
EBC0_BEAR : 0x0000 0000 EBC0_BESR : 0x0000 0000
2) After both invalidate_icache() and invalidate_dcache() have run:
<same>
3) After a NOP ext_bus_cntlr_init() has run:
<same>
4) After PBxAP and PBxCR have been set-up for the desired EBC region:
<same>
5) After the data cacheability has been set for this range:
MSR : 0x0000 0000 ESR (0x3D4) : 0x0000 0000 DEAR (0x3D5) : 0x0000 0000 SRR0 (0x01A) : 0x0000 0700 SRR1 (0x01B) : 0x0000 0000 SRR2 (0x3DE) : 0xFFFA 8678 (NfsStart + 0x2c) SRR3 (0x3DF) : 0x0000 0000 MCSR (0x23C) : 0x0000 0000 MCAR (0x23D) : 0x0000 0000 MCSRR0 (0x23A): 0x0000 0000 MCSRR1 (0x23B): 0x0000 0000
EBC0_BEAR : 0x0000 0000 * EBC0_BESR : 0x4000 0000 PERR=1
5) Immediately after the following instruction runs:
lis r1,CFG_INIT_RAM_ADDR@h
MSR : 0x0000 0000 ESR (0x3D4) : 0x0000 0000 DEAR (0x3D5) : 0x0000 0000 SRR0 (0x01A) : 0x0000 0700 SRR1 (0x01B) : 0x0000 0000 SRR2 (0x3DE) : 0xFFFA 8678 (NfsStart + 0x2c) SRR3 (0x3DF) : 0x0000 0000 * MCSR (0x23C) : 0xA000 0000 MCS = 1, DPLBE = 1 MCAR (0x23D) : 0x0000 0000 MCSRR0 (0x23A): 0x0000 0000 MCSRR1 (0x23B): 0x0000 0000
EBC0_BEAR : 0x0000 0000 EBC0_BESR : 0x4000 0000 PERR=1
However, the overall operation does appear to be working in terms of priming the primordial stack with known values:
(gdb) info registers r2 r2 0x40000fc4
(gdb) print /x *$r2 $1 = 0xdeaddead
(gdb) x /64xw 0x40000FC0 0x40000fc0: 0x00000000 0xdeaddead 0xdeaddead 0xdeaddead 0x40000fd0: 0xdeaddead 0xdeaddead 0xdeaddead 0xdeaddead 0x40000fe0: 0xdeaddead 0xdeaddead 0xdeaddead 0xdeaddead 0x40000ff0: 0xdeaddead 0xdeaddead 0xdeaddead 0xdeaddead 0x40001000: 0x00000000 0x00000000 0x00000000 0x00000000 0x40001010: 0x00000000 0x00000000 0x00000000 0x00000000 0x40001020: 0x00000000 0x00000000 0x00000000 0x00000000 0x40001030: 0x00000000 0x00000000 0x00000000 0x00000000 0x40001040: 0x00000000 0x00000000 0x00000000 0x00000000 0x40001050: 0x00000000 0x00000000 0x00000000 0x00000000 0x40001060: 0x00000000 0x00000000 0x00000000 0x00000000 0x40001070: 0x00000000 0x00000000 0x00000000 0x00000000 0x40001080: 0x00000000 0x00000000 0x00000000 0x00000000 0x40001090: 0x00000000 0x00000000 0x00000000 0x00000000 0x400010a0: 0x00000000 0x00000000 0x00000000 0x00000000 0x400010b0: 0x00000000 0x00000000 0x00000000 0x00000000
Other Experiments Tried:
Changing:
#define CFG_INIT_DCACHE_CS 3
to 4, 5, 6, or 7 doesn't seem to make any difference except I then also seem to get BOTH IPLBE=1 and DPLBE=1 in MCSR for 4, 5, 6 or 7.
While this seems to work OK on older 405 variants, is there something new or different about the PLB to OPB to EBC bridges in the 405EX[r] relative to those older 405 variants that cause this CFG_INIT_DCACHE_CS primordial stack trick to raise an exception where the others before it did not?
Regards,
Grant
participants (4)
-
Grant Erickson
-
kenneth johansson
-
Stefan Roese
-
Wolfgang Denk