gk7205v200-uboot/drivers/ddr/goke/default/cmd_ddr_training_v2.c
2025-08-07 17:13:54 +08:00

287 lines
7.8 KiB
C
Executable File

/*
* Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved.
*/
#include <common.h>
#include <command.h>
#include "ddr_interface.h"
#ifndef TEXT_BASE
#define TEXT_BASE (CONFIG_SYS_TEXT_BASE) /* for arm64 u-boot-2016.11 */
#endif
#define DDR_TRAINING_ENV "ddrtr"
#define DDR_TRAINING_ENV_UN "unddrtr"
#define DDR_TRAINING_DDRT_START_OFFSET 0x400000 /* 4M */
#define DDR_TRAINING_DDRT_LENGTH 0x400000 /* 4M at lease 0x8000 */
#define DDR_CMD_SW_STR "training"
#define DDR_CMD_TR_STR "tr"
#define DDR_CMD_HW_STR "hw"
#define DDR_CMD_MPR_STR "mpr"
#define DDR_CMD_WL_STR "wl"
#define DDR_CMD_GATE_STR "gate"
#define DDR_CMD_DATAEYE_STR "dataeye"
#define DDR_CMD_VREF_STR "vref"
#define DDR_CMD_DCC_STR "dcc"
#define DDR_CMD_PCODE_STR "pcode"
#define DDR_CMD_AC_STR "ac"
#define DDR_CMD_LPCA_STR "lpca"
#define DDR_CMD_LOG_STR "log"
#define DDR_CMD_BOOT_STR "boot"
#define DDR_CMD_CONSOLE_STR "console"
static struct ddr_training_result_st ddrtr_result_st; /* DDR training result */
static int ddr_log_level = DDR_LOG_ERROR; /* DDR training log level */
#ifdef CONFIG_DDR_TRAINING_BOOTENV
extern int do_saveenv(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
#endif
#ifdef DDR_TRAINING_EXEC_TIME
/**
* Start timer for calculate DDR training execute time.
* NOTE: Just only for debug.
*/
static void cmd_exec_timer_start(void)
{
/* timer start */
ddr_write(0, 0xF8002000); /* REG_BASE_TIMER01 + REG_TIMER_RELOAD */
/* TIMER_EN | TIMER_MODE |TIMER_PRE | TIMER_SIZE, REG_TIMER_CONTROL */
ddr_write(0xc2, 0xF8002008);
ddr_write(0xffffffff, 0xF8002000);
}
/**
* Stop timer for calculate DDR training execute time.
* NOTE: Just only for debug.
*/
static void cmd_exec_timer_stop(void)
{
/* timer stop */
ddr_write(0, 0xF8002008); /* REG_TIMER_CONTROL */
/* REG_TIMER_VALUE, 24MHz */
printf("DDR training execute time: [%d]us\n",
(0xffffffff - ddr_read(0xF8002004)) / 24);
}
#endif
/**
* Match string command.
* NOTE: Write leveling not support run repeatedly,
* so limit WL only run one time.
*/
static int cmd_ddr_match(const char *str, int *cmd)
{
static int wl_done; /* Write leveling control */
if (!strncmp(str, DDR_CMD_SW_STR, sizeof(DDR_CMD_SW_STR))) {
*cmd = DDR_TRAINING_CMD_SW_NO_WL;
} else if (!strncmp(str, DDR_CMD_TR_STR, sizeof(DDR_CMD_TR_STR))) {
if (wl_done) {
*cmd = DDR_TRAINING_CMD_SW_NO_WL;
} else {
wl_done++;
*cmd = DDR_TRAINING_CMD_SW;
}
} else if (!strncmp(str, DDR_CMD_HW_STR, sizeof(DDR_CMD_HW_STR))) {
*cmd = DDR_TRAINING_CMD_HW;
} else if (!strncmp(str, DDR_CMD_MPR_STR, sizeof(DDR_CMD_MPR_STR))) {
*cmd = DDR_TRAINING_CMD_MPR;
} else if (!strncmp(str, DDR_CMD_WL_STR, sizeof(DDR_CMD_WL_STR))) {
if (wl_done) {
printf("WL not support run repeatedly. %s",
"Already done once, can not do again.\n");
return -1;
} else {
*cmd = DDR_TRAINING_CMD_WL;
wl_done++;
}
} else if (!strncmp(str, DDR_CMD_GATE_STR, sizeof(DDR_CMD_GATE_STR))) {
*cmd = DDR_TRAINING_CMD_GATE;
} else if (!strncmp(str, DDR_CMD_DATAEYE_STR,
sizeof(DDR_CMD_DATAEYE_STR))) {
*cmd = DDR_TRAINING_CMD_DATAEYE;
} else if (!strncmp(str, DDR_CMD_VREF_STR, sizeof(DDR_CMD_VREF_STR))) {
*cmd = DDR_TRAINING_CMD_VREF;
} else if (!strncmp(str, DDR_CMD_AC_STR, sizeof(DDR_CMD_AC_STR))) {
*cmd = DDR_TRAINING_CMD_AC;
} else if (!strncmp(str, DDR_CMD_LPCA_STR, sizeof(DDR_CMD_LPCA_STR))) {
*cmd = DDR_TRAINING_CMD_LPCA;
} else if (!strncmp(str, DDR_CMD_DCC_STR, sizeof(DDR_CMD_DCC_STR))) {
*cmd = DDR_TRAINING_CMD_DCC;
} else if (!strncmp(str, DDR_CMD_PCODE_STR, sizeof(DDR_CMD_PCODE_STR))) {
*cmd = DDR_TRAINING_CMD_PCODE;
} else if (!strncmp(str, DDR_CMD_CONSOLE_STR, sizeof(DDR_CMD_CONSOLE_STR))) {
*cmd = DDR_TRAINING_CMD_CONSOLE;
} else {
printf("Command [ddr %s] is unsupport.\n", str);
return -1;
}
return 0;
}
/**
* Handle DDR training.
* Copy training codes from DDR to SRAM.
*/
static int cmd_ddr_handle(int cmd)
{
struct ddr_training_result_st *result_st = NULL;
struct ddr_cmd_st cmd_st;
cmd_st.cmd = cmd;
cmd_st.level = ddr_log_level;
cmd_st.start = TEXT_BASE + DDR_TRAINING_DDRT_START_OFFSET;
cmd_st.length = DDR_TRAINING_DDRT_LENGTH;
printf("DDR training area: 0x%08X - 0x%08X\n",
cmd_st.start, cmd_st.start + cmd_st.length);
#ifdef DDR_TRAINING_EXEC_TIME
cmd_exec_timer_start();
#endif
result_st = ddr_cmd_training_if(&cmd_st);
#ifdef DDR_TRAINING_EXEC_TIME
cmd_exec_timer_stop();
#endif
if (!result_st)
return -1;
if (sizeof(ddrtr_result_st) != sizeof(*result_st))
return -1;
/* copy training result from SRAM to DDR */
memcpy((void *)&ddrtr_result_st, result_st,
sizeof(*result_st));
printf("DDR training finished.\n");
return 0;
}
/* DDR training cmd dispatch */
static int cmd_ddr_dispatch(int cmd)
{
int result = 0;
result = cmd_ddr_handle(cmd);
switch (cmd) {
case DDR_TRAINING_CMD_SW:
case DDR_TRAINING_CMD_SW_NO_WL:
case DDR_TRAINING_CMD_CONSOLE:
ddr_cmd_result_display(&ddrtr_result_st,
DDR_TRAINING_CMD_DATAEYE
| DDR_TRAINING_CMD_LPCA);
break;
case DDR_TRAINING_CMD_DATAEYE:
case DDR_TRAINING_CMD_VREF:
ddr_cmd_result_display(&ddrtr_result_st,
DDR_TRAINING_CMD_DATAEYE);
break;
case DDR_TRAINING_CMD_WL:
case DDR_TRAINING_CMD_GATE:
case DDR_TRAINING_CMD_HW:
case DDR_TRAINING_CMD_DCC:
case DDR_TRAINING_CMD_PCODE:
break;
case DDR_TRAINING_CMD_LPCA:
ddr_cmd_result_display(&ddrtr_result_st,
DDR_TRAINING_CMD_LPCA);
break;
default:
break;
}
ddr_reg_result_display(&ddrtr_result_st);
return result;
}
/* Set DDR training log level */
int cmd_ddr_set_log_level(char * const argv[])
{
int level;
const char *str;
str = argv[1];
if (strncmp(str, DDR_CMD_LOG_STR, sizeof(DDR_CMD_LOG_STR))) {
printf("Command [ddr %s] is unsupport.\n", str);
return -1;
}
str = argv[2];
if (!strncmp(str, DDR_LOG_INFO_STR, sizeof(DDR_LOG_INFO_STR))) {
level = DDR_LOG_INFO;
} else if (!strncmp(str, DDR_LOG_DEBUG_STR,
sizeof(DDR_LOG_DEBUG_STR))) {
level = DDR_LOG_DEBUG;
} else if (!strncmp(str, DDR_LOG_WARNING_STR,
sizeof(DDR_LOG_WARNING_STR))) {
level = DDR_LOG_WARNING;
} else if (!strncmp(str, DDR_LOG_ERROR_STR,
sizeof(DDR_LOG_ERROR_STR))) {
level = DDR_LOG_ERROR;
} else if (!strncmp(str, DDR_LOG_FATAL_STR,
sizeof(DDR_LOG_FATAL_STR))) {
level = DDR_LOG_FATAL;
} else {
printf("Command [ddr log %s] is unsupport.\n", str);
return -1;
}
ddr_log_level = level;
printf("Set DDR training log level [%s] suc.\n", str);
return 0;
}
/**
* Accept DDR training cmd.
* Set training result to env without save.
*/
static int do_ddr_training(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
const char *str = NULL;
int cmd;
if (argc < 2 || argc > 3) {
/* cmd_usage(cmdtp); */
return -1;
} else if (argc == 3) {
return cmd_ddr_set_log_level(argv);
}
str = argv[1];
if (cmd_ddr_match(str, &cmd))
return -1;
if (cmd_ddr_dispatch(cmd))
return -1;
return 0;
}
U_BOOT_CMD(
ddr, CONFIG_SYS_MAXARGS, 1, do_ddr_training,
"ddr training function",
"training - DDR sofeware(Gate/Dataeye/Vref) training.\n"
"ddr tr - DDR sofeware(WL/Gate/Dataeye/Vref) training.\n"
"ddr wl - DDR Write leveling training.\n"
"ddr gate - DDR gate training.\n"
"ddr dataeye - DDR dataeye training and display training result.\n"
"ddr vref - DDR vref training.\n"
"ddr hw - DDR hardware training.\n"
"ddr mpr - DDR Multi-Purpose Register training.\n"
"ddr ac - DDR address command training.\n"
"ddr lpca - LPDDR command address training.\n"
"ddr dcc - DDR Duty Correction Control training.\n"
"ddr pcode - DDR io pcode training.\n"
"ddr console - DDR do training in SRAM.\n"
"ddr log [level] - DDR log level. [info,debug,warning,error,fatal]\n"
);