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