]> git.ipfire.org Git - people/ms/u-boot.git/blame - post/cpu/ppc4xx/denali_ecc.c
rename CFG_ macros to CONFIG_SYS
[people/ms/u-boot.git] / post / cpu / ppc4xx / denali_ecc.c
CommitLineData
531e3e8b
PK
1/*
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
0a51e924 34#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
531e3e8b
PK
35
36#include <post.h>
37
6d0f6bcf 38#if CONFIG_POST & CONFIG_SYS_POST_ECC
531e3e8b
PK
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
531e3e8b
PK
50DECLARE_GLOBAL_DATA_PTR;
51
4b3cc6ec 52const static uint8_t syndrome_codes[] = {
0d9cdeac 53 0xF4, 0XF1, 0XEC, 0XEA, 0XE9, 0XE6, 0XE5, 0XE3,
531e3e8b
PK
54 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
a724a9b4
LJ
66#define ECC_PATTERN 0x01010101
67#define ECC_PATTERN_CORR 0x11010101
4b3cc6ec 68#define ECC_PATTERN_UNCORR 0x61010101
531e3e8b 69
4b3cc6ec 70inline static void disable_ecc(void)
531e3e8b 71{
4b3cc6ec 72 uint32_t value;
531e3e8b 73
4b3cc6ec
LJ
74 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}
531e3e8b 79
4b3cc6ec
LJ
80inline static void clear_and_enable_ecc(void)
81{
82 uint32_t value;
531e3e8b 83
4b3cc6ec 84 sync(); /* Wait for any pending memory accesses to complete. */
531e3e8b 85 mfsdram(DDR0_00, value);
4b3cc6ec
LJ
86 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}
91
92static 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;
531e3e8b 103
4b3cc6ec
LJ
104#if defined(DEBUG)
105 if (int_status & (DDR0_00_INT_STATUS_BIT0 | DDR0_00_INT_STATUS_BIT1)) {
531e3e8b
PK
106 mfsdram(DDR0_32, laddr);
107 mfsdram(DDR0_33, haddr);
4b3cc6ec
LJ
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);
531e3e8b 116 }
4b3cc6ec
LJ
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
531e3e8b
PK
126 mfsdram(DDR0_38, laddr);
127 mfsdram(DDR0_39, haddr);
4b3cc6ec 128 haddr &= 0x00000001;
531e3e8b
PK
129 mfsdram(DDR0_40, ldata);
130 mfsdram(DDR0_41, hdata);
4b3cc6ec
LJ
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);
531e3e8b 138 }
4b3cc6ec
LJ
139 if (int_status & (DDR0_00_INT_STATUS_BIT4 | DDR0_00_INT_STATUS_BIT5)) {
140 mfsdram(DDR0_23, value);
141 syndrome = (value >> 8) & 0xff;
531e3e8b
PK
142 mfsdram(DDR0_34, laddr);
143 mfsdram(DDR0_35, haddr);
4b3cc6ec 144 haddr &= 0x00000001;
531e3e8b
PK
145 mfsdram(DDR0_36, ldata);
146 mfsdram(DDR0_37, hdata);
4b3cc6ec
LJ
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);
531e3e8b 155 }
4b3cc6ec
LJ
156 if (int_status & DDR0_00_INT_STATUS_BIT6)
157 debug("DRAM initialization complete\n");
158#endif /* defined(DEBUG) */
531e3e8b 159
4b3cc6ec 160 return int_status;
531e3e8b
PK
161}
162
4b3cc6ec 163static int test_ecc(uint32_t ecc_addr)
531e3e8b 164{
4b3cc6ec
LJ
165 uint32_t value;
166 volatile uint32_t *const ecc_mem = (volatile uint32_t *)ecc_addr;
a724a9b4 167 int ret = 0;
531e3e8b 168
531e3e8b
PK
169 WATCHDOG_RESET();
170
4b3cc6ec
LJ
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();
a724a9b4
LJ
175 out_be32(ecc_mem, ECC_PATTERN);
176 out_be32(ecc_mem + 1, ECC_PATTERN);
4b3cc6ec
LJ
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);
531e3e8b 191 ret = 1;
a724a9b4 192 }
531e3e8b 193
4b3cc6ec 194 /* Test for correctable error by creating a one-bit error */
a724a9b4 195 out_be32(ecc_mem, ECC_PATTERN_CORR);
4b3cc6ec
LJ
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);
531e3e8b 210 ret = 1;
a724a9b4 211 }
531e3e8b 212
4b3cc6ec 213 /* Test for uncorrectable error by creating a two-bit error */
a724a9b4 214 out_be32(ecc_mem, ECC_PATTERN_UNCORR);
4b3cc6ec
LJ
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);
531e3e8b 230 ret = 1;
a724a9b4 231 }
4b3cc6ec
LJ
232
233 /* Remove error from SDRAM and enable ECC. */
a724a9b4 234 out_be32(ecc_mem, ECC_PATTERN);
4b3cc6ec 235 clear_and_enable_ecc();
531e3e8b 236
531e3e8b
PK
237 return ret;
238}
239
4b3cc6ec 240int ecc_post_test(int flags)
531e3e8b
PK
241{
242 int ret = 0;
4b3cc6ec
LJ
243 uint32_t value;
244 uint32_t iaddr;
531e3e8b 245
a724a9b4
LJ
246 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
4b3cc6ec 252 /* Mask all interrupts. */
531e3e8b 253 mfsdram(DDR0_01, value);
0d9cdeac 254 mtsdram(DDR0_01, (value & ~DDR0_01_INT_MASK_MASK)
531e3e8b
PK
255 | DDR0_01_INT_MASK_ALL_OFF);
256
a724a9b4 257 for (iaddr = ECC_START_ADDR; iaddr <= ECC_STOP_ADDR; iaddr += iaddr) {
531e3e8b
PK
258 ret = test_ecc(iaddr);
259 if (ret)
260 break;
261 }
ea9f6bce 262 /*
4b3cc6ec
LJ
263 * Clear possible errors resulting from ECC testing. (If not done, we
264 * we could get an interrupt later on when exceptions are enabled.)
ea9f6bce
SR
265 */
266 set_mcsr(get_mcsr());
4b3cc6ec 267 debug("ecc_post_test() returning %d\n", ret);
531e3e8b 268 return ret;
531e3e8b 269}
6d0f6bcf 270#endif /* CONFIG_POST & CONFIG_SYS_POST_ECC */
0a51e924 271#endif /* defined(CONFIG_440EPX) || defined(CONFIG_440GRX) */