blob: 6d146355956252c9aa3ef1a1fd79d8b4262f7f5f [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
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020038#if CONFIG_POST & CONFIG_SYS_POST_ECC
Pavel Kolesnikov5d896112007-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 Roese247e9d72010-09-09 19:18:00 +020048#include <asm/ppc440.h>
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020049
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);
Stefan Roese82f7c372010-11-26 15:45:22 +0100177 ppcDcbf((u32)ecc_mem);
Larry Johnson0e42c7c2008-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);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200185 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400186 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500187 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 }
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200194
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500195 /* Test for correctable error by creating a one-bit error */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400196 out_be32(ecc_mem, ECC_PATTERN_CORR);
Stefan Roese82f7c372010-11-26 15:45:22 +0100197 ppcDcbf((u32)ecc_mem);
Larry Johnson0e42c7c2008-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);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200205 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400206 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500207 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 }
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200214
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500215 /* Test for uncorrectable error by creating a two-bit error */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400216 out_be32(ecc_mem, ECC_PATTERN_UNCORR);
Stefan Roese82f7c372010-11-26 15:45:22 +0100217 ppcDcbf((u32)ecc_mem);
Larry Johnson0e42c7c2008-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);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200226 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400227 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500228 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. */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400237 out_be32(ecc_mem, ECC_PATTERN);
Stefan Roese82f7c372010-11-26 15:45:22 +0100238 ppcDcbf((u32)ecc_mem);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500239 clear_and_enable_ecc();
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200240
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200241 return ret;
242}
243
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500244int ecc_post_test(int flags)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200245{
246 int ret = 0;
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500247 uint32_t value;
248 uint32_t iaddr;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200249
Larry Johnson3d8ffb42007-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 Johnson0e42c7c2008-01-15 14:35:58 -0500256 /* Mask all interrupts. */
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200257 mfsdram(DDR0_01, value);
Larry Johnsone22b9a82007-12-22 15:23:50 -0500258 mtsdram(DDR0_01, (value & ~DDR0_01_INT_MASK_MASK)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200259 | DDR0_01_INT_MASK_ALL_OFF);
260
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400261 for (iaddr = ECC_START_ADDR; iaddr <= ECC_STOP_ADDR; iaddr += iaddr) {
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200262 ret = test_ecc(iaddr);
263 if (ret)
264 break;
265 }
Stefan Roese0dd0e642007-07-31 08:37:01 +0200266 /*
Larry Johnson0e42c7c2008-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 Roese0dd0e642007-07-31 08:37:01 +0200269 */
270 set_mcsr(get_mcsr());
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500271 debug("ecc_post_test() returning %d\n", ret);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200272 return ret;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200273}
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200274#endif /* CONFIG_POST & CONFIG_SYS_POST_ECC */
Yuri Tikhonovdffe4f92008-03-31 10:49:34 +0200275#endif /* defined(CONFIG_440EPX) || defined(CONFIG_440GRX) */