Skip to contentSkip to conversation

Fix iProc PLL output clock frequency calculation

PATCH Superseded Ray Jui 2 participants 3 messages Oct 19, 2015 – Oct 21, 2015

Subsystems (3)
lore
Share & tools
lore

Ray Jui

author maintainer
#0 lore raw

PATCH v2 1/1 Fix iProc PLL output clock frequency calculation

This patch fixes incorrect iProc PLL clock frequency calculation. The issue is exposed when Cygnus audio PLL was being added.

This patch is based on v4.3-rc5 and has been tested on Cygnus bcm958305k wirelss audio board

This full tree is available here:
repo: https://github.com/Broadcom/cygnus-linux.git
branch: iproc-clk-pll-fix-v2

Changes from v1:
- Added "Fixes: ..." tag so the patch is merged back to stable kernel

Simran Rai (1):
clk: iproc: Fix PLL output frequency calculation

 drivers/clk/bcm/clk-iproc-pll.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)
Signature · 1 line
1.9.1
author maintainer
#1 lore raw

PATCH v2 1/1 clk: iproc: Fix PLL output frequency calculation

From: Simran Rai <[email protected]>

This patch affects the clocks that use fractional ndivider in their PLL output frequency calculation. Instead of 2^20 divide factor, the clock's ndiv integer shift was used. Fixed the bug by replacing ndiv integer shift with 2^20 factor.

Fixes 5fe225c105fd ("clk: iproc: add initial common clock support")
---
 drivers/clk/bcm/clk-iproc-pll.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)
drivers/clk/bcm/clk-iproc-pll.c +5 -8
index 2dda4e8..d679ab8 100644
@@ -345,8 +345,8 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw,
 	struct iproc_pll *pll = clk->pll;
 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
 	u32 val;
-	u64 ndiv;
-	unsigned int ndiv_int, ndiv_frac, pdiv;
+	u64 ndiv, ndiv_int, ndiv_frac;
+	unsigned int pdiv;
 
 	if (parent_rate == 0)
 		return 0;
@@ -366,22 +366,19 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw,
 	val = readl(pll->pll_base + ctrl->ndiv_int.offset);
 	ndiv_int = (val >> ctrl->ndiv_int.shift) &
 		bit_mask(ctrl->ndiv_int.width);
-	ndiv = (u64)ndiv_int << ctrl->ndiv_int.shift;
+	ndiv = ndiv_int << 20;
 
 	if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
 		val = readl(pll->pll_base + ctrl->ndiv_frac.offset);
 		ndiv_frac = (val >> ctrl->ndiv_frac.shift) &
 			bit_mask(ctrl->ndiv_frac.width);
-
-		if (ndiv_frac != 0)
-			ndiv = ((u64)ndiv_int << ctrl->ndiv_int.shift) |
-				ndiv_frac;
+		ndiv += ndiv_frac;
 	}
 
 	val = readl(pll->pll_base + ctrl->pdiv.offset);
 	pdiv = (val >> ctrl->pdiv.shift) & bit_mask(ctrl->pdiv.width);
 
-	clk->rate = (ndiv * parent_rate) >> ctrl->ndiv_int.shift;
+	clk->rate = (ndiv * parent_rate) >> 20;
 
 	if (pdiv == 0)
 		clk->rate *= 2;
Signature · 1 line
1.9.1
#2 lore raw

Re: [PATCH v2] clk: iproc: Fix PLL output frequency calculation

Quoting Ray Jui (2015-10-19 15:27:19)

Quoted 9 lines

From: Simran Rai <[email protected]>
=

This patch affects the clocks that use fractional ndivider in their PLL output frequency calculation. Instead of 2^20 divide factor, the clock's ndiv integer shift was used. Fixed the bug by replacing ndiv integer shift with 2^20 factor.
=

Quoted 4 lines
Fixes 5fe225c105fd ("clk: iproc: add initial common clock support")

Applied to clk-next.

Regards,
Mike

drivers/clk/bcm/clk-iproc-=

Quoted 6 lines
---
 drivers/clk/bcm/clk-iproc-pll.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

=

drivers/clk/bcm/clk-iproc-= renamed from drivers/clk/bcm/clk-iproc-pll.c +0 -0

pll.c

drivers/clk/bcm/clk-iproc-pll.c static unsigned long iproc_pll_recalc_rate(struct clk=

Quoted 4 lines

index 2dda4e8..d679ab8 100644

drivers/clk/bcm/clk-iproc-pll.c +0 -0
@@ -345,8 +345,8 @@ static unsigned long iproc_pll_recalc_rate(struct clk=

_hw *hw,

drivers/clk/bcm/clk-iproc-pll.c static unsigned long iproc_pll_recalc_rate(struct c=

Quoted 12 lines
drivers/clk/bcm/clk-iproc-pll.c +2 -2
        struct iproc_pll *pll =3D clk->pll;
        const struct iproc_pll_ctrl *ctrl =3D pll->ctrl;
        u32 val;
-       u64 ndiv;
-       unsigned int ndiv_int, ndiv_frac, pdiv;
+       u64 ndiv, ndiv_int, ndiv_frac;
+       unsigned int pdiv;
 =
 
        if (parent_rate =3D=3D 0)
                return 0;
drivers/clk/bcm/clk-iproc-pll.c +0 -0
@@ -366,22 +366,19 @@ static unsigned long iproc_pll_recalc_rate(struct c=

lk_hw *hw,

Quoted 33 lines
drivers/clk/bcm/clk-iproc-pll.c +3 -6
        val =3D readl(pll->pll_base + ctrl->ndiv_int.offset);
        ndiv_int =3D (val >> ctrl->ndiv_int.shift) &
                bit_mask(ctrl->ndiv_int.width);
-       ndiv =3D (u64)ndiv_int << ctrl->ndiv_int.shift;
+       ndiv =3D ndiv_int << 20;
 =
 
        if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
                val =3D readl(pll->pll_base + ctrl->ndiv_frac.offset);
                ndiv_frac =3D (val >> ctrl->ndiv_frac.shift) &
                        bit_mask(ctrl->ndiv_frac.width);
-
-               if (ndiv_frac !=3D 0)
-                       ndiv =3D ((u64)ndiv_int << ctrl->ndiv_int.shift) |
-                               ndiv_frac;
+               ndiv +=3D ndiv_frac;
        }
 =
 
        val =3D readl(pll->pll_base + ctrl->pdiv.offset);
        pdiv =3D (val >> ctrl->pdiv.shift) & bit_mask(ctrl->pdiv.width);
 =
 
-       clk->rate =3D (ndiv * parent_rate) >> ctrl->ndiv_int.shift;
+       clk->rate =3D (ndiv * parent_rate) >> 20;

=

        if (pdiv =3D=3D 0)
                clk->rate *=3D 2;

-- =

1.9.1
=20