diff options
Diffstat (limited to 'drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c')
-rw-r--r-- | drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c | 620 |
1 files changed, 592 insertions, 28 deletions
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c index 7b23db46c121..aa8dccc88dff 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c @@ -95,6 +95,9 @@ #define PLL_PLL_INT_GAIN_IFILT_BAND_1 0x15c #define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x164 #define PLL_FASTLOCK_EN_BAND 0x16c +#define PLL_FREQ_TUNE_ACCUM_INIT_LOW 0x170 +#define PLL_FREQ_TUNE_ACCUM_INIT_MID 0x174 +#define PLL_FREQ_TUNE_ACCUM_INIT_HIGH 0x178 #define PLL_FREQ_TUNE_ACCUM_INIT_MUX 0x17c #define PLL_PLL_LOCK_OVERRIDE 0x180 #define PLL_PLL_LOCK_DELAY 0x184 @@ -112,6 +115,7 @@ #define PHY_CMN_RBUF_CTRL 0x01c #define PHY_CMN_PLL_CNTRL 0x038 #define PHY_CMN_CTRL_0 0x024 +#define PHY_CMN_CTRL_2 0x02c /* Bit definition of SSC control registers */ #define SSC_CENTER BIT(0) @@ -123,6 +127,43 @@ #define SSC_START BIT(6) #define SSC_START_MUX BIT(7) +/* Dynamic Refresh Control Registers */ +#define DSI_DYNAMIC_REFRESH_PLL_CTRL0 (0x014) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL1 (0x018) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL2 (0x01C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL3 (0x020) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL4 (0x024) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL5 (0x028) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL6 (0x02C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL7 (0x030) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL8 (0x034) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL9 (0x038) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL10 (0x03C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL11 (0x040) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL12 (0x044) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL13 (0x048) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL14 (0x04C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL15 (0x050) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL16 (0x054) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL17 (0x058) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL18 (0x05C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL19 (0x060) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL20 (0x064) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL21 (0x068) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL22 (0x06C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL23 (0x070) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL24 (0x074) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL25 (0x078) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL26 (0x07C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL27 (0x080) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL28 (0x084) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL29 (0x088) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL30 (0x08C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL31 (0x090) +#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR (0x094) +#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2 (0x098) + +#define DSI_PHY_TO_PLL_OFFSET (0x600) enum { DSI_PLL_0, DSI_PLL_1, @@ -644,6 +685,7 @@ static int vco_10nm_set_rate(struct clk_hw *hw, unsigned long rate, rsc->vco_current_rate = rate; rsc->vco_ref_clk_rate = vco->ref_clk_rate; + rsc->dfps_trigger = false; rc = mdss_pll_resource_enable(rsc, true); if (rc) { @@ -674,6 +716,237 @@ static int vco_10nm_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +static int dsi_pll_read_stored_trim_codes(struct mdss_pll_resources *pll_res, + unsigned long vco_clk_rate) +{ + int i; + bool found = false; + + if (!pll_res->dfps) + return -EINVAL; + + for (i = 0; i < pll_res->dfps->vco_rate_cnt; i++) { + struct dfps_codes_info *codes_info = + &pll_res->dfps->codes_dfps[i]; + + pr_debug("valid=%d vco_rate=%d, code %d %d %d\n", + codes_info->is_valid, codes_info->clk_rate, + codes_info->pll_codes.pll_codes_1, + codes_info->pll_codes.pll_codes_2, + codes_info->pll_codes.pll_codes_3); + + if (vco_clk_rate != codes_info->clk_rate && + codes_info->is_valid) + continue; + + pll_res->cache_pll_trim_codes[0] = + codes_info->pll_codes.pll_codes_1; + pll_res->cache_pll_trim_codes[1] = + codes_info->pll_codes.pll_codes_2; + pll_res->cache_pll_trim_codes[2] = + codes_info->pll_codes.pll_codes_3; + found = true; + break; + } + + if (!found) + return -EINVAL; + + pr_debug("trim_code_0=0x%x trim_code_1=0x%x trim_code_2=0x%x\n", + pll_res->cache_pll_trim_codes[0], + pll_res->cache_pll_trim_codes[1], + pll_res->cache_pll_trim_codes[2]); + + return 0; +} + +static void shadow_dsi_pll_dynamic_refresh_10nm(struct dsi_pll_10nm *pll, + struct mdss_pll_resources *rsc) +{ + u32 data; + u32 offset = DSI_PHY_TO_PLL_OFFSET; + u32 upper_addr = 0; + struct dsi_pll_regs *reg = &pll->reg_setup; + + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1); + data &= ~BIT(5); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL0, + PHY_CMN_CLK_CFG1, PHY_CMN_PLL_CNTRL, data, 0); + upper_addr |= (upper_8_bit(PHY_CMN_CLK_CFG1) << 0); + upper_addr |= (upper_8_bit(PHY_CMN_PLL_CNTRL) << 1); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL1, + PHY_CMN_RBUF_CTRL, + (PLL_DECIMAL_DIV_START_1 + offset), + 0, reg->decimal_div_start); + upper_addr |= (upper_8_bit(PHY_CMN_RBUF_CTRL) << 2); + upper_addr |= (upper_8_bit(PLL_DECIMAL_DIV_START_1 + offset) << 3); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL2, + (PLL_FRAC_DIV_START_LOW_1 + offset), + (PLL_FRAC_DIV_START_MID_1 + offset), + reg->frac_div_start_low, reg->frac_div_start_mid); + upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_LOW_1 + offset) << 4); + upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_MID_1 + offset) << 5); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL3, + (PLL_FRAC_DIV_START_HIGH_1 + offset), + (PLL_PLL_PROP_GAIN_RATE_1 + offset), + reg->frac_div_start_high, reg->pll_prop_gain_rate); + upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_HIGH_1 + offset) << 6); + upper_addr |= (upper_8_bit(PLL_PLL_PROP_GAIN_RATE_1 + offset) << 7); + + data = MDSS_PLL_REG_R(rsc->pll_base, PLL_PLL_OUTDIV_RATE) & 0x03; + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL4, + (PLL_PLL_OUTDIV_RATE + offset), + (PLL_FREQ_TUNE_ACCUM_INIT_LOW + offset), + data, 0); + upper_addr |= (upper_8_bit(PLL_PLL_OUTDIV_RATE + offset) << 8); + upper_addr |= (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_LOW + offset) << 9); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL5, + (PLL_FREQ_TUNE_ACCUM_INIT_MID + offset), + (PLL_FREQ_TUNE_ACCUM_INIT_HIGH + offset), + rsc->cache_pll_trim_codes[1], + rsc->cache_pll_trim_codes[0]); + upper_addr |= + (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_MID + offset) << 10); + upper_addr |= + (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_HIGH + offset) << 11); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL6, + (PLL_FREQ_TUNE_ACCUM_INIT_MUX + offset), + (PLL_PLL_BAND_SET_RATE_1 + offset), + 0x07, rsc->cache_pll_trim_codes[2]); + upper_addr |= + (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_MUX + offset) << 12); + upper_addr |= (upper_8_bit(PLL_PLL_BAND_SET_RATE_1 + offset) << 13); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL7, + (PLL_CALIBRATION_SETTINGS + offset), + (PLL_BAND_SEL_CAL_SETTINGS + offset), 0x44, 0x3a); + upper_addr |= (upper_8_bit(PLL_CALIBRATION_SETTINGS + offset) << 14); + upper_addr |= (upper_8_bit(PLL_BAND_SEL_CAL_SETTINGS + offset) << 15); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL8, + (PLL_PLL_LOCKDET_RATE_1 + offset), + (PLL_PLL_LOCK_DELAY + offset), 0x10, 0x06); + upper_addr |= (upper_8_bit(PLL_PLL_LOCKDET_RATE_1 + offset) << 16); + upper_addr |= (upper_8_bit(PLL_PLL_LOCK_DELAY + offset) << 17); + + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG0); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL17, + PHY_CMN_CTRL_2, PHY_CMN_CLK_CFG0, 0x40, data); + if (rsc->slave) + MDSS_DYN_PLL_REG_W(rsc->slave->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL10, + PHY_CMN_CLK_CFG0, PHY_CMN_CTRL_0, + data, 0x7f); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL18, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + /* Dummy register writes */ + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL19, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL20, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL21, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL22, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL23, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL24, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL25, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL26, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL27, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL28, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL29, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + + /* Registers to configure after PLL enable delay */ + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1) | BIT(5); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL30, + PHY_CMN_CLK_CFG1, PHY_CMN_RBUF_CTRL, data, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL31, + PHY_CMN_CLK_CFG1, PHY_CMN_CLK_CFG1, data, data); + if (rsc->slave) { + data = MDSS_PLL_REG_R(rsc->slave->phy_base, PHY_CMN_CLK_CFG1) | + BIT(5); + MDSS_DYN_PLL_REG_W(rsc->slave->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL30, + PHY_CMN_CLK_CFG1, PHY_CMN_RBUF_CTRL, + data, 0x01); + MDSS_DYN_PLL_REG_W(rsc->slave->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL31, + PHY_CMN_CLK_CFG1, PHY_CMN_CLK_CFG1, + data, data); + } + + MDSS_PLL_REG_W(rsc->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR, upper_addr); + MDSS_PLL_REG_W(rsc->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2, 0); + wmb(); /* commit register writes */ +} + +static int shadow_vco_10nm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int rc; + struct dsi_pll_10nm *pll; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *rsc = vco->priv; + + if (!rsc) { + pr_err("pll resource not found\n"); + return -EINVAL; + } + + pll = rsc->priv; + if (!pll) { + pr_err("pll configuration not found\n"); + return -EINVAL; + } + + rc = dsi_pll_read_stored_trim_codes(rsc, rate); + if (rc) { + pr_err("cannot find pll codes rate=%ld\n", rate); + return -EINVAL; + } + pr_debug("ndx=%d, rate=%lu\n", rsc->index, rate); + + rsc->vco_current_rate = rate; + rsc->vco_ref_clk_rate = vco->ref_clk_rate; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("failed to enable mdss dsi pll(%d), rc=%d\n", + rsc->index, rc); + return rc; + } + + dsi_pll_setup_config(pll, rsc); + + dsi_pll_calc_dec_frac(pll, rsc); + + /* program dynamic refresh control registers */ + shadow_dsi_pll_dynamic_refresh_10nm(pll, rsc); + + /* update cached vco rate */ + rsc->vco_cached_rate = rate; + rsc->dfps_trigger = true; + + mdss_pll_resource_enable(rsc, false); + + return 0; +} + static int dsi_pll_10nm_lock_status(struct mdss_pll_resources *pll) { int rc; @@ -739,7 +1012,7 @@ static int dsi_pll_enable(struct dsi_pll_vco_clk *vco) phy_reg_update_bits_sub(rsc, PHY_CMN_CLK_CFG1, 0x03, rsc->cached_cfg1); if (rsc->slave) phy_reg_update_bits_sub(rsc->slave, PHY_CMN_CLK_CFG1, - 0x03, rsc->cached_cfg1); + 0x03, rsc->slave->cached_cfg1); wmb(); /* ensure dsiclk_sel is always programmed before pll start */ /* Start PLL */ @@ -789,6 +1062,7 @@ static void dsi_pll_disable(struct dsi_pll_vco_clk *vco) } rsc->handoff_resources = false; + rsc->dfps_trigger = false; pr_debug("stop PLL (%d)\n", rsc->index); @@ -840,16 +1114,18 @@ static void vco_10nm_unprepare(struct clk_hw *hw) /* * During unprepare in continuous splash use case we want driver * to pick all dividers instead of retaining bootloader configurations. + * Also handle use cases where dynamic refresh triggered before + * first suspend/resume. */ - if (!pll->handoff_resources) { + if (!pll->handoff_resources || pll->dfps_trigger) { pll->cached_cfg0 = MDSS_PLL_REG_R(pll->phy_base, - PHY_CMN_CLK_CFG0); + PHY_CMN_CLK_CFG0); pll->cached_outdiv = MDSS_PLL_REG_R(pll->pll_base, - PLL_PLL_OUTDIV_RATE); + PLL_PLL_OUTDIV_RATE); pr_debug("cfg0=%d,cfg1=%d, outdiv=%d\n", pll->cached_cfg0, - pll->cached_cfg1, pll->cached_outdiv); + pll->cached_cfg1, pll->cached_outdiv); - pll->vco_cached_rate = clk_hw_get_rate(hw); + pll->vco_cached_rate = clk_get_rate(hw->clk); } /* @@ -859,9 +1135,15 @@ static void vco_10nm_unprepare(struct clk_hw *hw) * does not change.For such usecases, we need to ensure that the cached * value is programmed prior to PLL being locked */ - if (pll->handoff_resources) + if (pll->handoff_resources) { pll->cached_cfg1 = MDSS_PLL_REG_R(pll->phy_base, - PHY_CMN_CLK_CFG1); + PHY_CMN_CLK_CFG1); + if (pll->slave) + pll->slave->cached_cfg1 = + MDSS_PLL_REG_R(pll->slave->phy_base, + PHY_CMN_CLK_CFG1); + } + dsi_pll_disable(vco); mdss_pll_resource_enable(pll, false); } @@ -889,7 +1171,7 @@ static int vco_10nm_prepare(struct clk_hw *hw) } if ((pll->vco_cached_rate != 0) && - (pll->vco_cached_rate == clk_hw_get_rate(hw))) { + (pll->vco_cached_rate == clk_get_rate(hw->clk))) { rc = hw->init->ops->set_rate(hw, pll->vco_cached_rate, pll->vco_cached_rate); if (rc) { @@ -902,6 +1184,9 @@ static int vco_10nm_prepare(struct clk_hw *hw) pll->cached_cfg1); MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, pll->cached_cfg0); + if (pll->slave) + MDSS_PLL_REG_W(pll->slave->phy_base, PHY_CMN_CLK_CFG0, + pll->cached_cfg0); MDSS_PLL_REG_W(pll->pll_base, PLL_PLL_OUTDIV_RATE, pll->cached_outdiv); } @@ -1037,6 +1322,14 @@ static void pixel_clk_set_div_sub(struct mdss_pll_resources *pll, int div) reg_val &= ~0xF0; reg_val |= (div << 4); MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, reg_val); + + /* + * cache the current parent index for cases where parent + * is not changing but rate is changing. In that case + * clock framework won't call parent_set and hence dsiclk_sel + * bit won't be programmed. e.g. dfps update use case. + */ + pll->cached_cfg0 = reg_val; } static int pixel_clk_set_div(void *context, unsigned int reg, unsigned int div) @@ -1174,6 +1467,12 @@ static const struct clk_ops clk_ops_vco_10nm = { .unprepare = vco_10nm_unprepare, }; +static const struct clk_ops clk_ops_shadow_vco_10nm = { + .recalc_rate = vco_10nm_recalc_rate, + .set_rate = shadow_vco_10nm_set_rate, + .round_rate = vco_10nm_round_rate, +}; + static struct regmap_bus mdss_mux_regmap_bus = { .reg_write = mdss_set_mux_sel, .reg_read = mdss_get_mux_sel, @@ -1248,6 +1547,19 @@ static struct dsi_pll_vco_clk dsi0pll_vco_clk = { }, }; +static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1000000000UL, + .max_rate = 3500000000UL, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_vco_clk", + .parent_names = (const char *[]){"bi_tcxo"}, + .num_parents = 1, + .ops = &clk_ops_shadow_vco_10nm, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + static struct dsi_pll_vco_clk dsi1pll_vco_clk = { .ref_clk_rate = 19200000UL, .min_rate = 1000000000UL, @@ -1261,6 +1573,19 @@ static struct dsi_pll_vco_clk dsi1pll_vco_clk = { }, }; +static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1000000000UL, + .max_rate = 3500000000UL, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_vco_clk", + .parent_names = (const char *[]){"bi_tcxo"}, + .num_parents = 1, + .ops = &clk_ops_shadow_vco_10nm, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + static struct clk_regmap_div dsi0pll_pll_out_div = { .reg = PLL_PLL_OUTDIV_RATE, .shift = 0, @@ -1277,6 +1602,23 @@ static struct clk_regmap_div dsi0pll_pll_out_div = { }, }; +static struct clk_regmap_div dsi0pll_shadow_pll_out_div = { + .reg = PLL_PLL_OUTDIV_RATE, + .shift = 0, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_pll_out_div", + .parent_names = (const char *[]){ + "dsi0pll_shadow_vco_clk"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + static struct clk_regmap_div dsi1pll_pll_out_div = { .reg = PLL_PLL_OUTDIV_RATE, .shift = 0, @@ -1293,6 +1635,23 @@ static struct clk_regmap_div dsi1pll_pll_out_div = { }, }; +static struct clk_regmap_div dsi1pll_shadow_pll_out_div = { + .reg = PLL_PLL_OUTDIV_RATE, + .shift = 0, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_pll_out_div", + .parent_names = (const char *[]){ + "dsi1pll_shadow_vco_clk"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + static struct clk_regmap_div dsi0pll_bitclk_src = { .shift = 0, .width = 4, @@ -1307,6 +1666,21 @@ static struct clk_regmap_div dsi0pll_bitclk_src = { }, }; +static struct clk_regmap_div dsi0pll_shadow_bitclk_src = { + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_bitclk_src", + .parent_names = (const char *[]){ + "dsi0pll_shadow_pll_out_div"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + static struct clk_regmap_div dsi1pll_bitclk_src = { .shift = 0, .width = 4, @@ -1321,6 +1695,21 @@ static struct clk_regmap_div dsi1pll_bitclk_src = { }, }; +static struct clk_regmap_div dsi1pll_shadow_bitclk_src = { + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_bitclk_src", + .parent_names = (const char *[]){ + "dsi1pll_shadow_pll_out_div"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + static struct clk_fixed_factor dsi0pll_post_vco_div = { .div = 4, .mult = 1, @@ -1328,7 +1717,19 @@ static struct clk_fixed_factor dsi0pll_post_vco_div = { .name = "dsi0pll_post_vco_div", .parent_names = (const char *[]){"dsi0pll_pll_out_div"}, .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_shadow_post_vco_div = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_post_vco_div", + .parent_names = (const char *[]){"dsi0pll_shadow_pll_out_div"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, .ops = &clk_fixed_factor_ops, }, }; @@ -1340,7 +1741,19 @@ static struct clk_fixed_factor dsi1pll_post_vco_div = { .name = "dsi1pll_post_vco_div", .parent_names = (const char *[]){"dsi1pll_pll_out_div"}, .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_shadow_post_vco_div = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_post_vco_div", + .parent_names = (const char *[]){"dsi1pll_shadow_pll_out_div"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, .ops = &clk_fixed_factor_ops, }, }; @@ -1357,6 +1770,18 @@ static struct clk_fixed_factor dsi0pll_byteclk_src = { }, }; +static struct clk_fixed_factor dsi0pll_shadow_byteclk_src = { + .div = 8, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_byteclk_src", + .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + static struct clk_fixed_factor dsi1pll_byteclk_src = { .div = 8, .mult = 1, @@ -1369,6 +1794,18 @@ static struct clk_fixed_factor dsi1pll_byteclk_src = { }, }; +static struct clk_fixed_factor dsi1pll_shadow_byteclk_src = { + .div = 8, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_byteclk_src", + .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + static struct clk_fixed_factor dsi0pll_post_bit_div = { .div = 2, .mult = 1, @@ -1381,6 +1818,18 @@ static struct clk_fixed_factor dsi0pll_post_bit_div = { }, }; +static struct clk_fixed_factor dsi0pll_shadow_post_bit_div = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_post_bit_div", + .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, + }, +}; + static struct clk_fixed_factor dsi1pll_post_bit_div = { .div = 2, .mult = 1, @@ -1393,15 +1842,29 @@ static struct clk_fixed_factor dsi1pll_post_bit_div = { }, }; +static struct clk_fixed_factor dsi1pll_shadow_post_bit_div = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_post_bit_div", + .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, + }, +}; + static struct clk_regmap_mux dsi0pll_byteclk_mux = { .shift = 0, .width = 1, .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi0_phy_pll_out_byteclk", - .parent_names = (const char *[]){"dsi0pll_byteclk_src"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .parent_names = (const char *[]){"dsi0pll_byteclk_src", + "dsi0pll_shadow_byteclk_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), .ops = &clk_regmap_mux_closest_ops, }, }, @@ -1413,9 +1876,11 @@ static struct clk_regmap_mux dsi1pll_byteclk_mux = { .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi1_phy_pll_out_byteclk", - .parent_names = (const char *[]){"dsi1pll_byteclk_src"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .parent_names = (const char *[]){"dsi1pll_byteclk_src", + "dsi1pll_shadow_byteclk_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), .ops = &clk_regmap_mux_closest_ops, }, }, @@ -1439,6 +1904,25 @@ static struct clk_regmap_mux dsi0pll_pclk_src_mux = { }, }; +static struct clk_regmap_mux dsi0pll_shadow_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_pclk_src_mux", + .parent_names = (const char *[]){ + "dsi0pll_shadow_bitclk_src", + "dsi0pll_shadow_post_bit_div", + "dsi0pll_shadow_pll_out_div", + "dsi0pll_shadow_post_vco_div"}, + .num_parents = 4, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + static struct clk_regmap_mux dsi1pll_pclk_src_mux = { .reg = PHY_CMN_CLK_CFG1, .shift = 0, @@ -1457,6 +1941,25 @@ static struct clk_regmap_mux dsi1pll_pclk_src_mux = { }, }; +static struct clk_regmap_mux dsi1pll_shadow_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_pclk_src_mux", + .parent_names = (const char *[]){ + "dsi1pll_shadow_bitclk_src", + "dsi1pll_shadow_post_bit_div", + "dsi1pll_shadow_pll_out_div", + "dsi1pll_shadow_post_vco_div"}, + .num_parents = 4, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + static struct clk_regmap_div dsi0pll_pclk_src = { .shift = 0, .width = 4, @@ -1472,6 +1975,21 @@ static struct clk_regmap_div dsi0pll_pclk_src = { }, }; +static struct clk_regmap_div dsi0pll_shadow_pclk_src = { + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_pclk_src", + .parent_names = (const char *[]){ + "dsi0pll_shadow_pclk_src_mux"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + static struct clk_regmap_div dsi1pll_pclk_src = { .shift = 0, .width = 4, @@ -1487,15 +2005,32 @@ static struct clk_regmap_div dsi1pll_pclk_src = { }, }; +static struct clk_regmap_div dsi1pll_shadow_pclk_src = { + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_pclk_src", + .parent_names = (const char *[]){ + "dsi1pll_shadow_pclk_src_mux"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + static struct clk_regmap_mux dsi0pll_pclk_mux = { .shift = 0, .width = 1, .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi0_phy_pll_out_dsiclk", - .parent_names = (const char *[]){"dsi0pll_pclk_src"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .parent_names = (const char *[]){"dsi0pll_pclk_src", + "dsi0pll_shadow_pclk_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), .ops = &clk_regmap_mux_closest_ops, }, }, @@ -1507,9 +2042,11 @@ static struct clk_regmap_mux dsi1pll_pclk_mux = { .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi1_phy_pll_out_dsiclk", - .parent_names = (const char *[]){"dsi1pll_pclk_src"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .parent_names = (const char *[]){"dsi1pll_pclk_src", + "dsi1pll_shadow_pclk_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), .ops = &clk_regmap_mux_closest_ops, }, }, @@ -1526,6 +2063,14 @@ static struct clk_hw *mdss_dsi_pllcc_10nm[] = { [PCLK_SRC_MUX_0_CLK] = &dsi0pll_pclk_src_mux.clkr.hw, [PCLK_SRC_0_CLK] = &dsi0pll_pclk_src.clkr.hw, [PCLK_MUX_0_CLK] = &dsi0pll_pclk_mux.clkr.hw, + [SHADOW_VCO_CLK_0] = &dsi0pll_shadow_vco_clk.hw, + [SHADOW_PLL_OUT_DIV_0_CLK] = &dsi0pll_shadow_pll_out_div.clkr.hw, + [SHADOW_BITCLK_SRC_0_CLK] = &dsi0pll_shadow_bitclk_src.clkr.hw, + [SHADOW_BYTECLK_SRC_0_CLK] = &dsi0pll_shadow_byteclk_src.hw, + [SHADOW_POST_BIT_DIV_0_CLK] = &dsi0pll_shadow_post_bit_div.hw, + [SHADOW_POST_VCO_DIV_0_CLK] = &dsi0pll_shadow_post_vco_div.hw, + [SHADOW_PCLK_SRC_MUX_0_CLK] = &dsi0pll_shadow_pclk_src_mux.clkr.hw, + [SHADOW_PCLK_SRC_0_CLK] = &dsi0pll_shadow_pclk_src.clkr.hw, [VCO_CLK_1] = &dsi1pll_vco_clk.hw, [PLL_OUT_DIV_1_CLK] = &dsi1pll_pll_out_div.clkr.hw, [BITCLK_SRC_1_CLK] = &dsi1pll_bitclk_src.clkr.hw, @@ -1536,6 +2081,14 @@ static struct clk_hw *mdss_dsi_pllcc_10nm[] = { [PCLK_SRC_MUX_1_CLK] = &dsi1pll_pclk_src_mux.clkr.hw, [PCLK_SRC_1_CLK] = &dsi1pll_pclk_src.clkr.hw, [PCLK_MUX_1_CLK] = &dsi1pll_pclk_mux.clkr.hw, + [SHADOW_VCO_CLK_1] = &dsi1pll_shadow_vco_clk.hw, + [SHADOW_PLL_OUT_DIV_1_CLK] = &dsi1pll_shadow_pll_out_div.clkr.hw, + [SHADOW_BITCLK_SRC_1_CLK] = &dsi1pll_shadow_bitclk_src.clkr.hw, + [SHADOW_BYTECLK_SRC_1_CLK] = &dsi1pll_shadow_byteclk_src.hw, + [SHADOW_POST_BIT_DIV_1_CLK] = &dsi1pll_shadow_post_bit_div.hw, + [SHADOW_POST_VCO_DIV_1_CLK] = &dsi1pll_shadow_post_vco_div.hw, + [SHADOW_PCLK_SRC_MUX_1_CLK] = &dsi1pll_shadow_pclk_src_mux.clkr.hw, + [SHADOW_PCLK_SRC_1_CLK] = &dsi1pll_shadow_pclk_src.clkr.hw, }; int dsi_pll_clock_register_10nm(struct platform_device *pdev, @@ -1580,18 +2133,20 @@ int dsi_pll_clock_register_10nm(struct platform_device *pdev, /* Establish client data */ if (ndx == 0) { - rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi0pll_pll_out_div.clkr.regmap = rmap; + dsi0pll_shadow_pll_out_div.clkr.regmap = rmap; rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi0pll_bitclk_src.clkr.regmap = rmap; + dsi0pll_shadow_bitclk_src.clkr.regmap = rmap; rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi0pll_pclk_src.clkr.regmap = rmap; + dsi0pll_shadow_pclk_src.clkr.regmap = rmap; rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, pll_res, &dsi_pll_10nm_config); @@ -1600,12 +2155,16 @@ int dsi_pll_clock_register_10nm(struct platform_device *pdev, rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi0pll_pclk_src_mux.clkr.regmap = rmap; + dsi0pll_shadow_pclk_src_mux.clkr.regmap = rmap; + rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi0pll_byteclk_mux.clkr.regmap = rmap; dsi0pll_vco_clk.priv = pll_res; - for (i = VCO_CLK_0; i <= PCLK_MUX_0_CLK; i++) { + dsi0pll_shadow_vco_clk.priv = pll_res; + + for (i = VCO_CLK_0; i <= SHADOW_PCLK_SRC_0_CLK; i++) { clk = devm_clk_register(&pdev->dev, mdss_dsi_pllcc_10nm[i]); if (IS_ERR(clk)) { @@ -1620,20 +2179,21 @@ int dsi_pll_clock_register_10nm(struct platform_device *pdev, rc = of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, clk_data); - - } else { rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi1pll_pll_out_div.clkr.regmap = rmap; + dsi1pll_shadow_pll_out_div.clkr.regmap = rmap; rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi1pll_bitclk_src.clkr.regmap = rmap; + dsi1pll_shadow_bitclk_src.clkr.regmap = rmap; rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi1pll_pclk_src.clkr.regmap = rmap; + dsi1pll_shadow_pclk_src.clkr.regmap = rmap; rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, pll_res, &dsi_pll_10nm_config); @@ -1642,12 +2202,16 @@ int dsi_pll_clock_register_10nm(struct platform_device *pdev, rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi1pll_pclk_src_mux.clkr.regmap = rmap; + dsi1pll_shadow_pclk_src_mux.clkr.regmap = rmap; + rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi1pll_byteclk_mux.clkr.regmap = rmap; + dsi1pll_vco_clk.priv = pll_res; + dsi1pll_shadow_vco_clk.priv = pll_res; - for (i = VCO_CLK_1; i <= PCLK_MUX_1_CLK; i++) { + for (i = VCO_CLK_1; i <= SHADOW_PCLK_SRC_1_CLK; i++) { clk = devm_clk_register(&pdev->dev, mdss_dsi_pllcc_10nm[i]); if (IS_ERR(clk)) { |