blob: 1190739ae1a90964523b6964fcc8edcd7269af80 [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 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02007 * SPDX-License-Identifier: GPL-2.0+
Pavel Kolesnikov5d896112007-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 Tikhonovdffe4f92008-03-31 10:49:34 +020018#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020019
20#include <post.h>
21
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020022#if CONFIG_POST & CONFIG_SYS_POST_ECC
Pavel Kolesnikov5d896112007-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 Roese247e9d72010-09-09 19:18:00 +020032#include <asm/ppc440.h>
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020033
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020034DECLARE_GLOBAL_DATA_PTR;
35
Larry Johnson0e42c7c2008-01-15 14:35:58 -050036const static uint8_t syndrome_codes[] = {
Larry Johnsone22b9a82007-12-22 15:23:50 -050037 0xF4, 0XF1, 0XEC, 0XEA, 0XE9, 0XE6, 0XE5, 0XE3,
Pavel Kolesnikov5d896112007-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 Johnson3d8ffb42007-10-27 12:48:15 -040050#define ECC_PATTERN 0x01010101
51#define ECC_PATTERN_CORR 0x11010101
Larry Johnson0e42c7c2008-01-15 14:35:58 -050052#define ECC_PATTERN_UNCORR 0x61010101
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020053
Larry Johnson0e42c7c2008-01-15 14:35:58 -050054inline static void disable_ecc(void)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020055{
Larry Johnson0e42c7c2008-01-15 14:35:58 -050056 uint32_t value;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020057
Larry Johnson0e42c7c2008-01-15 14:35:58 -050058 sync(); /* Wait for any pending memory accesses to complete. */
59 mfsdram(DDR0_22, value);
60 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
61 | DDR0_22_CTRL_RAW_ECC_DISABLE);
62}
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020063
Larry Johnson0e42c7c2008-01-15 14:35:58 -050064inline static void clear_and_enable_ecc(void)
65{
66 uint32_t value;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020067
Larry Johnson0e42c7c2008-01-15 14:35:58 -050068 sync(); /* Wait for any pending memory accesses to complete. */
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020069 mfsdram(DDR0_00, value);
Larry Johnson0e42c7c2008-01-15 14:35:58 -050070 mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
71 mfsdram(DDR0_22, value);
72 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
73 | DDR0_22_CTRL_RAW_ECC_ENABLE);
74}
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020075
Larry Johnson0e42c7c2008-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)) {
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020090 mfsdram(DDR0_32, laddr);
91 mfsdram(DDR0_33, haddr);
Larry Johnson0e42c7c2008-01-15 14:35:58 -050092 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);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200100 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500101 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
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200110 mfsdram(DDR0_38, laddr);
111 mfsdram(DDR0_39, haddr);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500112 haddr &= 0x00000001;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200113 mfsdram(DDR0_40, ldata);
114 mfsdram(DDR0_41, hdata);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500115 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);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200122 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500123 if (int_status & (DDR0_00_INT_STATUS_BIT4 | DDR0_00_INT_STATUS_BIT5)) {
124 mfsdram(DDR0_23, value);
125 syndrome = (value >> 8) & 0xff;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200126 mfsdram(DDR0_34, laddr);
127 mfsdram(DDR0_35, haddr);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500128 haddr &= 0x00000001;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200129 mfsdram(DDR0_36, ldata);
130 mfsdram(DDR0_37, hdata);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500131 if (int_status & DDR0_00_INT_STATUS_BIT5)
132 debug("Multiple uncorrectable ECC events");
133 else
134 debug("Single uncorrectable ECC event");
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200135
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500136 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) */
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200143
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500144 return int_status;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200145}
146
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500147static int test_ecc(uint32_t ecc_addr)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200148{
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500149 uint32_t value;
150 volatile uint32_t *const ecc_mem = (volatile uint32_t *)ecc_addr;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400151 int ret = 0;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200152
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200153 WATCHDOG_RESET();
154
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500155 debug("Entering test_ecc(0x%08x)\n", ecc_addr);
156 /* Set up correct ECC in memory */
157 disable_ecc();
158 clear_and_enable_ecc();
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400159 out_be32(ecc_mem, ECC_PATTERN);
160 out_be32(ecc_mem + 1, ECC_PATTERN);
Stefan Roese82f7c372010-11-26 15:45:22 +0100161 ppcDcbf((u32)ecc_mem);
Larry Johnson0e42c7c2008-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);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200169 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400170 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500171 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 }
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200178
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500179 /* Test for correctable error by creating a one-bit error */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400180 out_be32(ecc_mem, ECC_PATTERN_CORR);
Stefan Roese82f7c372010-11-26 15:45:22 +0100181 ppcDcbf((u32)ecc_mem);
Larry Johnson0e42c7c2008-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);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200189 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400190 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500191 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 }
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200198
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500199 /* Test for uncorrectable error by creating a two-bit error */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400200 out_be32(ecc_mem, ECC_PATTERN_UNCORR);
Stefan Roese82f7c372010-11-26 15:45:22 +0100201 ppcDcbf((u32)ecc_mem);
Larry Johnson0e42c7c2008-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);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200210 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400211 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500212 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. */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400221 out_be32(ecc_mem, ECC_PATTERN);
Stefan Roese82f7c372010-11-26 15:45:22 +0100222 ppcDcbf((u32)ecc_mem);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500223 clear_and_enable_ecc();
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200224
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200225 return ret;
226}
227
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500228int ecc_post_test(int flags)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200229{
230 int ret = 0;
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500231 uint32_t value;
232 uint32_t iaddr;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200233
Larry Johnson3d8ffb42007-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 Johnson0e42c7c2008-01-15 14:35:58 -0500240 /* Mask all interrupts. */
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200241 mfsdram(DDR0_01, value);
Larry Johnsone22b9a82007-12-22 15:23:50 -0500242 mtsdram(DDR0_01, (value & ~DDR0_01_INT_MASK_MASK)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200243 | DDR0_01_INT_MASK_ALL_OFF);
244
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400245 for (iaddr = ECC_START_ADDR; iaddr <= ECC_STOP_ADDR; iaddr += iaddr) {
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200246 ret = test_ecc(iaddr);
247 if (ret)
248 break;
249 }
Stefan Roese0dd0e642007-07-31 08:37:01 +0200250 /*
Larry Johnson0e42c7c2008-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 Roese0dd0e642007-07-31 08:37:01 +0200253 */
254 set_mcsr(get_mcsr());
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500255 debug("ecc_post_test() returning %d\n", ret);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200256 return ret;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200257}
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200258#endif /* CONFIG_POST & CONFIG_SYS_POST_ECC */
Yuri Tikhonovdffe4f92008-03-31 10:49:34 +0200259#endif /* defined(CONFIG_440EPX) || defined(CONFIG_440GRX) */