ARM: mach-at91: Add compile time option to choose proper timer
[platform/kernel/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 #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
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
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
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
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
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
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
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
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
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
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 }