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