diff --git a/arch/powerpc/cpu/mpc85xx/cpu.c b/arch/powerpc/cpu/mpc85xx/cpu.c index 3f8070071..fc5d951e9 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu.c +++ b/arch/powerpc/cpu/mpc85xx/cpu.c @@ -34,6 +34,9 @@ #include #include #include +#include +#include +#include DECLARE_GLOBAL_DATA_PTR; @@ -282,3 +285,219 @@ void mpc85xx_reginfo(void) print_laws(); print_lbc_regs(); } + +#if CONFIG_POST & CONFIG_SYS_POST_MEMORY + +/* Board-specific functions defined in each board's ddr.c */ +void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, + unsigned int ctrl_num); +void read_tlbcam_entry(int idx, u32 *valid, u32 *tsize, unsigned long *epn, + phys_addr_t *rpn); +unsigned int + setup_ddr_tlbs_phys(phys_addr_t p_addr, unsigned int memsize_in_meg); + +static void dump_spd_ddr_reg(void) +{ + int i, j, k, m; + u8 *p_8; + u32 *p_32; + ccsr_ddr_t *ddr[CONFIG_NUM_DDR_CONTROLLERS]; + generic_spd_eeprom_t + spd[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR]; + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + fsl_ddr_get_spd(spd[i], i); + + puts("SPD data of all dimms (zero vaule is omitted)...\n"); + puts("Byte (hex) "); + k = 1; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) + printf("Dimm%d ", k++); + } + puts("\n"); + for (k = 0; k < sizeof(generic_spd_eeprom_t); k++) { + m = 0; + printf("%3d (0x%02x) ", k, k); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + p_8 = (u8 *) &spd[i][j]; + if (p_8[k]) { + printf("0x%02x ", p_8[k]); + m++; + } else + puts(" "); + } + } + if (m) + puts("\n"); + else + puts("\r"); + } + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + switch (i) { + case 0: + ddr[i] = (void *)CONFIG_SYS_MPC85xx_DDR_ADDR; + break; +#ifdef CONFIG_SYS_MPC85xx_DDR2_ADDR + case 1: + ddr[i] = (void *)CONFIG_SYS_MPC85xx_DDR2_ADDR; + break; +#endif + default: + printf("%s unexpected controller number = %u\n", + __func__, i); + return; + } + } + printf("DDR registers dump for all controllers " + "(zero vaule is omitted)...\n"); + puts("Offset (hex) "); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + printf(" Base + 0x%04x", (u32)ddr[i] & 0xFFFF); + puts("\n"); + for (k = 0; k < sizeof(ccsr_ddr_t)/4; k++) { + m = 0; + printf("%6d (0x%04x)", k * 4, k * 4); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + p_32 = (u32 *) ddr[i]; + if (p_32[k]) { + printf(" 0x%08x", p_32[k]); + m++; + } else + puts(" "); + } + if (m) + puts("\n"); + else + puts("\r"); + } + puts("\n"); +} + +/* invalid the TLBs for DDR and setup new ones to cover p_addr */ +static int reset_tlb(phys_addr_t p_addr, u32 size, phys_addr_t *phys_offset) +{ + u32 vstart = CONFIG_SYS_DDR_SDRAM_BASE; + unsigned long epn; + u32 tsize, valid, ptr; + phys_addr_t rpn = 0; + int ddr_esel; + + ptr = vstart; + + while (ptr < (vstart + size)) { + ddr_esel = find_tlb_idx((void *)ptr, 1); + if (ddr_esel != -1) { + read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn); + disable_tlb(ddr_esel); + } + ptr += TSIZE_TO_BYTES(tsize); + } + + /* Setup new tlb to cover the physical address */ + setup_ddr_tlbs_phys(p_addr, size>>20); + + ptr = vstart; + ddr_esel = find_tlb_idx((void *)ptr, 1); + if (ddr_esel != -1) { + read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, phys_offset); + } else { + printf("TLB error in function %s\n", __func__); + return -1; + } + + return 0; +} + +/* + * slide the testing window up to test another area + * for 32_bit system, the maximum testable memory is limited to + * CONFIG_MAX_MEM_MAPPED + */ +int arch_memory_test_advance(u32 *vstart, u32 *size, phys_addr_t *phys_offset) +{ + phys_addr_t test_cap, p_addr; + phys_size_t p_size = min(gd->ram_size, CONFIG_MAX_MEM_MAPPED); + +#if !defined(CONFIG_PHYS_64BIT) || \ + !defined(CONFIG_SYS_INIT_RAM_ADDR_PHYS) || \ + (CONFIG_SYS_INIT_RAM_ADDR_PHYS < 0x100000000ull) + test_cap = p_size; +#else + test_cap = gd->ram_size; +#endif + p_addr = (*vstart) + (*size) + (*phys_offset); + if (p_addr < test_cap - 1) { + p_size = min(test_cap - p_addr, CONFIG_MAX_MEM_MAPPED); + if (reset_tlb(p_addr, p_size, phys_offset) == -1) + return -1; + *vstart = CONFIG_SYS_DDR_SDRAM_BASE; + *size = (u32) p_size; + printf("Testing 0x%08llx - 0x%08llx\n", + (u64)(*vstart) + (*phys_offset), + (u64)(*vstart) + (*phys_offset) + (*size) - 1); + } else + return 1; + + return 0; +} + +/* initialization for testing area */ +int arch_memory_test_prepare(u32 *vstart, u32 *size, phys_addr_t *phys_offset) +{ + phys_size_t p_size = min(gd->ram_size, CONFIG_MAX_MEM_MAPPED); + + *vstart = CONFIG_SYS_DDR_SDRAM_BASE; + *size = (u32) p_size; /* CONFIG_MAX_MEM_MAPPED < 4G */ + *phys_offset = 0; + +#if !defined(CONFIG_PHYS_64BIT) || \ + !defined(CONFIG_SYS_INIT_RAM_ADDR_PHYS) || \ + (CONFIG_SYS_INIT_RAM_ADDR_PHYS < 0x100000000ull) + if (gd->ram_size > CONFIG_MAX_MEM_MAPPED) { + puts("Cannot test more than "); + print_size(CONFIG_MAX_MEM_MAPPED, + " without proper 36BIT support.\n"); + } +#endif + printf("Testing 0x%08llx - 0x%08llx\n", + (u64)(*vstart) + (*phys_offset), + (u64)(*vstart) + (*phys_offset) + (*size) - 1); + + return 0; +} + +/* invalid TLBs for DDR and remap as normal after testing */ +int arch_memory_test_cleanup(u32 *vstart, u32 *size, phys_addr_t *phys_offset) +{ + unsigned long epn; + u32 tsize, valid, ptr; + phys_addr_t rpn = 0; + int ddr_esel; + + /* disable the TLBs for this testing */ + ptr = *vstart; + + while (ptr < (*vstart) + (*size)) { + ddr_esel = find_tlb_idx((void *)ptr, 1); + if (ddr_esel != -1) { + read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn); + disable_tlb(ddr_esel); + } + ptr += TSIZE_TO_BYTES(tsize); + } + + puts("Remap DDR "); + setup_ddr_tlbs(gd->ram_size>>20); + puts("\n"); + + return 0; +} + +void arch_memory_failure_handle(void) +{ + dump_spd_ddr_reg(); +} +#endif diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr index e108a0d50..1657ef617 100644 --- a/doc/README.fsl-ddr +++ b/doc/README.fsl-ddr @@ -78,6 +78,20 @@ If the DDR controller supports address hashing, it can be enabled by hwconfig. Syntax is: hwconfig=fsl_ddr:addr_hash=true + +Memory testing options for mpc85xx +================================== +1. Memory test can be done once U-boot prompt comes up using mtest, or +2. Memory test can be done with Power-On-Self-Test function, activated at + compile time. + + In order to enable the POST memory test, CONFIG_POST needs to be + defined in board configuraiton header file. By default, POST memory test + performs a fast test. A slow test can be enabled by changing the flag at + compiling time. To test memory bigger than 2GB, 36BIT support is needed. + Memory is tested within a 2GB window. TLBs are used to map the virtual 2GB + window to physical address so that all physical memory can be tested. + Combination of hwconfig ======================= Hwconfig can be combined with multiple parameters, for example, on a supported