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  */
ecc_clear(ddr83xx_t * ddr)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 
ecc_post_test(int flags)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