blob: 623b63b0f94cd67faa3a7232ca4bfeecf8e1520a [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
Simon Glass9edefc22019-11-14 12:57:37 -07008#include <cpu_func.h>
Simon Glass09140112020-05-10 11:40:03 -06009#include <env.h>
Simon Glass9b4a2052019-12-28 10:45:05 -070010#include <init.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060011#include <log.h>
Hao Zhang26459482014-10-22 17:47:59 +030012#include <asm/arch/hardware.h>
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +053013#include <asm/cache.h>
14#include <asm/emif.h>
Hao Zhang26459482014-10-22 17:47:59 +030015#include <common.h>
16#include <command.h>
17
18DECLARE_GLOBAL_DATA_PTR;
19
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +053020#ifdef CONFIG_ARCH_KEYSTONE
21#include <asm/arch/ddr3.h>
Hao Zhang26459482014-10-22 17:47:59 +030022#define DDR_MIN_ADDR CONFIG_SYS_SDRAM_BASE
Tom Rini01abae42017-04-06 20:42:18 -040023#define STACKSIZE (512 << 10) /* 512 KiB */
Hao Zhang26459482014-10-22 17:47:59 +030024
25#define DDR_REMAP_ADDR 0x80000000
26#define ECC_START_ADDR1 ((DDR_MIN_ADDR - DDR_REMAP_ADDR) >> 17)
27
28#define ECC_END_ADDR1 (((gd->start_addr_sp - DDR_REMAP_ADDR - \
Tom Rini01abae42017-04-06 20:42:18 -040029 STACKSIZE) >> 17) - 2)
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +053030#endif
Hao Zhang26459482014-10-22 17:47:59 +030031
32#define DDR_TEST_BURST_SIZE 1024
33
34static int ddr_memory_test(u32 start_address, u32 end_address, int quick)
35{
36 u32 index_start, value, index;
37
38 index_start = start_address;
39
40 while (1) {
41 /* Write a pattern */
42 for (index = index_start;
43 index < index_start + DDR_TEST_BURST_SIZE;
44 index += 4)
45 __raw_writel(index, index);
46
47 /* Read and check the pattern */
48 for (index = index_start;
49 index < index_start + DDR_TEST_BURST_SIZE;
50 index += 4) {
51 value = __raw_readl(index);
52 if (value != index) {
53 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
54 index, value, __raw_readl(index));
55
56 return -1;
57 }
58 }
59
60 index_start += DDR_TEST_BURST_SIZE;
61 if (index_start >= end_address)
62 break;
63
64 if (quick)
65 continue;
66
67 /* Write a pattern for complementary values */
68 for (index = index_start;
69 index < index_start + DDR_TEST_BURST_SIZE;
70 index += 4)
71 __raw_writel((u32)~index, index);
72
73 /* Read and check the pattern */
74 for (index = index_start;
75 index < index_start + DDR_TEST_BURST_SIZE;
76 index += 4) {
77 value = __raw_readl(index);
78 if (value != ~index) {
79 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
80 index, value, __raw_readl(index));
81
82 return -1;
83 }
84 }
85
86 index_start += DDR_TEST_BURST_SIZE;
87 if (index_start >= end_address)
88 break;
89
90 /* Write a pattern */
91 for (index = index_start;
92 index < index_start + DDR_TEST_BURST_SIZE;
93 index += 2)
94 __raw_writew((u16)index, index);
95
96 /* Read and check the pattern */
97 for (index = index_start;
98 index < index_start + DDR_TEST_BURST_SIZE;
99 index += 2) {
100 value = __raw_readw(index);
101 if (value != (u16)index) {
102 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
103 index, value, __raw_readw(index));
104
105 return -1;
106 }
107 }
108
109 index_start += DDR_TEST_BURST_SIZE;
110 if (index_start >= end_address)
111 break;
112
113 /* Write a pattern */
114 for (index = index_start;
115 index < index_start + DDR_TEST_BURST_SIZE;
116 index += 1)
117 __raw_writeb((u8)index, index);
118
119 /* Read and check the pattern */
120 for (index = index_start;
121 index < index_start + DDR_TEST_BURST_SIZE;
122 index += 1) {
123 value = __raw_readb(index);
124 if (value != (u8)index) {
125 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
126 index, value, __raw_readb(index));
127
128 return -1;
129 }
130 }
131
132 index_start += DDR_TEST_BURST_SIZE;
133 if (index_start >= end_address)
134 break;
135 }
136
137 puts("ddr memory test PASSED!\n");
138 return 0;
139}
140
141static int ddr_memory_compare(u32 address1, u32 address2, u32 size)
142{
143 u32 index, value, index2, value2;
144
145 for (index = address1, index2 = address2;
146 index < address1 + size;
147 index += 4, index2 += 4) {
148 value = __raw_readl(index);
149 value2 = __raw_readl(index2);
150
151 if (value != value2) {
152 printf("ddr_memory_test: Compare failed at address = 0x%x value = 0x%x, address2 = 0x%x value2 = 0x%x\n",
153 index, value, index2, value2);
154
155 return -1;
156 }
157 }
158
159 puts("ddr memory compare PASSED!\n");
160 return 0;
161}
162
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530163static void ddr_check_ecc_status(void)
Hao Zhang26459482014-10-22 17:47:59 +0300164{
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530165 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
166 u32 err_1b = readl(&emif->emif_1b_ecc_err_cnt);
167 u32 int_status = readl(&emif->emif_irqstatus_raw_sys);
168 int ecc_test = 0;
169 char *env;
Hao Zhang26459482014-10-22 17:47:59 +0300170
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530171 env = env_get("ecc_test");
172 if (env)
173 ecc_test = simple_strtol(env, NULL, 0);
Hao Zhang26459482014-10-22 17:47:59 +0300174
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530175 puts("ECC test Status:\n");
176 if (int_status & EMIF_INT_WR_ECC_ERR_SYS_MASK)
177 puts("\tECC test: DDR ECC write error interrupted\n");
Hao Zhang26459482014-10-22 17:47:59 +0300178
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530179 if (int_status & EMIF_INT_TWOBIT_ECC_ERR_SYS_MASK)
180 if (!ecc_test)
181 panic("\tECC test: DDR ECC 2-bit error interrupted");
Hao Zhang26459482014-10-22 17:47:59 +0300182
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530183 if (int_status & EMIF_INT_ONEBIT_ECC_ERR_SYS_MASK)
184 puts("\tECC test: DDR ECC 1-bit error interrupted\n");
Hao Zhang26459482014-10-22 17:47:59 +0300185
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530186 if (err_1b)
187 printf("\tECC test: 1-bit ECC err count: 0x%x\n", err_1b);
188}
Hao Zhang26459482014-10-22 17:47:59 +0300189
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530190static int ddr_memory_ecc_err(u32 addr, u32 ecc_err)
191{
192 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
193 u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
194 u32 val1, val2, val3;
Hao Zhang26459482014-10-22 17:47:59 +0300195
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530196 debug("Disabling D-Cache before ECC test\n");
197 dcache_disable();
198 invalidate_dcache_all();
199
200 puts("Testing DDR ECC:\n");
201 puts("\tECC test: Disabling DDR ECC ...\n");
202 writel(0, &emif->emif_ecc_ctrl_reg);
203
204 val1 = readl(addr);
205 val2 = val1 ^ ecc_err;
206 writel(val2, addr);
207
208 val3 = readl(addr);
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530209#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
Krunal Bhargav92ffd0d2019-09-16 13:47:19 +0530217 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",
218 addr, val1, val2, ecc_err, val3);
219
220 puts("\tECC test: Enabled DDR ECC ...\n");
221
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530222 val1 = readl(addr);
223 printf("\tECC test: addr 0x%x, read data 0x%x\n", addr, val1);
224
225 ddr_check_ecc_status();
226
227 debug("Enabling D-cache back after ECC test\n");
228 enable_caches();
229
Hao Zhang26459482014-10-22 17:47:59 +0300230 return 0;
231}
232
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530233static int is_addr_valid(u32 addr)
234{
235 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
236 u32 start_addr, end_addr, range, ecc_ctrl;
237
238#ifdef CONFIG_ARCH_KEYSTONE
239 ecc_ctrl = EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK;
240 range = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16);
241#else
242 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
243 range = readl(&emif->emif_ecc_address_range_1);
244#endif
245
246 /* Check in ecc address range 1 */
247 if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK) {
248 start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
249 + CONFIG_SYS_SDRAM_BASE;
Lokesh Vutla5ebe6c02019-09-16 13:47:16 +0530250 end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
251 CONFIG_SYS_SDRAM_BASE;
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530252 if ((addr >= start_addr) && (addr <= end_addr))
253 /* addr within ecc address range 1 */
254 return 1;
255 }
256
257 /* Check in ecc address range 2 */
258 if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_2_EN_MASK) {
259 range = readl(&emif->emif_ecc_address_range_2);
260 start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
261 + CONFIG_SYS_SDRAM_BASE;
Lokesh Vutla5ebe6c02019-09-16 13:47:16 +0530262 end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
263 CONFIG_SYS_SDRAM_BASE;
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530264 if ((addr >= start_addr) && (addr <= end_addr))
265 /* addr within ecc address range 2 */
266 return 1;
267 }
268
269 return 0;
270}
271
272static int is_ecc_enabled(void)
273{
274 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
275 u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
276
277 return (ecc_ctrl & EMIF_ECC_CTRL_REG_ECC_EN_MASK) &&
278 (ecc_ctrl & EMIF_ECC_REG_RMW_EN_MASK);
279}
280
Simon Glass09140112020-05-10 11:40:03 -0600281static int do_ddr_test(struct cmd_tbl *cmdtp,
282 int flag, int argc, char *const argv[])
Hao Zhang26459482014-10-22 17:47:59 +0300283{
284 u32 start_addr, end_addr, size, ecc_err;
285
286 if ((argc == 4) && (strncmp(argv[1], "ecc_err", 8) == 0)) {
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530287 if (!is_ecc_enabled()) {
288 puts("ECC not enabled. Please Enable ECC any try again\n");
289 return CMD_RET_FAILURE;
Hao Zhang26459482014-10-22 17:47:59 +0300290 }
291
292 start_addr = simple_strtoul(argv[2], NULL, 16);
293 ecc_err = simple_strtoul(argv[3], NULL, 16);
294
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530295 if (!is_addr_valid(start_addr)) {
296 puts("Invalid address. Please enter ECC supported address!\n");
297 return CMD_RET_FAILURE;
Hao Zhang26459482014-10-22 17:47:59 +0300298 }
299
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530300 ddr_memory_ecc_err(start_addr, ecc_err);
Hao Zhang26459482014-10-22 17:47:59 +0300301 return 0;
302 }
303
304 if (!(((argc == 4) && (strncmp(argv[1], "test", 5) == 0)) ||
305 ((argc == 5) && (strncmp(argv[1], "compare", 8) == 0))))
306 return cmd_usage(cmdtp);
307
308 start_addr = simple_strtoul(argv[2], NULL, 16);
309 end_addr = simple_strtoul(argv[3], NULL, 16);
310
311 if ((start_addr < CONFIG_SYS_SDRAM_BASE) ||
312 (start_addr > (CONFIG_SYS_SDRAM_BASE +
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530313 get_effective_memsize() - 1)) ||
Hao Zhang26459482014-10-22 17:47:59 +0300314 (end_addr < CONFIG_SYS_SDRAM_BASE) ||
315 (end_addr > (CONFIG_SYS_SDRAM_BASE +
Lokesh Vutla8a8af8a2017-12-29 11:47:50 +0530316 get_effective_memsize() - 1)) || (start_addr >= end_addr)) {
Hao Zhang26459482014-10-22 17:47:59 +0300317 puts("Invalid start or end address!\n");
318 return cmd_usage(cmdtp);
319 }
320
321 puts("Please wait ...\n");
322 if (argc == 5) {
323 size = simple_strtoul(argv[4], NULL, 16);
324 ddr_memory_compare(start_addr, end_addr, size);
325 } else {
326 ddr_memory_test(start_addr, end_addr, 0);
327 }
328
329 return 0;
330}
331
332U_BOOT_CMD(ddr, 5, 1, do_ddr_test,
333 "DDR3 test",
334 "test <start_addr in hex> <end_addr in hex> - test DDR from start\n"
335 " address to end address\n"
336 "ddr compare <start_addr in hex> <end_addr in hex> <size in hex> -\n"
337 " compare DDR data of (size) bytes from start address to end\n"
338 " address\n"
339 "ddr ecc_err <addr in hex> <bit_err in hex> - generate bit errors\n"
340 " in DDR data at <addr>, the command will read a 32-bit data\n"
341 " from <addr>, and write (data ^ bit_err) back to <addr>\n"
342);