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