From d0f02ce3b1685ef6ffe43692034599790f83e7ab Mon Sep 17 00:00:00 2001 From: Thierry Reding <treding@nvidia.com> Date: Fri, 4 Apr 2014 15:55:13 +0200 Subject: clk: tegra: Fix PLLE programming PLLE has M, N and P divider shift and width parameters that differ from the defaults. Furthermore, when clearing the M, N and P divider fields the corresponding masks were never shifted, thereby clearing only the lowest bits of the register. This lead to a situation where the PLLE programming would only work if the register hadn't been touched before. Signed-off-by: Thierry Reding <treding@nvidia.com> Acked-by: Stephen Warren <swarren@nvidia.com> --- drivers/clk/tegra/clk-pll.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 0d20241e0770..357911303315 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -58,9 +58,9 @@ #define PLLDU_LFCON_SET_DIVN 600 #define PLLE_BASE_DIVCML_SHIFT 24 -#define PLLE_BASE_DIVCML_WIDTH 4 +#define PLLE_BASE_DIVCML_MASK 0xf #define PLLE_BASE_DIVP_SHIFT 16 -#define PLLE_BASE_DIVP_WIDTH 7 +#define PLLE_BASE_DIVP_WIDTH 6 #define PLLE_BASE_DIVN_SHIFT 8 #define PLLE_BASE_DIVN_WIDTH 8 #define PLLE_BASE_DIVM_SHIFT 0 @@ -730,8 +730,10 @@ static int clk_plle_enable(struct clk_hw *hw) if (pll->params->flags & TEGRA_PLLE_CONFIGURE) { /* configure dividers */ val = pll_readl_base(pll); - val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll)); - val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT); + val &= ~(divp_mask(pll) << PLLE_BASE_DIVP_SHIFT | + divn_mask(pll) << PLLE_BASE_DIVN_SHIFT | + divm_mask(pll) << PLLE_BASE_DIVM_SHIFT); + val &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT); val |= sel.m << pll->params->div_nmp->divm_shift; val |= sel.n << pll->params->div_nmp->divn_shift; val |= sel.p << pll->params->div_nmp->divp_shift; @@ -745,6 +747,7 @@ static int clk_plle_enable(struct clk_hw *hw) pll_writel_misc(val, pll); val = readl(pll->clk_base + PLLE_SS_CTRL); + val &= ~PLLE_SS_COEFFICIENTS_MASK; val |= PLLE_SS_DISABLE; writel(val, pll->clk_base + PLLE_SS_CTRL); @@ -1292,8 +1295,10 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw) pll_writel(val, PLLE_SS_CTRL, pll); val = pll_readl_base(pll); - val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll)); - val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT); + val &= ~(divp_mask(pll) << PLLE_BASE_DIVP_SHIFT | + divn_mask(pll) << PLLE_BASE_DIVN_SHIFT | + divm_mask(pll) << PLLE_BASE_DIVM_SHIFT); + val &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT); val |= sel.m << pll->params->div_nmp->divm_shift; val |= sel.n << pll->params->div_nmp->divn_shift; val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; @@ -1410,6 +1415,15 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, return clk; } +static struct div_nmp pll_e_nmp = { + .divn_shift = PLLE_BASE_DIVN_SHIFT, + .divn_width = PLLE_BASE_DIVN_WIDTH, + .divm_shift = PLLE_BASE_DIVM_SHIFT, + .divm_width = PLLE_BASE_DIVM_WIDTH, + .divp_shift = PLLE_BASE_DIVP_SHIFT, + .divp_width = PLLE_BASE_DIVP_WIDTH, +}; + struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, unsigned long flags, struct tegra_clk_pll_params *pll_params, @@ -1420,6 +1434,10 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, pll_params->flags |= TEGRA_PLL_LOCK_MISC | TEGRA_PLL_BYPASS; pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + + if (!pll_params->div_nmp) + pll_params->div_nmp = &pll_e_nmp; + pll = _tegra_init_pll(clk_base, pmc, pll_params, lock); if (IS_ERR(pll)) return ERR_CAST(pll); -- cgit v1.2.3 From c61e4e75b95bda4c6fec134aa9f08b5629b532e6 Mon Sep 17 00:00:00 2001 From: Thierry Reding <treding@nvidia.com> Date: Fri, 4 Apr 2014 15:55:14 +0200 Subject: clk: tegra: Introduce divider mask and shift helpers Add div{m,n,p}_shift() and div{m,n,p}_mask_shifted() helpers to make the code that modifies the m-, n- and p-divider fields of PLLs shorter and easier to read. Signed-off-by: Thierry Reding <treding@nvidia.com> --- drivers/clk/tegra/clk-pll.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 357911303315..1187187a1cf2 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -183,6 +183,14 @@ #define divp_mask(p) (p->params->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :\ mask(p->params->div_nmp->divp_width)) +#define divm_shift(p) (p)->params->div_nmp->divm_shift +#define divn_shift(p) (p)->params->div_nmp->divn_shift +#define divp_shift(p) (p)->params->div_nmp->divp_shift + +#define divm_mask_shifted(p) (divm_mask(p) << divm_shift(p)) +#define divn_mask_shifted(p) (divn_mask(p) << divn_shift(p)) +#define divp_mask_shifted(p) (divp_mask(p) << divp_shift(p)) + #define divm_max(p) (divm_mask(p)) #define divn_max(p) (divn_mask(p)) #define divp_max(p) (1 << (divp_mask(p))) @@ -476,13 +484,12 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll, } else { val = pll_readl_base(pll); - val &= ~((divm_mask(pll) << div_nmp->divm_shift) | - (divn_mask(pll) << div_nmp->divn_shift) | - (divp_mask(pll) << div_nmp->divp_shift)); + val &= ~(divm_mask_shifted(pll) | divn_mask_shifted(pll) | + divp_mask_shifted(pll)); - val |= ((cfg->m << div_nmp->divm_shift) | - (cfg->n << div_nmp->divn_shift) | - (cfg->p << div_nmp->divp_shift)); + val |= (cfg->m << divm_shift(pll)) | + (cfg->n << divn_shift(pll)) | + (cfg->p << divp_shift(pll)); pll_writel_base(val, pll); } @@ -730,13 +737,12 @@ static int clk_plle_enable(struct clk_hw *hw) if (pll->params->flags & TEGRA_PLLE_CONFIGURE) { /* configure dividers */ val = pll_readl_base(pll); - val &= ~(divp_mask(pll) << PLLE_BASE_DIVP_SHIFT | - divn_mask(pll) << PLLE_BASE_DIVN_SHIFT | - divm_mask(pll) << PLLE_BASE_DIVM_SHIFT); + val &= ~(divp_mask_shifted(pll) | divn_mask_shifted(pll) | + divm_mask_shifted(pll)); val &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT); - val |= sel.m << pll->params->div_nmp->divm_shift; - val |= sel.n << pll->params->div_nmp->divn_shift; - val |= sel.p << pll->params->div_nmp->divp_shift; + val |= sel.m << divm_shift(pll); + val |= sel.n << divn_shift(pll); + val |= sel.p << divp_shift(pll); val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; pll_writel_base(val, pll); } @@ -1295,12 +1301,11 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw) pll_writel(val, PLLE_SS_CTRL, pll); val = pll_readl_base(pll); - val &= ~(divp_mask(pll) << PLLE_BASE_DIVP_SHIFT | - divn_mask(pll) << PLLE_BASE_DIVN_SHIFT | - divm_mask(pll) << PLLE_BASE_DIVM_SHIFT); + val &= ~(divp_mask_shifted(pll) | divn_mask_shifted(pll) | + divm_mask_shifted(pll)); val &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT); - val |= sel.m << pll->params->div_nmp->divm_shift; - val |= sel.n << pll->params->div_nmp->divn_shift; + val |= sel.m << divm_shift(pll); + val |= sel.n << divn_shift(pll); val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; pll_writel_base(val, pll); udelay(1); @@ -1575,9 +1580,8 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name, int m; m = _pll_fixed_mdiv(pll_params, parent_rate); - val = m << PLL_BASE_DIVM_SHIFT; - val |= (pll_params->vco_min / parent_rate) - << PLL_BASE_DIVN_SHIFT; + val = m << divm_shift(pll); + val |= (pll_params->vco_min / parent_rate) << divn_shift(pll); pll_writel_base(val, pll); } -- cgit v1.2.3 From 4ccc402ece35695dd2884ec0b652d52ae0230f13 Mon Sep 17 00:00:00 2001 From: Thierry Reding <treding@nvidia.com> Date: Fri, 4 Apr 2014 15:55:15 +0200 Subject: clk: tegra: Fix enabling of PLLE When enabling the PLLE as its final step, clk_plle_enable() would accidentally OR in the value previously written to the PLLE_SS_CTRL register. Signed-off-by: Thierry Reding <treding@nvidia.com> --- drivers/clk/tegra/clk-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 1187187a1cf2..7a1b70dac824 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -757,7 +757,7 @@ static int clk_plle_enable(struct clk_hw *hw) val |= PLLE_SS_DISABLE; writel(val, pll->clk_base + PLLE_SS_CTRL); - val |= pll_readl_base(pll); + val = pll_readl_base(pll); val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE); pll_writel_base(val, pll); -- cgit v1.2.3 From fe52e7505f8bf365d5ab0eeee19ababe406cbaaf Mon Sep 17 00:00:00 2001 From: Maxime COQUELIN <maxime.coquelin@st.com> Date: Wed, 7 May 2014 18:48:52 +0200 Subject: clk: divider: Fix table round up function Commit 1d9fe6b97 ("clk: divider: Fix best div calculation for power-of-two and table dividers") introduces a regression in its _table_round_up function. When the divider passed to this function is greater than the max divider available in the table, this function returns table's max divider. Problem is that it causes an infinite loop in clk_divider_bestdiv() because _next_div() will never return a value greater than maxdiv. Instead of returning table's max divider, this patch returns INT_MAX. Reported-by: Fabio Estevam <festevam@gmail.com> Reported-by: Shawn Guo <shawn.guo@freescale.com> Tested-by: Fabio Estevam <festevam@gmail.com> Tested-by: Shawn Guo <shawn.guo@freescale.com> Signed-off-by: Maxime Coquelin <maxime.coquelin@st.com> Signed-off-by: Mike Turquette <mturquette@linaro.org> --- drivers/clk/clk-divider.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/clk') diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 4637697c139f..3fbee4540228 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -147,7 +147,7 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div) static int _round_up_table(const struct clk_div_table *table, int div) { const struct clk_div_table *clkt; - int up = _get_table_maxdiv(table); + int up = INT_MAX; for (clkt = table; clkt->div; clkt++) { if (clkt->div == div) -- cgit v1.2.3 From 72b1c2c3a4de8891b06df18da95514d69eae65de Mon Sep 17 00:00:00 2001 From: Valentin Ilie <valentin.ilie@gmail.com> Date: Tue, 22 Apr 2014 16:15:54 +0300 Subject: clk: st: Fix memory leak When it fails to allocate div, gate should be free'd before return Signed-off-by: Valentin Ilie <valentin.ilie@gmail.com> Signed-off-by: Mike Turquette <mturquette@linaro.org> --- drivers/clk/st/clkgen-pll.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/clk') diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c index bca0a0badbfa..a886702f7c8b 100644 --- a/drivers/clk/st/clkgen-pll.c +++ b/drivers/clk/st/clkgen-pll.c @@ -521,8 +521,10 @@ static struct clk * __init clkgen_odf_register(const char *parent_name, gate->lock = odf_lock; div = kzalloc(sizeof(*div), GFP_KERNEL); - if (!div) + if (!div) { + kfree(gate); return ERR_PTR(-ENOMEM); + } div->flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO; div->reg = reg + pll_data->odf[odf].offset; -- cgit v1.2.3