aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLori Hikichi <lori.hikichi@broadcom.com>2017-08-14 15:00:38 -0400
committerStephen Boyd <sboyd@codeaurora.org>2017-12-28 17:53:33 -0500
commitbecf123772a9ef15823a3f495478fe68e45b5028 (patch)
tree3aea47d2966f28410ebf32995c16fd9178e31e16
parent4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323 (diff)
clk: iproc: Allow iproc pll to runtime calculate vco parameters
Add the ability for the iproc pll to calculate the pll parameters at runtime instead of only using predefined tables. This ability allows the clock users to select from the full range of vco frequencies. The old method of table based programming is retained so that existing users will retain expected behavior. The flag IPROC_CLK_PLL_CALC_PARAM will need to be set to enable the new runtime calculation method. Currently, this is only being enabled for the audio pll. This feature also revealed a problem with the driver using the round_rate api. The round_rate api does not allow for frequencies larger than 2^31 to be returned. Those large frequencies are interpreted as an error code. Therefore, we are moving to the determine_rate api which solves this problem. Signed-off-by: Simran Rai <ssimran@broadcom.com> Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r--drivers/clk/bcm/clk-cygnus.c25
-rw-r--r--drivers/clk/bcm/clk-iproc-pll.c97
-rw-r--r--drivers/clk/bcm/clk-iproc.h5
3 files changed, 92 insertions, 35 deletions
diff --git a/drivers/clk/bcm/clk-cygnus.c b/drivers/clk/bcm/clk-cygnus.c
index 464fdc4bc66b..b8d073e4855f 100644
--- a/drivers/clk/bcm/clk-cygnus.c
+++ b/drivers/clk/bcm/clk-cygnus.c
@@ -269,23 +269,10 @@ static void __init cygnus_asiu_init(struct device_node *node)
269} 269}
270CLK_OF_DECLARE(cygnus_asiu_clk, "brcm,cygnus-asiu-clk", cygnus_asiu_init); 270CLK_OF_DECLARE(cygnus_asiu_clk, "brcm,cygnus-asiu-clk", cygnus_asiu_init);
271 271
272/*
273 * AUDIO PLL VCO frequency parameter table
274 *
275 * PLL output frequency = ((ndiv_int + ndiv_frac / 2^20) *
276 * (parent clock rate / pdiv)
277 *
278 * On Cygnus, parent is the 25MHz oscillator
279 */
280static const struct iproc_pll_vco_param audiopll_vco_params[] = {
281 /* rate (Hz) ndiv_int ndiv_frac pdiv */
282 { 1354750204UL, 54, 199238, 1 },
283 { 1769470191UL, 70, 816639, 1 },
284};
285
286static const struct iproc_pll_ctrl audiopll = { 272static const struct iproc_pll_ctrl audiopll = {
287 .flags = IPROC_CLK_PLL_NEEDS_SW_CFG | IPROC_CLK_PLL_HAS_NDIV_FRAC | 273 .flags = IPROC_CLK_PLL_NEEDS_SW_CFG | IPROC_CLK_PLL_HAS_NDIV_FRAC |
288 IPROC_CLK_PLL_USER_MODE_ON | IPROC_CLK_PLL_RESET_ACTIVE_LOW, 274 IPROC_CLK_PLL_USER_MODE_ON | IPROC_CLK_PLL_RESET_ACTIVE_LOW |
275 IPROC_CLK_PLL_CALC_PARAM,
289 .reset = RESET_VAL(0x5c, 0, 1), 276 .reset = RESET_VAL(0x5c, 0, 1),
290 .dig_filter = DF_VAL(0x48, 0, 3, 6, 4, 3, 3), 277 .dig_filter = DF_VAL(0x48, 0, 3, 6, 4, 3, 3),
291 .sw_ctrl = SW_CTRL_VAL(0x4, 0), 278 .sw_ctrl = SW_CTRL_VAL(0x4, 0),
@@ -300,8 +287,7 @@ static const struct iproc_pll_ctrl audiopll = {
300static const struct iproc_clk_ctrl audiopll_clk[] = { 287static const struct iproc_clk_ctrl audiopll_clk[] = {
301 [BCM_CYGNUS_AUDIOPLL_CH0] = { 288 [BCM_CYGNUS_AUDIOPLL_CH0] = {
302 .channel = BCM_CYGNUS_AUDIOPLL_CH0, 289 .channel = BCM_CYGNUS_AUDIOPLL_CH0,
303 .flags = IPROC_CLK_AON | 290 .flags = IPROC_CLK_AON | IPROC_CLK_MCLK_DIV_BY_2,
304 IPROC_CLK_MCLK_DIV_BY_2,
305 .enable = ENABLE_VAL(0x14, 8, 10, 9), 291 .enable = ENABLE_VAL(0x14, 8, 10, 9),
306 .mdiv = REG_VAL(0x14, 0, 8), 292 .mdiv = REG_VAL(0x14, 0, 8),
307 }, 293 },
@@ -321,9 +307,8 @@ static const struct iproc_clk_ctrl audiopll_clk[] = {
321 307
322static void __init cygnus_audiopll_clk_init(struct device_node *node) 308static void __init cygnus_audiopll_clk_init(struct device_node *node)
323{ 309{
324 iproc_pll_clk_setup(node, &audiopll, audiopll_vco_params, 310 iproc_pll_clk_setup(node, &audiopll, NULL, 0,
325 ARRAY_SIZE(audiopll_vco_params), audiopll_clk, 311 audiopll_clk, ARRAY_SIZE(audiopll_clk));
326 ARRAY_SIZE(audiopll_clk));
327} 312}
328CLK_OF_DECLARE(cygnus_audiopll, "brcm,cygnus-audiopll", 313CLK_OF_DECLARE(cygnus_audiopll, "brcm,cygnus-audiopll",
329 cygnus_audiopll_clk_init); 314 cygnus_audiopll_clk_init);
diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c
index 375d8dd80d45..9514ecf319b0 100644
--- a/drivers/clk/bcm/clk-iproc-pll.c
+++ b/drivers/clk/bcm/clk-iproc-pll.c
@@ -95,6 +95,39 @@ struct iproc_pll {
95 95
96#define to_iproc_clk(hw) container_of(hw, struct iproc_clk, hw) 96#define to_iproc_clk(hw) container_of(hw, struct iproc_clk, hw)
97 97
98static int pll_calc_param(unsigned long target_rate,
99 unsigned long parent_rate,
100 struct iproc_pll_vco_param *vco_out)
101{
102 u64 ndiv_int, ndiv_frac, residual;
103
104 ndiv_int = target_rate / parent_rate;
105
106 if (!ndiv_int || (ndiv_int > 255))
107 return -EINVAL;
108
109 residual = target_rate - (ndiv_int * parent_rate);
110 residual <<= 20;
111
112 /*
113 * Add half of the divisor so the result will be rounded to closest
114 * instead of rounded down.
115 */
116 residual += (parent_rate / 2);
117 ndiv_frac = div64_u64((u64)residual, (u64)parent_rate);
118
119 vco_out->ndiv_int = ndiv_int;
120 vco_out->ndiv_frac = ndiv_frac;
121 vco_out->pdiv = 1;
122
123 vco_out->rate = vco_out->ndiv_int * parent_rate;
124 residual = (u64)vco_out->ndiv_frac * (u64)parent_rate;
125 residual >>= 20;
126 vco_out->rate += residual;
127
128 return 0;
129}
130
98/* 131/*
99 * Based on the target frequency, find a match from the VCO frequency parameter 132 * Based on the target frequency, find a match from the VCO frequency parameter
100 * table and return its index 133 * table and return its index
@@ -252,11 +285,10 @@ static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp,
252 iproc_pll_write(pll, pll->control_base, reset->offset, val); 285 iproc_pll_write(pll, pll->control_base, reset->offset, val);
253} 286}
254 287
255static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index, 288static int pll_set_rate(struct iproc_clk *clk, struct iproc_pll_vco_param *vco,
256 unsigned long parent_rate) 289 unsigned long parent_rate)
257{ 290{
258 struct iproc_pll *pll = clk->pll; 291 struct iproc_pll *pll = clk->pll;
259 const struct iproc_pll_vco_param *vco = &pll->vco_param[rate_index];
260 const struct iproc_pll_ctrl *ctrl = pll->ctrl; 292 const struct iproc_pll_ctrl *ctrl = pll->ctrl;
261 int ka = 0, ki, kp, ret; 293 int ka = 0, ki, kp, ret;
262 unsigned long rate = vco->rate; 294 unsigned long rate = vco->rate;
@@ -431,25 +463,50 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw,
431 return clk->rate; 463 return clk->rate;
432} 464}
433 465
434static long iproc_pll_round_rate(struct clk_hw *hw, unsigned long rate, 466static int iproc_pll_determine_rate(struct clk_hw *hw,
435 unsigned long *parent_rate) 467 struct clk_rate_request *req)
436{ 468{
437 unsigned i; 469 unsigned int i;
438 struct iproc_clk *clk = to_iproc_clk(hw); 470 struct iproc_clk *clk = to_iproc_clk(hw);
439 struct iproc_pll *pll = clk->pll; 471 struct iproc_pll *pll = clk->pll;
472 const struct iproc_pll_ctrl *ctrl = pll->ctrl;
473 unsigned long diff, best_diff;
474 unsigned int best_idx = 0;
475 int ret;
440 476
441 if (rate == 0 || *parent_rate == 0 || !pll->vco_param) 477 if (req->rate == 0 || req->best_parent_rate == 0)
442 return -EINVAL; 478 return -EINVAL;
443 479
480 if (ctrl->flags & IPROC_CLK_PLL_CALC_PARAM) {
481 struct iproc_pll_vco_param vco_param;
482
483 ret = pll_calc_param(req->rate, req->best_parent_rate,
484 &vco_param);
485 if (ret)
486 return ret;
487
488 req->rate = vco_param.rate;
489 return 0;
490 }
491
492 if (!pll->vco_param)
493 return -EINVAL;
494
495 best_diff = ULONG_MAX;
444 for (i = 0; i < pll->num_vco_entries; i++) { 496 for (i = 0; i < pll->num_vco_entries; i++) {
445 if (rate <= pll->vco_param[i].rate) 497 diff = abs(req->rate - pll->vco_param[i].rate);
498 if (diff <= best_diff) {
499 best_diff = diff;
500 best_idx = i;
501 }
502 /* break now if perfect match */
503 if (diff == 0)
446 break; 504 break;
447 } 505 }
448 506
449 if (i == pll->num_vco_entries) 507 req->rate = pll->vco_param[best_idx].rate;
450 i--;
451 508
452 return pll->vco_param[i].rate; 509 return 0;
453} 510}
454 511
455static int iproc_pll_set_rate(struct clk_hw *hw, unsigned long rate, 512static int iproc_pll_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -457,13 +514,23 @@ static int iproc_pll_set_rate(struct clk_hw *hw, unsigned long rate,
457{ 514{
458 struct iproc_clk *clk = to_iproc_clk(hw); 515 struct iproc_clk *clk = to_iproc_clk(hw);
459 struct iproc_pll *pll = clk->pll; 516 struct iproc_pll *pll = clk->pll;
517 const struct iproc_pll_ctrl *ctrl = pll->ctrl;
518 struct iproc_pll_vco_param vco_param;
460 int rate_index, ret; 519 int rate_index, ret;
461 520
462 rate_index = pll_get_rate_index(pll, rate); 521 if (ctrl->flags & IPROC_CLK_PLL_CALC_PARAM) {
463 if (rate_index < 0) 522 ret = pll_calc_param(rate, parent_rate, &vco_param);
464 return rate_index; 523 if (ret)
524 return ret;
525 } else {
526 rate_index = pll_get_rate_index(pll, rate);
527 if (rate_index < 0)
528 return rate_index;
529
530 vco_param = pll->vco_param[rate_index];
531 }
465 532
466 ret = pll_set_rate(clk, rate_index, parent_rate); 533 ret = pll_set_rate(clk, &vco_param, parent_rate);
467 return ret; 534 return ret;
468} 535}
469 536
@@ -471,7 +538,7 @@ static const struct clk_ops iproc_pll_ops = {
471 .enable = iproc_pll_enable, 538 .enable = iproc_pll_enable,
472 .disable = iproc_pll_disable, 539 .disable = iproc_pll_disable,
473 .recalc_rate = iproc_pll_recalc_rate, 540 .recalc_rate = iproc_pll_recalc_rate,
474 .round_rate = iproc_pll_round_rate, 541 .determine_rate = iproc_pll_determine_rate,
475 .set_rate = iproc_pll_set_rate, 542 .set_rate = iproc_pll_set_rate,
476}; 543};
477 544
diff --git a/drivers/clk/bcm/clk-iproc.h b/drivers/clk/bcm/clk-iproc.h
index 2148b4ea9f28..a48ddd3e0b28 100644
--- a/drivers/clk/bcm/clk-iproc.h
+++ b/drivers/clk/bcm/clk-iproc.h
@@ -81,6 +81,11 @@
81#define IPROC_CLK_PLL_RESET_ACTIVE_LOW BIT(9) 81#define IPROC_CLK_PLL_RESET_ACTIVE_LOW BIT(9)
82 82
83/* 83/*
84 * Calculate the PLL parameters are runtime, instead of using table
85 */
86#define IPROC_CLK_PLL_CALC_PARAM BIT(10)
87
88/*
84 * Parameters for VCO frequency configuration 89 * Parameters for VCO frequency configuration
85 * 90 *
86 * VCO frequency = 91 * VCO frequency =