blob: b82cbe152dc93361f5ea2ceace7db4c36aa1ac6e [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Hao Zhang26459482014-10-22 17:47:59 +03002/*
Lokesh Vutla5cd96612017-12-29 11:47:49 +05303 * EMIF: DDR3 test commands
Hao Zhang26459482014-10-22 17:47:59 +03004 *
Lokesh Vutla5cd96612017-12-29 11:47:49 +05305 * Copyright (C) 2012-2017 Texas Instruments Incorporated, <www.ti.com>
Hao Zhang26459482014-10-22 17:47:59 +03006 */
7
8#include <asm/arch/hardware.h>
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +05309#include <asm/cache.h>
10#include <asm/emif.h>
Hao Zhang26459482014-10-22 17:47:59 +030011#include <common.h>
12#include <command.h>
13
14DECLARE_GLOBAL_DATA_PTR;
15
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +053016#ifdef CONFIG_ARCH_KEYSTONE
17#include <asm/arch/ddr3.h>
Hao Zhang26459482014-10-22 17:47:59 +030018#define DDR_MIN_ADDR CONFIG_SYS_SDRAM_BASE
Tom Rini01abae42017-04-06 20:42:18 -040019#define STACKSIZE (512 << 10) /* 512 KiB */
Hao Zhang26459482014-10-22 17:47:59 +030020
21#define DDR_REMAP_ADDR 0x80000000
22#define ECC_START_ADDR1 ((DDR_MIN_ADDR - DDR_REMAP_ADDR) >> 17)
23
24#define ECC_END_ADDR1 (((gd->start_addr_sp - DDR_REMAP_ADDR - \
Tom Rini01abae42017-04-06 20:42:18 -040025 STACKSIZE) >> 17) - 2)
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +053026#endif
Hao Zhang26459482014-10-22 17:47:59 +030027
28#define DDR_TEST_BURST_SIZE 1024
29
30static int ddr_memory_test(u32 start_address, u32 end_address, int quick)
31{
32 u32 index_start, value, index;
33
34 index_start = start_address;
35
36 while (1) {
37 /* Write a pattern */
38 for (index = index_start;
39 index < index_start + DDR_TEST_BURST_SIZE;
40 index += 4)
41 __raw_writel(index, index);
42
43 /* Read and check the pattern */
44 for (index = index_start;
45 index < index_start + DDR_TEST_BURST_SIZE;
46 index += 4) {
47 value = __raw_readl(index);
48 if (value != index) {
49 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
50 index, value, __raw_readl(index));
51
52 return -1;
53 }
54 }
55
56 index_start += DDR_TEST_BURST_SIZE;
57 if (index_start >= end_address)
58 break;
59
60 if (quick)
61 continue;
62
63 /* Write a pattern for complementary values */
64 for (index = index_start;
65 index < index_start + DDR_TEST_BURST_SIZE;
66 index += 4)
67 __raw_writel((u32)~index, index);
68
69 /* Read and check the pattern */
70 for (index = index_start;
71 index < index_start + DDR_TEST_BURST_SIZE;
72 index += 4) {
73 value = __raw_readl(index);
74 if (value != ~index) {
75 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
76 index, value, __raw_readl(index));
77
78 return -1;
79 }
80 }
81
82 index_start += DDR_TEST_BURST_SIZE;
83 if (index_start >= end_address)
84 break;
85
86 /* Write a pattern */
87 for (index = index_start;
88 index < index_start + DDR_TEST_BURST_SIZE;
89 index += 2)
90 __raw_writew((u16)index, index);
91
92 /* Read and check the pattern */
93 for (index = index_start;
94 index < index_start + DDR_TEST_BURST_SIZE;
95 index += 2) {
96 value = __raw_readw(index);
97 if (value != (u16)index) {
98 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
99 index, value, __raw_readw(index));
100
101 return -1;
102 }
103 }
104
105 index_start += DDR_TEST_BURST_SIZE;
106 if (index_start >= end_address)
107 break;
108
109 /* Write a pattern */
110 for (index = index_start;
111 index < index_start + DDR_TEST_BURST_SIZE;
112 index += 1)
113 __raw_writeb((u8)index, index);
114
115 /* Read and check the pattern */
116 for (index = index_start;
117 index < index_start + DDR_TEST_BURST_SIZE;
118 index += 1) {
119 value = __raw_readb(index);
120 if (value != (u8)index) {
121 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
122 index, value, __raw_readb(index));
123
124 return -1;
125 }
126 }
127
128 index_start += DDR_TEST_BURST_SIZE;
129 if (index_start >= end_address)
130 break;
131 }
132
133 puts("ddr memory test PASSED!\n");
134 return 0;
135}
136
137static int ddr_memory_compare(u32 address1, u32 address2, u32 size)
138{
139 u32 index, value, index2, value2;
140
141 for (index = address1, index2 = address2;
142 index < address1 + size;
143 index += 4, index2 += 4) {
144 value = __raw_readl(index);
145 value2 = __raw_readl(index2);
146
147 if (value != value2) {
148 printf("ddr_memory_test: Compare failed at address = 0x%x value = 0x%x, address2 = 0x%x value2 = 0x%x\n",
149 index, value, index2, value2);
150
151 return -1;
152 }
153 }
154
155 puts("ddr memory compare PASSED!\n");
156 return 0;
157}
158
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530159static void ddr_check_ecc_status(void)
Hao Zhang26459482014-10-22 17:47:59 +0300160{
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530161 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
162 u32 err_1b = readl(&emif->emif_1b_ecc_err_cnt);
163 u32 int_status = readl(&emif->emif_irqstatus_raw_sys);
164 int ecc_test = 0;
165 char *env;
Hao Zhang26459482014-10-22 17:47:59 +0300166
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530167 env = env_get("ecc_test");
168 if (env)
169 ecc_test = simple_strtol(env, NULL, 0);
Hao Zhang26459482014-10-22 17:47:59 +0300170
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530171 puts("ECC test Status:\n");
172 if (int_status & EMIF_INT_WR_ECC_ERR_SYS_MASK)
173 puts("\tECC test: DDR ECC write error interrupted\n");
Hao Zhang26459482014-10-22 17:47:59 +0300174
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530175 if (int_status & EMIF_INT_TWOBIT_ECC_ERR_SYS_MASK)
176 if (!ecc_test)
177 panic("\tECC test: DDR ECC 2-bit error interrupted");
Hao Zhang26459482014-10-22 17:47:59 +0300178
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530179 if (int_status & EMIF_INT_ONEBIT_ECC_ERR_SYS_MASK)
180 puts("\tECC test: DDR ECC 1-bit error interrupted\n");
Hao Zhang26459482014-10-22 17:47:59 +0300181
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530182 if (err_1b)
183 printf("\tECC test: 1-bit ECC err count: 0x%x\n", err_1b);
184}
Hao Zhang26459482014-10-22 17:47:59 +0300185
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530186static int ddr_memory_ecc_err(u32 addr, u32 ecc_err)
187{
188 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
189 u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
190 u32 val1, val2, val3;
Hao Zhang26459482014-10-22 17:47:59 +0300191
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530192 debug("Disabling D-Cache before ECC test\n");
193 dcache_disable();
194 invalidate_dcache_all();
195
196 puts("Testing DDR ECC:\n");
197 puts("\tECC test: Disabling DDR ECC ...\n");
198 writel(0, &emif->emif_ecc_ctrl_reg);
199
200 val1 = readl(addr);
201 val2 = val1 ^ ecc_err;
202 writel(val2, addr);
203
204 val3 = readl(addr);
205 printf("\tECC test: addr 0x%x, read data 0x%x, written data 0x%x, err pattern: 0x%x, read after write data 0x%x\n",
206 addr, val1, val2, ecc_err, val3);
207
208 puts("\tECC test: Enabling DDR ECC ...\n");
209#ifdef CONFIG_ARCH_KEYSTONE
210 ecc_ctrl = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16);
211 writel(ecc_ctrl, EMIF1_BASE + KS2_DDR3_ECC_ADDR_RANGE1_OFFSET);
212 ddr3_enable_ecc(EMIF1_BASE, 1);
213#else
214 writel(ecc_ctrl, &emif->emif_ecc_ctrl_reg);
215#endif
216
217 val1 = readl(addr);
218 printf("\tECC test: addr 0x%x, read data 0x%x\n", addr, val1);
219
220 ddr_check_ecc_status();
221
222 debug("Enabling D-cache back after ECC test\n");
223 enable_caches();
224
Hao Zhang26459482014-10-22 17:47:59 +0300225 return 0;
226}
227
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530228static int is_addr_valid(u32 addr)
229{
230 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
231 u32 start_addr, end_addr, range, ecc_ctrl;
232
233#ifdef CONFIG_ARCH_KEYSTONE
234 ecc_ctrl = EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK;
235 range = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16);
236#else
237 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
238 range = readl(&emif->emif_ecc_address_range_1);
239#endif
240
241 /* Check in ecc address range 1 */
242 if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK) {
243 start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
244 + CONFIG_SYS_SDRAM_BASE;
245 end_addr = start_addr + (range & EMIF_ECC_REG_ECC_END_ADDR_MASK)
246 + 0xFFFF;
247 if ((addr >= start_addr) && (addr <= end_addr))
248 /* addr within ecc address range 1 */
249 return 1;
250 }
251
252 /* Check in ecc address range 2 */
253 if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_2_EN_MASK) {
254 range = readl(&emif->emif_ecc_address_range_2);
255 start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
256 + CONFIG_SYS_SDRAM_BASE;
257 end_addr = start_addr + (range & EMIF_ECC_REG_ECC_END_ADDR_MASK)
258 + 0xFFFF;
259 if ((addr >= start_addr) && (addr <= end_addr))
260 /* addr within ecc address range 2 */
261 return 1;
262 }
263
264 return 0;
265}
266
267static int is_ecc_enabled(void)
268{
269 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
270 u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
271
272 return (ecc_ctrl & EMIF_ECC_CTRL_REG_ECC_EN_MASK) &&
273 (ecc_ctrl & EMIF_ECC_REG_RMW_EN_MASK);
274}
275
Hao Zhang26459482014-10-22 17:47:59 +0300276static int do_ddr_test(cmd_tbl_t *cmdtp,
277 int flag, int argc, char * const argv[])
278{
279 u32 start_addr, end_addr, size, ecc_err;
280
281 if ((argc == 4) && (strncmp(argv[1], "ecc_err", 8) == 0)) {
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530282 if (!is_ecc_enabled()) {
283 puts("ECC not enabled. Please Enable ECC any try again\n");
284 return CMD_RET_FAILURE;
Hao Zhang26459482014-10-22 17:47:59 +0300285 }
286
287 start_addr = simple_strtoul(argv[2], NULL, 16);
288 ecc_err = simple_strtoul(argv[3], NULL, 16);
289
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530290 if (!is_addr_valid(start_addr)) {
291 puts("Invalid address. Please enter ECC supported address!\n");
292 return CMD_RET_FAILURE;
Hao Zhang26459482014-10-22 17:47:59 +0300293 }
294
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530295 ddr_memory_ecc_err(start_addr, ecc_err);
Hao Zhang26459482014-10-22 17:47:59 +0300296 return 0;
297 }
298
299 if (!(((argc == 4) && (strncmp(argv[1], "test", 5) == 0)) ||
300 ((argc == 5) && (strncmp(argv[1], "compare", 8) == 0))))
301 return cmd_usage(cmdtp);
302
303 start_addr = simple_strtoul(argv[2], NULL, 16);
304 end_addr = simple_strtoul(argv[3], NULL, 16);
305
306 if ((start_addr < CONFIG_SYS_SDRAM_BASE) ||
307 (start_addr > (CONFIG_SYS_SDRAM_BASE +
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530308 get_effective_memsize() - 1)) ||
Hao Zhang26459482014-10-22 17:47:59 +0300309 (end_addr < CONFIG_SYS_SDRAM_BASE) ||
310 (end_addr > (CONFIG_SYS_SDRAM_BASE +
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530311 get_effective_memsize() - 1)) || (start_addr >= end_addr)) {
Hao Zhang26459482014-10-22 17:47:59 +0300312 puts("Invalid start or end address!\n");
313 return cmd_usage(cmdtp);
314 }
315
316 puts("Please wait ...\n");
317 if (argc == 5) {
318 size = simple_strtoul(argv[4], NULL, 16);
319 ddr_memory_compare(start_addr, end_addr, size);
320 } else {
321 ddr_memory_test(start_addr, end_addr, 0);
322 }
323
324 return 0;
325}
326
327U_BOOT_CMD(ddr, 5, 1, do_ddr_test,
328 "DDR3 test",
329 "test <start_addr in hex> <end_addr in hex> - test DDR from start\n"
330 " address to end address\n"
331 "ddr compare <start_addr in hex> <end_addr in hex> <size in hex> -\n"
332 " compare DDR data of (size) bytes from start address to end\n"
333 " address\n"
334 "ddr ecc_err <addr in hex> <bit_err in hex> - generate bit errors\n"
335 " in DDR data at <addr>, the command will read a 32-bit data\n"
336 " from <addr>, and write (data ^ bit_err) back to <addr>\n"
337);