diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2016-05-02 16:53:02 -0700 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2016-05-02 16:53:02 -0700 |
commit | 5bc753249719e88c195e84bbf8eca6530507d403 (patch) | |
tree | c6f5e62bc0c9208de7691062007243e6c8eca568 /drivers/clk | |
parent | 5569aedf1dd82cc1e4d8d19f4424c2034583cb2a (diff) | |
parent | 2690e912644e610854c4c3b23d0a0daec9d030ca (diff) |
Merge tag 'tegra-for-4.7-clk' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into clk-next
Pull tegra clk driver changes from Thierry Reding:
This set of changes contains a bunch of cleanups and minor fixes along
with some new clocks, mainly on Tegra210, in preparation for supporting
DisplayPort and HDMI 2.0.
* tag 'tegra-for-4.7-clk' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
clk: tegra: dfll: Reformat CVB frequency table
clk: tegra: dfll: Properly clean up on failure and removal
clk: tegra: dfll: Make code more comprehensible
clk: tegra: dfll: Reference CVB table instead of copying data
clk: tegra: dfll: Update kerneldoc
clk: tegra: Fix PLL_U post divider and initial rate on Tegra30
clk: tegra: Initialize PLL_C to sane rate on Tegra30
clk: tegra: Fix pllre Tegra210 and add pll_re_out1
clk: tegra: Add sor_safe clock
clk: tegra: dpaux and dpaux1 are fixed factor clocks
clk: tegra: Add dpaux1 clock
clk: tegra: Use correct parent for dpaux clock
clk: tegra: Add fixed factor peripheral clock type
clk: tegra: Special-case mipi-cal parent on Tegra114
clk: tegra: Remove trailing blank line
clk: tegra: Constify peripheral clock registers
clk: tegra: Add interface to enable hardware control of SATA/XUSB PLLs
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/tegra/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-dfll.c | 11 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-dfll.h | 22 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-id.h | 2 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-periph-fixed.c | 120 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-periph-gate.c | 2 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-periph.c | 2 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-pll.c | 46 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra-fixed.c | 1 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra-periph.c | 5 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra114.c | 6 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra124-dfll-fcpu.c | 103 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra124.c | 4 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra210.c | 87 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra30.c | 12 | ||||
-rw-r--r-- | drivers/clk/tegra/clk.c | 4 | ||||
-rw-r--r-- | drivers/clk/tegra/clk.h | 27 | ||||
-rw-r--r-- | drivers/clk/tegra/cvb.c | 71 | ||||
-rw-r--r-- | drivers/clk/tegra/cvb.h | 15 |
19 files changed, 427 insertions, 114 deletions
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index 97984c503bbb..33fd0938d79e 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -3,6 +3,7 @@ obj-y += clk-audio-sync.o obj-y += clk-dfll.o obj-y += clk-divider.o obj-y += clk-periph.o +obj-y += clk-periph-fixed.o obj-y += clk-periph-gate.o obj-y += clk-pll.o obj-y += clk-pll-out.o diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c index 19bfa07e24b1..f010562534eb 100644 --- a/drivers/clk/tegra/clk-dfll.c +++ b/drivers/clk/tegra/clk-dfll.c @@ -55,6 +55,7 @@ #include <linux/seq_file.h> #include "clk-dfll.h" +#include "cvb.h" /* * DFLL control registers - access via dfll_{readl,writel} @@ -442,8 +443,8 @@ static void dfll_tune_low(struct tegra_dfll *td) { td->tune_range = DFLL_TUNE_LOW; - dfll_writel(td, td->soc->tune0_low, DFLL_TUNE0); - dfll_writel(td, td->soc->tune1, DFLL_TUNE1); + dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune0_low, DFLL_TUNE0); + dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune1, DFLL_TUNE1); dfll_wmb(td); if (td->soc->set_clock_trimmers_low) @@ -1449,7 +1450,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) } v_max = dev_pm_opp_get_voltage(opp); - v = td->soc->min_millivolts * 1000; + v = td->soc->cvb->min_millivolts * 1000; lut = find_vdd_map_entry_exact(td, v); if (lut < 0) goto out; @@ -1461,7 +1462,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) break; v_opp = dev_pm_opp_get_voltage(opp); - if (v_opp <= td->soc->min_millivolts * 1000) + if (v_opp <= td->soc->cvb->min_millivolts * 1000) td->dvco_rate_min = dev_pm_opp_get_freq(opp); for (;;) { @@ -1490,7 +1491,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) if (!td->dvco_rate_min) dev_err(td->dev, "no opp above DFLL minimum voltage %d mV\n", - td->soc->min_millivolts); + td->soc->cvb->min_millivolts); else ret = 0; diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h index 2e4c0772a5dc..ed2ad888268f 100644 --- a/drivers/clk/tegra/clk-dfll.h +++ b/drivers/clk/tegra/clk-dfll.h @@ -24,22 +24,18 @@ /** * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver - * @opp_dev: struct device * that holds the OPP table for the DFLL - * @min_millivolts: minimum voltage (in mV) that the DFLL can operate - * @tune0_low: DFLL tuning register 0 (low voltage range) - * @tune0_high: DFLL tuning register 0 (high voltage range) - * @tune1: DFLL tuning register 1 - * @assert_dvco_reset: fn ptr to place the DVCO in reset - * @deassert_dvco_reset: fn ptr to release the DVCO reset - * @set_clock_trimmers_high: fn ptr to tune clock trimmers for high voltage - * @set_clock_trimmers_low: fn ptr to tune clock trimmers for low voltage + * @dev: struct device * that holds the OPP table for the DFLL + * @max_freq: maximum frequency supported on this SoC + * @cvb: CPU frequency table for this SoC + * @init_clock_trimmers: callback to initialize clock trimmers + * @set_clock_trimmers_high: callback to tune clock trimmers for high voltage + * @set_clock_trimmers_low: callback to tune clock trimmers for low voltage */ struct tegra_dfll_soc_data { struct device *dev; - unsigned int min_millivolts; - u32 tune0_low; - u32 tune0_high; - u32 tune1; + unsigned long max_freq; + const struct cvb_table *cvb; + void (*init_clock_trimmers)(void); void (*set_clock_trimmers_high)(void); void (*set_clock_trimmers_low)(void); diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index 62ea38187b71..36c974916d4f 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -71,6 +71,7 @@ enum clk_id { tegra_clk_disp2_8, tegra_clk_dp2, tegra_clk_dpaux, + tegra_clk_dpaux1, tegra_clk_dsialp, tegra_clk_dsia_mux, tegra_clk_dsiblp, @@ -306,6 +307,7 @@ enum clk_id { tegra_clk_xusb_ss_div2, tegra_clk_xusb_ssp_src, tegra_clk_sclk_mux, + tegra_clk_sor_safe, tegra_clk_max, }; diff --git a/drivers/clk/tegra/clk-periph-fixed.c b/drivers/clk/tegra/clk-periph-fixed.c new file mode 100644 index 000000000000..c57dfb037b10 --- /dev/null +++ b/drivers/clk/tegra/clk-periph-fixed.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/clk-provider.h> + +#include "clk.h" + +static inline struct tegra_clk_periph_fixed * +to_tegra_clk_periph_fixed(struct clk_hw *hw) +{ + return container_of(hw, struct tegra_clk_periph_fixed, hw); +} + +static int tegra_clk_periph_fixed_is_enabled(struct clk_hw *hw) +{ + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); + u32 mask = 1 << (fixed->num % 32), value; + + value = readl(fixed->base + fixed->regs->enb_reg); + if (value & mask) { + value = readl(fixed->base + fixed->regs->rst_reg); + if ((value & mask) == 0) + return 1; + } + + return 0; +} + +static int tegra_clk_periph_fixed_enable(struct clk_hw *hw) +{ + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); + u32 mask = 1 << (fixed->num % 32); + + writel(mask, fixed->base + fixed->regs->enb_set_reg); + + return 0; +} + +static void tegra_clk_periph_fixed_disable(struct clk_hw *hw) +{ + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); + u32 mask = 1 << (fixed->num % 32); + + writel(mask, fixed->base + fixed->regs->enb_clr_reg); +} + +static unsigned long +tegra_clk_periph_fixed_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); + unsigned long long rate; + + rate = (unsigned long long)parent_rate * fixed->mul; + do_div(rate, fixed->div); + + return (unsigned long)rate; +} + +static const struct clk_ops tegra_clk_periph_fixed_ops = { + .is_enabled = tegra_clk_periph_fixed_is_enabled, + .enable = tegra_clk_periph_fixed_enable, + .disable = tegra_clk_periph_fixed_disable, + .recalc_rate = tegra_clk_periph_fixed_recalc_rate, +}; + +struct clk *tegra_clk_register_periph_fixed(const char *name, + const char *parent, + unsigned long flags, + void __iomem *base, + unsigned int mul, + unsigned int div, + unsigned int num) +{ + const struct tegra_clk_periph_regs *regs; + struct tegra_clk_periph_fixed *fixed; + struct clk_init_data init; + struct clk *clk; + + regs = get_reg_bank(num); + if (!regs) + return ERR_PTR(-EINVAL); + + fixed = kzalloc(sizeof(*fixed), GFP_KERNEL); + if (!fixed) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.flags = flags; + init.parent_names = parent ? &parent : NULL; + init.num_parents = parent ? 1 : 0; + init.ops = &tegra_clk_periph_fixed_ops; + + fixed->base = base; + fixed->regs = regs; + fixed->mul = mul; + fixed->div = div; + fixed->num = num; + + fixed->hw.init = &init; + + clk = clk_register(NULL, &fixed->hw); + if (IS_ERR(clk)) + kfree(fixed); + + return clk; +} diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c index d28d6e95020f..88127828befe 100644 --- a/drivers/clk/tegra/clk-periph-gate.c +++ b/drivers/clk/tegra/clk-periph-gate.c @@ -134,7 +134,7 @@ struct clk *tegra_clk_register_periph_gate(const char *name, struct tegra_clk_periph_gate *gate; struct clk *clk; struct clk_init_data init; - struct tegra_clk_periph_regs *pregs; + const struct tegra_clk_periph_regs *pregs; pregs = get_reg_bank(clk_num); if (!pregs) diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index ec5b6113b012..a17ca6d7f649 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -145,7 +145,7 @@ static struct clk *_tegra_clk_register_periph(const char *name, { struct clk *clk; struct clk_init_data init; - struct tegra_clk_periph_regs *bank; + const struct tegra_clk_periph_regs *bank; bool div = !(periph->gate.flags & TEGRA_PERIPH_NO_DIV); if (periph->gate.flags & TEGRA_PERIPH_NO_DIV) { diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 6ac3f843e7ca..4e194ecc8d5e 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -2013,6 +2013,52 @@ struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name, #endif #if defined(CONFIG_ARCH_TEGRA_210_SOC) +struct clk *tegra_clk_register_pllre_tegra210(const char *name, + const char *parent_name, void __iomem *clk_base, + void __iomem *pmc, unsigned long flags, + struct tegra_clk_pll_params *pll_params, + spinlock_t *lock, unsigned long parent_rate) +{ + u32 val; + struct tegra_clk_pll *pll; + struct clk *clk; + + pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate); + + if (pll_params->adjust_vco) + pll_params->vco_min = pll_params->adjust_vco(pll_params, + parent_rate); + + pll = _tegra_init_pll(clk_base, pmc, pll_params, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + /* program minimum rate by default */ + + val = pll_readl_base(pll); + if (val & PLL_BASE_ENABLE) + WARN_ON(readl_relaxed(clk_base + pll_params->iddq_reg) & + BIT(pll_params->iddq_bit_idx)); + else { + val = 0x4 << divm_shift(pll); + val |= 0x41 << divn_shift(pll); + pll_writel_base(val, pll); + } + + /* disable lock override */ + + val = pll_readl_misc(pll); + val &= ~BIT(29); + pll_writel_misc(val, pll); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_pllre_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + static int clk_plle_tegra210_enable(struct clk_hw *hw) { struct tegra_clk_pll *pll = to_clk_pll(hw); diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c index d64ec7a1b976..91c38f1666c1 100644 --- a/drivers/clk/tegra/clk-tegra-fixed.c +++ b/drivers/clk/tegra/clk-tegra-fixed.c @@ -107,4 +107,3 @@ void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks) *dt_clk = clk; } } - diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index ea2b9cbf9e70..29d04c663abf 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -803,7 +803,7 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("hda2hdmi", "clk_m", 128, TEGRA_PERIPH_ON_APB, tegra_clk_hda2hdmi, 0), GATE("bsea", "clk_m", 62, 0, tegra_clk_bsea, 0), GATE("bsev", "clk_m", 63, 0, tegra_clk_bsev, 0), - GATE("mipi-cal", "clk_m", 56, 0, tegra_clk_mipi_cal, 0), + GATE("mipi-cal", "clk72mhz", 56, 0, tegra_clk_mipi_cal, 0), GATE("usbd", "clk_m", 22, 0, tegra_clk_usbd, 0), GATE("usb2", "clk_m", 58, 0, tegra_clk_usb2, 0), GATE("usb3", "clk_m", 59, 0, tegra_clk_usb3, 0), @@ -821,7 +821,6 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("ispb", "clk_m", 3, 0, tegra_clk_ispb, 0), GATE("vim2_clk", "clk_m", 11, 0, tegra_clk_vim2_clk, 0), GATE("pcie", "clk_m", 70, 0, tegra_clk_pcie, 0), - GATE("dpaux", "clk_m", 181, 0, tegra_clk_dpaux, 0), GATE("gpu", "pll_ref", 184, 0, tegra_clk_gpu, 0), GATE("pllg_ref", "pll_ref", 189, 0, tegra_clk_pll_g_ref, 0), GATE("hsic_trk", "usb2_hsic_trk", 209, TEGRA_PERIPH_NO_RESET, tegra_clk_hsic_trk, 0), @@ -877,7 +876,7 @@ static void __init periph_clk_init(void __iomem *clk_base, struct clk **dt_clk; for (i = 0; i < ARRAY_SIZE(periph_clks); i++) { - struct tegra_clk_periph_regs *bank; + const struct tegra_clk_periph_regs *bank; struct tegra_periph_init_data *data; data = periph_clks + i; diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index df47ec3169c3..b78054fac0a8 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -743,7 +743,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { [tegra_clk_csi] = { .dt_id = TEGRA114_CLK_CSI, .present = true }, [tegra_clk_i2c2] = { .dt_id = TEGRA114_CLK_I2C2, .present = true }, [tegra_clk_uartc] = { .dt_id = TEGRA114_CLK_UARTC, .present = true }, - [tegra_clk_mipi_cal] = { .dt_id = TEGRA114_CLK_MIPI_CAL, .present = true }, [tegra_clk_emc] = { .dt_id = TEGRA114_CLK_EMC, .present = true }, [tegra_clk_usb2] = { .dt_id = TEGRA114_CLK_USB2, .present = true }, [tegra_clk_usb3] = { .dt_id = TEGRA114_CLK_USB3, .present = true }, @@ -1237,6 +1236,11 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base, &emc_lock); clks[TEGRA114_CLK_MC] = clk; + clk = tegra_clk_register_periph_gate("mipi-cal", "clk_m", 0, clk_base, + CLK_SET_RATE_PARENT, 56, + periph_clk_enb_refcnt); + clks[TEGRA114_CLK_MIPI_CAL] = clk; + for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { data = &tegra_periph_clk_list[i]; clk = tegra_clk_register_periph(data->name, diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index 61253330c12b..c205809ba580 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -47,32 +47,32 @@ static const struct cvb_table tegra124_cpu_cvb_tables[] = { }, .speedo_scale = 100, .voltage_scale = 1000, - .cvb_table = { - {204000000UL, {1112619, -29295, 402} }, - {306000000UL, {1150460, -30585, 402} }, - {408000000UL, {1190122, -31865, 402} }, - {510000000UL, {1231606, -33155, 402} }, - {612000000UL, {1274912, -34435, 402} }, - {714000000UL, {1320040, -35725, 402} }, - {816000000UL, {1366990, -37005, 402} }, - {918000000UL, {1415762, -38295, 402} }, - {1020000000UL, {1466355, -39575, 402} }, - {1122000000UL, {1518771, -40865, 402} }, - {1224000000UL, {1573009, -42145, 402} }, - {1326000000UL, {1629068, -43435, 402} }, - {1428000000UL, {1686950, -44715, 402} }, - {1530000000UL, {1746653, -46005, 402} }, - {1632000000UL, {1808179, -47285, 402} }, - {1734000000UL, {1871526, -48575, 402} }, - {1836000000UL, {1936696, -49855, 402} }, - {1938000000UL, {2003687, -51145, 402} }, - {2014500000UL, {2054787, -52095, 402} }, - {2116500000UL, {2124957, -53385, 402} }, - {2218500000UL, {2196950, -54665, 402} }, - {2320500000UL, {2270765, -55955, 402} }, - {2422500000UL, {2346401, -57235, 402} }, - {2524500000UL, {2437299, -58535, 402} }, - {0, { 0, 0, 0} }, + .entries = { + { 204000000UL, { 1112619, -29295, 402 } }, + { 306000000UL, { 1150460, -30585, 402 } }, + { 408000000UL, { 1190122, -31865, 402 } }, + { 510000000UL, { 1231606, -33155, 402 } }, + { 612000000UL, { 1274912, -34435, 402 } }, + { 714000000UL, { 1320040, -35725, 402 } }, + { 816000000UL, { 1366990, -37005, 402 } }, + { 918000000UL, { 1415762, -38295, 402 } }, + { 1020000000UL, { 1466355, -39575, 402 } }, + { 1122000000UL, { 1518771, -40865, 402 } }, + { 1224000000UL, { 1573009, -42145, 402 } }, + { 1326000000UL, { 1629068, -43435, 402 } }, + { 1428000000UL, { 1686950, -44715, 402 } }, + { 1530000000UL, { 1746653, -46005, 402 } }, + { 1632000000UL, { 1808179, -47285, 402 } }, + { 1734000000UL, { 1871526, -48575, 402 } }, + { 1836000000UL, { 1936696, -49855, 402 } }, + { 1938000000UL, { 2003687, -51145, 402 } }, + { 2014500000UL, { 2054787, -52095, 402 } }, + { 2116500000UL, { 2124957, -53385, 402 } }, + { 2218500000UL, { 2196950, -54665, 402 } }, + { 2320500000UL, { 2270765, -55955, 402 } }, + { 2422500000UL, { 2346401, -57235, 402 } }, + { 2524500000UL, { 2437299, -58535, 402 } }, + { 0UL, { 0, 0, 0 } }, }, .cpu_dfll_data = { .tune0_low = 0x005020ff, @@ -84,9 +84,8 @@ static const struct cvb_table tegra124_cpu_cvb_tables[] = { static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) { - int process_id, speedo_id, speedo_value; + int process_id, speedo_id, speedo_value, err; struct tegra_dfll_soc_data *soc; - const struct cvb_table *cvb; process_id = tegra_sku_info.cpu_process_id; speedo_id = tegra_sku_info.cpu_speedo_id; @@ -108,23 +107,41 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) return -ENODEV; } - cvb = tegra_cvb_build_opp_table(tegra124_cpu_cvb_tables, - ARRAY_SIZE(tegra124_cpu_cvb_tables), - process_id, speedo_id, speedo_value, - cpu_max_freq_table[speedo_id], - soc->dev); - if (IS_ERR(cvb)) { - dev_err(&pdev->dev, "couldn't build OPP table: %ld\n", - PTR_ERR(cvb)); - return PTR_ERR(cvb); + soc->max_freq = cpu_max_freq_table[speedo_id]; + + soc->cvb = tegra_cvb_add_opp_table(soc->dev, tegra124_cpu_cvb_tables, + ARRAY_SIZE(tegra124_cpu_cvb_tables), + process_id, speedo_id, speedo_value, + soc->max_freq); + if (IS_ERR(soc->cvb)) { + dev_err(&pdev->dev, "couldn't add OPP table: %ld\n", + PTR_ERR(soc->cvb)); + return PTR_ERR(soc->cvb); + } + + err = tegra_dfll_register(pdev, soc); + if (err < 0) { + tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq); + return err; } - soc->min_millivolts = cvb->min_millivolts; - soc->tune0_low = cvb->cpu_dfll_data.tune0_low; - soc->tune0_high = cvb->cpu_dfll_data.tune0_high; - soc->tune1 = cvb->cpu_dfll_data.tune1; + platform_set_drvdata(pdev, soc); + + return 0; +} + +static int tegra124_dfll_fcpu_remove(struct platform_device *pdev) +{ + struct tegra_dfll_soc_data *soc = platform_get_drvdata(pdev); + int err; + + err = tegra_dfll_unregister(pdev); + if (err < 0) + dev_err(&pdev->dev, "failed to unregister DFLL: %d\n", err); + + tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq); - return tegra_dfll_register(pdev, soc); + return 0; } static const struct of_device_id tegra124_dfll_fcpu_of_match[] = { @@ -140,7 +157,7 @@ static const struct dev_pm_ops tegra124_dfll_pm_ops = { static struct platform_driver tegra124_dfll_fcpu_driver = { .probe = tegra124_dfll_fcpu_probe, - .remove = tegra_dfll_unregister, + .remove = tegra124_dfll_fcpu_remove, .driver = { .name = "tegra124-dfll", .of_match_table = tegra124_dfll_fcpu_of_match, diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 1627258292d2..f4fbbf16a056 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1155,6 +1155,10 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base, 1, 2); clks[TEGRA124_CLK_XUSB_SS_DIV2] = clk; + clk = tegra_clk_register_periph_fixed("dpaux", "pll_p", 0, clk_base, + 1, 17, 181); + clks[TEGRA124_CLK_DPAUX] = clk; + clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0, clk_base + PLLD_MISC, 30, 0, &pll_d_lock); clks[TEGRA124_CLK_PLL_D_DSI_OUT] = clk; diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 637041fd53ad..b8551813ec43 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -92,6 +92,7 @@ #define PLLE_AUX 0x48c #define PLLRE_BASE 0x4c4 #define PLLRE_MISC0 0x4c8 +#define PLLRE_OUT1 0x4cc #define PLLDP_BASE 0x590 #define PLLDP_MISC 0x594 @@ -175,6 +176,19 @@ #define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14) #define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12) +#define SATA_PLL_CFG0 0x490 +#define SATA_PLL_CFG0_PADPLL_RESET_SWCTL BIT(0) +#define SATA_PLL_CFG0_PADPLL_USE_LOCKDET BIT(2) +#define SATA_PLL_CFG0_PADPLL_SLEEP_IDDQ BIT(13) +#define SATA_PLL_CFG0_SEQ_ENABLE BIT(24) + +#define XUSBIO_PLL_CFG0 0x51c +#define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL BIT(0) +#define XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL BIT(2) +#define XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET BIT(6) +#define XUSBIO_PLL_CFG0_PADPLL_SLEEP_IDDQ BIT(13) +#define XUSBIO_PLL_CFG0_SEQ_ENABLE BIT(24) + #define UTMIPLL_HW_PWRDN_CFG0 0x52c #define UTMIPLL_HW_PWRDN_CFG0_UTMIPLL_LOCK BIT(31) #define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE BIT(25) @@ -416,6 +430,51 @@ static const char *mux_pllmcp_clkm[] = { #define PLLU_MISC0_WRITE_MASK 0xbfffffff #define PLLU_MISC1_WRITE_MASK 0x00000007 +void tegra210_xusb_pll_hw_control_enable(void) +{ + u32 val; + + val = readl_relaxed(clk_base + XUSBIO_PLL_CFG0); + val &= ~(XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL | + XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL); + val |= XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET | + XUSBIO_PLL_CFG0_PADPLL_SLEEP_IDDQ; + writel_relaxed(val, clk_base + XUSBIO_PLL_CFG0); +} +EXPORT_SYMBOL_GPL(tegra210_xusb_pll_hw_control_enable); + +void tegra210_xusb_pll_hw_sequence_start(void) +{ + u32 val; + + val = readl_relaxed(clk_base + XUSBIO_PLL_CFG0); + val |= XUSBIO_PLL_CFG0_SEQ_ENABLE; + writel_relaxed(val, clk_base + XUSBIO_PLL_CFG0); +} +EXPORT_SYMBOL_GPL(tegra210_xusb_pll_hw_sequence_start); + +void tegra210_sata_pll_hw_control_enable(void) +{ + u32 val; + + val = readl_relaxed(clk_base + SATA_PLL_CFG0); + val &= ~SATA_PLL_CFG0_PADPLL_RESET_SWCTL; + val |= SATA_PLL_CFG0_PADPLL_USE_LOCKDET | + SATA_PLL_CFG0_PADPLL_SLEEP_IDDQ; + writel_relaxed(val, clk_base + SATA_PLL_CFG0); +} +EXPORT_SYMBOL_GPL(tegra210_sata_pll_hw_control_enable); + +void tegra210_sata_pll_hw_sequence_start(void) +{ + u32 val; + + val = readl_relaxed(clk_base + SATA_PLL_CFG0); + val |= SATA_PLL_CFG0_SEQ_ENABLE; + writel_relaxed(val, clk_base + SATA_PLL_CFG0); +} +EXPORT_SYMBOL_GPL(tegra210_sata_pll_hw_sequence_start); + static inline void _pll_misc_chk_default(void __iomem *base, struct tegra_clk_pll_params *params, u8 misc_num, u32 default_val, u32 mask) @@ -2092,6 +2151,7 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = { [tegra_clk_clk72Mhz_8] = { .dt_id = TEGRA210_CLK_CLK72MHZ, .present = true }, [tegra_clk_vic03_8] = { .dt_id = TEGRA210_CLK_VIC03, .present = true }, [tegra_clk_dpaux] = { .dt_id = TEGRA210_CLK_DPAUX, .present = true }, + [tegra_clk_dpaux1] = { .dt_id = TEGRA210_CLK_DPAUX1, .present = true }, [tegra_clk_sor0] = { .dt_id = TEGRA210_CLK_SOR0, .present = true }, [tegra_clk_sor0_lvds] = { .dt_id = TEGRA210_CLK_SOR0_LVDS, .present = true }, [tegra_clk_gpu] = { .dt_id = TEGRA210_CLK_GPU, .present = true }, @@ -2403,6 +2463,18 @@ static __init void tegra210_periph_clk_init(void __iomem *clk_base, 1, 2); clks[TEGRA210_CLK_XUSB_SS_DIV2] = clk; + clk = tegra_clk_register_periph_fixed("dpaux", "pll_p", 0, clk_base, + 1, 17, 181); + clks[TEGRA210_CLK_DPAUX] = clk; + + clk = tegra_clk_register_periph_fixed("dpaux1", "pll_p", 0, clk_base, + 1, 17, 207); + clks[TEGRA210_CLK_DPAUX1] = clk; + + clk = tegra_clk_register_periph_fixed("sor_safe", "pll_p", 0, clk_base, + 1, 17, 222); + clks[TEGRA210_CLK_SOR_SAFE] = clk; + /* pll_d_dsi_out */ clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0, clk_base + PLLD_MISC0, 21, 0, &pll_d_lock); @@ -2582,8 +2654,10 @@ static void __init tegra210_pll_init(void __iomem *clk_base, clks[TEGRA210_CLK_PLL_D_OUT0] = clk; /* PLLRE */ - clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc, - 0, &pll_re_vco_params, &pll_re_lock, pll_ref_freq); + clk = tegra_clk_register_pllre_tegra210("pll_re_vco", "pll_ref", + clk_base, pmc, 0, + &pll_re_vco_params, + &pll_re_lock, pll_ref_freq); clk_register_clkdev(clk, "pll_re_vco", NULL); clks[TEGRA210_CLK_PLL_RE_VCO] = clk; @@ -2593,6 +2667,15 @@ static void __init tegra210_pll_init(void __iomem *clk_base, clk_register_clkdev(clk, "pll_re_out", NULL); clks[TEGRA210_CLK_PLL_RE_OUT] = clk; + clk = tegra_clk_register_divider("pll_re_out1_div", "pll_re_vco", + clk_base + PLLRE_OUT1, 0, + TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_re_out1", "pll_re_out1_div", + clk_base + PLLRE_OUT1, 1, 0, + CLK_SET_RATE_PARENT, 0, NULL); + clks[TEGRA210_CLK_PLL_RE_OUT1] = clk; + /* PLLE */ clk = tegra_clk_register_plle_tegra210("pll_e", "pll_ref", clk_base, 0, &pll_e_params, NULL); diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 0478565cf292..9396f4930da7 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -339,11 +339,11 @@ static const struct pdiv_map pllu_p[] = { }; static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { - { 12000000, 480000000, 960, 12, 1, 12 }, - { 13000000, 480000000, 960, 13, 1, 12 }, - { 16800000, 480000000, 400, 7, 1, 5 }, - { 19200000, 480000000, 200, 4, 1, 3 }, - { 26000000, 480000000, 960, 26, 1, 12 }, + { 12000000, 480000000, 960, 12, 2, 12 }, + { 13000000, 480000000, 960, 13, 2, 12 }, + { 16800000, 480000000, 400, 7, 2, 5 }, + { 19200000, 480000000, 200, 4, 2, 3 }, + { 26000000, 480000000, 960, 26, 2, 12 }, { 0, 0, 0, 0, 0, 0 }, }; @@ -1372,6 +1372,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_SBC4, TEGRA30_CLK_PLL_P, 100000000, 0 }, { TEGRA30_CLK_SBC5, TEGRA30_CLK_PLL_P, 100000000, 0 }, { TEGRA30_CLK_SBC6, TEGRA30_CLK_PLL_P, 100000000, 0 }, + { TEGRA30_CLK_PLL_C, TEGRA30_CLK_CLK_MAX, 600000000, 0 }, { TEGRA30_CLK_HOST1X, TEGRA30_CLK_PLL_C, 150000000, 0 }, { TEGRA30_CLK_DISP1, TEGRA30_CLK_PLL_P, 600000000, 0 }, { TEGRA30_CLK_DISP2, TEGRA30_CLK_PLL_P, 600000000, 0 }, @@ -1379,6 +1380,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_GR2D, TEGRA30_CLK_PLL_C, 300000000, 0 }, { TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0 }, { TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0 }, + { TEGRA30_CLK_PLL_U, TEGRA30_CLK_CLK_MAX, 480000000, 0 }, /* must be the last entry */ { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 }, }; diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index f60fe2e344ca..b2cdd9a235f4 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -84,7 +84,7 @@ static int (*special_reset_assert)(unsigned long); static int (*special_reset_deassert)(unsigned long); static unsigned int num_special_reset; -static struct tegra_clk_periph_regs periph_regs[] = { +static const struct tegra_clk_periph_regs periph_regs[] = { [0] = { .enb_reg = CLK_OUT_ENB_L, .enb_set_reg = CLK_OUT_ENB_SET_L, @@ -182,7 +182,7 @@ static int tegra_clk_rst_deassert(struct reset_controller_dev *rcdev, return -EINVAL; } -struct tegra_clk_periph_regs *get_reg_bank(int clkid) +const struct tegra_clk_periph_regs *get_reg_bank(int clkid) { int reg_bank = clkid / 32; diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 4dbcfaec576a..9421f0310999 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -386,6 +386,12 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name, struct tegra_clk_pll_params *pll_params, spinlock_t *lock, unsigned long parent_rate); +struct clk *tegra_clk_register_pllre_tegra210(const char *name, + const char *parent_name, void __iomem *clk_base, + void __iomem *pmc, unsigned long flags, + struct tegra_clk_pll_params *pll_params, + spinlock_t *lock, unsigned long parent_rate); + struct clk *tegra_clk_register_plle_tegra114(const char *name, const char *parent_name, void __iomem *clk_base, unsigned long flags, @@ -496,7 +502,7 @@ struct tegra_clk_periph_gate { u8 flags; int clk_num; int *enable_refcnt; - struct tegra_clk_periph_regs *regs; + const struct tegra_clk_periph_regs *regs; }; #define to_clk_periph_gate(_hw) \ @@ -516,6 +522,23 @@ struct clk *tegra_clk_register_periph_gate(const char *name, const char *parent_name, u8 gate_flags, void __iomem *clk_base, unsigned long flags, int clk_num, int *enable_refcnt); +struct tegra_clk_periph_fixed { + struct clk_hw hw; + void __iomem *base; + const struct tegra_clk_periph_regs *regs; + unsigned int mul; + unsigned int div; + unsigned int num; +}; + +struct clk *tegra_clk_register_periph_fixed(const char *name, + const char *parent, + unsigned long flags, + void __iomem *base, + unsigned int mul, + unsigned int div, + unsigned int num); + /** * struct clk-periph - peripheral clock * @@ -716,7 +739,7 @@ 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); -struct tegra_clk_periph_regs *get_reg_bank(int clkid); +const struct tegra_clk_periph_regs *get_reg_bank(int clkid); struct clk **tegra_clk_init(void __iomem *clk_base, int num, int periph_banks); struct clk **tegra_lookup_dt_id(int clk_id, struct tegra_clk *tegra_clk); diff --git a/drivers/clk/tegra/cvb.c b/drivers/clk/tegra/cvb.c index 69c74eec3a4b..624115e82ff9 100644 --- a/drivers/clk/tegra/cvb.c +++ b/drivers/clk/tegra/cvb.c @@ -61,29 +61,28 @@ static int round_voltage(int mv, const struct rail_alignment *align, int up) return mv; } -static int build_opp_table(const struct cvb_table *d, - int speedo_value, - unsigned long max_freq, - struct device *opp_dev) +static int build_opp_table(struct device *dev, const struct cvb_table *table, + int speedo_value, unsigned long max_freq) { + const struct rail_alignment *align = &table->alignment; int i, ret, dfll_mv, min_mv, max_mv; - const struct cvb_table_freq_entry *table = NULL; - const struct rail_alignment *align = &d->alignment; - min_mv = round_voltage(d->min_millivolts, align, UP); - max_mv = round_voltage(d->max_millivolts, align, DOWN); + min_mv = round_voltage(table->min_millivolts, align, UP); + max_mv = round_voltage(table->max_millivolts, align, DOWN); for (i = 0; i < MAX_DVFS_FREQS; i++) { - table = &d->cvb_table[i]; - if (!table->freq || (table->freq > max_freq)) + const struct cvb_table_freq_entry *entry = &table->entries[i]; + + if (!entry->freq || (entry->freq > max_freq)) break; - dfll_mv = get_cvb_voltage( - speedo_value, d->speedo_scale, &table->coefficients); - dfll_mv = round_cvb_voltage(dfll_mv, d->voltage_scale, align); + dfll_mv = get_cvb_voltage(speedo_value, table->speedo_scale, + &entry->coefficients); + dfll_mv = round_cvb_voltage(dfll_mv, table->voltage_scale, + align); dfll_mv = clamp(dfll_mv, min_mv, max_mv); - ret = dev_pm_opp_add(opp_dev, table->freq, dfll_mv * 1000); + ret = dev_pm_opp_add(dev, entry->freq, dfll_mv * 1000); if (ret) return ret; } @@ -92,7 +91,7 @@ static int build_opp_table(const struct cvb_table *d, } /** - * tegra_cvb_build_opp_table - build OPP table from Tegra CVB tables + * tegra_cvb_add_opp_table - build OPP table from Tegra CVB tables * @cvb_tables: array of CVB tables * @sz: size of the previously mentioned array * @process_id: process id of the HW module @@ -108,26 +107,42 @@ static int build_opp_table(const struct cvb_table *d, * given @opp_dev. Returns a pointer to the struct cvb_table that matched * or an ERR_PTR on failure. */ -const struct cvb_table *tegra_cvb_build_opp_table( - const struct cvb_table *cvb_tables, - size_t sz, int process_id, - int speedo_id, int speedo_value, - unsigned long max_rate, - struct device *opp_dev) +const struct cvb_table * +tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *tables, + size_t count, int process_id, int speedo_id, + int speedo_value, unsigned long max_freq) { - int i, ret; + size_t i; + int ret; - for (i = 0; i < sz; i++) { - const struct cvb_table *d = &cvb_tables[i]; + for (i = 0; i < count; i++) { + const struct cvb_table *table = &tables[i]; - if (d->speedo_id != -1 && d->speedo_id != speedo_id) + if (table->speedo_id != -1 && table->speedo_id != speedo_id) continue; - if (d->process_id != -1 && d->process_id != process_id) + + if (table->process_id != -1 && table->process_id != process_id) continue; - ret = build_opp_table(d, speedo_value, max_rate, opp_dev); - return ret ? ERR_PTR(ret) : d; + ret = build_opp_table(dev, table, speedo_value, max_freq); + return ret ? ERR_PTR(ret) : table; } return ERR_PTR(-EINVAL); } + +void tegra_cvb_remove_opp_table(struct device *dev, + const struct cvb_table *table, + unsigned long max_freq) +{ + unsigned int i; + + for (i = 0; i < MAX_DVFS_FREQS; i++) { + const struct cvb_table_freq_entry *entry = &table->entries[i]; + + if (!entry->freq || (entry->freq > max_freq)) + break; + + dev_pm_opp_remove(dev, entry->freq); + } +} diff --git a/drivers/clk/tegra/cvb.h b/drivers/clk/tegra/cvb.h index f62cdc4f4234..c1f077993b2a 100644 --- a/drivers/clk/tegra/cvb.h +++ b/drivers/clk/tegra/cvb.h @@ -53,15 +53,16 @@ struct cvb_table { int speedo_scale; int voltage_scale; - struct cvb_table_freq_entry cvb_table[MAX_DVFS_FREQS]; + struct cvb_table_freq_entry entries[MAX_DVFS_FREQS]; struct cvb_cpu_dfll_data cpu_dfll_data; }; -const struct cvb_table *tegra_cvb_build_opp_table( - const struct cvb_table *cvb_tables, - size_t sz, int process_id, - int speedo_id, int speedo_value, - unsigned long max_rate, - struct device *opp_dev); +const struct cvb_table * +tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *cvb_tables, + size_t count, int process_id, int speedo_id, + int speedo_value, unsigned long max_freq); +void tegra_cvb_remove_opp_table(struct device *dev, + const struct cvb_table *table, + unsigned long max_freq); #endif |