blob: 77234838d9b806b1cc44e23623e1e63197bbd099 [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
Larry Johnson3d8ffb42007-10-27 12:48:15 -040034#if defined(CONFIG_POST) && (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
52const static unsigned char 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
68#define ECC_PATTERN_UNCORR 0xF1010101
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020069
70static int test_ecc_error(void)
71{
72 unsigned long value;
73 unsigned long hdata, ldata, haddr, laddr;
74 unsigned int bit;
75
76 int ret = 0;
77
78 mfsdram(DDR0_23, value);
79
80 for (bit = 0; bit < sizeof(syndrome_codes); bit++)
81 if (syndrome_codes[bit] == ((value >> 16) & 0xff))
82 break;
83
84 mfsdram(DDR0_00, value);
85
86 if (value & DDR0_00_INT_STATUS_BIT0) {
87 debug("Bit0. A single access outside the defined PHYSICAL"
88 " memory space detected\n");
89 mfsdram(DDR0_32, laddr);
90 mfsdram(DDR0_33, haddr);
91 debug(" addr = 0x%08x%08x\n", haddr, laddr);
92 ret = 1;
93 }
94 if (value & DDR0_00_INT_STATUS_BIT1) {
95 debug("Bit1. Multiple accesses outside the defined PHYSICAL"
96 " memory space detected\n");
97 ret = 2;
98 }
99 if (value & DDR0_00_INT_STATUS_BIT2) {
100 debug("Bit2. Single correctable ECC event detected\n");
101 mfsdram(DDR0_38, laddr);
102 mfsdram(DDR0_39, haddr);
103 mfsdram(DDR0_40, ldata);
104 mfsdram(DDR0_41, hdata);
105 debug(" 0x%08x - 0x%08x%08x, bit - %d\n",
106 laddr, hdata, ldata, bit);
107 ret = 3;
108 }
109 if (value & DDR0_00_INT_STATUS_BIT3) {
110 debug("Bit3. Multiple correctable ECC events detected\n");
111 mfsdram(DDR0_38, laddr);
112 mfsdram(DDR0_39, haddr);
113 mfsdram(DDR0_40, ldata);
114 mfsdram(DDR0_41, hdata);
115 debug(" 0x%08x - 0x%08x%08x, bit - %d\n",
116 laddr, hdata, ldata, bit);
117 ret = 4;
118 }
119 if (value & DDR0_00_INT_STATUS_BIT4) {
120 debug("Bit4. Single uncorrectable ECC event detected\n");
121 mfsdram(DDR0_34, laddr);
122 mfsdram(DDR0_35, haddr);
123 mfsdram(DDR0_36, ldata);
124 mfsdram(DDR0_37, hdata);
125 debug(" 0x%08x - 0x%08x%08x, bit - %d\n",
126 laddr, hdata, ldata, bit);
127 ret = 5;
128 }
129 if (value & DDR0_00_INT_STATUS_BIT5) {
130 debug("Bit5. Multiple uncorrectable ECC events detected\n");
131 mfsdram(DDR0_34, laddr);
132 mfsdram(DDR0_35, haddr);
133 mfsdram(DDR0_36, ldata);
134 mfsdram(DDR0_37, hdata);
135 debug(" 0x%08x - 0x%08x%08x, bit - %d\n",
136 laddr, hdata, ldata, bit);
137 ret = 6;
138 }
139 if (value & DDR0_00_INT_STATUS_BIT6) {
140 debug("Bit6. DRAM initialization complete\n");
141 ret = 7;
142 }
143
144 /* error status cleared */
145 mfsdram(DDR0_00, value);
146 mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
147
148 return ret;
149}
150
151static int test_ecc(unsigned long ecc_addr)
152{
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200153 unsigned long value;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400154 volatile unsigned *const ecc_mem = (volatile unsigned *) ecc_addr;
155 int pret;
156 int ret = 0;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200157
158 sync();
159 eieio();
160 WATCHDOG_RESET();
161
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400162 debug("Entering test_ecc(0x%08lX)\n", ecc_addr);
163 out_be32(ecc_mem, ECC_PATTERN);
164 out_be32(ecc_mem + 1, ECC_PATTERN);
165 in_be32(ecc_mem);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200166 pret = test_ecc_error();
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400167 if (pret != 0) {
168 debug("pret: expected 0, got %d\n", pret);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200169 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400170 }
171 /* test for correctable error */
172 /* disconnect from ecc storage */
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200173 mfsdram(DDR0_22, value);
Larry Johnsone22b9a82007-12-22 15:23:50 -0500174 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200175 | DDR0_22_CTRL_RAW_ECC_DISABLE);
176
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400177 /* creating (correctable) single-bit error */
178 out_be32(ecc_mem, ECC_PATTERN_CORR);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200179
180 /* enable ecc */
181 mfsdram(DDR0_22, value);
Larry Johnsone22b9a82007-12-22 15:23:50 -0500182 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200183 | DDR0_22_CTRL_RAW_ECC_ENABLE);
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400184 sync();
185 eieio();
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200186
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400187 in_be32(ecc_mem);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200188 pret = test_ecc_error();
189 /* if read data ok, 1 correctable error must be fixed */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400190 if (pret != 3) {
191 debug("pret: expected 3, got %d\n", pret);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200192 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400193 }
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200194 /* test for uncorrectable error */
195 /* disconnect from ecc storage */
196 mfsdram(DDR0_22, value);
Larry Johnsone22b9a82007-12-22 15:23:50 -0500197 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200198 | DDR0_22_CTRL_RAW_NO_ECC_RAM);
199
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400200 /* creating (uncorrectable) multiple-bit error */
201 out_be32(ecc_mem, ECC_PATTERN_UNCORR);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200202
203 /* enable ecc */
204 mfsdram(DDR0_22, value);
Larry Johnsone22b9a82007-12-22 15:23:50 -0500205 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200206 | DDR0_22_CTRL_RAW_ECC_ENABLE);
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400207 sync();
208 eieio();
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200209
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400210 in_be32(ecc_mem);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200211 pret = test_ecc_error();
212 /* info about uncorrectable error must appear */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400213 if (pret != 5) {
214 debug("pret: expected 5, got %d\n", pret);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200215 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400216 }
217 /* remove error from SDRAM */
218 out_be32(ecc_mem, ECC_PATTERN);
219 /* clear error caused by read-modify-write */
220 mfsdram(DDR0_00, value);
221 mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200222
223 sync();
224 eieio();
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200225 return ret;
226}
227
228int ecc_post_test (int flags)
229{
230 int ret = 0;
231 unsigned long value;
232 unsigned long iaddr;
233
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200234 sync();
235 eieio();
236
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400237 mfsdram(DDR0_22, value);
238 if (0x3 != DDR0_22_CTRL_RAW_DECODE(value)) {
239 debug("SDRAM ECC not enabled, skipping ECC POST.\n");
240 return 0;
241 }
242
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200243 /* mask all int */
244 mfsdram(DDR0_01, value);
Larry Johnsone22b9a82007-12-22 15:23:50 -0500245 mtsdram(DDR0_01, (value & ~DDR0_01_INT_MASK_MASK)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200246 | DDR0_01_INT_MASK_ALL_OFF);
247
248 /* clear error status */
249 mfsdram(DDR0_00, value);
250 mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
251
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400252 for (iaddr = ECC_START_ADDR; iaddr <= ECC_STOP_ADDR; iaddr += iaddr) {
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200253 ret = test_ecc(iaddr);
254 if (ret)
255 break;
256 }
Stefan Roese0dd0e642007-07-31 08:37:01 +0200257 /*
258 * Clear possible errors resulting from ECC testing.
259 * If not done, then we could get an interrupt later on when
260 * exceptions are enabled.
261 */
262 set_mcsr(get_mcsr());
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200263 return ret;
264
265}
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200266#endif /* CONFIG_POST & CFG_POST_ECC */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400267#endif /* defined(CONFIG_POST) && ... */