Hello Duan huayang,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/44717
to review the following change.
Change subject: soc/mediatek/mt8192: Do write leveling training ......................................................................
soc/mediatek/mt8192: Do write leveling training
Signed-off-by: Huayang Duan huayang.duan@mediatek.com Change-Id: Icf4f5d07eb8ef1d0d99ad106f497fea5f60c8a97 --- M src/soc/mediatek/mt8192/dramc_pi_basic_api.c M src/soc/mediatek/mt8192/dramc_pi_main.c 2 files changed, 196 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/17/44717/1
diff --git a/src/soc/mediatek/mt8192/dramc_pi_basic_api.c b/src/soc/mediatek/mt8192/dramc_pi_basic_api.c index 84acb3e..d418228 100644 --- a/src/soc/mediatek/mt8192/dramc_pi_basic_api.c +++ b/src/soc/mediatek/mt8192/dramc_pi_basic_api.c @@ -4096,6 +4096,191 @@ move_dramc_delay(cali, &ui_regs[idx], &mck_regs[idx], shift_ui); }
+static void shift_dq_oen_ui(const struct ddr_cali* cali, u8 rk) +{ + s8 shift_ui = -1; + u8 chn = cali->chn; + reg_transfer ui_regs[] = {{&ch[chn].ao.shu_rk[rk].shurk_selph_dq3, 16}, + {&ch[chn].ao.shu_rk[rk].shurk_selph_dq3, 20}, + {&ch[chn].ao.shu_rk[rk].shurk_selph_dq2, 16}, + {&ch[chn].ao.shu_rk[rk].shurk_selph_dq2, 20}}; + reg_transfer mck_regs[] = {{&ch[chn].ao.shu_rk[rk].shurk_selph_dq1, 16}, + {&ch[chn].ao.shu_rk[rk].shurk_selph_dq1, 20}, + {&ch[chn].ao.shu_rk[rk].shurk_selph_dq0, 16}, + {&ch[chn].ao.shu_rk[rk].shurk_selph_dq0, 20}}; + + for (u8 idx = 0; idx < ARRAY_SIZE(ui_regs); idx++) + move_dramc_delay(cali, &ui_regs[idx], &mck_regs[idx], shift_ui); +} + +static void shift_dqs_ui(const struct ddr_cali* cali, s8 shift_ui, u8 byte) +{ + u8 idx, step; + u8 chn = cali->chn; + + if (byte == 0) { + idx = 0; + step = 2; + } else if (byte == 1) { + idx = 1; + step = 2; + } else { + idx = 0; + step = 1; + } + + reg_transfer ui_regs[] = {{&ch[chn].ao.shu_selph_dqs1, 0}, + {&ch[chn].ao.shu_selph_dqs1, 4}}; + reg_transfer mck_regs[] = {{&ch[chn].ao.shu_selph_dqs0, 0}, + {&ch[chn].ao.shu_selph_dqs0, 4}}; + for (; idx < ARRAY_SIZE(ui_regs); idx += step) + move_dramc_delay(cali, &ui_regs[idx], &mck_regs[idx], shift_ui); +} + +static void shift_dqs_oen_ui(const struct ddr_cali* cali, s8 shift_ui, u8 byte) +{ + u8 idx, step; + u8 chn = cali->chn; + + if (byte == 0) { + idx = 0; + step = 2; + } else if (byte == 1) { + idx = 1; + step = 2; + } else { + idx = 0; + step = 1; + } + + reg_transfer ui_regs[] = {{&ch[chn].ao.shu_selph_dqs1, 16}, + {&ch[chn].ao.shu_selph_dqs1, 20}}; + reg_transfer mck_regs[] = {{&ch[chn].ao.shu_selph_dqs0, 16}, + {&ch[chn].ao.shu_selph_dqs0, 20}}; + for (; idx < ARRAY_SIZE(ui_regs); idx += step) + move_dramc_delay(cali, &ui_regs[idx], &mck_regs[idx], shift_ui); +} + +static void shift_dq_ui_all_rk(const struct ddr_cali* cali) +{ + s8 shift_ui = -1; + for (u8 rk = RANK_0; rk < cali->support_ranks; rk++) + shift_dq_ui(cali, rk, shift_ui); +} + +static void shift_dq_oen_ui_all_rk(const struct ddr_cali* cali) +{ + for (u8 rk = RANK_0; rk < cali->support_ranks; rk++) + shift_dq_oen_ui(cali, rk); +} + +static void shift_dqs_wck_ui(const struct ddr_cali* cali, s8 shift_ui, u8 byte) +{ + shift_dqs_ui(cali, shift_ui, byte); + shift_dqs_oen_ui(cali, shift_ui, byte); +} + +static void write_leveling_move_dqs_instead_of_clk(const struct ddr_cali* cali) +{ + s8 shift_ui = -1; + u8 chn = cali->chn; + + shift_dq_ui_all_rk(cali); + shift_dq_oen_ui_all_rk(cali); + shift_dqs_wck_ui(cali, shift_ui, BYTE_NUM); + + SET32_BITFIELDS(&ch[chn].phy_ao.byte[0].rk[0].shu_r0_b0_dq0, + SHU_R0_B0_DQ0_ARPI_PBYTE_B0, 0); + SET32_BITFIELDS(&ch[chn].phy_ao.byte[1].rk[0].shu_r0_b0_dq0, + SHU_R0_B1_DQ0_ARPI_PBYTE_B1, 0); +} + +static void set_dram_mr_write_leveling(const struct ddr_cali* cali, bool state) +{ + u8 chn = cali->chn; + u8 rank = cali->rank; + struct mr_values *mr_value = cali->mr_value; + u8 mr02 = mr_value->mr02[get_fsp(cali)]; + + if (state) + mr02 |= 0x80; + else + mr02 &= 0x7f; + + dramc_mode_reg_write_by_rank(cali, chn, rank, 2, mr02); +} + +void dramc_write_leveling(const struct ddr_cali* cali, u8 wl_dqs_final_delay[2][2]) +{ + s8 shift_ui; + u8 chn = cali->chn; + u8 rank = cali->rank; + u16 pi_bound; + + struct reg_bak regs_bak[] = { + {&ch[chn].ao.dramc_pd_ctrl}, + {&ch[chn].ao.cbt_wlev_ctrl0}, + {&ch[chn].ao.cbt_wlev_ctrl1}, + {&ch[chn].ao.cbt_wlev_ctrl3}, + {&ch[chn].ao.cbt_wlev_ctrl5}, + {&ch[chn].phy_ao.byte[0].shu_b0_vref}, + {&ch[chn].phy_ao.byte[1].shu_b0_vref}, + {&ch[chn].phy_ao.byte[0].rk[rank].shu_b0_phy_vref_sel}, + {&ch[chn].phy_ao.byte[1].rk[rank].shu_b0_phy_vref_sel}, + {&ch[chn].ao.dramc_pd_ctrl}, + }; + + if ((cali->freq_group == DDRFREQ_400) && (rank == RANK_1)) + return; + + if (cali->freq_group == DDRFREQ_400) + pi_bound = 32; + else + pi_bound = 64; + + wl_dqs_final_delay[rank][0] = cali->params->wr_level[chn][rank][0]; + wl_dqs_final_delay[rank][1] = cali->params->wr_level[chn][rank][1]; + dramc_dbg("WRITELEVELING DQS0:%d, DQS1:%d, pi_bound:%d\n", + wl_dqs_final_delay[rank][0], wl_dqs_final_delay[rank][1], pi_bound); + + dramc_auto_refresh_switch(chn, false); + + SET32_BITFIELDS(&ch[chn].ao.tx_set0, TX_SET0_TXRANK, rank); + SET32_BITFIELDS(&ch[chn].ao.tx_set0, TX_SET0_TXRANKFIX, 1); + + for (size_t i = 0; i < ARRAY_SIZE(regs_bak); i++) + regs_bak[i].value = read32(regs_bak[i].addr); + + if (rank == RANK_0) + write_leveling_move_dqs_instead_of_clk(cali); + + set_dram_mr_write_leveling(cali, false); + + SET32_BITFIELDS(&ch[chn].ao.cbt_wlev_ctrl0, CBT_WLEV_CTRL0_WRITE_LEVEL_EN, 0); + o1_path_on_off(cali, O1_OFF); + SET32_BITFIELDS(&ch[chn].ao.tx_set0, TX_SET0_TXRANK, 0); + SET32_BITFIELDS(&ch[chn].ao.tx_set0, TX_SET0_TXRANKFIX, 0); + + for (size_t i = 0; i < ARRAY_SIZE(regs_bak); i++) + write32(regs_bak[i].addr, regs_bak[i].value); + + for (u8 byte = 0; byte < BYTE_NUM; byte++) { + dramc_dbg("Write leveling (Byte %d): %d", byte, wl_dqs_final_delay[rank][byte]); + if (wl_dqs_final_delay[rank][byte] >= pi_bound) { + shift_ui = (wl_dqs_final_delay[rank][byte] / pi_bound) * (pi_bound / 32); + shift_dqs_wck_ui(cali, shift_ui, byte); + wl_dqs_final_delay[rank][byte] %= pi_bound; + } + dramc_dbg(" => %d\n", wl_dqs_final_delay[rank][byte]); + } + + for (u8 rk = rank; rk < RANK_MAX; rk++) { + SET32_BITFIELDS(&ch[chn].phy_ao.byte[0].rk[rk].shu_r0_b0_dq0, + SHU_R0_B0_DQ0_ARPI_PBYTE_B0, wl_dqs_final_delay[rank][0]); + SET32_BITFIELDS(&ch[chn].phy_ao.byte[1].rk[rk].shu_r0_b0_dq0, + SHU_R0_B1_DQ0_ARPI_PBYTE_B1, wl_dqs_final_delay[rank][1]); + } +} static void ddr_update_ac_timing(const struct ddr_cali *cali) { u8 table_idx; diff --git a/src/soc/mediatek/mt8192/dramc_pi_main.c b/src/soc/mediatek/mt8192/dramc_pi_main.c index 214bf55..2be3962 100644 --- a/src/soc/mediatek/mt8192/dramc_pi_main.c +++ b/src/soc/mediatek/mt8192/dramc_pi_main.c @@ -220,6 +220,8 @@
static void dramc_calibration_single_channel(struct ddr_cali *cali, u8 chn) { + u8 dqs_final_delay[RANK_MAX][DQS_NUMBER]; + cali->chn = chn; SET32_BITFIELDS(&ch[chn].phy_ao.ca_cmd2, CA_CMD2_RG_TX_ARCMD_OE_DIS_CA, 0, @@ -233,6 +235,15 @@ }
shuffle_dfs_to_fsp1(cali); + + for (u8 rank = RANK_0; rank < cali->support_ranks; rank++) { + cali->rank = rank; + dramc_dbg("Start K CH %d, RK %d\n", chn, rank); + + /* should disable the auto refresh before do write leveling */ + dramc_auto_refresh_switch(chn, false); + dramc_write_leveling(cali, dqs_final_delay); + } }
static void dramc_calibration_all_channels(struct ddr_cali *cali)