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