From cea735cf127e090fbb5fa588bd5d7bd3c959e49f Mon Sep 17 00:00:00 2001 From: Huayang Duan Date: Tue, 24 Sep 2019 14:07:11 +0800 Subject: soc/mediatek/mt8183: Run calibration with multiple frequencies for DVFS switch The patch adds config MT8183_DRAM_DVFS to enable DRAM calibration with multiple frequencies to support DVFS switch. BUG=b:80501386,b:142358843 BRANCH=kukui TEST=Boots correctly on Kukui Change-Id: I97c8e513dc3815a2d62b2904a246a1d8567704a4 Signed-off-by: Yu-Ping Wu Reviewed-on: https://review.coreboot.org/c/coreboot/+/35555 Tested-by: build bot (Jenkins) Reviewed-by: Hung-Te Lin --- src/soc/mediatek/mt8183/Kconfig | 7 + src/soc/mediatek/mt8183/dramc_init_setting.c | 44 +++++- src/soc/mediatek/mt8183/dramc_pi_calibration_api.c | 8 +- src/soc/mediatek/mt8183/emi.c | 172 ++++++++++++++++++--- .../mediatek/mt8183/include/soc/dramc_register.h | 2 +- 5 files changed, 207 insertions(+), 26 deletions(-) (limited to 'src/soc') diff --git a/src/soc/mediatek/mt8183/Kconfig b/src/soc/mediatek/mt8183/Kconfig index 5ded0d3801..46249be038 100644 --- a/src/soc/mediatek/mt8183/Kconfig +++ b/src/soc/mediatek/mt8183/Kconfig @@ -30,6 +30,13 @@ config MT8183_DRAM_EMCP The eMCP platform should select this option to run at different DRAM frequencies. +config MT8183_DRAM_DVFS + bool + default y + help + This options enables DRAM calibration with multiple frequencies (low, + medium and high) for DVFS feature. + config MEMORY_TEST bool default y diff --git a/src/soc/mediatek/mt8183/dramc_init_setting.c b/src/soc/mediatek/mt8183/dramc_init_setting.c index 32a8dd17a6..cef77a76fc 100644 --- a/src/soc/mediatek/mt8183/dramc_init_setting.c +++ b/src/soc/mediatek/mt8183/dramc_init_setting.c @@ -43,6 +43,40 @@ static void cke_fix_onoff(int option, u8 chn) (0x1 << 6) | (0x1 << 7), (on << 6) | (off << 7)); } +static void dvfs_settings(u8 freq_group) +{ + u8 dll_idle; + + switch (freq_group) { + case LP4X_DDR1600: + dll_idle = 0x18; + break; + case LP4X_DDR2400: + dll_idle = 0x10; + break; + case LP4X_DDR3200: + dll_idle = 0xc; + break; + case LP4X_DDR3600: + dll_idle = 0xa; + break; + default: + die("Invalid DDR frequency group %u\n", freq_group); + return; + } + + dll_idle = dll_idle << 1; + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) { + setbits_le32(&ch[chn].ao.dvfsdll, 0x1 << 5); + setbits_le32(&ch[chn].phy.dvfs_emi_clk, 0x1 << 29); + clrsetbits_le32(&ch[0].ao.shuctrl2, 0x7f, dll_idle); + + setbits_le32(&ch[0].phy.misc_ctrl0, 0x3 << 19); + setbits_le32(&ch[chn].phy.dvfs_emi_clk, 0x1 << 24); + setbits_le32(&ch[chn].ao.dvfsdll, 0x1 << 7); + } +} + static void ddr_phy_pll_setting(u8 chn, u8 freq_group) { u8 cap_sel, mid_cap_sel; @@ -1268,6 +1302,8 @@ static void dramc_setting(const struct sdram_params *params, u8 freq_group) setbits_le32(&ch[0].ao.dramc_pd_ctrl, 0x1 << 0); clrsetbits_le32(&ch[0].ao.eyescan, (0x1 << 1) | (0xf << 16), (0x0 << 1) | (0x1 << 16)); setbits_le32(&ch[0].ao.stbcal1, (0x1 << 10) | (0x1 << 11)); + clrsetbits_le32(&ch[0].ao.test2_1, 0xfffffff << 4, 0x10000 << 4); + clrsetbits_le32(&ch[0].ao.test2_2, 0xfffffff << 4, 0x400 << 4); clrsetbits_le32(&ch[0].ao.test2_3, (0x1 << 7) | (0x7 << 8) | (0x1 << 28), (0x1 << 7) | (0x4 << 8) | (0x1 << 28)); @@ -1277,15 +1313,14 @@ static void dramc_setting(const struct sdram_params *params, u8 freq_group) udelay(1); clrsetbits_le32(&ch[0].ao.hw_mrr_fun, (0xf << 0) | (0xf << 4), (0x8 << 0) | (0x6 << 4)); + clrbits_le32(&ch[0].ao.dramctrl, 0x1 << 0); clrsetbits_le32(&ch[0].ao.perfctl0, (0x1 << 18) | (0x1 << 19), (0x0 << 18) | (0x1 << 19)); + setbits_le32(&ch[0].ao.spcmdctrl, 0x1 << 28); clrbits_le32(&ch[0].ao.rstmask, 0x1 << 28); setbits_le32(&ch[0].ao.rkcfg, 0x1 << 11); - setbits_le32(&ch[0].ao.spcmdctrl, 0x1 << 28); - setbits_le32(&ch[0].ao.eyescan, 0x1 << 2); - - clrbits_le32(&ch[0].ao.dramctrl, 0x1 << 0); setbits_le32(&ch[0].ao.mpc_option, 0x1 << 17); + setbits_le32(&ch[0].ao.eyescan, 0x1 << 2); setbits_le32(&ch[0].ao.shu[0].wodt, 0x1 << 29); setbits_le32(&ch[0].phy.shu[0].b[0].dq[7], 0x1 << 7); setbits_le32(&ch[0].phy.shu[0].b[1].dq[7], 0x1 << 7); @@ -1699,6 +1734,7 @@ void dramc_init(const struct sdram_params *params, u8 freq_group) dramc_setting(params, freq_group); dramc_duty_calibration(params, freq_group); + dvfs_settings(freq_group); dramc_mode_reg_init(freq_group); ddr_update_ac_timing(freq_group); diff --git a/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c index 46f48ec868..0c45ea05fa 100644 --- a/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c +++ b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c @@ -414,14 +414,15 @@ void dramc_apply_config_before_calibration(u8 freq_group) clrsetbits_le32(&ch[chn].phy.b[0].dq[6], 0x3 << 0, 0x1 << 0); clrsetbits_le32(&ch[chn].phy.b[1].dq[6], 0x3 << 0, 0x1 << 0); clrsetbits_le32(&ch[chn].phy.ca_cmd[6], 0x3 << 0, 0x1 << 0); + + dramc_rx_input_delay_tracking_init_by_freq(chn); + setbits_le32(&ch[chn].ao.dummy_rd, 0x1 << 25); setbits_le32(&ch[chn].ao.drsctrl, 0x1 << 0); if (freq_group == LP4X_DDR3200 || freq_group == LP4X_DDR3600) clrbits_le32(&ch[chn].ao.shu[1].drving[1], 0x1 << 31); else setbits_le32(&ch[chn].ao.shu[1].drving[1], 0x1 << 31); - - dramc_rx_input_delay_tracking_init_by_freq(chn); } for (size_t r = 0; r < 2; r++) { @@ -2119,11 +2120,11 @@ int dramc_calibrate_all_channels(const struct sdram_params *pams, u8 freq_group) for (u8 rk = RANK_0; rk < RANK_MAX; rk++) { dramc_show("Start K: freq=%d, ch=%d, rank=%d\n", freq_group, chn, rk); - dramc_auto_refresh_switch(chn, false); dramc_cmd_bus_training(chn, rk, freq_group, pams, fast_calib); dramc_write_leveling(chn, rk, freq_group, pams->wr_level); dramc_auto_refresh_switch(chn, true); + dramc_rx_dqs_gating_cal(chn, rk, freq_group, pams, fast_calib); dramc_window_perbit_cal(chn, rk, freq_group, @@ -2138,6 +2139,7 @@ int dramc_calibrate_all_channels(const struct sdram_params *pams, u8 freq_group) return -2; dramc_window_perbit_cal(chn, rk, freq_group, RX_WIN_TEST_ENG, pams, fast_calib); + dramc_auto_refresh_switch(chn, false); } dramc_rx_dqs_gating_post_process(chn, freq_group); diff --git a/src/soc/mediatek/mt8183/emi.c b/src/soc/mediatek/mt8183/emi.c index c644dc3f96..8cdbabfebb 100644 --- a/src/soc/mediatek/mt8183/emi.c +++ b/src/soc/mediatek/mt8183/emi.c @@ -20,6 +20,7 @@ #include #include #include +#include static const u8 freq_shuffle[DRAM_DFS_SHUFFLE_MAX] = { [DRAM_DFS_SHUFFLE_1] = LP4X_DDR3200, @@ -339,6 +340,15 @@ static void dramc_ac_timing_optimize(u8 freq_group) } } +static void spm_pinmux_setting(void) +{ + clrsetbits_le32(&mtk_spm->poweron_config_set, + (0xffff << 16) | (0x1 << 0), (0xb16 << 16) | (0x1 << 0)); + clrbits_le32(&mtk_spm->pcm_pwr_io_en, (0xff << 0) | (0xff << 16)); + write32(&mtk_spm->dramc_dpy_clk_sw_con_sel, 0xffffffff); + write32(&mtk_spm->dramc_dpy_clk_sw_con_sel2, 0xffffffff); +} + static void dfs_init_for_calibration(const struct sdram_params *params, u8 freq_group) { dramc_init(params, freq_group); @@ -352,6 +362,8 @@ static void init_dram(const struct sdram_params *params, u8 freq_group) dramc_set_broadcast(DRAMC_BROADCAST_ON); dramc_init_pre_settings(); + spm_pinmux_setting(); + dramc_sw_impedance_cal(params, ODT_OFF); dramc_sw_impedance_cal(params, ODT_ON); @@ -368,13 +380,143 @@ void enable_emi_dcm(void) clrbits_le32(&ch[chn].emi.chn_conb, 0xff << 24); } -static int do_calib(const struct sdram_params *params, u8 freq_group) +struct shuffle_reg_addr { + u32 start; + u32 end; +}; + +#define AO_SHU_ADDR(s, e) \ + { \ + .start = offsetof(struct dramc_ao_regs_shu, s), \ + .end = offsetof(struct dramc_ao_regs_shu, e), \ + } + +static const struct shuffle_reg_addr dramc_regs[] = { + AO_SHU_ADDR(actim, hwset_vrcg), + AO_SHU_ADDR(rk[0], rk[0].dqs2dq_cal5), + AO_SHU_ADDR(rk[1], rk[1].dqs2dq_cal5), + AO_SHU_ADDR(rk[2], rk[2].dqs2dq_cal5), + AO_SHU_ADDR(dqsg_retry, dqsg_retry), +}; + +#define PHY_SHU_ADDR(s, e) \ + { \ + .start = offsetof(struct ddrphy_ao_shu, s), \ + .end = offsetof(struct ddrphy_ao_shu, e), \ + } + +static const struct shuffle_reg_addr phy_regs[] = { + PHY_SHU_ADDR(b[0], b[0].dll[1]), + PHY_SHU_ADDR(b[1], b[1].dll[1]), + PHY_SHU_ADDR(ca_cmd, ca_dll[1]), + PHY_SHU_ADDR(pll[0], pll[15]), + PHY_SHU_ADDR(pll20, misc0), + PHY_SHU_ADDR(rk[0].b[0], rk[0].b[0].rsvd_20[3]), + PHY_SHU_ADDR(rk[0].b[1], rk[0].b[1].rsvd_20[3]), + PHY_SHU_ADDR(rk[0].ca_cmd, rk[0].rsvd_22[1]), + PHY_SHU_ADDR(rk[1].b[0], rk[1].b[0].rsvd_20[3]), + PHY_SHU_ADDR(rk[1].b[1], rk[1].b[1].rsvd_20[3]), + PHY_SHU_ADDR(rk[1].ca_cmd, rk[1].rsvd_22[1]), + PHY_SHU_ADDR(rk[2].b[0], rk[2].b[0].rsvd_20[3]), + PHY_SHU_ADDR(rk[2].b[1], rk[2].b[1].rsvd_20[3]), + PHY_SHU_ADDR(rk[2].ca_cmd, rk[2].rsvd_22[1]), +}; + +static void dramc_save_result_to_shuffle(u32 src_shuffle, u32 dst_shuffle) +{ + u32 offset, chn, index, value; + u8 *src_addr, *dst_addr; + + if (src_shuffle == dst_shuffle) + return; + + dramc_show("Save shuffle %u to shuffle %u\n", src_shuffle, dst_shuffle); + + for (chn = 0; chn < CHANNEL_MAX; chn++) { + /* DRAMC */ + for (index = 0; index < ARRAY_SIZE(dramc_regs); index++) { + for (offset = dramc_regs[index].start; + offset <= dramc_regs[index].end; offset += 4) { + src_addr = (u8 *)&ch[chn].ao.shu[src_shuffle] + + offset; + dst_addr = (u8 *)&ch[chn].ao.shu[dst_shuffle] + + offset; + write32(dst_addr, read32(src_addr)); + + } + } + dramc_show("the dramc register of chn %d saved!\n", chn); + + /* DRAMC-exception-1 */ + src_addr = (u8 *)&ch[chn].ao.shuctrl2; + dst_addr = (u8 *)&ch[chn].ao.dvfsdll; + value = read32(src_addr) & 0x7f; + + if (dst_shuffle == DRAM_DFS_SHUFFLE_2) + clrsetbits_le32(dst_addr, 0x7f << 0x8, value << 0x8); + else if (dst_shuffle == DRAM_DFS_SHUFFLE_3) + clrsetbits_le32(dst_addr, 0x7f << 0x16, value << 0x16); + + dramc_show("the dramc exception-1 register of chn %d saved!\n", chn); + + /* DRAMC-exception-2 */ + src_addr = (u8 *)&ch[chn].ao.dvfsdll; + value = (read32(src_addr) >> 1) & 0x1; + + if (dst_shuffle == DRAM_DFS_SHUFFLE_2) + clrsetbits_le32(src_addr, 0x1 << 2, value << 2); + else if (dst_shuffle == DRAM_DFS_SHUFFLE_3) + clrsetbits_le32(src_addr, 0x1 << 3, value << 3); + + dramc_show("the dramc exception-2 register of chn %d saved!\n", chn); + + /* PHY */ + for (index = 0; index < ARRAY_SIZE(phy_regs); index++) { + for (offset = phy_regs[index].start; + offset <= phy_regs[index].end; offset += 4) { + src_addr = (u8 *)&ch[chn].phy.shu[src_shuffle] + + offset; + dst_addr = (u8 *)&ch[chn].phy.shu[dst_shuffle] + + offset; + write32(dst_addr, read32(src_addr)); + + } + } + dramc_show("the phy register of chn %d saved!\n", chn); + } +} + +static int run_calib(const struct dramc_param *dparam, + const int shuffle, bool *first_run) { - dramc_show("Start K, current clock is:%d\n", params->frequency); + const u8 *freq_tbl; + + if (CONFIG(MT8183_DRAM_EMCP)) + freq_tbl = freq_shuffle_emcp; + else + freq_tbl = freq_shuffle; + + const u8 freq_group = freq_tbl[shuffle]; + const struct sdram_params *params = &dparam->freq_params[shuffle]; + + set_vcore_voltage(freq_group); + + dramc_show("Run calibration (freq: %u, first: %d)\n", + freq_group, *first_run); + + if (*first_run) + init_dram(params, freq_group); + else + dfs_init_for_calibration(params, freq_group); + *first_run = false; + + dramc_show("Start K (current clock: %u\n", params->frequency); if (dramc_calibrate_all_channels(params, freq_group) != 0) return -1; dramc_ac_timing_optimize(freq_group); - dramc_show("K finish with clock:%d\n", params->frequency); + dramc_show("K finished (current clock: %u\n", params->frequency); + + dramc_save_result_to_shuffle(DRAM_DFS_SHUFFLE_1, shuffle); return 0; } @@ -386,23 +528,17 @@ static void after_calib(void) int mt_set_emi(const struct dramc_param *dparam) { - const u8 *freq_tbl; - const int shuffle = DRAM_DFS_SHUFFLE_1; - u8 current_freqsel; - const struct sdram_params *params; - - if (CONFIG(MT8183_DRAM_EMCP)) - freq_tbl = freq_shuffle_emcp; - else - freq_tbl = freq_shuffle; + bool first_run = true; + set_vdram1_vddq_voltage(); - current_freqsel = freq_tbl[shuffle]; - params = &dparam->freq_params[shuffle]; + if (CONFIG(MT8183_DRAM_DVFS)) { + if (run_calib(dparam, DRAM_DFS_SHUFFLE_3, &first_run) != 0) + return -1; + if (run_calib(dparam, DRAM_DFS_SHUFFLE_2, &first_run) != 0) + return -1; + } - set_vcore_voltage(current_freqsel); - set_vdram1_vddq_voltage(); - init_dram(params, current_freqsel); - if (do_calib(params, current_freqsel) != 0) + if (run_calib(dparam, DRAM_DFS_SHUFFLE_1, &first_run) != 0) return -1; after_calib(); diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_register.h b/src/soc/mediatek/mt8183/include/soc/dramc_register.h index 61019b3110..b3ee6af4c7 100644 --- a/src/soc/mediatek/mt8183/include/soc/dramc_register.h +++ b/src/soc/mediatek/mt8183/include/soc/dramc_register.h @@ -288,7 +288,7 @@ struct dramc_ao_regs { uint32_t rsvd_10[46]; struct dramc_ao_regs_rk rk[3]; uint32_t rsvd_16[64]; - struct { + struct dramc_ao_regs_shu { uint32_t rsvd0[64]; uint32_t actim[7]; uint32_t actim_xrt; -- cgit v1.2.3