aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZdenko Pulitika <zdenko.pulitika@imgtec.com>2015-08-26 12:11:39 -0400
committerStephen Boyd <sboyd@codeaurora.org>2015-08-26 14:34:41 -0400
commit7937c6c57e0da7bffa7b10bac23f230c77523e35 (patch)
treecc6bbea7149e3cac0b0adffbfae75c1496a1d2c6
parente53f21c761d141bbcbce06e9ddab3b4e0a828f2c (diff)
clk: pistachio: Fix PLL rate calculation in integer mode
.recalc_rate callback for the fractional PLL doesn't take operating mode into account when calculating PLL rate. This results in the incorrect PLL rates when PLL is operating in integer mode. Operating mode of fractional PLL is based on the value of the fractional divider. Currently it assumes that the PLL will always be configured in fractional mode which may not be the case. This may result in the wrong output frequency. Also vco was calculated based on the current operating mode which makes no sense because .set_rate is setting operating mode. Instead, vco should be calculated using PLL settings that are about to be set. Fixes: 43049b0c83f17("CLK: Pistachio: Add PLL driver") Cc: <stable@vger.kernel.org> # 4.1 Reviewed-by: Andrew Bresticker <abrestic@chromium.org> Signed-off-by: Zdenko Pulitika <zdenko.pulitika@imgtec.com> Signed-off-by: Govindraj Raja <govindraj.raja@imgtec.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r--drivers/clk/pistachio/clk-pll.c48
1 files changed, 46 insertions, 2 deletions
diff --git a/drivers/clk/pistachio/clk-pll.c b/drivers/clk/pistachio/clk-pll.c
index 9ae59ed0156b..7e8daab9025b 100644
--- a/drivers/clk/pistachio/clk-pll.c
+++ b/drivers/clk/pistachio/clk-pll.c
@@ -65,6 +65,12 @@
65#define MIN_OUTPUT_FRAC 12000000UL 65#define MIN_OUTPUT_FRAC 12000000UL
66#define MAX_OUTPUT_FRAC 1600000000UL 66#define MAX_OUTPUT_FRAC 1600000000UL
67 67
68/* Fractional PLL operating modes */
69enum pll_mode {
70 PLL_MODE_FRAC,
71 PLL_MODE_INT,
72};
73
68struct pistachio_clk_pll { 74struct pistachio_clk_pll {
69 struct clk_hw hw; 75 struct clk_hw hw;
70 void __iomem *base; 76 void __iomem *base;
@@ -99,6 +105,29 @@ static inline struct pistachio_clk_pll *to_pistachio_pll(struct clk_hw *hw)
99 return container_of(hw, struct pistachio_clk_pll, hw); 105 return container_of(hw, struct pistachio_clk_pll, hw);
100} 106}
101 107
108static inline enum pll_mode pll_frac_get_mode(struct clk_hw *hw)
109{
110 struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
111 u32 val;
112
113 val = pll_readl(pll, PLL_CTRL3) & PLL_FRAC_CTRL3_DSMPD;
114 return val ? PLL_MODE_INT : PLL_MODE_FRAC;
115}
116
117static inline void pll_frac_set_mode(struct clk_hw *hw, enum pll_mode mode)
118{
119 struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
120 u32 val;
121
122 val = pll_readl(pll, PLL_CTRL3);
123 if (mode == PLL_MODE_INT)
124 val |= PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_DACPD;
125 else
126 val &= ~(PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_DACPD);
127
128 pll_writel(pll, val, PLL_CTRL3);
129}
130
102static struct pistachio_pll_rate_table * 131static struct pistachio_pll_rate_table *
103pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref, 132pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref,
104 unsigned long fout) 133 unsigned long fout)
@@ -180,7 +209,11 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
180 if (!params || !params->refdiv) 209 if (!params || !params->refdiv)
181 return -EINVAL; 210 return -EINVAL;
182 211
183 vco = div64_u64(params->fref * params->fbdiv, params->refdiv); 212 /* calculate vco */
213 vco = params->fref;
214 vco *= (params->fbdiv << 24) + params->frac;
215 vco = div64_u64(vco, params->refdiv << 24);
216
184 if (vco < MIN_VCO_FRAC_FRAC || vco > MAX_VCO_FRAC_FRAC) 217 if (vco < MIN_VCO_FRAC_FRAC || vco > MAX_VCO_FRAC_FRAC)
185 pr_warn("%s: VCO %llu is out of range %lu..%lu\n", name, vco, 218 pr_warn("%s: VCO %llu is out of range %lu..%lu\n", name, vco,
186 MIN_VCO_FRAC_FRAC, MAX_VCO_FRAC_FRAC); 219 MIN_VCO_FRAC_FRAC, MAX_VCO_FRAC_FRAC);
@@ -224,6 +257,12 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
224 (params->postdiv2 << PLL_FRAC_CTRL2_POSTDIV2_SHIFT); 257 (params->postdiv2 << PLL_FRAC_CTRL2_POSTDIV2_SHIFT);
225 pll_writel(pll, val, PLL_CTRL2); 258 pll_writel(pll, val, PLL_CTRL2);
226 259
260 /* set operating mode */
261 if (params->frac)
262 pll_frac_set_mode(hw, PLL_MODE_FRAC);
263 else
264 pll_frac_set_mode(hw, PLL_MODE_INT);
265
227 if (enabled) 266 if (enabled)
228 pll_lock(pll); 267 pll_lock(pll);
229 268
@@ -247,8 +286,13 @@ static unsigned long pll_gf40lp_frac_recalc_rate(struct clk_hw *hw,
247 PLL_FRAC_CTRL2_POSTDIV2_MASK; 286 PLL_FRAC_CTRL2_POSTDIV2_MASK;
248 frac = (val >> PLL_FRAC_CTRL2_FRAC_SHIFT) & PLL_FRAC_CTRL2_FRAC_MASK; 287 frac = (val >> PLL_FRAC_CTRL2_FRAC_SHIFT) & PLL_FRAC_CTRL2_FRAC_MASK;
249 288
289 /* get operating mode (int/frac) and calculate rate accordingly */
250 rate = parent_rate; 290 rate = parent_rate;
251 rate *= (fbdiv << 24) + frac; 291 if (pll_frac_get_mode(hw) == PLL_MODE_FRAC)
292 rate *= (fbdiv << 24) + frac;
293 else
294 rate *= (fbdiv << 24);
295
252 rate = do_div_round_closest(rate, (prediv * postdiv1 * postdiv2) << 24); 296 rate = do_div_round_closest(rate, (prediv * postdiv1 * postdiv2) << 24);
253 297
254 return rate; 298 return rate;