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