mediatek/mt8183: Implement the dramc init setting

This patch implements the dram init setting by replacing the hard-coded
init sequence with a series of functions to support calibration for more
frequencies. These functions are modified from MediaTek's internal DRAM
full calibration source code.

BUG=b:80501386
BRANCH=none
TEST=1. Kukui boots correctly
     2. Stress test (/usr/sbin/memtester 500M) passes on Kukui

Change-Id: I756ad37e78cd1384ee0eb97e5e18c5461d73bc7b
Signed-off-by: Huayang Duan <huayang.duan@mediatek.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/34988
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
This commit is contained in:
Huayang Duan 2019-08-19 14:06:31 +08:00 committed by Patrick Georgi
parent e68da64969
commit 7378015b74
7 changed files with 1845 additions and 1097 deletions

File diff suppressed because it is too large Load Diff

View File

@ -20,11 +20,21 @@
#include <soc/dramc_register.h>
#include <soc/dramc_pi_api.h>
static u32 impedance[2][4];
u8 get_freq_fsq(u8 freq)
{
if (freq == LP4X_DDR1600 || freq == LP4X_DDR2400)
return FSP_0;
else
return FSP_1;
}
static void dramc_sw_imp_cal_vref_sel(u8 term_option, u8 impcal_stage)
{
u8 vref_sel = 0;
if (term_option == 1)
if (term_option == ODT_ON)
vref_sel = IMP_LP4X_TERM_VREF_SEL;
else {
switch (impcal_stage) {
@ -43,14 +53,114 @@ static void dramc_sw_imp_cal_vref_sel(u8 term_option, u8 impcal_stage)
clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11], 0x3f << 8, vref_sel << 8);
}
void dramc_sw_impedance(const struct sdram_params *params)
void dramc_sw_impedance_cal(const struct sdram_params *params, u8 term)
{
u8 term = 0, ca_term = ODT_OFF, dq_term = ODT_ON;
u32 broadcast_bak, impcal_bak, imp_cal_result;
u32 DRVP_result = 0xff, ODTN_result = 0xff, DRVN_result = 0x9;
broadcast_bak = dramc_get_broadcast();
dramc_set_broadcast(DRAMC_BROADCAST_OFF);
clrbits_le32(&ch[0].phy.misc_spm_ctrl1, 0xf << 0);
write32(&ch[0].phy.misc_spm_ctrl2, 0x0);
write32(&ch[0].phy.misc_spm_ctrl0, 0x0);
clrbits_le32(&ch[0].ao.impcal, 0x1 << 31);
impcal_bak = read32(&ch[0].ao.impcal);
dramc_sw_imp_cal_vref_sel(term, IMPCAL_STAGE_DRVP);
clrbits_le32(&ch[0].phy.misc_imp_ctrl1, 0x1 << 6);
clrsetbits_le32(&ch[0].ao.impcal, 0x1 << 21, 0x3 << 24);
clrsetbits_le32(&ch[0].phy.misc_imp_ctrl0, 0x7 << 4, 0x3 << 4);
udelay(1);
dramc_show("K DRVP\n");
setbits_le32(&ch[0].ao.impcal, 0x1 << 23);
setbits_le32(&ch[0].ao.impcal, 0x1 << 22);
clrbits_le32(&ch[0].ao.impcal, 0x1 << 21);
clrbits_le32(&ch[0].ao.shu[0].impcal1, 0x1f << 4 | 0x1f << 11);
clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11], 0xff << 0, 0x3);
for (u8 impx_drv = 0; impx_drv < 32; impx_drv++) {
impx_drv = (impx_drv == 16) ? 29 : impx_drv;
clrsetbits_le32(&ch[0].ao.shu[0].impcal1,
0x1f << 4, impx_drv << 4);
udelay(1);
imp_cal_result = (read32(&ch[0].phy_nao.misc_phy_rgs_cmd) >>
24) & 0x1;
dramc_show("1. OCD DRVP=%d CALOUT=%d\n",
impx_drv, imp_cal_result);
if (imp_cal_result == 1 && DRVP_result == 0xff) {
DRVP_result = impx_drv;
dramc_show("1. OCD DRVP calibration OK! DRVP=%d\n",
DRVP_result);
break;
}
}
dramc_show("K ODTN\n");
dramc_sw_imp_cal_vref_sel(term, IMPCAL_STAGE_DRVN);
clrbits_le32(&ch[0].ao.impcal, 0x1 << 22);
if (term == ODT_ON)
setbits_le32(&ch[0].ao.impcal, 0x1 << 21);
clrsetbits_le32(&ch[0].ao.shu[0].impcal1, 0x1f << 4 | 0x1f << 11,
DRVP_result << 4 | 0x1f << 11);
clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11], 0xff << 0, 0x3);
for (u8 impx_drv = 0; impx_drv < 32; impx_drv++) {
impx_drv = (impx_drv == 16) ? 29 : impx_drv;
clrsetbits_le32(&ch[0].ao.shu[0].impcal1,
0x1f << 11, impx_drv << 11);
udelay(1);
imp_cal_result = (read32(&ch[0].phy_nao.misc_phy_rgs_cmd) >>
24) & 0x1;
dramc_show("3. OCD ODTN=%d CALOUT=%d\n",
impx_drv, imp_cal_result);
if (imp_cal_result == 0 && ODTN_result == 0xff) {
ODTN_result = impx_drv;
dramc_show("3. OCD ODTN calibration OK! ODTN=%d\n",
ODTN_result);
break;
}
}
write32(&ch[0].ao.impcal, impcal_bak);
dramc_show("term:%d, DRVP=%d, DRVN=%d, ODTN=%d\n",
term, DRVP_result, DRVN_result, ODTN_result);
if (term == ODT_OFF) {
impedance[term][0] = DRVP_result;
impedance[term][1] = ODTN_result;
impedance[term][2] = 0;
impedance[term][3] = 15;
} else {
impedance[term][0] = (DRVP_result <= 3) ?
(DRVP_result * 3) : DRVP_result;
impedance[term][1] = (DRVN_result <= 3) ?
(DRVN_result * 3) : DRVN_result;
impedance[term][2] = 0;
impedance[term][3] = (ODTN_result <= 3) ?
(ODTN_result * 3) : ODTN_result;
}
dramc_sw_imp_cal_vref_sel(term, IMPCAL_STAGE_TRACKING);
dramc_set_broadcast(broadcast_bak);
}
void dramc_sw_impedance_save_reg(u8 freq_group)
{
u8 ca_term = ODT_OFF, dq_term = ODT_ON;
u32 sw_impedance[2][4] = {0};
for (term = 0; term < 2; term++)
if (get_freq_fsq(freq_group) == FSP_0)
dq_term = ODT_OFF;
for (u8 term = 0; term < 2; term++)
for (u8 i = 0; i < 4; i++)
sw_impedance[term][i] = params->impedance[term][i];
sw_impedance[term][i] = impedance[term][i];
sw_impedance[ODT_OFF][2] = sw_impedance[ODT_ON][2];
sw_impedance[ODT_OFF][3] = sw_impedance[ODT_ON][3];

View File

@ -102,13 +102,13 @@ static void dramc_auto_refresh_switch(u8 chn, bool option)
}
}
static void dramc_cke_fix_onoff(u8 chn, bool fix_on, bool fix_off)
void dramc_cke_fix_onoff(u8 chn, bool fix_on, bool fix_off)
{
clrsetbits_le32(&ch[chn].ao.ckectrl, (0x1 << 6) | (0x1 << 7),
((fix_on ? 1 : 0) << 6) | ((fix_off ? 1 : 0) << 7));
}
static void dramc_mode_reg_write(u8 chn, u8 mr_idx, u8 value)
void dramc_mode_reg_write(u8 chn, u8 mr_idx, u8 value)
{
u32 ckectrl_bak = read32(&ch[chn].ao.ckectrl);

View File

@ -279,16 +279,17 @@ static void dramc_ac_timing_optimize(void)
}
}
static void init_dram(const struct sdram_params *params)
static void init_dram(const struct sdram_params *params, u8 freq_group)
{
global_option_init(params);
emi_init(params);
dramc_set_broadcast(DRAMC_BROADCAST_ON);
dramc_init_pre_settings();
dramc_sw_impedance(params);
dramc_sw_impedance_cal(params, ODT_OFF);
dramc_sw_impedance_cal(params, ODT_ON);
dramc_init();
dramc_init(params, freq_group);
emi_init2(params);
}
@ -312,6 +313,6 @@ static void do_calib(const struct sdram_params *params)
void mt_set_emi(const struct sdram_params *params)
{
init_dram(params);
init_dram(params, LP4X_DDR3200);
do_calib(params);
}

View File

@ -85,8 +85,8 @@ enum {
};
enum {
SAVE_VALUE,
RESTORE_VALUE
DLL_MASTER = 0,
DLL_SLAVE,
};
struct reg_value {
@ -94,6 +94,9 @@ struct reg_value {
u32 value;
};
#define _SELPH_DQS_BITS(l, h) ((l << 0) | (l << 4) | (l << 8) | (l << 12) | \
(h << 16) | (h << 20) | (h << 24) | (h << 28))
enum {
DQ_DIV_SHIFT = 3,
DQ_DIV_MASK = BIT(DQ_DIV_SHIFT) - 1,
@ -103,30 +106,30 @@ enum {
DQS_DELAY_0P5T = 4,
DQS_DELAY = ((DQS_DELAY_2T << DQ_DIV_SHIFT) + DQS_DELAY_0P5T) << 5,
DQS_OEN_DELAY_2T = 3,
DQS_OEN_DELAY_0P5T = 1,
SELPH_DQS0 = (DQS_DELAY_2T << 0) | (DQS_DELAY_2T << 4) |
(DQS_DELAY_2T << 8) | (DQS_DELAY_2T << 12) |
(DQS_OEN_DELAY_2T << 16) | (DQS_OEN_DELAY_2T << 20) |
(DQS_OEN_DELAY_2T << 24) | (DQS_OEN_DELAY_2T << 28),
SELPH_DQS1 = (DQS_DELAY_0P5T << 0) | (DQS_DELAY_0P5T << 4) |
(DQS_DELAY_0P5T << 8) | (DQS_DELAY_0P5T << 12) |
(DQS_OEN_DELAY_0P5T << 16) | (DQS_OEN_DELAY_0P5T << 20) |
(DQS_OEN_DELAY_0P5T << 24) | (DQS_OEN_DELAY_0P5T << 28)
SELPH_DQS0 = _SELPH_DQS_BITS(0x3, 0x3),
SELPH_DQS1 = _SELPH_DQS_BITS(0x4, 0x1),
SELPH_DQS0_1600 = _SELPH_DQS_BITS(0x2, 0x1),
SELPH_DQS1_1600 = _SELPH_DQS_BITS(0x1, 0x6),
SELPH_DQS0_2400 = _SELPH_DQS_BITS(0x3, 0x2),
SELPH_DQS1_2400 = _SELPH_DQS_BITS(0x1, 0x6),
SELPH_DQS0_3600 = _SELPH_DQS_BITS(0x4, 0x3),
SELPH_DQS1_3600 = _SELPH_DQS_BITS(0x1, 0x6),
};
void dramc_get_rank_size(u64 *dram_rank_size);
void dramc_runtime_config(void);
void dramc_set_broadcast(u32 onoff);
u32 dramc_get_broadcast(void);
void dramc_init(void);
void dramc_sw_impedance(const struct sdram_params *params);
u8 get_freq_fsq(u8 freq_group);
void dramc_init(const struct sdram_params *params, u8 freq_group);
void dramc_sw_impedance_save_reg(u8 freq_group);
void dramc_sw_impedance_cal(const struct sdram_params *params, u8 term_option);
void dramc_apply_config_before_calibration(void);
void dramc_apply_config_after_calibration(void);
void dramc_calibrate_all_channels(const struct sdram_params *params);
void dramc_hw_gating_onoff(u8 chn, bool onoff);
void dramc_enable_phy_dcm(bool bEn);
void dramc_mode_reg_write(u8 chn, u8 mr_idx, u8 value);
void dramc_cke_fix_onoff(u8 chn, bool fix_on, bool fix_off);
#endif /* _DRAMC_PI_API_MT8183_H */

View File

@ -986,6 +986,8 @@ enum {
SPCMD_DQSGCNTRST_SHIFT = 9,
SPCMD_DQSGCNTEN_SHIFT = 8,
SPCMD_RDDQCEN_SHIFT = 7,
SPCMD_ZQLATEN_SHIFT = 6,
SPCMD_ZQCEN_SHIFT = 4,
SPCMD_MRWEN_SHIFT = 0,
};

View File

@ -33,6 +33,14 @@ struct sdram_params {
u16 delay_cell_unit;
};
enum {
LP4X_DDR1600,
LP4X_DDR2400,
LP4X_DDR3200,
LP4X_DDR3600,
LP4X_DDRFREQ_MAX,
};
extern const u8 phy_mapping[CHANNEL_MAX][16];
int complex_mem_test(u8 *start, unsigned int len);