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