Hello Duan huayang,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/44718
to review the following change.
Change subject: soc/mediatek/mt8192: Do rx dqs gating training ......................................................................
soc/mediatek/mt8192: Do rx dqs gating training
Signed-off-by: Huayang Duan huayang.duan@mediatek.com Change-Id: I141abc1fdd283f4898d0772736bc777e87017561 --- M src/soc/mediatek/mt8192/dramc_pi_calibration_api.c M src/soc/mediatek/mt8192/dramc_pi_main.c 2 files changed, 323 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/18/44718/1
diff --git a/src/soc/mediatek/mt8192/dramc_pi_calibration_api.c b/src/soc/mediatek/mt8192/dramc_pi_calibration_api.c index e531de0..8d65a67 100644 --- a/src/soc/mediatek/mt8192/dramc_pi_calibration_api.c +++ b/src/soc/mediatek/mt8192/dramc_pi_calibration_api.c @@ -18,6 +18,15 @@ }, };
+struct rxdqs_gating_best_win { + u8 dqsien_dly_mck[DQS_NUMBER]; + u8 dqsien_dly_ui[DQS_NUMBER]; + u8 dqsien_dly_pi[DQS_NUMBER]; + u8 dqsien_dly_mck_p1[DQS_NUMBER]; + u8 dqsien_dly_ui_p1[DQS_NUMBER]; + u8 dqsien_dly_pi_p1[DQS_NUMBER]; +}; + static const u8 imp_vref_sel[ODT_MAX][IMP_DRV_MAX] = { /* DRVP DRVN ODTP ODTN */ [ODT_OFF] = {0x37, 0x33, 0x00, 0x37}, @@ -1378,3 +1387,311 @@
dramc_set_broadcast(bc_bak); } + +static u8 rxdqs_gating_get_tx_dly_min(dram_freq_grp freq_group, + struct rxdqs_gating_best_win *rxdqs_best_win) +{ + u8 tx_dly_dqs_gated = 0, tx_dly_min = 0xff; + + for (u8 dqs = 0; dqs < DQS_NUMBER; dqs++) { + dramc_dbg("best DQS%d dly(MCK, UI, PI) = (%d, %d, %d)\n", dqs, + rxdqs_best_win->dqsien_dly_mck[dqs], + rxdqs_best_win->dqsien_dly_ui[dqs], + rxdqs_best_win->dqsien_dly_pi[dqs]); + + tx_dly_dqs_gated = (rxdqs_best_win->dqsien_dly_mck[dqs] << 4) + + rxdqs_best_win->dqsien_dly_ui[dqs]; + + if (freq_group != DDRFREQ_400) + tx_dly_dqs_gated >>= 3; + else + tx_dly_dqs_gated >>= 2; + + if (tx_dly_dqs_gated < tx_dly_min) + tx_dly_min = tx_dly_dqs_gated; + } + return tx_dly_min; +} + +static u8 rxdqs_gating_get_tx_dly_max(dram_freq_grp freq_group, + struct rxdqs_gating_best_win *rxdqs_best_win) +{ + u8 tx_dly_dqs_gated = 0, tx_dly_max = 0; + + for (u8 dqs = 0; dqs < DQS_NUMBER; dqs++) { + dramc_dbg("best DQS%d P1 dly(MCK, UI, PI) = (%d, %d, %d)\n", dqs, + rxdqs_best_win->dqsien_dly_mck_p1[dqs], + rxdqs_best_win->dqsien_dly_ui_p1[dqs], + rxdqs_best_win->dqsien_dly_pi_p1[dqs]); + + tx_dly_dqs_gated = (rxdqs_best_win->dqsien_dly_mck_p1[dqs] << 4) + + rxdqs_best_win->dqsien_dly_ui_p1[dqs]; + + if (freq_group != DDRFREQ_400) + tx_dly_dqs_gated >>= 3; + else + tx_dly_dqs_gated >>= 2; + + if (tx_dly_dqs_gated > tx_dly_max) + tx_dly_max = tx_dly_dqs_gated; + } + return tx_dly_max; +} + +void dramc_rx_dqs_gating_cal(const struct ddr_cali* cali, + u8 *tx_dly_min, u8 *tx_dly_max) +{ + u8 chn, rank; + u8 pi_per_ui, ui_per_mck, freq_div; + dram_freq_grp freq_group; + struct rxdqs_gating_best_win best_win = {0}; + const struct sdram_params *params = cali->params; + + chn = cali->chn; + rank = cali->rank; + freq_group = get_freq_group(cali); + + struct reg_bak regs_bak[] = { + {&ch[chn].ao.refctrl0}, + {&ch[chn].phy_ao.dvs_b[0].b0_dq6}, + {&ch[chn].phy_ao.dvs_b[1].b0_dq6}, + {&ch[chn].phy_ao.misc_stbcal1}, + {&ch[chn].phy_ao.misc_stbcal2}, + }; + for (size_t i = 0; i < ARRAY_SIZE(regs_bak); i++) + regs_bak[i].value = read32(regs_bak[i].addr); + + pi_per_ui = 32; + ui_per_mck = 16; + if (get_div_mode(cali) == DIV4_MODE) + freq_div = 2; + else + freq_div = 4; + + for (u8 dqs = 0; dqs < DQS_NUMBER; dqs++) { + best_win.dqsien_dly_mck[dqs] = params->gating_MCK[chn][rank][dqs]; + best_win.dqsien_dly_ui[dqs] = params->gating_UI[chn][rank][dqs]; + best_win.dqsien_dly_pi[dqs] = params->gating_PI[chn][rank][dqs]; + + /* Calculate P1 */ + best_win.dqsien_dly_ui_p1[dqs] = + best_win.dqsien_dly_mck[dqs] * ui_per_mck + + best_win.dqsien_dly_ui[dqs] + freq_div; + best_win.dqsien_dly_mck_p1[dqs] = + best_win.dqsien_dly_ui_p1[dqs] / ui_per_mck; + best_win.dqsien_dly_ui_p1[dqs] = + best_win.dqsien_dly_ui_p1[dqs] % ui_per_mck; + dramc_dbg("[FAST_K] CH%d RK%d best DQS%d dly(MCK, UI, PI) = (%d, %d, %d)\n", + chn, rank, dqs, best_win.dqsien_dly_mck[dqs], + best_win.dqsien_dly_ui[dqs], + best_win.dqsien_dly_pi[dqs]); + dramc_dbg("[FAST_K] CH%d RK%d best DQS%d P1 dly(MCK, UI, PI) = (%d, %d, %d)\n", + chn, rank, dqs, best_win.dqsien_dly_mck_p1[dqs], + best_win.dqsien_dly_ui_p1[dqs], + best_win.dqsien_dly_pi_p1[dqs]); + } + + *tx_dly_min = rxdqs_gating_get_tx_dly_min(freq_group, &best_win); + *tx_dly_max = rxdqs_gating_get_tx_dly_max(freq_group, &best_win); + + SET32_BITFIELDS(&ch[chn].phy_ao.byte[0].rk[rank].shu_dqsien_mck_ui_dly, + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P0_B0, best_win.dqsien_dly_mck[0], + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P0_B0, best_win.dqsien_dly_ui[0], + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P1_B0, best_win.dqsien_dly_mck_p1[0], + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P1_B0, best_win.dqsien_dly_ui_p1[0]); + SET32_BITFIELDS(&ch[chn].phy_ao.byte[1].rk[rank].shu_dqsien_mck_ui_dly, + SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P0_B1, best_win.dqsien_dly_mck[1], + SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P0_B1, best_win.dqsien_dly_ui[1], + SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P1_B1, best_win.dqsien_dly_mck_p1[1], + SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P1_B1, best_win.dqsien_dly_ui_p1[1]); + SET32_BITFIELDS(&ch[chn].phy_ao.byte[0].rk[rank].shu_rk_b0_dqsien_pi_dly, + SHU_RK_B0_DQSIEN_PI_DLY_DQSIEN_PI_B0, best_win.dqsien_dly_pi[0]); + SET32_BITFIELDS(&ch[chn].phy_ao.byte[1].rk[rank].shu_rk_b0_dqsien_pi_dly, + SHU_RK_B1_DQSIEN_PI_DLY_DQSIEN_PI_B1, best_win.dqsien_dly_pi[1]); + + for (size_t i = 0; i < ARRAY_SIZE(regs_bak); i++) + write32(regs_bak[i].addr, regs_bak[i].value); + + dramc_phy_reset(chn); +} + +static void dramc_rx_dqs_gating_post_process_find_best_coarse( + const struct ddr_cali* cali, s8 change_dqs_inctl, u8 mck2ui_shift) +{ + u8 chn, rk; + u8 best_coarse_mck[RANK_MAX][DQS_NUMBER]; + u8 best_coarse_ui[RANK_MAX][DQS_NUMBER]; + u8 best_coarse_mck_P1[RANK_MAX][DQS_NUMBER]; + u8 best_coarse_ui_P1[RANK_MAX][DQS_NUMBER]; + u32 rank_sel_mck_p0[2], rank_sel_mck_p1[2]; + + chn = cali->chn; + for (rk = 0; rk < cali->support_ranks; rk++) { + best_coarse_mck[rk][0] = + READ32_BITFIELD(&ch[chn].phy_ao.byte[0].rk[rk].shu_dqsien_mck_ui_dly, + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P0_B0); + best_coarse_ui[rk][0] = + READ32_BITFIELD(&ch[chn].phy_ao.byte[0].rk[rk].shu_dqsien_mck_ui_dly, + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P0_B0); + best_coarse_mck_P1[rk][0] = + READ32_BITFIELD(&ch[chn].phy_ao.byte[0].rk[rk].shu_dqsien_mck_ui_dly, + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P1_B0); + best_coarse_ui_P1[rk][0] = + READ32_BITFIELD(&ch[chn].phy_ao.byte[0].rk[rk].shu_dqsien_mck_ui_dly, + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P1_B0); + + best_coarse_mck[rk][1] = + READ32_BITFIELD(&ch[chn].phy_ao.byte[1].rk[rk].shu_dqsien_mck_ui_dly, + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P0_B0); + best_coarse_ui[rk][1] = + READ32_BITFIELD(&ch[chn].phy_ao.byte[1].rk[rk].shu_dqsien_mck_ui_dly, + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P0_B0); + best_coarse_mck_P1[rk][1] = + READ32_BITFIELD(&ch[chn].phy_ao.byte[1].rk[rk].shu_dqsien_mck_ui_dly, + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P1_B0); + best_coarse_ui_P1[rk][1] = + READ32_BITFIELD(&ch[chn].phy_ao.byte[1].rk[rk].shu_dqsien_mck_ui_dly, + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P1_B0); + } + + if (change_dqs_inctl != 0) { + for (rk = 0; rk < cali->support_ranks; rk++) { + for (u8 dqs = 0; dqs < DQS_NUMBER; dqs++) { + u8 total_ui, total_ui_P1; + total_ui = (best_coarse_mck[rk][dqs] << 4) + + best_coarse_ui[rk][dqs]; + total_ui_P1 = (best_coarse_mck_P1[rk][dqs] << 4) + + best_coarse_ui_P1[rk][dqs]; + + total_ui += (change_dqs_inctl << mck2ui_shift); + total_ui_P1 += (change_dqs_inctl << mck2ui_shift); + + best_coarse_mck[rk][dqs] = (total_ui >> 4); + best_coarse_ui[rk][dqs] = total_ui & 0xf; + + best_coarse_mck_P1[rk][dqs] = (total_ui_P1 >> 4); + best_coarse_ui_P1[rk][dqs] = total_ui_P1 & 0xf; + dramc_dbg("best DQS%d dly(2T, 0.5T) = (%d, %d)\n", + dqs, best_coarse_mck[rk][dqs], + best_coarse_ui[rk][dqs]); + } + for (u8 dqs = 0; dqs < DQS_NUMBER; dqs++) + dramc_dbg("best DQS%d P1 dly(2T, 0.5T) = (%d, %d)\n", + dqs, best_coarse_mck_P1[rk][dqs], + best_coarse_ui_P1[rk][dqs]); + } + + for (rk = 0; rk < cali->support_ranks; rk++) { + SET32_BITFIELDS(&ch[chn].phy_ao.byte[0].rk[rk].shu_dqsien_mck_ui_dly, + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P0_B0, + best_coarse_mck[rk][0], + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P0_B0, + best_coarse_ui[rk][0], + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P1_B0, + best_coarse_mck_P1[rk][0], + SHU_RK_B0_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P1_B0, + best_coarse_ui_P1[rk][0]); + SET32_BITFIELDS(&ch[chn].phy_ao.byte[1].rk[rk].shu_dqsien_mck_ui_dly, + SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P0_B1, + best_coarse_mck[rk][1], + SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P0_B1, + best_coarse_ui[rk][1], + SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_MCK_P1_B1, + best_coarse_mck_P1[rk][1], + SHU_RK_B1_DQSIEN_MCK_UI_DLY_DQSIEN_UI_P1_B1, + best_coarse_ui_P1[rk][1]); + } + } + + for (u8 dqs = 0; dqs < DQS_NUMBER; dqs++) { + if (best_coarse_mck[RANK_0][dqs] > best_coarse_mck[RANK_1][dqs]) { + rank_sel_mck_p0[dqs] = (best_coarse_mck[RANK_0][dqs] > 0) ? + (best_coarse_mck[RANK_0][dqs] - 1) : 0; + rank_sel_mck_p1[dqs] = (best_coarse_mck_P1[RANK_0][dqs] > 0) ? + (best_coarse_mck_P1[RANK_0][dqs] - 1) : 0; + } else { + rank_sel_mck_p0[dqs] = (best_coarse_mck[RANK_1][dqs] > 0) ? + (best_coarse_mck[RANK_1][dqs] - 1) : 0; + rank_sel_mck_p1[dqs] = (best_coarse_mck_P1[RANK_1][dqs] > 0) ? + (best_coarse_mck_P1[RANK_1][dqs] - 1) : 0; + } + } + + SET32_BITFIELDS(&ch[chn].phy_ao.byte[0].shu_b0_rank_selph_ui_dly, + SHU_B0_RANK_SELPH_UI_DLY_RANKSEL_MCK_DLY_P0_B0, rank_sel_mck_p0[0], + SHU_B0_RANK_SELPH_UI_DLY_RANKSEL_MCK_DLY_P1_B0, rank_sel_mck_p1[0]); + SET32_BITFIELDS(&ch[chn].phy_ao.byte[1].shu_b0_rank_selph_ui_dly, + SHU_B1_RANK_SELPH_UI_DLY_RANKSEL_MCK_DLY_P0_B1, rank_sel_mck_p0[1], + SHU_B1_RANK_SELPH_UI_DLY_RANKSEL_MCK_DLY_P1_B1, rank_sel_mck_p1[1]); +} + +void dramc_rx_dqs_gating_post_process(const struct ddr_cali* cali, + u8 tx_dly_min, u8 tx_dly_max) +{ + u8 chn, rank; + dram_freq_grp freq_group; + + u8 mck2ui_shift; + s8 change_dqs_inctl; + u16 phs_inctl = 0; + u32 read_dqs_inctl, rank_inctl_root, xrtr2r, tx_dly_dqs_gate_min = 0; + u32 rank_inctl_stb; + + chn = cali->chn; + rank = cali->rank; + freq_group = get_freq_group(cali); + + if (get_div_mode(cali) == DIV8_MODE) { + if (freq_group > DDRFREQ_1200) + tx_dly_dqs_gate_min = 2; + else + tx_dly_dqs_gate_min = 1; + mck2ui_shift = 3; + } else { + tx_dly_dqs_gate_min = 2; + mck2ui_shift = 2; + } + + change_dqs_inctl = tx_dly_dqs_gate_min - tx_dly_min; + dramc_dbg("[RxdqsGatingPostProcess] freq %d\n" + "ChangeDQSINCTL %d, tx_dly_dqs_gate_min %d, tx_dly_min %d\n", + get_frequency(cali), + change_dqs_inctl, tx_dly_dqs_gate_min, tx_dly_min); + + dramc_rx_dqs_gating_post_process_find_best_coarse(cali, change_dqs_inctl, mck2ui_shift); + + read_dqs_inctl = READ32_BITFIELD(&ch[chn].phy_ao.misc_rk[rank].misc_shu_rk_dqsctl, + MISC_SHU_RK_DQSCTL_DQSINCTL); + read_dqs_inctl -= change_dqs_inctl; + rank_inctl_stb = (read_dqs_inctl > 2) ? (read_dqs_inctl - 2) : 0; + phs_inctl = (read_dqs_inctl == 0) ? 0 : (read_dqs_inctl - 1); + SET32_BITFIELDS(&ch[chn].phy_ao.misc_shu_rankctl, + MISC_SHU_RANKCTL_RANKINCTL_STB, rank_inctl_stb); + SET32_BITFIELDS(&ch[chn].phy_ao.shu_misc_rank_sel_stb, + SHU_MISC_RANK_SEL_STB_RANK_SEL_PHSINCTL, phs_inctl); + + if (read_dqs_inctl >= 2) + rank_inctl_root = read_dqs_inctl - 2; + else + rank_inctl_root = 0; + + SET32_BITFIELDS(&ch[chn].phy_ao.misc_rk[0].misc_shu_rk_dqsctl, + MISC_SHU_RK_DQSCTL_DQSINCTL, read_dqs_inctl); + SET32_BITFIELDS(&ch[chn].phy_ao.misc_rk[1].misc_shu_rk_dqsctl, + MISC_SHU_RK_DQSCTL_DQSINCTL, read_dqs_inctl); + SET32_BITFIELDS(&ch[chn].phy_ao.misc_shu_rankctl, + MISC_SHU_RANKCTL_RANKINCTL_PHY, read_dqs_inctl); + SET32_BITFIELDS(&ch[chn].phy_ao.misc_shu_rankctl, + MISC_SHU_RANKCTL_RANKINCTL, rank_inctl_root); + SET32_BITFIELDS(&ch[chn].phy_ao.misc_shu_rankctl, + MISC_SHU_RANKCTL_RANKINCTL_ROOT1, rank_inctl_root); + SET32_BITFIELDS(&ch[chn].phy_ao.misc_shu_rankctl, + MISC_SHU_RANKCTL_RANKINCTL_RXDLY, rank_inctl_root); + xrtr2r = READ32_BITFIELD(&ch[chn].ao.shu_actim_xrt, + SHU_ACTIM_XRT_XRTR2R); + dramc_dbg("TX_dly_DQSgated check: min %d max %d, ChangeDQSINCTL=%d\n", + tx_dly_min, tx_dly_max, change_dqs_inctl); + dramc_dbg("DQSINCTL=%d, RANKINCTL=%d, xrtr2r=%d\n", + read_dqs_inctl, rank_inctl_root, xrtr2r); +} + diff --git a/src/soc/mediatek/mt8192/dramc_pi_main.c b/src/soc/mediatek/mt8192/dramc_pi_main.c index 2be3962..4b77c85 100644 --- a/src/soc/mediatek/mt8192/dramc_pi_main.c +++ b/src/soc/mediatek/mt8192/dramc_pi_main.c @@ -220,6 +220,7 @@
static void dramc_calibration_single_channel(struct ddr_cali *cali, u8 chn) { + u8 txdly_min, txdly_max; u8 dqs_final_delay[RANK_MAX][DQS_NUMBER];
cali->chn = chn; @@ -243,7 +244,12 @@ /* should disable the auto refresh before do write leveling */ dramc_auto_refresh_switch(chn, false); dramc_write_leveling(cali, dqs_final_delay); + + /* should enable the auto refresh before do RX and TX calibration */ + dramc_auto_refresh_switch(chn, true); + dramc_rx_dqs_gating_cal(cali, &txdly_min, &txdly_max); } + dramc_rx_dqs_gating_post_process(cali, txdly_min, txdly_max); }
static void dramc_calibration_all_channels(struct ddr_cali *cali)