Fix/enhance ECC POST for 440EPx/GRx
[platform/kernel/u-boot.git] / post / cpu / ppc4xx / denali_ecc.c
1 /*
2  * (C) Copyright 2007
3  * Developed for DENX Software Engineering GmbH.
4  *
5  * Author: Pavel Kolesnikov <concord@emcraft.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  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23  * MA 02111-1307 USA
24  */
25
26 /* define DEBUG for debugging output (obviously ;-)) */
27 #if 0
28 #define DEBUG
29 #endif
30
31 #include <common.h>
32 #include <watchdog.h>
33
34 #if defined(CONFIG_POST) && (defined(CONFIG_440EPX) || defined(CONFIG_440GRX))
35
36 #include <post.h>
37
38 #if CONFIG_POST & CFG_POST_ECC
39
40 /*
41  * MEMORY ECC test
42  *
43  * This test performs the checks ECC facility of memory.
44  */
45 #include <asm/processor.h>
46 #include <asm/mmu.h>
47 #include <asm/io.h>
48 #include <ppc440.h>
49
50 DECLARE_GLOBAL_DATA_PTR;
51
52 const static unsigned char syndrome_codes[] = {
53         0xF4, 0XF1, 0XEC ,0XEA, 0XE9, 0XE6, 0XE5, 0XE3,
54         0XDC, 0XDA, 0XD9, 0XD6, 0XD5, 0XD3, 0XCE, 0XCB,
55         0xB5, 0XB0, 0XAD, 0XAB, 0XA8, 0XA7, 0XA4, 0XA2,
56         0X9D, 0X9B, 0X98, 0X97, 0X94, 0X92, 0X8F, 0X8A,
57         0x75, 0x70, 0X6D, 0X6B, 0X68, 0X67, 0X64, 0X62,
58         0X5E, 0X5B, 0X58, 0X57, 0X54, 0X52, 0X4F, 0X4A,
59         0x34, 0x31, 0X2C, 0X2A, 0X29, 0X26, 0X25, 0X23,
60         0X1C, 0X1A, 0X19, 0X16, 0X15, 0X13, 0X0E, 0X0B,
61         0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
62 };
63
64 #define ECC_START_ADDR          0x10
65 #define ECC_STOP_ADDR           0x2000
66 #define ECC_PATTERN             0x01010101
67 #define ECC_PATTERN_CORR        0x11010101
68 #define ECC_PATTERN_UNCORR      0xF1010101
69
70 static int test_ecc_error(void)
71 {
72         unsigned long value;
73         unsigned long hdata, ldata, haddr, laddr;
74         unsigned int bit;
75
76         int ret = 0;
77
78         mfsdram(DDR0_23, value);
79
80         for (bit = 0; bit < sizeof(syndrome_codes); bit++)
81                 if (syndrome_codes[bit] == ((value >> 16) & 0xff))
82                         break;
83
84         mfsdram(DDR0_00, value);
85
86         if (value & DDR0_00_INT_STATUS_BIT0) {
87                 debug("Bit0. A single access outside the defined PHYSICAL"
88                       " memory space detected\n");
89                 mfsdram(DDR0_32, laddr);
90                 mfsdram(DDR0_33, haddr);
91                 debug("        addr = 0x%08x%08x\n", haddr, laddr);
92                 ret = 1;
93         }
94         if (value & DDR0_00_INT_STATUS_BIT1) {
95                 debug("Bit1. Multiple accesses outside the defined PHYSICAL"
96                       " memory space detected\n");
97                 ret = 2;
98         }
99         if (value & DDR0_00_INT_STATUS_BIT2) {
100                 debug("Bit2. Single correctable ECC event detected\n");
101                 mfsdram(DDR0_38, laddr);
102                 mfsdram(DDR0_39, haddr);
103                 mfsdram(DDR0_40, ldata);
104                 mfsdram(DDR0_41, hdata);
105                 debug("        0x%08x - 0x%08x%08x, bit - %d\n",
106                       laddr, hdata, ldata, bit);
107                 ret = 3;
108         }
109         if (value & DDR0_00_INT_STATUS_BIT3) {
110                 debug("Bit3. Multiple correctable ECC events detected\n");
111                 mfsdram(DDR0_38, laddr);
112                 mfsdram(DDR0_39, haddr);
113                 mfsdram(DDR0_40, ldata);
114                 mfsdram(DDR0_41, hdata);
115                 debug("        0x%08x - 0x%08x%08x, bit - %d\n",
116                       laddr, hdata, ldata, bit);
117                 ret = 4;
118         }
119         if (value & DDR0_00_INT_STATUS_BIT4) {
120                 debug("Bit4. Single uncorrectable ECC event detected\n");
121                 mfsdram(DDR0_34, laddr);
122                 mfsdram(DDR0_35, haddr);
123                 mfsdram(DDR0_36, ldata);
124                 mfsdram(DDR0_37, hdata);
125                 debug("        0x%08x - 0x%08x%08x, bit - %d\n",
126                       laddr, hdata, ldata, bit);
127                 ret = 5;
128         }
129         if (value & DDR0_00_INT_STATUS_BIT5) {
130                 debug("Bit5. Multiple uncorrectable ECC events detected\n");
131                 mfsdram(DDR0_34, laddr);
132                 mfsdram(DDR0_35, haddr);
133                 mfsdram(DDR0_36, ldata);
134                 mfsdram(DDR0_37, hdata);
135                 debug("        0x%08x - 0x%08x%08x, bit - %d\n",
136                       laddr, hdata, ldata, bit);
137                 ret = 6;
138         }
139         if (value & DDR0_00_INT_STATUS_BIT6) {
140                 debug("Bit6. DRAM initialization complete\n");
141                 ret = 7;
142         }
143
144         /* error status cleared */
145         mfsdram(DDR0_00, value);
146         mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
147
148         return ret;
149 }
150
151 static int test_ecc(unsigned long ecc_addr)
152 {
153         unsigned long value;
154         volatile unsigned *const ecc_mem = (volatile unsigned *) ecc_addr;
155         int pret;
156         int ret = 0;
157
158         sync();
159         eieio();
160         WATCHDOG_RESET();
161
162         debug("Entering test_ecc(0x%08lX)\n", ecc_addr);
163         out_be32(ecc_mem, ECC_PATTERN);
164         out_be32(ecc_mem + 1, ECC_PATTERN);
165         in_be32(ecc_mem);
166         pret = test_ecc_error();
167         if (pret != 0) {
168                 debug("pret: expected 0, got %d\n", pret);
169                 ret = 1;
170         }
171         /* test for correctable error */
172         /* disconnect from ecc storage */
173         mfsdram(DDR0_22, value);
174         mtsdram(DDR0_22, (value &~ DDR0_22_CTRL_RAW_MASK)
175                 | DDR0_22_CTRL_RAW_ECC_DISABLE);
176
177         /* creating (correctable) single-bit error */
178         out_be32(ecc_mem, ECC_PATTERN_CORR);
179
180         /* enable ecc */
181         mfsdram(DDR0_22, value);
182         mtsdram(DDR0_22, (value &~ DDR0_22_CTRL_RAW_MASK)
183                 | DDR0_22_CTRL_RAW_ECC_ENABLE);
184         sync();
185         eieio();
186
187         in_be32(ecc_mem);
188         pret = test_ecc_error();
189         /* if read data ok, 1 correctable error must be fixed */
190         if (pret != 3) {
191                 debug("pret: expected 3, got %d\n", pret);
192                 ret = 1;
193         }
194         /* test for uncorrectable error */
195         /* disconnect from ecc storage */
196         mfsdram(DDR0_22, value);
197         mtsdram(DDR0_22, (value &~ DDR0_22_CTRL_RAW_MASK)
198                 | DDR0_22_CTRL_RAW_NO_ECC_RAM);
199
200         /* creating (uncorrectable) multiple-bit error */
201         out_be32(ecc_mem, ECC_PATTERN_UNCORR);
202
203         /* enable ecc */
204         mfsdram(DDR0_22, value);
205         mtsdram(DDR0_22, (value &~ DDR0_22_CTRL_RAW_MASK)
206                 | DDR0_22_CTRL_RAW_ECC_ENABLE);
207         sync();
208         eieio();
209
210         in_be32(ecc_mem);
211         pret = test_ecc_error();
212         /* info about uncorrectable error must appear */
213         if (pret != 5) {
214                 debug("pret: expected 5, got %d\n", pret);
215                 ret = 1;
216         }
217         /* remove error from SDRAM */
218         out_be32(ecc_mem, ECC_PATTERN);
219         /* clear error caused by read-modify-write */
220         mfsdram(DDR0_00, value);
221         mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
222
223         sync();
224         eieio();
225         return ret;
226 }
227
228 int ecc_post_test (int flags)
229 {
230         int ret = 0;
231         unsigned long value;
232         unsigned long iaddr;
233
234         sync();
235         eieio();
236
237         mfsdram(DDR0_22, value);
238         if (0x3 != DDR0_22_CTRL_RAW_DECODE(value)) {
239                 debug("SDRAM ECC not enabled, skipping ECC POST.\n");
240                 return 0;
241         }
242
243         /* mask all int */
244         mfsdram(DDR0_01, value);
245         mtsdram(DDR0_01, (value &~ DDR0_01_INT_MASK_MASK)
246                 | DDR0_01_INT_MASK_ALL_OFF);
247
248         /* clear error status */
249         mfsdram(DDR0_00, value);
250         mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
251
252         for (iaddr = ECC_START_ADDR; iaddr <= ECC_STOP_ADDR; iaddr += iaddr) {
253                 ret = test_ecc(iaddr);
254                 if (ret)
255                         break;
256         }
257         /*
258          * Clear possible errors resulting from ECC testing.
259          * If not done, then we could get an interrupt later on when
260          * exceptions are enabled.
261          */
262         set_mcsr(get_mcsr());
263         return ret;
264
265 }
266 #endif /* CONFIG_POST & CFG_POST_ECC */
267 #endif /* defined(CONFIG_POST) && ... */