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