1 // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2 /*
3  * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
4  */
5 
6 #define LOG_CATEGORY UCLASS_RAM
7 
8 #include <common.h>
9 #include <command.h>
10 #include <console.h>
11 #include <cli.h>
12 #include <clk.h>
13 #include <log.h>
14 #include <malloc.h>
15 #include <ram.h>
16 #include <reset.h>
17 #include <asm/global_data.h>
18 #include "stm32mp1_ddr.h"
19 #include "stm32mp1_tests.h"
20 
21 DECLARE_GLOBAL_DATA_PTR;
22 
23 enum ddr_command {
24 	DDR_CMD_HELP,
25 	DDR_CMD_INFO,
26 	DDR_CMD_FREQ,
27 	DDR_CMD_RESET,
28 	DDR_CMD_PARAM,
29 	DDR_CMD_PRINT,
30 	DDR_CMD_EDIT,
31 	DDR_CMD_STEP,
32 	DDR_CMD_NEXT,
33 	DDR_CMD_GO,
34 	DDR_CMD_TEST,
35 	DDR_CMD_UNKNOWN,
36 };
37 
38 const char *step_str[] = {
39 	[STEP_DDR_RESET] = "DDR_RESET",
40 	[STEP_CTL_INIT] = "DDR_CTRL_INIT_DONE",
41 	[STEP_PHY_INIT] = "DDR PHY_INIT_DONE",
42 	[STEP_DDR_READY] = "DDR_READY",
43 	[STEP_RUN] = "RUN"
44 };
45 
stm32mp1_get_command(char * cmd,int argc)46 enum ddr_command stm32mp1_get_command(char *cmd, int argc)
47 {
48 	const char *cmd_string[DDR_CMD_UNKNOWN] = {
49 		[DDR_CMD_HELP] = "help",
50 		[DDR_CMD_INFO] = "info",
51 		[DDR_CMD_FREQ] = "freq",
52 		[DDR_CMD_RESET] = "reset",
53 		[DDR_CMD_PARAM] = "param",
54 		[DDR_CMD_PRINT] = "print",
55 		[DDR_CMD_EDIT] = "edit",
56 		[DDR_CMD_STEP] = "step",
57 		[DDR_CMD_NEXT] = "next",
58 		[DDR_CMD_GO] = "go",
59 #ifdef CONFIG_STM32MP1_DDR_TESTS
60 		[DDR_CMD_TEST] = "test",
61 #endif
62 	};
63 	/* min and max number of argument */
64 	const char cmd_arg[DDR_CMD_UNKNOWN][2] = {
65 		[DDR_CMD_HELP] = { 0, 0 },
66 		[DDR_CMD_INFO] = { 0, 255 },
67 		[DDR_CMD_FREQ] = { 0, 1 },
68 		[DDR_CMD_RESET] = { 0, 0 },
69 		[DDR_CMD_PARAM] = { 0, 2 },
70 		[DDR_CMD_PRINT] = { 0, 1 },
71 		[DDR_CMD_EDIT] = { 2, 2 },
72 		[DDR_CMD_STEP] = { 0, 1 },
73 		[DDR_CMD_NEXT] = { 0, 0 },
74 		[DDR_CMD_GO] = { 0, 0 },
75 #ifdef CONFIG_STM32MP1_DDR_TESTS
76 		[DDR_CMD_TEST] = { 0, 255 },
77 #endif
78 	};
79 	int i;
80 
81 	for (i = 0; i < DDR_CMD_UNKNOWN; i++)
82 		if (!strcmp(cmd, cmd_string[i])) {
83 			if (argc - 1 < cmd_arg[i][0]) {
84 				printf("no enought argument (min=%d)\n",
85 				       cmd_arg[i][0]);
86 				return DDR_CMD_UNKNOWN;
87 			} else if (argc - 1 > cmd_arg[i][1]) {
88 				printf("too many argument (max=%d)\n",
89 				       cmd_arg[i][1]);
90 				return DDR_CMD_UNKNOWN;
91 			} else {
92 				return i;
93 			}
94 		}
95 
96 	printf("unknown command %s\n", cmd);
97 	return DDR_CMD_UNKNOWN;
98 }
99 
stm32mp1_do_usage(void)100 static void stm32mp1_do_usage(void)
101 {
102 	const char *usage = {
103 		"commands:\n\n"
104 		"help                       displays help\n"
105 		"info                       displays DDR information\n"
106 		"info  <param> <val>        changes DDR information\n"
107 		"      with <param> = step, name, size or speed\n"
108 		"freq                       displays the DDR PHY frequency in kHz\n"
109 		"freq  <freq>               changes the DDR PHY frequency\n"
110 		"param [type|reg]           prints input parameters\n"
111 		"param <reg> <val>          edits parameters in step 0\n"
112 		"print [type|reg]           dumps registers\n"
113 		"edit <reg> <val>           modifies one register\n"
114 		"step                       lists the available step\n"
115 		"step <n>                   go to the step <n>\n"
116 		"next                       goes to the next step\n"
117 		"go                         continues the U-Boot SPL execution\n"
118 		"reset                      reboots machine\n"
119 #ifdef CONFIG_STM32MP1_DDR_TESTS
120 		"test [help] | <n> [...]    lists (with help) or executes test <n>\n"
121 #endif
122 		"\nwith for [type|reg]:\n"
123 		"  all registers if absent\n"
124 		"  <type> = ctl, phy\n"
125 		"           or one category (static, timing, map, perf, dyn)\n"
126 		"  <reg> = name of the register\n"
127 	};
128 
129 	puts(usage);
130 }
131 
stm32mp1_check_step(enum stm32mp1_ddr_interact_step step,enum stm32mp1_ddr_interact_step expected)132 static bool stm32mp1_check_step(enum stm32mp1_ddr_interact_step step,
133 				enum stm32mp1_ddr_interact_step expected)
134 {
135 	if (step != expected) {
136 		printf("invalid step %d:%s expecting %d:%s\n",
137 		       step, step_str[step],
138 		       expected,
139 		       step_str[expected]);
140 		return false;
141 	}
142 	return true;
143 }
144 
stm32mp1_do_info(struct ddr_info * priv,struct stm32mp1_ddr_config * config,enum stm32mp1_ddr_interact_step step,int argc,char * const argv[])145 static void stm32mp1_do_info(struct ddr_info *priv,
146 			     struct stm32mp1_ddr_config *config,
147 			     enum stm32mp1_ddr_interact_step step,
148 			     int argc, char *const argv[])
149 {
150 	unsigned long value;
151 	static char *ddr_name;
152 
153 	if (argc == 1) {
154 		printf("step = %d : %s\n", step, step_str[step]);
155 		printf("name = %s\n", config->info.name);
156 		printf("size = 0x%x\n", config->info.size);
157 		printf("speed = %d kHz\n", config->info.speed);
158 		return;
159 	}
160 
161 	if (argc < 3) {
162 		printf("no enought parameter\n");
163 		return;
164 	}
165 	if (!strcmp(argv[1], "name")) {
166 		u32 i, name_len = 0;
167 
168 		for (i = 2; i < argc; i++)
169 			name_len += strlen(argv[i]) + 1;
170 		if (ddr_name)
171 			free(ddr_name);
172 		ddr_name = malloc(name_len);
173 		config->info.name = ddr_name;
174 		if (!ddr_name) {
175 			printf("alloc error, length %d\n", name_len);
176 			return;
177 		}
178 		strcpy(ddr_name, argv[2]);
179 		for (i = 3; i < argc; i++) {
180 			strcat(ddr_name, " ");
181 			strcat(ddr_name, argv[i]);
182 		}
183 		printf("name = %s\n", ddr_name);
184 		return;
185 	}
186 	if (!strcmp(argv[1], "size")) {
187 		if (strict_strtoul(argv[2], 16, &value) < 0) {
188 			printf("invalid value %s\n", argv[2]);
189 		} else {
190 			config->info.size = value;
191 			printf("size = 0x%x\n", config->info.size);
192 		}
193 		return;
194 	}
195 	if (!strcmp(argv[1], "speed")) {
196 		if (strict_strtoul(argv[2], 10, &value) < 0) {
197 			printf("invalid value %s\n", argv[2]);
198 		} else {
199 			config->info.speed = value;
200 			printf("speed = %d kHz\n", config->info.speed);
201 			value = clk_get_rate(&priv->clk);
202 			printf("DDRPHY = %ld kHz\n", value / 1000);
203 		}
204 		return;
205 	}
206 	printf("argument %s invalid\n", argv[1]);
207 }
208 
stm32mp1_do_freq(struct ddr_info * priv,int argc,char * const argv[])209 static bool stm32mp1_do_freq(struct ddr_info *priv,
210 			     int argc, char *const argv[])
211 {
212 	unsigned long ddrphy_clk;
213 
214 	if (argc == 2) {
215 		if (strict_strtoul(argv[1], 0, &ddrphy_clk) < 0) {
216 			printf("invalid argument %s", argv[1]);
217 			return false;
218 		}
219 		if (clk_set_rate(&priv->clk, ddrphy_clk * 1000)) {
220 			printf("ERROR: update failed!\n");
221 			return false;
222 		}
223 	}
224 	ddrphy_clk = clk_get_rate(&priv->clk);
225 	printf("DDRPHY = %ld kHz\n", ddrphy_clk / 1000);
226 	if (argc == 2)
227 		return true;
228 	return false;
229 }
230 
stm32mp1_do_param(enum stm32mp1_ddr_interact_step step,const struct stm32mp1_ddr_config * config,int argc,char * const argv[])231 static void stm32mp1_do_param(enum stm32mp1_ddr_interact_step step,
232 			      const struct stm32mp1_ddr_config *config,
233 			      int argc, char *const argv[])
234 {
235 	switch (argc) {
236 	case 1:
237 		stm32mp1_dump_param(config, NULL);
238 		break;
239 	case 2:
240 		if (stm32mp1_dump_param(config, argv[1]))
241 			printf("invalid argument %s\n",
242 			       argv[1]);
243 		break;
244 	case 3:
245 		if (!stm32mp1_check_step(step, STEP_DDR_RESET))
246 			return;
247 		stm32mp1_edit_param(config, argv[1], argv[2]);
248 		break;
249 	}
250 }
251 
stm32mp1_do_print(struct ddr_info * priv,int argc,char * const argv[])252 static void stm32mp1_do_print(struct ddr_info *priv,
253 			      int argc, char *const argv[])
254 {
255 	switch (argc) {
256 	case 1:
257 		stm32mp1_dump_reg(priv, NULL);
258 		break;
259 	case 2:
260 		if (stm32mp1_dump_reg(priv, argv[1]))
261 			printf("invalid argument %s\n",
262 			       argv[1]);
263 		break;
264 	}
265 }
266 
stm32mp1_do_step(enum stm32mp1_ddr_interact_step step,int argc,char * const argv[])267 static int stm32mp1_do_step(enum stm32mp1_ddr_interact_step step,
268 			    int argc, char *const argv[])
269 {
270 	int i;
271 	unsigned long value;
272 
273 	switch (argc) {
274 	case 1:
275 		for (i = 0; i < ARRAY_SIZE(step_str); i++)
276 			printf("%d:%s\n", i, step_str[i]);
277 		break;
278 
279 	case 2:
280 		if ((strict_strtoul(argv[1], 0,
281 				    &value) < 0) ||
282 				    value >= ARRAY_SIZE(step_str)) {
283 			printf("invalid argument %s\n",
284 			       argv[1]);
285 			goto end;
286 		}
287 
288 		if (value != STEP_DDR_RESET &&
289 		    value <= step) {
290 			printf("invalid target %d:%s, current step is %d:%s\n",
291 			       (int)value, step_str[value],
292 			       step, step_str[step]);
293 			goto end;
294 		}
295 		printf("step to %d:%s\n",
296 		       (int)value, step_str[value]);
297 		return (int)value;
298 	};
299 
300 end:
301 	return step;
302 }
303 
304 #if defined(CONFIG_STM32MP1_DDR_TESTS)
305 static const char * const s_result[] = {
306 		[TEST_PASSED] = "Pass",
307 		[TEST_FAILED] = "Failed",
308 		[TEST_ERROR] = "Error"
309 };
310 
stm32mp1_ddr_subcmd(struct ddr_info * priv,int argc,char * argv[],const struct test_desc array[],const int array_nb)311 static void stm32mp1_ddr_subcmd(struct ddr_info *priv,
312 				int argc, char *argv[],
313 				const struct test_desc array[],
314 				const int array_nb)
315 {
316 	int i;
317 	unsigned long value;
318 	int result;
319 	char string[50] = "";
320 
321 	if (argc == 1) {
322 		printf("%s:%d\n", argv[0], array_nb);
323 		for (i = 0; i < array_nb; i++)
324 			printf("%d:%s:%s\n",
325 			       i, array[i].name, array[i].usage);
326 		return;
327 	}
328 	if (argc > 1 && !strcmp(argv[1], "help")) {
329 		printf("%s:%d\n", argv[0], array_nb);
330 		for (i = 0; i < array_nb; i++)
331 			printf("%d:%s:%s:%s\n", i,
332 			       array[i].name, array[i].usage, array[i].help);
333 		return;
334 	}
335 
336 	if ((strict_strtoul(argv[1], 0, &value) <  0) ||
337 	    value >= array_nb) {
338 		sprintf(string, "invalid argument %s",
339 			argv[1]);
340 		result = TEST_FAILED;
341 		goto end;
342 	}
343 
344 	if (argc > (array[value].max_args + 2)) {
345 		sprintf(string, "invalid nb of args %d, max %d",
346 			argc - 2, array[value].max_args);
347 		result = TEST_FAILED;
348 		goto end;
349 	}
350 
351 	printf("execute %d:%s\n", (int)value, array[value].name);
352 	clear_ctrlc();
353 	result = array[value].fct(priv->ctl, priv->phy,
354 				  string, argc - 2, &argv[2]);
355 
356 end:
357 	printf("Result: %s [%s]\n", s_result[result], string);
358 }
359 #endif
360 
stm32mp1_ddr_interactive(void * priv,enum stm32mp1_ddr_interact_step step,const struct stm32mp1_ddr_config * config)361 bool stm32mp1_ddr_interactive(void *priv,
362 			      enum stm32mp1_ddr_interact_step step,
363 			      const struct stm32mp1_ddr_config *config)
364 {
365 	char buffer[CONFIG_SYS_CBSIZE];
366 	char *argv[CONFIG_SYS_MAXARGS + 1];	/* NULL terminated */
367 	int argc;
368 	static int next_step = -1;
369 
370 	if (next_step < 0 && step == STEP_DDR_RESET) {
371 #ifdef CONFIG_STM32MP1_DDR_INTERACTIVE_FORCE
372 		gd->flags &= ~(GD_FLG_SILENT |
373 			       GD_FLG_DISABLE_CONSOLE);
374 		next_step = STEP_DDR_RESET;
375 #else
376 		unsigned long start = get_timer(0);
377 
378 		while (1) {
379 			if (tstc() && (getchar() == 'd')) {
380 				next_step = STEP_DDR_RESET;
381 				break;
382 			}
383 			if (get_timer(start) > 100)
384 				break;
385 		}
386 #endif
387 	}
388 
389 	log_debug("** step %d ** %s / %d\n", step, step_str[step], next_step);
390 
391 	if (next_step < 0)
392 		return false;
393 
394 	if (step < 0 || step >= ARRAY_SIZE(step_str)) {
395 		printf("** step %d ** INVALID\n", step);
396 		return false;
397 	}
398 
399 	printf("%d:%s\n", step, step_str[step]);
400 
401 	if (next_step > step)
402 		return false;
403 
404 	while (next_step == step) {
405 		cli_readline_into_buffer("DDR>", buffer, 0);
406 		argc = cli_simple_parse_line(buffer, argv);
407 		if (!argc)
408 			continue;
409 
410 		switch (stm32mp1_get_command(argv[0], argc)) {
411 		case DDR_CMD_HELP:
412 			stm32mp1_do_usage();
413 			break;
414 
415 		case DDR_CMD_INFO:
416 			stm32mp1_do_info(priv,
417 					 (struct stm32mp1_ddr_config *)config,
418 					 step, argc, argv);
419 			break;
420 
421 		case DDR_CMD_FREQ:
422 			if (stm32mp1_do_freq(priv, argc, argv))
423 				next_step = STEP_DDR_RESET;
424 			break;
425 
426 		case DDR_CMD_RESET:
427 			do_reset(NULL, 0, 0, NULL);
428 			break;
429 
430 		case DDR_CMD_PARAM:
431 			stm32mp1_do_param(step, config, argc, argv);
432 			break;
433 
434 		case DDR_CMD_PRINT:
435 			stm32mp1_do_print(priv, argc, argv);
436 			break;
437 
438 		case DDR_CMD_EDIT:
439 			stm32mp1_edit_reg(priv, argv[1], argv[2]);
440 			break;
441 
442 		case DDR_CMD_GO:
443 			next_step = STEP_RUN;
444 			break;
445 
446 		case DDR_CMD_NEXT:
447 			next_step = step + 1;
448 			break;
449 
450 		case DDR_CMD_STEP:
451 			next_step = stm32mp1_do_step(step, argc, argv);
452 			break;
453 
454 #ifdef CONFIG_STM32MP1_DDR_TESTS
455 		case DDR_CMD_TEST:
456 			if (!stm32mp1_check_step(step, STEP_DDR_READY))
457 				continue;
458 			stm32mp1_ddr_subcmd(priv, argc, argv, test, test_nb);
459 			break;
460 #endif
461 		default:
462 			break;
463 		}
464 	}
465 	return next_step == STEP_DDR_RESET;
466 }
467