summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter De Schrijver <pdeschrijver@nvidia.com>2013-06-05 16:51:25 +0300
committerMike Turquette <mturquette@linaro.org>2013-06-11 17:38:39 -0700
commitaa6fefde62401a84154161a8026872874a70e4c1 (patch)
treeb1787ce0bfe3258b9584f04a9ed49f30bfa6e66b
parentc388eee21ad20929f440d6fae94c995791c5818b (diff)
clk: tegra: allow PLL m,n,p init from SoC files
The m,n,p fields don't have the same bit offset and width across all PLLs. This patch allows SoC specific files to indicate the offset and width. Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> Tested-by: Stephen Warren <swarren@nvidia.com> Acked-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r--drivers/clk/tegra/clk-pll.c60
-rw-r--r--drivers/clk/tegra/clk.h32
2 files changed, 53 insertions, 39 deletions
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 85bec1dd87d..3b778d3c828 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -134,15 +134,24 @@
#define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p)
#define mask(w) ((1 << (w)) - 1)
-#define divm_mask(p) mask(p->divm_width)
-#define divn_mask(p) mask(p->divn_width)
+#define divm_mask(p) mask(p->params->div_nmp->divm_width)
+#define divn_mask(p) mask(p->params->div_nmp->divn_width)
#define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \
- mask(p->divp_width))
+ mask(p->params->div_nmp->divp_width))
#define divm_max(p) (divm_mask(p))
#define divn_max(p) (divn_mask(p))
#define divp_max(p) (1 << (divp_mask(p)))
+static struct div_nmp default_nmp = {
+ .divn_shift = PLL_BASE_DIVN_SHIFT,
+ .divn_width = PLL_BASE_DIVN_WIDTH,
+ .divm_shift = PLL_BASE_DIVM_SHIFT,
+ .divm_width = PLL_BASE_DIVM_WIDTH,
+ .divp_shift = PLL_BASE_DIVP_SHIFT,
+ .divp_width = PLL_BASE_DIVP_WIDTH,
+};
+
static void clk_pll_enable_lock(struct tegra_clk_pll *pll)
{
u32 val;
@@ -407,12 +416,12 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll,
val = pll_readl_base(pll);
- val &= ~((divm_mask(pll) << pll->divm_shift) |
- (divn_mask(pll) << pll->divn_shift) |
- (divp_mask(pll) << pll->divp_shift));
- val |= ((cfg->m << pll->divm_shift) |
- (cfg->n << pll->divn_shift) |
- (cfg->p << pll->divp_shift));
+ val &= ~((divm_mask(pll) << pll->params->div_nmp->divm_shift) |
+ (divn_mask(pll) << pll->params->div_nmp->divn_shift) |
+ (divp_mask(pll) << pll->params->div_nmp->divp_shift));
+ val |= ((cfg->m << pll->params->div_nmp->divm_shift) |
+ (cfg->n << pll->params->div_nmp->divn_shift) |
+ (cfg->p << pll->params->div_nmp->divp_shift));
pll_writel_base(val, pll);
}
@@ -424,9 +433,9 @@ static void _get_pll_mnp(struct tegra_clk_pll *pll,
val = pll_readl_base(pll);
- cfg->m = (val >> pll->divm_shift) & (divm_mask(pll));
- cfg->n = (val >> pll->divn_shift) & (divn_mask(pll));
- cfg->p = (val >> pll->divp_shift) & (divp_mask(pll));
+ cfg->m = (val >> pll->params->div_nmp->divm_shift) & (divm_mask(pll));
+ cfg->n = (val >> pll->params->div_nmp->divn_shift) & (divn_mask(pll));
+ cfg->p = (val >> pll->params->div_nmp->divp_shift) & (divp_mask(pll));
}
static void _update_pll_cpcon(struct tegra_clk_pll *pll,
@@ -646,9 +655,9 @@ static int clk_plle_enable(struct clk_hw *hw)
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 |= sel.m << pll->divm_shift;
- val |= sel.n << pll->divn_shift;
- val |= sel.p << pll->divp_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.cpcon << PLLE_BASE_DIVCML_SHIFT;
pll_writel_base(val, pll);
}
@@ -679,9 +688,9 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
u32 divn = 0, divm = 0, divp = 0;
u64 rate = parent_rate;
- divp = (val >> pll->divp_shift) & (divp_mask(pll));
- divn = (val >> pll->divn_shift) & (divn_mask(pll));
- divm = (val >> pll->divm_shift) & (divm_mask(pll));
+ divp = (val >> pll->params->div_nmp->divp_shift) & (divp_mask(pll));
+ divn = (val >> pll->params->div_nmp->divn_shift) & (divn_mask(pll));
+ divm = (val >> pll->params->div_nmp->divm_shift) & (divm_mask(pll));
divm *= divp;
rate *= divn;
@@ -902,7 +911,8 @@ static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,
val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE);
val &= ~(divn_mask(pll) | divm_mask(pll));
- val |= (cfg.m << pll->divm_shift) | (cfg.n << pll->divn_shift);
+ val |= (cfg.m << pll->params->div_nmp->divm_shift) |
+ (cfg.n << pll->params->div_nmp->divn_shift);
writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE);
} else
_update_pll_mnp(pll, &cfg);
@@ -1180,8 +1190,8 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
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 |= sel.m << pll->divm_shift;
- val |= sel.n << pll->divn_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;
pll_writel_base(val, pll);
udelay(1);
@@ -1242,12 +1252,8 @@ static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base,
pll->flags = pll_flags;
pll->lock = lock;
- pll->divp_shift = PLL_BASE_DIVP_SHIFT;
- pll->divp_width = PLL_BASE_DIVP_WIDTH;
- pll->divn_shift = PLL_BASE_DIVN_SHIFT;
- pll->divn_width = PLL_BASE_DIVN_WIDTH;
- pll->divm_shift = PLL_BASE_DIVM_SHIFT;
- pll->divm_width = PLL_BASE_DIVM_WIDTH;
+ if (!pll_params->div_nmp)
+ pll_params->div_nmp = &default_nmp;
return pll;
}
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 11278a80e63..d70eb2d2957 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -128,6 +128,25 @@ struct pdiv_map {
};
/**
+ * struct div_nmp - offset and width of m,n and p fields
+ *
+ * @divn_shift: shift to the feedback divider bit field
+ * @divn_width: width of the feedback divider bit field
+ * @divm_shift: shift to the input divider bit field
+ * @divm_width: width of the input divider bit field
+ * @divp_shift: shift to the post divider bit field
+ * @divp_width: width of the post divider bit field
+ */
+struct div_nmp {
+ u8 divn_shift;
+ u8 divn_width;
+ u8 divm_shift;
+ u8 divm_width;
+ u8 divp_shift;
+ u8 divp_width;
+};
+
+/**
* struct clk_pll_params - PLL parameters
*
* @input_min: Minimum input frequency
@@ -166,6 +185,7 @@ struct tegra_clk_pll_params {
int lock_delay;
int max_p;
struct pdiv_map *pdiv_tohw;
+ struct div_nmp *div_nmp;
};
/**
@@ -179,12 +199,6 @@ struct tegra_clk_pll_params {
* @flags: PLL flags
* @fixed_rate: PLL rate if it is fixed
* @lock: register lock
- * @divn_shift: shift to the feedback divider bit field
- * @divn_width: width of the feedback divider bit field
- * @divm_shift: shift to the input divider bit field
- * @divm_width: width of the input divider bit field
- * @divp_shift: shift to the post divider bit field
- * @divp_width: width of the post divider bit field
*
* Flags:
* TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
@@ -214,12 +228,6 @@ struct tegra_clk_pll {
u32 flags;
unsigned long fixed_rate;
spinlock_t *lock;
- u8 divn_shift;
- u8 divn_width;
- u8 divm_shift;
- u8 divm_width;
- u8 divp_shift;
- u8 divp_width;
struct tegra_clk_pll_freq_table *freq_table;
struct tegra_clk_pll_params *params;
};