blob: 6d146355956252c9aa3ef1a1fd79d8b4262f7f5f [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>
Stefan Roeseb36df562010-09-09 19:18:00 +020048#include <asm/ppc440.h>
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020049
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);
Stefan Roese28e94bb2010-11-26 15:45:22 +0100177 ppcDcbf((u32)ecc_mem);
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500178
179 /* Verify no ECC error reading back */
180 value = in_be32(ecc_mem);
181 disable_ecc();
182 if (ECC_PATTERN != value) {
183 debug("Data read error (no-error case): "
184 "expected 0x%08x, read 0x%08x\n", ECC_PATTERN, value);
185 ret = 1;
186 }
187 value = get_ecc_status();
188 if (0x00000000 != value) {
189 /* Expected no ECC status reported */
190 debug("get_ecc_status(): expected 0x%08x, got 0x%08x\n",
191 0x00000000, value);
192 ret = 1;
193 }
194
195 /* Test for correctable error by creating a one-bit error */
196 out_be32(ecc_mem, ECC_PATTERN_CORR);
Stefan Roese28e94bb2010-11-26 15:45:22 +0100197 ppcDcbf((u32)ecc_mem);
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500198 clear_and_enable_ecc();
199 value = in_be32(ecc_mem);
200 disable_ecc();
201 /* Test that the corrected data was read */
202 if (ECC_PATTERN != value) {
203 debug("Data read error (correctable-error case): "
204 "expected 0x%08x, read 0x%08x\n", ECC_PATTERN, value);
205 ret = 1;
206 }
207 value = get_ecc_status();
208 if ((DDR0_00_INT_STATUS_BIT2 | DDR0_00_INT_STATUS_BIT7) != value) {
209 /* Expected a single correctable error reported */
210 debug("get_ecc_status(): expected 0x%08x, got 0x%08x\n",
211 DDR0_00_INT_STATUS_BIT2, value);
212 ret = 1;
213 }
214
215 /* Test for uncorrectable error by creating a two-bit error */
216 out_be32(ecc_mem, ECC_PATTERN_UNCORR);
Stefan Roese28e94bb2010-11-26 15:45:22 +0100217 ppcDcbf((u32)ecc_mem);
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500218 clear_and_enable_ecc();
219 value = in_be32(ecc_mem);
220 disable_ecc();
221 /* Test that the corrected data was read */
222 if (ECC_PATTERN_UNCORR != value) {
223 debug("Data read error (uncorrectable-error case): "
224 "expected 0x%08x, read 0x%08x\n", ECC_PATTERN_UNCORR,
225 value);
226 ret = 1;
227 }
228 value = get_ecc_status();
229 if ((DDR0_00_INT_STATUS_BIT4 | DDR0_00_INT_STATUS_BIT7) != value) {
230 /* Expected a single uncorrectable error reported */
231 debug("get_ecc_status(): expected 0x%08x, got 0x%08x\n",
232 DDR0_00_INT_STATUS_BIT4, value);
233 ret = 1;
234 }
235
236 /* Remove error from SDRAM and enable ECC. */
237 out_be32(ecc_mem, ECC_PATTERN);
Stefan Roese28e94bb2010-11-26 15:45:22 +0100238 ppcDcbf((u32)ecc_mem);
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500239 clear_and_enable_ecc();
240
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200241 return ret;
242}
243
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500244int ecc_post_test(int flags)
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200245{
246 int ret = 0;
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500247 uint32_t value;
248 uint32_t iaddr;
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200249
Larry Johnsona724a9b2007-10-27 12:48:15 -0400250 mfsdram(DDR0_22, value);
251 if (0x3 != DDR0_22_CTRL_RAW_DECODE(value)) {
252 debug("SDRAM ECC not enabled, skipping ECC POST.\n");
253 return 0;
254 }
255
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500256 /* Mask all interrupts. */
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200257 mfsdram(DDR0_01, value);
Larry Johnson0d9cdea2007-12-22 15:23:50 -0500258 mtsdram(DDR0_01, (value & ~DDR0_01_INT_MASK_MASK)
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200259 | DDR0_01_INT_MASK_ALL_OFF);
260
Larry Johnsona724a9b2007-10-27 12:48:15 -0400261 for (iaddr = ECC_START_ADDR; iaddr <= ECC_STOP_ADDR; iaddr += iaddr) {
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200262 ret = test_ecc(iaddr);
263 if (ret)
264 break;
265 }
Stefan Roeseea9f6bc2007-07-31 08:37:01 +0200266 /*
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500267 * Clear possible errors resulting from ECC testing. (If not done, we
268 * we could get an interrupt later on when exceptions are enabled.)
Stefan Roeseea9f6bc2007-07-31 08:37:01 +0200269 */
270 set_mcsr(get_mcsr());
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500271 debug("ecc_post_test() returning %d\n", ret);
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200272 return ret;
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200273}
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200274#endif /* CONFIG_POST & CONFIG_SYS_POST_ECC */
Yuri Tikhonov0a51e922008-03-31 10:49:34 +0200275#endif /* defined(CONFIG_440EPX) || defined(CONFIG_440GRX) */