diff options
author | Huayang Duan <huayang.duan@mediatek.com> | 2018-09-26 17:39:29 +0800 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2018-12-11 08:57:16 +0000 |
commit | 2b5067b2c70bf0e0a995b6e33485a8ac15268cbc (patch) | |
tree | 75ba50d1d2efe7767dd36cdd47d09c5de958f1f2 /src/soc/mediatek | |
parent | 0655761b67d515fbe44ec5b31c3e58167d5f2b4e (diff) |
mediatek/mt8183: Add DDR driver of tx rx window perbit cal part
BUG=b:80501386
BRANCH=none
TEST=Boots correctly on Kukui, and inits DRAM successfully with related
patches.
Change-Id: I4434897864993e254e1362416316470083351493
Signed-off-by: Huayang Duan <huayang.duan@mediatek.com>
Reviewed-on: https://review.coreboot.org/c/28842
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: You-Cheng Syu <youcheng@google.com>
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Diffstat (limited to 'src/soc/mediatek')
-rw-r--r-- | src/soc/mediatek/mt8183/dramc_pi_calibration_api.c | 922 | ||||
-rw-r--r-- | src/soc/mediatek/mt8183/emi.c | 2 | ||||
-rw-r--r-- | src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h | 24 | ||||
-rw-r--r-- | src/soc/mediatek/mt8183/include/soc/dramc_register.h | 2 | ||||
-rw-r--r-- | src/soc/mediatek/mt8183/include/soc/emi.h | 2 | ||||
-rw-r--r-- | src/soc/mediatek/mt8183/include/soc/memlayout.ld | 2 |
6 files changed, 864 insertions, 90 deletions
diff --git a/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c index 08264fd129..92117ef5ee 100644 --- a/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c +++ b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c @@ -19,18 +19,79 @@ #include <soc/emi.h> #include <soc/dramc_register.h> #include <soc/dramc_pi_api.h> +#include <timer.h> + +enum { + RX_VREF_BEGIN = 0, + RX_VREF_END = 12, + RX_VREF_STEP = 1, + TX_VREF_BEGIN = 8, + TX_VREF_END = 18, + TX_VREF_STEP = 2, +}; + +enum { + FIRST_DQ_DELAY = 0, + FIRST_DQS_DELAY = -10, + MAX_DQDLY_TAPS = 16, + MAX_RX_DQDLY_TAPS = 63, +}; enum { GATING_START = 26, GATING_END = GATING_START + 24, }; -static void auto_refresh_switch(u8 chn, u8 option) +enum CAL_TYPE { + RX_WIN_RD_DQC = 0, + RX_WIN_TEST_ENG, + TX_WIN_DQ_ONLY, + TX_WIN_DQ_DQM, +}; + +enum RX_TYPE { + RX_DQ = 0, + RX_DQM, + RX_DQS, +}; + +struct dqdqs_perbit_dly { + struct perbit_dly { + s16 first; + s16 last; + s16 best_first; + s16 best_last; + s16 best; + } dqdly, dqsdly; +}; + +struct vref_perbit_dly { + u8 vref; + u16 max_win; + u16 min_win; + struct dqdqs_perbit_dly perbit_dly[DQ_DATA_WIDTH]; +}; + +struct tx_dly_tune { + u8 fine_tune; + u8 coarse_tune_large; + u8 coarse_tune_small; + u8 coarse_tune_large_oen; + u8 coarse_tune_small_oen; +}; + +struct per_byte_dly { + u16 max_center; + u16 min_center; + u16 final_dly; +}; + +static void auto_refresh_switch(u8 chn, bool option) { clrsetbits_le32(&ch[chn].ao.refctrl0, 1 << REFCTRL0_REFDIS_SHIFT, (option ? 0 : 1) << REFCTRL0_REFDIS_SHIFT); - if (option == DISABLE) { + if (!option) { /* * Because HW will actually disable autorefresh after * refresh_queue empty, we need to wait until queue empty. @@ -41,25 +102,17 @@ static void auto_refresh_switch(u8 chn, u8 option) } } -static void dramc_cke_fix_onoff(int option, u8 chn) +static void dramc_cke_fix_onoff(u8 chn, bool fix_on, bool fix_off) { - u8 on = 0, off = 0; - - /* If CKE is dynamic, set both CKE fix On and Off as 0. */ - if (option != CKE_DYNAMIC) { - on = option; - off = (1 - option); - } - - clrsetbits_le32(&ch[chn].ao.ckectrl, - (0x1 << 6) | (0x1 << 7), (on << 6) | (off << 7)); + 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) { u32 ckectrl_bak = read32(&ch[chn].ao.ckectrl); - dramc_cke_fix_onoff(CKE_FIXON, chn); + dramc_cke_fix_onoff(chn, true, false); clrsetbits_le32(&ch[chn].ao.mrs, MRS_MRSMA_MASK, mr_idx << MRS_MRSMA_SHIFT); clrsetbits_le32(&ch[chn].ao.mrs, @@ -120,21 +173,21 @@ static void cmd_bus_training(u8 chn, u8 rank, dramc_mode_reg_write_by_rank(chn, rank, 12, mr12_value); } -static void dramc_read_dbi_onoff(u8 onoff) +static void dramc_read_dbi_onoff(bool on) { for (size_t chn = 0; chn < CHANNEL_MAX; chn++) for (size_t b = 0; b < 2; b++) clrsetbits_le32(&ch[chn].phy.shu[0].b[b].dq[7], - 0x1 << SHU1_BX_DQ7_R_DMDQMDBI_SHU_SHIFT, - onoff << SHU1_BX_DQ7_R_DMDQMDBI_SHU_SHIFT); + 0x1 << SHU1_BX_DQ7_R_DMDQMDBI_SHIFT, + (on ? 1 : 0) << SHU1_BX_DQ7_R_DMDQMDBI_SHIFT); } -static void dramc_write_dbi_onoff(u8 onoff) +static void dramc_write_dbi_onoff(bool on) { for (size_t chn = 0; chn < CHANNEL_MAX; chn++) clrsetbits_le32(&ch[chn].ao.shu[0].wodt, 0x1 << SHU1_WODT_DBIWR_SHIFT, - onoff << SHU1_WODT_DBIWR_SHIFT); + (on ? 1 : 0) << SHU1_WODT_DBIWR_SHIFT); } static void dramc_phy_dcm_disable(u8 chn) @@ -152,7 +205,7 @@ static void dramc_phy_dcm_disable(u8 chn) clrbits_le32(&ch[chn].phy.misc_cg_ctrl5, (0x7 << 16) | (0x7 << 20)); } -static void dramc_enable_phy_dcm(u8 en) +static void dramc_enable_phy_dcm(bool en) { u32 broadcast_bak = dramc_get_broadcast(); dramc_set_broadcast(DRAMC_BROADCAST_OFF); @@ -178,10 +231,12 @@ static void dramc_enable_phy_dcm(u8 en) ((en ? 0x1 : 0) << 31)); /* DCM on: CHANNEL_EMI free run; DCM off: mem_dcm */ - assert(en == 0 || en == 1); - write32(&ch[chn].phy.misc_cg_ctrl2, 0x8060033e | (0x40 << en)); - write32(&ch[chn].phy.misc_cg_ctrl2, 0x8060033f | (0x40 << en)); - write32(&ch[chn].phy.misc_cg_ctrl2, 0x8060033e | (0x40 << en)); + write32(&ch[chn].phy.misc_cg_ctrl2, + 0x8060033e | (0x40 << (en ? 0x1 : 0))); + write32(&ch[chn].phy.misc_cg_ctrl2, + 0x8060033f | (0x40 << (en ? 0x1 : 0))); + write32(&ch[chn].phy.misc_cg_ctrl2, + 0x8060033e | (0x40 << (en ? 0x1 : 0))); clrsetbits_le32(&ch[chn].phy.misc_ctrl3, 0x3 << 26, (en ? 0 : 0x3) << 26); @@ -215,13 +270,13 @@ static void reset_delay_chain_before_calibration(void) } } -static void dramc_hw_gating_onoff(u8 chn, u8 onoff) +static void dramc_hw_gating_onoff(u8 chn, bool on) { clrsetbits_le32(&ch[chn].ao.shuctrl2, 0x3 << 14, - (onoff << 14) | (onoff << 15)); - clrsetbits_le32(&ch[chn].ao.stbcal2, 0x1 << 28, onoff << 28); - clrsetbits_le32(&ch[chn].ao.stbcal, 0x1 << 24, onoff << 24); - clrsetbits_le32(&ch[chn].ao.stbcal, 0x1 << 22, onoff << 22); + (on ? 0x3 : 0) << 14); + clrsetbits_le32(&ch[chn].ao.stbcal2, 0x1 << 28, (on ? 0x1 : 0) << 28); + clrsetbits_le32(&ch[chn].ao.stbcal, 0x1 << 24, (on ? 0x1 : 0) << 24); + clrsetbits_le32(&ch[chn].ao.stbcal, 0x1 << 22, (on ? 0x1 : 0) << 22); } static void dramc_rx_input_delay_tracking_init_by_freq(u8 chn) @@ -236,7 +291,7 @@ static void dramc_rx_input_delay_tracking_init_by_freq(u8 chn) void dramc_apply_pre_calibration_config(void) { - dramc_enable_phy_dcm(0); + dramc_enable_phy_dcm(false); reset_delay_chain_before_calibration(); setbits_le32(&ch[0].ao.shu[0].conf[3], 0x1ff << 16); @@ -252,8 +307,8 @@ void dramc_apply_pre_calibration_config(void) clrbits_le32(&ch[0].ao.dqsoscr, 0x1 << 26); clrbits_le32(&ch[0].ao.dqsoscr, 0x1 << 25); - dramc_write_dbi_onoff(DBI_OFF); - dramc_read_dbi_onoff(DBI_OFF); + dramc_write_dbi_onoff(false); + dramc_read_dbi_onoff(false); for (size_t chn = 0; chn < CHANNEL_MAX; chn++) { setbits_le32(&ch[chn].ao.spcmdctrl, 0x1 << 29); @@ -262,7 +317,7 @@ void dramc_apply_pre_calibration_config(void) setbits_le32(&ch[chn].ao.shu[shu].scintv, 0x1 << 30); clrbits_le32(&ch[chn].ao.dummy_rd, (0x1 << 7) | (0x7 << 20)); - dramc_hw_gating_onoff(chn, GATING_OFF); + dramc_hw_gating_onoff(chn, false); clrbits_le32(&ch[chn].ao.stbcal2, 0x1 << 28); setbits_le32(&ch[chn].phy.misc_ctrl1, @@ -303,7 +358,7 @@ static void dramc_set_rank_engine2(u8 chn, u8 rank) rank << TEST2_4_TESTAGENTRK_SHIFT); } -static void dramc_engine2_init(u8 chn, u8 rank, u32 size, bool testaudpat) +static void dramc_engine2_init(u8 chn, u8 rank, u32 size, bool test_pat) { const u32 pat0 = 0x55; const u32 pat1 = 0xaa; @@ -335,11 +390,11 @@ static void dramc_engine2_init(u8 chn, u8 rank, u32 size, bool testaudpat) (0x1 << TEST2_4_TESTAUDMODE_SHIFT) | (0x1 << TEST2_4_TESTAUDBITINV_SHIFT) | (0x1 << TEST2_4_TESTXTALKPAT_SHIFT), - ((!testaudpat ? 1 : 0) << TEST2_4_TESTXTALKPAT_SHIFT) | - ((testaudpat ? 1 : 0) << TEST2_4_TESTAUDMODE_SHIFT) | - ((testaudpat ? 1 : 0) << TEST2_4_TESTAUDBITINV_SHIFT)); + ((!test_pat ? 1 : 0) << TEST2_4_TESTXTALKPAT_SHIFT) | + ((test_pat ? 1 : 0) << TEST2_4_TESTAUDMODE_SHIFT) | + ((test_pat ? 1 : 0) << TEST2_4_TESTAUDBITINV_SHIFT)); - if (!testaudpat) { + if (!test_pat) { clrbits_le32(&ch[chn].ao.test2_4, (0x1 << TEST2_4_TEST_REQ_LEN1_SHIFT) | (0x1 << TEST2_4_TESTSSOPAT_SHIFT) | @@ -354,28 +409,19 @@ static void dramc_engine2_init(u8 chn, u8 rank, u32 size, bool testaudpat) } clrsetbits_le32(&ch[chn].ao.test2_3, TEST2_3_TESTCNT_MASK | (0x1 << TEST2_3_TESTAUDPAT_SHIFT), - (testaudpat ? 1 : 0) << TEST2_3_TESTAUDPAT_SHIFT); + (test_pat ? 1 : 0) << TEST2_3_TESTAUDPAT_SHIFT); } static void dramc_engine2_check_complete(u8 chn) { - u32 u4loop_count = 0; - /* In some case test engine finished but the complete signal late come, * system will wait very long time. Hence, we set a timeout here. * After system receive complete signal or wait until time out * it will return, the caller will check compare result to verify * whether engine success. */ - while ((read32(&ch[chn].nao.testrpt) & 0x1) == 0) { - udelay(1); - u4loop_count++; - - if (u4loop_count > MAX_CMP_CPT_WAIT_LOOP) { - dramc_dbg("MEASURE_A timeout\n"); - break; - } - } + if (!wait_us(10000, read32(&ch[chn].nao.testrpt) & 0x1)) + dramc_dbg("MEASURE_A timeout\n"); } static u32 dramc_engine2_run(u8 chn, enum dram_te_op wr) @@ -530,10 +576,10 @@ static void dramc_set_gating_mode(u8 chn, bool mode) static void dramc_rx_dqs_gating_cal_pre(u8 chn, u8 rank) { - rx_dqs_isi_pulse_cg_switch(chn, DISABLE); + rx_dqs_isi_pulse_cg_switch(chn, false); clrbits_le32(&ch[chn].ao.refctrl0, 1 << REFCTRL0_PBREFEN_SHIFT); - dramc_hw_gating_onoff(chn, GATING_OFF); + dramc_hw_gating_onoff(chn, false); setbits_le32(&ch[chn].ao.stbcal1, 1 << STBCAL1_STBENCMPEN_SHIFT); setbits_le32(&ch[chn].ao.stbcal1, 1 << STBCAL1_STBCNT_LATCH_EN_SHIFT); @@ -559,7 +605,7 @@ static void dramc_write_dqs_gating_result(u8 chn, u8 rank, u8 best_coarse_rodt_p1[DQS_NUMBER]; u8 best_coarse_0p5t_rodt_p1[DQS_NUMBER]; - rx_dqs_isi_pulse_cg_switch(chn, ENABLE); + rx_dqs_isi_pulse_cg_switch(chn, true); write32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0, ((u32) best_coarse_tune2t[0] << @@ -604,7 +650,7 @@ static void dramc_write_dqs_gating_result(u8 chn, u8 rank, best_coarse_0p5t_rodt[dqs] = 0; best_coarse_rodt_p1[dqs] = 4; best_coarse_0p5t_rodt_p1[dqs] = 4; - dramc_dbg("RxdqsGatingCal error: best_coarse_tune2t:%d" + dramc_dbg("RxdqsGatingCal error: best_coarse_tune2t:%zd" " is already 0. RODT cannot be -1 coarse\n", dqs); } @@ -667,7 +713,7 @@ static void dramc_rx_dqs_gating_cal(u8 chn, u8 rank) dramc_rx_dqs_gating_cal_pre(chn, rank); u32 dummy_rd_backup = read32(&ch[chn].ao.dummy_rd); - dramc_engine2_init(chn, rank, 0x23, 1); + dramc_engine2_init(chn, rank, 0x23, true); dramc_dbg("[Gating]\n"); for (u32 coarse_tune = coarse_start; coarse_tune < coarse_end; @@ -834,9 +880,753 @@ static void dramc_rx_dqs_gating_cal(u8 chn, u8 rank) dram_phy_reset(chn); } +static void dramc_rd_dqc_init(u8 chn, u8 rank) +{ + const u8 *lpddr_phy_mapping = phy_mapping[chn]; + u16 temp_value = 0; + + for (size_t b = 0; b < 2; b++) + clrbits_le32(&ch[chn].phy.shu[0].b[b].dq[7], + 0x1 << SHU1_BX_DQ7_R_DMDQMDBI_SHIFT); + + clrsetbits_le32(&ch[chn].ao.mrs, + MRS_MRSRK_MASK, rank << MRS_MRSRK_SHIFT); + setbits_le32(&ch[chn].ao.mpc_option, + 0x1 << MPC_OPTION_MPCRKEN_SHIFT); + + for (size_t i = 0; i < 16; i++) + temp_value |= ((0x5555 >> i) & 0x1) << lpddr_phy_mapping[i]; + + u16 mr15_golden_value = temp_value & 0xff; + u16 mr20_golden_value = (temp_value >> 8) & 0xff; + clrsetbits_le32(&ch[chn].ao.mr_golden, + MR_GOLDEN_MR15_GOLDEN_MASK | MR_GOLDEN_MR20_GOLDEN_MASK, + (mr15_golden_value << 8) | mr20_golden_value); +} + +static u32 dramc_rd_dqc_run(u8 chn) +{ + setbits_le32(&ch[chn].ao.spcmdctrl, 1 << SPCMDCTRL_RDDQCDIS_SHIFT); + setbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_RDDQCEN_SHIFT); + + if (!wait_us(100, read32(&ch[chn].nao.spcmdresp) & + (0x1 << SPCMDRESP_RDDQC_RESPONSE_SHIFT))) + dramc_dbg("[RDDQC] resp fail (time out)\n"); + + u32 result = read32(&ch[chn].nao.rdqc_cmp); + clrbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_RDDQCEN_SHIFT); + clrbits_le32(&ch[chn].ao.spcmdctrl, 1 << SPCMDCTRL_RDDQCDIS_SHIFT); + + return result; +} + +static void dramc_rd_dqc_end(u8 chn) +{ + clrbits_le32(&ch[chn].ao.mrs, MRS_MRSRK_MASK); +} + +static void dramc_rx_vref_enable(u8 chn) +{ + setbits_le32(&ch[chn].phy.b[0].dq[5], + 0x1 << B0_DQ5_RG_RX_ARDQ_VREF_EN_B0_SHIFT); + setbits_le32(&ch[chn].phy.b[1].dq[5], + 0x1 << B1_DQ5_RG_RX_ARDQ_VREF_EN_B1_SHIFT); +} + +static void dramc_set_rx_vref(u8 chn, u8 value) +{ + for (size_t b = 0; b < 2; b++) + clrsetbits_le32(&ch[chn].phy.shu[0].b[b].dq[5], + SHU1_BX_DQ5_RG_RX_ARDQ_VREF_SEL_B0_MASK, + value << SHU1_BX_DQ5_RG_RX_ARDQ_VREF_SEL_B0_SHIFT); +} + +static void dramc_set_tx_vref(u8 chn, u8 rank, u8 value) +{ + dramc_mode_reg_write_by_rank(chn, rank, 14, value); +} + +static void dramc_set_vref(u8 chn, u8 rank, enum CAL_TYPE type, u8 vref) +{ + if (type == RX_WIN_TEST_ENG) + dramc_set_rx_vref(chn, vref); + else + dramc_set_tx_vref(chn, rank, vref); +} + +static void dramc_transfer_dly_tune( + u8 chn, u32 dly, struct tx_dly_tune *dly_tune) +{ + u16 tmp_val; + + dly_tune->fine_tune = dly & (TX_DQ_COARSE_TUNE_TO_FINE_TUNE_TAP - 1); + + tmp_val = (dly / TX_DQ_COARSE_TUNE_TO_FINE_TUNE_TAP) << 1; + dly_tune->coarse_tune_small = tmp_val - ((tmp_val >> 3) << 3); + dly_tune->coarse_tune_large = tmp_val >> 3; + + tmp_val -= 4; + dly_tune->coarse_tune_small_oen = tmp_val - ((tmp_val >> 3) << 3); + dly_tune->coarse_tune_large_oen = tmp_val >> 3; +} + +static void set_rx_dly_factor(u8 chn, u8 rank, enum RX_TYPE type, u32 val) +{ + u32 tmp, mask; + + switch (type) { + case RX_DQ: + tmp = (val << 24 | val << 16 | val << 8 | val); + for (size_t i = 2; i < 6; i++) { + write32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[i], tmp); + write32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[i], tmp); + } + break; + + case RX_DQM: + tmp = (val << 8 | val); + mask = SHU1_B0_DQ6_RK_RX_ARDQM0_F_DLY_B0_MASK | + SHU1_B0_DQ6_RK_RX_ARDQM0_R_DLY_B0_MASK; + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[6], + mask, tmp); + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[6], + mask, tmp); + break; + + case RX_DQS: + tmp = (val << 24 | val << 16); + mask = SHU1_B0_DQ6_RK_RX_ARDQS0_F_DLY_B0_MASK | + SHU1_B0_DQ6_RK_RX_ARDQS0_R_DLY_B0_MASK; + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[6], + mask, tmp); + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[6], + mask, tmp); + break; + } +} + +static void set_tx_dly_factor(u8 chn, u8 rank, enum CAL_TYPE type, u32 val) +{ + struct tx_dly_tune dly_tune = {0}; + u32 coarse_tune_large = 0, coarse_tune_large_oen = 0; + u32 coarse_tune_small = 0, coarse_tune_small_oen = 0; + + dramc_transfer_dly_tune(chn, val, &dly_tune); + + for (u8 i = 0; i < 4; i++) { + coarse_tune_large += dly_tune.coarse_tune_large << (i * 4); + coarse_tune_large_oen += + dly_tune.coarse_tune_large_oen << (i * 4); + coarse_tune_small += dly_tune.coarse_tune_small << (i * 4); + coarse_tune_small_oen += + dly_tune.coarse_tune_small_oen << (i * 4); + } + if (type == TX_WIN_DQ_DQM) + dramc_dbg("%3d |%d %d %2d | [0]", + val, dly_tune.coarse_tune_large, + dly_tune.coarse_tune_small, dly_tune.fine_tune); + + if (type != TX_WIN_DQ_DQM && type != TX_WIN_DQ_ONLY) + return; + + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[0], + (coarse_tune_large_oen << 16) | coarse_tune_large); + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[2], + (coarse_tune_small_oen << 16) | coarse_tune_small); + for (size_t b = 0; b < 2; b++) + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[b].dq[7], + FINE_TUNE_DQ_MASK, dly_tune.fine_tune << 8); + + if (type == TX_WIN_DQ_DQM) { + /* Large coarse_tune setting */ + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[1], + (coarse_tune_large_oen << 16) | coarse_tune_large); + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[3], + (coarse_tune_small_oen << 16) | coarse_tune_small); + /* Fine_tune delay setting */ + for (size_t b = 0; b < 2; b++) + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[b].dq[7], + FINE_TUNE_DQM_MASK, dly_tune.fine_tune << 16); + } +} + +static u32 dramc_get_smallest_dqs_dly( + u8 chn, u8 rank, const struct sdram_params *params) +{ + u32 min_dly = 0xffff; + + for (size_t i = 0; i < DQS_NUMBER; i++) + min_dly = MIN(min_dly, params->wr_level[chn][rank][i]); + + return DQS_DELAY + min_dly + 40; +} + +static void dramc_get_dly_range(u8 chn, u8 rank, enum CAL_TYPE type, + u16 *pre_cal, s16 *begin, s16 *end, + const struct sdram_params *params) +{ + u16 pre_dq_dly; + switch (type) { + case RX_WIN_RD_DQC: + *begin = FIRST_DQS_DELAY; + *end = MAX_RX_DQDLY_TAPS; + break; + + case RX_WIN_TEST_ENG: + *begin = FIRST_DQ_DELAY; + *end = MAX_RX_DQDLY_TAPS; + break; + + case TX_WIN_DQ_DQM: + *begin = dramc_get_smallest_dqs_dly(chn, rank, params); + *end = *begin + 256; + break; + + case TX_WIN_DQ_ONLY: + pre_dq_dly = MIN(pre_cal[0], pre_cal[1]); + pre_dq_dly = (pre_dq_dly > 24) ? (pre_dq_dly - 24) : 0; + *begin = pre_dq_dly; + *end = *begin + 64; + break; + } +} +static int dramc_check_dqdqs_win( + struct dqdqs_perbit_dly *p, s16 dly_pass, s16 last_step, + bool fail, bool is_dq) +{ + s16 best_pass_win; + struct perbit_dly *dly = is_dq ? &p->dqdly : &p->dqsdly; + + if (!fail && dly->first == -1) + dly->first = dly_pass; + + if (!fail && dly->last == -2 && dly_pass == last_step) + dly->last = dly_pass; + else if (fail && dly->first != -1 && dly->last == -2) + dly->last = dly_pass - 1; + + if (dly->last == -2) + return 0; + + int pass_win = dly->last - dly->first; + best_pass_win = dly->best_last - dly->best_first; + if (pass_win > best_pass_win) { + dly->best_last = dly->last; + dly->best_first = dly->first; + } + /* Clear to find the next pass range if it has */ + dly->first = -1; + dly->last = -2; + + return pass_win; +} + +static void dramc_set_vref_dly(struct vref_perbit_dly *vref_dly, + u8 vref, u32 win_size_sum, struct dqdqs_perbit_dly delay[]) +{ + struct dqdqs_perbit_dly *perbit_dly = vref_dly->perbit_dly; + + vref_dly->max_win = win_size_sum; + vref_dly->vref = vref; + for (size_t bit = 0; bit < DQ_DATA_WIDTH; bit++) { + perbit_dly[bit].dqdly.best = delay[bit].dqdly.best; + perbit_dly[bit].dqdly.best_first = delay[bit].dqdly.best_first; + perbit_dly[bit].dqdly.best_last = delay[bit].dqdly.best_last; + perbit_dly[bit].dqsdly.best_first = + delay[bit].dqsdly.best_first; + perbit_dly[bit].dqsdly.best_last = delay[bit].dqsdly.best_last; + } +} + +static bool dramk_calc_best_vref(enum CAL_TYPE type, u8 vref, + struct vref_perbit_dly *vref_dly, + struct dqdqs_perbit_dly delay[]) +{ + u32 win_size; + u32 win_size_sum = 0; + static u32 min_win_size_vref; + + switch (type) { + case RX_WIN_TEST_ENG: + for (size_t bit = 0; bit < DQ_DATA_WIDTH; bit++) { + win_size_sum += delay[bit].dqdly.best_last - + delay[bit].dqdly.best_first + 1; + win_size_sum += delay[bit].dqsdly.best_last - + delay[bit].dqsdly.best_first + 1; + } + + if (win_size_sum > vref_dly->max_win) + dramc_set_vref_dly(vref_dly, vref, win_size_sum, delay); + + if (win_size_sum < (vref_dly->max_win * 95 / 100)) + return true; + + break; + case TX_DQ_DQS_MOVE_DQ_ONLY: + for (size_t bit = 0; bit < DQ_DATA_WIDTH; bit++) { + win_size = delay[bit].dqdly.best_last - + delay[bit].dqdly.best_first + 1; + vref_dly->min_win = MIN(vref_dly->min_win, win_size); + win_size_sum += win_size; + } + + if (win_size_sum > vref_dly->max_win + && vref_dly->min_win >= min_win_size_vref) { + min_win_size_vref = vref_dly->min_win; + dramc_set_vref_dly(vref_dly, vref, win_size_sum, delay); + } + + break; + default: + dramc_set_vref_dly(vref_dly, vref, win_size_sum, delay); + break; + } + + return false; +} + +static void dramc_calc_tx_perbyte_dly( + struct dqdqs_perbit_dly *p, s16 *win, + struct per_byte_dly *byte_delay_prop) +{ + s16 win_center = (p->dqdly.best_first + p->dqdly.best_last) >> 1; + *win = win_center; + + if (win_center < byte_delay_prop->min_center) + byte_delay_prop->min_center = win_center; + if (win_center > byte_delay_prop->max_center) + byte_delay_prop->max_center = win_center; +} + +static void dramc_set_rx_dly(u8 chn, u8 rank, s32 dly) +{ + if (dly <= 0) { + /* Hold time calibration */ + set_rx_dly_factor(chn, rank, RX_DQS, -dly); + dram_phy_reset(chn); + } else { + /* Setup time calibration */ + set_rx_dly_factor(chn, rank, RX_DQS, 0); + set_rx_dly_factor(chn, rank, RX_DQM, dly); + dram_phy_reset(chn); + set_rx_dly_factor(chn, rank, RX_DQ, dly); + } + +} + +static void set_tx_best_dly_factor(u8 chn, u8 rank_start, + struct per_byte_dly *tx_perbyte_dly, u16 dq_precal_result[]) +{ + u32 coarse_tune_large = 0; + u32 coarse_tune_large_oen = 0; + u32 coarse_tune_small = 0; + u32 coarse_tune_small_oen = 0; + u16 dq_oen[DQS_NUMBER] = {0}, dqm_oen[DQS_NUMBER] = {0}; + struct tx_dly_tune dqdly_tune[DQS_NUMBER] = {0}; + struct tx_dly_tune dqmdly_tune[DQS_NUMBER] = {0}; + + for (size_t i = 0; i < DQS_NUMBER; i++) { + dramc_transfer_dly_tune(chn, tx_perbyte_dly[i].final_dly, + &dqdly_tune[i]); + dramc_transfer_dly_tune(chn, dq_precal_result[i], + &dqmdly_tune[i]); + + coarse_tune_large += dqdly_tune[i].coarse_tune_large << (i * 4); + coarse_tune_large_oen += + dqdly_tune[i].coarse_tune_large_oen << (i * 4); + coarse_tune_small += dqdly_tune[i].coarse_tune_small << (i * 4); + coarse_tune_small_oen += + dqdly_tune[i].coarse_tune_small_oen << (i * 4); + + dq_oen[i] = (dqdly_tune[i].coarse_tune_large_oen << 3) + + (dqdly_tune[i].coarse_tune_small_oen << 5) + + dqdly_tune[i].fine_tune; + dqm_oen[i] = (dqmdly_tune[i].coarse_tune_large_oen << 3) + + (dqmdly_tune[i].coarse_tune_small_oen << 5) + + dqmdly_tune[i].fine_tune; + } + + for (size_t rank = rank_start; rank < RANK_MAX; rank++) { + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[0], + (coarse_tune_large_oen << 16) | coarse_tune_large); + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[2], + (coarse_tune_small_oen << 16) | coarse_tune_small); + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[1], + (coarse_tune_large_oen << 16) | coarse_tune_large); + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[3], + (coarse_tune_small_oen << 16) | coarse_tune_small); + } + + for (size_t rank = rank_start; rank < RANK_MAX; rank++) + for (size_t b = 0; b < 2; b++) + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[b].dq[7], + FINE_TUNE_DQ_MASK | FINE_TUNE_DQM_MASK, + (dqdly_tune[b].fine_tune << + FINE_TUNE_DQ_SHIFT) | + (dqmdly_tune[b].fine_tune << + FINE_TUNE_DQM_SHIFT)); +} + +static void set_rx_best_dly_factor(u8 chn, u8 rank, + struct dqdqs_perbit_dly *dqdqs_perbit_dly, + u32 *max_dqsdly_byte, u32 *ave_dqm_dly) +{ + u32 value; + + for (size_t i = 0; i < DQS_NUMBER; i++) { + value = (max_dqsdly_byte[i] << 24) | + (max_dqsdly_byte[i] << 16) | + (ave_dqm_dly[i] << 8) | (ave_dqm_dly[i] << 0); + write32(&ch[chn].phy.shu[0].rk[rank].b[i].dq[6], value); + } + dram_phy_reset(chn); + + for (size_t i = 0; i < DQ_DATA_WIDTH; i += 2) { + u32 byte = i / DQS_BIT_NUMBER; + u32 index = 2 + ((i % 8) * 2) / 4; + value = dqdqs_perbit_dly[i + 1].dqdly.best << 24 | + dqdqs_perbit_dly[i + 1].dqdly.best << 16 | + dqdqs_perbit_dly[i].dqdly.best << 8 | + dqdqs_perbit_dly[i].dqdly.best; + write32(&ch[chn].phy.shu[0].rk[rank].b[byte].dq[index], value); + } +} + +static bool dramc_calc_best_dly(u8 bit, + struct dqdqs_perbit_dly *p, u32 *p_max_byte) +{ + u8 fail = 0, hold, setup; + + hold = p->dqsdly.best_last - p->dqsdly.best_first + 1; + setup = p->dqdly.best_last - p->dqdly.best_first + 1; + + if (hold > setup) { + p->dqdly.best = 0; + p->dqsdly.best = (setup != 0) ? (hold - setup) / 2 : + (hold - setup) / 2 + p->dqsdly.best_first; + + if (p->dqsdly.best > *p_max_byte) + *p_max_byte = p->dqsdly.best; + + } else if (hold < setup) { + p->dqsdly.best = 0; + p->dqdly.best = (hold != 0) ? (setup - hold) / 2 : + (setup - hold) / 2 + p->dqdly.best_first; + + } else { /* Hold time == setup time */ + p->dqsdly.best = 0; + p->dqdly.best = 0; + + if (hold == 0) { + dramc_dbg("Error bit %d, setup = hold = 0\n", bit); + fail = 1; + } + } + + dramc_dbg("bit#%d : dq =%d dqs=%d win=%d (%d, %d)\n", bit, setup, + hold, setup + hold, p->dqdly.best, p->dqsdly.best); + + return fail; +} + +static void dramc_set_dqdqs_dly(u8 chn, u8 rank, enum CAL_TYPE type, s32 dly) +{ + if ((type == RX_WIN_RD_DQC) || (type == RX_WIN_TEST_ENG)) + dramc_set_rx_dly(chn, rank, dly); + else + set_tx_dly_factor(chn, rank, type, dly); +} + +static void dramc_set_tx_best_dly(u8 chn, u8 rank, + struct dqdqs_perbit_dly *tx_dly, u16 *tx_dq_precal_result, + const struct sdram_params *params) +{ + s16 dq_win_center[DQ_DATA_WIDTH]; + u16 pi_diff; + u32 byte_dly_cell[DQS_NUMBER] = {0}; + struct per_byte_dly tx_perbyte_dly[DQS_NUMBER]; + u16 dly_cell_unit = params->delay_cell_unit; + int index, bit; + u16 dq_delay_cell[DQ_DATA_WIDTH]; + + for (size_t i = 0; i < DQS_NUMBER; i++) { + tx_perbyte_dly[i].min_center = 0xffff; + tx_perbyte_dly[i].max_center = 0; + } + + for (size_t i = 0; i < DQ_DATA_WIDTH; i++) { + index = i / DQS_BIT_NUMBER; + dramc_calc_tx_perbyte_dly(&tx_dly[i], + &dq_win_center[i], &tx_perbyte_dly[index]); + } + + for (size_t i = 0; i < DQS_NUMBER; i++) { + tx_perbyte_dly[i].final_dly = tx_perbyte_dly[i].min_center; + tx_dq_precal_result[i] = (tx_perbyte_dly[i].max_center + + tx_perbyte_dly[i].min_center) >> 1; + + for (bit = 0; bit < DQS_BIT_NUMBER; bit++) { + pi_diff = dq_win_center[i * 8 + bit] + - tx_perbyte_dly[i].min_center; + dq_delay_cell[i * 8 + bit] = + ((pi_diff * 1000000) / (16 * 64)) + / dly_cell_unit; + byte_dly_cell[i] |= + (dq_delay_cell[i * 8 + bit] << (bit * 4)); + } + + write32(&ch[chn].phy.shu[0].rk[rank].b[i].dq[0], + byte_dly_cell[i]); + } + + set_tx_best_dly_factor(chn, rank, tx_perbyte_dly, tx_dq_precal_result); +} + +static int dramc_set_rx_best_dly(u8 chn, u8 rank, + struct dqdqs_perbit_dly *rx_dly) +{ + s16 dly; + bool fail = false; + u8 index, max_limit; + static u32 max_dqsdly_byte[DQS_NUMBER]; + static u32 ave_dqmdly_byte[DQS_NUMBER]; + + for (size_t i = 0; i < DQS_NUMBER; i++) { + max_dqsdly_byte[i] = 0; + ave_dqmdly_byte[i] = 0; + } + + for (size_t i = 0; i < DQ_DATA_WIDTH; i++) { + index = i / DQS_BIT_NUMBER; + fail |= dramc_calc_best_dly(i, &rx_dly[i], + &max_dqsdly_byte[index]); + } + + for (size_t i = 0; i < DQ_DATA_WIDTH; i++) { + index = i / DQS_BIT_NUMBER; + /* Set DQS to max for 8-bit */ + if (rx_dly[i].dqsdly.best < max_dqsdly_byte[index]) { + /* Delay DQ to compensate extra DQS delay */ + dly = max_dqsdly_byte[index] - rx_dly[i].dqsdly.best; + rx_dly[i].dqdly.best += dly; + max_limit = MAX_DQDLY_TAPS - 1; + if (rx_dly[i].dqdly.best > max_limit) + rx_dly[i].dqdly.best = max_limit; + } + + ave_dqmdly_byte[index] += rx_dly[i].dqdly.best; + if ((i + 1) % DQS_BIT_NUMBER == 0) + ave_dqmdly_byte[index] /= DQS_BIT_NUMBER; + } + + if (fail) { + dramc_dbg("Fail on perbit_window_cal()\n"); + return -1; + } + + set_rx_best_dly_factor(chn, rank, rx_dly, max_dqsdly_byte, + ave_dqmdly_byte); + return 0; +} + +static void dramc_get_vref_prop(u8 rank, enum CAL_TYPE type, + u8 *vref_scan_en, u8 *vref_begin, u8 *vref_end) +{ + if (type == RX_WIN_TEST_ENG && rank == RANK_0) { + *vref_scan_en = 1; + *vref_begin = RX_VREF_BEGIN; + *vref_end = RX_VREF_END; + } else if (type == TX_WIN_DQ_ONLY) { + *vref_scan_en = 1; + *vref_begin = TX_VREF_BEGIN; + *vref_end = TX_VREF_END; + } else { + *vref_scan_en = 0; + } +} + +static void dramc_engine2_setpat(u8 chn, bool test_pat) +{ + clrbits_le32(&ch[chn].ao.test2_4, + (0x1 << TEST2_4_TESTXTALKPAT_SHIFT) | + (0x1 << TEST2_4_TESTAUDMODE_SHIFT) | + (0x1 << TEST2_4_TESTAUDBITINV_SHIFT)); + + if (!test_pat) { + setbits_le32(&ch[chn].ao.perfctl0, 1 << PERFCTL0_RWOFOEN_SHIFT); + + clrbits_le32(&ch[chn].ao.test2_4, + (0x1 << TEST2_4_TEST_REQ_LEN1_SHIFT) | + (0x1 << TEST2_4_TESTSSOPAT_SHIFT) | + (0x1 << TEST2_4_TESTSSOXTALKPAT_SHIFT) | + (0x1 << TEST2_4_TESTXTALKPAT_SHIFT)); + } else { + clrsetbits_le32(&ch[chn].ao.test2_4, + TEST2_4_TESTAUDINIT_MASK | TEST2_4_TESTAUDINC_MASK, + (0x11 << 8) | (0xd << 0) | (0x1 << 14)); + } + clrsetbits_le32(&ch[chn].ao.test2_3, + (0x1 << TEST2_3_TESTAUDPAT_SHIFT) | TEST2_3_TESTCNT_MASK, + (test_pat ? 1 : 0) << TEST2_3_TESTAUDPAT_SHIFT); +} + +static u32 dram_k_perbit(u8 chn, enum CAL_TYPE type) +{ + u32 err_value; + + if (type == RX_WIN_RD_DQC) { + err_value = dramc_rd_dqc_run(chn); + } else { + dramc_engine2_setpat(chn, true); + err_value = dramc_engine2_run(chn, TE_OP_WRITE_READ_CHECK); + dramc_engine2_setpat(chn, false); + err_value |= dramc_engine2_run(chn, TE_OP_WRITE_READ_CHECK); + } + return err_value; +} + +static u8 dramc_window_perbit_cal(u8 chn, u8 rank, + enum CAL_TYPE type, const struct sdram_params *params) +{ + u8 vref = 0, vref_begin = 0, vref_end = 1, vref_step = 1; + u8 dly_step = 2, vref_scan_enable = 0; + s16 dly, dly_begin = 0, dly_end = 0, last_step; + s16 dly_pass; + u32 dummy_rd_backup = 0, err_value, finish_bit; + static u16 dq_precal_result[DQS_NUMBER]; + static struct vref_perbit_dly vref_dly; + struct dqdqs_perbit_dly dq_perbit_dly[DQ_DATA_WIDTH]; + + dramc_get_vref_prop(rank, type, + &vref_scan_enable, &vref_begin, &vref_end); + if (vref_scan_enable && type == RX_WIN_RD_DQC) + dramc_rx_vref_enable(chn); + + dramc_dbg("[channel %d] [rank %d] type:%d, vref_enable:%d\n", + chn, rank, type, vref_scan_enable); + + if ((type == TX_WIN_DQ_ONLY) || (type == TX_WIN_DQ_DQM)) { + for (size_t i = 0; i < 2; i++) { + write32(&ch[chn].phy.shu[0].rk[rank].b[i].dq[0], 0); + clrbits_le32(&ch[chn].phy.shu[0].rk[rank].b[i].dq[1], + 0xf); + } + setbits_le32(&ch[chn].phy.misc_ctrl1, + 0x1 << MISC_CTRL1_R_DMAR_FINE_TUNE_DQ_SW_SHIFT); + setbits_le32(&ch[chn].ao.dqsoscr, + 0x1 << DQSOSCR_AR_COARSE_TUNE_DQ_SW_SHIFT); + vref_step = 2; + } + + if (type == RX_WIN_RD_DQC) { + dramc_rd_dqc_init(chn, rank); + } else { + dummy_rd_backup = read32(&ch[chn].ao.dummy_rd); + dramc_engine2_init(chn, rank, 0x400, false); + } + + vref_dly.max_win = 0; + vref_dly.min_win = 0xffff; + for (vref = vref_begin; vref < vref_end; vref += vref_step) { + vref_dly.vref = vref; + finish_bit = 0; + for (size_t i = 0; i < DQ_DATA_WIDTH; i++) { + dq_perbit_dly[i].dqdly.first = -1; + dq_perbit_dly[i].dqdly.last = -2; + dq_perbit_dly[i].dqsdly.first = -1; + dq_perbit_dly[i].dqsdly.last = -2; + dq_perbit_dly[i].dqdly.best_first = -1; + dq_perbit_dly[i].dqdly.best_last = -2; + dq_perbit_dly[i].dqsdly.best_first = -1; + dq_perbit_dly[i].dqsdly.best_last = -2; + } + + if (vref_scan_enable) + dramc_set_vref(chn, rank, type, vref_dly.vref); + + if ((type == RX_WIN_RD_DQC) || (type == RX_WIN_TEST_ENG)) { + set_rx_dly_factor(chn, rank, RX_DQM, FIRST_DQ_DELAY); + set_rx_dly_factor(chn, rank, RX_DQ, FIRST_DQ_DELAY); + } + + dramc_get_dly_range(chn, rank, type, dq_precal_result, + &dly_begin, &dly_end, params); + for (dly = dly_begin; dly < dly_end; dly += dly_step) { + dramc_set_dqdqs_dly(chn, rank, type, dly); + err_value = dram_k_perbit(chn, type); + finish_bit = 0; + if (!vref_scan_enable) + dramc_dbg("%d ", dly); + + for (size_t bit = 0; bit < DQ_DATA_WIDTH; bit++) { + bool flag; + bool fail = (err_value & ((u32) 1 << bit)) != 0; + + if (dly < 0) { + dly_pass = -dly; + last_step = -FIRST_DQS_DELAY; + flag = false; + } else { + dly_pass = dly; + last_step = dly_end; + flag = true; + } + + /* pass window bigger than 7, + consider as real pass window */ + if (dramc_check_dqdqs_win(&(dq_perbit_dly[bit]), + dly_pass, last_step, + fail, flag) > 7) + finish_bit |= (1 << bit); + + if (vref_scan_enable) + continue; + dramc_dbg("%s", !fail ? "o" : "x"); + } + + if (!vref_scan_enable) + dramc_dbg(" [MSB]\n"); + if (finish_bit == ((1 << DQ_DATA_WIDTH) - 1)) { + dramc_dbg("all bits window found, break!\n"); + break; + } + } + + for (size_t bit = 0; bit < DQ_DATA_WIDTH; bit++) + dramc_dbg("Dq[%zd] win(%d ~ %d)\n", bit, + dq_perbit_dly[bit].dqdly.best_first, + dq_perbit_dly[bit].dqdly.best_last); + + if (dramk_calc_best_vref(type, vref, &vref_dly, dq_perbit_dly)) + break; + + if (finish_bit == ((1 << DQ_DATA_WIDTH) - 1)) { + dramc_dbg("all bits window found, break!\n"); + break; + } + } + + if (type == RX_WIN_RD_DQC) { + dramc_rd_dqc_end(chn); + } else { + dramc_engine2_end(chn); + write32(&ch[chn].ao.dummy_rd, dummy_rd_backup); + } + + if (vref_scan_enable) + dramc_set_vref(chn, rank, type, vref_dly.vref); + + if ((type == RX_WIN_RD_DQC) || (type == RX_WIN_TEST_ENG)) + dramc_set_rx_best_dly(chn, rank, vref_dly.perbit_dly); + else + dramc_set_tx_best_dly(chn, rank, vref_dly.perbit_dly, + dq_precal_result, params); + return 0; +} + static void dramc_rx_dqs_gating_post_process(u8 chn) { - u8 dqs, rank_rx_dvs, dqsinctl; + u8 rank_rx_dvs, dqsinctl; u32 read_dqsinctl, rankinctl_root, xrtr2r, reg_tx_dly_dqsgated_min = 3; u8 txdly_cal_min = 0xff, txdly_cal_max = 0, tx_dly_dqs_gated = 0; u32 best_coarse_tune2t[RANK_MAX][DQS_NUMBER]; @@ -851,7 +1641,7 @@ static void dramc_rx_dqs_gating_post_process(u8 chn) for (size_t rank = 0; rank < RANK_MAX; rank++) { u32 dqsg0 = read32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0); - for (dqs = 0; dqs < DQS_NUMBER; dqs++) { + for (size_t dqs = 0; dqs < DQS_NUMBER; dqs++) { best_coarse_tune2t[rank][dqs] = (dqsg0 >> (dqs * 8)) & SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_MASK; @@ -859,7 +1649,7 @@ static void dramc_rx_dqs_gating_post_process(u8 chn) ((dqsg0 >> (dqs * 8)) & SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_MASK) >> SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_SHIFT; - dramc_dbg("Rank%d best DQS%d dly(2T,(P1)2T)=(%d, %d)\n", + dramc_dbg("Rank%zd best DQS%zd dly(2T,(P1)2T)=(%d, %d)\n", rank, dqs, best_coarse_tune2t[rank][dqs], best_coarse_tune2t_p1[rank][dqs]); @@ -880,14 +1670,14 @@ static void dramc_rx_dqs_gating_post_process(u8 chn) txdly_cal_max += dqsinctl; for (size_t rank = 0; rank < RANK_MAX; rank++) { - dramc_dbg("Rank: %d\n", rank); - for (dqs = 0; dqs < DQS_NUMBER; dqs++) { + dramc_dbg("Rank: %zd\n", rank); + for (size_t dqs = 0; dqs < DQS_NUMBER; dqs++) { best_coarse_tune2t[rank][dqs] += dqsinctl; best_coarse_tune2t_p1[rank][dqs] += dqsinctl; - dramc_dbg("Best DQS%d dly(2T) = (%d)\n", + dramc_dbg("Best DQS%zd dly(2T) = (%d)\n", dqs, best_coarse_tune2t[rank][dqs]); - dramc_dbg("Best DQS%d P1 dly(2T) = (%d)\n", + dramc_dbg("Best DQS%zd P1 dly(2T) = (%d)\n", dqs, best_coarse_tune2t_p1[rank][dqs]); } @@ -933,11 +1723,15 @@ void dramc_calibrate_all_channels(const struct sdram_params *pams) for (u8 chn = 0; chn < CHANNEL_MAX; chn++) { for (u8 rk = RANK_0; rk < RANK_MAX; rk++) { dramc_show("Start K ch:%d, rank:%d\n", chn, rk); - auto_refresh_switch(chn, 0); + auto_refresh_switch(chn, false); cmd_bus_training(chn, rk, pams); dramc_write_leveling(chn, rk, pams->wr_level); - auto_refresh_switch(chn, 1); + auto_refresh_switch(chn, true); dramc_rx_dqs_gating_cal(chn, rk); + dramc_window_perbit_cal(chn, rk, RX_WIN_RD_DQC, pams); + dramc_window_perbit_cal(chn, rk, TX_WIN_DQ_DQM, pams); + dramc_window_perbit_cal(chn, rk, TX_WIN_DQ_ONLY, pams); + dramc_window_perbit_cal(chn, rk, RX_WIN_TEST_ENG, pams); } dramc_rx_dqs_gating_post_process(chn); diff --git a/src/soc/mediatek/mt8183/emi.c b/src/soc/mediatek/mt8183/emi.c index a4ac4ab4d9..c1d9250f28 100644 --- a/src/soc/mediatek/mt8183/emi.c +++ b/src/soc/mediatek/mt8183/emi.c @@ -131,7 +131,7 @@ static void set_rank_info_to_conf(const struct sdram_params *params) static void set_MRR_pinmux_mapping(void) { - for (u8 chn = 0; chn < CHANNEL_MAX; chn++) { + for (size_t chn = 0; chn < CHANNEL_MAX; chn++) { const u8 *map = phy_mapping[chn]; write32(&ch[chn].ao.mrr_bit_mux1, (map[0] << 0) | (map[1] << 8) | diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h b/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h index 3fb8c25d47..7b3215840d 100644 --- a/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h +++ b/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h @@ -27,17 +27,11 @@ #define dramc_dbg(_x_...) #endif -#define ENABLE 1 -#define DISABLE 0 - #define DATLAT_TAP_NUMBER 32 -#define MAX_CMP_CPT_WAIT_LOOP 10000 -#define TIME_OUT_CNT 100 - #define DRAMC_BROADCAST_ON 0x1f #define DRAMC_BROADCAST_OFF 0x0 -#define MAX_BACKUP_REG_CNT 32 +#define TX_DQ_COARSE_TUNE_TO_FINE_TUNE_TAP 64 #define IMP_LP4X_TERM_VREF_SEL 0x1b #define IMP_DRVP_LP4X_UNTERM_VREF_SEL 0x1a @@ -50,11 +44,6 @@ enum dram_te_op { }; enum { - DBI_OFF = 0, - DBI_ON -}; - -enum { FSP_0 = 0, FSP_1, FSP_MAX @@ -75,17 +64,6 @@ enum { }; enum { - GATING_OFF = 0, - GATING_ON = 1 -}; - -enum { - CKE_FIXOFF = 0, - CKE_FIXON, - CKE_DYNAMIC -}; - -enum { GATING_PATTERN_NUM = 0x23, GATING_GOLDEND_DQSCNT = 0x4646 }; diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_register.h b/src/soc/mediatek/mt8183/include/soc/dramc_register.h index 5d79b4949b..2487504a28 100644 --- a/src/soc/mediatek/mt8183/include/soc/dramc_register.h +++ b/src/soc/mediatek/mt8183/include/soc/dramc_register.h @@ -1145,7 +1145,7 @@ enum { }; enum { - SHU1_BX_DQ7_R_DMDQMDBI_SHU_SHIFT = 7, + SHU1_BX_DQ7_R_DMDQMDBI_SHIFT = 7, SHU1_BX_DQ7_R_DMRANKRXDVS_SHIFT = 0, SHU1_BX_DQ7_R_DMRANKRXDVS_MASK = 0x0000000f, }; diff --git a/src/soc/mediatek/mt8183/include/soc/emi.h b/src/soc/mediatek/mt8183/include/soc/emi.h index 22331ae42b..81e3d91daa 100644 --- a/src/soc/mediatek/mt8183/include/soc/emi.h +++ b/src/soc/mediatek/mt8183/include/soc/emi.h @@ -33,6 +33,8 @@ struct sdram_params { u16 delay_cell_unit; }; +extern const u8 phy_mapping[CHANNEL_MAX][16]; + int complex_mem_test(u8 *start, unsigned int len); size_t sdram_size(void); const struct sdram_params *get_sdram_config(void); diff --git a/src/soc/mediatek/mt8183/include/soc/memlayout.ld b/src/soc/mediatek/mt8183/include/soc/memlayout.ld index f148eed519..2a6d42de63 100644 --- a/src/soc/mediatek/mt8183/include/soc/memlayout.ld +++ b/src/soc/mediatek/mt8183/include/soc/memlayout.ld @@ -39,7 +39,7 @@ SECTIONS SRAM_END(0x00120000) SRAM_L2C_START(0x00200000) - OVERLAP_DECOMPRESSOR_ROMSTAGE(0x000201000, 92K) + OVERLAP_DECOMPRESSOR_ROMSTAGE(0x000201000, 110K) BOOTBLOCK(0x00227000, 89K) VERSTAGE(0x0023E000, 114K) SRAM_L2C_END(0x00280000) |