]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - post/board/lwmon5/ecc.c
POST: Add ECC POST for the lwmon5 board
[karo-tx-uboot.git] / post / board / lwmon5 / 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 #ifdef CONFIG_POST
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 #include "../../../board/lwmon5/sdram.h"
51
52 DECLARE_GLOBAL_DATA_PTR;
53
54 const static unsigned char syndrome_codes[] = {
55         0xF4, 0XF1, 0XEC ,0XEA, 0XE9, 0XE6, 0XE5, 0XE3,
56         0XDC, 0XDA, 0XD9, 0XD6, 0XD5, 0XD3, 0XCE, 0XCB,
57         0xB5, 0XB0, 0XAD, 0XAB, 0XA8, 0XA7, 0XA4, 0XA2,
58         0X9D, 0X9B, 0X98, 0X97, 0X94, 0X92, 0X8F, 0X8A,
59         0x75, 0x70, 0X6D, 0X6B, 0X68, 0X67, 0X64, 0X62,
60         0X5E, 0X5B, 0X58, 0X57, 0X54, 0X52, 0X4F, 0X4A,
61         0x34, 0x31, 0X2C, 0X2A, 0X29, 0X26, 0X25, 0X23,
62         0X1C, 0X1A, 0X19, 0X16, 0X15, 0X13, 0X0E, 0X0B,
63         0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
64 };
65
66 #define ECC_START_ADDR          0x10
67 #define ECC_STOP_ADDR           0x2000
68 #define ECC_PATTERN             0x0101010101010101ull
69 #define ECC_PATTERN_CORR        0x0101010101010100ull
70 #define ECC_PATTERN_UNCORR      0x010101010101010Full
71
72 static int test_ecc_error(void)
73 {
74         unsigned long value;
75         unsigned long hdata, ldata, haddr, laddr;
76         unsigned int bit;
77
78         int ret = 0;
79
80         mfsdram(DDR0_23, value);
81
82         for (bit = 0; bit < sizeof(syndrome_codes); bit++)
83                 if (syndrome_codes[bit] == ((value >> 16) & 0xff))
84                         break;
85
86         mfsdram(DDR0_00, value);
87
88         if (value & DDR0_00_INT_STATUS_BIT0) {
89                 debug("Bit0. A single access outside the defined PHYSICAL"
90                       " memory space detected\n");
91                 mfsdram(DDR0_32, laddr);
92                 mfsdram(DDR0_33, haddr);
93                 debug("        addr = 0x%08x%08x\n", haddr, laddr);
94                 ret = 1;
95         }
96         if (value & DDR0_00_INT_STATUS_BIT1) {
97                 debug("Bit1. Multiple accesses outside the defined PHYSICAL"
98                       " memory space detected\n");
99                 ret = 2;
100         }
101         if (value & DDR0_00_INT_STATUS_BIT2) {
102                 debug("Bit2. Single correctable ECC event detected\n");
103                 mfsdram(DDR0_38, laddr);
104                 mfsdram(DDR0_39, haddr);
105                 mfsdram(DDR0_40, ldata);
106                 mfsdram(DDR0_41, hdata);
107                 debug("        0x%08x - 0x%08x%08x, bit - %d\n",
108                       laddr, hdata, ldata, bit);
109                 ret = 3;
110         }
111         if (value & DDR0_00_INT_STATUS_BIT3) {
112                 debug("Bit3. Multiple correctable ECC events detected\n");
113                 mfsdram(DDR0_38, laddr);
114                 mfsdram(DDR0_39, haddr);
115                 mfsdram(DDR0_40, ldata);
116                 mfsdram(DDR0_41, hdata);
117                 debug("        0x%08x - 0x%08x%08x, bit - %d\n",
118                       laddr, hdata, ldata, bit);
119                 ret = 4;
120         }
121         if (value & DDR0_00_INT_STATUS_BIT4) {
122                 debug("Bit4. Single uncorrectable ECC event detected\n");
123                 mfsdram(DDR0_34, laddr);
124                 mfsdram(DDR0_35, haddr);
125                 mfsdram(DDR0_36, ldata);
126                 mfsdram(DDR0_37, hdata);
127                 debug("        0x%08x - 0x%08x%08x, bit - %d\n",
128                       laddr, hdata, ldata, bit);
129                 ret = 5;
130         }
131         if (value & DDR0_00_INT_STATUS_BIT5) {
132                 debug("Bit5. Multiple uncorrectable ECC events detected\n");
133                 mfsdram(DDR0_34, laddr);
134                 mfsdram(DDR0_35, haddr);
135                 mfsdram(DDR0_36, ldata);
136                 mfsdram(DDR0_37, hdata);
137                 debug("        0x%08x - 0x%08x%08x, bit - %d\n",
138                       laddr, hdata, ldata, bit);
139                 ret = 6;
140         }
141         if (value & DDR0_00_INT_STATUS_BIT6) {
142                 debug("Bit6. DRAM initialization complete\n");
143                 ret = 7;
144         }
145
146         /* error status cleared */
147         mfsdram(DDR0_00, value);
148         mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
149
150         return ret;
151 }
152
153 static int test_ecc(unsigned long ecc_addr)
154 {
155         volatile unsigned long long *ecc_mem;
156         unsigned long value;
157         unsigned long ecc_data;
158         volatile unsigned long *lecc_mem;
159         int pret, ret = 0;
160
161         sync();
162         eieio();
163         WATCHDOG_RESET();
164
165         ecc_mem = (unsigned long long *)ecc_addr;
166         lecc_mem = (ulong *)ecc_addr;
167         *ecc_mem = ECC_PATTERN;
168         pret = test_ecc_error();
169         if (pret != 0)
170                 ret = 1;
171
172         /* disconnect ecc */
173         mfsdram(DDR0_22, value);
174         mtsdram(DDR0_22, (value &~ DDR0_22_CTRL_RAW_MASK)
175                 | DDR0_22_CTRL_RAW_ECC_DISABLE);
176
177         /* injecting error */
178         *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
185         ecc_data = *lecc_mem;
186         pret = test_ecc_error();
187         /* if read data ok, 1 correctable error must be fixed */
188         if (pret != 3)
189                 ret = 1;
190
191         /* test for uncorrectable error */
192         /* disconnect from ecc storage */
193         mfsdram(DDR0_22, value);
194         mtsdram(DDR0_22, (value &~ DDR0_22_CTRL_RAW_MASK)
195                 | DDR0_22_CTRL_RAW_NO_ECC_RAM);
196
197         /* injecting multiply bit error */
198
199         *ecc_mem = ECC_PATTERN_UNCORR;
200
201         /* enable ecc */
202         mfsdram(DDR0_22, value);
203         mtsdram(DDR0_22, (value &~ DDR0_22_CTRL_RAW_MASK)
204                 | DDR0_22_CTRL_RAW_ECC_ENABLE);
205
206         ecc_data = *lecc_mem;
207         /* what the data should be read? */
208
209         pret = test_ecc_error();
210         /* info about uncorrectable error must appear */
211         if (pret != 5)
212                 ret = 1;
213
214         sync();
215         eieio();
216
217         return ret;
218 }
219
220 int ecc_post_test (int flags)
221 {
222         int ret = 0;
223         unsigned long value;
224         unsigned long iaddr;
225
226 #if CONFIG_DDR_ECC
227         sync();
228         eieio();
229
230         /* mask all int */
231         mfsdram(DDR0_01, value);
232         mtsdram(DDR0_01, (value &~ DDR0_01_INT_MASK_MASK)
233                 | DDR0_01_INT_MASK_ALL_OFF);
234
235         /* clear error status */
236         mfsdram(DDR0_00, value);
237         mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
238
239
240         /* enable full support of ECC */
241         mfsdram(DDR0_22, value);
242         mtsdram(DDR0_22, (value &~ DDR0_22_CTRL_RAW_MASK)
243                 | DDR0_22_CTRL_RAW_ECC_ENABLE);
244
245         for (iaddr = ECC_START_ADDR; iaddr < ECC_STOP_ADDR; iaddr += iaddr) {
246                 ret = test_ecc(iaddr);
247                 if (ret)
248                         break;
249         }
250 #endif
251
252         return ret;
253
254 }
255
256 #endif /* CONFIG_POST & CFG_POST_ECC */
257 #endif /* CONFIG_POST */