blob: 1a31948cb17da2473d4e9c030e7b24187e4c7099 [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"
14
15DECLARE_GLOBAL_DATA_PTR;
16
17enum ddr_command {
18 DDR_CMD_HELP,
19 DDR_CMD_INFO,
20 DDR_CMD_FREQ,
21 DDR_CMD_RESET,
22 DDR_CMD_PARAM,
23 DDR_CMD_PRINT,
24 DDR_CMD_EDIT,
25 DDR_CMD_STEP,
26 DDR_CMD_NEXT,
27 DDR_CMD_GO,
28 DDR_CMD_TEST,
29 DDR_CMD_TUNING,
30 DDR_CMD_UNKNOWN,
31};
32
33const char *step_str[] = {
34 [STEP_DDR_RESET] = "DDR_RESET",
35 [STEP_CTL_INIT] = "DDR_CTRL_INIT_DONE",
36 [STEP_PHY_INIT] = "DDR PHY_INIT_DONE",
37 [STEP_DDR_READY] = "DDR_READY",
38 [STEP_RUN] = "RUN"
39};
40
41enum ddr_command stm32mp1_get_command(char *cmd, int argc)
42{
43 const char *cmd_string[DDR_CMD_UNKNOWN] = {
44 [DDR_CMD_HELP] = "help",
45 [DDR_CMD_INFO] = "info",
46 [DDR_CMD_FREQ] = "freq",
47 [DDR_CMD_RESET] = "reset",
48 [DDR_CMD_PARAM] = "param",
49 [DDR_CMD_PRINT] = "print",
50 [DDR_CMD_EDIT] = "edit",
51 [DDR_CMD_STEP] = "step",
52 [DDR_CMD_NEXT] = "next",
53 [DDR_CMD_GO] = "go",
54 };
55 /* min and max number of argument */
56 const char cmd_arg[DDR_CMD_UNKNOWN][2] = {
57 [DDR_CMD_HELP] = { 0, 0 },
58 [DDR_CMD_INFO] = { 0, 255 },
59 [DDR_CMD_FREQ] = { 0, 1 },
60 [DDR_CMD_RESET] = { 0, 0 },
61 [DDR_CMD_PARAM] = { 0, 2 },
62 [DDR_CMD_PRINT] = { 0, 1 },
63 [DDR_CMD_EDIT] = { 2, 2 },
64 [DDR_CMD_STEP] = { 0, 1 },
65 [DDR_CMD_NEXT] = { 0, 0 },
66 [DDR_CMD_GO] = { 0, 0 },
67 };
68 int i;
69
70 for (i = 0; i < DDR_CMD_UNKNOWN; i++)
71 if (!strcmp(cmd, cmd_string[i])) {
72 if (argc - 1 < cmd_arg[i][0]) {
73 printf("no enought argument (min=%d)\n",
74 cmd_arg[i][0]);
75 return DDR_CMD_UNKNOWN;
76 } else if (argc - 1 > cmd_arg[i][1]) {
77 printf("too many argument (max=%d)\n",
78 cmd_arg[i][1]);
79 return DDR_CMD_UNKNOWN;
80 } else {
81 return i;
82 }
83 }
84
85 printf("unknown command %s\n", cmd);
86 return DDR_CMD_UNKNOWN;
87}
88
89static void stm32mp1_do_usage(void)
90{
91 const char *usage = {
92 "commands:\n\n"
93 "help displays help\n"
94 "info displays DDR information\n"
95 "info <param> <val> changes DDR information\n"
96 " with <param> = step, name, size or speed\n"
97 "freq displays the DDR PHY frequency in kHz\n"
98 "freq <freq> changes the DDR PHY frequency\n"
99 "param [type|reg] prints input parameters\n"
100 "param <reg> <val> edits parameters in step 0\n"
101 "print [type|reg] dumps registers\n"
102 "edit <reg> <val> modifies one register\n"
103 "step lists the available step\n"
104 "step <n> go to the step <n>\n"
105 "next goes to the next step\n"
106 "go continues the U-Boot SPL execution\n"
107 "reset reboots machine\n"
108 "\nwith for [type|reg]:\n"
109 " all registers if absent\n"
110 " <type> = ctl, phy\n"
111 " or one category (static, timing, map, perf, cal, dyn)\n"
112 " <reg> = name of the register\n"
113 };
114
115 puts(usage);
116}
117
118static bool stm32mp1_check_step(enum stm32mp1_ddr_interact_step step,
119 enum stm32mp1_ddr_interact_step expected)
120{
121 if (step != expected) {
122 printf("invalid step %d:%s expecting %d:%s\n",
123 step, step_str[step],
124 expected,
125 step_str[expected]);
126 return false;
127 }
128 return true;
129}
130
131static void stm32mp1_do_info(struct ddr_info *priv,
132 struct stm32mp1_ddr_config *config,
133 enum stm32mp1_ddr_interact_step step,
134 int argc, char * const argv[])
135{
136 unsigned long value;
137 static char *ddr_name;
138
139 if (argc == 1) {
140 printf("step = %d : %s\n", step, step_str[step]);
141 printf("name = %s\n", config->info.name);
142 printf("size = 0x%x\n", config->info.size);
143 printf("speed = %d kHz\n", config->info.speed);
144 return;
145 }
146
147 if (argc < 3) {
148 printf("no enought parameter\n");
149 return;
150 }
151 if (!strcmp(argv[1], "name")) {
152 u32 i, name_len = 0;
153
154 for (i = 2; i < argc; i++)
155 name_len += strlen(argv[i]) + 1;
156 if (ddr_name)
157 free(ddr_name);
158 ddr_name = malloc(name_len);
159 config->info.name = ddr_name;
160 if (!ddr_name) {
161 printf("alloc error, length %d\n", name_len);
162 return;
163 }
164 strcpy(ddr_name, argv[2]);
165 for (i = 3; i < argc; i++) {
166 strcat(ddr_name, " ");
167 strcat(ddr_name, argv[i]);
168 }
169 printf("name = %s\n", ddr_name);
170 return;
171 }
172 if (!strcmp(argv[1], "size")) {
173 if (strict_strtoul(argv[2], 16, &value) < 0) {
174 printf("invalid value %s\n", argv[2]);
175 } else {
176 config->info.size = value;
177 printf("size = 0x%x\n", config->info.size);
178 }
179 return;
180 }
181 if (!strcmp(argv[1], "speed")) {
182 if (strict_strtoul(argv[2], 10, &value) < 0) {
183 printf("invalid value %s\n", argv[2]);
184 } else {
185 config->info.speed = value;
186 printf("speed = %d kHz\n", config->info.speed);
187 value = clk_get_rate(&priv->clk);
188 printf("DDRPHY = %ld kHz\n", value / 1000);
189 }
190 return;
191 }
192 printf("argument %s invalid\n", argv[1]);
193}
194
195static bool stm32mp1_do_freq(struct ddr_info *priv,
196 int argc, char * const argv[])
197{
198 unsigned long ddrphy_clk;
199
200 if (argc == 2) {
201 if (strict_strtoul(argv[1], 0, &ddrphy_clk) < 0) {
202 printf("invalid argument %s", argv[1]);
203 return false;
204 }
205 if (clk_set_rate(&priv->clk, ddrphy_clk * 1000)) {
206 printf("ERROR: update failed!\n");
207 return false;
208 }
209 }
210 ddrphy_clk = clk_get_rate(&priv->clk);
211 printf("DDRPHY = %ld kHz\n", ddrphy_clk / 1000);
212 if (argc == 2)
213 return true;
214 return false;
215}
216
217static void stm32mp1_do_param(enum stm32mp1_ddr_interact_step step,
218 const struct stm32mp1_ddr_config *config,
219 int argc, char * const argv[])
220{
221 switch (argc) {
222 case 1:
223 stm32mp1_dump_param(config, NULL);
224 break;
225 case 2:
226 if (stm32mp1_dump_param(config, argv[1]))
227 printf("invalid argument %s\n",
228 argv[1]);
229 break;
230 case 3:
231 if (!stm32mp1_check_step(step, STEP_DDR_RESET))
232 return;
233 stm32mp1_edit_param(config, argv[1], argv[2]);
234 break;
235 }
236}
237
238static void stm32mp1_do_print(struct ddr_info *priv,
239 int argc, char * const argv[])
240{
241 switch (argc) {
242 case 1:
243 stm32mp1_dump_reg(priv, NULL);
244 break;
245 case 2:
246 if (stm32mp1_dump_reg(priv, argv[1]))
247 printf("invalid argument %s\n",
248 argv[1]);
249 break;
250 }
251}
252
253static int stm32mp1_do_step(enum stm32mp1_ddr_interact_step step,
254 int argc, char * const argv[])
255{
256 int i;
257 unsigned long value;
258
259 switch (argc) {
260 case 1:
261 for (i = 0; i < ARRAY_SIZE(step_str); i++)
262 printf("%d:%s\n", i, step_str[i]);
263 break;
264
265 case 2:
266 if ((strict_strtoul(argv[1], 0,
267 &value) < 0) ||
268 value >= ARRAY_SIZE(step_str)) {
269 printf("invalid argument %s\n",
270 argv[1]);
271 goto end;
272 }
273
274 if (value != STEP_DDR_RESET &&
275 value <= step) {
276 printf("invalid target %d:%s, current step is %d:%s\n",
277 (int)value, step_str[value],
278 step, step_str[step]);
279 goto end;
280 }
281 printf("step to %d:%s\n",
282 (int)value, step_str[value]);
283 return (int)value;
284 };
285
286end:
287 return step;
288}
289
290bool stm32mp1_ddr_interactive(void *priv,
291 enum stm32mp1_ddr_interact_step step,
292 const struct stm32mp1_ddr_config *config)
293{
294 const char *prompt = "DDR>";
295 char buffer[CONFIG_SYS_CBSIZE];
296 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
297 int argc;
298 static int next_step = -1;
299
300 if (next_step < 0 && step == STEP_DDR_RESET) {
301#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE_FORCE
302 gd->flags &= ~(GD_FLG_SILENT |
303 GD_FLG_DISABLE_CONSOLE);
304 next_step = STEP_DDR_RESET;
305#else
306 unsigned long start = get_timer(0);
307
308 while (1) {
309 if (tstc() && (getc() == 'd')) {
310 next_step = STEP_DDR_RESET;
311 break;
312 }
313 if (get_timer(start) > 100)
314 break;
315 }
316#endif
317 }
318
319 debug("** step %d ** %s / %d\n", step, step_str[step], next_step);
320
321 if (next_step < 0)
322 return false;
323
324 if (step < 0 || step > ARRAY_SIZE(step_str)) {
325 printf("** step %d ** INVALID\n", step);
326 return false;
327 }
328
329 printf("%d:%s\n", step, step_str[step]);
330 printf("%s\n", prompt);
331
332 if (next_step > step)
333 return false;
334
335 while (next_step == step) {
336 cli_readline_into_buffer(prompt, buffer, 0);
337 argc = cli_simple_parse_line(buffer, argv);
338 if (!argc)
339 continue;
340
341 switch (stm32mp1_get_command(argv[0], argc)) {
342 case DDR_CMD_HELP:
343 stm32mp1_do_usage();
344 break;
345
346 case DDR_CMD_INFO:
347 stm32mp1_do_info(priv,
348 (struct stm32mp1_ddr_config *)config,
349 step, argc, argv);
350 break;
351
352 case DDR_CMD_FREQ:
353 if (stm32mp1_do_freq(priv, argc, argv))
354 next_step = STEP_DDR_RESET;
355 break;
356
357 case DDR_CMD_RESET:
358 do_reset(NULL, 0, 0, NULL);
359 break;
360
361 case DDR_CMD_PARAM:
362 stm32mp1_do_param(step, config, argc, argv);
363 break;
364
365 case DDR_CMD_PRINT:
366 stm32mp1_do_print(priv, argc, argv);
367 break;
368
369 case DDR_CMD_EDIT:
370 stm32mp1_edit_reg(priv, argv[1], argv[2]);
371 break;
372
373 case DDR_CMD_GO:
374 next_step = STEP_RUN;
375 break;
376
377 case DDR_CMD_NEXT:
378 next_step = step + 1;
379 break;
380
381 case DDR_CMD_STEP:
382 next_step = stm32mp1_do_step(step, argc, argv);
383 break;
384
385 default:
386 break;
387 }
388 }
389 return next_step == STEP_DDR_RESET;
390}