1028 lines
35 KiB
C
1028 lines
35 KiB
C
/**
|
|
* @file sdrv_sdramc.c
|
|
* @brief sdrv sdramc driver
|
|
*
|
|
* @copyright Copyright (c) 2021 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include <armv7-r/cache.h>
|
|
#include <param.h>
|
|
#include <types.h>
|
|
#include <sdrv_sdramc.h>
|
|
|
|
#ifndef CONFIG_SDRAM_BASE
|
|
#define CONFIG_SDRAM_BASE 0x30000000u
|
|
#endif
|
|
|
|
#if !CONFIG_WORK_ON_Z1
|
|
#define SDRAMC_DLL_LOCK_TIMEOUT (1000)
|
|
#else
|
|
#define SDRAMC_DLL_LOCK_TIMEOUT (1)
|
|
#endif
|
|
|
|
#define SDRAMC_PATTERN_LENS (16u)
|
|
/* If the width is 32bits, the value is 4u */
|
|
#define SDRAMC_WIDTH (4u)
|
|
#define TRAINING_STEPS (32u)
|
|
#define WIN_MAX_SUCCESS 33u
|
|
|
|
#if SDRAMC_WIDTH == 4
|
|
typedef uint32_t sdram_data_t;
|
|
#define training_write(val, reg) writel(val, reg)
|
|
#define training_read(reg) readl(reg)
|
|
//32bit bl=8
|
|
static const uint8_t training_patten[SDRAMC_WIDTH * SDRAMC_PATTERN_LENS] = {
|
|
0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
|
|
0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
|
|
};
|
|
|
|
static const uint8_t training_patten_trans[SDRAMC_WIDTH * SDRAMC_PATTERN_LENS]
|
|
= {
|
|
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
|
|
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
|
|
0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
|
|
0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
|
|
0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
|
|
0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
|
|
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
|
|
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
|
|
};
|
|
|
|
#elif SDRAMC_WIDTH == 2
|
|
#define training_write(val, reg) writew(val, reg)
|
|
#define training_read(reg) readw(reg)
|
|
typedef uint16_t sdram_data_t;
|
|
//16bit bl=8
|
|
static const uint8_t training_patten[SDRAMC_WIDTH * SDRAMC_PATTERN_LENS] = {
|
|
0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
|
|
};
|
|
static const uint8_t training_patten_trans[SDRAMC_WIDTH * SDRAMC_PATTERN_LENS]
|
|
= {
|
|
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
|
|
0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
|
|
0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
|
|
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
|
|
};
|
|
|
|
#elif SDRAMC_WIDTH == 1
|
|
#define training_write(val, reg) writeb(val, reg)
|
|
#define training_read(reg) readb(reg)
|
|
typedef uint8_t sdram_data_t;
|
|
//8bit bl=8
|
|
static uint8_t training_patten[SDRAMC_WIDTH * SDRAMC_PATTERN_LENS] = {
|
|
0x55u, 0xAAu, 0x55u, 0xAAu, 0xAAu, 0x55u, 0xAAu, 0x55u,
|
|
0xAAu, 0x55u, 0xAAu, 0x55u, 0x55u, 0xAAu, 0x55u, 0xAAu,
|
|
};
|
|
static uint8_t training_patten_trans[SDRAMC_WIDTH * SDRAMC_PATTERN_LENS] = {
|
|
0x55u, 0xAAu, 0x55u, 0xAAu, 0xAAu, 0x55u, 0xAAu, 0x55u,
|
|
0xAAu, 0x55u, 0xAAu, 0x55u, 0x55u, 0xAAu, 0x55u, 0xAAu,
|
|
};
|
|
#endif
|
|
|
|
static uint8_t training_data[TRAINING_STEPS][SDRAMC_WIDTH * SDRAMC_PATTERN_LENS]
|
|
= {0u} ;
|
|
|
|
struct sd_para cs_p;
|
|
|
|
/**
|
|
* @brief save sdramc parameters
|
|
* @param [in] cs get sdram parameters
|
|
*/
|
|
void sdrv_set_sd_para(struct sd_para *cs)
|
|
{
|
|
if (cs != NULL) {
|
|
cs_p.column_start = cs->column_start;
|
|
cs_p.column_bits = cs->column_bits;
|
|
cs_p.cs_start = cs->cs_start;
|
|
cs_p.cs_bits = cs->cs_bits;
|
|
cs_p.bank_start = cs->bank_start;
|
|
cs_p.bank_bits = cs->bank_bits;
|
|
cs_p.row_start = cs->row_start;
|
|
cs_p.row_bits = cs->row_bits;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* @brief get sdramc parameters
|
|
* @retval sdram parameters
|
|
*/
|
|
struct sd_para *sdrv_get_sd_para(void)
|
|
{
|
|
return &cs_p;
|
|
}
|
|
|
|
static inline __ALWAYS_INLINE uint32_t log2_uint(uint32_t val)
|
|
{
|
|
if (val == 0u)
|
|
return 0u; // undefined
|
|
|
|
return (sizeof(val) * 8u) - 1u - __builtin_clz(val);
|
|
}
|
|
|
|
/**
|
|
* @brief Matrix reverse to matrix_array_trans array
|
|
* @param [in] matrix_array raw data
|
|
* @param [in] matrix_array_trans get reverse data from raw data
|
|
* @param [in] row Matrix row number
|
|
* @param [in] column Matrix column number
|
|
*/
|
|
static void sdrv_matrix_transpose(uint8_t *matrix_array,
|
|
uint8_t *matrix_array_trans,
|
|
uint32_t row, uint32_t column)
|
|
{
|
|
for (uint32_t i = 0; i < row; i++) {
|
|
for (uint32_t j = 0; j < column; j++) {
|
|
*(matrix_array_trans + column * i + j) = *(matrix_array + row * j + i);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief sdramc dll config
|
|
* @param [in] base sdramc base register address
|
|
* @param [in] value dll config set value
|
|
* @param [in] num dll serial number dll0~3
|
|
* @return int32_t
|
|
* @retval 0: success
|
|
* @retval other: failed
|
|
*/
|
|
static int32_t sdramc_dll_config(addr_t base, uint8_t value, uint8_t num)
|
|
{
|
|
uint32_t reg;
|
|
int32_t ret;
|
|
addr_t dll_addr;
|
|
addr_t dll_status_addr;
|
|
dll_addr = SDRAMC_DLL0 + num * 0x4u;
|
|
dll_status_addr = SDRAMC_DLL_STATUS0 + num * 0x4u;
|
|
|
|
reg = 0u;
|
|
ret = SDRV_STATUS_OK;
|
|
ddr_writel(reg, base + dll_addr);
|
|
|
|
reg = value << SDRAMC_DLL0_SLVTGRT_LSB;
|
|
reg |= SDRAMC_DLL0_DLLEN;//enable dll
|
|
ddr_writel(reg, base + dll_addr);
|
|
|
|
int32_t j = SDRAMC_DLL_LOCK_TIMEOUT;
|
|
|
|
while (j) {
|
|
reg = ddr_readl(base + dll_status_addr);
|
|
|
|
if (reg & SDRAMC_DLL_STATUS0_SLVLOCK) {
|
|
ssdk_printf(SSDK_DEBUG, "sdramc dll%d locked!\r\n", num);
|
|
break;
|
|
}
|
|
|
|
j--;
|
|
}
|
|
|
|
if (j == 0) {
|
|
ssdk_printf(SSDK_ERR, "sdramc dll%d lock failed!\r\n", num);
|
|
ret = SDRV_STATUS_SDRAMC_DLL_LOCK_ERR;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief sdramc config all dll, maximal DLL0-3
|
|
* @param [in] base sdramc base register address
|
|
* @param [in] value dll config set value
|
|
* @return int32_t
|
|
* @retval 0: success
|
|
* @retval other: failed
|
|
*/
|
|
static int32_t sdramc_dll_config_all(addr_t base, uint8_t value)
|
|
{
|
|
int32_t ret = SDRV_STATUS_FAIL;
|
|
|
|
/* Config DLL0-3 */
|
|
for (uint32_t i = 0; i < 4u; i++) {
|
|
ret = sdramc_dll_config(base, value, i);
|
|
if(ret != SDRV_STATUS_OK){
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief ddr or sdr mode dump training windows result for debug
|
|
* @param [in] training_win_ddr record training window data
|
|
* @param [in] conf sdr one sets of data, ddr two sets of data
|
|
* @param [in] ddr_mode is ddr mode not not
|
|
*/
|
|
static void dump_training_win_result(uint32_t (*training_win_ddr)[2][4][2],
|
|
sdram_config_t *conf, uint32_t times, bool ddr_mode)
|
|
{
|
|
SDRAMC_CTL_DATA_DEBUG("cs gate(ddr) dll win\r\n");
|
|
|
|
for (uint32_t i = 0; i < conf->cs_num ; i++) {
|
|
for (uint32_t j = 0; j < times; j++) {
|
|
for (uint32_t k = 0; k < conf->dq_width / 8u; k++) {
|
|
for (uint32_t l = 0; l < 2u; l++) {
|
|
SDRAMC_CTL_DATA_DEBUG("[%d][%d][%d][%d] = %d ", i, j,
|
|
k, l, training_win_ddr[i][j][k][l]);
|
|
}
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("\r\n");
|
|
}
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("\r\n");
|
|
}
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("\r\n");
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* @brief training success or failed result dump for debug
|
|
* @param [in] pass_win_min_l2r lest to right success times and max value 32
|
|
* @param [in] times dll training success times
|
|
*/
|
|
static void sdrv_training_result_dump(uint32_t pass_win_min_l2r, uint8_t times)
|
|
{
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("min_l2r = %d \r\n", pass_win_min_l2r);
|
|
|
|
if (pass_win_min_l2r != WIN_MAX_SUCCESS && times == SDRAMC_WIDTH) {
|
|
SDRAMC_CTL_DATA_DEBUG("failed times = %d\r\nsuccess times = %d \r\n",
|
|
TRAINING_STEPS - pass_win_min_l2r, pass_win_min_l2r);
|
|
}
|
|
else {
|
|
SDRAMC_CTL_DATA_DEBUG("failed times = %d\r\nsuccess times = %d \r\n",
|
|
TRAINING_STEPS, TRAINING_STEPS - TRAINING_STEPS);
|
|
}
|
|
|
|
#ifdef ENABLE_SDRAMC_CTL_DATA_DEBUG
|
|
ssdk_printf(SSDK_CRIT, "hexdump training data \r\n");
|
|
hexdump8_ex(training_data,
|
|
TRAINING_STEPS * SDRAMC_WIDTH * SDRAMC_PATTERN_LENS,
|
|
(uint64_t)((addr_t)training_data));
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief debug windows info
|
|
* @param [in] dll_l_r record max left windows to min right windows value
|
|
*/
|
|
static void training_maxl2minr_dump(uint32_t (*dll_l_r)[2])
|
|
{
|
|
|
|
for (uint32_t i = 0; i < 4u ; i++) {
|
|
for (uint32_t j = 0; j < 2u; j++) {
|
|
SDRAMC_CTL_DATA_DEBUG("l_r[%d][%d] = %d ", i, j, dll_l_r[i][j]);
|
|
}
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("\r\n");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief record training result and fill training win data
|
|
* @param [in] ddr_mode ddr or sdr mode
|
|
* @param [in] ddr_gate_index ddr: index 0 or 1, sdr: index 0
|
|
* @param [in] gate_val ddr gate value
|
|
* @param [in] training_win_data_ddr sdr or ddr result
|
|
* @param [in] cs_num cs number
|
|
* @param [in] pass_win_min_l2r record min left to min right window value
|
|
* @param [in] pass_win_l training pass window min left value
|
|
* @param [in] pass_win_r training pass window max right value
|
|
* @param [in] j dll0~4 index
|
|
*/
|
|
static void sdramc_getwin(bool ddr_mode, uint32_t ddr_gate_index,
|
|
uint32_t (*gate_val)[2],
|
|
uint32_t (*training_win_data_ddr)[2][4][2], uint32_t cs_num,
|
|
uint32_t pass_win_min_l2r, uint32_t pass_win_l, uint32_t pass_win_r, uint32_t j)
|
|
{
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("pass_win_min_l2r = %d \r\n", pass_win_min_l2r);
|
|
|
|
if (ddr_mode == true) {
|
|
if (gate_val != NULL) {
|
|
gate_val[ddr_gate_index][1] = MIN(gate_val[ddr_gate_index][1],
|
|
pass_win_min_l2r);
|
|
}
|
|
|
|
if (training_win_data_ddr != NULL) {
|
|
training_win_data_ddr[cs_num][ddr_gate_index][j][0] = pass_win_l;
|
|
training_win_data_ddr[cs_num][ddr_gate_index][j][1] = pass_win_r;
|
|
}
|
|
}
|
|
else {
|
|
if (training_win_data_ddr != NULL) {
|
|
training_win_data_ddr[cs_num][0][j][0] = pass_win_l;
|
|
training_win_data_ddr[cs_num][0][j][1] = pass_win_r;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief record training result and fill training win data
|
|
* @param [in] base sdramc base register address
|
|
* @param [in] ddr_gate_index ddr: index 0 or 1, sdr: index 0
|
|
* @param [in] gate_val ddr gate value
|
|
* @param [in] ddr_mode ddr or sdr mode
|
|
* @param [in] training_win_data_ddr sdr or ddr result
|
|
* @param [in] cs_num cs number
|
|
* @return int32_t
|
|
* @retval 0: success
|
|
* @retval other: failed
|
|
*/
|
|
static int32_t sdramc_dll_training(addr_t base, uint32_t ddr_gate_index,
|
|
uint32_t (*gate_val)[2], bool ddr_mode,
|
|
uint32_t (*training_win_data_ddr)[2][4][2],
|
|
uint32_t cs_num)
|
|
{
|
|
sdram_data_t *p_pattern;
|
|
sdram_data_t *p_data;
|
|
bool data_cmp_res;
|
|
bool training_succ[SDRAMC_WIDTH] = {false};
|
|
bool training_end[SDRAMC_WIDTH] = {false};
|
|
uint32_t pass_win_l[SDRAMC_WIDTH] = {0u};
|
|
uint32_t pass_win_r[SDRAMC_WIDTH] = {0u};
|
|
uint8_t read_data[SDRAMC_PATTERN_LENS * SDRAMC_WIDTH] = {0};
|
|
uint32_t pass_win_min_l2r = WIN_MAX_SUCCESS;
|
|
uint32_t save_pass_win_l[SDRAMC_WIDTH] = {0u};
|
|
uint8_t success_time = 0;
|
|
uint32_t cs_offset = 0;
|
|
int32_t ret = SDRV_STATUS_FAIL;
|
|
|
|
if (gate_val != NULL) {
|
|
SDRAMC_CTL_DATA_DEBUG("gate = 0x%08x\r\n", gate_val[ddr_gate_index][0]);
|
|
}
|
|
|
|
struct sd_para *sd_dll_bt = sdrv_get_sd_para();
|
|
|
|
cs_offset = cs_num << sd_dll_bt->cs_start;
|
|
|
|
for (uint32_t i = 0; i < TRAINING_STEPS; i++) {
|
|
|
|
p_pattern = (sdram_data_t *)training_patten;
|
|
p_data = (sdram_data_t *)read_data;
|
|
ret = sdramc_dll_config_all(base, i);
|
|
if(ret != SDRV_STATUS_OK){
|
|
goto err;
|
|
}
|
|
|
|
/* write test pattern to sdram address */
|
|
for (uint32_t j = 0; j < SDRAMC_PATTERN_LENS; j++) {
|
|
training_write(*(p_pattern + j),
|
|
(uint8_t *)CONFIG_SDRAM_BASE + cs_offset + SDRAMC_WIDTH * j);
|
|
}
|
|
|
|
arch_clean_invalidate_cache_range((addr_t)CONFIG_SDRAM_BASE + cs_offset,
|
|
SDRAMC_WIDTH * SDRAMC_PATTERN_LENS);
|
|
//DSB;
|
|
|
|
/* read sdram address data to read_data array */
|
|
for (uint32_t j = 0; j < SDRAMC_PATTERN_LENS; j++) {
|
|
*(p_data + j) = training_read((uint8_t *)CONFIG_SDRAM_BASE + cs_offset +
|
|
SDRAMC_WIDTH * j);
|
|
}
|
|
|
|
/* Matrix reverse */
|
|
sdrv_matrix_transpose(read_data, training_data[i], SDRAMC_PATTERN_LENS,
|
|
SDRAMC_WIDTH);
|
|
|
|
/* compare training_data and training_patten_trans data */
|
|
for (uint32_t j = 0; j < SDRAMC_WIDTH; j++) {
|
|
for (uint32_t k = 0; k < SDRAMC_PATTERN_LENS; k += SDRAMC_WIDTH) {
|
|
data_cmp_res = *((sdram_data_t *)training_data[i] + j + k) ==
|
|
*((sdram_data_t *)training_patten_trans + j + k);
|
|
|
|
if (data_cmp_res == false)
|
|
break;
|
|
}
|
|
|
|
/* check success and record maximal left window and minimal right window */
|
|
if (data_cmp_res) {
|
|
if (training_succ[j] == false) {
|
|
training_succ[j] = true;
|
|
pass_win_l[j] = data_cmp_res ? i : 0u;
|
|
save_pass_win_l[j] = pass_win_l[j];
|
|
SDRAMC_CTL_DATA_DEBUG("sdramc dll%d training succ! win_l is %d\r\n", j,
|
|
pass_win_l[j]);
|
|
}
|
|
}
|
|
else {
|
|
if (training_succ[j] == true && (i > (save_pass_win_l[j] + 15u))) {
|
|
training_succ[j] = true;
|
|
}
|
|
else {
|
|
training_succ[j] = false;
|
|
}
|
|
}
|
|
|
|
if (training_succ[j] == true && (!data_cmp_res || i == 31u)
|
|
&& training_end[j] != true) {
|
|
training_end[j] = true;
|
|
pass_win_r[j] = data_cmp_res ? 31u : (i - 1u);
|
|
SDRAMC_CTL_DATA_DEBUG("sdramc dll%d training succ! win_r is %d\r\n", j,
|
|
pass_win_r[j]);
|
|
pass_win_min_l2r = MIN(pass_win_r[j] - pass_win_l[j] + 1u, pass_win_min_l2r);
|
|
sdramc_getwin(ddr_mode, ddr_gate_index, gate_val, training_win_data_ddr, cs_num,
|
|
pass_win_min_l2r, pass_win_l[j], pass_win_r[j], j);
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("\n dll%d, l = %d , r = %d, mid = %d \r\n", j,
|
|
pass_win_l[j], pass_win_r[j],
|
|
(pass_win_r[j] - pass_win_l[j]) / 2 + pass_win_l[j]);
|
|
/* success and sdramc config dll */
|
|
ret = sdramc_dll_config(base, (pass_win_r[j] - pass_win_l[j]) / 2u + pass_win_l[j],
|
|
j);
|
|
if(ret != SDRV_STATUS_OK){
|
|
goto err;
|
|
}
|
|
success_time++;
|
|
}
|
|
}
|
|
|
|
if (success_time == SDRAMC_WIDTH) {
|
|
SDRAMC_CTL_DATA_DEBUG("dll training success times = %d \r\n", success_time);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (success_time != SDRAMC_WIDTH) { //clear failed gate_index
|
|
if (ddr_mode == true) {
|
|
gate_val[ddr_gate_index][1] = 0;
|
|
}
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("%d way dll failed \r\n", SDRAMC_WIDTH - success_time);
|
|
ret = SDRV_STATUS_SDRAMC_DLL_WAYS_ERR;
|
|
}
|
|
|
|
sdrv_training_result_dump(pass_win_min_l2r, success_time);
|
|
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief sdramc sdr training
|
|
* @param [in] base sdramc base register address
|
|
* @param [in] conf sdramc config parameters
|
|
* @param [in] training_win_data set sdr training result
|
|
* @return int32_t
|
|
* @retval 0: success
|
|
* @retval other: failed
|
|
*/
|
|
static int32_t sdramc_sdr_training_data(addr_t base, sdram_config_t *conf,
|
|
uint32_t (*training_win_data)[2][4][2])
|
|
{
|
|
|
|
int32_t ret = SDRV_STATUS_FAIL;
|
|
|
|
for (uint32_t sdr_cs_num = 0; sdr_cs_num < conf->cs_num; sdr_cs_num++) {
|
|
ret = sdramc_dll_training(base, 0u, NULL, false, training_win_data, sdr_cs_num);
|
|
|
|
if(ret != SDRV_STATUS_OK){
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
dump_training_win_result(training_win_data, conf, 1, false);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief sdramc sdr training
|
|
* @param [in] base sdramc base register address
|
|
* @param [in] conf sdramc config parameters
|
|
* @param [in] training_win get value and set sdr dll mid value
|
|
* @return int32_t
|
|
* @retval 0: success
|
|
* @retval other: failed
|
|
*/
|
|
static int32_t sdramc_sdr_set_dll_config(addr_t base, sdram_config_t *conf,
|
|
uint32_t (*training_win)[2][4][2])
|
|
{
|
|
|
|
int32_t ret = SDRV_STATUS_FAIL;
|
|
uint32_t dll_l_r[4][2] = {{0u, 33u}, {0u, 33u}, {0u, 33u}, {0u, 33u}};
|
|
|
|
for (uint32_t dll_index = 0; dll_index < conf->dq_width / 8u; dll_index++) {
|
|
for (uint32_t cs_num = 0; cs_num < conf->cs_num; cs_num++) {
|
|
dll_l_r[dll_index][0] = MAX(training_win[cs_num][0][dll_index][0],
|
|
dll_l_r[dll_index][0]);
|
|
dll_l_r[dll_index][1] = MIN(training_win[cs_num][0][dll_index][1],
|
|
dll_l_r[dll_index][1]);
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0; i < conf->dq_width / 8u; i++) {
|
|
uint32_t dll_mid = (dll_l_r[i][1] - dll_l_r[i][0]) / 2 + dll_l_r[i][0];
|
|
ret = sdramc_dll_config(base, dll_mid, i);
|
|
|
|
if(ret != SDRV_STATUS_OK){
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief gate set value for ddr mode
|
|
* @param [in] cas_num use cas latency value and set DQS_SHIFT register
|
|
* @param [in] index gate array index
|
|
* @return uint32_t
|
|
*/
|
|
static uint32_t sdrv_gate_set_val(uint32_t cas_num, uint32_t index)
|
|
{
|
|
uint32_t gate_reg = 0;
|
|
gate_reg = cas_num << SDRAMC_DDR_DQS_SHIFT_NUM0_LSB;
|
|
gate_reg |= cas_num << SDRAMC_DDR_DQS_SHIFT_NUM1_LSB;
|
|
gate_reg |= cas_num << SDRAMC_DDR_DQS_SHIFT_NUM2_LSB;
|
|
gate_reg |= cas_num << SDRAMC_DDR_DQS_SHIFT_NUM3_LSB;
|
|
|
|
if (index == 1) {
|
|
gate_reg |= (cas_num + 1u) << SDRAMC_DDR_DQS_SHIFT_NUM0NEG_LSB;
|
|
gate_reg |= (cas_num + 1u) << SDRAMC_DDR_DQS_SHIFT_NUM1NEG_LSB;
|
|
gate_reg |= (cas_num + 1u) << SDRAMC_DDR_DQS_SHIFT_NUM2NEG_LSB;
|
|
gate_reg |= (cas_num + 1u) << SDRAMC_DDR_DQS_SHIFT_NUM3NEG_LSB;
|
|
}
|
|
else {
|
|
gate_reg |= cas_num << SDRAMC_DDR_DQS_SHIFT_NUM0NEG_LSB;
|
|
gate_reg |= cas_num << SDRAMC_DDR_DQS_SHIFT_NUM1NEG_LSB;
|
|
gate_reg |= cas_num << SDRAMC_DDR_DQS_SHIFT_NUM2NEG_LSB;
|
|
gate_reg |= cas_num << SDRAMC_DDR_DQS_SHIFT_NUM3NEG_LSB;
|
|
}
|
|
|
|
return gate_reg;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief sdramc ddr set gate value, and this is
|
|
* the reference value according to the frequency
|
|
* @param [in] base sdramc base register address
|
|
* @param [in] conf sdramc config parameters
|
|
* @param [in] gate_val gate value for ddr mode
|
|
* @return int32_t
|
|
* @retval 0: success
|
|
* @retval other: failed
|
|
*/
|
|
static int32_t sdramc_ddr_set_gate(addr_t base, sdram_config_t *conf,
|
|
uint32_t (*gate_val)[2])
|
|
{
|
|
uint32_t val = conf->clock / 1000000u;
|
|
SDRAMC_CTL_DATA_DEBUG("cas = %d, val = %d\r\n", conf->cas_latency_x2, val);
|
|
int32_t ret = SDRV_STATUS_FAIL;
|
|
|
|
if (val >= 366u && val < 410u) {
|
|
gate_val[0][0] = sdrv_gate_set_val(conf->cas_latency_x2 - 2u, 0);
|
|
gate_val[1][0] = sdrv_gate_set_val(conf->cas_latency_x2 - 2u, 1);
|
|
ret = SDRV_STATUS_OK;
|
|
}
|
|
else if (val >= 333u && val < 366u) {
|
|
gate_val[0][0] = sdrv_gate_set_val(conf->cas_latency_x2 - 2u, 0);
|
|
gate_val[1][0] = sdrv_gate_set_val(conf->cas_latency_x2 - 2u, 1);
|
|
ret = SDRV_STATUS_OK;
|
|
}
|
|
else if (val >= 300u && val < 333u) {
|
|
gate_val[0][0] = sdrv_gate_set_val(conf->cas_latency_x2 - 3u, 1);
|
|
gate_val[1][0] = sdrv_gate_set_val(conf->cas_latency_x2 - 2u, 0);
|
|
ret = SDRV_STATUS_OK;
|
|
}
|
|
else if (val >= 266u && val < 300u) {
|
|
gate_val[0][0] = sdrv_gate_set_val(conf->cas_latency_x2 - 3u, 1);
|
|
gate_val[1][0] = sdrv_gate_set_val(conf->cas_latency_x2 - 2u, 0);
|
|
ret = SDRV_STATUS_OK;
|
|
}
|
|
else if (val >= 233u && val < 266u) {
|
|
gate_val[0][0] = sdrv_gate_set_val(conf->cas_latency_x2 - 3u, 1);
|
|
gate_val[1][0] = sdrv_gate_set_val(conf->cas_latency_x2 - 2u, 0);
|
|
ret = SDRV_STATUS_OK;
|
|
}
|
|
else if (val >= 190u && val < 233u) {
|
|
gate_val[0][0] = sdrv_gate_set_val(conf->cas_latency_x2 - 3u, 0);
|
|
gate_val[1][0] = sdrv_gate_set_val(conf->cas_latency_x2 - 3u, 1);
|
|
ret = SDRV_STATUS_OK;
|
|
}
|
|
else {
|
|
ssdk_printf(SSDK_CRIT, "conf->clock set failed \r\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief sdramc ddr training data
|
|
* @param [in] base sdramc base register address
|
|
* @param [in] conf sdramc config parameters
|
|
* @param [in] gate_times twice ddr mode
|
|
* @param [in] gate_val record gate value
|
|
* @param [in] gate_index gate index0 or index1
|
|
* @param [in] training_win record training result
|
|
* @return int32_t
|
|
* @retval 0: success
|
|
* @retval other: failed
|
|
*/
|
|
static int32_t sdramc_ddr_training_data(addr_t base, sdram_config_t *conf,
|
|
uint32_t gate_times, uint32_t (*gate_val)[2], const uint32_t gate_index,
|
|
uint32_t (*training_win)[2][4][2])
|
|
{
|
|
|
|
int32_t ret = SDRV_STATUS_FAIL;
|
|
|
|
for (uint32_t ddr_cs_num = 0; ddr_cs_num < conf->cs_num; ddr_cs_num++) {
|
|
ddr_writel(gate_val[gate_index][0], base + SDRAMC_DDR_DQS_SHIFT);
|
|
ret = sdramc_dll_training(base, gate_index, gate_val, true,
|
|
training_win, ddr_cs_num);
|
|
}
|
|
|
|
dump_training_win_result(training_win, conf, gate_times, true);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief sdramc ddr dll config
|
|
* This function use get key and get value
|
|
* @param [in] base sdramc base register address
|
|
* @param [in] conf sdramc config parameters
|
|
* @param [in] gate_val ddr gate value
|
|
* @param [in] gate_nums gate index
|
|
* @return gate_record_s
|
|
*/
|
|
static gate_record_s sdramc_ddr_dll_config(addr_t base, sdram_config_t *conf,
|
|
uint32_t (*gate_val)[2], uint32_t gate_nums)
|
|
{
|
|
uint32_t max_val = 0u;
|
|
uint32_t get_key = 0u;
|
|
uint32_t gate_index;
|
|
gate_record_s record;
|
|
|
|
for (uint32_t times = 0u; times < gate_nums; times++) {
|
|
if (gate_val[times][1] < WIN_MAX_SUCCESS)
|
|
max_val = MAX(gate_val[times][1], max_val);
|
|
}
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("max_success_times = %d \r\n", max_val);
|
|
|
|
for (gate_index = 0; gate_index < gate_nums; gate_index++) {
|
|
if (max_val == gate_val[gate_index][1]) {
|
|
get_key = gate_val[gate_index][0];
|
|
break;
|
|
}
|
|
}
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("get_key = 0x%08x \r\n", get_key);
|
|
|
|
record.gate_val = get_key;
|
|
record.gate_index = gate_index;
|
|
|
|
return record;
|
|
}
|
|
|
|
/**
|
|
* @brief sdramc ddr set dll config
|
|
* @param [in] base sdramc base register address
|
|
* @param [in] conf sdramc config parameters
|
|
* @param [in] training_win_data_ddr record sdr or ddr result
|
|
* @param [in] gate_s ddr gate array value
|
|
* @return int32_t
|
|
* @retval 0: success
|
|
* @retval other: failed
|
|
*/
|
|
static int32_t sdramc_ddr_set_dll_config(addr_t base, sdram_config_t *conf,
|
|
uint32_t (*training_win_data_ddr)[2][4][2], const gate_record_s *gate_s)
|
|
{
|
|
int32_t ret = SDRV_STATUS_FAIL;;
|
|
uint32_t dll_l_r[4][2] = {{0u, 33u}, {0u, 33u}, {0u, 33u}, {0u, 33u}};
|
|
uint32_t dll_mid = 0;
|
|
ddr_writel(gate_s->gate_val, base + SDRAMC_DDR_DQS_SHIFT);
|
|
|
|
for (uint32_t dll_index = 0; dll_index < conf->dq_width / 8u; dll_index++) {
|
|
for (uint32_t cs_num = 0; cs_num < conf->cs_num; cs_num++) {
|
|
dll_l_r[dll_index][0] = MAX(
|
|
training_win_data_ddr[cs_num][gate_s->gate_index][dll_index][0],
|
|
dll_l_r[dll_index][0]);
|
|
dll_l_r[dll_index][1] = MIN(
|
|
training_win_data_ddr[cs_num][gate_s->gate_index][dll_index][1],
|
|
dll_l_r[dll_index][1]);
|
|
}
|
|
}
|
|
|
|
training_maxl2minr_dump(dll_l_r);
|
|
|
|
for (uint32_t i = 0; i < conf->dq_width / 8u; i++) {
|
|
if (dll_l_r[i][1] > dll_l_r[i][0]) {
|
|
dll_mid = (dll_l_r[i][1] - dll_l_r[i][0]) / 2 + dll_l_r[i][0];
|
|
}
|
|
else {
|
|
return ret;
|
|
}
|
|
|
|
/* find dll mid value and config */
|
|
ret = sdramc_dll_config(base, dll_mid, i);
|
|
|
|
if (ret != SDRV_STATUS_OK) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief sdramc init main function
|
|
*
|
|
* 1.config sdr/ddr register according to different mode
|
|
* 2.training and config dll value for sdr/ddr mode
|
|
*
|
|
* @param [in] base sdramc base register address
|
|
* @param [in] conf sdramc config parameters
|
|
* @return int32_t
|
|
* @retval 0: success
|
|
* @retval other: failed
|
|
*/
|
|
int32_t sdrv_sdramc_init(addr_t base, sdram_config_t *conf)
|
|
{
|
|
|
|
uint32_t reg = 0u;
|
|
uint32_t data_width_mode;
|
|
|
|
int32_t ret = SDRV_STATUS_FAIL;
|
|
|
|
if (conf->ddr_mode) {
|
|
reg = SDRAMC_INIT_DDR_ASYNC_FLUSH_B;
|
|
}
|
|
|
|
|
|
ddr_writel(SDRAMC_INIT_SOFT_RESET, base + SDRAMC_INIT);
|
|
|
|
|
|
ddr_writel(reg, base + SDRAMC_INIT);
|
|
ddr_readl(base + SDRAMC_INIT);
|
|
|
|
ddr_writel((uint32_t)0xFFFFFFFFu, base + SDRAMC_AXI_RDY_CNT);
|
|
|
|
//reg = conf->ddr_mode == false ? 3u : 0u; /* wrdly clk or ddrdqs */
|
|
reg = conf->ddr_mode == false ? 1u : 0u; /* lpb clk or ddrdqs */
|
|
ddr_writel(reg, base + RD_CLK);
|
|
|
|
reg = conf->ddr_mode == false ? 1u : 0u;
|
|
ddr_writel(reg, base + SDRAM_DDR_MODE);
|
|
|
|
ddr_writel(log2_uint(conf->burst_length), base + SDRAM_BURST_MODE);
|
|
|
|
switch (conf->dq_width) {
|
|
case 32u:
|
|
data_width_mode = 0u;
|
|
break;
|
|
|
|
case 16u:
|
|
data_width_mode = 1u;
|
|
break;
|
|
|
|
case 8u:
|
|
data_width_mode = 2u;
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
ddr_writel(data_width_mode, base + SDRAM_WIDTH_MODE);
|
|
|
|
if (conf->cas_latency_x2 == 5u) {
|
|
/* 2.5 cas latency value is 6 */
|
|
reg = 6u << SDRAMC_CAS_MODE_LSB;
|
|
}
|
|
else {
|
|
reg = conf->cas_latency_x2 / 2u << SDRAMC_CAS_MODE_LSB;
|
|
}
|
|
|
|
if (conf->ddr_mode) {
|
|
reg |= (conf->cas_latency_x2 - 2u + 4u) <<
|
|
SDRAMC_CAS_MODE_RD_NONE_DLY; /* default val + 4 */
|
|
}
|
|
else {
|
|
reg |= (conf->cas_latency_x2 / 6u + 4u) << SDRAMC_CAS_MODE_RD_NONE_DLY;
|
|
}
|
|
|
|
ddr_writel(reg, base + SDRAMC_CAS_MODE);
|
|
|
|
reg = 0x0Fu << SDRAMC_SCH_WEIGHT_QOS_W_LSB;
|
|
reg |= 0x02u << SDRAMC_SCH_WEIGHT_BANKIDLE_W_LSB;
|
|
reg |= 0x10u << SDRAMC_SCH_WEIGHT_PAGE_W_LSB;
|
|
reg |= 0x01u << SDRAMC_SCH_WEIGHT_RW_W_LSB;
|
|
ddr_writel(reg, base + SDRAMC_SCH_WEIGHT);
|
|
|
|
reg = 0x02u << SDRAMC_AGING_WEIGHT_LSB;
|
|
ddr_writel(reg, base + SDRAMC_AGING_WEIGHT);
|
|
|
|
// TODO:
|
|
if (conf->ddr_mode == false) {
|
|
ddr_writel((uint32_t)0u, base + SDRAMC_OPERATING_MODE);
|
|
}
|
|
else {
|
|
// TODO: just for test cas latency
|
|
ddr_writel((uint32_t)0u, base + SDRAMC_EXTEND_CONTROL); /* enable dll */
|
|
ddr_writel((uint32_t)0u, base + SDRAMC_OPERATING_MODE);
|
|
}
|
|
|
|
reg = SDRAMC_NS_2_TICKS(conf->clock, conf->comm_config->t_ras_ns)
|
|
<< SDRAMC_TIMING_TRAS_MIN_LSB;
|
|
reg |= SDRAMC_NS_2_TICKS(conf->clock, conf->comm_config->t_rc_ns)
|
|
<< SDRAMC_TIMING_TRC_LSB;
|
|
reg |= SDRAMC_NS_2_TICKS(conf->clock, conf->comm_config->t_rfc_ns)
|
|
<< SDRAMC_TIMING_TRFC_LSB;
|
|
reg |= SDRAMC_NS_2_TICKS(conf->clock, conf->comm_config->t_rcd_ns)
|
|
<< SDRAMC_TIMING_TRCD_LSB;
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("PART1: 0x%x\r\n", reg);
|
|
ddr_writel(reg, base + SDRAMC_TIMING_REGS_PART1);
|
|
|
|
reg = SDRAMC_NS_2_TICKS(conf->clock, conf->comm_config->t_rp_ns)
|
|
<< SDRAMC_TIMING_TRP_LSB;
|
|
reg |= SDRAMC_NS_2_TICKS(conf->clock, conf->comm_config->t_wr_ns)
|
|
<< SDRAMC_TIMING_TWR_LSB;
|
|
reg |= SDRAMC_NS_2_TICKS(conf->clock, conf->comm_config->t_rrd_ns)
|
|
<< SDRAMC_TIMING_TRRD_LSB;
|
|
reg |= conf->comm_config->t_wtr_cycle << SDRAMC_TIMING_TWTR_LSB;
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("PART2: 0x%x\r\n", reg);
|
|
ddr_writel(reg, base + SDRAMC_TIMING_REGS_PART2);
|
|
|
|
// TODO:
|
|
reg = (64u * (conf->clock / 1000u)) / conf->row_num - 60u;
|
|
reg |= (conf->ddr_mode == false ? 200u : 400u)
|
|
<< SDRAMC_TIMING_CNT_200CYCLE_LSB;
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("PART3: 0x%x\r\n", reg);
|
|
ddr_writel(reg, base + SDRAMC_TIMING_REGS_PART3);
|
|
|
|
/* set init 200us count */
|
|
reg = 200u * (conf->clock / 1000000u);
|
|
ddr_writel(reg, base + SDRAMC_INIT_WAIT_CONT);
|
|
|
|
/* ||<--row-->|<---cs--->|<--bank-->|<--column-->|<--dq-width-->|| */
|
|
struct sd_para *sd_bt = sdrv_get_sd_para();
|
|
sd_bt->column_start = 8u;
|
|
SDRAMC_CTL_DATA_DEBUG("column_start = %d\r\n", sd_bt->column_start);
|
|
sd_bt->column_bits = log2_uint(conf->column_num);
|
|
SDRAMC_CTL_DATA_DEBUG("column_bits = %d\r\n", sd_bt->column_bits);
|
|
reg = sd_bt->column_start << SDRAMC_ADDR_DIVED_MODE_COLOW_START_LSB;
|
|
|
|
sd_bt->bank_start = sd_bt->column_bits + log2_uint(conf->dq_width) - 3u;
|
|
SDRAMC_CTL_DATA_DEBUG("bank_start = %d\r\n", sd_bt->bank_start);
|
|
sd_bt->bank_bits = log2_uint(conf->bank_num);
|
|
SDRAMC_CTL_DATA_DEBUG("bank_bits = %d\r\n", sd_bt->bank_bits);
|
|
reg |= sd_bt->bank_start << SDRAMC_ADDR_DIVED_MODE_BANK_START_LSB;
|
|
|
|
|
|
sd_bt->cs_start = sd_bt->bank_start + sd_bt->bank_bits;;
|
|
SDRAMC_CTL_DATA_DEBUG("cs_start = %d\r\n", sd_bt->cs_start);
|
|
sd_bt->cs_bits = log2_uint(conf->cs_num);
|
|
SDRAMC_CTL_DATA_DEBUG("cs_bits = %d\r\n", sd_bt->cs_bits);
|
|
reg |= sd_bt->cs_start << SDRAMC_ADDR_DIVED_MODE_CS_START_LSB;
|
|
|
|
sd_bt->row_start = sd_bt->cs_start + sd_bt->cs_bits;
|
|
SDRAMC_CTL_DATA_DEBUG("row_start = %d\r\n", sd_bt->row_start);
|
|
sd_bt->row_bits = log2_uint(conf->row_num);
|
|
SDRAMC_CTL_DATA_DEBUG("row_bits = %d\r\n", sd_bt->row_bits);
|
|
reg |= sd_bt->row_start << SDRAMC_ADDR_DIVED_MODE_ROW_START_LSB;
|
|
reg |= (sd_bt->row_bits - 7u) << SDRAMC_ADDR_DIVED_MODE_ROW_MODE_LSB;
|
|
ddr_writel(reg, base + SDRAMC_ADDR_DIVED_MODE);
|
|
|
|
reg = sd_bt->cs_bits << SDRAMC_CHIP_SELECT_MODE_LSB;
|
|
reg |= (sd_bt->column_bits - 5u) << SDRAMC_CHIP_SELECT_COLOW_MODE_LSB;
|
|
ddr_writel(reg, base + SDRAMC_CHIP_SELECT_MODE);
|
|
ddr_writel(sd_bt->bank_bits, base + SDRAMC_BANK_MODE);
|
|
|
|
sdrv_set_sd_para(sd_bt); /* save config info */
|
|
|
|
// TODO:
|
|
reg = (conf->ddr_mode == false ? 200u : 400u) << SDRAMC_TIMING_TXSRD_LSB;
|
|
reg |= SDRAMC_NS_2_TICKS(conf->clock, 70000u) - 50u;
|
|
ddr_writel(reg, base + SDRAMC_TIMING_REGS_PART4);
|
|
|
|
reg = (conf->ddr_mode == false ? 1u : 2u) * conf->comm_config->mrd_cycle;
|
|
reg = reg << SDRAMC_MRD_TMR_LSB;
|
|
ddr_writel(reg, base + SDRAMC_MRD);
|
|
|
|
reg = 0u;
|
|
|
|
if (conf->ddr_mode) {
|
|
reg = SDRAMC_INIT_DDR_ASYNC_FLUSH_B;
|
|
ddr_writel(reg, base + SDRAMC_INIT);
|
|
}
|
|
|
|
ddr_writel((uint32_t)0u, base + SDRAMC_INIT);
|
|
|
|
if (conf->ddr_mode) {
|
|
reg = SDRAMC_INIT_DDR_ASYNC_FLUSH_B;
|
|
ddr_writel(reg, base + SDRAMC_INIT);
|
|
}
|
|
|
|
/* Enable clock out */
|
|
reg |= SDRAMC_INIT_DDR_ASYNC_FLUSH_B;
|
|
reg |= SDRAMC_INIT_CLK_OUT_EN;
|
|
ddr_writel(reg, base + SDRAMC_INIT);
|
|
|
|
// TODO: sdramc enable
|
|
reg |= SDRAMC_INIT_START;
|
|
ddr_writel(reg, base + SDRAMC_INIT);
|
|
|
|
/* wait for sdramc register config end */
|
|
while (1) {
|
|
reg = ddr_readl(base + SDRAMC_INIT);
|
|
|
|
if (reg & SDRAMC_INIT_DONE) {
|
|
ssdk_printf(SSDK_CRIT, "sdramc reg config init done!\r\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
reg = ddr_readl(base + SDRAMC_FLOW_CTRL);
|
|
reg &= ~(uint32_t)(SDRAMC_FLOW_CTRL_WR_SET | SDRAMC_FLOW_CTRL_AW_SET |
|
|
SDRAMC_FLOW_CTRL_AR_SET);
|
|
ddr_writel(reg, base + SDRAMC_FLOW_CTRL);
|
|
|
|
/* cs gate(ddr) dllx win_lr */
|
|
uint32_t training_win_record[4u][2u][4u][2u] = {0u};
|
|
|
|
if (conf->ddr_mode == true) {
|
|
|
|
uint32_t gate_val[][2u] = {
|
|
{0u, WIN_MAX_SUCCESS},
|
|
{0u, WIN_MAX_SUCCESS},
|
|
};
|
|
/* set the gate value depending on the frequency */
|
|
ret = sdramc_ddr_set_gate(base, conf, gate_val);
|
|
|
|
if (ret != SDRV_STATUS_OK) {
|
|
ssdk_printf(SSDK_CRIT, "ddr set gate failed!\r\n");
|
|
goto exit;
|
|
}
|
|
|
|
for (uint32_t gate_index = 0; gate_index < ARRAY_SIZE(gate_val); gate_index++) {
|
|
/* entry ddr mode training, and choose the best result from gate value*/
|
|
ret = sdramc_ddr_training_data(base, conf, ARRAY_SIZE(gate_val), gate_val,
|
|
gate_index, training_win_record);
|
|
|
|
if (ret != SDRV_STATUS_OK) {
|
|
ssdk_printf(SSDK_CRIT, "ddr training data failed!\r\n");
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
/* ddr get gate val and index */
|
|
gate_record_s gate_s = sdramc_ddr_dll_config(base, conf, gate_val,
|
|
ARRAY_SIZE(gate_val));
|
|
|
|
SDRAMC_CTL_DATA_DEBUG("gate_val = 0x%x, gate_index = %d \r\n", gate_s.gate_val,
|
|
gate_s.gate_index);
|
|
SDRAMC_CTL_DATA_DEBUG("%d , %d\r\n", gate_val[0][1], gate_val[1][1]);
|
|
|
|
/* ddr set save record result for dll */
|
|
ret = sdramc_ddr_set_dll_config(base, conf, training_win_record, &gate_s);
|
|
|
|
if (ret != SDRV_STATUS_OK) {
|
|
ssdk_printf(SSDK_CRIT, "ddr set dll config failed!\r\n");
|
|
goto exit;
|
|
}
|
|
|
|
}
|
|
else {
|
|
ddr_writel(SDRAMC_DQS_QE_SET_VAL | SDRAMC_DQS_QE_SET_EN,
|
|
base + SDRAMC_DQS_QE_SET);
|
|
uint32_t cas_num = conf->cas_latency_x2 / 2u - 1u;
|
|
ddr_writel(cas_num, base + SDRAMC_SDR_DQS_SHIFT);
|
|
|
|
/* entry sdr mode training */
|
|
ret = sdramc_sdr_training_data(base, conf, training_win_record);
|
|
|
|
if (ret != SDRV_STATUS_OK) {
|
|
ssdk_printf(SSDK_CRIT, "sdr training data failed!\r\n");
|
|
goto exit;
|
|
}
|
|
|
|
/* sdr training end and set dll */
|
|
ret = sdramc_sdr_set_dll_config(base, conf, training_win_record);
|
|
|
|
if (ret != SDRV_STATUS_OK) {
|
|
ssdk_printf(SSDK_CRIT, "sdr dll config failed!\r\n");
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return ret;
|
|
}
|