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