diff options
author | Rajkumar Subbiah <rsubbia@codeaurora.org> | 2017-05-08 16:15:22 -0400 |
---|---|---|
committer | Rajkumar Subbiah <rsubbia@codeaurora.org> | 2017-05-15 11:45:13 -0400 |
commit | 8c2a2f02ed70141c744794226e92d5b4ff9fab08 (patch) | |
tree | 541eb834f820832452377023cc10967dce00e8b3 /drivers/clk | |
parent | 6d8fa6f1ccf8ec205e34e1333bffc39b920fe171 (diff) |
clk: msm: Fix pll out div programming
The PLL out divider is currently not programmed when the PLL is
locked. Since they are setup as fixed ratio dividers, the set_div
is not called during set_rate. So this fix moves the pll out div
programming to pll out mux selection callback which gets called
during set_rate.
Change-Id: I48b0254c6eb308071706258d2b5a77f06d9927c2
Signed-off-by: Rajkumar Subbiah <rsubbia@codeaurora.org>
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/msm/mdss/mdss-dsi-pll-8998.c | 137 |
1 files changed, 48 insertions, 89 deletions
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c index 680c501b4a9d..040707e58e25 100644 --- a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c +++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c @@ -551,11 +551,23 @@ static int dsi_pll_enable(struct dsi_pll_vco_clk *vco) { int rc; struct mdss_pll_resources *rsc = vco->priv; + struct dsi_pll_8998 *pll = rsc->priv; + struct dsi_pll_regs *regs = &pll->reg_setup; dsi_pll_enable_pll_bias(rsc); if (rsc->slave) dsi_pll_enable_pll_bias(rsc->slave); + /* + * The PLL out dividers are fixed divider clocks and hence the + * set_div is not called during set_rate cycle of the tree. + * The outdiv rate is therefore set in the pll out mux's set_sel + * callback. But that will be called only after vco's set rate. + * Hence PLL out div value is set here before locking the PLL. + */ + MDSS_PLL_REG_W(rsc->pll_base, PLL_PLL_OUTDIV_RATE, + regs->pll_outdiv_rate); + /* Start PLL */ MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0x01); @@ -682,7 +694,9 @@ static int vco_8998_prepare(struct clk *c) static unsigned long dsi_pll_get_vco_rate(struct clk *c) { struct dsi_pll_vco_clk *vco = to_vco_clk(c); - struct mdss_pll_resources *pll = vco->priv; + struct mdss_pll_resources *rsc = vco->priv; + struct dsi_pll_8998 *pll = rsc->priv; + struct dsi_pll_regs *regs = &pll->reg_setup; int rc; u64 ref_clk = vco->ref_clk_rate; u64 vco_rate; @@ -692,27 +706,30 @@ static unsigned long dsi_pll_get_vco_rate(struct clk *c) u32 outdiv; u64 pll_freq, tmp64; - rc = mdss_pll_resource_enable(pll, true); + rc = mdss_pll_resource_enable(rsc, true); if (rc) { pr_err("failed to enable pll(%d) resource, rc=%d\n", - pll->index, rc); + rsc->index, rc); return 0; } - dec = MDSS_PLL_REG_R(pll->pll_base, PLL_DECIMAL_DIV_START_1); + dec = MDSS_PLL_REG_R(rsc->pll_base, PLL_DECIMAL_DIV_START_1); dec &= 0xFF; - frac = MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_LOW_1); - frac |= ((MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_MID_1) & + frac = MDSS_PLL_REG_R(rsc->pll_base, PLL_FRAC_DIV_START_LOW_1); + frac |= ((MDSS_PLL_REG_R(rsc->pll_base, PLL_FRAC_DIV_START_MID_1) & 0xFF) << 8); - frac |= ((MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_HIGH_1) & + frac |= ((MDSS_PLL_REG_R(rsc->pll_base, PLL_FRAC_DIV_START_HIGH_1) & 0x3) << 16); /* OUTDIV_1:0 field is (log(outdiv, 2)) */ - outdiv = MDSS_PLL_REG_R(pll->pll_base, PLL_PLL_OUTDIV_RATE); + outdiv = MDSS_PLL_REG_R(rsc->pll_base, PLL_PLL_OUTDIV_RATE); outdiv &= 0x3; + + regs->pll_outdiv_rate = outdiv; + outdiv = 1 << outdiv; /* @@ -730,7 +747,7 @@ static unsigned long dsi_pll_get_vco_rate(struct clk *c) pr_debug("dec=0x%x, frac=0x%x, outdiv=%d, vco=%llu\n", dec, frac, outdiv, vco_rate); - (void)mdss_pll_resource_enable(pll, false); + (void)mdss_pll_resource_enable(rsc, false); return (unsigned long)vco_rate; } @@ -884,72 +901,26 @@ static int bit_clk_set_div(struct div_clk *clk, int div) return rc; } -static int pll_out_clk_set_div(struct div_clk *clk, int div) +static int dsi_pll_out_set_mux_sel(struct mux_clk *clk, int sel) { - int rc; - u32 reg_val = 0; - int i; - struct mdss_pll_resources *rsc = clk->priv; struct dsi_pll_8998 *pll = rsc->priv; struct dsi_pll_regs *regs = &pll->reg_setup; - rc = mdss_pll_resource_enable(rsc, true); - if (rc) { - pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); - return rc; - } - - /* - * out_div = 2 ^ div_log - * To get div_log from output div just get the index of the - * 1 bit in the value. - * div_log ranges from 0-3. so check the 4 lsbs - */ - - for (i = 0; i < 4; i++) { - if (div & (1 << i)) { - reg_val = i; - break; - } - } - - regs->pll_outdiv_rate = reg_val; - - MDSS_PLL_REG_W(rsc->pll_base, PLL_PLL_OUTDIV_RATE, reg_val); - - pr_debug("Setting PLL outdiv rate on pll(%d) to 0x%x\n", - rsc->index, reg_val); - - (void)mdss_pll_resource_enable(rsc, false); + regs->pll_outdiv_rate = sel; return 0; } - -static int pll_out_clk_get_div(struct div_clk *clk) +static int dsi_pll_out_get_mux_sel(struct mux_clk *clk) { - int rc; - u32 reg_val; - int div; - - struct mdss_pll_resources *pll = clk->priv; - - rc = mdss_pll_resource_enable(pll, true); - if (rc) { - pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); - return rc; - } - - reg_val = MDSS_PLL_REG_R(pll->pll_base, PLL_PLL_OUTDIV_RATE); - div = 1 << (reg_val & 3); - - (void)mdss_pll_resource_enable(pll, false); + struct mdss_pll_resources *rsc = clk->priv; + struct dsi_pll_8998 *pll = rsc->priv; + struct dsi_pll_regs *regs = &pll->reg_setup; - return div; + return regs->pll_outdiv_rate; } - static int post_vco_clk_get_div(struct div_clk *clk) { int rc; @@ -1111,7 +1082,6 @@ static struct clk_ops clk_ops_bitclk_src_c; static struct clk_ops clk_ops_post_vco_div_c; static struct clk_ops clk_ops_post_bit_div_c; static struct clk_ops clk_ops_pclk_src_c; -static struct clk_ops clk_ops_pll_out_div_c; static struct clk_div_ops clk_post_vco_div_ops = { .set_div = post_vco_clk_set_div, @@ -1133,11 +1103,6 @@ static struct clk_div_ops clk_bitclk_src_ops = { .get_div = bit_clk_get_div, }; -static struct clk_div_ops clk_pll_out_div_ops = { - .set_div = pll_out_clk_set_div, - .get_div = pll_out_clk_get_div, -}; - static struct clk_ops clk_ops_vco_8998 = { .set_rate = vco_8998_set_rate, .round_rate = vco_8998_round_rate, @@ -1151,6 +1116,11 @@ static struct clk_mux_ops mdss_mux_ops = { .get_mux_sel = mdss_get_mux_sel, }; +static struct clk_mux_ops mdss_pll_out_mux_ops = { + .set_mux_sel = dsi_pll_out_set_mux_sel, + .get_mux_sel = dsi_pll_out_get_mux_sel, +}; + /* * Clock tree for generating DSI byte and pixel clocks. * @@ -1236,11 +1206,10 @@ static struct div_clk dsi0pll_pll_out_div1 = { .min_div = 1, .max_div = 1, }, - .ops = &clk_pll_out_div_ops, .c = { .parent = &dsi0pll_vco_clk.c, .dbg_name = "dsi0pll_pll_out_div1", - .ops = &clk_ops_pll_out_div_c, + .ops = &clk_ops_div, .flags = CLKFLAG_NO_RATE_CACHE, CLK_INIT(dsi0pll_pll_out_div1.c), } @@ -1252,11 +1221,10 @@ static struct div_clk dsi0pll_pll_out_div2 = { .min_div = 2, .max_div = 2, }, - .ops = &clk_pll_out_div_ops, .c = { .parent = &dsi0pll_vco_clk.c, .dbg_name = "dsi0pll_pll_out_div2", - .ops = &clk_ops_pll_out_div_c, + .ops = &clk_ops_div, .flags = CLKFLAG_NO_RATE_CACHE, CLK_INIT(dsi0pll_pll_out_div2.c), } @@ -1268,11 +1236,10 @@ static struct div_clk dsi0pll_pll_out_div4 = { .min_div = 4, .max_div = 4, }, - .ops = &clk_pll_out_div_ops, .c = { .parent = &dsi0pll_vco_clk.c, .dbg_name = "dsi0pll_pll_out_div4", - .ops = &clk_ops_pll_out_div_c, + .ops = &clk_ops_div, .flags = CLKFLAG_NO_RATE_CACHE, CLK_INIT(dsi0pll_pll_out_div4.c), } @@ -1284,11 +1251,10 @@ static struct div_clk dsi0pll_pll_out_div8 = { .min_div = 8, .max_div = 8, }, - .ops = &clk_pll_out_div_ops, .c = { .parent = &dsi0pll_vco_clk.c, .dbg_name = "dsi0pll_pll_out_div8", - .ops = &clk_ops_pll_out_div_c, + .ops = &clk_ops_div, .flags = CLKFLAG_NO_RATE_CACHE, CLK_INIT(dsi0pll_pll_out_div8.c), } @@ -1302,7 +1268,7 @@ static struct mux_clk dsi0pll_pll_out_mux = { {&dsi0pll_pll_out_div4.c, 2}, {&dsi0pll_pll_out_div8.c, 3}, }, - .ops = &mdss_mux_ops, + .ops = &mdss_pll_out_mux_ops, .c = { .parent = &dsi0pll_pll_out_div1.c, .dbg_name = "dsi0pll_pll_out_mux", @@ -1486,11 +1452,10 @@ static struct div_clk dsi1pll_pll_out_div1 = { .min_div = 1, .max_div = 1, }, - .ops = &clk_pll_out_div_ops, .c = { .parent = &dsi1pll_vco_clk.c, .dbg_name = "dsi1pll_pll_out_div1", - .ops = &clk_ops_pll_out_div_c, + .ops = &clk_ops_div, .flags = CLKFLAG_NO_RATE_CACHE, CLK_INIT(dsi1pll_pll_out_div1.c), } @@ -1502,11 +1467,10 @@ static struct div_clk dsi1pll_pll_out_div2 = { .min_div = 2, .max_div = 2, }, - .ops = &clk_pll_out_div_ops, .c = { .parent = &dsi1pll_vco_clk.c, .dbg_name = "dsi1pll_pll_out_div2", - .ops = &clk_ops_pll_out_div_c, + .ops = &clk_ops_div, .flags = CLKFLAG_NO_RATE_CACHE, CLK_INIT(dsi1pll_pll_out_div2.c), } @@ -1518,11 +1482,10 @@ static struct div_clk dsi1pll_pll_out_div4 = { .min_div = 4, .max_div = 4, }, - .ops = &clk_pll_out_div_ops, .c = { .parent = &dsi1pll_vco_clk.c, .dbg_name = "dsi1pll_pll_out_div4", - .ops = &clk_ops_pll_out_div_c, + .ops = &clk_ops_div, .flags = CLKFLAG_NO_RATE_CACHE, CLK_INIT(dsi1pll_pll_out_div4.c), } @@ -1534,11 +1497,10 @@ static struct div_clk dsi1pll_pll_out_div8 = { .min_div = 8, .max_div = 8, }, - .ops = &clk_pll_out_div_ops, .c = { .parent = &dsi1pll_vco_clk.c, .dbg_name = "dsi1pll_pll_out_div8", - .ops = &clk_ops_pll_out_div_c, + .ops = &clk_ops_div, .flags = CLKFLAG_NO_RATE_CACHE, CLK_INIT(dsi1pll_pll_out_div8.c), } @@ -1552,7 +1514,7 @@ static struct mux_clk dsi1pll_pll_out_mux = { {&dsi1pll_pll_out_div4.c, 2}, {&dsi1pll_pll_out_div8.c, 3}, }, - .ops = &mdss_mux_ops, + .ops = &mdss_pll_out_mux_ops, .c = { .parent = &dsi1pll_pll_out_div1.c, .dbg_name = "dsi1pll_pll_out_mux", @@ -1786,9 +1748,6 @@ int dsi_pll_clock_register_8998(struct platform_device *pdev, clk_ops_bitclk_src_c = clk_ops_div; clk_ops_bitclk_src_c.prepare = mdss_pll_div_prepare; - clk_ops_pll_out_div_c = clk_ops_div; - clk_ops_pll_out_div_c.prepare = mdss_pll_div_prepare; - /* * Set the ops for the two dividers in the pixel clock tree to the * slave_div to ensure that a set rate on this divider clock will not |