1 // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
3 * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
6 #define LOG_CATEGORY UCLASS_RAM
17 #include <asm/global_data.h>
18 #include "stm32mp1_ddr.h"
19 #include "stm32mp1_tests.h"
21 DECLARE_GLOBAL_DATA_PTR;
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",
47 enum ddr_command stm32mp1_get_command(char *cmd, int argc)
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",
60 #ifdef CONFIG_STM32MP1_DDR_TESTS
61 [DDR_CMD_TEST] = "test",
63 #ifdef CONFIG_STM32MP1_DDR_TUNING
64 [DDR_CMD_TUNING] = "tuning",
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 },
82 #ifdef CONFIG_STM32MP1_DDR_TUNING
83 [DDR_CMD_TUNING] = { 0, 255 },
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",
93 return DDR_CMD_UNKNOWN;
94 } else if (argc - 1 > cmd_arg[i][1]) {
95 printf("too many argument (max=%d)\n",
97 return DDR_CMD_UNKNOWN;
103 printf("unknown command %s\n", cmd);
104 return DDR_CMD_UNKNOWN;
107 static void stm32mp1_do_usage(void)
109 const char *usage = {
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 or speed\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"
129 #ifdef CONFIG_STM32MP1_DDR_TUNING
130 "tuning [help] | <n> [...] lists (with help) or execute tuning <n>\n"
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, dyn)\n"
136 " <reg> = name of the register\n"
142 static bool stm32mp1_check_step(enum stm32mp1_ddr_interact_step step,
143 enum stm32mp1_ddr_interact_step expected)
145 if (step != expected) {
146 printf("invalid step %d:%s expecting %d:%s\n",
147 step, step_str[step],
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[])
161 static char *ddr_name;
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);
172 printf("no enought parameter\n");
175 if (!strcmp(argv[1], "name")) {
178 for (i = 2; i < argc; i++)
179 name_len += strlen(argv[i]) + 1;
182 ddr_name = malloc(name_len);
183 config->info.name = ddr_name;
185 printf("alloc error, length %d\n", name_len);
188 strcpy(ddr_name, argv[2]);
189 for (i = 3; i < argc; i++) {
190 strcat(ddr_name, " ");
191 strcat(ddr_name, argv[i]);
193 printf("name = %s\n", ddr_name);
196 if (!strcmp(argv[1], "size")) {
197 if (strict_strtoul(argv[2], 16, &value) < 0) {
198 printf("invalid value %s\n", argv[2]);
200 config->info.size = value;
201 printf("size = 0x%x\n", config->info.size);
205 if (!strcmp(argv[1], "speed")) {
206 if (strict_strtoul(argv[2], 10, &value) < 0) {
207 printf("invalid value %s\n", argv[2]);
209 config->info.speed = value;
210 printf("speed = %d kHz\n", config->info.speed);
211 value = clk_get_rate(&priv->clk);
212 printf("DDRPHY = %ld kHz\n", value / 1000);
216 printf("argument %s invalid\n", argv[1]);
219 static bool stm32mp1_do_freq(struct ddr_info *priv,
220 int argc, char *const argv[])
222 unsigned long ddrphy_clk;
225 if (strict_strtoul(argv[1], 0, &ddrphy_clk) < 0) {
226 printf("invalid argument %s", argv[1]);
229 if (clk_set_rate(&priv->clk, ddrphy_clk * 1000)) {
230 printf("ERROR: update failed!\n");
234 ddrphy_clk = clk_get_rate(&priv->clk);
235 printf("DDRPHY = %ld kHz\n", ddrphy_clk / 1000);
241 static void stm32mp1_do_param(enum stm32mp1_ddr_interact_step step,
242 const struct stm32mp1_ddr_config *config,
243 int argc, char *const argv[])
247 stm32mp1_dump_param(config, NULL);
250 if (stm32mp1_dump_param(config, argv[1]))
251 printf("invalid argument %s\n",
255 if (!stm32mp1_check_step(step, STEP_DDR_RESET))
257 stm32mp1_edit_param(config, argv[1], argv[2]);
262 static void stm32mp1_do_print(struct ddr_info *priv,
263 int argc, char *const argv[])
267 stm32mp1_dump_reg(priv, NULL);
270 if (stm32mp1_dump_reg(priv, argv[1]))
271 printf("invalid argument %s\n",
277 static int stm32mp1_do_step(enum stm32mp1_ddr_interact_step step,
278 int argc, char *const argv[])
285 for (i = 0; i < ARRAY_SIZE(step_str); i++)
286 printf("%d:%s\n", i, step_str[i]);
290 if ((strict_strtoul(argv[1], 0,
292 value >= ARRAY_SIZE(step_str)) {
293 printf("invalid argument %s\n",
298 if (value != STEP_DDR_RESET &&
300 printf("invalid target %d:%s, current step is %d:%s\n",
301 (int)value, step_str[value],
302 step, step_str[step]);
305 printf("step to %d:%s\n",
306 (int)value, step_str[value]);
314 #if defined(CONFIG_STM32MP1_DDR_TESTS) || defined(CONFIG_STM32MP1_DDR_TUNING)
315 static const char * const s_result[] = {
316 [TEST_PASSED] = "Pass",
317 [TEST_FAILED] = "Failed",
318 [TEST_ERROR] = "Error"
321 static void stm32mp1_ddr_subcmd(struct ddr_info *priv,
322 int argc, char *argv[],
323 const struct test_desc array[],
329 char string[50] = "";
332 printf("%s:%d\n", argv[0], array_nb);
333 for (i = 0; i < array_nb; i++)
335 i, array[i].name, array[i].usage);
338 if (argc > 1 && !strcmp(argv[1], "help")) {
339 printf("%s:%d\n", argv[0], array_nb);
340 for (i = 0; i < array_nb; i++)
341 printf("%d:%s:%s:%s\n", i,
342 array[i].name, array[i].usage, array[i].help);
346 if ((strict_strtoul(argv[1], 0, &value) < 0) ||
348 sprintf(string, "invalid argument %s",
350 result = TEST_FAILED;
354 if (argc > (array[value].max_args + 2)) {
355 sprintf(string, "invalid nb of args %d, max %d",
356 argc - 2, array[value].max_args);
357 result = TEST_FAILED;
361 printf("execute %d:%s\n", (int)value, array[value].name);
363 result = array[value].fct(priv->ctl, priv->phy,
364 string, argc - 2, &argv[2]);
367 printf("Result: %s [%s]\n", s_result[result], string);
371 bool stm32mp1_ddr_interactive(void *priv,
372 enum stm32mp1_ddr_interact_step step,
373 const struct stm32mp1_ddr_config *config)
375 char buffer[CONFIG_SYS_CBSIZE];
376 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
378 static int next_step = -1;
380 if (next_step < 0 && step == STEP_DDR_RESET) {
381 #ifdef CONFIG_STM32MP1_DDR_INTERACTIVE_FORCE
382 gd->flags &= ~(GD_FLG_SILENT |
383 GD_FLG_DISABLE_CONSOLE);
384 next_step = STEP_DDR_RESET;
386 unsigned long start = get_timer(0);
389 if (tstc() && (getchar() == 'd')) {
390 next_step = STEP_DDR_RESET;
393 if (get_timer(start) > 100)
399 log_debug("** step %d ** %s / %d\n", step, step_str[step], next_step);
404 if (step < 0 || step > ARRAY_SIZE(step_str)) {
405 printf("** step %d ** INVALID\n", step);
409 printf("%d:%s\n", step, step_str[step]);
411 if (next_step > step)
414 while (next_step == step) {
415 cli_readline_into_buffer("DDR>", buffer, 0);
416 argc = cli_simple_parse_line(buffer, argv);
420 switch (stm32mp1_get_command(argv[0], argc)) {
426 stm32mp1_do_info(priv,
427 (struct stm32mp1_ddr_config *)config,
432 if (stm32mp1_do_freq(priv, argc, argv))
433 next_step = STEP_DDR_RESET;
437 do_reset(NULL, 0, 0, NULL);
441 stm32mp1_do_param(step, config, argc, argv);
445 stm32mp1_do_print(priv, argc, argv);
449 stm32mp1_edit_reg(priv, argv[1], argv[2]);
453 next_step = STEP_RUN;
457 next_step = step + 1;
461 next_step = stm32mp1_do_step(step, argc, argv);
464 #ifdef CONFIG_STM32MP1_DDR_TESTS
466 if (!stm32mp1_check_step(step, STEP_DDR_READY))
468 stm32mp1_ddr_subcmd(priv, argc, argv, test, test_nb);
472 #ifdef CONFIG_STM32MP1_DDR_TUNING
474 if (!stm32mp1_check_step(step, STEP_DDR_READY))
476 stm32mp1_ddr_subcmd(priv, argc, argv,
485 return next_step == STEP_DDR_RESET;