1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <common.h>
26#include <asm/ppc4xx.h>
27#include <asm/processor.h>
28#include <asm/io.h>
29#include <asm/cache.h>
30
31#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR) || \
32 defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
33#if defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC)
34
35#if defined(CONFIG_405EX)
36
37
38
39
40#define SDRAM_DATA_ALT_WIDTH 2
41#else
42#define SDRAM_DATA_ALT_WIDTH 8
43#endif
44
45#if defined(CONFIG_SYS_OCM_BASE)
46#define CONFIG_FUNC_ISRAM_ADDR CONFIG_SYS_OCM_BASE
47#endif
48
49#if defined(CONFIG_SYS_ISRAM_BASE)
50#define CONFIG_FUNC_ISRAM_ADDR CONFIG_SYS_ISRAM_BASE
51#endif
52
53#if !defined(CONFIG_FUNC_ISRAM_ADDR)
54#error "No internal SRAM/OCM provided!"
55#endif
56
57#define force_inline inline __attribute__ ((always_inline))
58
59static inline void machine_check_disable(void)
60{
61 mtmsr(mfmsr() & ~MSR_ME);
62}
63
64static inline void machine_check_enable(void)
65{
66 mtmsr(mfmsr() | MSR_ME);
67}
68
69
70
71
72
73
74
75static force_inline void wait_ddr_idle(void)
76{
77 u32 val;
78
79 do {
80 mfsdram(SDRAM_MCSTAT, val);
81 } while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT);
82}
83
84static force_inline void recalibrate_ddr(void)
85{
86 u32 val;
87
88
89
90
91
92
93 mfsdram(SDRAM_RQDC, val);
94 mtsdram(SDRAM_RQDC, val);
95 mfsdram(SDRAM_RFDC, val);
96 mtsdram(SDRAM_RFDC, val);
97}
98
99static force_inline void set_mcopt1_mchk(u32 bits)
100{
101 u32 val;
102
103 wait_ddr_idle();
104 mfsdram(SDRAM_MCOPT1, val);
105 mtsdram(SDRAM_MCOPT1, (val & ~SDRAM_MCOPT1_MCHK_MASK) | bits);
106 recalibrate_ddr();
107}
108
109
110
111
112
113
114static void inject_ecc_error(void *ptr, int par)
115{
116 u32 val;
117
118
119
120
121
122
123
124
125
126 out_be32(ptr, 0x00000000);
127 val = in_be32(ptr);
128
129
130 set_mcopt1_mchk(SDRAM_MCOPT1_MCHK_NON);
131
132
133 if (par == 1)
134 out_be32(ptr, in_be32(ptr) ^ 0x00000001);
135 else
136 out_be32(ptr, in_be32(ptr) ^ 0x00000003);
137
138
139 val = in_be32(ptr);
140 set_mcopt1_mchk(SDRAM_MCOPT1_MCHK_CHK_REP);
141
142
143 wait_ddr_idle();
144
145
146}
147
148static void rewrite_ecc_parity(void *ptr, int par)
149{
150 u32 current_address = (u32)ptr;
151 u32 end_address;
152 u32 address_increment;
153 u32 mcopt1;
154 u32 val;
155
156
157
158
159
160
161
162 val = in_be32(0x00000000);
163 set_mcopt1_mchk(SDRAM_MCOPT1_MCHK_GEN);
164
165
166 mfsdram(SDRAM_MCOPT1, mcopt1);
167 if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32)
168 address_increment = 4;
169 else
170 address_increment = SDRAM_DATA_ALT_WIDTH;
171 end_address = current_address + CONFIG_SYS_CACHELINE_SIZE;
172
173 while (current_address < end_address) {
174 *((unsigned long *)current_address) = 0;
175 current_address += address_increment;
176 }
177
178 set_mcopt1_mchk(SDRAM_MCOPT1_MCHK_CHK_REP);
179
180
181 wait_ddr_idle();
182}
183
184static int do_ecctest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
185{
186 u32 old_val;
187 u32 val;
188 u32 *ptr;
189 void (*sram_func)(u32 *, int);
190 int error;
191
192 if (argc < 3) {
193 return cmd_usage(cmdtp);
194 }
195
196 ptr = (u32 *)simple_strtoul(argv[1], NULL, 16);
197 error = simple_strtoul(argv[2], NULL, 16);
198 if ((error < 1) || (error > 2)) {
199 return cmd_usage(cmdtp);
200 }
201
202 printf("Using address %p for %d bit ECC error injection\n",
203 ptr, error);
204
205
206
207
208 old_val = in_be32(ptr);
209
210
211
212
213 sram_func = (void *)CONFIG_FUNC_ISRAM_ADDR;
214 memcpy((void *)CONFIG_FUNC_ISRAM_ADDR, inject_ecc_error, 0x10000);
215
216
217
218
219
220 disable_interrupts();
221 machine_check_disable();
222 eieio();
223
224
225
226
227 (*sram_func)(ptr, error);
228
229
230 val = in_be32(ptr);
231
232
233
234
235
236
237 mfsdram(SDRAM_ECCES, val);
238 if (val & SDRAM_ECCES_CE)
239 printf("ECC: Correctable error\n");
240 if (val & SDRAM_ECCES_UE) {
241 printf("ECC: Uncorrectable error at 0x%02x%08x\n",
242 mfdcr(SDRAM_ERRADDULL), mfdcr(SDRAM_ERRADDLLL));
243 }
244
245
246
247
248 mtsdram(SDRAM_ECCES, 0xffffffff);
249 mtdcr(SDRAM_ERRSTATLL, 0xff000000);
250 set_mcsr(get_mcsr());
251
252
253 eieio();
254 machine_check_enable();
255 enable_interrupts();
256
257
258
259
260
261
262
263
264 memcpy((void *)CONFIG_FUNC_ISRAM_ADDR, rewrite_ecc_parity, 0x10000);
265 (*sram_func)(ptr, 0);
266
267
268
269
270 out_be32(ptr, old_val);
271
272 return 0;
273}
274
275U_BOOT_CMD(
276 ecctest, 3, 0, do_ecctest,
277 "Test ECC by single and double error bit injection",
278 "address 1/2"
279);
280
281#endif
282#endif
283