From 9e685b764ac6ab41e6c7cb5f7cd3d147506d9dc6 Mon Sep 17 00:00:00 2001 From: Huayang Duan Date: Tue, 23 Jun 2020 16:26:26 +0800 Subject: soc/mediatek/mt8192: Add DDR mode register init Signed-off-by: Huayang Duan Change-Id: If200f4dcef0b1d0b7e901d4ae6e667b1f75156f5 Reviewed-on: https://review.coreboot.org/c/coreboot/+/44711 Tested-by: build bot (Jenkins) Reviewed-by: Yu-Ping Wu --- src/soc/mediatek/mt8192/Makefile.inc | 3 +- src/soc/mediatek/mt8192/dramc_dvfs.c | 106 ++++++++++ src/soc/mediatek/mt8192/dramc_pi_basic_api.c | 300 +++++++++++++++++++++++++++ 3 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 src/soc/mediatek/mt8192/dramc_dvfs.c (limited to 'src/soc') diff --git a/src/soc/mediatek/mt8192/Makefile.inc b/src/soc/mediatek/mt8192/Makefile.inc index ccf571e760..cb3b6c2873 100644 --- a/src/soc/mediatek/mt8192/Makefile.inc +++ b/src/soc/mediatek/mt8192/Makefile.inc @@ -27,7 +27,8 @@ verstage-y += ../common/uart.c romstage-y += ../common/auxadc.c romstage-y += ../common/cbmem.c -romstage-y += dramc_pi_main.c dramc_pi_basic_api.c dramc_pi_calibration_api.c dramc_utility.c +romstage-y += dramc_pi_main.c dramc_pi_basic_api.c dramc_pi_calibration_api.c +romstage-y += dramc_utility.c dramc_dvfs.c romstage-y += emi.c romstage-y += flash_controller.c romstage-y += ../common/gpio.c gpio.c diff --git a/src/soc/mediatek/mt8192/dramc_dvfs.c b/src/soc/mediatek/mt8192/dramc_dvfs.c new file mode 100644 index 0000000000..c784dfb090 --- /dev/null +++ b/src/soc/mediatek/mt8192/dramc_dvfs.c @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include + +void enable_dfs_hw_mode_clk(void) +{ + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) { + SET32_BITFIELDS(&ch[chn].phy_ao.misc_dvfsctl3, + MISC_DVFSCTL3_RG_DVFS_MEM_CK_SEL_DESTI, 0x3, + MISC_DVFSCTL3_RG_DVFS_MEM_CK_SEL_SOURCE, 0x1); + SET32_BITFIELDS(&ch[chn].phy_ao.misc_clk_ctrl, + MISC_CLK_CTRL_DVFS_MEM_CK_MUX_UPDATE_EN, 0x1, + MISC_CLK_CTRL_DVFS_CLK_MEM_SEL, 0x1, + MISC_CLK_CTRL_DVFS_MEM_CK_MUX_SEL_MODE, 0x0, + MISC_CLK_CTRL_DVFS_MEM_CK_MUX_SEL, 0x1); + } +} + +void dramc_dfs_direct_jump_rg_mode(const struct ddr_cali *cali, u8 shu_level) +{ + u8 shu_ack = 0; + u8 tmp_level; + u8 pll_mode = *(cali->pll_mode); + u32 *shu_ack_reg = &mtk_dpm->status_4; + + if (pll_mode == PHYPLL_MODE) { + dramc_dbg("Disable CLRPLL\n"); + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.clrpll0, CLRPLL0_RG_RCLRPLL_EN, 0); + } else { + dramc_dbg("Disable PHYPLL\n"); + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.phypll0, PHYPLL0_RG_RPHYPLL_EN, 0); + } + + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) + shu_ack |= (0x1 << chn); + + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.misc_rg_dfs_ctrl, + MISC_RG_DFS_CTRL_RG_DDRPHY_FB_CK_EN, 1); + + if (shu_level == DRAM_DFS_SHU0) + tmp_level = shu_level; + else + tmp_level = 1; + + if (pll_mode == PHYPLL_MODE) { + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) { + SET32_BITFIELDS(&ch[chn].phy_ao.misc_rg_dfs_ctrl, + MISC_RG_DFS_CTRL_RG_PHYPLL_SHU_EN, 0); + SET32_BITFIELDS(&ch[chn].phy_ao.misc_rg_dfs_ctrl, + MISC_RG_DFS_CTRL_RG_DR_SHU_LEVEL, tmp_level); + SET32_BITFIELDS(&ch[chn].phy_ao.misc_rg_dfs_ctrl, + MISC_RG_DFS_CTRL_RG_PHYPLL2_SHU_EN, 1); + } + dramc_dbg("Enable CLRPLL\n"); + } else { + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) { + SET32_BITFIELDS(&ch[chn].phy_ao.misc_rg_dfs_ctrl, + MISC_RG_DFS_CTRL_RG_PHYPLL2_SHU_EN, 0); + SET32_BITFIELDS(&ch[chn].phy_ao.misc_rg_dfs_ctrl, + MISC_RG_DFS_CTRL_RG_DR_SHU_LEVEL, tmp_level); + SET32_BITFIELDS(&ch[chn].phy_ao.misc_rg_dfs_ctrl, + MISC_RG_DFS_CTRL_RG_PHYPLL_SHU_EN, 1); + } + dramc_dbg("Enable PHYPLL\n"); + } + udelay(1); + + if (pll_mode == PHYPLL_MODE) + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.clrpll0, CLRPLL0_RG_RCLRPLL_EN, 1); + else + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.phypll0, PHYPLL0_RG_RPHYPLL_EN, 1); + + udelay(20); + + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.misc_rg_dfs_ctrl, + MISC_RG_DFS_CTRL_RG_DR_SHU_EN, 1); + while ((READ32_BITFIELD(shu_ack_reg, LPIF_STATUS_4_SHU_EN_ACK) & shu_ack) != shu_ack) + dramc_dbg("Waiting shu_en ack\n"); + + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.misc_rg_dfs_ctrl, + MISC_RG_DFS_CTRL_RG_DR_SHU_EN, 0); + + if (pll_mode == PHYPLL_MODE) + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.phypll0, PHYPLL0_RG_RPHYPLL_EN, 0); + else + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.clrpll0, CLRPLL0_RG_RCLRPLL_EN, 0); + + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.misc_rg_dfs_ctrl, + MISC_RG_DFS_CTRL_RG_DDRPHY_FB_CK_EN, 0); + + dramc_dbg("Shuffle flow completed\n"); + + pll_mode = !pll_mode; + *(cali->pll_mode) = pll_mode; +} diff --git a/src/soc/mediatek/mt8192/dramc_pi_basic_api.c b/src/soc/mediatek/mt8192/dramc_pi_basic_api.c index eeeeceae8a..e2ca919260 100644 --- a/src/soc/mediatek/mt8192/dramc_pi_basic_api.c +++ b/src/soc/mediatek/mt8192/dramc_pi_basic_api.c @@ -3,6 +3,7 @@ #include #include #include +#include static const u8 mrr_o1_pinmux_mapping[PINMUX_MAX][CHANNEL_MAX][DQ_DATA_WIDTH] = { [PINMUX_DSC] = { @@ -108,6 +109,74 @@ void global_option_init(struct ddr_cali *cali) set_dqo1_pinmux_mapping(cali); } +static void dramc_init_default_mr_value(const struct ddr_cali *cali) +{ + struct mr_values *mr_value = cali->mr_value; + dram_freq_grp freq_group = cali->freq_group; + u8 highest_freq = get_highest_freq_group(); + + mr_value->mr01[FSP_0] = 0x26; + mr_value->mr01[FSP_1] = 0x56; + mr_value->mr02[FSP_0] = 0x1a; + mr_value->mr02[FSP_1] = 0x1a; + + mr_value->mr03[FSP_0] = 0x30 | 0x4; + mr_value->mr03[FSP_1] = 0x30 | 0x4 | 0x2; + + mr_value->mr04[RANK_0] = 0x3; + mr_value->mr04[RANK_1] = 0x3; + + mr_value->mr21[FSP_0] = 0x0; + mr_value->mr21[FSP_1] = 0x0; + mr_value->mr51[FSP_0] = 0x0; + mr_value->mr51[FSP_1] = 0x0; + + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) + for (u8 rk = 0; rk < RANK_MAX; rk++) { + mr_value->mr23[chn][rk] = 0x3f; + for (u8 fsp = 0; fsp < FSP_MAX; fsp++) { + mr_value->mr14[chn][rk][fsp] = (fsp == FSP_0) ? 0x5d : 0x18; + mr_value->mr12[chn][rk][fsp] = (fsp == FSP_0) ? 0x5d : 0x1b; + } + } + + mr_value->mr01[FSP_0] &= 0x8F; + mr_value->mr01[FSP_1] &= 0x8F; + + if (highest_freq == DDRFREQ_2133) { + mr_value->mr01[FSP_0] |= (0x7 << 4); + mr_value->mr01[FSP_1] |= (0x7 << 4); + } else { + mr_value->mr01[FSP_0] |= (0x5 << 4); + mr_value->mr01[FSP_1] |= (0x5 << 4); + } + + switch (freq_group) { + case DDRFREQ_400: + mr_value->mr02[FSP_0] = 0x12; + break; + case DDRFREQ_600: + case DDRFREQ_800: + mr_value->mr02[FSP_0] = 0x12; + break; + case DDRFREQ_933: + mr_value->mr02[FSP_0] = 0x1b; + break; + case DDRFREQ_1200: + mr_value->mr02[FSP_0] = 0x24; + break; + case DDRFREQ_1600: + mr_value->mr02[FSP_1] = 0x2d; + break; + case DDRFREQ_2133: + mr_value->mr02[FSP_1] = 0x3f; + break; + default: + die("Invalid DDR frequency group %u\n", freq_group); + return; + } +} + static void sv_algorithm_assistance_lp4_800(void) { SET32_BITFIELDS(&ch[0].phy_ao.shu_misc_rdsel_track, @@ -3700,6 +3769,235 @@ void cke_fix_onoff(const struct ddr_cali *cali, u8 chn, u8 rank, int option) } } +static void dramc_power_on_sequence(const struct ddr_cali *cali) +{ + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) { + SET32_BITFIELDS(&ch[chn].phy_ao.misc_ctrl1, + MISC_CTRL1_R_DMDA_RRESETB_I, 0x0); + cke_fix_onoff(cali, chn, RANK_MAX, CKE_FIXOFF); + udelay(200); + SET32_BITFIELDS(&ch[chn].phy_ao.misc_ctrl1, + MISC_CTRL1_R_DMDA_RRESETB_I, 0x1); + SET32_BITFIELDS(&ch[chn].ao.dramc_pd_ctrl, + DRAMC_PD_CTRL_APHYCKCG_FIXOFF, 1); + SET32_BITFIELDS(&ch[chn].ao.dramc_pd_ctrl, + DRAMC_PD_CTRL_TCKFIXON, 1); + mdelay(2); + cke_fix_onoff(cali, chn, RANK_MAX, CKE_FIXON); + udelay(2); + SET32_BITFIELDS(&ch[chn].ao.dramc_pd_ctrl, + DRAMC_PD_CTRL_TCKFIXON, 0); + SET32_BITFIELDS(&ch[chn].ao.dramc_pd_ctrl, + DRAMC_PD_CTRL_APHYCKCG_FIXOFF, 0); + } +} + +static void dramc_zq_calibration(const struct ddr_cali *cali, u8 chn, u8 rank) +{ + const u32 timeout = 100; + + struct reg_bak regs_bak[] = { + {&ch[chn].ao.swcmd_en}, + {&ch[chn].ao.swcmd_ctrl0}, + {&ch[chn].ao.dramc_pd_ctrl}, + {&ch[chn].ao.ckectrl}, + }; + + for (int i = 0; i < ARRAY_SIZE(regs_bak); i++) + regs_bak[i].value = read32(regs_bak[i].addr); + + SET32_BITFIELDS(&ch[chn].ao.dramc_pd_ctrl, DRAMC_PD_CTRL_APHYCKCG_FIXOFF, 1); + SET32_BITFIELDS(&ch[chn].ao.dramc_pd_ctrl, DRAMC_PD_CTRL_TCKFIXON, 1); + udelay(1); + cke_fix_onoff(cali, chn, rank, CKE_FIXON); + SET32_BITFIELDS(&ch[chn].ao.swcmd_ctrl0, SWCMD_CTRL0_SWTRIG_ZQ_RK, rank); + SET32_BITFIELDS(&ch[chn].ao.swcmd_en, SWCMD_EN_ZQCEN_SWTRIG, 1); + if (!wait_us(timeout, READ32_BITFIELD(&ch[chn].nao.spcmdresp3, + SPCMDRESP3_ZQC_SWTRIG_RESPONSE))) { + dramc_err("ZQCAL Start failed (time out)\n"); + return; + } + SET32_BITFIELDS(&ch[chn].ao.swcmd_en, SWCMD_EN_ZQCEN_SWTRIG, 0); + + udelay(1); + SET32_BITFIELDS(&ch[chn].ao.swcmd_en, SWCMD_EN_ZQLATEN_SWTRIG, 1); + if (!wait_us(timeout, READ32_BITFIELD(&ch[chn].nao.spcmdresp3, + SPCMDRESP3_ZQLAT_SWTRIG_RESPONSE))) { + dramc_err("ZQCAL Latch failed (time out)\n"); + return; + } + SET32_BITFIELDS(&ch[chn].ao.swcmd_en, SWCMD_EN_ZQLATEN_SWTRIG, 0); + + udelay(1); + for (int i = 0; i < ARRAY_SIZE(regs_bak); i++) + write32(regs_bak[i].addr, regs_bak[i].value); +} + +void dramc_mode_reg_write_by_rank(const struct ddr_cali *cali, + u8 chn, u8 rank, u8 mr_idx, u8 value) +{ + u32 bk_bak, ckectrl_bak; + dramc_info("MRW CH%d RK%d MR%d = %#x\n", chn, rank, mr_idx, value); + + bk_bak = READ32_BITFIELD(&ch[chn].ao.swcmd_ctrl0, SWCMD_CTRL0_MRSRK); + ckectrl_bak = read32(&ch[chn].ao.ckectrl); + + SET32_BITFIELDS(&ch[chn].ao.swcmd_ctrl0, SWCMD_CTRL0_MRSRK, rank); + cke_fix_onoff(cali, chn, rank, CKE_FIXON); + SET32_BITFIELDS(&ch[chn].ao.swcmd_ctrl0, SWCMD_CTRL0_MRSMA, mr_idx); + SET32_BITFIELDS(&ch[chn].ao.swcmd_ctrl0, SWCMD_CTRL0_MRSOP, value); + SET32_BITFIELDS(&ch[chn].ao.swcmd_en, SWCMD_EN_MRWEN, 1); + while (READ32_BITFIELD(&ch[chn].nao.spcmdresp, SPCMDRESP_MRW_RESPONSE) == 0) + udelay(1); + + SET32_BITFIELDS(&ch[chn].ao.swcmd_en, SWCMD_EN_MRWEN, 0); + write32(&ch[chn].ao.ckectrl, ckectrl_bak); + SET32_BITFIELDS(&ch[chn].ao.swcmd_ctrl0, SWCMD_CTRL0_MRSRK, bk_bak); +} + +void cbt_switch_freq(const struct ddr_cali *cali, cbt_freq freq) +{ + static u8 _cur_freq = CBT_UNKNOWN_FREQ; + + /* if frequency is the same as before, do nothing */ + if (_cur_freq == freq) + return; + _cur_freq = freq; + + enable_dfs_hw_mode_clk(); + + if (freq == CBT_LOW_FREQ) + dramc_dfs_direct_jump_rg_mode(cali, DRAM_DFS_SHU1); + else + dramc_dfs_direct_jump_rg_mode(cali, DRAM_DFS_SHU0); + + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.misc_clk_ctrl, + MISC_CLK_CTRL_DVFS_CLK_MEM_SEL, 0, + MISC_CLK_CTRL_DVFS_MEM_CK_MUX_UPDATE_EN, 0); +} + +static void dramc_mode_reg_init(const struct ddr_cali *cali) +{ + u8 chn; + u8 set_mrsrk; + u8 operate_fsp = get_fsp(cali); + struct mr_values *mr_value = cali->mr_value; + + u32 bc_bak = dramc_get_broadcast(); + dramc_set_broadcast(DRAMC_BROADCAST_OFF); + dramc_power_on_sequence(cali); + + if (get_fsp(cali) == FSP_1) { + for (chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.ca_cmd2, + CA_CMD2_RG_TX_ARCMD_OE_DIS_CA, 1, + CA_CMD2_RG_TX_ARCA_OE_TIE_SEL_CA, 0, + CA_CMD2_RG_TX_ARCA_OE_TIE_EN_CA, 0xff); + cbt_switch_freq(cali, CBT_LOW_FREQ); + for (chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.ca_cmd2, + CA_CMD2_RG_TX_ARCMD_OE_DIS_CA, 0, + CA_CMD2_RG_TX_ARCA_OE_TIE_SEL_CA, 1, + CA_CMD2_RG_TX_ARCA_OE_TIE_EN_CA, 0xff); + } + + for (chn = 0; chn < CHANNEL_MAX; chn++) { + for (u8 rk = 0; rk < cali->support_ranks; rk++) { + dramc_dbg("ModeRegInit CH%u RK%u\n", chn, rk); + for (u8 fsp = FSP_0; fsp < FSP_MAX; fsp++) { + if (fsp == FSP_0) { + dramc_dbg("FSP0\n"); + mr_value->mr13[rk] = BIT(4) | BIT(3); + mr_value->mr22[fsp] = 0x38; + mr_value->mr11[fsp] = 0x0; + } else { + dramc_dbg("FSP1\n"); + mr_value->mr13[rk] |= 0x40; + + if (cali->cbt_mode[rk] == CBT_NORMAL_MODE) + mr_value->mr11[fsp] = 0x3 | 0x40; + else + mr_value->mr11[fsp] = 0x3 | 0x20; + + if (rk == RANK_0) + mr_value->mr22[fsp] = 0x4; + else + mr_value->mr22[fsp] = 0x2c; + } + + dramc_mode_reg_write_by_rank(cali, chn, rk, 13, + mr_value->mr13[rk]); + dramc_mode_reg_write_by_rank(cali, chn, rk, 12, + mr_value->mr12[chn][rk][fsp]); + dramc_mode_reg_write_by_rank(cali, chn, rk, 1, + mr_value->mr01[fsp]); + dramc_mode_reg_write_by_rank(cali, chn, rk, 2, + mr_value->mr02[fsp]); + dramc_mode_reg_write_by_rank(cali, chn, rk, 11, + mr_value->mr11[fsp]); + dramc_mode_reg_write_by_rank(cali, chn, rk, 21, + mr_value->mr21[fsp]); + dramc_mode_reg_write_by_rank(cali, chn, rk, 51, + mr_value->mr51[fsp]); + dramc_mode_reg_write_by_rank(cali, chn, rk, 22, + mr_value->mr22[fsp]); + dramc_mode_reg_write_by_rank(cali, chn, rk, 14, + mr_value->mr14[chn][rk][fsp]); + dramc_mode_reg_write_by_rank(cali, chn, rk, 3, + mr_value->mr03[fsp]); + dramc_mode_reg_write_by_rank(cali, chn, rk, 4, + mr_value->mr04[rk]); + dramc_mode_reg_write_by_rank(cali, chn, rk, 3, + mr_value->mr03[fsp]); + } + + dramc_zq_calibration(cali, chn, rk); + + if (operate_fsp == FSP_0) + mr_value->mr13[rk] &= 0x3f; + else + mr_value->mr13[rk] |= 0xc0; + } + + if (cali->support_ranks == DUAL_RANK_DDR) + set_mrsrk = 0x3; + else + set_mrsrk = RANK_0; + + dramc_mode_reg_write_by_rank(cali, chn, set_mrsrk, 13, mr_value->mr13[RANK_0]); + + SET32_BITFIELDS(&ch[chn].ao.shu_hwset_mr13, + SHU_HWSET_MR13_HWSET_MR13_OP, mr_value->mr13[RANK_0] | BIT(3), + SHU_HWSET_MR13_HWSET_MR13_MRSMA, 13); + SET32_BITFIELDS(&ch[chn].ao.shu_hwset_vrcg, + SHU_HWSET_VRCG_HWSET_VRCG_OP, mr_value->mr13[RANK_0] | BIT(3), + SHU_HWSET_VRCG_HWSET_VRCG_MRSMA, 13); + SET32_BITFIELDS(&ch[chn].ao.shu_hwset_mr2, + SHU_HWSET_MR2_HWSET_MR2_OP, mr_value->mr02[operate_fsp], + SHU_HWSET_MR2_HWSET_MR2_MRSMA, 2); + } + + if (operate_fsp == FSP_1) { + for (chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.ca_cmd2, + CA_CMD2_RG_TX_ARCMD_OE_DIS_CA, 1, + CA_CMD2_RG_TX_ARCA_OE_TIE_SEL_CA, 0, + CA_CMD2_RG_TX_ARCA_OE_TIE_EN_CA, 0xff); + cbt_switch_freq(cali, CBT_HIGH_FREQ); + for (chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].phy_ao.ca_cmd2, + CA_CMD2_RG_TX_ARCMD_OE_DIS_CA, 0, + CA_CMD2_RG_TX_ARCA_OE_TIE_SEL_CA, 1, + CA_CMD2_RG_TX_ARCA_OE_TIE_EN_CA, 0xff); + } + + for (chn = 0; chn < CHANNEL_MAX; chn++) + SET32_BITFIELDS(&ch[chn].ao.swcmd_ctrl0, SWCMD_CTRL0_MRSRK, RANK_0); + + dramc_set_broadcast(bc_bak); +} + static void set_cke2rank_independent(void) { for (u8 chn = 0; chn < CHANNEL_MAX; chn++) { @@ -3792,6 +4090,7 @@ static void dramc_init(const struct ddr_cali *cali) dramc_reset_delay_chain_before_calibration(); dramc_8_phase_cal(cali); dramc_duty_calibration(cali->params); + dramc_mode_reg_init(cali); } static void dramc_before_calibration(const struct ddr_cali *cali) @@ -3870,6 +4169,7 @@ static void dramc_before_calibration(const struct ddr_cali *cali) void dfs_init_for_calibration(const struct ddr_cali *cali) { + dramc_init_default_mr_value(cali); dramc_init(cali); dramc_before_calibration(cali); } -- cgit v1.2.3