]> git.baikalelectronics.ru Git - kernel.git/commitdiff
clk: qcom: fix 16 bit alpha support calculation
authorAbhishek Sahu <absahu@codeaurora.org>
Thu, 28 Sep 2017 17:50:41 +0000 (23:20 +0530)
committerStephen Boyd <sboyd@codeaurora.org>
Wed, 13 Dec 2017 21:45:31 +0000 (13:45 -0800)
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>
drivers/clk/qcom/clk-alpha-pll.c
drivers/clk/qcom/clk-alpha-pll.h

index 446a9a4eee186cb6e44934e66b530aba049bd426..3890f20be7d544352593f8c4a5c2cd69b1311583 100644 (file)
@@ -74,8 +74,13 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
  * Even though 40 bits are present, use only 32 for ease of calculation.
  */
 #define ALPHA_REG_BITWIDTH     40
-#define ALPHA_BITWIDTH         32
-#define ALPHA_16BIT_MASK       0xffff
+#define ALPHA_REG_16BIT_WIDTH  16
+#define ALPHA_BITWIDTH         32U
+#define ALPHA_SHIFT(w)         min(w, ALPHA_BITWIDTH)
+
+#define pll_alpha_width(p)                                     \
+               ((PLL_ALPHA_VAL_U(p) - PLL_ALPHA_VAL(p) == 4) ? \
+                                ALPHA_REG_BITWIDTH : ALPHA_REG_16BIT_WIDTH)
 
 #define to_clk_alpha_pll(_hw) container_of(to_clk_regmap(_hw), \
                                           struct clk_alpha_pll, clkr)
@@ -312,13 +317,15 @@ static void clk_alpha_pll_disable(struct clk_hw *hw)
        regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), mask, 0);
 }
 
-static unsigned long alpha_pll_calc_rate(u64 prate, u32 l, u32 a)
+static unsigned long
+alpha_pll_calc_rate(u64 prate, u32 l, u32 a, u32 alpha_width)
 {
-       return (prate * l) + ((prate * a) >> ALPHA_BITWIDTH);
+       return (prate * l) + ((prate * a) >> ALPHA_SHIFT(alpha_width));
 }
 
 static unsigned long
-alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a)
+alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a,
+                    u32 alpha_width)
 {
        u64 remainder;
        u64 quotient;
@@ -333,14 +340,15 @@ alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a)
        }
 
        /* Upper ALPHA_BITWIDTH bits of Alpha */
-       quotient = remainder << ALPHA_BITWIDTH;
+       quotient = remainder << ALPHA_SHIFT(alpha_width);
+
        remainder = do_div(quotient, prate);
 
        if (remainder)
                quotient++;
 
        *a = quotient;
-       return alpha_pll_calc_rate(prate, *l, *a);
+       return alpha_pll_calc_rate(prate, *l, *a, alpha_width);
 }
 
 static const struct pll_vco *
@@ -362,23 +370,26 @@ clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
        u32 l, low, high, ctl;
        u64 a = 0, prate = parent_rate;
        struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+       u32 alpha_width = pll_alpha_width(pll);
 
        regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l);
 
        regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl);
        if (ctl & PLL_ALPHA_EN) {
                regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &low);
-               if (pll->flags & SUPPORTS_16BIT_ALPHA) {
-                       a = low & ALPHA_16BIT_MASK;
-               } else {
+               if (alpha_width > 32) {
                        regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll),
                                    &high);
                        a = (u64)high << 32 | low;
-                       a >>= ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH;
+               } else {
+                       a = low & GENMASK(alpha_width - 1, 0);
                }
+
+               if (alpha_width > ALPHA_BITWIDTH)
+                       a >>= alpha_width - ALPHA_BITWIDTH;
        }
 
-       return alpha_pll_calc_rate(prate, l, a);
+       return alpha_pll_calc_rate(prate, l, a, alpha_width);
 }
 
 static 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,
 {
        struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
        const struct pll_vco *vco;
-       u32 l;
+       u32 l, alpha_width = pll_alpha_width(pll);
        u64 a;
 
-       rate = alpha_pll_round_rate(rate, prate, &l, &a);
+       rate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width);
        vco = alpha_pll_find_vco(pll, rate);
        if (!vco) {
                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,
 
        regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
 
-       if (pll->flags & SUPPORTS_16BIT_ALPHA) {
-               regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll),
-                            a & ALPHA_16BIT_MASK);
-       } else {
-               a <<= (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH);
-               regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll),
-                            a >> 32);
-       }
+       if (alpha_width > ALPHA_BITWIDTH)
+               a <<= alpha_width - ALPHA_BITWIDTH;
+
+       if (alpha_width > 32)
+               regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), a >> 32);
+
+       regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a);
 
        regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll),
                           PLL_VCO_MASK << PLL_VCO_SHIFT,
@@ -421,11 +431,11 @@ static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate,
                                     unsigned long *prate)
 {
        struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
-       u32 l;
+       u32 l, alpha_width = pll_alpha_width(pll);
        u64 a;
        unsigned long min_freq, max_freq;
 
-       rate = alpha_pll_round_rate(rate, *prate, &l, &a);
+       rate = alpha_pll_round_rate(rate, *prate, &l, &a, alpha_width);
        if (alpha_pll_find_vco(pll, rate))
                return rate;
 
index ef7c75effbfe2be5381b999239e96fc3c550638a..18c0c3eff85544ea99217718a433b08e28c10b4f 100644 (file)
@@ -59,7 +59,6 @@ struct clk_alpha_pll {
        const struct pll_vco *vco_table;
        size_t num_vco;
 #define SUPPORTS_OFFLINE_REQ   BIT(0)
-#define SUPPORTS_16BIT_ALPHA   BIT(1)
 #define SUPPORTS_FSM_MODE      BIT(2)
        u8 flags;