/* * Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved. */ #include #include #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" );