blob: 3fa3ba62435747b338078a2bd0bce3559386fd8d [file] [log] [blame]
Pavel Kolesnikov5d896112007-07-20 15:03:03 +02001/*
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
52DECLARE_GLOBAL_DATA_PTR;
53
54const 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
72static 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
153static 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
220int 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
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200239 /* enable full support of ECC */
240 mfsdram(DDR0_22, value);
241 mtsdram(DDR0_22, (value &~ DDR0_22_CTRL_RAW_MASK)
242 | DDR0_22_CTRL_RAW_ECC_ENABLE);
243
244 for (iaddr = ECC_START_ADDR; iaddr < ECC_STOP_ADDR; iaddr += iaddr) {
245 ret = test_ecc(iaddr);
246 if (ret)
247 break;
248 }
Stefan Roese0dd0e642007-07-31 08:37:01 +0200249
250 /* clear error status */
251 mfsdram(DDR0_00, value);
252 mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
253
254 /*
255 * Clear possible errors resulting from ECC testing.
256 * If not done, then we could get an interrupt later on when
257 * exceptions are enabled.
258 */
259 set_mcsr(get_mcsr());
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200260#endif
261
262 return ret;
263
264}
265
266#endif /* CONFIG_POST & CFG_POST_ECC */
267#endif /* CONFIG_POST */