blob: 6b43a7386832a72f2a52ebd6777e4b0dedc79d57 [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 Glassed38aef2020-05-10 11:40:03 -06009#include <env.h>
Simon Glass8e16b1e2019-12-28 10:45:05 -070010#include <init.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Hao Zhangb2592392014-10-22 17:47:59 +030012#include <asm/arch/hardware.h>
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +053013#include <asm/cache.h>
14#include <asm/emif.h>
Hao Zhangb2592392014-10-22 17:47:59 +030015#include <common.h>
16#include <command.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060017#include <asm/global_data.h>
Hao Zhangb2592392014-10-22 17:47:59 +030018
19DECLARE_GLOBAL_DATA_PTR;
20
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +053021#ifdef CONFIG_ARCH_KEYSTONE
22#include <asm/arch/ddr3.h>
Hao Zhangb2592392014-10-22 17:47:59 +030023#define DDR_MIN_ADDR CONFIG_SYS_SDRAM_BASE
Tom Rinidfafe892017-04-06 20:42:18 -040024#define STACKSIZE (512 << 10) /* 512 KiB */
Hao Zhangb2592392014-10-22 17:47:59 +030025
26#define DDR_REMAP_ADDR 0x80000000
27#define ECC_START_ADDR1 ((DDR_MIN_ADDR - DDR_REMAP_ADDR) >> 17)
28
29#define ECC_END_ADDR1 (((gd->start_addr_sp - DDR_REMAP_ADDR - \
Tom Rinidfafe892017-04-06 20:42:18 -040030 STACKSIZE) >> 17) - 2)
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +053031#endif
Hao Zhangb2592392014-10-22 17:47:59 +030032
33#define DDR_TEST_BURST_SIZE 1024
34
35static int ddr_memory_test(u32 start_address, u32 end_address, int quick)
36{
37 u32 index_start, value, index;
38
39 index_start = start_address;
40
41 while (1) {
42 /* Write a pattern */
43 for (index = index_start;
44 index < index_start + DDR_TEST_BURST_SIZE;
45 index += 4)
46 __raw_writel(index, index);
47
48 /* Read and check the pattern */
49 for (index = index_start;
50 index < index_start + DDR_TEST_BURST_SIZE;
51 index += 4) {
52 value = __raw_readl(index);
53 if (value != index) {
54 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
55 index, value, __raw_readl(index));
56
57 return -1;
58 }
59 }
60
61 index_start += DDR_TEST_BURST_SIZE;
62 if (index_start >= end_address)
63 break;
64
65 if (quick)
66 continue;
67
68 /* Write a pattern for complementary values */
69 for (index = index_start;
70 index < index_start + DDR_TEST_BURST_SIZE;
71 index += 4)
72 __raw_writel((u32)~index, index);
73
74 /* Read and check the pattern */
75 for (index = index_start;
76 index < index_start + DDR_TEST_BURST_SIZE;
77 index += 4) {
78 value = __raw_readl(index);
79 if (value != ~index) {
80 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
81 index, value, __raw_readl(index));
82
83 return -1;
84 }
85 }
86
87 index_start += DDR_TEST_BURST_SIZE;
88 if (index_start >= end_address)
89 break;
90
91 /* Write a pattern */
92 for (index = index_start;
93 index < index_start + DDR_TEST_BURST_SIZE;
94 index += 2)
95 __raw_writew((u16)index, index);
96
97 /* Read and check the pattern */
98 for (index = index_start;
99 index < index_start + DDR_TEST_BURST_SIZE;
100 index += 2) {
101 value = __raw_readw(index);
102 if (value != (u16)index) {
103 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
104 index, value, __raw_readw(index));
105
106 return -1;
107 }
108 }
109
110 index_start += DDR_TEST_BURST_SIZE;
111 if (index_start >= end_address)
112 break;
113
114 /* Write a pattern */
115 for (index = index_start;
116 index < index_start + DDR_TEST_BURST_SIZE;
117 index += 1)
118 __raw_writeb((u8)index, index);
119
120 /* Read and check the pattern */
121 for (index = index_start;
122 index < index_start + DDR_TEST_BURST_SIZE;
123 index += 1) {
124 value = __raw_readb(index);
125 if (value != (u8)index) {
126 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
127 index, value, __raw_readb(index));
128
129 return -1;
130 }
131 }
132
133 index_start += DDR_TEST_BURST_SIZE;
134 if (index_start >= end_address)
135 break;
136 }
137
138 puts("ddr memory test PASSED!\n");
139 return 0;
140}
141
142static int ddr_memory_compare(u32 address1, u32 address2, u32 size)
143{
144 u32 index, value, index2, value2;
145
146 for (index = address1, index2 = address2;
147 index < address1 + size;
148 index += 4, index2 += 4) {
149 value = __raw_readl(index);
150 value2 = __raw_readl(index2);
151
152 if (value != value2) {
153 printf("ddr_memory_test: Compare failed at address = 0x%x value = 0x%x, address2 = 0x%x value2 = 0x%x\n",
154 index, value, index2, value2);
155
156 return -1;
157 }
158 }
159
160 puts("ddr memory compare PASSED!\n");
161 return 0;
162}
163
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530164static void ddr_check_ecc_status(void)
Hao Zhangb2592392014-10-22 17:47:59 +0300165{
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530166 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
167 u32 err_1b = readl(&emif->emif_1b_ecc_err_cnt);
168 u32 int_status = readl(&emif->emif_irqstatus_raw_sys);
169 int ecc_test = 0;
170 char *env;
171
172 env = env_get("ecc_test");
173 if (env)
174 ecc_test = simple_strtol(env, NULL, 0);
175
176 puts("ECC test Status:\n");
177 if (int_status & EMIF_INT_WR_ECC_ERR_SYS_MASK)
178 puts("\tECC test: DDR ECC write error interrupted\n");
Hao Zhangb2592392014-10-22 17:47:59 +0300179
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530180 if (int_status & EMIF_INT_TWOBIT_ECC_ERR_SYS_MASK)
181 if (!ecc_test)
182 panic("\tECC test: DDR ECC 2-bit error interrupted");
Hao Zhangb2592392014-10-22 17:47:59 +0300183
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530184 if (int_status & EMIF_INT_ONEBIT_ECC_ERR_SYS_MASK)
185 puts("\tECC test: DDR ECC 1-bit error interrupted\n");
Hao Zhangb2592392014-10-22 17:47:59 +0300186
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530187 if (err_1b)
188 printf("\tECC test: 1-bit ECC err count: 0x%x\n", err_1b);
189}
190
191static int ddr_memory_ecc_err(u32 addr, u32 ecc_err)
192{
193 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
194 u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
195 u32 val1, val2, val3;
196
197 debug("Disabling D-Cache before ECC test\n");
198 dcache_disable();
199 invalidate_dcache_all();
Hao Zhangb2592392014-10-22 17:47:59 +0300200
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530201 puts("Testing DDR ECC:\n");
202 puts("\tECC test: Disabling DDR ECC ...\n");
203 writel(0, &emif->emif_ecc_ctrl_reg);
Hao Zhangb2592392014-10-22 17:47:59 +0300204
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530205 val1 = readl(addr);
206 val2 = val1 ^ ecc_err;
207 writel(val2, addr);
Hao Zhangb2592392014-10-22 17:47:59 +0300208
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530209 val3 = readl(addr);
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530210#ifdef CONFIG_ARCH_KEYSTONE
211 ecc_ctrl = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16);
212 writel(ecc_ctrl, EMIF1_BASE + KS2_DDR3_ECC_ADDR_RANGE1_OFFSET);
213 ddr3_enable_ecc(EMIF1_BASE, 1);
214#else
215 writel(ecc_ctrl, &emif->emif_ecc_ctrl_reg);
216#endif
217
Krunal Bhargav986fb6a2019-09-16 13:47:19 +0530218 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",
219 addr, val1, val2, ecc_err, val3);
220
221 puts("\tECC test: Enabled DDR ECC ...\n");
222
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530223 val1 = readl(addr);
224 printf("\tECC test: addr 0x%x, read data 0x%x\n", addr, val1);
225
226 ddr_check_ecc_status();
227
228 debug("Enabling D-cache back after ECC test\n");
229 enable_caches();
230
Hao Zhangb2592392014-10-22 17:47:59 +0300231 return 0;
232}
233
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530234static int is_addr_valid(u32 addr)
235{
236 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
237 u32 start_addr, end_addr, range, ecc_ctrl;
238
239#ifdef CONFIG_ARCH_KEYSTONE
240 ecc_ctrl = EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK;
241 range = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16);
242#else
243 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
244 range = readl(&emif->emif_ecc_address_range_1);
245#endif
246
247 /* Check in ecc address range 1 */
248 if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK) {
249 start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
250 + CONFIG_SYS_SDRAM_BASE;
Lokesh Vutlae728d542019-09-16 13:47:16 +0530251 end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
252 CONFIG_SYS_SDRAM_BASE;
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530253 if ((addr >= start_addr) && (addr <= end_addr))
254 /* addr within ecc address range 1 */
255 return 1;
256 }
257
258 /* Check in ecc address range 2 */
259 if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_2_EN_MASK) {
260 range = readl(&emif->emif_ecc_address_range_2);
261 start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
262 + CONFIG_SYS_SDRAM_BASE;
Lokesh Vutlae728d542019-09-16 13:47:16 +0530263 end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
264 CONFIG_SYS_SDRAM_BASE;
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530265 if ((addr >= start_addr) && (addr <= end_addr))
266 /* addr within ecc address range 2 */
267 return 1;
268 }
269
270 return 0;
271}
272
273static int is_ecc_enabled(void)
274{
275 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
276 u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
277
278 return (ecc_ctrl & EMIF_ECC_CTRL_REG_ECC_EN_MASK) &&
279 (ecc_ctrl & EMIF_ECC_REG_RMW_EN_MASK);
280}
281
Simon Glassed38aef2020-05-10 11:40:03 -0600282static int do_ddr_test(struct cmd_tbl *cmdtp,
283 int flag, int argc, char *const argv[])
Hao Zhangb2592392014-10-22 17:47:59 +0300284{
285 u32 start_addr, end_addr, size, ecc_err;
286
287 if ((argc == 4) && (strncmp(argv[1], "ecc_err", 8) == 0)) {
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530288 if (!is_ecc_enabled()) {
289 puts("ECC not enabled. Please Enable ECC any try again\n");
290 return CMD_RET_FAILURE;
Hao Zhangb2592392014-10-22 17:47:59 +0300291 }
292
293 start_addr = simple_strtoul(argv[2], NULL, 16);
294 ecc_err = simple_strtoul(argv[3], NULL, 16);
295
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530296 if (!is_addr_valid(start_addr)) {
297 puts("Invalid address. Please enter ECC supported address!\n");
298 return CMD_RET_FAILURE;
Hao Zhangb2592392014-10-22 17:47:59 +0300299 }
300
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530301 ddr_memory_ecc_err(start_addr, ecc_err);
Hao Zhangb2592392014-10-22 17:47:59 +0300302 return 0;
303 }
304
305 if (!(((argc == 4) && (strncmp(argv[1], "test", 5) == 0)) ||
306 ((argc == 5) && (strncmp(argv[1], "compare", 8) == 0))))
307 return cmd_usage(cmdtp);
308
309 start_addr = simple_strtoul(argv[2], NULL, 16);
310 end_addr = simple_strtoul(argv[3], NULL, 16);
311
312 if ((start_addr < CONFIG_SYS_SDRAM_BASE) ||
313 (start_addr > (CONFIG_SYS_SDRAM_BASE +
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530314 get_effective_memsize() - 1)) ||
Hao Zhangb2592392014-10-22 17:47:59 +0300315 (end_addr < CONFIG_SYS_SDRAM_BASE) ||
316 (end_addr > (CONFIG_SYS_SDRAM_BASE +
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530317 get_effective_memsize() - 1)) || (start_addr >= end_addr)) {
Hao Zhangb2592392014-10-22 17:47:59 +0300318 puts("Invalid start or end address!\n");
319 return cmd_usage(cmdtp);
320 }
321
322 puts("Please wait ...\n");
323 if (argc == 5) {
324 size = simple_strtoul(argv[4], NULL, 16);
325 ddr_memory_compare(start_addr, end_addr, size);
326 } else {
327 ddr_memory_test(start_addr, end_addr, 0);
328 }
329
330 return 0;
331}
332
333U_BOOT_CMD(ddr, 5, 1, do_ddr_test,
334 "DDR3 test",
335 "test <start_addr in hex> <end_addr in hex> - test DDR from start\n"
336 " address to end address\n"
337 "ddr compare <start_addr in hex> <end_addr in hex> <size in hex> -\n"
338 " compare DDR data of (size) bytes from start address to end\n"
339 " address\n"
340 "ddr ecc_err <addr in hex> <bit_err in hex> - generate bit errors\n"
341 " in DDR data at <addr>, the command will read a 32-bit data\n"
342 " from <addr>, and write (data ^ bit_err) back to <addr>\n"
343);