stm32mp1_interactive.c 11 KB

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