aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAbhishek Sahu <absahu@codeaurora.org>2017-09-28 13:50:41 -0400
committerStephen Boyd <sboyd@codeaurora.org>2017-12-13 16:45:31 -0500
commit1e859d3e03f0ac97d15e1952bddda4b29de1c71c (patch)
tree5ba5a79a34e0d4e8b3b7b5ef2e7ddab6428a153f
parent28d3f06e56baa9c6e2c8e1d9e5fd663138c08b92 (diff)
clk: qcom: fix 16 bit alpha support calculation
The alpha value calculation has been written for 40-bit alpha values which doesn't work work properly for 16-bit ones. The alpha value is calculated on the basis of ALPHA_BITWIDTH to make the computation easy for 40 bit alpha. After calculating the 32 bit alpha, it is converted to 40 bit alpha by making lower bits zero. But if actual alpha register width is less than ALPHA_BITWIDTH, then the actual width can be used for calculation. This also means, during the 40 bit alpha pll set rate path, the lower alpha register is not configured Change the code to calculate the rate and register values from 'alpha_width' instead of hard-coding it so that it can work for the different widths that are supported. Signed-off-by: Abhishek Sahu <absahu@codeaurora.org> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.c58
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.h1
2 files changed, 34 insertions, 25 deletions
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index 446a9a4eee18..3890f20be7d5 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -74,8 +74,13 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
74 * Even though 40 bits are present, use only 32 for ease of calculation. 74 * Even though 40 bits are present, use only 32 for ease of calculation.
75 */ 75 */
76#define ALPHA_REG_BITWIDTH 40 76#define ALPHA_REG_BITWIDTH 40
77#define ALPHA_BITWIDTH 32 77#define ALPHA_REG_16BIT_WIDTH 16
78#define ALPHA_16BIT_MASK 0xffff 78#define ALPHA_BITWIDTH 32U
79#define ALPHA_SHIFT(w) min(w, ALPHA_BITWIDTH)
80
81#define pll_alpha_width(p) \
82 ((PLL_ALPHA_VAL_U(p) - PLL_ALPHA_VAL(p) == 4) ? \
83 ALPHA_REG_BITWIDTH : ALPHA_REG_16BIT_WIDTH)
79 84
80#define to_clk_alpha_pll(_hw) container_of(to_clk_regmap(_hw), \ 85#define to_clk_alpha_pll(_hw) container_of(to_clk_regmap(_hw), \
81 struct clk_alpha_pll, clkr) 86 struct clk_alpha_pll, clkr)
@@ -312,13 +317,15 @@ static void clk_alpha_pll_disable(struct clk_hw *hw)
312 regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), mask, 0); 317 regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), mask, 0);
313} 318}
314 319
315static unsigned long alpha_pll_calc_rate(u64 prate, u32 l, u32 a) 320static unsigned long
321alpha_pll_calc_rate(u64 prate, u32 l, u32 a, u32 alpha_width)
316{ 322{
317 return (prate * l) + ((prate * a) >> ALPHA_BITWIDTH); 323 return (prate * l) + ((prate * a) >> ALPHA_SHIFT(alpha_width));
318} 324}
319 325
320static unsigned long 326static unsigned long
321alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a) 327alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a,
328 u32 alpha_width)
322{ 329{
323 u64 remainder; 330 u64 remainder;
324 u64 quotient; 331 u64 quotient;
@@ -333,14 +340,15 @@ alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a)
333 } 340 }
334 341
335 /* Upper ALPHA_BITWIDTH bits of Alpha */ 342 /* Upper ALPHA_BITWIDTH bits of Alpha */
336 quotient = remainder << ALPHA_BITWIDTH; 343 quotient = remainder << ALPHA_SHIFT(alpha_width);
344
337 remainder = do_div(quotient, prate); 345 remainder = do_div(quotient, prate);
338 346
339 if (remainder) 347 if (remainder)
340 quotient++; 348 quotient++;
341 349
342 *a = quotient; 350 *a = quotient;
343 return alpha_pll_calc_rate(prate, *l, *a); 351 return alpha_pll_calc_rate(prate, *l, *a, alpha_width);
344} 352}
345 353
346static const struct pll_vco * 354static const struct pll_vco *
@@ -362,23 +370,26 @@ clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
362 u32 l, low, high, ctl; 370 u32 l, low, high, ctl;
363 u64 a = 0, prate = parent_rate; 371 u64 a = 0, prate = parent_rate;
364 struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); 372 struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
373 u32 alpha_width = pll_alpha_width(pll);
365 374
366 regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); 375 regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l);
367 376
368 regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); 377 regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl);
369 if (ctl & PLL_ALPHA_EN) { 378 if (ctl & PLL_ALPHA_EN) {
370 regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &low); 379 regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &low);
371 if (pll->flags & SUPPORTS_16BIT_ALPHA) { 380 if (alpha_width > 32) {
372 a = low & ALPHA_16BIT_MASK;
373 } else {
374 regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), 381 regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll),
375 &high); 382 &high);
376 a = (u64)high << 32 | low; 383 a = (u64)high << 32 | low;
377 a >>= ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH; 384 } else {
385 a = low & GENMASK(alpha_width - 1, 0);
378 } 386 }
387
388 if (alpha_width > ALPHA_BITWIDTH)
389 a >>= alpha_width - ALPHA_BITWIDTH;
379 } 390 }
380 391
381 return alpha_pll_calc_rate(prate, l, a); 392 return alpha_pll_calc_rate(prate, l, a, alpha_width);
382} 393}
383 394
384static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate, 395static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -386,10 +397,10 @@ static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
386{ 397{
387 struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); 398 struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
388 const struct pll_vco *vco; 399 const struct pll_vco *vco;
389 u32 l; 400 u32 l, alpha_width = pll_alpha_width(pll);
390 u64 a; 401 u64 a;
391 402
392 rate = alpha_pll_round_rate(rate, prate, &l, &a); 403 rate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width);
393 vco = alpha_pll_find_vco(pll, rate); 404 vco = alpha_pll_find_vco(pll, rate);
394 if (!vco) { 405 if (!vco) {
395 pr_err("alpha pll not in a valid vco range\n"); 406 pr_err("alpha pll not in a valid vco range\n");
@@ -398,14 +409,13 @@ static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
398 409
399 regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); 410 regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
400 411
401 if (pll->flags & SUPPORTS_16BIT_ALPHA) { 412 if (alpha_width > ALPHA_BITWIDTH)
402 regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), 413 a <<= alpha_width - ALPHA_BITWIDTH;
403 a & ALPHA_16BIT_MASK); 414
404 } else { 415 if (alpha_width > 32)
405 a <<= (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH); 416 regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), a >> 32);
406 regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), 417
407 a >> 32); 418 regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a);
408 }
409 419
410 regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), 420 regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll),
411 PLL_VCO_MASK << PLL_VCO_SHIFT, 421 PLL_VCO_MASK << PLL_VCO_SHIFT,
@@ -421,11 +431,11 @@ static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate,
421 unsigned long *prate) 431 unsigned long *prate)
422{ 432{
423 struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); 433 struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
424 u32 l; 434 u32 l, alpha_width = pll_alpha_width(pll);
425 u64 a; 435 u64 a;
426 unsigned long min_freq, max_freq; 436 unsigned long min_freq, max_freq;
427 437
428 rate = alpha_pll_round_rate(rate, *prate, &l, &a); 438 rate = alpha_pll_round_rate(rate, *prate, &l, &a, alpha_width);
429 if (alpha_pll_find_vco(pll, rate)) 439 if (alpha_pll_find_vco(pll, rate))
430 return rate; 440 return rate;
431 441
diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h
index ef7c75effbfe..18c0c3eff855 100644
--- a/drivers/clk/qcom/clk-alpha-pll.h
+++ b/drivers/clk/qcom/clk-alpha-pll.h
@@ -59,7 +59,6 @@ struct clk_alpha_pll {
59 const struct pll_vco *vco_table; 59 const struct pll_vco *vco_table;
60 size_t num_vco; 60 size_t num_vco;
61#define SUPPORTS_OFFLINE_REQ BIT(0) 61#define SUPPORTS_OFFLINE_REQ BIT(0)
62#define SUPPORTS_16BIT_ALPHA BIT(1)
63#define SUPPORTS_FSM_MODE BIT(2) 62#define SUPPORTS_FSM_MODE BIT(2)
64 u8 flags; 63 u8 flags;
65 64