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 * See file CREDITS for list of people who contributed to this 10 * project. 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License as 14 * published by the Free Software Foundation; either version 2 of 15 * the License, or (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 25 * MA 02111-1307 USA 26 */ 27 28 #include <common.h> 29 #include <mpc83xx.h> 30 #include <watchdog.h> 31 #include <asm/io.h> 32 #include <post.h> 33 34 #if CONFIG_POST & CONFIG_SYS_POST_ECC 35 /* 36 * We use the RAW I/O accessors where possible in order to 37 * achieve performance goal, since the test's execution time 38 * affects the board start up time. 39 */ 40 static inline void ecc_clear(ddr83xx_t *ddr) 41 { 42 /* Clear capture registers */ 43 __raw_writel(0, &ddr->capture_address); 44 __raw_writel(0, &ddr->capture_data_hi); 45 __raw_writel(0, &ddr->capture_data_lo); 46 __raw_writel(0, &ddr->capture_ecc); 47 __raw_writel(0, &ddr->capture_attributes); 48 49 /* Clear SBEC and set SBET to 1 */ 50 out_be32(&ddr->err_sbe, 1 << ECC_ERROR_MAN_SBET_SHIFT); 51 52 /* Clear Error Detect register */ 53 out_be32(&ddr->err_detect, ECC_ERROR_DETECT_MME |\ 54 ECC_ERROR_DETECT_MBE |\ 55 ECC_ERROR_DETECT_SBE |\ 56 ECC_ERROR_DETECT_MSE); 57 58 isync(); 59 } 60 61 int ecc_post_test(int flags) 62 { 63 int ret = 0; 64 int int_state; 65 int errbit; 66 u32 pattern[2], writeback[2], retval[2]; 67 ddr83xx_t *ddr = &((immap_t *)CONFIG_SYS_IMMR)->ddr; 68 volatile u64 *addr = (u64 *)CONFIG_SYS_POST_ECC_START_ADDR; 69 70 /* The pattern is written into memory to generate error */ 71 pattern[0] = 0xfedcba98UL; 72 pattern[1] = 0x76543210UL; 73 74 /* After injecting error, re-initialize the memory with the value */ 75 writeback[0] = ~pattern[0]; 76 writeback[1] = ~pattern[1]; 77 78 /* Check if ECC is enabled */ 79 if (__raw_readl(&ddr->err_disable) & ECC_ERROR_ENABLE) { 80 debug("DDR's ECC is not enabled, skipping the ECC POST.\n"); 81 return 0; 82 } 83 84 int_state = disable_interrupts(); 85 icache_enable(); 86 87 #ifdef CONFIG_DDR_32BIT 88 /* It seems like no one really uses the CONFIG_DDR_32BIT mode */ 89 #error "Add ECC POST support for CONFIG_DDR_32BIT here!" 90 #else 91 for (addr = (u64*)CONFIG_SYS_POST_ECC_START_ADDR, errbit=0; 92 addr < (u64*)CONFIG_SYS_POST_ECC_STOP_ADDR; addr++, errbit++ ) { 93 94 WATCHDOG_RESET(); 95 96 ecc_clear(ddr); 97 98 /* Enable error injection */ 99 setbits_be32(&ddr->ecc_err_inject, ECC_ERR_INJECT_EIEN); 100 sync(); 101 isync(); 102 103 /* Set bit to be injected */ 104 if (errbit < 32) { 105 __raw_writel(1 << errbit, &ddr->data_err_inject_lo); 106 __raw_writel(0, &ddr->data_err_inject_hi); 107 } else { 108 __raw_writel(0, &ddr->data_err_inject_lo); 109 __raw_writel(1<<(errbit-32), &ddr->data_err_inject_hi); 110 } 111 sync(); 112 isync(); 113 114 /* Write memory location injecting SBE */ 115 ppcDWstore((u32*)addr, pattern); 116 sync(); 117 118 /* Disable error injection */ 119 clrbits_be32(&ddr->ecc_err_inject, ECC_ERR_INJECT_EIEN); 120 sync(); 121 isync(); 122 123 /* Data read should generate SBE */ 124 ppcDWload((u32*)addr, retval); 125 sync(); 126 127 if (!(__raw_readl(&ddr->err_detect) & ECC_ERROR_DETECT_SBE) || 128 (__raw_readl(&ddr->data_err_inject_hi) != 129 (__raw_readl(&ddr->capture_data_hi) ^ pattern[0])) || 130 (__raw_readl(&ddr->data_err_inject_lo) != 131 (__raw_readl(&ddr->capture_data_lo) ^ pattern[1]))) { 132 133 post_log("ECC failed to detect SBE error at %08x, " 134 "SBE injection mask %08x-%08x, wrote " 135 "%08x-%08x, read %08x-%08x\n", addr, 136 ddr->data_err_inject_hi, 137 ddr->data_err_inject_lo, 138 pattern[0], pattern[1], 139 retval[0], retval[1]); 140 141 printf("ERR_DETECT Reg: %08x\n", ddr->err_detect); 142 printf("ECC CAPTURE_DATA Reg: %08x-%08x\n", 143 ddr->capture_data_hi, ddr->capture_data_lo); 144 ret = 1; 145 break; 146 } 147 148 /* Re-initialize the ECC memory */ 149 ppcDWstore((u32*)addr, writeback); 150 sync(); 151 isync(); 152 153 errbit %= 63; 154 } 155 #endif /* !CONFIG_DDR_32BIT */ 156 157 ecc_clear(ddr); 158 159 icache_disable(); 160 161 if (int_state) 162 enable_interrupts(); 163 164 return ret; 165 } 166 #endif 167