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