blob: 756aa9eb3eda42b58af30bac01d37855761f7cc3 [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>
Hao Zhangb2592392014-10-22 17:47:59 +030011#include <asm/arch/hardware.h>
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +053012#include <asm/cache.h>
13#include <asm/emif.h>
Hao Zhangb2592392014-10-22 17:47:59 +030014#include <common.h>
15#include <command.h>
16
17DECLARE_GLOBAL_DATA_PTR;
18
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +053019#ifdef CONFIG_ARCH_KEYSTONE
20#include <asm/arch/ddr3.h>
Hao Zhangb2592392014-10-22 17:47:59 +030021#define DDR_MIN_ADDR CONFIG_SYS_SDRAM_BASE
Tom Rinidfafe892017-04-06 20:42:18 -040022#define STACKSIZE (512 << 10) /* 512 KiB */
Hao Zhangb2592392014-10-22 17:47:59 +030023
24#define DDR_REMAP_ADDR 0x80000000
25#define ECC_START_ADDR1 ((DDR_MIN_ADDR - DDR_REMAP_ADDR) >> 17)
26
27#define ECC_END_ADDR1 (((gd->start_addr_sp - DDR_REMAP_ADDR - \
Tom Rinidfafe892017-04-06 20:42:18 -040028 STACKSIZE) >> 17) - 2)
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +053029#endif
Hao Zhangb2592392014-10-22 17:47:59 +030030
31#define DDR_TEST_BURST_SIZE 1024
32
33static int ddr_memory_test(u32 start_address, u32 end_address, int quick)
34{
35 u32 index_start, value, index;
36
37 index_start = start_address;
38
39 while (1) {
40 /* Write a pattern */
41 for (index = index_start;
42 index < index_start + DDR_TEST_BURST_SIZE;
43 index += 4)
44 __raw_writel(index, index);
45
46 /* Read and check the pattern */
47 for (index = index_start;
48 index < index_start + DDR_TEST_BURST_SIZE;
49 index += 4) {
50 value = __raw_readl(index);
51 if (value != index) {
52 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
53 index, value, __raw_readl(index));
54
55 return -1;
56 }
57 }
58
59 index_start += DDR_TEST_BURST_SIZE;
60 if (index_start >= end_address)
61 break;
62
63 if (quick)
64 continue;
65
66 /* Write a pattern for complementary values */
67 for (index = index_start;
68 index < index_start + DDR_TEST_BURST_SIZE;
69 index += 4)
70 __raw_writel((u32)~index, index);
71
72 /* Read and check the pattern */
73 for (index = index_start;
74 index < index_start + DDR_TEST_BURST_SIZE;
75 index += 4) {
76 value = __raw_readl(index);
77 if (value != ~index) {
78 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
79 index, value, __raw_readl(index));
80
81 return -1;
82 }
83 }
84
85 index_start += DDR_TEST_BURST_SIZE;
86 if (index_start >= end_address)
87 break;
88
89 /* Write a pattern */
90 for (index = index_start;
91 index < index_start + DDR_TEST_BURST_SIZE;
92 index += 2)
93 __raw_writew((u16)index, index);
94
95 /* Read and check the pattern */
96 for (index = index_start;
97 index < index_start + DDR_TEST_BURST_SIZE;
98 index += 2) {
99 value = __raw_readw(index);
100 if (value != (u16)index) {
101 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
102 index, value, __raw_readw(index));
103
104 return -1;
105 }
106 }
107
108 index_start += DDR_TEST_BURST_SIZE;
109 if (index_start >= end_address)
110 break;
111
112 /* Write a pattern */
113 for (index = index_start;
114 index < index_start + DDR_TEST_BURST_SIZE;
115 index += 1)
116 __raw_writeb((u8)index, index);
117
118 /* Read and check the pattern */
119 for (index = index_start;
120 index < index_start + DDR_TEST_BURST_SIZE;
121 index += 1) {
122 value = __raw_readb(index);
123 if (value != (u8)index) {
124 printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
125 index, value, __raw_readb(index));
126
127 return -1;
128 }
129 }
130
131 index_start += DDR_TEST_BURST_SIZE;
132 if (index_start >= end_address)
133 break;
134 }
135
136 puts("ddr memory test PASSED!\n");
137 return 0;
138}
139
140static int ddr_memory_compare(u32 address1, u32 address2, u32 size)
141{
142 u32 index, value, index2, value2;
143
144 for (index = address1, index2 = address2;
145 index < address1 + size;
146 index += 4, index2 += 4) {
147 value = __raw_readl(index);
148 value2 = __raw_readl(index2);
149
150 if (value != value2) {
151 printf("ddr_memory_test: Compare failed at address = 0x%x value = 0x%x, address2 = 0x%x value2 = 0x%x\n",
152 index, value, index2, value2);
153
154 return -1;
155 }
156 }
157
158 puts("ddr memory compare PASSED!\n");
159 return 0;
160}
161
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530162static void ddr_check_ecc_status(void)
Hao Zhangb2592392014-10-22 17:47:59 +0300163{
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530164 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
165 u32 err_1b = readl(&emif->emif_1b_ecc_err_cnt);
166 u32 int_status = readl(&emif->emif_irqstatus_raw_sys);
167 int ecc_test = 0;
168 char *env;
169
170 env = env_get("ecc_test");
171 if (env)
172 ecc_test = simple_strtol(env, NULL, 0);
173
174 puts("ECC test Status:\n");
175 if (int_status & EMIF_INT_WR_ECC_ERR_SYS_MASK)
176 puts("\tECC test: DDR ECC write error interrupted\n");
Hao Zhangb2592392014-10-22 17:47:59 +0300177
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530178 if (int_status & EMIF_INT_TWOBIT_ECC_ERR_SYS_MASK)
179 if (!ecc_test)
180 panic("\tECC test: DDR ECC 2-bit error interrupted");
Hao Zhangb2592392014-10-22 17:47:59 +0300181
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530182 if (int_status & EMIF_INT_ONEBIT_ECC_ERR_SYS_MASK)
183 puts("\tECC test: DDR ECC 1-bit error interrupted\n");
Hao Zhangb2592392014-10-22 17:47:59 +0300184
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530185 if (err_1b)
186 printf("\tECC test: 1-bit ECC err count: 0x%x\n", err_1b);
187}
188
189static int ddr_memory_ecc_err(u32 addr, u32 ecc_err)
190{
191 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
192 u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
193 u32 val1, val2, val3;
194
195 debug("Disabling D-Cache before ECC test\n");
196 dcache_disable();
197 invalidate_dcache_all();
Hao Zhangb2592392014-10-22 17:47:59 +0300198
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530199 puts("Testing DDR ECC:\n");
200 puts("\tECC test: Disabling DDR ECC ...\n");
201 writel(0, &emif->emif_ecc_ctrl_reg);
Hao Zhangb2592392014-10-22 17:47:59 +0300202
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530203 val1 = readl(addr);
204 val2 = val1 ^ ecc_err;
205 writel(val2, addr);
Hao Zhangb2592392014-10-22 17:47:59 +0300206
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530207 val3 = readl(addr);
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530208#ifdef CONFIG_ARCH_KEYSTONE
209 ecc_ctrl = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16);
210 writel(ecc_ctrl, EMIF1_BASE + KS2_DDR3_ECC_ADDR_RANGE1_OFFSET);
211 ddr3_enable_ecc(EMIF1_BASE, 1);
212#else
213 writel(ecc_ctrl, &emif->emif_ecc_ctrl_reg);
214#endif
215
Krunal Bhargav986fb6a2019-09-16 13:47:19 +0530216 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",
217 addr, val1, val2, ecc_err, val3);
218
219 puts("\tECC test: Enabled DDR ECC ...\n");
220
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530221 val1 = readl(addr);
222 printf("\tECC test: addr 0x%x, read data 0x%x\n", addr, val1);
223
224 ddr_check_ecc_status();
225
226 debug("Enabling D-cache back after ECC test\n");
227 enable_caches();
228
Hao Zhangb2592392014-10-22 17:47:59 +0300229 return 0;
230}
231
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530232static int is_addr_valid(u32 addr)
233{
234 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
235 u32 start_addr, end_addr, range, ecc_ctrl;
236
237#ifdef CONFIG_ARCH_KEYSTONE
238 ecc_ctrl = EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK;
239 range = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16);
240#else
241 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
242 range = readl(&emif->emif_ecc_address_range_1);
243#endif
244
245 /* Check in ecc address range 1 */
246 if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK) {
247 start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
248 + CONFIG_SYS_SDRAM_BASE;
Lokesh Vutlae728d542019-09-16 13:47:16 +0530249 end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
250 CONFIG_SYS_SDRAM_BASE;
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530251 if ((addr >= start_addr) && (addr <= end_addr))
252 /* addr within ecc address range 1 */
253 return 1;
254 }
255
256 /* Check in ecc address range 2 */
257 if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_2_EN_MASK) {
258 range = readl(&emif->emif_ecc_address_range_2);
259 start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
260 + CONFIG_SYS_SDRAM_BASE;
Lokesh Vutlae728d542019-09-16 13:47:16 +0530261 end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
262 CONFIG_SYS_SDRAM_BASE;
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530263 if ((addr >= start_addr) && (addr <= end_addr))
264 /* addr within ecc address range 2 */
265 return 1;
266 }
267
268 return 0;
269}
270
271static int is_ecc_enabled(void)
272{
273 struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
274 u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
275
276 return (ecc_ctrl & EMIF_ECC_CTRL_REG_ECC_EN_MASK) &&
277 (ecc_ctrl & EMIF_ECC_REG_RMW_EN_MASK);
278}
279
Simon Glassed38aef2020-05-10 11:40:03 -0600280static int do_ddr_test(struct cmd_tbl *cmdtp,
281 int flag, int argc, char *const argv[])
Hao Zhangb2592392014-10-22 17:47:59 +0300282{
283 u32 start_addr, end_addr, size, ecc_err;
284
285 if ((argc == 4) && (strncmp(argv[1], "ecc_err", 8) == 0)) {
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530286 if (!is_ecc_enabled()) {
287 puts("ECC not enabled. Please Enable ECC any try again\n");
288 return CMD_RET_FAILURE;
Hao Zhangb2592392014-10-22 17:47:59 +0300289 }
290
291 start_addr = simple_strtoul(argv[2], NULL, 16);
292 ecc_err = simple_strtoul(argv[3], NULL, 16);
293
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530294 if (!is_addr_valid(start_addr)) {
295 puts("Invalid address. Please enter ECC supported address!\n");
296 return CMD_RET_FAILURE;
Hao Zhangb2592392014-10-22 17:47:59 +0300297 }
298
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530299 ddr_memory_ecc_err(start_addr, ecc_err);
Hao Zhangb2592392014-10-22 17:47:59 +0300300 return 0;
301 }
302
303 if (!(((argc == 4) && (strncmp(argv[1], "test", 5) == 0)) ||
304 ((argc == 5) && (strncmp(argv[1], "compare", 8) == 0))))
305 return cmd_usage(cmdtp);
306
307 start_addr = simple_strtoul(argv[2], NULL, 16);
308 end_addr = simple_strtoul(argv[3], NULL, 16);
309
310 if ((start_addr < CONFIG_SYS_SDRAM_BASE) ||
311 (start_addr > (CONFIG_SYS_SDRAM_BASE +
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530312 get_effective_memsize() - 1)) ||
Hao Zhangb2592392014-10-22 17:47:59 +0300313 (end_addr < CONFIG_SYS_SDRAM_BASE) ||
314 (end_addr > (CONFIG_SYS_SDRAM_BASE +
Lokesh Vutla2dacbbf2017-12-29 11:47:50 +0530315 get_effective_memsize() - 1)) || (start_addr >= end_addr)) {
Hao Zhangb2592392014-10-22 17:47:59 +0300316 puts("Invalid start or end address!\n");
317 return cmd_usage(cmdtp);
318 }
319
320 puts("Please wait ...\n");
321 if (argc == 5) {
322 size = simple_strtoul(argv[4], NULL, 16);
323 ddr_memory_compare(start_addr, end_addr, size);
324 } else {
325 ddr_memory_test(start_addr, end_addr, 0);
326 }
327
328 return 0;
329}
330
331U_BOOT_CMD(ddr, 5, 1, do_ddr_test,
332 "DDR3 test",
333 "test <start_addr in hex> <end_addr in hex> - test DDR from start\n"
334 " address to end address\n"
335 "ddr compare <start_addr in hex> <end_addr in hex> <size in hex> -\n"
336 " compare DDR data of (size) bytes from start address to end\n"
337 " address\n"
338 "ddr ecc_err <addr in hex> <bit_err in hex> - generate bit errors\n"
339 " in DDR data at <addr>, the command will read a 32-bit data\n"
340 " from <addr>, and write (data ^ bit_err) back to <addr>\n"
341);