1 /* 2 * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. 3 * 4 * Dave Liu <daveliu@freescale.com> 5 * based on the contribution of Marian Balakowicz <m8@semihalf.com> 6 * 7 * See file CREDITS for list of people who contributed to this 8 * project. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation; either version 2 of 13 * the License, or (at your option) any later version. 14 */ 15 16 #include <common.h> 17 #include <mpc83xx.h> 18 #include <command.h> 19 20 #if defined(CONFIG_DDR_ECC) && defined(CONFIG_DDR_ECC_CMD) 21 void ecc_print_status(void) 22 { 23 immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; 24 #ifdef CONFIG_FSL_DDR2 25 ccsr_ddr_t *ddr = &immap->ddr; 26 #else 27 ddr83xx_t *ddr = &immap->ddr; 28 #endif 29 30 printf("\nECC mode: %s\n\n", 31 (ddr->sdram_cfg & SDRAM_CFG_ECC_EN) ? "ON" : "OFF"); 32 33 /* Interrupts */ 34 printf("Memory Error Interrupt Enable:\n"); 35 printf(" Multiple-Bit Error Interrupt Enable: %d\n", 36 (ddr->err_int_en & ECC_ERR_INT_EN_MBEE) ? 1 : 0); 37 printf(" Single-Bit Error Interrupt Enable: %d\n", 38 (ddr->err_int_en & ECC_ERR_INT_EN_SBEE) ? 1 : 0); 39 printf(" Memory Select Error Interrupt Enable: %d\n\n", 40 (ddr->err_int_en & ECC_ERR_INT_EN_MSEE) ? 1 : 0); 41 42 /* Error disable */ 43 printf("Memory Error Disable:\n"); 44 printf(" Multiple-Bit Error Disable: %d\n", 45 (ddr->err_disable & ECC_ERROR_DISABLE_MBED) ? 1 : 0); 46 printf(" Sinle-Bit Error Disable: %d\n", 47 (ddr->err_disable & ECC_ERROR_DISABLE_SBED) ? 1 : 0); 48 printf(" Memory Select Error Disable: %d\n\n", 49 (ddr->err_disable & ECC_ERROR_DISABLE_MSED) ? 1 : 0); 50 51 /* Error injection */ 52 printf("Memory Data Path Error Injection Mask High/Low: %08x %08x\n", 53 ddr->data_err_inject_hi, ddr->data_err_inject_lo); 54 55 printf("Memory Data Path Error Injection Mask ECC:\n"); 56 printf(" ECC Mirror Byte: %d\n", 57 (ddr->ecc_err_inject & ECC_ERR_INJECT_EMB) ? 1 : 0); 58 printf(" ECC Injection Enable: %d\n", 59 (ddr->ecc_err_inject & ECC_ERR_INJECT_EIEN) ? 1 : 0); 60 printf(" ECC Error Injection Mask: 0x%02x\n\n", 61 ddr->ecc_err_inject & ECC_ERR_INJECT_EEIM); 62 63 /* SBE counter/threshold */ 64 printf("Memory Single-Bit Error Management (0..255):\n"); 65 printf(" Single-Bit Error Threshold: %d\n", 66 (ddr->err_sbe & ECC_ERROR_MAN_SBET) >> ECC_ERROR_MAN_SBET_SHIFT); 67 printf(" Single-Bit Error Counter: %d\n\n", 68 (ddr->err_sbe & ECC_ERROR_MAN_SBEC) >> ECC_ERROR_MAN_SBEC_SHIFT); 69 70 /* Error detect */ 71 printf("Memory Error Detect:\n"); 72 printf(" Multiple Memory Errors: %d\n", 73 (ddr->err_detect & ECC_ERROR_DETECT_MME) ? 1 : 0); 74 printf(" Multiple-Bit Error: %d\n", 75 (ddr->err_detect & ECC_ERROR_DETECT_MBE) ? 1 : 0); 76 printf(" Single-Bit Error: %d\n", 77 (ddr->err_detect & ECC_ERROR_DETECT_SBE) ? 1 : 0); 78 printf(" Memory Select Error: %d\n\n", 79 (ddr->err_detect & ECC_ERROR_DETECT_MSE) ? 1 : 0); 80 81 /* Capture data */ 82 printf("Memory Error Address Capture: 0x%08x\n", ddr->capture_address); 83 printf("Memory Data Path Read Capture High/Low: %08x %08x\n", 84 ddr->capture_data_hi, ddr->capture_data_lo); 85 printf("Memory Data Path Read Capture ECC: 0x%02x\n\n", 86 ddr->capture_ecc & CAPTURE_ECC_ECE); 87 88 printf("Memory Error Attributes Capture:\n"); 89 printf(" Data Beat Number: %d\n", 90 (ddr->capture_attributes & ECC_CAPT_ATTR_BNUM) >> 91 ECC_CAPT_ATTR_BNUM_SHIFT); 92 printf(" Transaction Size: %d\n", 93 (ddr->capture_attributes & ECC_CAPT_ATTR_TSIZ) >> 94 ECC_CAPT_ATTR_TSIZ_SHIFT); 95 printf(" Transaction Source: %d\n", 96 (ddr->capture_attributes & ECC_CAPT_ATTR_TSRC) >> 97 ECC_CAPT_ATTR_TSRC_SHIFT); 98 printf(" Transaction Type: %d\n", 99 (ddr->capture_attributes & ECC_CAPT_ATTR_TTYP) >> 100 ECC_CAPT_ATTR_TTYP_SHIFT); 101 printf(" Error Information Valid: %d\n\n", 102 ddr->capture_attributes & ECC_CAPT_ATTR_VLD); 103 } 104 105 int do_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 106 { 107 immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; 108 #ifdef CONFIG_FSL_DDR2 109 ccsr_ddr_t *ddr = &immap->ddr; 110 #else 111 ddr83xx_t *ddr = &immap->ddr; 112 #endif 113 volatile u32 val; 114 u64 *addr; 115 u32 count; 116 register u64 *i; 117 u32 ret[2]; 118 u32 pattern[2]; 119 u32 writeback[2]; 120 121 /* The pattern is written into memory to generate error */ 122 pattern[0] = 0xfedcba98UL; 123 pattern[1] = 0x76543210UL; 124 125 /* After injecting error, re-initialize the memory with the value */ 126 writeback[0] = 0x01234567UL; 127 writeback[1] = 0x89abcdefUL; 128 129 if (argc > 4) 130 return cmd_usage(cmdtp); 131 132 if (argc == 2) { 133 if (strcmp(argv[1], "status") == 0) { 134 ecc_print_status(); 135 return 0; 136 } else if (strcmp(argv[1], "captureclear") == 0) { 137 ddr->capture_address = 0; 138 ddr->capture_data_hi = 0; 139 ddr->capture_data_lo = 0; 140 ddr->capture_ecc = 0; 141 ddr->capture_attributes = 0; 142 return 0; 143 } 144 } 145 if (argc == 3) { 146 if (strcmp(argv[1], "sbecnt") == 0) { 147 val = simple_strtoul(argv[2], NULL, 10); 148 if (val > 255) { 149 printf("Incorrect Counter value, " 150 "should be 0..255\n"); 151 return 1; 152 } 153 154 val = (val << ECC_ERROR_MAN_SBEC_SHIFT); 155 val |= (ddr->err_sbe & ECC_ERROR_MAN_SBET); 156 157 ddr->err_sbe = val; 158 return 0; 159 } else if (strcmp(argv[1], "sbethr") == 0) { 160 val = simple_strtoul(argv[2], NULL, 10); 161 if (val > 255) { 162 printf("Incorrect Counter value, " 163 "should be 0..255\n"); 164 return 1; 165 } 166 167 val = (val << ECC_ERROR_MAN_SBET_SHIFT); 168 val |= (ddr->err_sbe & ECC_ERROR_MAN_SBEC); 169 170 ddr->err_sbe = val; 171 return 0; 172 } else if (strcmp(argv[1], "errdisable") == 0) { 173 val = ddr->err_disable; 174 175 if (strcmp(argv[2], "+sbe") == 0) { 176 val |= ECC_ERROR_DISABLE_SBED; 177 } else if (strcmp(argv[2], "+mbe") == 0) { 178 val |= ECC_ERROR_DISABLE_MBED; 179 } else if (strcmp(argv[2], "+mse") == 0) { 180 val |= ECC_ERROR_DISABLE_MSED; 181 } else if (strcmp(argv[2], "+all") == 0) { 182 val |= (ECC_ERROR_DISABLE_SBED | 183 ECC_ERROR_DISABLE_MBED | 184 ECC_ERROR_DISABLE_MSED); 185 } else if (strcmp(argv[2], "-sbe") == 0) { 186 val &= ~ECC_ERROR_DISABLE_SBED; 187 } else if (strcmp(argv[2], "-mbe") == 0) { 188 val &= ~ECC_ERROR_DISABLE_MBED; 189 } else if (strcmp(argv[2], "-mse") == 0) { 190 val &= ~ECC_ERROR_DISABLE_MSED; 191 } else if (strcmp(argv[2], "-all") == 0) { 192 val &= ~(ECC_ERROR_DISABLE_SBED | 193 ECC_ERROR_DISABLE_MBED | 194 ECC_ERROR_DISABLE_MSED); 195 } else { 196 printf("Incorrect err_disable field\n"); 197 return 1; 198 } 199 200 ddr->err_disable = val; 201 __asm__ __volatile__("sync"); 202 __asm__ __volatile__("isync"); 203 return 0; 204 } else if (strcmp(argv[1], "errdetectclr") == 0) { 205 val = ddr->err_detect; 206 207 if (strcmp(argv[2], "mme") == 0) { 208 val |= ECC_ERROR_DETECT_MME; 209 } else if (strcmp(argv[2], "sbe") == 0) { 210 val |= ECC_ERROR_DETECT_SBE; 211 } else if (strcmp(argv[2], "mbe") == 0) { 212 val |= ECC_ERROR_DETECT_MBE; 213 } else if (strcmp(argv[2], "mse") == 0) { 214 val |= ECC_ERROR_DETECT_MSE; 215 } else if (strcmp(argv[2], "all") == 0) { 216 val |= (ECC_ERROR_DETECT_MME | 217 ECC_ERROR_DETECT_MBE | 218 ECC_ERROR_DETECT_SBE | 219 ECC_ERROR_DETECT_MSE); 220 } else { 221 printf("Incorrect err_detect field\n"); 222 return 1; 223 } 224 225 ddr->err_detect = val; 226 return 0; 227 } else if (strcmp(argv[1], "injectdatahi") == 0) { 228 val = simple_strtoul(argv[2], NULL, 16); 229 230 ddr->data_err_inject_hi = val; 231 return 0; 232 } else if (strcmp(argv[1], "injectdatalo") == 0) { 233 val = simple_strtoul(argv[2], NULL, 16); 234 235 ddr->data_err_inject_lo = val; 236 return 0; 237 } else if (strcmp(argv[1], "injectecc") == 0) { 238 val = simple_strtoul(argv[2], NULL, 16); 239 if (val > 0xff) { 240 printf("Incorrect ECC inject mask, " 241 "should be 0x00..0xff\n"); 242 return 1; 243 } 244 val |= (ddr->ecc_err_inject & ~ECC_ERR_INJECT_EEIM); 245 246 ddr->ecc_err_inject = val; 247 return 0; 248 } else if (strcmp(argv[1], "inject") == 0) { 249 val = ddr->ecc_err_inject; 250 251 if (strcmp(argv[2], "en") == 0) 252 val |= ECC_ERR_INJECT_EIEN; 253 else if (strcmp(argv[2], "dis") == 0) 254 val &= ~ECC_ERR_INJECT_EIEN; 255 else 256 printf("Incorrect command\n"); 257 258 ddr->ecc_err_inject = val; 259 __asm__ __volatile__("sync"); 260 __asm__ __volatile__("isync"); 261 return 0; 262 } else if (strcmp(argv[1], "mirror") == 0) { 263 val = ddr->ecc_err_inject; 264 265 if (strcmp(argv[2], "en") == 0) 266 val |= ECC_ERR_INJECT_EMB; 267 else if (strcmp(argv[2], "dis") == 0) 268 val &= ~ECC_ERR_INJECT_EMB; 269 else 270 printf("Incorrect command\n"); 271 272 ddr->ecc_err_inject = val; 273 return 0; 274 } 275 } 276 if (argc == 4) { 277 if (strcmp(argv[1], "testdw") == 0) { 278 addr = (u64 *) simple_strtoul(argv[2], NULL, 16); 279 count = simple_strtoul(argv[3], NULL, 16); 280 281 if ((u32) addr % 8) { 282 printf("Address not alligned on " 283 "double word boundary\n"); 284 return 1; 285 } 286 disable_interrupts(); 287 288 for (i = addr; i < addr + count; i++) { 289 290 /* enable injects */ 291 ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN; 292 __asm__ __volatile__("sync"); 293 __asm__ __volatile__("isync"); 294 295 /* write memory location injecting errors */ 296 ppcDWstore((u32 *) i, pattern); 297 __asm__ __volatile__("sync"); 298 299 /* disable injects */ 300 ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN; 301 __asm__ __volatile__("sync"); 302 __asm__ __volatile__("isync"); 303 304 /* read data, this generates ECC error */ 305 ppcDWload((u32 *) i, ret); 306 __asm__ __volatile__("sync"); 307 308 /* re-initialize memory, double word write the location again, 309 * generates new ECC code this time */ 310 ppcDWstore((u32 *) i, writeback); 311 __asm__ __volatile__("sync"); 312 } 313 enable_interrupts(); 314 return 0; 315 } 316 if (strcmp(argv[1], "testword") == 0) { 317 addr = (u64 *) simple_strtoul(argv[2], NULL, 16); 318 count = simple_strtoul(argv[3], NULL, 16); 319 320 if ((u32) addr % 8) { 321 printf("Address not alligned on " 322 "double word boundary\n"); 323 return 1; 324 } 325 disable_interrupts(); 326 327 for (i = addr; i < addr + count; i++) { 328 329 /* enable injects */ 330 ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN; 331 __asm__ __volatile__("sync"); 332 __asm__ __volatile__("isync"); 333 334 /* write memory location injecting errors */ 335 *(u32 *) i = 0xfedcba98UL; 336 __asm__ __volatile__("sync"); 337 338 /* sub double word write, 339 * bus will read-modify-write, 340 * generates ECC error */ 341 *((u32 *) i + 1) = 0x76543210UL; 342 __asm__ __volatile__("sync"); 343 344 /* disable injects */ 345 ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN; 346 __asm__ __volatile__("sync"); 347 __asm__ __volatile__("isync"); 348 349 /* re-initialize memory, 350 * double word write the location again, 351 * generates new ECC code this time */ 352 ppcDWstore((u32 *) i, writeback); 353 __asm__ __volatile__("sync"); 354 } 355 enable_interrupts(); 356 return 0; 357 } 358 } 359 return cmd_usage(cmdtp); 360 } 361 362 U_BOOT_CMD(ecc, 4, 0, do_ecc, 363 "support for DDR ECC features", 364 "status - print out status info\n" 365 "ecc captureclear - clear capture regs data\n" 366 "ecc sbecnt <val> - set Single-Bit Error counter\n" 367 "ecc sbethr <val> - set Single-Bit Threshold\n" 368 "ecc errdisable <flag> - clear/set disable Memory Error Disable, flag:\n" 369 " [-|+]sbe - Single-Bit Error\n" 370 " [-|+]mbe - Multiple-Bit Error\n" 371 " [-|+]mse - Memory Select Error\n" 372 " [-|+]all - all errors\n" 373 "ecc errdetectclr <flag> - clear Memory Error Detect, flag:\n" 374 " mme - Multiple Memory Errors\n" 375 " sbe - Single-Bit Error\n" 376 " mbe - Multiple-Bit Error\n" 377 " mse - Memory Select Error\n" 378 " all - all errors\n" 379 "ecc injectdatahi <hi> - set Memory Data Path Error Injection Mask High\n" 380 "ecc injectdatalo <lo> - set Memory Data Path Error Injection Mask Low\n" 381 "ecc injectecc <ecc> - set ECC Error Injection Mask\n" 382 "ecc inject <en|dis> - enable/disable error injection\n" 383 "ecc mirror <en|dis> - enable/disable mirror byte\n" 384 "ecc testdw <addr> <cnt> - test mem region with double word access:\n" 385 " - enables injects\n" 386 " - writes pattern injecting errors with double word access\n" 387 " - disables injects\n" 388 " - reads pattern back with double word access, generates error\n" 389 " - re-inits memory\n" 390 "ecc testword <addr> <cnt> - test mem region with word access:\n" 391 " - enables injects\n" 392 " - writes pattern injecting errors with word access\n" 393 " - writes pattern with word access, generates error\n" 394 " - disables injects\n" " - re-inits memory"); 395 #endif 396