Hello Duan huayang,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/44719
to review the following change.
Change subject: soc/mediatek/mt8192: Do dramc rx window training ......................................................................
soc/mediatek/mt8192: Do dramc rx window training
Signed-off-by: Huayang Duan huayang.duan@mediatek.com Change-Id: I584db990a9777551bcf3d4d59cdd3fd64d6e52cc --- M src/soc/mediatek/mt8192/dramc_pi_calibration_api.c M src/soc/mediatek/mt8192/dramc_pi_main.c 2 files changed, 264 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/19/44719/1
diff --git a/src/soc/mediatek/mt8192/dramc_pi_calibration_api.c b/src/soc/mediatek/mt8192/dramc_pi_calibration_api.c index 8d65a67..363a3bd 100644 --- a/src/soc/mediatek/mt8192/dramc_pi_calibration_api.c +++ b/src/soc/mediatek/mt8192/dramc_pi_calibration_api.c @@ -27,6 +27,15 @@ u8 dqsien_dly_pi_p1[DQS_NUMBER]; };
+typedef struct { + s16 first_pass; + s16 last_pass; + s16 win_center; + u16 win_size; + u16 best_dqdly; +} pass_win_data_t; + + static const u8 imp_vref_sel[ODT_MAX][IMP_DRV_MAX] = { /* DRVP DRVN ODTP ODTN */ [ODT_OFF] = {0x37, 0x33, 0x00, 0x37}, @@ -1695,3 +1704,255 @@ read_dqs_inctl, rank_inctl_root, xrtr2r); }
+ +static void dramc_set_rank_engin2(u8 chn, u8 rank) +{ + SET32_BITFIELDS(&ch[chn].ao.test2_a3, TEST2_A3_ADRDECEN_TARKMODE, 1); + SET32_BITFIELDS(&ch[chn].ao.test2_a4, TEST2_A4_TESTAGENTRKSEL, 0); + SET32_BITFIELDS(&ch[chn].ao.test2_a4, TEST2_A4_TESTAGENTRK, rank); +} + +static void dramc_engin2_set_ui_shift(u8 chn) +{ + SET32_BITFIELDS(&ch[chn].ao.test2_a0, + TEST2_A0_TA2_LOOP_EN, 1, + TEST2_A0_LOOP_CNT_INDEX, 3); + SET32_BITFIELDS(&ch[chn].ao.test2_a3, + TEST2_A3_TEST2_PAT_SHIFT, 1, + TEST2_A3_PAT_SHIFT_SW_EN, 0); +} + +static void dramc_engin2_set_pat(u8 chn, u8 rank, u8 loop_cnt) +{ + SET32_BITFIELDS(&ch[chn].ao.test2_a4, + TEST2_A4_TEST_REQ_LEN1, 1, + TEST2_A4_TESTAUDINIT, 0, + TEST2_A4_TESTAUDINC, 0, + TEST2_A4_TESTXTALKPAT, 0, + TEST2_A4_TESTSSOPAT, 0); + SET32_BITFIELDS(&ch[chn].ao.test2_a3, + TEST2_A3_TESTAUDPAT, 0, + TEST2_A3_AUTO_GEN_PAT, 1, + TEST2_A3_HFIDPAT, 1, + TEST2_A3_TEST_AID_EN, 1, + TEST2_A3_TESTCNT, loop_cnt); + SET32_BITFIELDS(&ch[chn].ao.test2_a2, TEST2_A2_TEST2_OFF, 0x56); + dramc_engin2_set_ui_shift(chn); +} + +static void dramc_engine2_init(u8 chn, u8 rank) +{ + u32 test2_1 = 0x55000000; + u32 test2_2 = 0xaa000100; + + dramc_set_rank_engin2(chn, rank); + SET32_BITFIELDS(&ch[chn].ao.dummy_rd, + DUMMY_RD_DQSG_DMYRD_EN, 0, + DUMMY_RD_DQSG_DMYWR_EN, 0, + DUMMY_RD_DUMMY_RD_EN, 0, + DUMMY_RD_SREF_DMYRD_EN, 0, + DUMMY_RD_DMY_RD_DBG, 0, + DUMMY_RD_DMY_WR_DBG, 0); + SET32_BITFIELDS(&ch[chn].ao.test2_a3, + TEST2_A3_TEST2W, 0, + TEST2_A3_TEST2R, 0, + TEST2_A3_TEST1, 0); + SET32_BITFIELDS(&ch[chn].ao.test2_a0, + TEST2_A0_TEST2_PAT0, test2_1 >> 24, + TEST2_A0_TEST2_PAT1, test2_2 >> 24); + SET32_BITFIELDS(&ch[chn].ao.rk[rank].rk_test2_a1, + RK_TEST2_A1_TEST2_BASE, (test2_1 + 0x10000) & 0x00ffffff); + SET32_BITFIELDS(&ch[chn].ao.test2_a2, TEST2_A2_TEST2_OFF, test2_2 & 0x00ffffff); + + dramc_engin2_set_pat(chn, rank, 0); +} + +static const u8 uiLPDDR4_RDDQC_Mapping_POP[PINMUX_MAX][CHANNEL_MAX][DQ_DATA_WIDTH] = +{ + [PINMUX_DSC] = { + [CHANNEL_A] = { 0, 1, 6, 7, 4, 5, 3, 2, 9, 8, 11, 10, 15, 14, 12, 13}, + [CHANNEL_B] = { 1, 0, 5, 4, 7, 2, 3, 6, 8, 9, 11, 10, 12, 14, 13, 15}, + }, + [PINMUX_LPBK] = { + }, + [PINMUX_EMCP] = { + [CHANNEL_A] = {1, 0, 3, 2, 4, 7, 6, 5, 8, 9, 10, 12, 15, 14, 11, 13}, + [CHANNEL_B] = {0, 1, 7, 4, 2, 5, 6, 3, 9, 8, 10, 12, 11, 14, 13, 15}, + } +}; + +static void rddqc_pinmux_set(const struct ddr_cali* cali) +{ + u8 chn = cali->chn; + u8 pinmux = get_pinmux_type(cali); + + const u8 *pinmux_map = uiLPDDR4_RDDQC_Mapping_POP[pinmux][chn]; + + SET32_BITFIELDS(&ch[chn].ao.mrr_bit_mux1, + MRR_BIT_MUX1_MRR_BIT0_SEL, pinmux_map[0], + MRR_BIT_MUX1_MRR_BIT1_SEL, pinmux_map[1], + MRR_BIT_MUX1_MRR_BIT2_SEL, pinmux_map[2], + MRR_BIT_MUX1_MRR_BIT3_SEL, pinmux_map[3]); + SET32_BITFIELDS(&ch[chn].ao.mrr_bit_mux2, + MRR_BIT_MUX2_MRR_BIT4_SEL, pinmux_map[4], + MRR_BIT_MUX2_MRR_BIT5_SEL, pinmux_map[5], + MRR_BIT_MUX2_MRR_BIT6_SEL, pinmux_map[6], + MRR_BIT_MUX2_MRR_BIT7_SEL, pinmux_map[7]); + SET32_BITFIELDS(&ch[chn].ao.mrr_bit_mux3, + MRR_BIT_MUX3_MRR_BIT8_SEL, pinmux_map[8], + MRR_BIT_MUX3_MRR_BIT9_SEL, pinmux_map[9], + MRR_BIT_MUX3_MRR_BIT10_SEL, pinmux_map[10], + MRR_BIT_MUX3_MRR_BIT11_SEL, pinmux_map[11]); + SET32_BITFIELDS(&ch[chn].ao.mrr_bit_mux4, + MRR_BIT_MUX4_MRR_BIT12_SEL, pinmux_map[12], + MRR_BIT_MUX4_MRR_BIT13_SEL, pinmux_map[13], + MRR_BIT_MUX4_MRR_BIT14_SEL, pinmux_map[14], + MRR_BIT_MUX4_MRR_BIT15_SEL, pinmux_map[15]); +} + +static void dramc_rx_rddqc_init(const struct ddr_cali* cali) +{ + u8 rddqc_bit_ctrl_lower = 0x55; + u8 rddqc_bit_ctrl_upper = 0x55; + u8 rddqc_patternA = 0x5A; + u8 rddqc_patternB = 0x3C; + + u8 chn = cali->chn; + u8 rank = cali->rank; + + SET32_BITFIELDS(&ch[chn].phy_ao.byte[0].shu_b0_dq7, + SHU_B0_DQ7_R_DMDQMDBI_SHU_B0, 0); + SET32_BITFIELDS(&ch[chn].phy_ao.byte[1].shu_b0_dq7, + SHU_B1_DQ7_R_DMDQMDBI_SHU_B1, 0); + + SET32_BITFIELDS(&ch[chn].ao.swcmd_ctrl0, SWCMD_CTRL0_MRSRK, rank); + rddqc_pinmux_set(cali); + dramc_mode_reg_write_by_rank(cali, chn, rank, 15, rddqc_bit_ctrl_lower); + dramc_mode_reg_write_by_rank(cali, chn, rank, 20, rddqc_bit_ctrl_upper); + dramc_mode_reg_write_by_rank(cali, chn, rank, 32, rddqc_patternA); + dramc_mode_reg_write_by_rank(cali, chn, rank, 40, rddqc_patternB); + + SET32_BITFIELDS(&ch[chn].ao.rddqcgolden, + RDDQCGOLDEN_MR15_GOLDEN, rddqc_bit_ctrl_lower, + RDDQCGOLDEN_MR20_GOLDEN, rddqc_bit_ctrl_upper, + RDDQCGOLDEN_MR32_GOLDEN, rddqc_patternA, + RDDQCGOLDEN_MR40_GOLDEN, rddqc_patternB); + + SET32_BITFIELDS(&ch[chn].phy_ao.byte[0].shu_b0_dq8, + SHU_B0_DQ8_R_DMRXDLY_CG_IG_B0, 1); + SET32_BITFIELDS(&ch[chn].phy_ao.byte[1].shu_b0_dq8, + SHU_B1_DQ8_R_DMRXDLY_CG_IG_B1, 1); +} +void dramc_rx_window_perbit_cal(const struct ddr_cali* cali, rx_cali_type cali_type) +{ + u8 chn, rank, fsp; + dram_odt_state odt; + dram_freq_grp freq_group = cali->freq_group; + const struct sdram_params *params = cali->params; + + u8 bit, byte; + bool enable_vref_scan = false; + u16 final_vref[DQS_NUMBER] = {0xe, 0xe}; + pass_win_data_t final_win_perbit[DQ_DATA_WIDTH]; + s32 dqs_dly_perbyte[DQS_NUMBER] = {0x0}, dqm_dly_perbyte[DQS_NUMBER] = {0x0}; + + chn = cali->chn; + rank = cali->rank; + fsp = get_fsp(cali); + odt = get_odt_state(cali); + dramc_dbg("RX window ch:%d, rank:%d, freq_group:%d, type:%d\n", + chn, rank, freq_group, cali_type); + + struct reg_bak regs_bak[] = { + {&ch[chn].ao.mrr_bit_mux1}, + {&ch[chn].ao.mrr_bit_mux2}, + {&ch[chn].ao.mrr_bit_mux3}, + {&ch[chn].ao.mrr_bit_mux4}, + }; + for (size_t i = 0; i < ARRAY_SIZE(regs_bak); i++) + regs_bak[i].value = read32(regs_bak[i].addr); + + dramc_auto_refresh_switch(chn, false); + + if (cali_type == RX_WIN_TEST_ENG) { + dramc_engine2_init(chn, rank); + + if ((rank == RANK_0) || (freq_group == DDRFREQ_2133)) + enable_vref_scan = true; + } else { + dramc_rx_rddqc_init(cali); + } + + if (enable_vref_scan) { + SET32_BITFIELDS(&ch[chn].phy_ao.dvs_b[0].b0_dq5, + B0_DQ5_RG_RX_ARDQ_VREF_EN_B0, 1); + SET32_BITFIELDS(&ch[chn].phy_ao.dvs_b[1].b0_dq5, + B1_DQ5_RG_RX_ARDQ_VREF_EN_B1, 1); + } + + for (byte = 0; byte < BYTE_NUM; byte++) { + if (enable_vref_scan) + final_vref[byte] = params->rx_best_vref[chn][rank][byte]; + + dqs_dly_perbyte[byte] = params->rx_perbit_dqs[chn][rank][byte]; + dqm_dly_perbyte[byte] = params->rx_perbit_dqm[chn][rank][byte]; + } + + for (bit = 0; bit < DQ_DATA_WIDTH; bit++) + final_win_perbit[bit].best_dqdly = params->rx_perbit_dq[chn][rank][bit]; + + if (enable_vref_scan) { + for (u8 rk = rank; rk < cali->support_ranks; rk++) { + SET32_BITFIELDS(&ch[chn].phy_ao.byte[0].rk[rk].shu_b0_phy_vref_sel, + RG_RX_ARDQ_VREF_SEL_LB_B0, final_vref[0], + RG_RX_ARDQ_VREF_SEL_UB_B0, final_vref[0]); + SET32_BITFIELDS(&ch[chn].phy_ao.byte[1].rk[rk].shu_b0_phy_vref_sel, + RG_RX_ARDQ_VREF_SEL_LB_B1, final_vref[1], + RG_RX_ARDQ_VREF_SEL_UB_B1, final_vref[1]); + + for (byte = 0; byte < BYTE_NUM; byte++) { + dramc_dbg("Final RX Vref Byte %d = %d to rank%d\n", + byte, final_vref[byte], rk); + } + } + } + + /* set dqs delay, (dqm delay) */ + SET32_BITFIELDS(&ch[chn].phy_ao.byte[0].rk[rank].shu_r0_b0_rxdly5, + SHU_R0_B0_RXDLY5_RX_ARDQS0_R_DLY_B0, dqs_dly_perbyte[0]); + SET32_BITFIELDS(&ch[chn].phy_ao.byte[0].rk[rank].shu_r0_b0_rxdly4, + SHU_R0_B0_RXDLY4_RX_ARDQM0_R_DLY_B0, dqm_dly_perbyte[0]); + SET32_BITFIELDS(&ch[chn].phy_ao.byte[1].rk[rank].shu_r0_b0_rxdly5, + SHU_R0_B1_RXDLY5_RX_ARDQS0_R_DLY_B1, dqs_dly_perbyte[1]); + SET32_BITFIELDS(&ch[chn].phy_ao.byte[1].rk[rank].shu_r0_b0_rxdly4, + SHU_R0_B1_RXDLY4_RX_ARDQM0_R_DLY_B1, dqm_dly_perbyte[1]); + + /* set dq delay */ + for (bit = 0; bit < DQS_BIT_NUMBER; bit += 2) { + SET32_BITFIELDS(&ch[chn].phy_ao.byte[0].rk[rank].shu_r0_b0_rxdly0 + bit / 2, + SHU_R0_B0_RXDLY0_RX_ARDQ0_R_DLY_B0, final_win_perbit[bit].best_dqdly, + SHU_R0_B0_RXDLY0_RX_ARDQ1_R_DLY_B0, final_win_perbit[bit + 1].best_dqdly); + + SET32_BITFIELDS(&ch[chn].phy_ao.byte[1].rk[rank].shu_r0_b0_rxdly0 + bit / 2, + SHU_R0_B1_RXDLY0_RX_ARDQ0_R_DLY_B1, final_win_perbit[bit + 8].best_dqdly, + SHU_R0_B1_RXDLY0_RX_ARDQ1_R_DLY_B1, final_win_perbit[bit + 9].best_dqdly); + } + + dramc_phy_reset(chn); + + for (size_t i = 0; i < ARRAY_SIZE(regs_bak); i++) + write32(regs_bak[i].addr, regs_bak[i].value); + + dramc_dbg("DQS Delay:\nDQS0 = %d, DQS1 = %d\n" + "DQM Delay:\nDQM0 = %d, DQM1 = %d\n", + dqs_dly_perbyte[0], dqs_dly_perbyte[1], + dqm_dly_perbyte[0], dqm_dly_perbyte[1]); + + dramc_dbg("DQ Delay:\n"); + for (bit = 0; bit < DQ_DATA_WIDTH; bit = bit + 4) + dramc_dbg("DQ%d =%d, DQ%d =%d, DQ%d =%d, DQ%d =%d\n", + bit, final_win_perbit[bit].best_dqdly, + bit + 1, final_win_perbit[bit + 1].best_dqdly, + bit + 2, final_win_perbit[bit + 2].best_dqdly, + bit + 3, final_win_perbit[bit + 3].best_dqdly); +} diff --git a/src/soc/mediatek/mt8192/dramc_pi_main.c b/src/soc/mediatek/mt8192/dramc_pi_main.c index 4b77c85..41d85a2 100644 --- a/src/soc/mediatek/mt8192/dramc_pi_main.c +++ b/src/soc/mediatek/mt8192/dramc_pi_main.c @@ -248,6 +248,9 @@ /* 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_window_perbit_cal(cali, RX_WIN_RD_DQC); + dramc_rx_window_perbit_cal(cali, RX_WIN_TEST_ENG); } dramc_rx_dqs_gating_post_process(cali, txdly_min, txdly_max); }