PLLM has override bits on Tegra30 and Tegra114. This patchset implements
support for them for both Tegra30 and Tegra114.
Changes since v1:
* Remove some stray lines from 'clk: tegra: override bits for Tegra114 PLLM'
Peter De Schrijver (4):
clk: tegra: Add fields for override bits
clk: tegra: override bits for Tegra114 PLLM
clk: tegra: override bits for Tegra30 PLLM
clk: tegra: Use override bits when needed
drivers/clk/tegra/clk-pll.c | 82 ++++++++++++++++++++++---------------
drivers/clk/tegra/clk-tegra114.c | 9 ++++
drivers/clk/tegra/clk-tegra30.c | 18 ++++++++
drivers/clk/tegra/clk.h | 8 ++++
4 files changed, 84 insertions(+), 33 deletions(-)
--
1.7.7.rc0.72.g4b5ea.dirty
PLLM can have override bits in the PMC. Describe those in the PLL parameters.
Signed-off-by: Peter De Schrijver <[email protected]>
---
drivers/clk/tegra/clk.h | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index d70eb2d..e01ac46 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -136,6 +136,9 @@ struct pdiv_map {
* @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
+ * @override_divn_shift: shift to the feedback divider bitfield in override reg
+ * @override_divm_shift: shift to the input divider bitfield in override reg
+ * @override_divp_shift: shift to the post divider bitfield in override reg
*/
struct div_nmp {
u8 divn_shift;
@@ -144,6 +147,9 @@ struct div_nmp {
u8 divm_width;
u8 divp_shift;
u8 divp_width;
+ u8 override_divn_shift;
+ u8 override_divm_shift;
+ u8 override_divp_shift;
};
/**
@@ -180,6 +186,8 @@ struct tegra_clk_pll_params {
u32 aux_reg;
u32 dyn_ramp_reg;
u32 ext_misc_reg[3];
+ u32 pmc_divnm_reg;
+ u32 pmc_divp_reg;
int stepa_shift;
int stepb_shift;
int lock_delay;
--
1.7.7.rc0.72.g4b5ea.dirty
Define override bits for Tegra114 PLLM.
Signed-off-by: Peter De Schrijver <[email protected]>
---
drivers/clk/tegra/clk-tegra114.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index d29ad1d..5b61a51 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -254,6 +254,10 @@
/* Tegra CPU clock and reset control regs */
#define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470
+/* PLLM override registers */
+#define PMC_PLLM_WB0_OVERRIDE 0x1dc
+#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0
+
static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32];
static void __iomem *clk_base;
@@ -398,10 +402,13 @@ static struct tegra_clk_pll_params pll_c3_params = {
static struct div_nmp pllm_nmp = {
.divm_shift = 0,
.divm_width = 8,
+ .override_divm_shift = 0,
.divn_shift = 8,
.divn_width = 8,
+ .override_divn_shift = 8,
.divp_shift = 20,
.divp_width = 1,
+ .override_divp_shift = 27,
};
static struct pdiv_map pllm_p[] = {
@@ -434,6 +441,8 @@ static struct tegra_clk_pll_params pll_m_params = {
.max_p = 2,
.pdiv_tohw = pllm_p,
.div_nmp = &pllm_nmp,
+ .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
+ .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
};
static struct div_nmp pllp_nmp = {
--
1.7.7.rc0.72.g4b5ea.dirty
Define override bits for Tegra30 PLLM.
Signed-off-by: Peter De Schrijver <[email protected]>
---
drivers/clk/tegra/clk-tegra30.c | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index b62e140..e598656 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -252,6 +252,9 @@
#define CLK_RESET_CCLK_RUN_POLICY 2
#define CLK_RESET_CCLK_BURST_POLICY_PLLX 8
+/* PLLM override registers */
+#define PMC_PLLM_WB0_OVERRIDE 0x1dc
+
#ifdef CONFIG_PM_SLEEP
static struct cpu_clk_suspend_context {
u32 pllx_misc;
@@ -563,6 +566,18 @@ static struct tegra_clk_pll_params pll_c_params = {
.lock_delay = 300,
};
+static struct div_nmp pllm_nmp = {
+ .divn_shift = 8,
+ .divn_width = 10,
+ .override_divn_shift = 5,
+ .divm_shift = 0,
+ .divm_width = 5,
+ .override_divm_shift = 0,
+ .divp_shift = 20,
+ .divp_width = 3,
+ .override_divp_shift = 15,
+};
+
static struct tegra_clk_pll_params pll_m_params = {
.input_min = 2000000,
.input_max = 31000000,
@@ -575,6 +590,9 @@ static struct tegra_clk_pll_params pll_m_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
+ .div_nmp = &pllm_nmp,
+ .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
+ .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE,
};
static struct tegra_clk_pll_params pll_p_params = {
--
1.7.7.rc0.72.g4b5ea.dirty
PLLM has override bits in the PMC. Use those when PLLM_OVERRIDE_ENABLE
is set.
Signed-off-by: Peter De Schrijver <[email protected]>
---
drivers/clk/tegra/clk-pll.c | 82 +++++++++++++++++++++++++-----------------
1 files changed, 49 insertions(+), 33 deletions(-)
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 3b778d3..4293643 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -117,10 +117,6 @@
#define PLLCX_MISC2_DEFAULT 0x30211200
#define PLLCX_MISC3_DEFAULT 0x200
-#define PMC_PLLM_WB0_OVERRIDE 0x1dc
-#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0
-#define PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK BIT(27)
-
#define PMC_SATA_PWRGT 0x1ac
#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5)
#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4)
@@ -128,10 +124,12 @@
#define pll_readl(offset, p) readl_relaxed(p->clk_base + offset)
#define pll_readl_base(p) pll_readl(p->params->base_reg, p)
#define pll_readl_misc(p) pll_readl(p->params->misc_reg, p)
+#define pll_override_readl(offset, p) readl_relaxed(p->pmc + offset)
#define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset)
#define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p)
#define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p)
+#define pll_override_writel(val, offset, p) writel(val, p->pmc + offset)
#define mask(w) ((1 << (w)) - 1)
#define divm_mask(p) mask(p->params->div_nmp->divm_width)
@@ -413,29 +411,61 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll,
struct tegra_clk_pll_freq_table *cfg)
{
u32 val;
+ struct tegra_clk_pll_params *params = pll->params;
+ struct div_nmp *div_nmp = params->div_nmp;
+
+ if ((pll->flags & TEGRA_PLLM) &&
+ (pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
+ PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
+ val = pll_override_readl(params->pmc_divp_reg, pll);
+ val &= ~(divp_mask(pll) << div_nmp->override_divp_shift);
+ val |= cfg->p << div_nmp->override_divp_shift;
+ pll_override_writel(val, params->pmc_divp_reg, pll);
+
+ val = pll_override_readl(params->pmc_divnm_reg, pll);
+ val &= ~(divm_mask(pll) << div_nmp->override_divm_shift) |
+ ~(divn_mask(pll) << div_nmp->override_divn_shift);
+ val |= (cfg->m << div_nmp->override_divm_shift) |
+ (cfg->n << div_nmp->override_divn_shift);
+ pll_override_writel(val, params->pmc_divnm_reg, pll);
+ } else {
+ val = pll_readl_base(pll);
- 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(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));
+ val |= ((cfg->m << div_nmp->divm_shift) |
+ (cfg->n << div_nmp->divn_shift) |
+ (cfg->p << div_nmp->divp_shift));
- pll_writel_base(val, pll);
+ pll_writel_base(val, pll);
+ }
}
static void _get_pll_mnp(struct tegra_clk_pll *pll,
struct tegra_clk_pll_freq_table *cfg)
{
u32 val;
+ struct tegra_clk_pll_params *params = pll->params;
+ struct div_nmp *div_nmp = params->div_nmp;
+
+ if ((pll->flags & TEGRA_PLLM) &&
+ (pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
+ PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
+ val = pll_override_readl(params->pmc_divp_reg, pll);
+ cfg->p = (val >> div_nmp->override_divp_shift) & divp_mask(pll);
+
+ val = pll_override_readl(params->pmc_divnm_reg, pll);
+ cfg->m = (val >> div_nmp->override_divm_shift) & divm_mask(pll);
+ cfg->n = (val >> div_nmp->override_divn_shift) & divn_mask(pll);
+ } else {
+ val = pll_readl_base(pll);
- val = pll_readl_base(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));
+ cfg->m = (val >> div_nmp->divm_shift) & divm_mask(pll);
+ cfg->n = (val >> div_nmp->divn_shift) & divn_mask(pll);
+ cfg->p = (val >> div_nmp->divp_shift) & divp_mask(pll);
+ }
}
static void _update_pll_cpcon(struct tegra_clk_pll *pll,
@@ -883,7 +913,6 @@ static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,
struct tegra_clk_pll *pll = to_clk_pll(hw);
unsigned long flags = 0;
int state, ret = 0;
- u32 val;
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
@@ -902,21 +931,7 @@ static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,
if (ret < 0)
goto out;
- val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE);
- if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) {
- val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE_2);
- val = cfg.p ? (val | PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK) :
- (val & ~PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK);
- writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE_2);
-
- val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE);
- val &= ~(divn_mask(pll) | divm_mask(pll));
- 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);
-
+ _update_pll_mnp(pll, &cfg);
out:
if (pll->lock)
@@ -1461,6 +1476,7 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
pll_flags |= TEGRA_PLL_BYPASS;
pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+ pll_flags |= TEGRA_PLLM;
pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,
freq_table, lock);
if (IS_ERR(pll))
--
1.7.7.rc0.72.g4b5ea.dirty
On 06/06/2013 04:47 AM, Peter De Schrijver wrote:
> PLLM has override bits on Tegra30 and Tegra114. This patchset implements
> support for them for both Tegra30 and Tegra114.
>
> Changes since v1:
> * Remove some stray lines from 'clk: tegra: override bits for Tegra114 PLLM'
Recall that for V1, I said:
Tested-by: Stephen Warren <[email protected]>
Acked-by: Stephen Warren <[email protected]>
(assuming the one comment I already made is fixed)
(and according to the changelog above, it has been)
Quoting Peter De Schrijver (2013-06-06 03:47:27)
> PLLM has override bits on Tegra30 and Tegra114. This patchset implements
> support for them for both Tegra30 and Tegra114.
>
> Changes since v1:
> * Remove some stray lines from 'clk: tegra: override bits for Tegra114 PLLM'
Pulled into clk-next.
Regards,
Mike
>
> Peter De Schrijver (4):
> clk: tegra: Add fields for override bits
> clk: tegra: override bits for Tegra114 PLLM
> clk: tegra: override bits for Tegra30 PLLM
> clk: tegra: Use override bits when needed
>
> drivers/clk/tegra/clk-pll.c | 82 ++++++++++++++++++++++---------------
> drivers/clk/tegra/clk-tegra114.c | 9 ++++
> drivers/clk/tegra/clk-tegra30.c | 18 ++++++++
> drivers/clk/tegra/clk.h | 8 ++++
> 4 files changed, 84 insertions(+), 33 deletions(-)
>
> --
> 1.7.7.rc0.72.g4b5ea.dirty