diff options
-rw-r--r-- | drivers/clk/bcm/clk-iproc-pll.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c index 7df010b2edcd..ab10819e2c09 100644 --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c | |||
@@ -285,6 +285,40 @@ static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp, | |||
285 | iproc_pll_write(pll, pll->control_base, reset->offset, val); | 285 | iproc_pll_write(pll, pll->control_base, reset->offset, val); |
286 | } | 286 | } |
287 | 287 | ||
288 | /* | ||
289 | * Determines if the change to be applied to the PLL is minor (just an update | ||
290 | * or the fractional divider). If so, then we can avoid going through a | ||
291 | * disruptive reset and lock sequence. | ||
292 | */ | ||
293 | static bool pll_fractional_change_only(struct iproc_pll *pll, | ||
294 | struct iproc_pll_vco_param *vco) | ||
295 | { | ||
296 | const struct iproc_pll_ctrl *ctrl = pll->ctrl; | ||
297 | u32 val; | ||
298 | u32 ndiv_int; | ||
299 | unsigned int pdiv; | ||
300 | |||
301 | /* PLL needs to be locked */ | ||
302 | val = readl(pll->status_base + ctrl->status.offset); | ||
303 | if ((val & (1 << ctrl->status.shift)) == 0) | ||
304 | return false; | ||
305 | |||
306 | val = readl(pll->control_base + ctrl->ndiv_int.offset); | ||
307 | ndiv_int = (val >> ctrl->ndiv_int.shift) & | ||
308 | bit_mask(ctrl->ndiv_int.width); | ||
309 | |||
310 | if (ndiv_int != vco->ndiv_int) | ||
311 | return false; | ||
312 | |||
313 | val = readl(pll->control_base + ctrl->pdiv.offset); | ||
314 | pdiv = (val >> ctrl->pdiv.shift) & bit_mask(ctrl->pdiv.width); | ||
315 | |||
316 | if (pdiv != vco->pdiv) | ||
317 | return false; | ||
318 | |||
319 | return true; | ||
320 | } | ||
321 | |||
288 | static int pll_set_rate(struct iproc_clk *clk, struct iproc_pll_vco_param *vco, | 322 | static int pll_set_rate(struct iproc_clk *clk, struct iproc_pll_vco_param *vco, |
289 | unsigned long parent_rate) | 323 | unsigned long parent_rate) |
290 | { | 324 | { |
@@ -333,6 +367,19 @@ static int pll_set_rate(struct iproc_clk *clk, struct iproc_pll_vco_param *vco, | |||
333 | return ret; | 367 | return ret; |
334 | } | 368 | } |
335 | 369 | ||
370 | if (pll_fractional_change_only(clk->pll, vco)) { | ||
371 | /* program fractional part of NDIV */ | ||
372 | if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) { | ||
373 | val = readl(pll->control_base + ctrl->ndiv_frac.offset); | ||
374 | val &= ~(bit_mask(ctrl->ndiv_frac.width) << | ||
375 | ctrl->ndiv_frac.shift); | ||
376 | val |= vco->ndiv_frac << ctrl->ndiv_frac.shift; | ||
377 | iproc_pll_write(pll, pll->control_base, | ||
378 | ctrl->ndiv_frac.offset, val); | ||
379 | return 0; | ||
380 | } | ||
381 | } | ||
382 | |||
336 | /* put PLL in reset */ | 383 | /* put PLL in reset */ |
337 | __pll_put_in_reset(pll); | 384 | __pll_put_in_reset(pll); |
338 | 385 | ||