diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 20:54:50 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 20:54:50 +0200 |
commit | 92295f632cefbdf15d46e9ac5f0fc3cfade35259 (patch) | |
tree | 5b3820d4ed135ccbef540781d99a46137959bbb6 /drivers/clk/tegra | |
parent | Merge tag 'spi-v3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/brooni... (diff) | |
parent | clk: tegra: fix ifdef for tegra_periph_reset_assert inline (diff) | |
download | linux-92295f632cefbdf15d46e9ac5f0fc3cfade35259.tar.xz linux-92295f632cefbdf15d46e9ac5f0fc3cfade35259.zip |
Merge tag 'clk-for-linus-3.11' of git://git.linaro.org/people/mturquette/linux
Pull clock framework updates from Mike Turquette:
"The common clock framework changes for 3.11 include new clock drivers
across several different platforms and architectures, fixes to
existing drivers, a MAINTAINERS file fix and improvements to the basic
clock types that allow them to be of use to more platforms than before.
Only a few fixes to the core framework are included with most all of
the changes landing in the various clock drivers themselves."
* tag 'clk-for-linus-3.11' of git://git.linaro.org/people/mturquette/linux: (55 commits)
clk: tegra: fix ifdef for tegra_periph_reset_assert inline
clk: tegra: provide tegra_periph_reset_assert alternative
clk: exynos4: Fix clock aliases for cpufreq related clocks
clk: samsung: Add MUX_FA macro to pass flag and alias
clk: add support for Rockchip gate clocks
clk: vexpress: Make the clock drivers directly available for arm64
clk: vexpress: Use full node name to identify individual clocks
clk: tegra: T114: add DFLL DVCO reset control
clk: tegra: T114: add DFLL source clocks
clk: tegra: T114: add FCPU clock shaper programming, needed by the DFLL
clk: gate: add CLK_GATE_HIWORD_MASK
clk: divider: add CLK_DIVIDER_HIWORD_MASK flag
clk: mux: add CLK_MUX_HIWORD_MASK
clk: Always notify whole subtree when reparenting
MAINTAINERS: make drivers/clk entry match subdirs
clk: honor CLK_GET_RATE_NOCACHE in clk_set_rate
clk: use clk_get_rate() for debugfs
clk: tegra: Use override bits when needed
clk: tegra: override bits for Tegra30 PLLM
clk: tegra: override bits for Tegra114 PLLM
...
Diffstat (limited to 'drivers/clk/tegra')
-rw-r--r-- | drivers/clk/tegra/clk-pll.c | 281 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra114.c | 270 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra20.c | 3 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra30.c | 25 | ||||
-rw-r--r-- | drivers/clk/tegra/clk.c | 12 | ||||
-rw-r--r-- | drivers/clk/tegra/clk.h | 62 |
6 files changed, 472 insertions, 181 deletions
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 17c2cc086eb4..197074a57754 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,38 +124,31 @@ #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->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))) - -#ifdef CONFIG_ARCH_TEGRA_114_SOC -/* PLLXC has 4-bit PDIV, but entry 15 is not allowed in h/w */ -#define PLLXC_PDIV_MAX 14 - -/* non-monotonic mapping below is not a typo */ -static u8 pllxc_p[PLLXC_PDIV_MAX + 1] = { - /* PDIV: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */ - /* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32 -}; - -#define PLLCX_PDIV_MAX 7 -static u8 pllcx_p[PLLCX_PDIV_MAX + 1] = { - /* PDIV: 0, 1, 2, 3, 4, 5, 6, 7 */ - /* p: */ 1, 2, 3, 4, 6, 8, 12, 16 +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, }; -#endif static void clk_pll_enable_lock(struct tegra_clk_pll *pll) { @@ -297,6 +286,39 @@ static void clk_pll_disable(struct clk_hw *hw) spin_unlock_irqrestore(pll->lock, flags); } +static int _p_div_to_hw(struct clk_hw *hw, u8 p_div) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + struct pdiv_map *p_tohw = pll->params->pdiv_tohw; + + if (p_tohw) { + while (p_tohw->pdiv) { + if (p_div <= p_tohw->pdiv) + return p_tohw->hw_val; + p_tohw++; + } + return -EINVAL; + } + return -EINVAL; +} + +static int _hw_to_p_div(struct clk_hw *hw, u8 p_div_hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + struct pdiv_map *p_tohw = pll->params->pdiv_tohw; + + if (p_tohw) { + while (p_tohw->pdiv) { + if (p_div_hw == p_tohw->hw_val) + return p_tohw->pdiv; + p_tohw++; + } + return -EINVAL; + } + + return 1 << p_div_hw; +} + static int _get_table_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, unsigned long rate, unsigned long parent_rate) @@ -326,9 +348,9 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, unsigned long rate, unsigned long parent_rate) { struct tegra_clk_pll *pll = to_clk_pll(hw); - struct pdiv_map *p_tohw = pll->params->pdiv_tohw; unsigned long cfreq; u32 p_div = 0; + int ret; switch (parent_rate) { case 12000000: @@ -369,20 +391,16 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, || cfg->output_rate > pll->params->vco_max) { pr_err("%s: Failed to set %s rate %lu\n", __func__, __clk_get_name(hw->clk), rate); + WARN_ON(1); return -EINVAL; } - if (p_tohw) { - p_div = 1 << p_div; - while (p_tohw->pdiv) { - if (p_div <= p_tohw->pdiv) { - cfg->p = p_tohw->hw_val; - break; - } - p_tohw++; - } - if (!p_tohw->pdiv) - return -EINVAL; + if (pll->params->pdiv_tohw) { + ret = _p_div_to_hw(hw, 1 << p_div); + if (ret < 0) + return ret; + else + cfg->p = ret; } else cfg->p = p_div; @@ -393,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->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 |= ((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->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 >> 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, @@ -485,9 +535,10 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, } if (_get_table_rate(hw, &cfg, rate, parent_rate) && - _calc_rate(hw, &cfg, rate, parent_rate)) + _calc_rate(hw, &cfg, rate, parent_rate)) { + WARN_ON(1); return -EINVAL; - + } if (pll->lock) spin_lock_irqsave(pll->lock, flags); @@ -507,7 +558,6 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, { struct tegra_clk_pll *pll = to_clk_pll(hw); struct tegra_clk_pll_freq_table cfg; - u64 output_rate = *prate; if (pll->flags & TEGRA_PLL_FIXED) return pll->fixed_rate; @@ -517,13 +567,12 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, return __clk_get_rate(hw->clk); if (_get_table_rate(hw, &cfg, rate, *prate) && - _calc_rate(hw, &cfg, rate, *prate)) + _calc_rate(hw, &cfg, rate, *prate)) { + WARN_ON(1); return -EINVAL; + } - output_rate *= cfg.n; - do_div(output_rate, cfg.m * (1 << cfg.p)); - - return output_rate; + return cfg.output_rate; } static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, @@ -531,7 +580,6 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, { struct tegra_clk_pll *pll = to_clk_pll(hw); struct tegra_clk_pll_freq_table cfg; - struct pdiv_map *p_tohw = pll->params->pdiv_tohw; u32 val; u64 rate = parent_rate; int pdiv; @@ -553,21 +601,11 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, _get_pll_mnp(pll, &cfg); - if (p_tohw) { - while (p_tohw->pdiv) { - if (cfg.p == p_tohw->hw_val) { - pdiv = p_tohw->pdiv; - break; - } - p_tohw++; - } - - if (!p_tohw->pdiv) { - WARN_ON(1); - pdiv = 1; - } - } else - pdiv = 1 << cfg.p; + pdiv = _hw_to_p_div(hw, cfg.p); + if (pdiv < 0) { + WARN_ON(1); + pdiv = 1; + } cfg.m *= pdiv; @@ -647,9 +685,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); } @@ -680,9 +718,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; @@ -769,16 +807,22 @@ static int _calc_dynamic_ramp_rate(struct clk_hw *hw, { struct tegra_clk_pll *pll = to_clk_pll(hw); unsigned int p; + int p_div; if (!rate) return -EINVAL; p = DIV_ROUND_UP(pll->params->vco_min, rate); cfg->m = _pll_fixed_mdiv(pll->params, parent_rate); - cfg->p = p; - cfg->output_rate = rate * cfg->p; + cfg->output_rate = rate * p; cfg->n = cfg->output_rate * cfg->m / parent_rate; + p_div = _p_div_to_hw(hw, p); + if (p_div < 0) + return p_div; + else + cfg->p = p_div; + if (cfg->n > divn_max(pll) || cfg->output_rate > pll->params->vco_max) return -EINVAL; @@ -790,18 +834,25 @@ static int _pll_ramp_calc_pll(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct tegra_clk_pll *pll = to_clk_pll(hw); - int err = 0; + int err = 0, p_div; err = _get_table_rate(hw, cfg, rate, parent_rate); if (err < 0) err = _calc_dynamic_ramp_rate(hw, cfg, rate, parent_rate); - else if (cfg->m != _pll_fixed_mdiv(pll->params, parent_rate)) { + else { + if (cfg->m != _pll_fixed_mdiv(pll->params, parent_rate)) { WARN_ON(1); err = -EINVAL; goto out; + } + p_div = _p_div_to_hw(hw, cfg->p); + if (p_div < 0) + return p_div; + else + cfg->p = p_div; } - if (!cfg->p || (cfg->p > pll->params->max_p)) + if (cfg->p > pll->params->max_p) err = -EINVAL; out: @@ -815,7 +866,6 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate, struct tegra_clk_pll_freq_table cfg, old_cfg; unsigned long flags = 0; int ret = 0; - u8 old_p; ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_rate); if (ret < 0) @@ -826,11 +876,8 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate, _get_pll_mnp(pll, &old_cfg); - old_p = pllxc_p[old_cfg.p]; - if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_p != cfg.p) { - cfg.p -= 1; + if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p) ret = _program_pll(hw, &cfg, rate); - } if (pll->lock) spin_unlock_irqrestore(pll->lock, flags); @@ -842,15 +889,19 @@ static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { struct tegra_clk_pll_freq_table cfg; - int ret = 0; + int ret = 0, p_div; u64 output_rate = *prate; ret = _pll_ramp_calc_pll(hw, &cfg, rate, *prate); if (ret < 0) return ret; + p_div = _hw_to_p_div(hw, cfg.p); + if (p_div < 0) + return p_div; + output_rate *= cfg.n; - do_div(output_rate, cfg.m * cfg.p); + do_div(output_rate, cfg.m * p_div); return output_rate; } @@ -862,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); @@ -881,22 +931,7 @@ static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate, if (ret < 0) goto out; - cfg.p -= 1; - - 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->divm_shift) | (cfg.n << pll->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) @@ -1010,13 +1045,10 @@ static int _pllcx_update_dynamic_coef(struct tegra_clk_pll *pll, static int clk_pllc_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { - struct tegra_clk_pll_freq_table cfg; + struct tegra_clk_pll_freq_table cfg, old_cfg; struct tegra_clk_pll *pll = to_clk_pll(hw); unsigned long flags = 0; int state, ret = 0; - u32 val; - u16 old_m, old_n; - u8 old_p; if (pll->lock) spin_lock_irqsave(pll->lock, flags); @@ -1025,21 +1057,16 @@ static int clk_pllc_set_rate(struct clk_hw *hw, unsigned long rate, if (ret < 0) goto out; - val = pll_readl_base(pll); - old_m = (val >> pll->divm_shift) & (divm_mask(pll)); - old_n = (val >> pll->divn_shift) & (divn_mask(pll)); - old_p = pllcx_p[(val >> pll->divp_shift) & (divp_mask(pll))]; + _get_pll_mnp(pll, &old_cfg); - if (cfg.m != old_m) { + if (cfg.m != old_cfg.m) { WARN_ON(1); goto out; } - if (old_n == cfg.n && old_p == cfg.p) + if (old_cfg.n == cfg.n && old_cfg.p == cfg.p) goto out; - cfg.p -= 1; - state = clk_pll_is_enabled(hw); if (state) _clk_pllc_disable(hw); @@ -1178,8 +1205,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); @@ -1240,12 +1267,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; } @@ -1401,7 +1424,7 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name, struct tegra_clk_pll *pll; struct clk *clk; - pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC; pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, freq_table, lock); if (IS_ERR(pll)) @@ -1428,7 +1451,6 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name, val &= ~BIT(29); pll_writel_misc(val, pll); - pll_flags |= TEGRA_PLL_LOCK_MISC; clk = _tegra_clk_register_pll(pll, name, parent_name, flags, &tegra_clk_pllre_ops); if (IS_ERR(clk)) @@ -1453,6 +1475,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)) diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 40d939d091bf..b6015cb4fc01 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -21,6 +21,7 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/delay.h> +#include <linux/export.h> #include <linux/clk/tegra.h> #include "clk.h" @@ -28,6 +29,7 @@ #define RST_DEVICES_L 0x004 #define RST_DEVICES_H 0x008 #define RST_DEVICES_U 0x00C +#define RST_DFLL_DVCO 0x2F4 #define RST_DEVICES_V 0x358 #define RST_DEVICES_W 0x35C #define RST_DEVICES_X 0x28C @@ -41,8 +43,36 @@ #define RST_DEVICES_CLR_V 0x434 #define RST_DEVICES_SET_W 0x438 #define RST_DEVICES_CLR_W 0x43c +#define CPU_FINETRIM_SELECT 0x4d4 /* override default prop dlys */ +#define CPU_FINETRIM_DR 0x4d8 /* rise->rise prop dly A */ +#define CPU_FINETRIM_R 0x4e4 /* rise->rise prop dly inc A */ #define RST_DEVICES_NUM 5 +/* RST_DFLL_DVCO bitfields */ +#define DVFS_DFLL_RESET_SHIFT 0 + +/* CPU_FINETRIM_SELECT and CPU_FINETRIM_DR bitfields */ +#define CPU_FINETRIM_1_FCPU_1 BIT(0) /* fcpu0 */ +#define CPU_FINETRIM_1_FCPU_2 BIT(1) /* fcpu1 */ +#define CPU_FINETRIM_1_FCPU_3 BIT(2) /* fcpu2 */ +#define CPU_FINETRIM_1_FCPU_4 BIT(3) /* fcpu3 */ +#define CPU_FINETRIM_1_FCPU_5 BIT(4) /* fl2 */ +#define CPU_FINETRIM_1_FCPU_6 BIT(5) /* ftop */ + +/* CPU_FINETRIM_R bitfields */ +#define CPU_FINETRIM_R_FCPU_1_SHIFT 0 /* fcpu0 */ +#define CPU_FINETRIM_R_FCPU_1_MASK (0x3 << CPU_FINETRIM_R_FCPU_1_SHIFT) +#define CPU_FINETRIM_R_FCPU_2_SHIFT 2 /* fcpu1 */ +#define CPU_FINETRIM_R_FCPU_2_MASK (0x3 << CPU_FINETRIM_R_FCPU_2_SHIFT) +#define CPU_FINETRIM_R_FCPU_3_SHIFT 4 /* fcpu2 */ +#define CPU_FINETRIM_R_FCPU_3_MASK (0x3 << CPU_FINETRIM_R_FCPU_3_SHIFT) +#define CPU_FINETRIM_R_FCPU_4_SHIFT 6 /* fcpu3 */ +#define CPU_FINETRIM_R_FCPU_4_MASK (0x3 << CPU_FINETRIM_R_FCPU_4_SHIFT) +#define CPU_FINETRIM_R_FCPU_5_SHIFT 8 /* fl2 */ +#define CPU_FINETRIM_R_FCPU_5_MASK (0x3 << CPU_FINETRIM_R_FCPU_5_SHIFT) +#define CPU_FINETRIM_R_FCPU_6_SHIFT 10 /* ftop */ +#define CPU_FINETRIM_R_FCPU_6_MASK (0x3 << CPU_FINETRIM_R_FCPU_6_SHIFT) + #define CLK_OUT_ENB_L 0x010 #define CLK_OUT_ENB_H 0x014 #define CLK_OUT_ENB_U 0x018 @@ -127,6 +157,7 @@ #define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 #define PMC_CTRL 0 #define PMC_CTRL_BLINK_ENB 7 +#define PMC_BLINK_TIMER 0x40 #define OSC_CTRL 0x50 #define OSC_CTRL_OSC_FREQ_SHIFT 28 @@ -242,6 +273,8 @@ #define CLK_SOURCE_I2CSLOW 0x3fc #define CLK_SOURCE_SE 0x42c #define CLK_SOURCE_MSELECT 0x3b4 +#define CLK_SOURCE_DFLL_REF 0x62c +#define CLK_SOURCE_DFLL_SOC 0x630 #define CLK_SOURCE_SOC_THERM 0x644 #define CLK_SOURCE_XUSB_HOST_SRC 0x600 #define CLK_SOURCE_XUSB_FALCON_SRC 0x604 @@ -250,6 +283,10 @@ #define CLK_SOURCE_XUSB_DEV_SRC 0x60c #define CLK_SOURCE_EMC 0x19c +/* PLLM override registers */ +#define PMC_PLLM_WB0_OVERRIDE 0x1dc +#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0 + /* Tegra CPU clock and reset control regs */ #define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470 @@ -267,6 +304,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 }, @@ -315,6 +361,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[] = { @@ -348,6 +404,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, @@ -366,11 +424,25 @@ 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, + .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[] = { { .pdiv = 1, .hw_val = 0 }, { .pdiv = 2, .hw_val = 1 }, @@ -400,6 +472,18 @@ static struct tegra_clk_pll_params pll_m_params = { .lock_delay = 300, .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 = { + .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[] = { @@ -423,6 +507,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[] = { @@ -449,6 +534,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[] = { @@ -484,6 +570,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 = { @@ -498,6 +585,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[] = { @@ -506,6 +594,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}, @@ -528,6 +625,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[] = { @@ -560,6 +658,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[] = { @@ -569,6 +668,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, @@ -582,6 +690,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 = { @@ -598,6 +716,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 */ @@ -765,6 +884,7 @@ enum tegra114_clk { audio1, audio2, audio3, audio4, spdif, clk_out_1, clk_out_2, clk_out_3, blink, xusb_host_src = 252, xusb_falcon_src, xusb_fs_src, xusb_ss_src, xusb_dev_src, xusb_dev, xusb_hs_src, sclk, hclk, pclk, cclk_g, cclk_lp, + dfll_ref = 264, dfll_soc, /* Mux clocks */ @@ -1202,8 +1322,8 @@ static void __init tegra114_pll_init(void __iomem *clk_base, /* PLLP_OUT2 */ clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p", clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED | - TEGRA_DIVIDER_ROUND_UP, 24, 8, 1, - &pll_div_lock); + TEGRA_DIVIDER_ROUND_UP | TEGRA_DIVIDER_INT, 24, + 8, 1, &pll_div_lock); clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div", clk_base + PLLP_OUTA, 17, 16, CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, @@ -1605,7 +1725,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base) /* clk_out_2 */ clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents, - ARRAY_SIZE(clk_out1_parents), 0, + ARRAY_SIZE(clk_out2_parents), 0, pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0, &clk_out_lock); clks[clk_out_2_mux] = clk; @@ -1617,7 +1737,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base) /* clk_out_3 */ clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents, - ARRAY_SIZE(clk_out1_parents), 0, + ARRAY_SIZE(clk_out3_parents), 0, pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0, &clk_out_lock); clks[clk_out_3_mux] = clk; @@ -1628,6 +1748,8 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base) clks[clk_out_3] = clk; /* blink */ + /* clear the blink timer register to directly output clk_32k */ + writel_relaxed(0, pmc_base + PMC_BLINK_TIMER); clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0, pmc_base + PMC_DPD_PADS_ORIDE, PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); @@ -1640,7 +1762,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base) } static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", - "pll_p_out3", "pll_p_out2", "unused", + "pll_p", "pll_p_out2", "unused", "clk_32k", "pll_m_out1" }; static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", @@ -1750,7 +1872,7 @@ static struct tegra_periph_init_data tegra_periph_clk_list[] = { TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor), TEGRA_INIT_DATA_INT8("vi", "vi", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi), TEGRA_INIT_DATA_INT8("epp", NULL, "epp", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp), - TEGRA_INIT_DATA_INT8("msenc", NULL, "msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, &periph_h_regs, TEGRA_PERIPH_WAR_1005168, msenc), + TEGRA_INIT_DATA_INT8("msenc", NULL, "msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, &periph_u_regs, TEGRA_PERIPH_WAR_1005168, msenc), TEGRA_INIT_DATA_INT8("tsec", NULL, "tsec", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_TSEC, 83, &periph_u_regs, 0, tsec), TEGRA_INIT_DATA_INT8("host1x", NULL, "host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x), TEGRA_INIT_DATA_MUX8("hdmi", NULL, "hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi), @@ -1767,6 +1889,8 @@ static struct tegra_periph_init_data tegra_periph_clk_list[] = { TEGRA_INIT_DATA_MUX("i2cslow", NULL, "i2cslow", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_I2CSLOW, 81, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2cslow), TEGRA_INIT_DATA_INT8("se", NULL, "se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, &periph_v_regs, TEGRA_PERIPH_ON_APB, se), TEGRA_INIT_DATA_INT_FLAGS("mselect", NULL, "mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, &periph_v_regs, 0, mselect, CLK_IGNORE_UNUSED), + TEGRA_INIT_DATA_MUX("dfll_ref", "ref", "t114_dfll", mux_pllp_clkm, CLK_SOURCE_DFLL_REF, 155, &periph_w_regs, TEGRA_PERIPH_ON_APB, dfll_ref), + TEGRA_INIT_DATA_MUX("dfll_soc", "soc", "t114_dfll", mux_pllp_clkm, CLK_SOURCE_DFLL_SOC, 155, &periph_w_regs, TEGRA_PERIPH_ON_APB, dfll_soc), TEGRA_INIT_DATA_MUX8("soc_therm", NULL, "soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, &periph_u_regs, TEGRA_PERIPH_ON_APB, soc_therm), TEGRA_INIT_DATA_XUSB("xusb_host_src", "host_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, &periph_w_regs, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, xusb_host_src), TEGRA_INIT_DATA_XUSB("xusb_falcon_src", "falcon_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_falcon_src), @@ -2028,6 +2152,10 @@ static const struct of_device_id pmc_match[] __initconst = { {}, }; +/* + * dfll_soc/dfll_ref apparently must be kept enabled, otherwise I2C5 + * breaks + */ static __initdata struct tegra_clk_init_table init_table[] = { {uarta, pll_p, 408000000, 0}, {uartb, pll_p, 408000000, 0}, @@ -2043,6 +2171,8 @@ static __initdata struct tegra_clk_init_table init_table[] = { {i2s2, pll_a_out0, 11289600, 0}, {i2s3, pll_a_out0, 11289600, 0}, {i2s4, pll_a_out0, 11289600, 0}, + {dfll_soc, pll_p, 51000000, 1}, + {dfll_ref, pll_p, 51000000, 1}, {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */ }; @@ -2051,7 +2181,132 @@ static void __init tegra114_clock_apply_init_table(void) tegra_init_from_table(init_table, clks, clk_max); } -void __init tegra114_clock_init(struct device_node *np) + +/** + * tegra114_car_barrier - wait for pending writes to the CAR to complete + * + * Wait for any outstanding writes to the CAR MMIO space from this CPU + * to complete before continuing execution. No return value. + */ +static void tegra114_car_barrier(void) +{ + wmb(); /* probably unnecessary */ + readl_relaxed(clk_base + CPU_FINETRIM_SELECT); +} + +/** + * tegra114_clock_tune_cpu_trimmers_high - use high-voltage propagation delays + * + * When the CPU rail voltage is in the high-voltage range, use the + * built-in hardwired clock propagation delays in the CPU clock + * shaper. No return value. + */ +void tegra114_clock_tune_cpu_trimmers_high(void) +{ + u32 select = 0; + + /* Use hardwired rise->rise & fall->fall clock propagation delays */ + select |= ~(CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 | + CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 | + CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6); + writel_relaxed(select, clk_base + CPU_FINETRIM_SELECT); + + tegra114_car_barrier(); +} +EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_high); + +/** + * tegra114_clock_tune_cpu_trimmers_low - use low-voltage propagation delays + * + * When the CPU rail voltage is in the low-voltage range, use the + * extended clock propagation delays set by + * tegra114_clock_tune_cpu_trimmers_init(). The intention is to + * maintain the input clock duty cycle that the FCPU subsystem + * expects. No return value. + */ +void tegra114_clock_tune_cpu_trimmers_low(void) +{ + u32 select = 0; + + /* + * Use software-specified rise->rise & fall->fall clock + * propagation delays (from + * tegra114_clock_tune_cpu_trimmers_init() + */ + select |= (CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 | + CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 | + CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6); + writel_relaxed(select, clk_base + CPU_FINETRIM_SELECT); + + tegra114_car_barrier(); +} +EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_low); + +/** + * tegra114_clock_tune_cpu_trimmers_init - set up and enable clk prop delays + * + * Program extended clock propagation delays into the FCPU clock + * shaper and enable them. XXX Define the purpose - peak current + * reduction? No return value. + */ +/* XXX Initial voltage rail state assumption issues? */ +void tegra114_clock_tune_cpu_trimmers_init(void) +{ + u32 dr = 0, r = 0; + + /* Increment the rise->rise clock delay by four steps */ + r |= (CPU_FINETRIM_R_FCPU_1_MASK | CPU_FINETRIM_R_FCPU_2_MASK | + CPU_FINETRIM_R_FCPU_3_MASK | CPU_FINETRIM_R_FCPU_4_MASK | + CPU_FINETRIM_R_FCPU_5_MASK | CPU_FINETRIM_R_FCPU_6_MASK); + writel_relaxed(r, clk_base + CPU_FINETRIM_R); + + /* + * Use the rise->rise clock propagation delay specified in the + * r field + */ + dr |= (CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 | + CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 | + CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6); + writel_relaxed(dr, clk_base + CPU_FINETRIM_DR); + + tegra114_clock_tune_cpu_trimmers_low(); +} +EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_init); + +/** + * tegra114_clock_assert_dfll_dvco_reset - assert the DFLL's DVCO reset + * + * Assert the reset line of the DFLL's DVCO. No return value. + */ +void tegra114_clock_assert_dfll_dvco_reset(void) +{ + u32 v; + + v = readl_relaxed(clk_base + RST_DFLL_DVCO); + v |= (1 << DVFS_DFLL_RESET_SHIFT); + writel_relaxed(v, clk_base + RST_DFLL_DVCO); + tegra114_car_barrier(); +} +EXPORT_SYMBOL(tegra114_clock_assert_dfll_dvco_reset); + +/** + * tegra114_clock_deassert_dfll_dvco_reset - deassert the DFLL's DVCO reset + * + * Deassert the reset line of the DFLL's DVCO, allowing the DVCO to + * operate. No return value. + */ +void tegra114_clock_deassert_dfll_dvco_reset(void) +{ + u32 v; + + v = readl_relaxed(clk_base + RST_DFLL_DVCO); + v &= ~(1 << DVFS_DFLL_RESET_SHIFT); + writel_relaxed(v, clk_base + RST_DFLL_DVCO); + tegra114_car_barrier(); +} +EXPORT_SYMBOL(tegra114_clock_deassert_dfll_dvco_reset); + +static void __init tegra114_clock_init(struct device_node *np) { struct device_node *node; int i; @@ -2104,3 +2359,4 @@ void __init tegra114_clock_init(struct device_node *np) tegra_cpu_car_ops = &tegra114_cpu_car_ops; } +CLK_OF_DECLARE(tegra114, "nvidia,tegra114-car", tegra114_clock_init); diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 075db0c99edb..759ca47be753 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -1287,7 +1287,7 @@ static const struct of_device_id pmc_match[] __initconst = { {}, }; -void __init tegra20_clock_init(struct device_node *np) +static void __init tegra20_clock_init(struct device_node *np) { int i; struct device_node *node; @@ -1339,3 +1339,4 @@ void __init tegra20_clock_init(struct device_node *np) tegra_cpu_car_ops = &tegra20_cpu_car_ops; } +CLK_OF_DECLARE(tegra20, "nvidia,tegra20-car", tegra20_clock_init); diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index ba99e3844106..e2c6ca0431d6 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 = { @@ -1223,7 +1241,7 @@ static void __init tegra30_pmc_clk_init(void) /* clk_out_2 */ clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents, - ARRAY_SIZE(clk_out1_parents), 0, + ARRAY_SIZE(clk_out2_parents), 0, pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0, &clk_out_lock); clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0, @@ -1234,7 +1252,7 @@ static void __init tegra30_pmc_clk_init(void) /* clk_out_3 */ clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents, - ARRAY_SIZE(clk_out1_parents), 0, + ARRAY_SIZE(clk_out3_parents), 0, pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0, &clk_out_lock); clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0, @@ -1954,7 +1972,7 @@ static const struct of_device_id pmc_match[] __initconst = { {}, }; -void __init tegra30_clock_init(struct device_node *np) +static void __init tegra30_clock_init(struct device_node *np) { struct device_node *node; int i; @@ -2005,3 +2023,4 @@ void __init tegra30_clock_init(struct device_node *np) tegra_cpu_car_ops = &tegra30_cpu_car_ops; } +CLK_OF_DECLARE(tegra30, "nvidia,tegra30-car", tegra30_clock_init); diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index 923ca7ee4694..86581ac1fd69 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -74,18 +74,6 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl, } } -static const struct of_device_id tegra_dt_clk_match[] = { - { .compatible = "nvidia,tegra20-car", .data = tegra20_clock_init }, - { .compatible = "nvidia,tegra30-car", .data = tegra30_clock_init }, - { .compatible = "nvidia,tegra114-car", .data = tegra114_clock_init }, - { } -}; - -void __init tegra_clocks_init(void) -{ - of_clk_init(tegra_dt_clk_match); -} - tegra_clk_apply_init_table_func tegra_clk_apply_init_table; void __init tegra_clocks_apply_init_table(void) diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index e0565620d68e..07cfacd91686 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -128,6 +128,31 @@ 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 + * @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; + u8 divn_width; + u8 divm_shift; + u8 divm_width; + u8 divp_shift; + u8 divp_width; + u8 override_divn_shift; + u8 override_divm_shift; + u8 override_divp_shift; +}; + +/** * struct clk_pll_params - PLL parameters * * @input_min: Minimum input frequency @@ -161,11 +186,14 @@ 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; int max_p; struct pdiv_map *pdiv_tohw; + struct div_nmp *div_nmp; }; /** @@ -179,12 +207,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 +236,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; }; @@ -571,23 +587,11 @@ void tegra_init_from_table(struct tegra_clk_init_table *tbl, void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, struct clk *clks[], int clk_max); -#ifdef CONFIG_ARCH_TEGRA_2x_SOC -void tegra20_clock_init(struct device_node *np); -#else -static inline void tegra20_clock_init(struct device_node *np) {} -#endif /* CONFIG_ARCH_TEGRA_2x_SOC */ - -#ifdef CONFIG_ARCH_TEGRA_3x_SOC -void tegra30_clock_init(struct device_node *np); -#else -static inline void tegra30_clock_init(struct device_node *np) {} -#endif /* CONFIG_ARCH_TEGRA_3x_SOC */ - -#ifdef CONFIG_ARCH_TEGRA_114_SOC -void tegra114_clock_init(struct device_node *np); -#else -static inline void tegra114_clock_init(struct device_node *np) {} -#endif /* CONFIG_ARCH_TEGRA114_SOC */ +void tegra114_clock_tune_cpu_trimmers_high(void); +void tegra114_clock_tune_cpu_trimmers_low(void); +void tegra114_clock_tune_cpu_trimmers_init(void); +void tegra114_clock_assert_dfll_dvco_reset(void); +void tegra114_clock_deassert_dfll_dvco_reset(void); typedef void (*tegra_clk_apply_init_table_func)(void); extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table; |