• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ddr_memory_test(u32 start_address,u32 end_address,int quick)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 
ddr_memory_compare(u32 address1,u32 address2,u32 size)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 
ddr_check_ecc_status(void)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 
ddr_memory_ecc_err(u32 addr,u32 ecc_err)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 
is_addr_valid(u32 addr)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 
is_ecc_enabled(void)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 
do_ddr_test(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])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 );
340