blob: ad5e64fbb00827e721b1ea2765fb18cecea9bb35 [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
Tom Rini1eba7582017-06-16 13:06:27 -040036#if defined(DEBUG)
Larry Johnson0e42c7c2008-01-15 14:35:58 -050037const static uint8_t syndrome_codes[] = {
Larry Johnsone22b9a82007-12-22 15:23:50 -050038 0xF4, 0XF1, 0XEC, 0XEA, 0XE9, 0XE6, 0XE5, 0XE3,
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020039 0XDC, 0XDA, 0XD9, 0XD6, 0XD5, 0XD3, 0XCE, 0XCB,
40 0xB5, 0XB0, 0XAD, 0XAB, 0XA8, 0XA7, 0XA4, 0XA2,
41 0X9D, 0X9B, 0X98, 0X97, 0X94, 0X92, 0X8F, 0X8A,
42 0x75, 0x70, 0X6D, 0X6B, 0X68, 0X67, 0X64, 0X62,
43 0X5E, 0X5B, 0X58, 0X57, 0X54, 0X52, 0X4F, 0X4A,
44 0x34, 0x31, 0X2C, 0X2A, 0X29, 0X26, 0X25, 0X23,
45 0X1C, 0X1A, 0X19, 0X16, 0X15, 0X13, 0X0E, 0X0B,
46 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
47};
Tom Rini1eba7582017-06-16 13:06:27 -040048#endif
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020049
50#define ECC_START_ADDR 0x10
51#define ECC_STOP_ADDR 0x2000
Larry Johnson3d8ffb42007-10-27 12:48:15 -040052#define ECC_PATTERN 0x01010101
53#define ECC_PATTERN_CORR 0x11010101
Larry Johnson0e42c7c2008-01-15 14:35:58 -050054#define ECC_PATTERN_UNCORR 0x61010101
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020055
Larry Johnson0e42c7c2008-01-15 14:35:58 -050056inline static void disable_ecc(void)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020057{
Larry Johnson0e42c7c2008-01-15 14:35:58 -050058 uint32_t value;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020059
Larry Johnson0e42c7c2008-01-15 14:35:58 -050060 sync(); /* Wait for any pending memory accesses to complete. */
61 mfsdram(DDR0_22, value);
62 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
63 | DDR0_22_CTRL_RAW_ECC_DISABLE);
64}
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020065
Larry Johnson0e42c7c2008-01-15 14:35:58 -050066inline static void clear_and_enable_ecc(void)
67{
68 uint32_t value;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020069
Larry Johnson0e42c7c2008-01-15 14:35:58 -050070 sync(); /* Wait for any pending memory accesses to complete. */
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020071 mfsdram(DDR0_00, value);
Larry Johnson0e42c7c2008-01-15 14:35:58 -050072 mtsdram(DDR0_00, value | DDR0_00_INT_ACK_ALL);
73 mfsdram(DDR0_22, value);
74 mtsdram(DDR0_22, (value & ~DDR0_22_CTRL_RAW_MASK)
75 | DDR0_22_CTRL_RAW_ECC_ENABLE);
76}
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020077
Larry Johnson0e42c7c2008-01-15 14:35:58 -050078static uint32_t get_ecc_status(void)
79{
80 uint32_t int_status;
81#if defined(DEBUG)
82 uint8_t syndrome;
83 uint32_t hdata, ldata, haddr, laddr;
84 uint32_t value;
85#endif
86
87 mfsdram(DDR0_00, int_status);
88 int_status &= DDR0_00_INT_STATUS_MASK;
89
90#if defined(DEBUG)
91 if (int_status & (DDR0_00_INT_STATUS_BIT0 | DDR0_00_INT_STATUS_BIT1)) {
Pavel Kolesnikov5d896112007-07-20 15:03:03 +020092 mfsdram(DDR0_32, laddr);
93 mfsdram(DDR0_33, haddr);
Larry Johnson0e42c7c2008-01-15 14:35:58 -050094 haddr &= 0x00000001;
95 if (int_status & DDR0_00_INT_STATUS_BIT1)
96 debug("Multiple accesses");
97 else
98 debug("A single access");
99
100 debug(" outside the defined physical memory space detected\n"
101 " addr = 0x%01x%08x\n", haddr, laddr);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200102 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500103 if (int_status & (DDR0_00_INT_STATUS_BIT2 | DDR0_00_INT_STATUS_BIT3)) {
104 unsigned int bit;
105
106 mfsdram(DDR0_23, value);
107 syndrome = (value >> 16) & 0xff;
108 for (bit = 0; bit < sizeof(syndrome_codes); bit++)
109 if (syndrome_codes[bit] == syndrome)
110 break;
111
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200112 mfsdram(DDR0_38, laddr);
113 mfsdram(DDR0_39, haddr);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500114 haddr &= 0x00000001;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200115 mfsdram(DDR0_40, ldata);
116 mfsdram(DDR0_41, hdata);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500117 if (int_status & DDR0_00_INT_STATUS_BIT3)
118 debug("Multiple correctable ECC events");
119 else
120 debug("Single correctable ECC event");
121
122 debug(" detected\n 0x%01x%08x - 0x%08x%08x, bit - %d\n",
123 haddr, laddr, hdata, ldata, bit);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200124 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500125 if (int_status & (DDR0_00_INT_STATUS_BIT4 | DDR0_00_INT_STATUS_BIT5)) {
126 mfsdram(DDR0_23, value);
127 syndrome = (value >> 8) & 0xff;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200128 mfsdram(DDR0_34, laddr);
129 mfsdram(DDR0_35, haddr);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500130 haddr &= 0x00000001;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200131 mfsdram(DDR0_36, ldata);
132 mfsdram(DDR0_37, hdata);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500133 if (int_status & DDR0_00_INT_STATUS_BIT5)
134 debug("Multiple uncorrectable ECC events");
135 else
136 debug("Single uncorrectable ECC event");
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200137
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500138 debug(" detected\n 0x%01x%08x - 0x%08x%08x, "
139 "syndrome - 0x%02x\n",
140 haddr, laddr, hdata, ldata, syndrome);
141 }
142 if (int_status & DDR0_00_INT_STATUS_BIT6)
143 debug("DRAM initialization complete\n");
144#endif /* defined(DEBUG) */
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200145
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500146 return int_status;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200147}
148
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500149static int test_ecc(uint32_t ecc_addr)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200150{
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500151 uint32_t value;
152 volatile uint32_t *const ecc_mem = (volatile uint32_t *)ecc_addr;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400153 int ret = 0;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200154
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200155 WATCHDOG_RESET();
156
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500157 debug("Entering test_ecc(0x%08x)\n", ecc_addr);
158 /* Set up correct ECC in memory */
159 disable_ecc();
160 clear_and_enable_ecc();
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400161 out_be32(ecc_mem, ECC_PATTERN);
162 out_be32(ecc_mem + 1, ECC_PATTERN);
Stefan Roese82f7c372010-11-26 15:45:22 +0100163 ppcDcbf((u32)ecc_mem);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500164
165 /* Verify no ECC error reading back */
166 value = in_be32(ecc_mem);
167 disable_ecc();
168 if (ECC_PATTERN != value) {
169 debug("Data read error (no-error case): "
170 "expected 0x%08x, read 0x%08x\n", ECC_PATTERN, value);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200171 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400172 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500173 value = get_ecc_status();
174 if (0x00000000 != value) {
175 /* Expected no ECC status reported */
176 debug("get_ecc_status(): expected 0x%08x, got 0x%08x\n",
177 0x00000000, value);
178 ret = 1;
179 }
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200180
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500181 /* Test for correctable error by creating a one-bit error */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400182 out_be32(ecc_mem, ECC_PATTERN_CORR);
Stefan Roese82f7c372010-11-26 15:45:22 +0100183 ppcDcbf((u32)ecc_mem);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500184 clear_and_enable_ecc();
185 value = in_be32(ecc_mem);
186 disable_ecc();
187 /* Test that the corrected data was read */
188 if (ECC_PATTERN != value) {
189 debug("Data read error (correctable-error case): "
190 "expected 0x%08x, read 0x%08x\n", ECC_PATTERN, value);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200191 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400192 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500193 value = get_ecc_status();
194 if ((DDR0_00_INT_STATUS_BIT2 | DDR0_00_INT_STATUS_BIT7) != value) {
195 /* Expected a single correctable error reported */
196 debug("get_ecc_status(): expected 0x%08x, got 0x%08x\n",
197 DDR0_00_INT_STATUS_BIT2, value);
198 ret = 1;
199 }
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200200
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500201 /* Test for uncorrectable error by creating a two-bit error */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400202 out_be32(ecc_mem, ECC_PATTERN_UNCORR);
Stefan Roese82f7c372010-11-26 15:45:22 +0100203 ppcDcbf((u32)ecc_mem);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500204 clear_and_enable_ecc();
205 value = in_be32(ecc_mem);
206 disable_ecc();
207 /* Test that the corrected data was read */
208 if (ECC_PATTERN_UNCORR != value) {
209 debug("Data read error (uncorrectable-error case): "
210 "expected 0x%08x, read 0x%08x\n", ECC_PATTERN_UNCORR,
211 value);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200212 ret = 1;
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400213 }
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500214 value = get_ecc_status();
215 if ((DDR0_00_INT_STATUS_BIT4 | DDR0_00_INT_STATUS_BIT7) != value) {
216 /* Expected a single uncorrectable error reported */
217 debug("get_ecc_status(): expected 0x%08x, got 0x%08x\n",
218 DDR0_00_INT_STATUS_BIT4, value);
219 ret = 1;
220 }
221
222 /* Remove error from SDRAM and enable ECC. */
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400223 out_be32(ecc_mem, ECC_PATTERN);
Stefan Roese82f7c372010-11-26 15:45:22 +0100224 ppcDcbf((u32)ecc_mem);
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500225 clear_and_enable_ecc();
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200226
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200227 return ret;
228}
229
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500230int ecc_post_test(int flags)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200231{
232 int ret = 0;
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500233 uint32_t value;
234 uint32_t iaddr;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200235
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400236 mfsdram(DDR0_22, value);
237 if (0x3 != DDR0_22_CTRL_RAW_DECODE(value)) {
238 debug("SDRAM ECC not enabled, skipping ECC POST.\n");
239 return 0;
240 }
241
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500242 /* Mask all interrupts. */
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200243 mfsdram(DDR0_01, value);
Larry Johnsone22b9a82007-12-22 15:23:50 -0500244 mtsdram(DDR0_01, (value & ~DDR0_01_INT_MASK_MASK)
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200245 | DDR0_01_INT_MASK_ALL_OFF);
246
Larry Johnson3d8ffb42007-10-27 12:48:15 -0400247 for (iaddr = ECC_START_ADDR; iaddr <= ECC_STOP_ADDR; iaddr += iaddr) {
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200248 ret = test_ecc(iaddr);
249 if (ret)
250 break;
251 }
Stefan Roese0dd0e642007-07-31 08:37:01 +0200252 /*
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500253 * Clear possible errors resulting from ECC testing. (If not done, we
254 * we could get an interrupt later on when exceptions are enabled.)
Stefan Roese0dd0e642007-07-31 08:37:01 +0200255 */
256 set_mcsr(get_mcsr());
Larry Johnson0e42c7c2008-01-15 14:35:58 -0500257 debug("ecc_post_test() returning %d\n", ret);
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200258 return ret;
Pavel Kolesnikov5d896112007-07-20 15:03:03 +0200259}
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200260#endif /* CONFIG_POST & CONFIG_SYS_POST_ECC */
Yuri Tikhonovdffe4f92008-03-31 10:49:34 +0200261#endif /* defined(CONFIG_440EPX) || defined(CONFIG_440GRX) */