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