summaryrefslogtreecommitdiff
path: root/arch/powerpc/cpu/mpc85xx/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/cpu/mpc85xx/cpu.c')
-rw-r--r--arch/powerpc/cpu/mpc85xx/cpu.c219
1 files changed, 219 insertions, 0 deletions
diff --git a/arch/powerpc/cpu/mpc85xx/cpu.c b/arch/powerpc/cpu/mpc85xx/cpu.c
index 3f80700..fc5d951 100644
--- a/arch/powerpc/cpu/mpc85xx/cpu.c
+++ b/arch/powerpc/cpu/mpc85xx/cpu.c
@@ -34,6 +34,9 @@
#include <asm/io.h>
#include <asm/mmu.h>
#include <asm/fsl_law.h>
+#include <post.h>
+#include <asm/processor.h>
+#include <asm/fsl_ddr_sdram.h>
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