Commit aa6fefde authored by Peter De Schrijver's avatar Peter De Schrijver Committed by Mike Turquette

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: default avatarPeter De Schrijver <pdeschrijver@nvidia.com>
Tested-by: default avatarStephen Warren <swarren@nvidia.com>
Acked-by: default avatarStephen Warren <swarren@nvidia.com>
Signed-off-by: default avatarMike Turquette <mturquette@linaro.org>
parent c388eee2
......@@ -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;
}
......
......@@ -127,6 +127,25 @@ struct pdiv_map {
u8 hw_val;
};
/**
* 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
*
......@@ -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;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment