]> Git Repo - u-boot.git/blob - cmd/ti/ddr3.c
Merge tag 'ti-v2021.01-rc1' of https://gitlab.denx.de/u-boot/custodians/u-boot-ti
[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 <log.h>
12 #include <asm/arch/hardware.h>
13 #include <asm/cache.h>
14 #include <asm/emif.h>
15 #include <common.h>
16 #include <command.h>
17
18 DECLARE_GLOBAL_DATA_PTR;
19
20 #ifdef CONFIG_ARCH_KEYSTONE
21 #include <asm/arch/ddr3.h>
22 #define DDR_MIN_ADDR            CONFIG_SYS_SDRAM_BASE
23 #define STACKSIZE               (512 << 10)     /* 512 KiB */
24
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 - \
29                                  STACKSIZE) >> 17) - 2)
30 #endif
31
32 #define DDR_TEST_BURST_SIZE     1024
33
34 static 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
141 static 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
163 static void ddr_check_ecc_status(void)
164 {
165         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;
170
171         env = env_get("ecc_test");
172         if (env)
173                 ecc_test = simple_strtol(env, NULL, 0);
174
175         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");
178
179         if (int_status & EMIF_INT_TWOBIT_ECC_ERR_SYS_MASK)
180                 if (!ecc_test)
181                         panic("\tECC test: DDR ECC 2-bit error interrupted");
182
183         if (int_status & EMIF_INT_ONEBIT_ECC_ERR_SYS_MASK)
184                 puts("\tECC test: DDR ECC 1-bit error interrupted\n");
185
186         if (err_1b)
187                 printf("\tECC test: 1-bit ECC err count: 0x%x\n", err_1b);
188 }
189
190 static 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;
195
196         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);
209 #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
217         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
222         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
230         return 0;
231 }
232
233 static 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;
250                 end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
251                                 CONFIG_SYS_SDRAM_BASE;
252                 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;
262                 end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
263                                 CONFIG_SYS_SDRAM_BASE;
264                 if ((addr >= start_addr) && (addr <= end_addr))
265                         /* addr within ecc address range 2 */
266                         return 1;
267         }
268
269         return 0;
270 }
271
272 static 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
281 static int do_ddr_test(struct cmd_tbl *cmdtp,
282                        int flag, int argc, char *const argv[])
283 {
284         u32 start_addr, end_addr, size, ecc_err;
285
286         if ((argc == 4) && (strncmp(argv[1], "ecc_err", 8) == 0)) {
287                 if (!is_ecc_enabled()) {
288                         puts("ECC not enabled. Please Enable ECC any try again\n");
289                         return CMD_RET_FAILURE;
290                 }
291
292                 start_addr = simple_strtoul(argv[2], NULL, 16);
293                 ecc_err = simple_strtoul(argv[3], NULL, 16);
294
295                 if (!is_addr_valid(start_addr)) {
296                         puts("Invalid address. Please enter ECC supported address!\n");
297                         return CMD_RET_FAILURE;
298                 }
299
300                 ddr_memory_ecc_err(start_addr, ecc_err);
301                 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 +
313              get_effective_memsize() - 1)) ||
314             (end_addr < CONFIG_SYS_SDRAM_BASE) ||
315             (end_addr > (CONFIG_SYS_SDRAM_BASE +
316              get_effective_memsize() - 1)) || (start_addr >= end_addr)) {
317                 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
332 U_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 );
This page took 0.057608 seconds and 4 git commands to generate.