u-boot/drivers/ram/stm32mp1/stm32mp1_interactive.c
Heinrich Schuchardt c670aeee3d common: rename getc() to getchar()
The sandbox is built with the SDL2 library with invokes the X11 library
which in turn calls getc(). But getc() in glibc is defined as

    int getc(FILE *)

This does not match our definition.

    int getc(void)

The sandbox crashes when called with parameter -l.

Rename our library symbol getc() to getchar().

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
2020-10-22 09:54:53 -04:00

494 lines
11 KiB
C

// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
*/
#include <common.h>
#include <command.h>
#include <console.h>
#include <cli.h>
#include <clk.h>
#include <log.h>
#include <malloc.h>
#include <ram.h>
#include <reset.h>
#include "stm32mp1_ddr.h"
#include "stm32mp1_tests.h"
DECLARE_GLOBAL_DATA_PTR;
enum ddr_command {
DDR_CMD_HELP,
DDR_CMD_INFO,
DDR_CMD_FREQ,
DDR_CMD_RESET,
DDR_CMD_PARAM,
DDR_CMD_PRINT,
DDR_CMD_EDIT,
DDR_CMD_STEP,
DDR_CMD_NEXT,
DDR_CMD_GO,
DDR_CMD_TEST,
DDR_CMD_TUNING,
DDR_CMD_UNKNOWN,
};
const char *step_str[] = {
[STEP_DDR_RESET] = "DDR_RESET",
[STEP_CTL_INIT] = "DDR_CTRL_INIT_DONE",
[STEP_PHY_INIT] = "DDR PHY_INIT_DONE",
[STEP_DDR_READY] = "DDR_READY",
[STEP_RUN] = "RUN"
};
enum ddr_command stm32mp1_get_command(char *cmd, int argc)
{
const char *cmd_string[DDR_CMD_UNKNOWN] = {
[DDR_CMD_HELP] = "help",
[DDR_CMD_INFO] = "info",
[DDR_CMD_FREQ] = "freq",
[DDR_CMD_RESET] = "reset",
[DDR_CMD_PARAM] = "param",
[DDR_CMD_PRINT] = "print",
[DDR_CMD_EDIT] = "edit",
[DDR_CMD_STEP] = "step",
[DDR_CMD_NEXT] = "next",
[DDR_CMD_GO] = "go",
#ifdef CONFIG_STM32MP1_DDR_TESTS
[DDR_CMD_TEST] = "test",
#endif
#ifdef CONFIG_STM32MP1_DDR_TUNING
[DDR_CMD_TUNING] = "tuning",
#endif
};
/* min and max number of argument */
const char cmd_arg[DDR_CMD_UNKNOWN][2] = {
[DDR_CMD_HELP] = { 0, 0 },
[DDR_CMD_INFO] = { 0, 255 },
[DDR_CMD_FREQ] = { 0, 1 },
[DDR_CMD_RESET] = { 0, 0 },
[DDR_CMD_PARAM] = { 0, 2 },
[DDR_CMD_PRINT] = { 0, 1 },
[DDR_CMD_EDIT] = { 2, 2 },
[DDR_CMD_STEP] = { 0, 1 },
[DDR_CMD_NEXT] = { 0, 0 },
[DDR_CMD_GO] = { 0, 0 },
#ifdef CONFIG_STM32MP1_DDR_TESTS
[DDR_CMD_TEST] = { 0, 255 },
#endif
#ifdef CONFIG_STM32MP1_DDR_TUNING
[DDR_CMD_TUNING] = { 0, 255 },
#endif
};
int i;
for (i = 0; i < DDR_CMD_UNKNOWN; i++)
if (!strcmp(cmd, cmd_string[i])) {
if (argc - 1 < cmd_arg[i][0]) {
printf("no enought argument (min=%d)\n",
cmd_arg[i][0]);
return DDR_CMD_UNKNOWN;
} else if (argc - 1 > cmd_arg[i][1]) {
printf("too many argument (max=%d)\n",
cmd_arg[i][1]);
return DDR_CMD_UNKNOWN;
} else {
return i;
}
}
printf("unknown command %s\n", cmd);
return DDR_CMD_UNKNOWN;
}
static void stm32mp1_do_usage(void)
{
const char *usage = {
"commands:\n\n"
"help displays help\n"
"info displays DDR information\n"
"info <param> <val> changes DDR information\n"
" with <param> = step, name, size, speed or cal\n"
"freq displays the DDR PHY frequency in kHz\n"
"freq <freq> changes the DDR PHY frequency\n"
"param [type|reg] prints input parameters\n"
"param <reg> <val> edits parameters in step 0\n"
"print [type|reg] dumps registers\n"
"edit <reg> <val> modifies one register\n"
"step lists the available step\n"
"step <n> go to the step <n>\n"
"next goes to the next step\n"
"go continues the U-Boot SPL execution\n"
"reset reboots machine\n"
#ifdef CONFIG_STM32MP1_DDR_TESTS
"test [help] | <n> [...] lists (with help) or executes test <n>\n"
#endif
#ifdef CONFIG_STM32MP1_DDR_TUNING
"tuning [help] | <n> [...] lists (with help) or execute tuning <n>\n"
#endif
"\nwith for [type|reg]:\n"
" all registers if absent\n"
" <type> = ctl, phy\n"
" or one category (static, timing, map, perf, cal, dyn)\n"
" <reg> = name of the register\n"
};
puts(usage);
}
static bool stm32mp1_check_step(enum stm32mp1_ddr_interact_step step,
enum stm32mp1_ddr_interact_step expected)
{
if (step != expected) {
printf("invalid step %d:%s expecting %d:%s\n",
step, step_str[step],
expected,
step_str[expected]);
return false;
}
return true;
}
static void stm32mp1_do_info(struct ddr_info *priv,
struct stm32mp1_ddr_config *config,
enum stm32mp1_ddr_interact_step step,
int argc, char *const argv[])
{
unsigned long value;
static char *ddr_name;
if (argc == 1) {
printf("step = %d : %s\n", step, step_str[step]);
printf("name = %s\n", config->info.name);
printf("size = 0x%x\n", config->info.size);
printf("speed = %d kHz\n", config->info.speed);
printf("cal = %d\n", config->p_cal_present);
return;
}
if (argc < 3) {
printf("no enought parameter\n");
return;
}
if (!strcmp(argv[1], "name")) {
u32 i, name_len = 0;
for (i = 2; i < argc; i++)
name_len += strlen(argv[i]) + 1;
if (ddr_name)
free(ddr_name);
ddr_name = malloc(name_len);
config->info.name = ddr_name;
if (!ddr_name) {
printf("alloc error, length %d\n", name_len);
return;
}
strcpy(ddr_name, argv[2]);
for (i = 3; i < argc; i++) {
strcat(ddr_name, " ");
strcat(ddr_name, argv[i]);
}
printf("name = %s\n", ddr_name);
return;
}
if (!strcmp(argv[1], "size")) {
if (strict_strtoul(argv[2], 16, &value) < 0) {
printf("invalid value %s\n", argv[2]);
} else {
config->info.size = value;
printf("size = 0x%x\n", config->info.size);
}
return;
}
if (!strcmp(argv[1], "speed")) {
if (strict_strtoul(argv[2], 10, &value) < 0) {
printf("invalid value %s\n", argv[2]);
} else {
config->info.speed = value;
printf("speed = %d kHz\n", config->info.speed);
value = clk_get_rate(&priv->clk);
printf("DDRPHY = %ld kHz\n", value / 1000);
}
return;
}
if (!strcmp(argv[1], "cal")) {
if (strict_strtoul(argv[2], 10, &value) < 0 ||
(value != 0 && value != 1)) {
printf("invalid value %s\n", argv[2]);
} else {
config->p_cal_present = value;
printf("cal = %d\n", config->p_cal_present);
}
return;
}
printf("argument %s invalid\n", argv[1]);
}
static bool stm32mp1_do_freq(struct ddr_info *priv,
int argc, char *const argv[])
{
unsigned long ddrphy_clk;
if (argc == 2) {
if (strict_strtoul(argv[1], 0, &ddrphy_clk) < 0) {
printf("invalid argument %s", argv[1]);
return false;
}
if (clk_set_rate(&priv->clk, ddrphy_clk * 1000)) {
printf("ERROR: update failed!\n");
return false;
}
}
ddrphy_clk = clk_get_rate(&priv->clk);
printf("DDRPHY = %ld kHz\n", ddrphy_clk / 1000);
if (argc == 2)
return true;
return false;
}
static void stm32mp1_do_param(enum stm32mp1_ddr_interact_step step,
const struct stm32mp1_ddr_config *config,
int argc, char *const argv[])
{
switch (argc) {
case 1:
stm32mp1_dump_param(config, NULL);
break;
case 2:
if (stm32mp1_dump_param(config, argv[1]))
printf("invalid argument %s\n",
argv[1]);
break;
case 3:
if (!stm32mp1_check_step(step, STEP_DDR_RESET))
return;
stm32mp1_edit_param(config, argv[1], argv[2]);
break;
}
}
static void stm32mp1_do_print(struct ddr_info *priv,
int argc, char *const argv[])
{
switch (argc) {
case 1:
stm32mp1_dump_reg(priv, NULL);
break;
case 2:
if (stm32mp1_dump_reg(priv, argv[1]))
printf("invalid argument %s\n",
argv[1]);
break;
}
}
static int stm32mp1_do_step(enum stm32mp1_ddr_interact_step step,
int argc, char *const argv[])
{
int i;
unsigned long value;
switch (argc) {
case 1:
for (i = 0; i < ARRAY_SIZE(step_str); i++)
printf("%d:%s\n", i, step_str[i]);
break;
case 2:
if ((strict_strtoul(argv[1], 0,
&value) < 0) ||
value >= ARRAY_SIZE(step_str)) {
printf("invalid argument %s\n",
argv[1]);
goto end;
}
if (value != STEP_DDR_RESET &&
value <= step) {
printf("invalid target %d:%s, current step is %d:%s\n",
(int)value, step_str[value],
step, step_str[step]);
goto end;
}
printf("step to %d:%s\n",
(int)value, step_str[value]);
return (int)value;
};
end:
return step;
}
#if defined(CONFIG_STM32MP1_DDR_TESTS) || defined(CONFIG_STM32MP1_DDR_TUNING)
static const char * const s_result[] = {
[TEST_PASSED] = "Pass",
[TEST_FAILED] = "Failed",
[TEST_ERROR] = "Error"
};
static void stm32mp1_ddr_subcmd(struct ddr_info *priv,
int argc, char *argv[],
const struct test_desc array[],
const int array_nb)
{
int i;
unsigned long value;
int result;
char string[50] = "";
if (argc == 1) {
printf("%s:%d\n", argv[0], array_nb);
for (i = 0; i < array_nb; i++)
printf("%d:%s:%s\n",
i, array[i].name, array[i].usage);
return;
}
if (argc > 1 && !strcmp(argv[1], "help")) {
printf("%s:%d\n", argv[0], array_nb);
for (i = 0; i < array_nb; i++)
printf("%d:%s:%s:%s\n", i,
array[i].name, array[i].usage, array[i].help);
return;
}
if ((strict_strtoul(argv[1], 0, &value) < 0) ||
value >= array_nb) {
sprintf(string, "invalid argument %s",
argv[1]);
result = TEST_FAILED;
goto end;
}
if (argc > (array[value].max_args + 2)) {
sprintf(string, "invalid nb of args %d, max %d",
argc - 2, array[value].max_args);
result = TEST_FAILED;
goto end;
}
printf("execute %d:%s\n", (int)value, array[value].name);
clear_ctrlc();
result = array[value].fct(priv->ctl, priv->phy,
string, argc - 2, &argv[2]);
end:
printf("Result: %s [%s]\n", s_result[result], string);
}
#endif
bool stm32mp1_ddr_interactive(void *priv,
enum stm32mp1_ddr_interact_step step,
const struct stm32mp1_ddr_config *config)
{
char buffer[CONFIG_SYS_CBSIZE];
char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
int argc;
static int next_step = -1;
if (next_step < 0 && step == STEP_DDR_RESET) {
#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE_FORCE
gd->flags &= ~(GD_FLG_SILENT |
GD_FLG_DISABLE_CONSOLE);
next_step = STEP_DDR_RESET;
#else
unsigned long start = get_timer(0);
while (1) {
if (tstc() && (getchar() == 'd')) {
next_step = STEP_DDR_RESET;
break;
}
if (get_timer(start) > 100)
break;
}
#endif
}
debug("** step %d ** %s / %d\n", step, step_str[step], next_step);
if (next_step < 0)
return false;
if (step < 0 || step > ARRAY_SIZE(step_str)) {
printf("** step %d ** INVALID\n", step);
return false;
}
printf("%d:%s\n", step, step_str[step]);
if (next_step > step)
return false;
while (next_step == step) {
cli_readline_into_buffer("DDR>", buffer, 0);
argc = cli_simple_parse_line(buffer, argv);
if (!argc)
continue;
switch (stm32mp1_get_command(argv[0], argc)) {
case DDR_CMD_HELP:
stm32mp1_do_usage();
break;
case DDR_CMD_INFO:
stm32mp1_do_info(priv,
(struct stm32mp1_ddr_config *)config,
step, argc, argv);
break;
case DDR_CMD_FREQ:
if (stm32mp1_do_freq(priv, argc, argv))
next_step = STEP_DDR_RESET;
break;
case DDR_CMD_RESET:
do_reset(NULL, 0, 0, NULL);
break;
case DDR_CMD_PARAM:
stm32mp1_do_param(step, config, argc, argv);
break;
case DDR_CMD_PRINT:
stm32mp1_do_print(priv, argc, argv);
break;
case DDR_CMD_EDIT:
stm32mp1_edit_reg(priv, argv[1], argv[2]);
break;
case DDR_CMD_GO:
next_step = STEP_RUN;
break;
case DDR_CMD_NEXT:
next_step = step + 1;
break;
case DDR_CMD_STEP:
next_step = stm32mp1_do_step(step, argc, argv);
break;
#ifdef CONFIG_STM32MP1_DDR_TESTS
case DDR_CMD_TEST:
if (!stm32mp1_check_step(step, STEP_DDR_READY))
continue;
stm32mp1_ddr_subcmd(priv, argc, argv, test, test_nb);
break;
#endif
#ifdef CONFIG_STM32MP1_DDR_TUNING
case DDR_CMD_TUNING:
if (!stm32mp1_check_step(step, STEP_DDR_READY))
continue;
stm32mp1_ddr_subcmd(priv, argc, argv,
tuning, tuning_nb);
break;
#endif
default:
break;
}
}
return next_step == STEP_DDR_RESET;
}