aboutsummaryrefslogtreecommitdiff
path: root/src/soc/mediatek
diff options
context:
space:
mode:
authorHuayang Duan <huayang.duan@mediatek.com>2019-09-24 14:07:11 +0800
committerPatrick Georgi <pgeorgi@google.com>2019-10-18 12:21:31 +0000
commitcea735cf127e090fbb5fa588bd5d7bd3c959e49f (patch)
treefa9e222b0932791c6bd813f2bb64a1a6fcd61ccc /src/soc/mediatek
parent107927b319d8bdffbe66d596906d06d47b7cbbed (diff)
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 <yupingso@chromium.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/35555 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Diffstat (limited to 'src/soc/mediatek')
-rw-r--r--src/soc/mediatek/mt8183/Kconfig7
-rw-r--r--src/soc/mediatek/mt8183/dramc_init_setting.c44
-rw-r--r--src/soc/mediatek/mt8183/dramc_pi_calibration_api.c8
-rw-r--r--src/soc/mediatek/mt8183/emi.c172
-rw-r--r--src/soc/mediatek/mt8183/include/soc/dramc_register.h2
5 files changed, 207 insertions, 26 deletions
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 <soc/emi.h>
#include <soc/infracfg.h>
#include <soc/mt6358.h>
+#include <soc/spm.h>
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;