blob: 1190739ae1a90964523b6964fcc8edcd7269af80 [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 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02007 * SPDX-License-Identifier: GPL-2.0+
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +02008 */
9
10/* define DEBUG for debugging output (obviously ;-)) */
11#if 0
12#define DEBUG
13#endif
14
15#include <common.h>
16#include <watchdog.h>
17
Yuri Tikhonov0a51e922008-03-31 10:49:34 +020018#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020019
20#include <post.h>
21
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020022#if CONFIG_POST & CONFIG_SYS_POST_ECC
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020023
24/*
25 * MEMORY ECC test
26 *
27 * This test performs the checks ECC facility of memory.
28 */
29#include <asm/processor.h>
30#include <asm/mmu.h>
31#include <asm/io.h>
Stefan Roeseb36df562010-09-09 19:18:00 +020032#include <asm/ppc440.h>
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020033
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020034DECLARE_GLOBAL_DATA_PTR;
35
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050036const static uint8_t syndrome_codes[] = {
Larry Johnson0d9cdea2007-12-22 15:23:50 -050037 0xF4, 0XF1, 0XEC, 0XEA, 0XE9, 0XE6, 0XE5, 0XE3,
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020038 0XDC, 0XDA, 0XD9, 0XD6, 0XD5, 0XD3, 0XCE, 0XCB,
39 0xB5, 0XB0, 0XAD, 0XAB, 0XA8, 0XA7, 0XA4, 0XA2,
40 0X9D, 0X9B, 0X98, 0X97, 0X94, 0X92, 0X8F, 0X8A,
41 0x75, 0x70, 0X6D, 0X6B, 0X68, 0X67, 0X64, 0X62,
42 0X5E, 0X5B, 0X58, 0X57, 0X54, 0X52, 0X4F, 0X4A,
43 0x34, 0x31, 0X2C, 0X2A, 0X29, 0X26, 0X25, 0X23,
44 0X1C, 0X1A, 0X19, 0X16, 0X15, 0X13, 0X0E, 0X0B,
45 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
46};
47
48#define ECC_START_ADDR 0x10
49#define ECC_STOP_ADDR 0x2000
Larry Johnsona724a9b2007-10-27 12:48:15 -040050#define ECC_PATTERN 0x01010101
51#define ECC_PATTERN_CORR 0x11010101
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050052#define ECC_PATTERN_UNCORR 0x61010101
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020053
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050054inline static void disable_ecc(void)
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020055{
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050056 uint32_t value;
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020057
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050058 sync(); /* Wait for any pending memory accesses to complete. */
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020059 mfsdram(DDR0_22, value);
Larry Johnson0d9cdea2007-12-22 15:23:50 -050060 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020061 | DDR0_22_CTRL_RAW_ECC_DISABLE);
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050062}
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020063
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050064inline static void clear_and_enable_ecc(void)
65{
66 uint32_t value;
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +020067
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050068 sync(); /* Wait for any pending memory accesses to complete. */
Larry Johnsona724a9b2007-10-27 12:48:15 -040069 mfsdram(DDR0_00, value);
70 mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050071 mfsdram(DDR0_22, value);
72 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
73 | DDR0_22_CTRL_RAW_ECC_ENABLE);
74}
Larry Johnsona724a9b2007-10-27 12:48:15 -040075
Larry Johnson4b3cc6e2008-01-15 14:35:58 -050076static uint32_t get_ecc_status(void)
77{
78 uint32_t int_status;
79#if defined(DEBUG)
80 uint8_t syndrome;
81 uint32_t hdata, ldata, haddr, laddr;
82 uint32_t value;
83#endif
84
85 mfsdram(DDR0_00, int_status);
86 int_status &= DDR0_00_INT_STATUS_MASK;
87
88#if defined(DEBUG)
89 if (int_status & (DDR0_00_INT_STATUS_BIT0 | DDR0_00_INT_STATUS_BIT1)) {
90 mfsdram(DDR0_32, laddr);
91 mfsdram(DDR0_33, haddr);
92 haddr &= 0x00000001;
93 if (int_status & DDR0_00_INT_STATUS_BIT1)
94 debug("Multiple accesses");
95 else
96 debug("A single access");
97
98 debug(" outside the defined physical memory space detected\n"
99 " addr = 0x%01x%08x\n", haddr, laddr);
100 }
101 if (int_status & (DDR0_00_INT_STATUS_BIT2 | DDR0_00_INT_STATUS_BIT3)) {
102 unsigned int bit;
103
104 mfsdram(DDR0_23, value);
105 syndrome = (value >> 16) & 0xff;
106 for (bit = 0; bit < sizeof(syndrome_codes); bit++)
107 if (syndrome_codes[bit] == syndrome)
108 break;
109
110 mfsdram(DDR0_38, laddr);
111 mfsdram(DDR0_39, haddr);
112 haddr &= 0x00000001;
113 mfsdram(DDR0_40, ldata);
114 mfsdram(DDR0_41, hdata);
115 if (int_status & DDR0_00_INT_STATUS_BIT3)
116 debug("Multiple correctable ECC events");
117 else
118 debug("Single correctable ECC event");
119
120 debug(" detected\n 0x%01x%08x - 0x%08x%08x, bit - %d\n",
121 haddr, laddr, hdata, ldata, bit);
122 }
123 if (int_status & (DDR0_00_INT_STATUS_BIT4 | DDR0_00_INT_STATUS_BIT5)) {
124 mfsdram(DDR0_23, value);
125 syndrome = (value >> 8) & 0xff;
126 mfsdram(DDR0_34, laddr);
127 mfsdram(DDR0_35, haddr);
128 haddr &= 0x00000001;
129 mfsdram(DDR0_36, ldata);
130 mfsdram(DDR0_37, hdata);
131 if (int_status & DDR0_00_INT_STATUS_BIT5)
132 debug("Multiple uncorrectable ECC events");
133 else
134 debug("Single uncorrectable ECC event");
135
136 debug(" detected\n 0x%01x%08x - 0x%08x%08x, "
137 "syndrome - 0x%02x\n",
138 haddr, laddr, hdata, ldata, syndrome);
139 }
140 if (int_status & DDR0_00_INT_STATUS_BIT6)
141 debug("DRAM initialization complete\n");
142#endif /* defined(DEBUG) */
143
144 return int_status;
145}
146
147static int test_ecc(uint32_t ecc_addr)
148{
149 uint32_t value;
150 volatile uint32_t *const ecc_mem = (volatile uint32_t *)ecc_addr;
151 int ret = 0;
152
153 WATCHDOG_RESET();
154
155 debug("Entering test_ecc(0x%08x)\n", ecc_addr);
156 /* Set up correct ECC in memory */
157 disable_ecc();
158 clear_and_enable_ecc();
159 out_be32(ecc_mem, ECC_PATTERN);
160 out_be32(ecc_mem + 1, ECC_PATTERN);
Stefan Roese28e94bb2010-11-26 15:45:22 +0100161 ppcDcbf((u32)ecc_mem);
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500162
163 /* Verify no ECC error reading back */
164 value = in_be32(ecc_mem);
165 disable_ecc();
166 if (ECC_PATTERN != value) {
167 debug("Data read error (no-error case): "
168 "expected 0x%08x, read 0x%08x\n", ECC_PATTERN, value);
169 ret = 1;
170 }
171 value = get_ecc_status();
172 if (0x00000000 != value) {
173 /* Expected no ECC status reported */
174 debug("get_ecc_status(): expected 0x%08x, got 0x%08x\n",
175 0x00000000, value);
176 ret = 1;
177 }
178
179 /* Test for correctable error by creating a one-bit error */
180 out_be32(ecc_mem, ECC_PATTERN_CORR);
Stefan Roese28e94bb2010-11-26 15:45:22 +0100181 ppcDcbf((u32)ecc_mem);
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500182 clear_and_enable_ecc();
183 value = in_be32(ecc_mem);
184 disable_ecc();
185 /* Test that the corrected data was read */
186 if (ECC_PATTERN != value) {
187 debug("Data read error (correctable-error case): "
188 "expected 0x%08x, read 0x%08x\n", ECC_PATTERN, value);
189 ret = 1;
190 }
191 value = get_ecc_status();
192 if ((DDR0_00_INT_STATUS_BIT2 | DDR0_00_INT_STATUS_BIT7) != value) {
193 /* Expected a single correctable error reported */
194 debug("get_ecc_status(): expected 0x%08x, got 0x%08x\n",
195 DDR0_00_INT_STATUS_BIT2, value);
196 ret = 1;
197 }
198
199 /* Test for uncorrectable error by creating a two-bit error */
200 out_be32(ecc_mem, ECC_PATTERN_UNCORR);
Stefan Roese28e94bb2010-11-26 15:45:22 +0100201 ppcDcbf((u32)ecc_mem);
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500202 clear_and_enable_ecc();
203 value = in_be32(ecc_mem);
204 disable_ecc();
205 /* Test that the corrected data was read */
206 if (ECC_PATTERN_UNCORR != value) {
207 debug("Data read error (uncorrectable-error case): "
208 "expected 0x%08x, read 0x%08x\n", ECC_PATTERN_UNCORR,
209 value);
210 ret = 1;
211 }
212 value = get_ecc_status();
213 if ((DDR0_00_INT_STATUS_BIT4 | DDR0_00_INT_STATUS_BIT7) != value) {
214 /* Expected a single uncorrectable error reported */
215 debug("get_ecc_status(): expected 0x%08x, got 0x%08x\n",
216 DDR0_00_INT_STATUS_BIT4, value);
217 ret = 1;
218 }
219
220 /* Remove error from SDRAM and enable ECC. */
221 out_be32(ecc_mem, ECC_PATTERN);
Stefan Roese28e94bb2010-11-26 15:45:22 +0100222 ppcDcbf((u32)ecc_mem);
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500223 clear_and_enable_ecc();
224
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200225 return ret;
226}
227
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500228int ecc_post_test(int flags)
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200229{
230 int ret = 0;
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500231 uint32_t value;
232 uint32_t iaddr;
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200233
Larry Johnsona724a9b2007-10-27 12:48:15 -0400234 mfsdram(DDR0_22, value);
235 if (0x3 != DDR0_22_CTRL_RAW_DECODE(value)) {
236 debug("SDRAM ECC not enabled, skipping ECC POST.\n");
237 return 0;
238 }
239
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500240 /* Mask all interrupts. */
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200241 mfsdram(DDR0_01, value);
Larry Johnson0d9cdea2007-12-22 15:23:50 -0500242 mtsdram(DDR0_01, (value & ~DDR0_01_INT_MASK_MASK)
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200243 | DDR0_01_INT_MASK_ALL_OFF);
244
Larry Johnsona724a9b2007-10-27 12:48:15 -0400245 for (iaddr = ECC_START_ADDR; iaddr <= ECC_STOP_ADDR; iaddr += iaddr) {
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200246 ret = test_ecc(iaddr);
247 if (ret)
248 break;
249 }
Stefan Roeseea9f6bc2007-07-31 08:37:01 +0200250 /*
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500251 * Clear possible errors resulting from ECC testing. (If not done, we
252 * we could get an interrupt later on when exceptions are enabled.)
Stefan Roeseea9f6bc2007-07-31 08:37:01 +0200253 */
254 set_mcsr(get_mcsr());
Larry Johnson4b3cc6e2008-01-15 14:35:58 -0500255 debug("ecc_post_test() returning %d\n", ret);
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200256 return ret;
Pavel Kolesnikov531e3e82007-07-20 15:03:03 +0200257}
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200258#endif /* CONFIG_POST & CONFIG_SYS_POST_ECC */
Yuri Tikhonov0a51e922008-03-31 10:49:34 +0200259#endif /* defined(CONFIG_440EPX) || defined(CONFIG_440GRX) */