blob: a452fe7876a8b76089bc5e7929b917933dd73cd3 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Hao Zhangb2592392014-10-22 17:47:59 +03002/*
Lokesh Vutla962c4e02017-12-29 11:47:49 +05303 * EMIF: DDR3 test commands
Hao Zhangb2592392014-10-22 17:47:59 +03004 *
Lokesh Vutla962c4e02017-12-29 11:47:49 +05305 * Copyright (C) 2012-2017 Texas Instruments Incorporated, <www.ti.com>
Hao Zhangb2592392014-10-22 17:47:59 +03006 */
7
Simon Glass1d91ba72019-11-14 12:57:37 -07008#include <cpu_func.h>
Simon Glass8e16b1e2019-12-28 10:45:05 -07009#include <init.h>
Hao Zhangb2592392014-10-22 17:47:59 +030010#include <asm/arch/hardware.h>
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +053011#include <asm/cache.h>
12#include <asm/emif.h>
Hao Zhangb2592392014-10-22 17:47:59 +030013#include <common.h>
14#include <command.h>
15
16DECLARE_GLOBAL_DATA_PTR;
17
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +053018#ifdef CONFIG_ARCH_KEYSTONE
19#include <asm/arch/ddr3.h>
Hao Zhangb2592392014-10-22 17:47:59 +030020#define DDR_MIN_ADDR CONFIG_SYS_SDRAM_BASE
Tom Rinidfafe892017-04-06 20:42:18 -040021#define STACKSIZE (512 << 10) /* 512 KiB */
Hao Zhangb2592392014-10-22 17:47:59 +030022
23#define DDR_REMAP_ADDR 0x80000000
24#define ECC_START_ADDR1 ((DDR_MIN_ADDR - DDR_REMAP_ADDR) >> 17)
25
26#define ECC_END_ADDR1 (((gd->start_addr_sp - DDR_REMAP_ADDR - \
Tom Rinidfafe892017-04-06 20:42:18 -040027 STACKSIZE) >> 17) - 2)
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +053028#endif
Hao Zhangb2592392014-10-22 17:47:59 +030029
30#define DDR_TEST_BURST_SIZE 1024
31
32static int ddr_memory_test(u32 start_address, u32 end_address, int quick)
33{
34 u32 index_start, value, index;
35
36 index_start = start_address;
37
38 while (1) {
39 /* Write a pattern */
40 for (index = index_start;
41 index < index_start + DDR_TEST_BURST_SIZE;
42 index += 4)
43 __raw_writel(index, index);
44
45 /* Read and check the pattern */
46 for (index = index_start;
47 index < index_start + DDR_TEST_BURST_SIZE;
48 index += 4) {
49 value = __raw_readl(index);
50 if (value != index) {
51 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
52 index, value, __raw_readl(index));
53
54 return -1;
55 }
56 }
57
58 index_start += DDR_TEST_BURST_SIZE;
59 if (index_start >= end_address)
60 break;
61
62 if (quick)
63 continue;
64
65 /* Write a pattern for complementary values */
66 for (index = index_start;
67 index < index_start + DDR_TEST_BURST_SIZE;
68 index += 4)
69 __raw_writel((u32)~index, index);
70
71 /* Read and check the pattern */
72 for (index = index_start;
73 index < index_start + DDR_TEST_BURST_SIZE;
74 index += 4) {
75 value = __raw_readl(index);
76 if (value != ~index) {
77 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
78 index, value, __raw_readl(index));
79
80 return -1;
81 }
82 }
83
84 index_start += DDR_TEST_BURST_SIZE;
85 if (index_start >= end_address)
86 break;
87
88 /* Write a pattern */
89 for (index = index_start;
90 index < index_start + DDR_TEST_BURST_SIZE;
91 index += 2)
92 __raw_writew((u16)index, index);
93
94 /* Read and check the pattern */
95 for (index = index_start;
96 index < index_start + DDR_TEST_BURST_SIZE;
97 index += 2) {
98 value = __raw_readw(index);
99 if (value != (u16)index) {
100 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
101 index, value, __raw_readw(index));
102
103 return -1;
104 }
105 }
106
107 index_start += DDR_TEST_BURST_SIZE;
108 if (index_start >= end_address)
109 break;
110
111 /* Write a pattern */
112 for (index = index_start;
113 index < index_start + DDR_TEST_BURST_SIZE;
114 index += 1)
115 __raw_writeb((u8)index, index);
116
117 /* Read and check the pattern */
118 for (index = index_start;
119 index < index_start + DDR_TEST_BURST_SIZE;
120 index += 1) {
121 value = __raw_readb(index);
122 if (value != (u8)index) {
123 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
124 index, value, __raw_readb(index));
125
126 return -1;
127 }
128 }
129
130 index_start += DDR_TEST_BURST_SIZE;
131 if (index_start >= end_address)
132 break;
133 }
134
135 puts("ddr memory test PASSED!\n");
136 return 0;
137}
138
139static int ddr_memory_compare(u32 address1, u32 address2, u32 size)
140{
141 u32 index, value, index2, value2;
142
143 for (index = address1, index2 = address2;
144 index < address1 + size;
145 index += 4, index2 += 4) {
146 value = __raw_readl(index);
147 value2 = __raw_readl(index2);
148
149 if (value != value2) {
150 printf("ddr_memory_test: Compare failed at address = 0x%x value = 0x%x, address2 = 0x%x value2 = 0x%x\n",
151 index, value, index2, value2);
152
153 return -1;
154 }
155 }
156
157 puts("ddr memory compare PASSED!\n");
158 return 0;
159}
160
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530161static void ddr_check_ecc_status(void)
Hao Zhangb2592392014-10-22 17:47:59 +0300162{
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530163 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
164 u32 err_1b = readl(&emif->emif_1b_ecc_err_cnt);
165 u32 int_status = readl(&emif->emif_irqstatus_raw_sys);
166 int ecc_test = 0;
167 char *env;
168
169 env = env_get("ecc_test");
170 if (env)
171 ecc_test = simple_strtol(env, NULL, 0);
172
173 puts("ECC test Status:\n");
174 if (int_status & EMIF_INT_WR_ECC_ERR_SYS_MASK)
175 puts("\tECC test: DDR ECC write error interrupted\n");
Hao Zhangb2592392014-10-22 17:47:59 +0300176
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530177 if (int_status & EMIF_INT_TWOBIT_ECC_ERR_SYS_MASK)
178 if (!ecc_test)
179 panic("\tECC test: DDR ECC 2-bit error interrupted");
Hao Zhangb2592392014-10-22 17:47:59 +0300180
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530181 if (int_status & EMIF_INT_ONEBIT_ECC_ERR_SYS_MASK)
182 puts("\tECC test: DDR ECC 1-bit error interrupted\n");
Hao Zhangb2592392014-10-22 17:47:59 +0300183
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530184 if (err_1b)
185 printf("\tECC test: 1-bit ECC err count: 0x%x\n", err_1b);
186}
187
188static int ddr_memory_ecc_err(u32 addr, u32 ecc_err)
189{
190 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
191 u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
192 u32 val1, val2, val3;
193
194 debug("Disabling D-Cache before ECC test\n");
195 dcache_disable();
196 invalidate_dcache_all();
Hao Zhangb2592392014-10-22 17:47:59 +0300197
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530198 puts("Testing DDR ECC:\n");
199 puts("\tECC test: Disabling DDR ECC ...\n");
200 writel(0, &emif->emif_ecc_ctrl_reg);
Hao Zhangb2592392014-10-22 17:47:59 +0300201
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530202 val1 = readl(addr);
203 val2 = val1 ^ ecc_err;
204 writel(val2, addr);
Hao Zhangb2592392014-10-22 17:47:59 +0300205
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530206 val3 = readl(addr);
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530207#ifdef CONFIG_ARCH_KEYSTONE
208 ecc_ctrl = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16);
209 writel(ecc_ctrl, EMIF1_BASE + KS2_DDR3_ECC_ADDR_RANGE1_OFFSET);
210 ddr3_enable_ecc(EMIF1_BASE, 1);
211#else
212 writel(ecc_ctrl, &emif->emif_ecc_ctrl_reg);
213#endif
214
Krunal Bhargav986fb6a2019-09-16 13:47:19 +0530215 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",
216 addr, val1, val2, ecc_err, val3);
217
218 puts("\tECC test: Enabled DDR ECC ...\n");
219
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530220 val1 = readl(addr);
221 printf("\tECC test: addr 0x%x, read data 0x%x\n", addr, val1);
222
223 ddr_check_ecc_status();
224
225 debug("Enabling D-cache back after ECC test\n");
226 enable_caches();
227
Hao Zhangb2592392014-10-22 17:47:59 +0300228 return 0;
229}
230
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530231static int is_addr_valid(u32 addr)
232{
233 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
234 u32 start_addr, end_addr, range, ecc_ctrl;
235
236#ifdef CONFIG_ARCH_KEYSTONE
237 ecc_ctrl = EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK;
238 range = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16);
239#else
240 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
241 range = readl(&emif->emif_ecc_address_range_1);
242#endif
243
244 /* Check in ecc address range 1 */
245 if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK) {
246 start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
247 + CONFIG_SYS_SDRAM_BASE;
Lokesh Vutlae728d542019-09-16 13:47:16 +0530248 end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
249 CONFIG_SYS_SDRAM_BASE;
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530250 if ((addr >= start_addr) && (addr <= end_addr))
251 /* addr within ecc address range 1 */
252 return 1;
253 }
254
255 /* Check in ecc address range 2 */
256 if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_2_EN_MASK) {
257 range = readl(&emif->emif_ecc_address_range_2);
258 start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
259 + CONFIG_SYS_SDRAM_BASE;
Lokesh Vutlae728d542019-09-16 13:47:16 +0530260 end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
261 CONFIG_SYS_SDRAM_BASE;
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530262 if ((addr >= start_addr) && (addr <= end_addr))
263 /* addr within ecc address range 2 */
264 return 1;
265 }
266
267 return 0;
268}
269
270static int is_ecc_enabled(void)
271{
272 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
273 u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
274
275 return (ecc_ctrl & EMIF_ECC_CTRL_REG_ECC_EN_MASK) &&
276 (ecc_ctrl & EMIF_ECC_REG_RMW_EN_MASK);
277}
278
Hao Zhangb2592392014-10-22 17:47:59 +0300279static int do_ddr_test(cmd_tbl_t *cmdtp,
280 int flag, int argc, char * const argv[])
281{
282 u32 start_addr, end_addr, size, ecc_err;
283
284 if ((argc == 4) && (strncmp(argv[1], "ecc_err", 8) == 0)) {
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530285 if (!is_ecc_enabled()) {
286 puts("ECC not enabled. Please Enable ECC any try again\n");
287 return CMD_RET_FAILURE;
Hao Zhangb2592392014-10-22 17:47:59 +0300288 }
289
290 start_addr = simple_strtoul(argv[2], NULL, 16);
291 ecc_err = simple_strtoul(argv[3], NULL, 16);
292
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530293 if (!is_addr_valid(start_addr)) {
294 puts("Invalid address. Please enter ECC supported address!\n");
295 return CMD_RET_FAILURE;
Hao Zhangb2592392014-10-22 17:47:59 +0300296 }
297
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530298 ddr_memory_ecc_err(start_addr, ecc_err);
Hao Zhangb2592392014-10-22 17:47:59 +0300299 return 0;
300 }
301
302 if (!(((argc == 4) && (strncmp(argv[1], "test", 5) == 0)) ||
303 ((argc == 5) && (strncmp(argv[1], "compare", 8) == 0))))
304 return cmd_usage(cmdtp);
305
306 start_addr = simple_strtoul(argv[2], NULL, 16);
307 end_addr = simple_strtoul(argv[3], NULL, 16);
308
309 if ((start_addr < CONFIG_SYS_SDRAM_BASE) ||
310 (start_addr > (CONFIG_SYS_SDRAM_BASE +
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530311 get_effective_memsize() - 1)) ||
Hao Zhangb2592392014-10-22 17:47:59 +0300312 (end_addr < CONFIG_SYS_SDRAM_BASE) ||
313 (end_addr > (CONFIG_SYS_SDRAM_BASE +
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530314 get_effective_memsize() - 1)) || (start_addr >= end_addr)) {
Hao Zhangb2592392014-10-22 17:47:59 +0300315 puts("Invalid start or end address!\n");
316 return cmd_usage(cmdtp);
317 }
318
319 puts("Please wait ...\n");
320 if (argc == 5) {
321 size = simple_strtoul(argv[4], NULL, 16);
322 ddr_memory_compare(start_addr, end_addr, size);
323 } else {
324 ddr_memory_test(start_addr, end_addr, 0);
325 }
326
327 return 0;
328}
329
330U_BOOT_CMD(ddr, 5, 1, do_ddr_test,
331 "DDR3 test",
332 "test <start_addr in hex> <end_addr in hex> - test DDR from start\n"
333 " address to end address\n"
334 "ddr compare <start_addr in hex> <end_addr in hex> <size in hex> -\n"
335 " compare DDR data of (size) bytes from start address to end\n"
336 " address\n"
337 "ddr ecc_err <addr in hex> <bit_err in hex> - generate bit errors\n"
338 " in DDR data at <addr>, the command will read a 32-bit data\n"
339 " from <addr>, and write (data ^ bit_err) back to <addr>\n"
340);