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:
parent
e68da64969
commit
7378015b74
File diff suppressed because it is too large
Load Diff
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue