blob: 6ab1593138519fc43143bd70cbf31eb46dbd4e9a [file] [log] [blame]
Pavel Kolesnikov531e3e82007-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
Yuri Tikhonov0a51e922008-03-31 10:49:34 +020034#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020035
36#include <post.h>
37
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020038#if CONFIG_POST & CONFIG_SYS_POST_ECC
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020039
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
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020050DECLARE_GLOBAL_DATA_PTR;
51
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050052const static uint8_t syndrome_codes[] = {
Larry Johnson0d9cdea2007-12-22 15:23:50 -050053 0xF4, 0XF1, 0XEC, 0XEA, 0XE9, 0XE6, 0XE5, 0XE3,
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020054 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
Larry Johnsona724a9b2007-10-27 12:48:15 -040066#define ECC_PATTERN 0x01010101
67#define ECC_PATTERN_CORR 0x11010101
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050068#define ECC_PATTERN_UNCORR 0x61010101
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020069
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050070inline static void disable_ecc(void)
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020071{
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050072 uint32_t value;
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020073
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050074 sync(); /* Wait for any pending memory accesses to complete. */
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020075 mfsdram(DDR0_22, value);
Larry Johnson0d9cdea2007-12-22 15:23:50 -050076 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020077 | DDR0_22_CTRL_RAW_ECC_DISABLE);
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050078}
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020079
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050080inline static void clear_and_enable_ecc(void)
81{
82 uint32_t value;
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020083
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050084 sync(); /* Wait for any pending memory accesses to complete. */
Larry Johnsona724a9b2007-10-27 12:48:15 -040085 mfsdram(DDR0_00, value);
86 mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050087 mfsdram(DDR0_22, value);
88 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
89 | DDR0_22_CTRL_RAW_ECC_ENABLE);
90}
Larry Johnsona724a9b2007-10-27 12:48:15 -040091
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050092static uint32_t get_ecc_status(void)
93{
94 uint32_t int_status;
95#if defined(DEBUG)
96 uint8_t syndrome;
97 uint32_t hdata, ldata, haddr, laddr;
98 uint32_t value;
99#endif
100
101 mfsdram(DDR0_00, int_status);
102 int_status &= DDR0_00_INT_STATUS_MASK;
103
104#if defined(DEBUG)
105 if (int_status & (DDR0_00_INT_STATUS_BIT0 | DDR0_00_INT_STATUS_BIT1)) {
106 mfsdram(DDR0_32, laddr);
107 mfsdram(DDR0_33, haddr);
108 haddr &= 0x00000001;
109 if (int_status & DDR0_00_INT_STATUS_BIT1)
110 debug("Multiple accesses");
111 else
112 debug("A single access");
113
114 debug(" outside the defined physical memory space detected\n"
115 " addr = 0x%01x%08x\n", haddr, laddr);
116 }
117 if (int_status & (DDR0_00_INT_STATUS_BIT2 | DDR0_00_INT_STATUS_BIT3)) {
118 unsigned int bit;
119
120 mfsdram(DDR0_23, value);
121 syndrome = (value >> 16) & 0xff;
122 for (bit = 0; bit < sizeof(syndrome_codes); bit++)
123 if (syndrome_codes[bit] == syndrome)
124 break;
125
126 mfsdram(DDR0_38, laddr);
127 mfsdram(DDR0_39, haddr);
128 haddr &= 0x00000001;
129 mfsdram(DDR0_40, ldata);
130 mfsdram(DDR0_41, hdata);
131 if (int_status & DDR0_00_INT_STATUS_BIT3)
132 debug("Multiple correctable ECC events");
133 else
134 debug("Single correctable ECC event");
135
136 debug(" detected\n 0x%01x%08x - 0x%08x%08x, bit - %d\n",
137 haddr, laddr, hdata, ldata, bit);
138 }
139 if (int_status & (DDR0_00_INT_STATUS_BIT4 | DDR0_00_INT_STATUS_BIT5)) {
140 mfsdram(DDR0_23, value);
141 syndrome = (value >> 8) & 0xff;
142 mfsdram(DDR0_34, laddr);
143 mfsdram(DDR0_35, haddr);
144 haddr &= 0x00000001;
145 mfsdram(DDR0_36, ldata);
146 mfsdram(DDR0_37, hdata);
147 if (int_status & DDR0_00_INT_STATUS_BIT5)
148 debug("Multiple uncorrectable ECC events");
149 else
150 debug("Single uncorrectable ECC event");
151
152 debug(" detected\n 0x%01x%08x - 0x%08x%08x, "
153 "syndrome - 0x%02x\n",
154 haddr, laddr, hdata, ldata, syndrome);
155 }
156 if (int_status & DDR0_00_INT_STATUS_BIT6)
157 debug("DRAM initialization complete\n");
158#endif /* defined(DEBUG) */
159
160 return int_status;
161}
162
163static int test_ecc(uint32_t ecc_addr)
164{
165 uint32_t value;
166 volatile uint32_t *const ecc_mem = (volatile uint32_t *)ecc_addr;
167 int ret = 0;
168
169 WATCHDOG_RESET();
170
171 debug("Entering test_ecc(0x%08x)\n", ecc_addr);
172 /* Set up correct ECC in memory */
173 disable_ecc();
174 clear_and_enable_ecc();
175 out_be32(ecc_mem, ECC_PATTERN);
176 out_be32(ecc_mem + 1, ECC_PATTERN);
177
178 /* Verify no ECC error reading back */
179 value = in_be32(ecc_mem);
180 disable_ecc();
181 if (ECC_PATTERN != value) {
182 debug("Data read error (no-error case): "
183 "expected 0x%08x, read 0x%08x\n", ECC_PATTERN, value);
184 ret = 1;
185 }
186 value = get_ecc_status();
187 if (0x00000000 != value) {
188 /* Expected no ECC status reported */
189 debug("get_ecc_status(): expected 0x%08x, got 0x%08x\n",
190 0x00000000, value);
191 ret = 1;
192 }
193
194 /* Test for correctable error by creating a one-bit error */
195 out_be32(ecc_mem, ECC_PATTERN_CORR);
196 clear_and_enable_ecc();
197 value = in_be32(ecc_mem);
198 disable_ecc();
199 /* Test that the corrected data was read */
200 if (ECC_PATTERN != value) {
201 debug("Data read error (correctable-error case): "
202 "expected 0x%08x, read 0x%08x\n", ECC_PATTERN, value);
203 ret = 1;
204 }
205 value = get_ecc_status();
206 if ((DDR0_00_INT_STATUS_BIT2 | DDR0_00_INT_STATUS_BIT7) != value) {
207 /* Expected a single correctable error reported */
208 debug("get_ecc_status(): expected 0x%08x, got 0x%08x\n",
209 DDR0_00_INT_STATUS_BIT2, value);
210 ret = 1;
211 }
212
213 /* Test for uncorrectable error by creating a two-bit error */
214 out_be32(ecc_mem, ECC_PATTERN_UNCORR);
215 clear_and_enable_ecc();
216 value = in_be32(ecc_mem);
217 disable_ecc();
218 /* Test that the corrected data was read */
219 if (ECC_PATTERN_UNCORR != value) {
220 debug("Data read error (uncorrectable-error case): "
221 "expected 0x%08x, read 0x%08x\n", ECC_PATTERN_UNCORR,
222 value);
223 ret = 1;
224 }
225 value = get_ecc_status();
226 if ((DDR0_00_INT_STATUS_BIT4 | DDR0_00_INT_STATUS_BIT7) != value) {
227 /* Expected a single uncorrectable error reported */
228 debug("get_ecc_status(): expected 0x%08x, got 0x%08x\n",
229 DDR0_00_INT_STATUS_BIT4, value);
230 ret = 1;
231 }
232
233 /* Remove error from SDRAM and enable ECC. */
234 out_be32(ecc_mem, ECC_PATTERN);
235 clear_and_enable_ecc();
236
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200237 return ret;
238}
239
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500240int ecc_post_test(int flags)
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200241{
242 int ret = 0;
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500243 uint32_t value;
244 uint32_t iaddr;
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200245
Larry Johnsona724a9b2007-10-27 12:48:15 -0400246 mfsdram(DDR0_22, value);
247 if (0x3 != DDR0_22_CTRL_RAW_DECODE(value)) {
248 debug("SDRAM ECC not enabled, skipping ECC POST.\n");
249 return 0;
250 }
251
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500252 /* Mask all interrupts. */
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200253 mfsdram(DDR0_01, value);
Larry Johnson0d9cdea2007-12-22 15:23:50 -0500254 mtsdram(DDR0_01, (value & ~DDR0_01_INT_MASK_MASK)
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200255 | DDR0_01_INT_MASK_ALL_OFF);
256
Larry Johnsona724a9b2007-10-27 12:48:15 -0400257 for (iaddr = ECC_START_ADDR; iaddr <= ECC_STOP_ADDR; iaddr += iaddr) {
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200258 ret = test_ecc(iaddr);
259 if (ret)
260 break;
261 }
Stefan Roeseea9f6bc2007-07-31 08:37:01 +0200262 /*
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500263 * Clear possible errors resulting from ECC testing. (If not done, we
264 * we could get an interrupt later on when exceptions are enabled.)
Stefan Roeseea9f6bc2007-07-31 08:37:01 +0200265 */
266 set_mcsr(get_mcsr());
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500267 debug("ecc_post_test() returning %d\n", ret);
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200268 return ret;
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200269}
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200270#endif /* CONFIG_POST & CONFIG_SYS_POST_ECC */
Yuri Tikhonov0a51e922008-03-31 10:49:34 +0200271#endif /* defined(CONFIG_440EPX) || defined(CONFIG_440GRX) */