aboutsummaryrefslogtreecommitdiff
path: root/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
diff options
context:
space:
mode:
authorHuayang Duan <huayang.duan@mediatek.com>2020-06-01 16:30:27 +0800
committerHung-Te Lin <hungte@chromium.org>2020-09-25 01:33:11 +0000
commit63ee16075e7e4dee90c0cb9b05caeb91f77bf1e5 (patch)
tree31a9df5073b1248a6dece2d390e017da733e3a31 /src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
parent92c1546c01795f8c8c079e7ea03c9cb36314e92a (diff)
soc/mediatek/mt8183: Enable CA perbit mechanism
LPDDR4x has 6 CA PINs, but for some 8GB LPDDR4X DDR, the left margin of some CA PIN window is too small than others. Need to enable the CA perbit mechanism to avoid those risks. BUG=none BRANCH=kukui TEST=Boots correctly on Kukui Change-Id: I58e29d0c91a469112b0b1292da80bcb802322d47 Signed-off-by: Huayang Duan <huayang.duan@mediatek.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/41965 Reviewed-by: Hung-Te Lin <hungte@chromium.org> Reviewed-by: Yu-Ping Wu <yupingso@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/soc/mediatek/mt8183/dramc_pi_calibration_api.c')
-rw-r--r--src/soc/mediatek/mt8183/dramc_pi_calibration_api.c344
1 files changed, 315 insertions, 29 deletions
diff --git a/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
index fce7c9ff4a..17fa2306e3 100644
--- a/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
+++ b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
@@ -8,6 +8,7 @@
#include <soc/dramc_register.h>
#include <soc/dramc_param.h>
#include <soc/dramc_pi_api.h>
+#include <soc/spm.h>
#include <timer.h>
enum {
@@ -72,6 +73,11 @@ struct per_byte_dly {
u16 final_dly;
};
+static const u8 lp4_ca_mapping_pop[CHANNEL_MAX][CA_NUM_LP4] = {
+ [CHANNEL_A] = {1, 4, 3, 2, 0, 5},
+ [CHANNEL_B] = {0, 3, 2, 4, 1, 5},
+};
+
static void dramc_auto_refresh_switch(u8 chn, bool option)
{
SET32_BITFIELDS(&ch[chn].ao.refctrl0, REFCTRL0_REFDIS, option ? 0 : 1);
@@ -86,13 +92,6 @@ static void dramc_auto_refresh_switch(u8 chn, bool option)
}
}
-void dramc_cke_fix_onoff(u8 chn, bool cke_on, bool cke_off)
-{
- SET32_BITFIELDS(&ch[chn].ao.ckectrl,
- CKECTRL_CKEFIXON, cke_on,
- CKECTRL_CKEFIXOFF, cke_off);
-}
-
static u16 dramc_mode_reg_read(u8 chn, u8 mr_idx)
{
u16 value;
@@ -116,7 +115,7 @@ void dramc_mode_reg_write(u8 chn, u8 mr_idx, u8 value)
{
u32 ckectrl_bak = read32(&ch[chn].ao.ckectrl);
- dramc_cke_fix_onoff(chn, true, false);
+ dramc_cke_fix_onoff(CKE_FIXON, chn);
SET32_BITFIELDS(&ch[chn].ao.mrs, MRS_MRSMA, mr_idx);
SET32_BITFIELDS(&ch[chn].ao.mrs, MRS_MRSOP, value);
SET32_BITFIELDS(&ch[chn].ao.spcmd, SPCMD_MRWEN, 1);
@@ -255,33 +254,320 @@ static void dramc_write_leveling(u8 chn, u8 rank, u8 freq_group,
}
}
-static void dramc_cmd_bus_training(u8 chn, u8 rank, u8 freq_group,
- const struct sdram_params *params, const bool fast_calib)
+static void cbt_set_perbit_delay_cell(u8 chn, u8 rank)
{
- u32 final_vref, clk_dly, cmd_dly, cs_dly;
+ SET32_BITFIELDS(&ch[chn].phy.shu[0].rk[rank].ca_cmd[0],
+ SHU1_R0_CA_CMD0_RK0_TX_ARCA0_DLY, 0,
+ SHU1_R0_CA_CMD0_RK0_TX_ARCA1_DLY, 0,
+ SHU1_R0_CA_CMD0_RK0_TX_ARCA2_DLY, 0,
+ SHU1_R0_CA_CMD0_RK0_TX_ARCA3_DLY, 0,
+ SHU1_R0_CA_CMD0_RK0_TX_ARCA4_DLY, 0,
+ SHU1_R0_CA_CMD0_RK0_TX_ARCA5_DLY, 0);
+}
- clk_dly = params->cbt_clk_dly[chn][rank];
- cmd_dly = params->cbt_cmd_dly[chn][rank];
- cs_dly = params->cbt_cs_dly[chn][rank];
- final_vref = params->cbt_final_vref[chn][rank];
+static void set_dram_mr_cbt_on_off(u8 chn, u8 rank, u8 fsp,
+ u8 cbt_on, struct mr_value *mr)
+{
+ u8 MR13Value = mr->MR13Value;
- if (fast_calib) {
+ if (cbt_on) {
+ MR13Value |= 0x1;
+ if (fsp == FSP_1)
+ MR13Value &= 0x7f;
+ else
+ MR13Value |= 0x80;
+ } else {
+ MR13Value &= 0xfe;
+ if (fsp == FSP_1)
+ MR13Value |= 0x80;
+ else
+ MR13Value &= 0x7f;
+ }
+
+ dramc_mode_reg_write_by_rank(chn, rank, 13, MR13Value);
+ mr->MR13Value = MR13Value;
+}
+
+static void cbt_set_fsp(u8 chn, u8 rank, u8 fsp, struct mr_value *mr)
+{
+ u8 MR13Value = mr->MR13Value;
+
+ if (fsp == FSP_0) {
+ MR13Value &= ~(BIT(6));
+ MR13Value &= 0x7f;
+ } else {
+ MR13Value |= BIT(6);
+ MR13Value |= 0x80;
+ }
+
+ dramc_mode_reg_write_by_rank(chn, rank, 13, MR13Value);
+ mr->MR13Value = MR13Value;
+}
+
+static void o1_path_on_off(u8 cbt_on)
+{
+ u8 fix_dqien = (cbt_on == 1) ? 3 : 0;
+
+ for (u8 chn = 0; chn < CHANNEL_MAX; chn++) {
+ SET32_BITFIELDS(&ch[chn].ao.padctrl, PADCTRL_FIXDQIEN, fix_dqien);
+ SET32_BITFIELDS(&ch[chn].phy.b[0].dq[5],
+ B0_DQ5_RG_RX_ARDQ_EYE_VREF_EN_B0, cbt_on);
+ SET32_BITFIELDS(&ch[chn].phy.b[1].dq[5],
+ B1_DQ5_RG_RX_ARDQ_EYE_VREF_EN_B1, cbt_on);
+ SET32_BITFIELDS(&ch[chn].phy.b[0].dq[3],
+ B0_DQ3_RG_RX_ARDQ_SMT_EN_B0, cbt_on);
+ SET32_BITFIELDS(&ch[chn].phy.b[1].dq[3],
+ B1_DQ3_RG_RX_ARDQ_SMT_EN_B1, cbt_on);
+ }
+ udelay(1);
+}
+
+static void cbt_entry(u8 chn, u8 rank, u8 fsp, struct mr_value *mr)
+{
+ SET32_BITFIELDS(&ch[chn].ao.dramc_pd_ctrl,
+ DRAMC_PD_CTRL_PHYCLKDYNGEN, 0,
+ DRAMC_PD_CTRL_DCMEN, 0);
+ SET32_BITFIELDS(&ch[chn].ao.stbcal, STBCAL_DQSIENCG_NORMAL_EN, 0);
+ SET32_BITFIELDS(&ch[chn].ao.dramc_pd_ctrl, DRAMC_PD_CTRL_MIOCKCTRLOFF, 1);
+
+ dramc_cke_fix_onoff(CKE_FIXON, chn);
+ set_dram_mr_cbt_on_off(chn, rank, fsp, 1, mr);
+ SET32_BITFIELDS(&ch[chn].ao.write_lev, WRITE_LEV_WRITE_LEVEL_EN, 1);
+
+ udelay(1);
+ dramc_cke_fix_onoff(CKE_FIXOFF, chn);
+ o1_path_on_off(1);
+}
+
+static void cbt_exit(u8 chn, u8 rank, u8 fsp, struct mr_value *mr)
+{
+ dramc_cke_fix_onoff(CKE_FIXON, chn);
+
+ udelay(1);
+ set_dram_mr_cbt_on_off(chn, rank, fsp, 0, mr);
+ o1_path_on_off(0);
+}
+
+static void cbt_set_vref(u8 chn, u8 rank, u8 vref, bool is_final)
+{
+ if (!is_final) {
+ SET32_BITFIELDS(&ch[chn].ao.write_lev, WRITE_LEV_DMVREFCA, vref);
+ SET32_BITFIELDS(&ch[chn].ao.write_lev, WRITE_LEV_DQS_SEL, 1);
+ SET32_BITFIELDS(&ch[chn].ao.write_lev, WRITE_LEV_DQSBX_G, 0xa);
+ SET32_BITFIELDS(&ch[chn].ao.write_lev, WRITE_LEV_DQS_WLEV, 1);
+ udelay(1);
+ SET32_BITFIELDS(&ch[chn].ao.write_lev, WRITE_LEV_DQS_WLEV, 0);
+ } else {
+ vref |= BIT(6);
+ dramc_dbg("final_vref: %#x\n", vref);
+
+ /* CBT set vref */
+ dramc_mode_reg_write_by_rank(chn, rank, 12, vref);
+ }
+}
+
+static void cbt_set_ca_clk_result(u8 chn, u8 rank,
+ const struct sdram_params *params)
+{
+ const u8 *perbit_dly;
+ u8 clk_dly = params->cbt_clk_dly[chn][rank];
+ u8 cmd_dly = params->cbt_cmd_dly[chn][rank];
+ const u8 *ca_mapping = lp4_ca_mapping_pop[chn];
+
+ for (u8 rk = 0; rk < rank + 1; rk++) {
/* Set CLK and CA delay */
- SET32_BITFIELDS(&ch[chn].phy.shu[0].rk[rank].ca_cmd[9],
+ SET32_BITFIELDS(&ch[chn].phy.shu[0].rk[rk].ca_cmd[9],
SHU1_R0_CA_CMD9_RG_RK0_ARPI_CMD, cmd_dly,
SHU1_R0_CA_CMD9_RG_RK0_ARPI_CLK, clk_dly);
udelay(1);
+
+ perbit_dly = params->cbt_ca_perbit_delay[chn][rk];
+
+ /* Set CA perbit delay line calibration results */
+ SET32_BITFIELDS(&ch[chn].phy.shu[0].rk[rk].ca_cmd[0],
+ SHU1_R0_CA_CMD0_RK0_TX_ARCA0_DLY, perbit_dly[ca_mapping[0]],
+ SHU1_R0_CA_CMD0_RK0_TX_ARCA1_DLY, perbit_dly[ca_mapping[1]],
+ SHU1_R0_CA_CMD0_RK0_TX_ARCA2_DLY, perbit_dly[ca_mapping[2]],
+ SHU1_R0_CA_CMD0_RK0_TX_ARCA3_DLY, perbit_dly[ca_mapping[3]],
+ SHU1_R0_CA_CMD0_RK0_TX_ARCA4_DLY, perbit_dly[ca_mapping[4]],
+ SHU1_R0_CA_CMD0_RK0_TX_ARCA5_DLY, perbit_dly[ca_mapping[5]]);
}
+}
- /* Set CLK and CS delay */
- SET32_BITFIELDS(&ch[chn].phy.shu[0].rk[rank].ca_cmd[9],
- SHU1_R0_CA_CMD9_RG_RK0_ARPI_CS, cs_dly);
+static u8 get_cbt_vref_pinmux_value(u8 chn, u8 vref_level)
+{
+ u8 vref_bit, vref_new, vref_org;
- final_vref |= (1 << 6);
+ vref_new = 0;
+ vref_org = BIT(6) | (vref_level & 0x3f);
+ for (vref_bit = 0; vref_bit < 8; vref_bit++) {
+ if (vref_org & (1 << vref_bit))
+ vref_new |= (1 << phy_mapping[chn][vref_bit]);
+ }
+
+ dramc_dbg("vref_new: %#x --> %#x\n", vref_org, vref_new);
+
+ return vref_new;
+}
+
+static void cbt_dramc_dfs_direct_jump(u8 shu_level)
+{
+ u8 shu_ack = 0;
+ static bool phy_pll_en = true;
+
+ for (u8 chn = 0; chn < CHANNEL_MAX; chn++)
+ shu_ack |= (0x1 << chn);
+
+ if (phy_pll_en) {
+ dramc_dbg("Disable CLRPLL\n");
+ SET32_BITFIELDS(&ch[0].phy.pll2, PLL2_RG_RCLRPLL_EN, 0);
+ dramc_dbg("DFS jump to CLRPLL, shu lev=%d, ACK=%x\n",
+ shu_level, shu_ack);
+ } else {
+ dramc_dbg("Disable PHYPLL\n");
+ SET32_BITFIELDS(&ch[0].phy.pll1, PLL1_RG_RPHYPLL_EN, 0);
+ dramc_dbg("DFS jump to PHYPLL, shu lev=%d, ACK=%x\n",
+ shu_level, shu_ack);
+ }
+
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_PHYPLL1_SHU_EN_PCM, 0);
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_PHYPLL2_SHU_EN_PCM, 0);
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_DR_SHU_LEVEL_PCM, 0);
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_DR_SHU_LEVEL_PCM, shu_level);
+
+ if (phy_pll_en) {
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_PHYPLL2_SHU_EN_PCM, 1);
+ udelay(1);
+ SET32_BITFIELDS(&ch[0].phy.pll2, PLL2_RG_RCLRPLL_EN, 1);
+ dramc_dbg("Enable CLRPLL\n");
+ } else {
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_PHYPLL1_SHU_EN_PCM, 1);
+ udelay(1);
+ SET32_BITFIELDS(&ch[0].phy.pll1, PLL1_RG_RPHYPLL_EN, 1);
+ dramc_dbg("Enable PHYPLL\n");
+ }
+
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_TX_TRACKING_DIS, 3);
+
+ udelay(20);
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_DDRPHY_FB_CK_EN_PCM, 1);
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_DPHY_RXDLY_TRACK_EN, 0);
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_DR_SHU_EN_PCM, 1);
- /* CBT set vref */
- dramc_mode_reg_write_by_rank(chn, rank, 12, final_vref);
- dramc_dbg("final_vref: %#x\n", final_vref);
+ while ((READ32_BITFIELD(&mtk_spm->dramc_dpy_clk_sw_con,
+ DRAMC_DPY_CLK_SW_CON_SC_DMDRAMCSHU_ACK) & shu_ack)
+ != shu_ack) {
+ dramc_dbg("wait shu_en ack.\n");
+ }
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_DR_SHU_EN_PCM, 0);
+
+ if (shu_level == 0)
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_DPHY_RXDLY_TRACK_EN, 3);
+
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_TX_TRACKING_DIS, 0);
+ SET32_BITFIELDS(&mtk_spm->spm_power_on_val0,
+ SPM_POWER_ON_VAL0_SC_DDRPHY_FB_CK_EN_PCM, 0);
+
+ if (phy_pll_en)
+ SET32_BITFIELDS(&ch[0].phy.pll1, PLL1_RG_RPHYPLL_EN, 0);
+ else
+ SET32_BITFIELDS(&ch[0].phy.pll2, PLL2_RG_RCLRPLL_EN, 0);
+ dramc_dbg("Shuffle flow complete\n");
+
+ phy_pll_en = !phy_pll_en;
+}
+
+static void cbt_switch_freq(cbt_freq freq)
+{
+ if (freq == CBT_LOW_FREQ)
+ cbt_dramc_dfs_direct_jump(DRAM_DFS_SHUFFLE_MAX - 1);
+ else
+ cbt_dramc_dfs_direct_jump(DRAM_DFS_SHUFFLE_1);
+}
+
+static void dramc_cmd_bus_training(u8 chn, u8 rank, u8 freq_group,
+ const struct sdram_params *params, const bool fast_calib,
+ struct mr_value *mr)
+{
+ u8 final_vref, cs_dly;
+ u8 fsp = get_freq_fsq(freq_group);
+
+ cs_dly = params->cbt_cs_dly[chn][rank];
+ final_vref = params->cbt_final_vref[chn][rank];
+
+ struct reg_value regs_bak[] = {
+ {&ch[chn].ao.dramc_pd_ctrl},
+ {&ch[chn].ao.stbcal},
+ {&ch[chn].ao.ckectrl},
+ {&ch[chn].ao.write_lev},
+ {&ch[chn].ao.refctrl0},
+ {&ch[chn].ao.spcmdctrl},
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(regs_bak); i++)
+ regs_bak[i].value = read32(regs_bak[i].addr);
+
+ dramc_auto_refresh_switch(chn, false);
+ if (rank == RANK_1) {
+ SET32_BITFIELDS(&ch[chn].ao.mrs, MRS_MRSRK, rank);
+ SET32_BITFIELDS(&ch[chn].ao.rkcfg, RKCFG_TXRANK, rank);
+ SET32_BITFIELDS(&ch[chn].ao.rkcfg, RKCFG_TXRANKFIX, 1);
+ SET32_BITFIELDS(&ch[chn].ao.mpc_option, MPC_OPTION_MPCRKEN, 0);
+ }
+
+ cbt_set_perbit_delay_cell(chn, rank);
+
+ if (fsp == FSP_1)
+ cbt_switch_freq(CBT_LOW_FREQ);
+ cbt_entry(chn, rank, fsp, mr);
+ if (fsp == FSP_1)
+ cbt_switch_freq(CBT_HIGH_FREQ);
+
+ u8 new_vref = get_cbt_vref_pinmux_value(chn, final_vref);
+ cbt_set_vref(chn, rank, new_vref, 0);
+
+ cbt_set_ca_clk_result(chn, rank, params);
+
+ for (u8 rk = 0; rk < rank + 1; rk++) {
+ /* Set CLK and CS delay */
+ SET32_BITFIELDS(&ch[chn].phy.shu[0].rk[rk].ca_cmd[9],
+ SHU1_R0_CA_CMD9_RG_RK0_ARPI_CS, cs_dly);
+ }
+
+ if (fsp == FSP_1)
+ cbt_switch_freq(CBT_LOW_FREQ);
+ cbt_exit(chn, rank, fsp, mr);
+
+ cbt_set_fsp(chn, rank, fsp, mr);
+ cbt_set_vref(chn, rank, final_vref, 1);
+
+ if (fsp == FSP_1)
+ cbt_switch_freq(CBT_HIGH_FREQ);
+
+ /* restore MRR pinmux */
+ set_mrr_pinmux_mapping();
+ if (rank == RANK_1) {
+ SET32_BITFIELDS(&ch[chn].ao.mrs, MRS_MRSRK, 0);
+ SET32_BITFIELDS(&ch[chn].ao.rkcfg, RKCFG_TXRANK, 0);
+ SET32_BITFIELDS(&ch[chn].ao.rkcfg, RKCFG_TXRANKFIX, 0);
+ SET32_BITFIELDS(&ch[chn].ao.mpc_option, MPC_OPTION_MPCRKEN, 0x1);
+ }
+
+ for (int i = 0; i < ARRAY_SIZE(regs_bak); i++)
+ write32(regs_bak[i].addr, regs_bak[i].value);
}
static void dramc_read_dbi_onoff(size_t chn, bool on)
@@ -505,7 +791,7 @@ void dramc_apply_config_after_calibration(const struct mr_value *mr)
clrbits32(&ch[chn].ao.shu[shu].scintv, 0x1 << 30);
clrbits32(&ch[chn].ao.dummy_rd, (0x7 << 20) | (0x1 << 7));
- dramc_cke_fix_onoff(chn, false, false);
+ dramc_cke_fix_onoff(CKE_DYNAMIC, chn);
clrbits32(&ch[chn].ao.dramc_pd_ctrl, 0x1 << 26);
clrbits32(&ch[chn].ao.eyescan, 0x7 << 8);
@@ -2189,7 +2475,7 @@ static void dqsosc_auto(u8 chn, u8 rank, u8 freq_group,
SET32_BITFIELDS(&ch[chn].ao.dramc_pd_ctrl,
DRAMC_PD_CTRL_MIOCKCTRLOFF, 1);
- dramc_cke_fix_onoff(chn, true, false);
+ dramc_cke_fix_onoff(CKE_FIXON, chn);
start_dqsosc(chn);
udelay(1);
@@ -2757,8 +3043,8 @@ void get_dram_info_after_cal(u8 *density_result)
*density_result = max_density;
}
-int dramc_calibrate_all_channels(const struct sdram_params *pams, u8 freq_group,
- const struct mr_value *mr)
+int dramc_calibrate_all_channels(const struct sdram_params *pams,
+ u8 freq_group, struct mr_value *mr)
{
bool fast_calib;
switch (pams->source) {
@@ -2782,7 +3068,7 @@ int dramc_calibrate_all_channels(const struct sdram_params *pams, u8 freq_group,
dramc_dbg("Start K: freq=%d, ch=%d, rank=%d\n",
freq_group, chn, rk);
dramc_cmd_bus_training(chn, rk, freq_group, pams,
- fast_calib);
+ fast_calib, mr);
dramc_write_leveling(chn, rk, freq_group, pams->wr_level);
dramc_auto_refresh_switch(chn, true);