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