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>
This commit is contained in:
parent
107927b319
commit
cea735cf12
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
dramc_show("Start K, current clock is:%d\n", params->frequency);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
current_freqsel = freq_tbl[shuffle];
|
||||
params = &dparam->freq_params[shuffle];
|
||||
|
||||
set_vcore_voltage(current_freqsel);
|
||||
bool first_run = true;
|
||||
set_vdram1_vddq_voltage();
|
||||
init_dram(params, current_freqsel);
|
||||
if (do_calib(params, current_freqsel) != 0)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (run_calib(dparam, DRAM_DFS_SHUFFLE_1, &first_run) != 0)
|
||||
return -1;
|
||||
|
||||
after_calib();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue