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 #include <asm/global_data.h>
18 
19 DECLARE_GLOBAL_DATA_PTR;
20 
21 #ifdef CONFIG_ARCH_KEYSTONE
22 #include <asm/arch/ddr3.h>
23 #define DDR_MIN_ADDR		CONFIG_SYS_SDRAM_BASE
24 #define STACKSIZE		(512 << 10)     /* 512 KiB */
25 
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 - \
30 				 STACKSIZE) >> 17) - 2)
31 #endif
32 
33 #define DDR_TEST_BURST_SIZE	1024
34 
ddr_memory_test(u32 start_address,u32 end_address,int quick)35 static 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 
ddr_memory_compare(u32 address1,u32 address2,u32 size)142 static 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 
ddr_check_ecc_status(void)164 static void ddr_check_ecc_status(void)
165 {
166 	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");
179 
180 	if (int_status & EMIF_INT_TWOBIT_ECC_ERR_SYS_MASK)
181 		if (!ecc_test)
182 			panic("\tECC test: DDR ECC 2-bit error interrupted");
183 
184 	if (int_status & EMIF_INT_ONEBIT_ECC_ERR_SYS_MASK)
185 		puts("\tECC test: DDR ECC 1-bit error interrupted\n");
186 
187 	if (err_1b)
188 		printf("\tECC test: 1-bit ECC err count: 0x%x\n", err_1b);
189 }
190 
ddr_memory_ecc_err(u32 addr,u32 ecc_err)191 static 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();
200 
201 	puts("Testing DDR ECC:\n");
202 	puts("\tECC test: Disabling DDR ECC ...\n");
203 	writel(0, &emif->emif_ecc_ctrl_reg);
204 
205 	val1 = readl(addr);
206 	val2 = val1 ^ ecc_err;
207 	writel(val2, addr);
208 
209 	val3 = readl(addr);
210 #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 
218 	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 
223 	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 
231 	return 0;
232 }
233 
is_addr_valid(u32 addr)234 static 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;
251 		end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
252 				CONFIG_SYS_SDRAM_BASE;
253 		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;
263 		end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF +
264 				CONFIG_SYS_SDRAM_BASE;
265 		if ((addr >= start_addr) && (addr <= end_addr))
266 			/* addr within ecc address range 2 */
267 			return 1;
268 	}
269 
270 	return 0;
271 }
272 
is_ecc_enabled(void)273 static 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 
do_ddr_test(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])282 static int do_ddr_test(struct cmd_tbl *cmdtp,
283 		       int flag, int argc, char *const argv[])
284 {
285 	u32 start_addr, end_addr, size, ecc_err;
286 
287 	if ((argc == 4) && (strncmp(argv[1], "ecc_err", 8) == 0)) {
288 		if (!is_ecc_enabled()) {
289 			puts("ECC not enabled. Please Enable ECC any try again\n");
290 			return CMD_RET_FAILURE;
291 		}
292 
293 		start_addr = simple_strtoul(argv[2], NULL, 16);
294 		ecc_err = simple_strtoul(argv[3], NULL, 16);
295 
296 		if (!is_addr_valid(start_addr)) {
297 			puts("Invalid address. Please enter ECC supported address!\n");
298 			return CMD_RET_FAILURE;
299 		}
300 
301 		ddr_memory_ecc_err(start_addr, ecc_err);
302 		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 +
314 	     get_effective_memsize() - 1)) ||
315 	    (end_addr < CONFIG_SYS_SDRAM_BASE) ||
316 	    (end_addr > (CONFIG_SYS_SDRAM_BASE +
317 	     get_effective_memsize() - 1)) || (start_addr >= end_addr)) {
318 		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 
333 U_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 );
344