diff options
author | Thierry Reding <treding@nvidia.com> | 2014-04-04 09:55:13 -0400 |
---|---|---|
committer | Peter De Schrijver <pdeschrijver@nvidia.com> | 2014-04-17 07:12:34 -0400 |
commit | d0f02ce3b1685ef6ffe43692034599790f83e7ab (patch) | |
tree | 08b7289a4e5db66417e3d1455577345f29114ed1 | |
parent | c9eaa447e77efe77b7fa4c953bd62de8297fd6c5 (diff) |
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>
-rw-r--r-- | drivers/clk/tegra/clk-pll.c | 30 |
1 files changed, 24 insertions, 6 deletions
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 @@ | |||
58 | #define PLLDU_LFCON_SET_DIVN 600 | 58 | #define PLLDU_LFCON_SET_DIVN 600 |
59 | 59 | ||
60 | #define PLLE_BASE_DIVCML_SHIFT 24 | 60 | #define PLLE_BASE_DIVCML_SHIFT 24 |
61 | #define PLLE_BASE_DIVCML_WIDTH 4 | 61 | #define PLLE_BASE_DIVCML_MASK 0xf |
62 | #define PLLE_BASE_DIVP_SHIFT 16 | 62 | #define PLLE_BASE_DIVP_SHIFT 16 |
63 | #define PLLE_BASE_DIVP_WIDTH 7 | 63 | #define PLLE_BASE_DIVP_WIDTH 6 |
64 | #define PLLE_BASE_DIVN_SHIFT 8 | 64 | #define PLLE_BASE_DIVN_SHIFT 8 |
65 | #define PLLE_BASE_DIVN_WIDTH 8 | 65 | #define PLLE_BASE_DIVN_WIDTH 8 |
66 | #define PLLE_BASE_DIVM_SHIFT 0 | 66 | #define PLLE_BASE_DIVM_SHIFT 0 |
@@ -730,8 +730,10 @@ static int clk_plle_enable(struct clk_hw *hw) | |||
730 | if (pll->params->flags & TEGRA_PLLE_CONFIGURE) { | 730 | if (pll->params->flags & TEGRA_PLLE_CONFIGURE) { |
731 | /* configure dividers */ | 731 | /* configure dividers */ |
732 | val = pll_readl_base(pll); | 732 | val = pll_readl_base(pll); |
733 | val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll)); | 733 | val &= ~(divp_mask(pll) << PLLE_BASE_DIVP_SHIFT | |
734 | val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT); | 734 | divn_mask(pll) << PLLE_BASE_DIVN_SHIFT | |
735 | divm_mask(pll) << PLLE_BASE_DIVM_SHIFT); | ||
736 | val &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT); | ||
735 | val |= sel.m << pll->params->div_nmp->divm_shift; | 737 | val |= sel.m << pll->params->div_nmp->divm_shift; |
736 | val |= sel.n << pll->params->div_nmp->divn_shift; | 738 | val |= sel.n << pll->params->div_nmp->divn_shift; |
737 | val |= sel.p << pll->params->div_nmp->divp_shift; | 739 | val |= sel.p << pll->params->div_nmp->divp_shift; |
@@ -745,6 +747,7 @@ static int clk_plle_enable(struct clk_hw *hw) | |||
745 | pll_writel_misc(val, pll); | 747 | pll_writel_misc(val, pll); |
746 | 748 | ||
747 | val = readl(pll->clk_base + PLLE_SS_CTRL); | 749 | val = readl(pll->clk_base + PLLE_SS_CTRL); |
750 | val &= ~PLLE_SS_COEFFICIENTS_MASK; | ||
748 | val |= PLLE_SS_DISABLE; | 751 | val |= PLLE_SS_DISABLE; |
749 | writel(val, pll->clk_base + PLLE_SS_CTRL); | 752 | writel(val, pll->clk_base + PLLE_SS_CTRL); |
750 | 753 | ||
@@ -1292,8 +1295,10 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw) | |||
1292 | pll_writel(val, PLLE_SS_CTRL, pll); | 1295 | pll_writel(val, PLLE_SS_CTRL, pll); |
1293 | 1296 | ||
1294 | val = pll_readl_base(pll); | 1297 | val = pll_readl_base(pll); |
1295 | val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll)); | 1298 | val &= ~(divp_mask(pll) << PLLE_BASE_DIVP_SHIFT | |
1296 | val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT); | 1299 | divn_mask(pll) << PLLE_BASE_DIVN_SHIFT | |
1300 | divm_mask(pll) << PLLE_BASE_DIVM_SHIFT); | ||
1301 | val &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT); | ||
1297 | val |= sel.m << pll->params->div_nmp->divm_shift; | 1302 | val |= sel.m << pll->params->div_nmp->divm_shift; |
1298 | val |= sel.n << pll->params->div_nmp->divn_shift; | 1303 | val |= sel.n << pll->params->div_nmp->divn_shift; |
1299 | val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; | 1304 | val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; |
@@ -1410,6 +1415,15 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, | |||
1410 | return clk; | 1415 | return clk; |
1411 | } | 1416 | } |
1412 | 1417 | ||
1418 | static struct div_nmp pll_e_nmp = { | ||
1419 | .divn_shift = PLLE_BASE_DIVN_SHIFT, | ||
1420 | .divn_width = PLLE_BASE_DIVN_WIDTH, | ||
1421 | .divm_shift = PLLE_BASE_DIVM_SHIFT, | ||
1422 | .divm_width = PLLE_BASE_DIVM_WIDTH, | ||
1423 | .divp_shift = PLLE_BASE_DIVP_SHIFT, | ||
1424 | .divp_width = PLLE_BASE_DIVP_WIDTH, | ||
1425 | }; | ||
1426 | |||
1413 | struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, | 1427 | struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, |
1414 | void __iomem *clk_base, void __iomem *pmc, | 1428 | void __iomem *clk_base, void __iomem *pmc, |
1415 | unsigned long flags, struct tegra_clk_pll_params *pll_params, | 1429 | 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, | |||
1420 | 1434 | ||
1421 | pll_params->flags |= TEGRA_PLL_LOCK_MISC | TEGRA_PLL_BYPASS; | 1435 | pll_params->flags |= TEGRA_PLL_LOCK_MISC | TEGRA_PLL_BYPASS; |
1422 | pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE; | 1436 | pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE; |
1437 | |||
1438 | if (!pll_params->div_nmp) | ||
1439 | pll_params->div_nmp = &pll_e_nmp; | ||
1440 | |||
1423 | pll = _tegra_init_pll(clk_base, pmc, pll_params, lock); | 1441 | pll = _tegra_init_pll(clk_base, pmc, pll_params, lock); |
1424 | if (IS_ERR(pll)) | 1442 | if (IS_ERR(pll)) |
1425 | return ERR_CAST(pll); | 1443 | return ERR_CAST(pll); |