command: Remove the cmd_tbl_t typedef
[oweals/u-boot.git] / cmd / ti / ddr3.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * EMIF: DDR3 test commands
4  *
5  * Copyright (C) 2012-2017 Texas Instruments Incorporated, <www.ti.com>
6  */
7
8 #include <cpu_func.h>
9 #include <env.h>
10 #include <init.h>
11 #include <asm/arch/hardware.h>
12 #include <asm/cache.h>
13 #include <asm/emif.h>
14 #include <common.h>
15 #include <command.h>
16
17 DECLARE_GLOBAL_DATA_PTR;
18
19 #ifdef CONFIG_ARCH_KEYSTONE
20 #include <asm/arch/ddr3.h>
21 #define DDR_MIN_ADDR            CONFIG_SYS_SDRAM_BASE
22 #define STACKSIZE               (512 << 10)     /* 512 KiB */
23
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 - \
28                                  STACKSIZE) >> 17) - 2)
29 #endif
30
31 #define DDR_TEST_BURST_SIZE     1024
32
33 static 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
140 static 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
162 static void ddr_check_ecc_status(void)
163 {
164         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");
177
178         if (int_status & EMIF_INT_TWOBIT_ECC_ERR_SYS_MASK)
179                 if (!ecc_test)
180                         panic("\tECC test: DDR ECC 2-bit error interrupted");
181
182         if (int_status & EMIF_INT_ONEBIT_ECC_ERR_SYS_MASK)
183                 puts("\tECC test: DDR ECC 1-bit error interrupted\n");
184
185         if (err_1b)
186                 printf("\tECC test: 1-bit ECC err count: 0x%x\n", err_1b);
187 }
188
189 static 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();
198
199         puts("Testing DDR ECC:\n");
200         puts("\tECC test: Disabling DDR ECC ...\n");
201         writel(0, &emif->emif_ecc_ctrl_reg);
202
203         val1 = readl(addr);
204         val2 = val1 ^ ecc_err;
205         writel(val2, addr);
206
207         val3 = readl(addr);
208 #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
216         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
221         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
229         return 0;
230 }
231
232 static 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;
249                 end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
250                                 CONFIG_SYS_SDRAM_BASE;
251                 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;
261                 end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
262                                 CONFIG_SYS_SDRAM_BASE;
263                 if ((addr >= start_addr) && (addr <= end_addr))
264                         /* addr within ecc address range 2 */
265                         return 1;
266         }
267
268         return 0;
269 }
270
271 static 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
280 static int do_ddr_test(struct cmd_tbl *cmdtp,
281                        int flag, int argc, char *const argv[])
282 {
283         u32 start_addr, end_addr, size, ecc_err;
284
285         if ((argc == 4) && (strncmp(argv[1], "ecc_err", 8) == 0)) {
286                 if (!is_ecc_enabled()) {
287                         puts("ECC not enabled. Please Enable ECC any try again\n");
288                         return CMD_RET_FAILURE;
289                 }
290
291                 start_addr = simple_strtoul(argv[2], NULL, 16);
292                 ecc_err = simple_strtoul(argv[3], NULL, 16);
293
294                 if (!is_addr_valid(start_addr)) {
295                         puts("Invalid address. Please enter ECC supported address!\n");
296                         return CMD_RET_FAILURE;
297                 }
298
299                 ddr_memory_ecc_err(start_addr, ecc_err);
300                 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 +
312              get_effective_memsize() - 1)) ||
313             (end_addr < CONFIG_SYS_SDRAM_BASE) ||
314             (end_addr > (CONFIG_SYS_SDRAM_BASE +
315              get_effective_memsize() - 1)) || (start_addr >= end_addr)) {
316                 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
331 U_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 );