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:
Huayang Duan 2019-09-24 14:07:11 +08:00 committed by Patrick Georgi
parent 107927b319
commit cea735cf12
5 changed files with 208 additions and 27 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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;