The m,n,p fields don't have the same bit offset and width across all PLLs.
This patchset allows SoC specific files to indicate the offset and width.
It also provides the data for Tegra114.
Peter De Schrijver (2):
clk: tegra: allow PLL m,n,p init from SoC files
clk: tegra: PLL m,n,p init for Tegra114
drivers/clk/tegra/clk-pll.c | 60 ++++++++++++++++-------------
drivers/clk/tegra/clk-tegra114.c | 77 ++++++++++++++++++++++++++++++++++++++
drivers/clk/tegra/clk.h | 32 ++++++++++------
3 files changed, 130 insertions(+), 39 deletions(-)
--
1.7.7.rc0.72.g4b5ea.dirty
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 <[email protected]>
---
drivers/clk/tegra/clk-pll.c | 60 +++++++++++++++++++++++-------------------
drivers/clk/tegra/clk.h | 32 ++++++++++++++--------
2 files changed, 53 insertions(+), 39 deletions(-)
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 85bec1d..3b778d3 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 11278a8..d70eb2d 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;
};
--
1.7.7.rc0.72.g4b5ea.dirty
Signed-off-by: Peter De Schrijver <[email protected]>
---
drivers/clk/tegra/clk-tegra114.c | 77 ++++++++++++++++++++++++++++++++++++++
1 files changed, 77 insertions(+), 0 deletions(-)
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 5e029fe..d29ad1d 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -268,6 +268,15 @@ static DEFINE_SPINLOCK(clk_doubler_lock);
static DEFINE_SPINLOCK(clk_out_lock);
static DEFINE_SPINLOCK(sysrate_lock);
+static struct div_nmp pllxc_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 4,
+};
+
static struct pdiv_map pllxc_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
@@ -316,6 +325,16 @@ static struct tegra_clk_pll_params pll_c_params = {
.stepa_shift = 17,
.stepb_shift = 9,
.pdiv_tohw = pllxc_p,
+ .div_nmp = &pllxc_nmp,
+};
+
+static struct div_nmp pllcx_nmp = {
+ .divm_shift = 0,
+ .divm_width = 2,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 3,
};
static struct pdiv_map pllc_p[] = {
@@ -349,6 +368,8 @@ static struct tegra_clk_pll_params pll_c2_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.pdiv_tohw = pllc_p,
+ .div_nmp = &pllcx_nmp,
+ .max_p = 7,
.ext_misc_reg[0] = 0x4f0,
.ext_misc_reg[1] = 0x4f4,
.ext_misc_reg[2] = 0x4f8,
@@ -367,11 +388,22 @@ static struct tegra_clk_pll_params pll_c3_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.pdiv_tohw = pllc_p,
+ .div_nmp = &pllcx_nmp,
+ .max_p = 7,
.ext_misc_reg[0] = 0x504,
.ext_misc_reg[1] = 0x508,
.ext_misc_reg[2] = 0x50c,
};
+static struct div_nmp pllm_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 1,
+};
+
static struct pdiv_map pllm_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
@@ -401,6 +433,16 @@ static struct tegra_clk_pll_params pll_m_params = {
.lock_delay = 300,
.max_p = 2,
.pdiv_tohw = pllm_p,
+ .div_nmp = &pllm_nmp,
+};
+
+static struct div_nmp pllp_nmp = {
+ .divm_shift = 0,
+ .divm_width = 5,
+ .divn_shift = 8,
+ .divn_width = 10,
+ .divp_shift = 20,
+ .divp_width = 3,
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
@@ -424,6 +466,7 @@ static struct tegra_clk_pll_params pll_p_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
+ .div_nmp = &pllp_nmp,
};
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
@@ -450,6 +493,7 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
+ .div_nmp = &pllp_nmp,
};
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
@@ -485,6 +529,7 @@ static struct tegra_clk_pll_params pll_d_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
+ .div_nmp = &pllp_nmp,
};
static struct tegra_clk_pll_params pll_d2_params = {
@@ -499,6 +544,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
+ .div_nmp = &pllp_nmp,
};
static struct pdiv_map pllu_p[] = {
@@ -507,6 +553,15 @@ static struct pdiv_map pllu_p[] = {
{ .pdiv = 0, .hw_val = 0 },
};
+static struct div_nmp pllu_nmp = {
+ .divm_shift = 0,
+ .divm_width = 5,
+ .divn_shift = 8,
+ .divn_width = 10,
+ .divp_shift = 20,
+ .divp_width = 1,
+};
+
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
{12000000, 480000000, 960, 12, 0, 12},
{13000000, 480000000, 960, 13, 0, 12},
@@ -529,6 +584,7 @@ static struct tegra_clk_pll_params pll_u_params = {
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
.pdiv_tohw = pllu_p,
+ .div_nmp = &pllu_nmp,
};
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
@@ -561,6 +617,7 @@ static struct tegra_clk_pll_params pll_x_params = {
.stepa_shift = 16,
.stepb_shift = 24,
.pdiv_tohw = pllxc_p,
+ .div_nmp = &pllxc_nmp,
};
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
@@ -570,6 +627,15 @@ static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
{0, 0, 0, 0, 0, 0},
};
+static struct div_nmp plle_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 24,
+ .divp_width = 4,
+};
+
static struct tegra_clk_pll_params pll_e_params = {
.input_min = 12000000,
.input_max = 1000000000,
@@ -583,6 +649,16 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_mask = PLLE_MISC_LOCK,
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 300,
+ .div_nmp = &plle_nmp,
+};
+
+static struct div_nmp pllre_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 16,
+ .divp_width = 4,
};
static struct tegra_clk_pll_params pll_re_vco_params = {
@@ -599,6 +675,7 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
.lock_delay = 300,
.iddq_reg = PLLRE_MISC,
.iddq_bit_idx = PLLRE_IDDQ_BIT,
+ .div_nmp = &pllre_nmp,
};
/* Peripheral clock registers */
--
1.7.7.rc0.72.g4b5ea.dirty
On Wed, Jun 05, 2013 at 03:51:24PM +0200, Peter De Schrijver wrote:
> The m,n,p fields don't have the same bit offset and width across all PLLs.
> This patchset allows SoC specific files to indicate the offset and width.
> It also provides the data for Tegra114.
>
Depends on 'clk: tegra: pllc and pllxc should use pdiv_map'
Cheers,
Peter.
On 06/05/2013 07:51 AM, Peter De Schrijver wrote:
> The m,n,p fields don't have the same bit offset and width across all PLLs.
> This patchset allows SoC specific files to indicate the offset and width.
> It also provides the data for Tegra114.
The series,
Tested-by: Stephen Warren <[email protected]>
Acked-by: Stephen Warren <[email protected]>
Quoting Peter De Schrijver (2013-06-05 06:51:24)
> The m,n,p fields don't have the same bit offset and width across all PLLs.
> This patchset allows SoC specific files to indicate the offset and width.
> It also provides the data for Tegra114.
>
Taken into clk-next.
Thanks,
Mike
> Peter De Schrijver (2):
> clk: tegra: allow PLL m,n,p init from SoC files
> clk: tegra: PLL m,n,p init for Tegra114
>
> drivers/clk/tegra/clk-pll.c | 60 ++++++++++++++++-------------
> drivers/clk/tegra/clk-tegra114.c | 77 ++++++++++++++++++++++++++++++++++++++
> drivers/clk/tegra/clk.h | 32 ++++++++++------
> 3 files changed, 130 insertions(+), 39 deletions(-)
>
> --
> 1.7.7.rc0.72.g4b5ea.dirty