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