491 lines
12 KiB
C
491 lines
12 KiB
C
|
|
/*
|
||
|
|
* Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <stdarg.h>
|
||
|
|
#include <command.h>
|
||
|
|
#include "ddr_interface.h"
|
||
|
|
#include "ddr_training_impl.h"
|
||
|
|
|
||
|
|
/* ddr training cmd result */
|
||
|
|
struct ddr_training_result_st ddrt_result_sram;
|
||
|
|
static unsigned int ddr_training_addr_start;
|
||
|
|
static unsigned int ddr_training_addr_end;
|
||
|
|
static int ddr_print_level = DDR_LOG_ERROR;
|
||
|
|
|
||
|
|
#ifdef DDR_TRAINING_LOG_CONFIG
|
||
|
|
|
||
|
|
/* Log ddr training info. */
|
||
|
|
void ddr_training_log(const char *func, int level, const char *fmt, ...)
|
||
|
|
{
|
||
|
|
va_list args;
|
||
|
|
|
||
|
|
if (ddr_print_level > level)
|
||
|
|
return;
|
||
|
|
|
||
|
|
DDR_PUTC('[');
|
||
|
|
switch (level) {
|
||
|
|
case DDR_LOG_INFO:
|
||
|
|
DDR_PUTS("INFO");
|
||
|
|
break;
|
||
|
|
case DDR_LOG_DEBUG:
|
||
|
|
DDR_PUTS("DEBUG");
|
||
|
|
break;
|
||
|
|
case DDR_LOG_WARNING:
|
||
|
|
DDR_PUTS("WARNING");
|
||
|
|
break;
|
||
|
|
case DDR_LOG_ERROR:
|
||
|
|
DDR_PUTS("ERROR");
|
||
|
|
break;
|
||
|
|
case DDR_LOG_FATAL:
|
||
|
|
DDR_PUTS("FATAL");
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
DDR_PUTC(']');
|
||
|
|
DDR_PUTC('[');
|
||
|
|
DDR_PUTS(func);
|
||
|
|
DDR_PUTC(']');
|
||
|
|
|
||
|
|
va_start(args, fmt);
|
||
|
|
while (*fmt != '\0') {
|
||
|
|
if (*fmt != '%') {
|
||
|
|
DDR_PUTC(*fmt);
|
||
|
|
} else {
|
||
|
|
fmt++;
|
||
|
|
switch (*fmt) {
|
||
|
|
case 'x':
|
||
|
|
case 'X':
|
||
|
|
DDR_PUTS("0x");
|
||
|
|
DDR_PUT_HEX(va_arg(args, int));
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
DDR_PUTC('%');
|
||
|
|
DDR_PUTC(*fmt);
|
||
|
|
break;
|
||
|
|
} /* switch */
|
||
|
|
}
|
||
|
|
fmt++;
|
||
|
|
} /* while */
|
||
|
|
va_end(args);
|
||
|
|
DDR_PUTS("\r\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Nothing to do in DDR command when defined DDR_TRAINING_LOG_CONFIG. */
|
||
|
|
void ddr_training_error(unsigned int mask, unsigned int phy, int byte, int dq)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
#else
|
||
|
|
/* Display DDR training error. */
|
||
|
|
void ddr_training_error(unsigned int mask, unsigned int phy, int byte, int dq)
|
||
|
|
{
|
||
|
|
switch (mask) {
|
||
|
|
case DDR_ERR_WL:
|
||
|
|
DDR_PUTS("WL");
|
||
|
|
break;
|
||
|
|
case DDR_ERR_HW_GATING:
|
||
|
|
DDR_PUTS("HW Gate");
|
||
|
|
break;
|
||
|
|
case DDR_ERR_GATING:
|
||
|
|
DDR_PUTS("Gate");
|
||
|
|
break;
|
||
|
|
case DDR_ERR_DDRT_TIME_OUT:
|
||
|
|
DDR_PUTS("DDRT");
|
||
|
|
break;
|
||
|
|
case DDR_ERR_HW_RD_DATAEYE:
|
||
|
|
DDR_PUTS("HW Dataeye");
|
||
|
|
break;
|
||
|
|
case DDR_ERR_MPR:
|
||
|
|
DDR_PUTS("MPR");
|
||
|
|
break;
|
||
|
|
case DDR_ERR_DATAEYE:
|
||
|
|
DDR_PUTS("Dataeye");
|
||
|
|
break;
|
||
|
|
case DDR_ERR_LPCA:
|
||
|
|
DDR_PUTS("LPCA");
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
DDR_PUTS(" Err:");
|
||
|
|
|
||
|
|
if (phy != 0) {
|
||
|
|
DDR_PUTS(" Phy:");
|
||
|
|
DDR_PUT_HEX(phy);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (byte != -1) {
|
||
|
|
DDR_PUTS(" Byte:");
|
||
|
|
DDR_PUT_HEX(byte);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (dq != -1) {
|
||
|
|
DDR_PUTS(" DQ:");
|
||
|
|
DDR_PUT_HEX(dq);
|
||
|
|
}
|
||
|
|
|
||
|
|
DDR_PUTS("\r\n");
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/* Inint ddr training cmd result */
|
||
|
|
static void ddr_training_result_init(struct ddr_cfg_st *cfg, struct ddr_training_result_st *ddrtr_res)
|
||
|
|
{
|
||
|
|
int i, j;
|
||
|
|
|
||
|
|
ddrtr_memset(ddrtr_res, 0, sizeof(struct ddr_training_result_st));
|
||
|
|
ddrtr_res->phy_num = cfg->phy_num;
|
||
|
|
for (i = 0; i < cfg->phy_num; i++) {
|
||
|
|
ddrtr_res->phy_st[i].rank_num = cfg->phy[i].rank_num;
|
||
|
|
|
||
|
|
for (j = 0; j < cfg->phy[i].rank_num; j++) {
|
||
|
|
ddrtr_res->phy_st[i].rank_st[j].item = cfg->phy[i].rank[j].item;
|
||
|
|
ddrtr_res->phy_st[i].rank_st[j].ddrtr_data.base_phy = cfg->phy[i].addr;
|
||
|
|
ddrtr_res->phy_st[i].rank_st[j].ddrtr_data.byte_num = cfg->phy[i].total_byte_num;
|
||
|
|
ddrtr_res->phy_st[i].rank_st[j].ddrtr_data.rank_idx = j;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Save ddr training cmd result */
|
||
|
|
void ddr_result_data_save(struct ddr_cfg_st *cfg, struct training_data *training)
|
||
|
|
{
|
||
|
|
unsigned int i;
|
||
|
|
unsigned int offset;
|
||
|
|
struct training_data *dest = NULL;
|
||
|
|
struct ddr_training_result_st *ddrtr_res = (struct ddr_training_result_st *)cfg->res_st;
|
||
|
|
|
||
|
|
if (!ddrtr_res)
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (cfg->cur_mode == DDR_MODE_READ)
|
||
|
|
dest = &ddrtr_res->phy_st[cfg->phy_idx].rank_st[cfg->rank_idx].ddrtr_data.read;
|
||
|
|
else
|
||
|
|
dest = &ddrtr_res->phy_st[cfg->phy_idx].rank_st[cfg->rank_idx].ddrtr_data.write;
|
||
|
|
|
||
|
|
if (cfg->phy[cfg->phy_idx].dmc_num == 1)
|
||
|
|
ddrtr_memcpy(dest, training, sizeof(struct training_data));
|
||
|
|
else {
|
||
|
|
/* dmc[0] + dmc[1] */
|
||
|
|
offset = cfg->dmc_idx << 4;
|
||
|
|
for (i = 0; i < GET_BYTE_NUM(cfg) << 3; i++) {
|
||
|
|
dest->ddr_bit_result[i + offset] = training->ddr_bit_result[i + offset];
|
||
|
|
dest->ddr_bit_best[i + offset] = training->ddr_bit_best[i + offset];
|
||
|
|
}
|
||
|
|
dest->ddr_win_sum += training->ddr_win_sum;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Save lpca training data */
|
||
|
|
void ddr_lpca_data_save(struct ca_data_st *data)
|
||
|
|
{
|
||
|
|
|
||
|
|
#if 0
|
||
|
|
unsigned int index;
|
||
|
|
struct ddr_training_result_st *result_st
|
||
|
|
= (struct ddr_training_result_st *)ddrtr_result;
|
||
|
|
struct ddr_training_data_st *tr_data;
|
||
|
|
|
||
|
|
for (index = 0; index < DDR_SUPPORT_PHY_MAX; index++) {
|
||
|
|
if (result_st->ddrtr_data[index].base_phy == data->base_phy)
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
tr_data = &result_st->ddrtr_data[index];
|
||
|
|
|
||
|
|
for (index = 0; index < DDR_PHY_CA_MAX; index++)
|
||
|
|
tr_data->ca_addr[index] = (data->left[index]
|
||
|
|
<< DDR_DATAEYE_RESULT_BIT) | data->right[index];
|
||
|
|
#endif
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Get DDRT test addrress */
|
||
|
|
unsigned int ddr_ddrt_get_test_addr(void)
|
||
|
|
{
|
||
|
|
if (ddr_training_addr_start <= DDRT_CFG_TEST_ADDR_CMD
|
||
|
|
&& ddr_training_addr_end >= DDRT_CFG_TEST_ADDR_CMD) {
|
||
|
|
return DDRT_CFG_TEST_ADDR_CMD;
|
||
|
|
} else {
|
||
|
|
DDR_ERROR("DDRT test address[%x] out of range[%x, %x]",
|
||
|
|
DDRT_CFG_TEST_ADDR_CMD,
|
||
|
|
ddr_training_addr_start,
|
||
|
|
ddr_training_addr_end);
|
||
|
|
return ddr_training_addr_start;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Nothing to do in DDR command */
|
||
|
|
void ddr_training_suc(void) { return; }
|
||
|
|
|
||
|
|
/* Nothing to do in DDR command */
|
||
|
|
void ddr_training_start(void) { return; }
|
||
|
|
|
||
|
|
static void dump_result(struct ddr_training_data_st *ddrtr_data)
|
||
|
|
{
|
||
|
|
unsigned int i;
|
||
|
|
unsigned int base_phy = ddrtr_data->base_phy;
|
||
|
|
unsigned int byte_num = ddrtr_data->byte_num;
|
||
|
|
unsigned int rank = ddrtr_data->rank_idx;
|
||
|
|
unsigned int ACPHYCTL7;
|
||
|
|
|
||
|
|
/* Static register have to read two times to get the right value. */
|
||
|
|
ACPHYCTL7 = ddr_read(base_phy + DDR_PHY_ACPHYCTL7);
|
||
|
|
ACPHYCTL7 = ddr_read(base_phy + DDR_PHY_ACPHYCTL7);
|
||
|
|
|
||
|
|
for (i = 0; i < ddrtr_data->byte_num << 3; i++) {
|
||
|
|
DDR_INFO("Byte[%x] Write[%x][%x] Read[%x][%x]",
|
||
|
|
i, ddrtr_data->write.ddr_bit_result[i], ddrtr_data->write.ddr_bit_best[i],
|
||
|
|
ddrtr_data->read.ddr_bit_result[i], ddrtr_data->read.ddr_bit_best[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (i = 0; i < DDR_PHY_CA_MAX; i++) {
|
||
|
|
if (ddrtr_data->ca_addr[i] != 0)
|
||
|
|
DDR_INFO("CA[%x] Range[%x]", i, ddrtr_data->ca_addr[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* WDQS */
|
||
|
|
for (i = 0; i < byte_num; i++) {
|
||
|
|
DDR_INFO("[%x = %x] WDQS Byte(%x) ",
|
||
|
|
base_phy + DDR_PHY_DXWDQSDLY(rank, i),
|
||
|
|
ddr_read(base_phy + DDR_PHY_DXWDQSDLY(rank, i)), i);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* WDQ Phase */
|
||
|
|
for (i = 0; i < byte_num; i++) {
|
||
|
|
DDR_INFO("[%x = %x] WDQ Phase Byte(%x)",
|
||
|
|
base_phy + DDR_PHY_DXNWDQDLY(rank, i),
|
||
|
|
ddr_read(base_phy + DDR_PHY_DXNWDQDLY(rank, i)), i);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* WDQ BDL */
|
||
|
|
for (i = 0; i < byte_num; i++) {
|
||
|
|
/* DQ0-DQ3 */
|
||
|
|
DDR_INFO("[%x = %x] WDQ BDL DQ(%x-%x)",
|
||
|
|
base_phy + DDR_PHY_DXNWDQNBDL0(rank, i),
|
||
|
|
ddr_read(base_phy + DDR_PHY_DXNWDQNBDL0(rank, i)),
|
||
|
|
(i << 3), ((i << 3) + 3));
|
||
|
|
|
||
|
|
/* DQ4-DQ7 */
|
||
|
|
DDR_INFO("[%x = %x] WDQ BDL DQ(%x-%x)",
|
||
|
|
base_phy + DDR_PHY_DXNWDQNBDL1(rank, i),
|
||
|
|
ddr_read(base_phy + DDR_PHY_DXNWDQNBDL1(rank, i)),
|
||
|
|
((i << 3) + 4), ((i << 3) + 7));
|
||
|
|
}
|
||
|
|
|
||
|
|
/* WDM */
|
||
|
|
for (i = 0; i < byte_num; i++) {
|
||
|
|
DDR_INFO("[%x = %x] WDM Byte(%x)",
|
||
|
|
base_phy + DDR_PHY_DXNWDQNBDL2(rank, i),
|
||
|
|
ddr_read(base_phy + DDR_PHY_DXNWDQNBDL2(rank, i)), i);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Write DO/DOS OE */
|
||
|
|
for (i = 0; i < byte_num; i++) {
|
||
|
|
DDR_INFO("[%x = %x] Write DQ/DQS OE Byte(%x)",
|
||
|
|
base_phy + DDR_PHY_DXNOEBDL(rank, i),
|
||
|
|
ddr_read(base_phy + DDR_PHY_DXNOEBDL(rank, i)), i);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* RDQS */
|
||
|
|
for (i = 0; i < byte_num; i++) {
|
||
|
|
DDR_INFO("[%x = %x] RDQS Byte(%x)",
|
||
|
|
base_phy + DDR_PHY_DXNRDQSDLY(i),
|
||
|
|
ddr_read(base_phy + DDR_PHY_DXNRDQSDLY(i)), i);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* RDQ BDL */
|
||
|
|
for (i = 0; i < byte_num; i++) {
|
||
|
|
/* DQ0-DQ3 */
|
||
|
|
DDR_INFO("[%x = %x] RDQ BDL DQ(%x-%x)",
|
||
|
|
base_phy + DDR_PHY_DXNRDQNBDL0(rank, i),
|
||
|
|
ddr_read(base_phy + DDR_PHY_DXNRDQNBDL0(rank, i)),
|
||
|
|
(i << 3), ((i << 3) + 3));
|
||
|
|
|
||
|
|
/* DQ4-DQ7 */
|
||
|
|
DDR_INFO("[%x = %x] RDQ BDL DQ(%x-%x)",
|
||
|
|
base_phy + DDR_PHY_DXNRDQNBDL1(rank, i),
|
||
|
|
ddr_read(base_phy + DDR_PHY_DXNRDQNBDL1(rank, i)),
|
||
|
|
((i << 3) + 4), ((i << 3) + 7));
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Gate */
|
||
|
|
for (i = 0; i < byte_num; i++) {
|
||
|
|
DDR_INFO("[%x = %x] Gate Byte(%x)",
|
||
|
|
base_phy + DDR_PHY_DXNRDQSGDLY(rank, i),
|
||
|
|
ddr_read(base_phy + DDR_PHY_DXNRDQSGDLY(rank, i)), i);
|
||
|
|
}
|
||
|
|
|
||
|
|
DDR_INFO("[%x = %x] CS",
|
||
|
|
base_phy + DDR_PHY_ACCMDBDL2,
|
||
|
|
ddr_read(base_phy + DDR_PHY_ACCMDBDL2));
|
||
|
|
|
||
|
|
DDR_INFO("[%x = %x] CLK",
|
||
|
|
base_phy + DDR_PHY_ACPHYCTL7, ACPHYCTL7);
|
||
|
|
|
||
|
|
DDR_PHY_SWITCH_RANK(base_phy, rank);
|
||
|
|
|
||
|
|
/* HOST Vref */
|
||
|
|
DDR_PHY_VREF_HOST_DISPLAY_CMD(base_phy, rank, byte_num);
|
||
|
|
|
||
|
|
/* DRAM Vref */
|
||
|
|
DDR_PHY_VREF_DRAM_DISPLAY_CMD(base_phy, byte_num);
|
||
|
|
|
||
|
|
/* Addr Phase */
|
||
|
|
DDR_PHY_ADDRPH_DISPLAY_CMD(base_phy);
|
||
|
|
|
||
|
|
/* Addr BDL */
|
||
|
|
DDR_PHY_ADDRBDL_DISPLAY_CMD(base_phy);
|
||
|
|
|
||
|
|
/* DCC */
|
||
|
|
DDR_PHY_DCC_DISPLAY_CMD(base_phy);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void dump_result_by_rank(struct ddr_training_result_st *ddrtr_result,
|
||
|
|
unsigned int phy_index, unsigned int rank_index)
|
||
|
|
{
|
||
|
|
unsigned int mask = 1 << phy_index; /* DDR_BYPASS_PHY0_MASK DDR_BYPASS_PHY1_MASK */
|
||
|
|
struct rank_data_st *rank_st = &ddrtr_result->phy_st[phy_index].rank_st[rank_index];
|
||
|
|
|
||
|
|
if (rank_st->item & mask)
|
||
|
|
return;
|
||
|
|
|
||
|
|
DDR_INFO("PHY[%x] RANK[%x]:", phy_index, rank_index);
|
||
|
|
dump_result(&rank_st->ddrtr_data);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void dump_result_by_phy(struct ddr_training_result_st *ddrtr_result,
|
||
|
|
unsigned int phy_index)
|
||
|
|
{
|
||
|
|
int i;
|
||
|
|
struct phy_data_st *phy_st = &ddrtr_result->phy_st[phy_index];
|
||
|
|
|
||
|
|
for (i = 0; i < phy_st->rank_num; i++) {
|
||
|
|
dump_result_by_rank(ddrtr_result, phy_index, i);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Display ddr training result before return to DDR */
|
||
|
|
static void dump_result_all(struct ddr_training_result_st *ddrtr_result)
|
||
|
|
{
|
||
|
|
int i;
|
||
|
|
for (i = 0; i < ddrtr_result->phy_num; i++) {
|
||
|
|
dump_result_by_phy(ddrtr_result, i);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int ddr_training_cmd_func(struct ddr_cfg_st *cfg)
|
||
|
|
{
|
||
|
|
int result = 0;
|
||
|
|
struct ddr_cmd_st *cmd_st = (struct ddr_cmd_st *)cfg->cmd_st;
|
||
|
|
unsigned int item = cfg->cur_item;
|
||
|
|
|
||
|
|
DDR_DEBUG("DDR training cmd[%x]", cmd_st->cmd);
|
||
|
|
|
||
|
|
switch (cmd_st->cmd) {
|
||
|
|
case DDR_TRAINING_CMD_SW:
|
||
|
|
/* todo */
|
||
|
|
result = ddr_dataeye_training_func(cfg);
|
||
|
|
result += ddr_vref_training_func(cfg);
|
||
|
|
break;
|
||
|
|
case DDR_TRAINING_CMD_DATAEYE:
|
||
|
|
result = ddr_dataeye_training_func(cfg);
|
||
|
|
break;
|
||
|
|
case DDR_TRAINING_CMD_HW:
|
||
|
|
result = ddr_hw_training_if();
|
||
|
|
break;
|
||
|
|
case DDR_TRAINING_CMD_MPR:
|
||
|
|
result = ddr_mpr_training_func(cfg);
|
||
|
|
break;
|
||
|
|
case DDR_TRAINING_CMD_WL:
|
||
|
|
result = ddr_wl_func(cfg);
|
||
|
|
break;
|
||
|
|
case DDR_TRAINING_CMD_GATE:
|
||
|
|
result = ddr_gating_func(cfg);
|
||
|
|
break;
|
||
|
|
case DDR_TRAINING_CMD_VREF:
|
||
|
|
result = ddr_vref_training_func(cfg);
|
||
|
|
break;
|
||
|
|
case DDR_TRAINING_CMD_AC:
|
||
|
|
result = ddr_ac_training_func(cfg);
|
||
|
|
break;
|
||
|
|
case DDR_TRAINING_CMD_LPCA:
|
||
|
|
result = ddr_lpca_training_func(cfg);
|
||
|
|
break;
|
||
|
|
case DDR_TRAINING_CMD_SW_NO_WL:
|
||
|
|
/* wl bypass */
|
||
|
|
ddr_write(item | DDR_BYPASS_WL_MASK,
|
||
|
|
DDR_REG_BASE_SYSCTRL + SYSCTRL_DDR_TRAINING_CFG);
|
||
|
|
result = ddr_dataeye_training_func(cfg);
|
||
|
|
result += ddr_vref_training_func(cfg);
|
||
|
|
/* restore cfg */
|
||
|
|
ddr_write(item,
|
||
|
|
DDR_REG_BASE_SYSCTRL + SYSCTRL_DDR_TRAINING_CFG);
|
||
|
|
break;
|
||
|
|
case DDR_TRAINING_CMD_CONSOLE:
|
||
|
|
result = ddr_training_console_if((void *)&ddrt_result_sram);
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
result = -1;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* DDR training command entry. Call by cmd_ddr_handle(). */
|
||
|
|
struct ddr_training_result_st *ddr_training_cmd_entry(
|
||
|
|
struct ddr_cmd_st *cmd_st)
|
||
|
|
{
|
||
|
|
int result = 0;
|
||
|
|
|
||
|
|
struct ddr_cfg_st ddr_cfg;
|
||
|
|
struct ddr_cfg_st *cfg = &ddr_cfg;
|
||
|
|
struct ddr_cmd_st cmd_in_sram;
|
||
|
|
|
||
|
|
ddr_training_addr_start = cmd_st->start;
|
||
|
|
ddr_training_addr_end = cmd_st->start + cmd_st->length;
|
||
|
|
ddr_print_level = cmd_st->level;
|
||
|
|
|
||
|
|
DDR_INFO("DDR Training Version: "DDR_TRAINING_VER);
|
||
|
|
DDR_DEBUG("DDR training command entry. Sysctl[%x = %x]",
|
||
|
|
(DDR_REG_BASE_SYSCTRL + SYSCTRL_DDR_TRAINING_CFG),
|
||
|
|
ddr_read(DDR_REG_BASE_SYSCTRL + SYSCTRL_DDR_TRAINING_CFG));
|
||
|
|
|
||
|
|
#ifdef SYSCTRL_DDR_TRAINING_CFG_SEC
|
||
|
|
DDR_DEBUG("Rank1 Sysctl[%x = %x]",
|
||
|
|
(DDR_REG_BASE_SYSCTRL + SYSCTRL_DDR_TRAINING_CFG_SEC),
|
||
|
|
ddr_read(DDR_REG_BASE_SYSCTRL + SYSCTRL_DDR_TRAINING_CFG_SEC));
|
||
|
|
#endif
|
||
|
|
|
||
|
|
ddr_training_cfg_init(cfg);
|
||
|
|
ddrtr_memcpy(&cmd_in_sram, cmd_st, sizeof(struct ddr_cmd_st));
|
||
|
|
cfg->cmd_st = (void *)&cmd_in_sram;
|
||
|
|
cfg->res_st = (void *)&ddrt_result_sram;
|
||
|
|
|
||
|
|
ddr_training_result_init(cfg, &ddrt_result_sram);
|
||
|
|
|
||
|
|
if (cmd_st->cmd == DDR_TRAINING_CMD_HW)
|
||
|
|
result = ddr_hw_training(cfg);
|
||
|
|
else if (cmd_st->cmd == DDR_TRAINING_CMD_PCODE)
|
||
|
|
result = ddr_pcode_training(cfg);
|
||
|
|
else if (cmd_st->cmd == DDR_TRAINING_CMD_DCC)
|
||
|
|
result = ddr_dcc_training_func(cfg);
|
||
|
|
else if (cmd_st->cmd == DDR_TRAINING_CMD_CONSOLE)
|
||
|
|
result = ddr_training_console_if((void *)&ddrt_result_sram);
|
||
|
|
else
|
||
|
|
result = ddr_training_all(cfg);
|
||
|
|
|
||
|
|
dump_result_all(&ddrt_result_sram);
|
||
|
|
|
||
|
|
if (!result) {
|
||
|
|
return &ddrt_result_sram;
|
||
|
|
} else {
|
||
|
|
DDR_DEBUG("DDR training result[%x]", result);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|