blob: 12a1bbfa87686f99c516d7bddd1bb500bc55877f [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
Yuri Tikhonovdffe4f92008-03-31 10:49:34 +020034#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020035
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
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020050DECLARE_GLOBAL_DATA_PTR;
51
Larry Johnson0e42c7c2008-01-15 14:35:58 -050052const static uint8_t syndrome_codes[] = {
Larry Johnsone22b9a82007-12-22 15:23:50 -050053 0xF4, 0XF1, 0XEC, 0XEA, 0XE9, 0XE6, 0XE5, 0XE3,
Pavel Kolesnikov5d896112007-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 Johnson3d8ffb42007-10-27 12:48:15 -040066#define ECC_PATTERN 0x01010101
67#define ECC_PATTERN_CORR 0x11010101
Larry Johnson0e42c7c2008-01-15 14:35:58 -050068#define ECC_PATTERN_UNCORR 0x61010101
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020069
Larry Johnson0e42c7c2008-01-15 14:35:58 -050070inline static void disable_ecc(void)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020071{
Larry Johnson0e42c7c2008-01-15 14:35:58 -050072 uint32_t value;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020073
Larry Johnson0e42c7c2008-01-15 14:35:58 -050074 sync(); /* Wait for any pending memory accesses to complete. */
75 mfsdram(DDR0_22, value);
76 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
77 | DDR0_22_CTRL_RAW_ECC_DISABLE);
78}
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020079
Larry Johnson0e42c7c2008-01-15 14:35:58 -050080inline static void clear_and_enable_ecc(void)
81{
82 uint32_t value;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020083
Larry Johnson0e42c7c2008-01-15 14:35:58 -050084 sync(); /* Wait for any pending memory accesses to complete. */
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020085 mfsdram(DDR0_00, value);
Larry Johnson0e42c7c2008-01-15 14:35:58 -050086 mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
87 mfsdram(DDR0_22, value);
88 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
89 | DDR0_22_CTRL_RAW_ECC_ENABLE);
90}
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020091
Larry Johnson0e42c7c2008-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)) {
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200106 mfsdram(DDR0_32, laddr);
107 mfsdram(DDR0_33, haddr);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500108 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);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200116 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500117 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
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200126 mfsdram(DDR0_38, laddr);
127 mfsdram(DDR0_39, haddr);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500128 haddr &= 0x00000001;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200129 mfsdram(DDR0_40, ldata);
130 mfsdram(DDR0_41, hdata);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500131 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);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200138 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500139 if (int_status & (DDR0_00_INT_STATUS_BIT4 | DDR0_00_INT_STATUS_BIT5)) {
140 mfsdram(DDR0_23, value);
141 syndrome = (value >> 8) & 0xff;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200142 mfsdram(DDR0_34, laddr);
143 mfsdram(DDR0_35, haddr);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500144 haddr &= 0x00000001;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200145 mfsdram(DDR0_36, ldata);
146 mfsdram(DDR0_37, hdata);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500147 if (int_status & DDR0_00_INT_STATUS_BIT5)
148 debug("Multiple uncorrectable ECC events");
149 else
150 debug("Single uncorrectable ECC event");
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200151
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500152 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) */
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200159
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500160 return int_status;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200161}
162
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500163static int test_ecc(uint32_t ecc_addr)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200164{
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500165 uint32_t value;
166 volatile uint32_t *const ecc_mem = (volatile uint32_t *)ecc_addr;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400167 int ret = 0;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200168
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200169 WATCHDOG_RESET();
170
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500171 debug("Entering test_ecc(0x%08x)\n", ecc_addr);
172 /* Set up correct ECC in memory */
173 disable_ecc();
174 clear_and_enable_ecc();
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400175 out_be32(ecc_mem, ECC_PATTERN);
176 out_be32(ecc_mem + 1, ECC_PATTERN);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500177
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);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200184 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400185 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500186 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 }
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200193
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500194 /* Test for correctable error by creating a one-bit error */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400195 out_be32(ecc_mem, ECC_PATTERN_CORR);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500196 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);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200203 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400204 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500205 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 }
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200212
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500213 /* Test for uncorrectable error by creating a two-bit error */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400214 out_be32(ecc_mem, ECC_PATTERN_UNCORR);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500215 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);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200223 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400224 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500225 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. */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400234 out_be32(ecc_mem, ECC_PATTERN);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500235 clear_and_enable_ecc();
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200236
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200237 return ret;
238}
239
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500240int ecc_post_test(int flags)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200241{
242 int ret = 0;
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500243 uint32_t value;
244 uint32_t iaddr;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200245
Larry Johnson3d8ffb42007-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 Johnson0e42c7c2008-01-15 14:35:58 -0500252 /* Mask all interrupts. */
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200253 mfsdram(DDR0_01, value);
Larry Johnsone22b9a82007-12-22 15:23:50 -0500254 mtsdram(DDR0_01, (value & ~DDR0_01_INT_MASK_MASK)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200255 | DDR0_01_INT_MASK_ALL_OFF);
256
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400257 for (iaddr = ECC_START_ADDR; iaddr <= ECC_STOP_ADDR; iaddr += iaddr) {
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200258 ret = test_ecc(iaddr);
259 if (ret)
260 break;
261 }
Stefan Roese0dd0e642007-07-31 08:37:01 +0200262 /*
Larry Johnson0e42c7c2008-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 Roese0dd0e642007-07-31 08:37:01 +0200265 */
266 set_mcsr(get_mcsr());
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500267 debug("ecc_post_test() returning %d\n", ret);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200268 return ret;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200269}
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200270#endif /* CONFIG_POST & CFG_POST_ECC */
Yuri Tikhonovdffe4f92008-03-31 10:49:34 +0200271#endif /* defined(CONFIG_440EPX) || defined(CONFIG_440GRX) */