1 /* 2 * (C) Copyright 2010 3 * Eastman Kodak Company, <www.kodak.com> 4 * Michael Zaidman, <michael.zaidman@kodak.com> 5 * 6 * The code is based on the cpu/mpc83xx/ecc.c written by 7 * Dave Liu <daveliu@freescale.com> 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include <common.h> 13 #include <mpc83xx.h> 14 #include <watchdog.h> 15 #include <asm/io.h> 16 #include <post.h> 17 18 #if CONFIG_POST & CONFIG_SYS_POST_ECC 19 /* 20 * We use the RAW I/O accessors where possible in order to 21 * achieve performance goal, since the test's execution time 22 * affects the board start up time. 23 */ 24 static inline void ecc_clear(ddr83xx_t *ddr) 25 { 26 /* Clear capture registers */ 27 __raw_writel(0, &ddr->capture_address); 28 __raw_writel(0, &ddr->capture_data_hi); 29 __raw_writel(0, &ddr->capture_data_lo); 30 __raw_writel(0, &ddr->capture_ecc); 31 __raw_writel(0, &ddr->capture_attributes); 32 33 /* Clear SBEC and set SBET to 1 */ 34 out_be32(&ddr->err_sbe, 1 << ECC_ERROR_MAN_SBET_SHIFT); 35 36 /* Clear Error Detect register */ 37 out_be32(&ddr->err_detect, ECC_ERROR_DETECT_MME |\ 38 ECC_ERROR_DETECT_MBE |\ 39 ECC_ERROR_DETECT_SBE |\ 40 ECC_ERROR_DETECT_MSE); 41 42 isync(); 43 } 44 45 int ecc_post_test(int flags) 46 { 47 int ret = 0; 48 int int_state; 49 int errbit; 50 u32 pattern[2], writeback[2], retval[2]; 51 ddr83xx_t *ddr = &((immap_t *)CONFIG_SYS_IMMR)->ddr; 52 volatile u64 *addr = (u64 *)CONFIG_SYS_POST_ECC_START_ADDR; 53 54 /* The pattern is written into memory to generate error */ 55 pattern[0] = 0xfedcba98UL; 56 pattern[1] = 0x76543210UL; 57 58 /* After injecting error, re-initialize the memory with the value */ 59 writeback[0] = ~pattern[0]; 60 writeback[1] = ~pattern[1]; 61 62 /* Check if ECC is enabled */ 63 if (__raw_readl(&ddr->err_disable) & ECC_ERROR_ENABLE) { 64 debug("DDR's ECC is not enabled, skipping the ECC POST.\n"); 65 return 0; 66 } 67 68 int_state = disable_interrupts(); 69 icache_enable(); 70 71 #ifdef CONFIG_DDR_32BIT 72 /* It seems like no one really uses the CONFIG_DDR_32BIT mode */ 73 #error "Add ECC POST support for CONFIG_DDR_32BIT here!" 74 #else 75 for (addr = (u64*)CONFIG_SYS_POST_ECC_START_ADDR, errbit=0; 76 addr < (u64*)CONFIG_SYS_POST_ECC_STOP_ADDR; addr++, errbit++ ) { 77 78 WATCHDOG_RESET(); 79 80 ecc_clear(ddr); 81 82 /* Enable error injection */ 83 setbits_be32(&ddr->ecc_err_inject, ECC_ERR_INJECT_EIEN); 84 sync(); 85 isync(); 86 87 /* Set bit to be injected */ 88 if (errbit < 32) { 89 __raw_writel(1 << errbit, &ddr->data_err_inject_lo); 90 __raw_writel(0, &ddr->data_err_inject_hi); 91 } else { 92 __raw_writel(0, &ddr->data_err_inject_lo); 93 __raw_writel(1<<(errbit-32), &ddr->data_err_inject_hi); 94 } 95 sync(); 96 isync(); 97 98 /* Write memory location injecting SBE */ 99 ppcDWstore((u32*)addr, pattern); 100 sync(); 101 102 /* Disable error injection */ 103 clrbits_be32(&ddr->ecc_err_inject, ECC_ERR_INJECT_EIEN); 104 sync(); 105 isync(); 106 107 /* Data read should generate SBE */ 108 ppcDWload((u32*)addr, retval); 109 sync(); 110 111 if (!(__raw_readl(&ddr->err_detect) & ECC_ERROR_DETECT_SBE) || 112 (__raw_readl(&ddr->data_err_inject_hi) != 113 (__raw_readl(&ddr->capture_data_hi) ^ pattern[0])) || 114 (__raw_readl(&ddr->data_err_inject_lo) != 115 (__raw_readl(&ddr->capture_data_lo) ^ pattern[1]))) { 116 117 post_log("ECC failed to detect SBE error at %08x, " 118 "SBE injection mask %08x-%08x, wrote " 119 "%08x-%08x, read %08x-%08x\n", addr, 120 ddr->data_err_inject_hi, 121 ddr->data_err_inject_lo, 122 pattern[0], pattern[1], 123 retval[0], retval[1]); 124 125 printf("ERR_DETECT Reg: %08x\n", ddr->err_detect); 126 printf("ECC CAPTURE_DATA Reg: %08x-%08x\n", 127 ddr->capture_data_hi, ddr->capture_data_lo); 128 ret = 1; 129 break; 130 } 131 132 /* Re-initialize the ECC memory */ 133 ppcDWstore((u32*)addr, writeback); 134 sync(); 135 isync(); 136 137 errbit %= 63; 138 } 139 #endif /* !CONFIG_DDR_32BIT */ 140 141 ecc_clear(ddr); 142 143 icache_disable(); 144 145 if (int_state) 146 enable_interrupts(); 147 148 return ret; 149 } 150 #endif 151