From 5a88b0d10f198ddd5f988f40d34b52f34c87a5c6 Mon Sep 17 00:00:00 2001 From: Yen Lin Date: Wed, 6 Mar 2013 11:47:24 +0000 Subject: [PATCH 01/20] clk: tegra: Fix periph_clk_to_bit macro The parameter name should be "gate", not "periph". This worked, however, because it happens that everywhere periph_clk_to_bit is called, "gate" was in the local scope. Signed-off-by: Yen Lin Signed-off-by: Andrew Chew Reviewed-by: Thierry Reding Reviewed-by: Prashant Gaikwad Acked-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-periph-gate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c index 6dd533251e7b..d87e1cece9fa 100644 --- a/drivers/clk/tegra/clk-periph-gate.c +++ b/drivers/clk/tegra/clk-periph-gate.c @@ -41,7 +41,7 @@ static DEFINE_SPINLOCK(periph_ref_lock); #define write_rst_clr(val, gate) \ writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg)) -#define periph_clk_to_bit(periph) (1 << (gate->clk_num % 32)) +#define periph_clk_to_bit(gate) (1 << (gate->clk_num % 32)) /* Peripheral gate clock ops */ static int clk_periph_is_enabled(struct clk_hw *hw) From 4dd59cdd35506b77ed4ebf4bb90347d7653ba585 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 28 Mar 2013 21:31:27 +0100 Subject: [PATCH 02/20] clk: tegra: Export peripheral reset functions The tegra_periph_reset_assert() and tegra_periph_reset_deassert() functions can be used by drivers to reset peripherals. In order to allow such drivers to be built as modules, export the functions. Note that this restores the status quo as the functions were exported before the move to the drivers/clk tree. Signed-off-by: Thierry Reding Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-periph.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index 788486e6331a..9dbd301ace77 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -128,6 +129,7 @@ void tegra_periph_reset_deassert(struct clk *c) tegra_periph_reset(gate, 0); } +EXPORT_SYMBOL(tegra_periph_reset_deassert); void tegra_periph_reset_assert(struct clk *c) { @@ -147,6 +149,7 @@ void tegra_periph_reset_assert(struct clk *c) tegra_periph_reset(gate, 1); } +EXPORT_SYMBOL(tegra_periph_reset_assert); const struct clk_ops tegra_clk_periph_ops = { .get_parent = clk_periph_get_parent, From ce910686f814fe220f4e55ecca5cfdea7082b3de Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 2 Apr 2013 16:18:44 +0200 Subject: [PATCH 03/20] clk: tegra: Make gr2d and gr3d clocks children of pll_c By default these clocks are children of pll_m, but in downstream kernels they are reparented to pll_c. While at it, decrease their frequencies to 300 MHz because the defaults aren't in the specified range. gr2d can reportedly run at much higher frequencies, but 300 MHz works and is a more conservative default. Signed-off-by: Thierry Reding Acked-by: Mike Turquette Acked-By: Peter De Schrijver Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-tegra20.c | 2 ++ drivers/clk/tegra/clk-tegra30.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index b92d48be4cc9..f87bd4a8c324 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -1247,6 +1247,8 @@ static __initdata struct tegra_clk_init_table init_table[] = { {host1x, pll_c, 150000000, 0}, {disp1, pll_p, 600000000, 0}, {disp2, pll_p, 600000000, 0}, + {gr2d, pll_c, 300000000, 0}, + {gr3d, pll_c, 300000000, 0}, {clk_max, clk_max, 0, 0}, /* This MUST be the last entry */ }; diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index ba6f51bc9f3b..b8b241de3f4c 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -1911,6 +1911,8 @@ static __initdata struct tegra_clk_init_table init_table[] = { {disp1, pll_p, 600000000, 0}, {disp2, pll_p, 600000000, 0}, {twd, clk_max, 0, 1}, + {gr2d, pll_c, 300000000, 0}, + {gr3d, pll_c, 300000000, 0}, {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */ }; From 82ce742140f32394cc5be75f1c98cdbbff284582 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Thu, 4 Apr 2013 14:35:04 +0530 Subject: [PATCH 04/20] clk: tegra: Fix cdev1 and cdev2 IDs Correct IDs for cdev1 and cdev2 are 94 and 93 respectively. Signed-off-by: Prashant Gaikwad [swarren: split into separate driver and device-tree patches] Signed-off-by: Stephen Warren --- .../devicetree/bindings/clock/nvidia,tegra20-car.txt | 4 ++-- drivers/clk/tegra/clk-tegra20.c | 2 +- drivers/clk/tegra/clk-tegra30.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt index 0921fac73528..e885680f6b45 100644 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt @@ -120,8 +120,8 @@ Required properties : 90 clk_d 91 unassigned 92 sus - 93 cdev1 - 94 cdev2 + 93 cdev2 + 94 cdev1 95 unassigned 96 uart2 diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index f87bd4a8c324..a7dc0a937361 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -236,7 +236,7 @@ enum tegra20_clk { dvc, dsi, mipi = 50, hdmi, csi, tvdac, i2c2, uartc, emc = 57, usb2, usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3, pex, owr, afi, csite, pcie_xclk, avpucq = 75, la, irama = 84, iramb, - iramc, iramd, cram2, audio_2x, clk_d, csus = 92, cdev1, cdev2, + iramc, iramd, cram2, audio_2x, clk_d, csus = 92, cdev2, cdev1, uartb = 96, vfir, spdif_in, spdif_out, vi, vi_sensor, tvo, cve, osc, clk_32k, clk_m, sclk, cclk, hclk, pclk, blink, pll_a, pll_a_out0, pll_c, pll_c_out1, pll_d, pll_d_out0, pll_e, pll_m, pll_m_out1, diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index b8b241de3f4c..181a6eef5ce8 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -330,7 +330,7 @@ enum tegra30_clk { usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3, pcie, owr, afi, csite, pciex, avpucq, la, dtv = 79, ndspeed, i2cslow, dsib, irama = 84, iramb, iramc, iramd, cram2, audio_2x = 90, csus = 92, - cdev1, cdev2, cpu_g = 96, cpu_lp, gr3d2, mselect, tsensor, i2s3, i2s4, + cdev2, cdev1, cpu_g = 96, cpu_lp, gr3d2, mselect, tsensor, i2s3, i2s4, i2c4, sbc5, sbc6, d_audio, apbif, dam0, dam1, dam2, hda2codec_2x, atomics, audio0_2x, audio1_2x, audio2_2x, audio3_2x, audio4_2x, spdif_2x, actmon, extern1, extern2, extern3, sata_oob, sata, hda, From 441f199a37cfd66c5dd8dd45490bd3ea6971117d Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 25 Mar 2013 13:22:24 -0600 Subject: [PATCH 05/20] clk: tegra: defer application of init table The Tegra clock driver is initialized during the ARM machine descriptor's .init_irq() hook. It can't be initialized earlier, since dynamic memory usage is required. It can't be initialized later, since the .init_timer() hook needs the clocks initialized. However, at this time, udelay() doesn't work. The Tegra clock initialization table may enable some PLLs. Enabling a PLL may require usage of udelay(). Hence, this can't happen right when the clock driver is initialized. To solve this, separate the clock driver initialization from the clock table processing, so they can execute at separate times. Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/tegra.c | 3 +++ drivers/clk/tegra/clk-tegra20.c | 7 ++++++- drivers/clk/tegra/clk-tegra30.c | 7 ++++++- drivers/clk/tegra/clk.c | 10 ++++++++++ drivers/clk/tegra/clk.h | 3 +++ include/linux/clk/tegra.h | 1 + 6 files changed, 29 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index 84deeab23ee7..61749e2d8111 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,8 @@ static void __init tegra_dt_init(void) struct soc_device *soc_dev; struct device *parent = NULL; + tegra_clocks_apply_init_table(); + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); if (!soc_dev_attr) goto out; diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index a7dc0a937361..a15fb28197b5 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -1252,6 +1252,11 @@ static __initdata struct tegra_clk_init_table init_table[] = { {clk_max, clk_max, 0, 0}, /* This MUST be the last entry */ }; +static void __init tegra20_clock_apply_init_table(void) +{ + tegra_init_from_table(init_table, clks, clk_max); +} + /* * Some clocks may be used by different drivers depending on the board * configuration. List those here to register them twice in the clock lookup @@ -1318,7 +1323,7 @@ void __init tegra20_clock_init(struct device_node *np) clk_data.clk_num = ARRAY_SIZE(clks); of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); - tegra_init_from_table(init_table, clks, clk_max); + tegra_clk_apply_init_table = tegra20_clock_apply_init_table; tegra_cpu_car_ops = &tegra20_cpu_car_ops; } diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 181a6eef5ce8..e0ee93c2db6c 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -1916,6 +1916,11 @@ static __initdata struct tegra_clk_init_table init_table[] = { {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */ }; +static void __init tegra30_clock_apply_init_table(void) +{ + tegra_init_from_table(init_table, clks, clk_max); +} + /* * Some clocks may be used by different drivers depending on the board * configuration. List those here to register them twice in the clock lookup @@ -1989,7 +1994,7 @@ void __init tegra30_clock_init(struct device_node *np) clk_data.clk_num = ARRAY_SIZE(clks); of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); - tegra_init_from_table(init_table, clks, clk_max); + tegra_clk_apply_init_table = tegra30_clock_apply_init_table; tegra_cpu_car_ops = &tegra30_cpu_car_ops; } diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index a603b9af0ad3..4a61d15425dc 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -83,3 +83,13 @@ 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) +{ + if (!tegra_clk_apply_init_table) + return; + + tegra_clk_apply_init_table(); +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index a09d7dcaf183..3c566e2d518a 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -510,4 +510,7 @@ void tegra30_clock_init(struct device_node *np); static inline void tegra30_clock_init(struct device_node *np) {} #endif /* CONFIG_ARCH_TEGRA_3x_SOC */ +typedef void (*tegra_clk_apply_init_table_func)(void); +extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table; + #endif /* TEGRA_CLK_H */ diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index 404d6f940872..642789baec74 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -123,5 +123,6 @@ static inline void tegra_cpu_clock_resume(void) void tegra_periph_reset_deassert(struct clk *c); void tegra_periph_reset_assert(struct clk *c); void tegra_clocks_init(void); +void tegra_clocks_apply_init_table(void); #endif /* __LINUX_CLK_TEGRA_H_ */ From 6a676fa0af4e2bd11ab3950e277e81a959a9a198 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 3 Apr 2013 17:40:35 +0300 Subject: [PATCH 06/20] clk: tegra: provide dummy cpu car ops tegra_boot_secondary() relies on some of the car ops. This means having an uninitialized tegra_cpu_car_ops will lead to an early boot panic. Providing a dummy struct avoids this and makes adding Tegra114 clock support in a bisectable way a lot easier. Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index 4a61d15425dc..70b7a4783bee 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -22,7 +22,8 @@ #include "clk.h" /* Global data of Tegra CPU CAR ops */ -struct tegra_cpu_car_ops *tegra_cpu_car_ops; +static struct tegra_cpu_car_ops dummy_car_ops; +struct tegra_cpu_car_ops *tegra_cpu_car_ops = &dummy_car_ops; void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, struct clk *clks[], int clk_max) From dba4072a4a20b2986562cced98ce04a887614528 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 3 Apr 2013 17:40:36 +0300 Subject: [PATCH 07/20] clk: tegra: Refactor PLL programming code Refactor the PLL programming code to make it useable by the new PLL types introduced by Tegra114. The following changes were done: * Split programming the PLL into updating m,n,p and updating cpcon * Move locking from _update_pll_cpcon() to clk_pll_set_rate() * Introduce _get_pll_mnp() helper * Move check for identical m,n,p values to clk_pll_set_rate() * struct tegra_clk_pll_freq_table will always contain the values as defined by the hardware. * Simplify the arguments to clk_pll_wait_for_lock() * Split _tegra_clk_register_pll() Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-pll.c | 284 +++++++++++++++++++------------- drivers/clk/tegra/clk-tegra20.c | 144 ++++++++-------- drivers/clk/tegra/clk-tegra30.c | 220 ++++++++++++------------- drivers/clk/tegra/clk.h | 9 +- 4 files changed, 360 insertions(+), 297 deletions(-) diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 165f24734c1b..3feefb15e473 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012, 2013, 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, @@ -113,20 +113,28 @@ static void clk_pll_enable_lock(struct tegra_clk_pll *pll) pll_writel_misc(val, pll); } -static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll, - void __iomem *lock_addr, u32 lock_bit_idx) +static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll) { int i; - u32 val; + u32 val, lock_bit; + void __iomem *lock_addr; if (!(pll->flags & TEGRA_PLL_USE_LOCK)) { udelay(pll->params->lock_delay); return 0; } + lock_addr = pll->clk_base; + if (pll->flags & TEGRA_PLL_LOCK_MISC) + lock_addr += pll->params->misc_reg; + else + lock_addr += pll->params->base_reg; + + lock_bit = BIT(pll->params->lock_bit_idx); + for (i = 0; i < pll->params->lock_delay; i++) { val = readl_relaxed(lock_addr); - if (val & BIT(lock_bit_idx)) { + if (val & lock_bit) { udelay(PLL_POST_LOCK_DELAY); return 0; } @@ -155,7 +163,7 @@ static int clk_pll_is_enabled(struct clk_hw *hw) return val & PLL_BASE_ENABLE ? 1 : 0; } -static int _clk_pll_enable(struct clk_hw *hw) +static void _clk_pll_enable(struct clk_hw *hw) { struct tegra_clk_pll *pll = to_clk_pll(hw); u32 val; @@ -172,11 +180,6 @@ static int _clk_pll_enable(struct clk_hw *hw) val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE); } - - clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->base_reg, - pll->params->lock_bit_idx); - - return 0; } static void _clk_pll_disable(struct clk_hw *hw) @@ -204,7 +207,9 @@ static int clk_pll_enable(struct clk_hw *hw) if (pll->lock) spin_lock_irqsave(pll->lock, flags); - ret = _clk_pll_enable(hw); + _clk_pll_enable(hw); + + ret = clk_pll_wait_for_lock(pll); if (pll->lock) spin_unlock_irqrestore(pll->lock, flags); @@ -241,8 +246,6 @@ static int _get_table_rate(struct clk_hw *hw, if (sel->input_rate == 0) return -EINVAL; - BUG_ON(sel->p < 1); - cfg->input_rate = sel->input_rate; cfg->output_rate = sel->output_rate; cfg->m = sel->m; @@ -290,88 +293,109 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, cfg->output_rate <<= 1) p_div++; - cfg->p = 1 << p_div; + cfg->p = p_div; cfg->m = parent_rate / cfreq; cfg->n = cfg->output_rate / cfreq; cfg->cpcon = OUT_OF_TABLE_CPCON; if (cfg->m > divm_max(pll) || cfg->n > divn_max(pll) || - cfg->p > divp_max(pll) || cfg->output_rate > pll->params->vco_max) { + (1 << p_div) > divp_max(pll) + || cfg->output_rate > pll->params->vco_max) { pr_err("%s: Failed to set %s rate %lu\n", __func__, __clk_get_name(hw->clk), rate); return -EINVAL; } + if (pll->flags & TEGRA_PLLU) + cfg->p ^= 1; + return 0; } +static void _update_pll_mnp(struct tegra_clk_pll *pll, + struct tegra_clk_pll_freq_table *cfg) +{ + u32 val; + + 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)); + + pll_writel_base(val, pll); +} + +static void _get_pll_mnp(struct tegra_clk_pll *pll, + struct tegra_clk_pll_freq_table *cfg) +{ + u32 val; + + 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)); +} + +static void _update_pll_cpcon(struct tegra_clk_pll *pll, + struct tegra_clk_pll_freq_table *cfg, + unsigned long rate) +{ + u32 val; + + val = pll_readl_misc(pll); + + val &= ~(PLL_MISC_CPCON_MASK << PLL_MISC_CPCON_SHIFT); + val |= cfg->cpcon << PLL_MISC_CPCON_SHIFT; + + if (pll->flags & TEGRA_PLL_SET_LFCON) { + val &= ~(PLL_MISC_LFCON_MASK << PLL_MISC_LFCON_SHIFT); + if (cfg->n >= PLLDU_LFCON_SET_DIVN) + val |= 1 << PLL_MISC_LFCON_SHIFT; + } else if (pll->flags & TEGRA_PLL_SET_DCCON) { + val &= ~(1 << PLL_MISC_DCCON_SHIFT); + if (rate >= (pll->params->vco_max >> 1)) + val |= 1 << PLL_MISC_DCCON_SHIFT; + } + + pll_writel_misc(val, pll); +} + static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, unsigned long rate) { struct tegra_clk_pll *pll = to_clk_pll(hw); - unsigned long flags = 0; - u32 divp, val, old_base; - int state; - - divp = __ffs(cfg->p); - - if (pll->flags & TEGRA_PLLU) - divp ^= 1; - - if (pll->lock) - spin_lock_irqsave(pll->lock, flags); - - old_base = 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) | - (divp << pll->divp_shift)); - if (val == old_base) { - if (pll->lock) - spin_unlock_irqrestore(pll->lock, flags); - return 0; - } + int state, ret = 0; state = clk_pll_is_enabled(hw); - if (state) { - _clk_pll_disable(hw); - val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); - } - pll_writel_base(val, pll); - - if (pll->flags & TEGRA_PLL_HAS_CPCON) { - val = pll_readl_misc(pll); - val &= ~(PLL_MISC_CPCON_MASK << PLL_MISC_CPCON_SHIFT); - val |= cfg->cpcon << PLL_MISC_CPCON_SHIFT; - if (pll->flags & TEGRA_PLL_SET_LFCON) { - val &= ~(PLL_MISC_LFCON_MASK << PLL_MISC_LFCON_SHIFT); - if (cfg->n >= PLLDU_LFCON_SET_DIVN) - val |= 0x1 << PLL_MISC_LFCON_SHIFT; - } else if (pll->flags & TEGRA_PLL_SET_DCCON) { - val &= ~(0x1 << PLL_MISC_DCCON_SHIFT); - if (rate >= (pll->params->vco_max >> 1)) - val |= 0x1 << PLL_MISC_DCCON_SHIFT; - } - pll_writel_misc(val, pll); - } - - if (pll->lock) - spin_unlock_irqrestore(pll->lock, flags); - if (state) - clk_pll_enable(hw); + _clk_pll_disable(hw); - return 0; + _update_pll_mnp(pll, cfg); + + if (pll->flags & TEGRA_PLL_HAS_CPCON) + _update_pll_cpcon(pll, cfg, rate); + + if (state) { + _clk_pll_enable(hw); + ret = clk_pll_wait_for_lock(pll); + } + + return ret; } static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct tegra_clk_pll *pll = to_clk_pll(hw); - struct tegra_clk_pll_freq_table cfg; + struct tegra_clk_pll_freq_table cfg, old_cfg; + unsigned long flags = 0; + int ret = 0; if (pll->flags & TEGRA_PLL_FIXED) { if (rate != pll->fixed_rate) { @@ -387,7 +411,18 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, _calc_rate(hw, &cfg, rate, parent_rate)) return -EINVAL; - return _program_pll(hw, &cfg, rate); + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _get_pll_mnp(pll, &old_cfg); + + 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); + + return ret; } static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, @@ -409,7 +444,7 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, return -EINVAL; output_rate *= cfg.n; - do_div(output_rate, cfg.m * cfg.p); + do_div(output_rate, cfg.m * (1 << cfg.p)); return output_rate; } @@ -418,10 +453,12 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct tegra_clk_pll *pll = to_clk_pll(hw); - u32 val = pll_readl_base(pll); - u32 divn = 0, divm = 0, divp = 0; + struct tegra_clk_pll_freq_table cfg; + u32 val; u64 rate = parent_rate; + val = pll_readl_base(pll); + if (val & PLL_BASE_BYPASS) return parent_rate; @@ -435,16 +472,16 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, return pll->fixed_rate; } - divp = (val >> pll->divp_shift) & (divp_mask(pll)); + _get_pll_mnp(pll, &cfg); + if (pll->flags & TEGRA_PLLU) - divp ^= 1; + cfg.p ^= 1; - divn = (val >> pll->divn_shift) & (divn_mask(pll)); - divm = (val >> pll->divm_shift) & (divm_mask(pll)); - divm *= (1 << divp); + cfg.m *= 1 << cfg.p; + + rate *= cfg.n; + do_div(rate, cfg.m); - rate *= divn; - do_div(rate, divm); return rate; } @@ -538,8 +575,8 @@ static int clk_plle_enable(struct clk_hw *hw) val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE); pll_writel_base(val, pll); - clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->misc_reg, - pll->params->lock_bit_idx); + clk_pll_wait_for_lock(pll); + return 0; } @@ -577,28 +614,17 @@ const struct clk_ops tegra_clk_plle_ops = { .enable = clk_plle_enable, }; -static struct clk *_tegra_clk_register_pll(const char *name, - const char *parent_name, void __iomem *clk_base, - void __iomem *pmc, unsigned long flags, - unsigned long fixed_rate, - struct tegra_clk_pll_params *pll_params, u8 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock, - const struct clk_ops *ops) +static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base, + void __iomem *pmc, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) { struct tegra_clk_pll *pll; - struct clk *clk; - struct clk_init_data init; pll = kzalloc(sizeof(*pll), GFP_KERNEL); if (!pll) return ERR_PTR(-ENOMEM); - init.name = name; - init.ops = ops; - init.flags = flags; - init.parent_names = (parent_name ? &parent_name : NULL); - init.num_parents = (parent_name ? 1 : 0); - pll->clk_base = clk_base; pll->pmc = pmc; @@ -615,34 +641,68 @@ static struct clk *_tegra_clk_register_pll(const char *name, pll->divm_shift = PLL_BASE_DIVM_SHIFT; pll->divm_width = PLL_BASE_DIVM_WIDTH; + return pll; +} + +static struct clk *_tegra_clk_register_pll(struct tegra_clk_pll *pll, + const char *name, const char *parent_name, unsigned long flags, + const struct clk_ops *ops) +{ + struct clk_init_data init; + + init.name = name; + init.ops = ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + /* Data in .init is copied by clk_register(), so stack variable OK */ pll->hw.init = &init; - clk = clk_register(NULL, &pll->hw); + return clk_register(NULL, &pll->hw); +} + +struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) +{ + struct tegra_clk_pll *pll; + struct clk *clk; + + pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, + freq_table, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_pll_ops); if (IS_ERR(clk)) kfree(pll); return clk; } -struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, - void __iomem *clk_base, void __iomem *pmc, - unsigned long flags, unsigned long fixed_rate, - struct tegra_clk_pll_params *pll_params, u8 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) -{ - return _tegra_clk_register_pll(name, parent_name, clk_base, pmc, - flags, fixed_rate, pll_params, pll_flags, freq_table, - lock, &tegra_clk_pll_ops); -} - struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, unsigned long flags, unsigned long fixed_rate, - struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_params *pll_params, u32 pll_flags, struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) { - return _tegra_clk_register_pll(name, parent_name, clk_base, pmc, - flags, fixed_rate, pll_params, pll_flags, freq_table, - lock, &tegra_clk_plle_ops); + struct tegra_clk_pll *pll; + struct clk *clk; + pll_flags |= TEGRA_PLL_LOCK_MISC; + + pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, + freq_table, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_plle_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; } diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index a15fb28197b5..c2a1c4cae47c 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -248,125 +248,125 @@ static struct clk *clks[clk_max]; static struct clk_onecell_data clk_data; static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { - { 12000000, 600000000, 600, 12, 1, 8 }, - { 13000000, 600000000, 600, 13, 1, 8 }, - { 19200000, 600000000, 500, 16, 1, 6 }, - { 26000000, 600000000, 600, 26, 1, 8 }, + { 12000000, 600000000, 600, 12, 0, 8 }, + { 13000000, 600000000, 600, 13, 0, 8 }, + { 19200000, 600000000, 500, 16, 0, 6 }, + { 26000000, 600000000, 600, 26, 0, 8 }, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_m_freq_table[] = { - { 12000000, 666000000, 666, 12, 1, 8}, - { 13000000, 666000000, 666, 13, 1, 8}, - { 19200000, 666000000, 555, 16, 1, 8}, - { 26000000, 666000000, 666, 26, 1, 8}, - { 12000000, 600000000, 600, 12, 1, 8}, - { 13000000, 600000000, 600, 13, 1, 8}, - { 19200000, 600000000, 375, 12, 1, 6}, - { 26000000, 600000000, 600, 26, 1, 8}, + { 12000000, 666000000, 666, 12, 0, 8}, + { 13000000, 666000000, 666, 13, 0, 8}, + { 19200000, 666000000, 555, 16, 0, 8}, + { 26000000, 666000000, 666, 26, 0, 8}, + { 12000000, 600000000, 600, 12, 0, 8}, + { 13000000, 600000000, 600, 13, 0, 8}, + { 19200000, 600000000, 375, 12, 0, 6}, + { 26000000, 600000000, 600, 26, 0, 8}, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { - { 12000000, 216000000, 432, 12, 2, 8}, - { 13000000, 216000000, 432, 13, 2, 8}, - { 19200000, 216000000, 90, 4, 2, 1}, - { 26000000, 216000000, 432, 26, 2, 8}, - { 12000000, 432000000, 432, 12, 1, 8}, - { 13000000, 432000000, 432, 13, 1, 8}, - { 19200000, 432000000, 90, 4, 1, 1}, - { 26000000, 432000000, 432, 26, 1, 8}, + { 12000000, 216000000, 432, 12, 1, 8}, + { 13000000, 216000000, 432, 13, 1, 8}, + { 19200000, 216000000, 90, 4, 1, 1}, + { 26000000, 216000000, 432, 26, 1, 8}, + { 12000000, 432000000, 432, 12, 0, 8}, + { 13000000, 432000000, 432, 13, 0, 8}, + { 19200000, 432000000, 90, 4, 0, 1}, + { 26000000, 432000000, 432, 26, 0, 8}, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { - { 28800000, 56448000, 49, 25, 1, 1}, - { 28800000, 73728000, 64, 25, 1, 1}, - { 28800000, 24000000, 5, 6, 1, 1}, + { 28800000, 56448000, 49, 25, 0, 1}, + { 28800000, 73728000, 64, 25, 0, 1}, + { 28800000, 24000000, 5, 6, 0, 1}, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { - { 12000000, 216000000, 216, 12, 1, 4}, - { 13000000, 216000000, 216, 13, 1, 4}, - { 19200000, 216000000, 135, 12, 1, 3}, - { 26000000, 216000000, 216, 26, 1, 4}, + { 12000000, 216000000, 216, 12, 0, 4}, + { 13000000, 216000000, 216, 13, 0, 4}, + { 19200000, 216000000, 135, 12, 0, 3}, + { 26000000, 216000000, 216, 26, 0, 4}, - { 12000000, 594000000, 594, 12, 1, 8}, - { 13000000, 594000000, 594, 13, 1, 8}, - { 19200000, 594000000, 495, 16, 1, 8}, - { 26000000, 594000000, 594, 26, 1, 8}, + { 12000000, 594000000, 594, 12, 0, 8}, + { 13000000, 594000000, 594, 13, 0, 8}, + { 19200000, 594000000, 495, 16, 0, 8}, + { 26000000, 594000000, 594, 26, 0, 8}, - { 12000000, 1000000000, 1000, 12, 1, 12}, - { 13000000, 1000000000, 1000, 13, 1, 12}, - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 12}, + { 12000000, 1000000000, 1000, 12, 0, 12}, + { 13000000, 1000000000, 1000, 13, 0, 12}, + { 19200000, 1000000000, 625, 12, 0, 8}, + { 26000000, 1000000000, 1000, 26, 0, 12}, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { - { 12000000, 480000000, 960, 12, 2, 0}, - { 13000000, 480000000, 960, 13, 2, 0}, - { 19200000, 480000000, 200, 4, 2, 0}, - { 26000000, 480000000, 960, 26, 2, 0}, + { 12000000, 480000000, 960, 12, 0, 0}, + { 13000000, 480000000, 960, 13, 0, 0}, + { 19200000, 480000000, 200, 4, 0, 0}, + { 26000000, 480000000, 960, 26, 0, 0}, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { /* 1 GHz */ - { 12000000, 1000000000, 1000, 12, 1, 12}, - { 13000000, 1000000000, 1000, 13, 1, 12}, - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 12}, + { 12000000, 1000000000, 1000, 12, 0, 12}, + { 13000000, 1000000000, 1000, 13, 0, 12}, + { 19200000, 1000000000, 625, 12, 0, 8}, + { 26000000, 1000000000, 1000, 26, 0, 12}, /* 912 MHz */ - { 12000000, 912000000, 912, 12, 1, 12}, - { 13000000, 912000000, 912, 13, 1, 12}, - { 19200000, 912000000, 760, 16, 1, 8}, - { 26000000, 912000000, 912, 26, 1, 12}, + { 12000000, 912000000, 912, 12, 0, 12}, + { 13000000, 912000000, 912, 13, 0, 12}, + { 19200000, 912000000, 760, 16, 0, 8}, + { 26000000, 912000000, 912, 26, 0, 12}, /* 816 MHz */ - { 12000000, 816000000, 816, 12, 1, 12}, - { 13000000, 816000000, 816, 13, 1, 12}, - { 19200000, 816000000, 680, 16, 1, 8}, - { 26000000, 816000000, 816, 26, 1, 12}, + { 12000000, 816000000, 816, 12, 0, 12}, + { 13000000, 816000000, 816, 13, 0, 12}, + { 19200000, 816000000, 680, 16, 0, 8}, + { 26000000, 816000000, 816, 26, 0, 12}, /* 760 MHz */ - { 12000000, 760000000, 760, 12, 1, 12}, - { 13000000, 760000000, 760, 13, 1, 12}, - { 19200000, 760000000, 950, 24, 1, 8}, - { 26000000, 760000000, 760, 26, 1, 12}, + { 12000000, 760000000, 760, 12, 0, 12}, + { 13000000, 760000000, 760, 13, 0, 12}, + { 19200000, 760000000, 950, 24, 0, 8}, + { 26000000, 760000000, 760, 26, 0, 12}, /* 750 MHz */ - { 12000000, 750000000, 750, 12, 1, 12}, - { 13000000, 750000000, 750, 13, 1, 12}, - { 19200000, 750000000, 625, 16, 1, 8}, - { 26000000, 750000000, 750, 26, 1, 12}, + { 12000000, 750000000, 750, 12, 0, 12}, + { 13000000, 750000000, 750, 13, 0, 12}, + { 19200000, 750000000, 625, 16, 0, 8}, + { 26000000, 750000000, 750, 26, 0, 12}, /* 608 MHz */ - { 12000000, 608000000, 608, 12, 1, 12}, - { 13000000, 608000000, 608, 13, 1, 12}, - { 19200000, 608000000, 380, 12, 1, 8}, - { 26000000, 608000000, 608, 26, 1, 12}, + { 12000000, 608000000, 608, 12, 0, 12}, + { 13000000, 608000000, 608, 13, 0, 12}, + { 19200000, 608000000, 380, 12, 0, 8}, + { 26000000, 608000000, 608, 26, 0, 12}, /* 456 MHz */ - { 12000000, 456000000, 456, 12, 1, 12}, - { 13000000, 456000000, 456, 13, 1, 12}, - { 19200000, 456000000, 380, 16, 1, 8}, - { 26000000, 456000000, 456, 26, 1, 12}, + { 12000000, 456000000, 456, 12, 0, 12}, + { 13000000, 456000000, 456, 13, 0, 12}, + { 19200000, 456000000, 380, 16, 0, 8}, + { 26000000, 456000000, 456, 26, 0, 12}, /* 312 MHz */ - { 12000000, 312000000, 312, 12, 1, 12}, - { 13000000, 312000000, 312, 13, 1, 12}, - { 19200000, 312000000, 260, 16, 1, 8}, - { 26000000, 312000000, 312, 26, 1, 12}, + { 12000000, 312000000, 312, 12, 0, 12}, + { 13000000, 312000000, 312, 13, 0, 12}, + { 19200000, 312000000, 260, 16, 0, 8}, + { 26000000, 312000000, 312, 26, 0, 12}, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { - { 12000000, 100000000, 200, 24, 1, 0 }, + { 12000000, 100000000, 200, 24, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, }; diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index e0ee93c2db6c..02609d125e0e 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -374,164 +374,164 @@ static const struct utmi_clk_param utmi_parameters[] = { }; static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { - { 12000000, 1040000000, 520, 6, 1, 8}, - { 13000000, 1040000000, 480, 6, 1, 8}, - { 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */ - { 19200000, 1040000000, 325, 6, 1, 6}, - { 26000000, 1040000000, 520, 13, 1, 8}, + { 12000000, 1040000000, 520, 6, 0, 8}, + { 13000000, 1040000000, 480, 6, 0, 8}, + { 16800000, 1040000000, 495, 8, 0, 8}, /* actual: 1039.5 MHz */ + { 19200000, 1040000000, 325, 6, 0, 6}, + { 26000000, 1040000000, 520, 13, 0, 8}, - { 12000000, 832000000, 416, 6, 1, 8}, - { 13000000, 832000000, 832, 13, 1, 8}, - { 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */ - { 19200000, 832000000, 260, 6, 1, 8}, - { 26000000, 832000000, 416, 13, 1, 8}, + { 12000000, 832000000, 416, 6, 0, 8}, + { 13000000, 832000000, 832, 13, 0, 8}, + { 16800000, 832000000, 396, 8, 0, 8}, /* actual: 831.6 MHz */ + { 19200000, 832000000, 260, 6, 0, 8}, + { 26000000, 832000000, 416, 13, 0, 8}, - { 12000000, 624000000, 624, 12, 1, 8}, - { 13000000, 624000000, 624, 13, 1, 8}, - { 16800000, 600000000, 520, 14, 1, 8}, - { 19200000, 624000000, 520, 16, 1, 8}, - { 26000000, 624000000, 624, 26, 1, 8}, + { 12000000, 624000000, 624, 12, 0, 8}, + { 13000000, 624000000, 624, 13, 0, 8}, + { 16800000, 600000000, 520, 14, 0, 8}, + { 19200000, 624000000, 520, 16, 0, 8}, + { 26000000, 624000000, 624, 26, 0, 8}, - { 12000000, 600000000, 600, 12, 1, 8}, - { 13000000, 600000000, 600, 13, 1, 8}, - { 16800000, 600000000, 500, 14, 1, 8}, - { 19200000, 600000000, 375, 12, 1, 6}, - { 26000000, 600000000, 600, 26, 1, 8}, + { 12000000, 600000000, 600, 12, 0, 8}, + { 13000000, 600000000, 600, 13, 0, 8}, + { 16800000, 600000000, 500, 14, 0, 8}, + { 19200000, 600000000, 375, 12, 0, 6}, + { 26000000, 600000000, 600, 26, 0, 8}, - { 12000000, 520000000, 520, 12, 1, 8}, - { 13000000, 520000000, 520, 13, 1, 8}, - { 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */ - { 19200000, 520000000, 325, 12, 1, 6}, - { 26000000, 520000000, 520, 26, 1, 8}, + { 12000000, 520000000, 520, 12, 0, 8}, + { 13000000, 520000000, 520, 13, 0, 8}, + { 16800000, 520000000, 495, 16, 0, 8}, /* actual: 519.75 MHz */ + { 19200000, 520000000, 325, 12, 0, 6}, + { 26000000, 520000000, 520, 26, 0, 8}, - { 12000000, 416000000, 416, 12, 1, 8}, - { 13000000, 416000000, 416, 13, 1, 8}, - { 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */ - { 19200000, 416000000, 260, 12, 1, 6}, - { 26000000, 416000000, 416, 26, 1, 8}, + { 12000000, 416000000, 416, 12, 0, 8}, + { 13000000, 416000000, 416, 13, 0, 8}, + { 16800000, 416000000, 396, 16, 0, 8}, /* actual: 415.8 MHz */ + { 19200000, 416000000, 260, 12, 0, 6}, + { 26000000, 416000000, 416, 26, 0, 8}, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_m_freq_table[] = { - { 12000000, 666000000, 666, 12, 1, 8}, - { 13000000, 666000000, 666, 13, 1, 8}, - { 16800000, 666000000, 555, 14, 1, 8}, - { 19200000, 666000000, 555, 16, 1, 8}, - { 26000000, 666000000, 666, 26, 1, 8}, - { 12000000, 600000000, 600, 12, 1, 8}, - { 13000000, 600000000, 600, 13, 1, 8}, - { 16800000, 600000000, 500, 14, 1, 8}, - { 19200000, 600000000, 375, 12, 1, 6}, - { 26000000, 600000000, 600, 26, 1, 8}, + { 12000000, 666000000, 666, 12, 0, 8}, + { 13000000, 666000000, 666, 13, 0, 8}, + { 16800000, 666000000, 555, 14, 0, 8}, + { 19200000, 666000000, 555, 16, 0, 8}, + { 26000000, 666000000, 666, 26, 0, 8}, + { 12000000, 600000000, 600, 12, 0, 8}, + { 13000000, 600000000, 600, 13, 0, 8}, + { 16800000, 600000000, 500, 14, 0, 8}, + { 19200000, 600000000, 375, 12, 0, 6}, + { 26000000, 600000000, 600, 26, 0, 8}, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { - { 12000000, 216000000, 432, 12, 2, 8}, - { 13000000, 216000000, 432, 13, 2, 8}, - { 16800000, 216000000, 360, 14, 2, 8}, - { 19200000, 216000000, 360, 16, 2, 8}, - { 26000000, 216000000, 432, 26, 2, 8}, + { 12000000, 216000000, 432, 12, 1, 8}, + { 13000000, 216000000, 432, 13, 1, 8}, + { 16800000, 216000000, 360, 14, 1, 8}, + { 19200000, 216000000, 360, 16, 1, 8}, + { 26000000, 216000000, 432, 26, 1, 8}, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { - { 9600000, 564480000, 294, 5, 1, 4}, - { 9600000, 552960000, 288, 5, 1, 4}, - { 9600000, 24000000, 5, 2, 1, 1}, + { 9600000, 564480000, 294, 5, 0, 4}, + { 9600000, 552960000, 288, 5, 0, 4}, + { 9600000, 24000000, 5, 2, 0, 1}, - { 28800000, 56448000, 49, 25, 1, 1}, - { 28800000, 73728000, 64, 25, 1, 1}, - { 28800000, 24000000, 5, 6, 1, 1}, + { 28800000, 56448000, 49, 25, 0, 1}, + { 28800000, 73728000, 64, 25, 0, 1}, + { 28800000, 24000000, 5, 6, 0, 1}, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { - { 12000000, 216000000, 216, 12, 1, 4}, - { 13000000, 216000000, 216, 13, 1, 4}, - { 16800000, 216000000, 180, 14, 1, 4}, - { 19200000, 216000000, 180, 16, 1, 4}, - { 26000000, 216000000, 216, 26, 1, 4}, + { 12000000, 216000000, 216, 12, 0, 4}, + { 13000000, 216000000, 216, 13, 0, 4}, + { 16800000, 216000000, 180, 14, 0, 4}, + { 19200000, 216000000, 180, 16, 0, 4}, + { 26000000, 216000000, 216, 26, 0, 4}, - { 12000000, 594000000, 594, 12, 1, 8}, - { 13000000, 594000000, 594, 13, 1, 8}, - { 16800000, 594000000, 495, 14, 1, 8}, - { 19200000, 594000000, 495, 16, 1, 8}, - { 26000000, 594000000, 594, 26, 1, 8}, + { 12000000, 594000000, 594, 12, 0, 8}, + { 13000000, 594000000, 594, 13, 0, 8}, + { 16800000, 594000000, 495, 14, 0, 8}, + { 19200000, 594000000, 495, 16, 0, 8}, + { 26000000, 594000000, 594, 26, 0, 8}, - { 12000000, 1000000000, 1000, 12, 1, 12}, - { 13000000, 1000000000, 1000, 13, 1, 12}, - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 12}, + { 12000000, 1000000000, 1000, 12, 0, 12}, + { 13000000, 1000000000, 1000, 13, 0, 12}, + { 19200000, 1000000000, 625, 12, 0, 8}, + { 26000000, 1000000000, 1000, 26, 0, 12}, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { - { 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}, + { 12000000, 480000000, 960, 12, 0, 12}, + { 13000000, 480000000, 960, 13, 0, 12}, + { 16800000, 480000000, 400, 7, 0, 5}, + { 19200000, 480000000, 200, 4, 0, 3}, + { 26000000, 480000000, 960, 26, 0, 12}, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { /* 1.7 GHz */ - { 12000000, 1700000000, 850, 6, 1, 8}, - { 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */ - { 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */ - { 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */ - { 26000000, 1700000000, 850, 13, 1, 8}, + { 12000000, 1700000000, 850, 6, 0, 8}, + { 13000000, 1700000000, 915, 7, 0, 8}, /* actual: 1699.2 MHz */ + { 16800000, 1700000000, 708, 7, 0, 8}, /* actual: 1699.2 MHz */ + { 19200000, 1700000000, 885, 10, 0, 8}, /* actual: 1699.2 MHz */ + { 26000000, 1700000000, 850, 13, 0, 8}, /* 1.6 GHz */ - { 12000000, 1600000000, 800, 6, 1, 8}, - { 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */ - { 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */ - { 19200000, 1600000000, 500, 6, 1, 8}, - { 26000000, 1600000000, 800, 13, 1, 8}, + { 12000000, 1600000000, 800, 6, 0, 8}, + { 13000000, 1600000000, 738, 6, 0, 8}, /* actual: 1599.0 MHz */ + { 16800000, 1600000000, 857, 9, 0, 8}, /* actual: 1599.7 MHz */ + { 19200000, 1600000000, 500, 6, 0, 8}, + { 26000000, 1600000000, 800, 13, 0, 8}, /* 1.5 GHz */ - { 12000000, 1500000000, 750, 6, 1, 8}, - { 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */ - { 16800000, 1500000000, 625, 7, 1, 8}, - { 19200000, 1500000000, 625, 8, 1, 8}, - { 26000000, 1500000000, 750, 13, 1, 8}, + { 12000000, 1500000000, 750, 6, 0, 8}, + { 13000000, 1500000000, 923, 8, 0, 8}, /* actual: 1499.8 MHz */ + { 16800000, 1500000000, 625, 7, 0, 8}, + { 19200000, 1500000000, 625, 8, 0, 8}, + { 26000000, 1500000000, 750, 13, 0, 8}, /* 1.4 GHz */ - { 12000000, 1400000000, 700, 6, 1, 8}, - { 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */ - { 16800000, 1400000000, 1000, 12, 1, 8}, - { 19200000, 1400000000, 875, 12, 1, 8}, - { 26000000, 1400000000, 700, 13, 1, 8}, + { 12000000, 1400000000, 700, 6, 0, 8}, + { 13000000, 1400000000, 969, 9, 0, 8}, /* actual: 1399.7 MHz */ + { 16800000, 1400000000, 1000, 12, 0, 8}, + { 19200000, 1400000000, 875, 12, 0, 8}, + { 26000000, 1400000000, 700, 13, 0, 8}, /* 1.3 GHz */ - { 12000000, 1300000000, 975, 9, 1, 8}, - { 13000000, 1300000000, 1000, 10, 1, 8}, - { 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */ - { 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */ - { 26000000, 1300000000, 650, 13, 1, 8}, + { 12000000, 1300000000, 975, 9, 0, 8}, + { 13000000, 1300000000, 1000, 10, 0, 8}, + { 16800000, 1300000000, 928, 12, 0, 8}, /* actual: 1299.2 MHz */ + { 19200000, 1300000000, 812, 12, 0, 8}, /* actual: 1299.2 MHz */ + { 26000000, 1300000000, 650, 13, 0, 8}, /* 1.2 GHz */ - { 12000000, 1200000000, 1000, 10, 1, 8}, - { 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */ - { 16800000, 1200000000, 1000, 14, 1, 8}, - { 19200000, 1200000000, 1000, 16, 1, 8}, - { 26000000, 1200000000, 600, 13, 1, 8}, + { 12000000, 1200000000, 1000, 10, 0, 8}, + { 13000000, 1200000000, 923, 10, 0, 8}, /* actual: 1199.9 MHz */ + { 16800000, 1200000000, 1000, 14, 0, 8}, + { 19200000, 1200000000, 1000, 16, 0, 8}, + { 26000000, 1200000000, 600, 13, 0, 8}, /* 1.1 GHz */ - { 12000000, 1100000000, 825, 9, 1, 8}, - { 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */ - { 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */ - { 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */ - { 26000000, 1100000000, 550, 13, 1, 8}, + { 12000000, 1100000000, 825, 9, 0, 8}, + { 13000000, 1100000000, 846, 10, 0, 8}, /* actual: 1099.8 MHz */ + { 16800000, 1100000000, 982, 15, 0, 8}, /* actual: 1099.8 MHz */ + { 19200000, 1100000000, 859, 15, 0, 8}, /* actual: 1099.5 MHz */ + { 26000000, 1100000000, 550, 13, 0, 8}, /* 1 GHz */ - { 12000000, 1000000000, 1000, 12, 1, 8}, - { 13000000, 1000000000, 1000, 13, 1, 8}, - { 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */ - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 8}, + { 12000000, 1000000000, 1000, 12, 0, 8}, + { 13000000, 1000000000, 1000, 13, 0, 8}, + { 16800000, 1000000000, 833, 14, 0, 8}, /* actual: 999.6 MHz */ + { 19200000, 1000000000, 625, 12, 0, 8}, + { 26000000, 1000000000, 1000, 26, 0, 8}, { 0, 0, 0, 0, 0, 0 }, }; diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 3c566e2d518a..b9691ddcbd9b 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -182,12 +182,14 @@ struct tegra_clk_pll_params { * TEGRA_PLL_FIXED - We are not supposed to change output frequency * of some plls. * TEGRA_PLLE_CONFIGURE - Configure PLLE when enabling. + * TEGRA_PLL_LOCK_MISC - Lock bit is in the misc register instead of the + * base register. */ struct tegra_clk_pll { struct clk_hw hw; void __iomem *clk_base; void __iomem *pmc; - u8 flags; + u32 flags; unsigned long fixed_rate; spinlock_t *lock; u8 divn_shift; @@ -210,18 +212,19 @@ struct tegra_clk_pll { #define TEGRA_PLLM BIT(5) #define TEGRA_PLL_FIXED BIT(6) #define TEGRA_PLLE_CONFIGURE BIT(7) +#define TEGRA_PLL_LOCK_MISC BIT(8) extern const struct clk_ops tegra_clk_pll_ops; extern const struct clk_ops tegra_clk_plle_ops; struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, unsigned long flags, unsigned long fixed_rate, - struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_params *pll_params, u32 pll_flags, struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, unsigned long flags, unsigned long fixed_rate, - struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_params *pll_params, u32 pll_flags, struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); /** From dd93587be8dc8acf23a0d8a23efc74a91d8f0dfe Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 3 Apr 2013 17:40:37 +0300 Subject: [PATCH 08/20] clk: tegra: Add TEGRA_PLL_BYPASS flag Not all PLLs in Tegra114 have a bypass bit. Adapt the common code to only use this bit when available. Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-pll.c | 12 ++++++++---- drivers/clk/tegra/clk.h | 2 ++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 3feefb15e473..4ee6d03bc575 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -171,7 +171,8 @@ static void _clk_pll_enable(struct clk_hw *hw) clk_pll_enable_lock(pll); val = pll_readl_base(pll); - val &= ~PLL_BASE_BYPASS; + if (pll->flags & TEGRA_PLL_BYPASS) + val &= ~PLL_BASE_BYPASS; val |= PLL_BASE_ENABLE; pll_writel_base(val, pll); @@ -188,7 +189,9 @@ static void _clk_pll_disable(struct clk_hw *hw) u32 val; val = pll_readl_base(pll); - val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); + if (pll->flags & TEGRA_PLL_BYPASS) + val &= ~PLL_BASE_BYPASS; + val &= ~PLL_BASE_ENABLE; pll_writel_base(val, pll); if (pll->flags & TEGRA_PLLM) { @@ -459,7 +462,7 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, val = pll_readl_base(pll); - if (val & PLL_BASE_BYPASS) + if ((pll->flags & TEGRA_PLL_BYPASS) && (val & PLL_BASE_BYPASS)) return parent_rate; if ((pll->flags & TEGRA_PLL_FIXED) && !(val & PLL_BASE_OVERRIDE)) { @@ -671,6 +674,7 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, struct tegra_clk_pll *pll; struct clk *clk; + pll_flags |= TEGRA_PLL_BYPASS; pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, freq_table, lock); if (IS_ERR(pll)) @@ -692,8 +696,8 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, { struct tegra_clk_pll *pll; struct clk *clk; - pll_flags |= TEGRA_PLL_LOCK_MISC; + pll_flags |= TEGRA_PLL_LOCK_MISC | TEGRA_PLL_BYPASS; 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.h b/drivers/clk/tegra/clk.h index b9691ddcbd9b..fff520ae72fc 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -184,6 +184,7 @@ struct tegra_clk_pll_params { * TEGRA_PLLE_CONFIGURE - Configure PLLE when enabling. * TEGRA_PLL_LOCK_MISC - Lock bit is in the misc register instead of the * base register. + * TEGRA_PLL_BYPASS - PLL has bypass bit */ struct tegra_clk_pll { struct clk_hw hw; @@ -213,6 +214,7 @@ struct tegra_clk_pll { #define TEGRA_PLL_FIXED BIT(6) #define TEGRA_PLLE_CONFIGURE BIT(7) #define TEGRA_PLL_LOCK_MISC BIT(8) +#define TEGRA_PLL_BYPASS BIT(9) extern const struct clk_ops tegra_clk_pll_ops; extern const struct clk_ops tegra_clk_plle_ops; From 7ba28813b41120dd67329fd04dc732ea7fef05a0 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 3 Apr 2013 17:40:38 +0300 Subject: [PATCH 09/20] clk: tegra: introduce TEGRA_PLL_HAS_LOCK_ENABLE Tegra114 PLLC2 and PLLC3 don't have a lock enable bit. The lock bits are always functional. Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-pll.c | 5 +++++ drivers/clk/tegra/clk.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 4ee6d03bc575..eaab060cda24 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -108,6 +108,9 @@ static void clk_pll_enable_lock(struct tegra_clk_pll *pll) if (!(pll->flags & TEGRA_PLL_USE_LOCK)) return; + if (!(pll->flags & TEGRA_PLL_HAS_LOCK_ENABLE)) + return; + val = pll_readl_misc(pll); val |= BIT(pll->params->lock_enable_bit_idx); pll_writel_misc(val, pll); @@ -675,6 +678,7 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, struct clk *clk; pll_flags |= TEGRA_PLL_BYPASS; + pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, freq_table, lock); if (IS_ERR(pll)) @@ -698,6 +702,7 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, struct clk *clk; pll_flags |= TEGRA_PLL_LOCK_MISC | TEGRA_PLL_BYPASS; + pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; 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.h b/drivers/clk/tegra/clk.h index fff520ae72fc..17ddb22f7a50 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -185,6 +185,7 @@ struct tegra_clk_pll_params { * TEGRA_PLL_LOCK_MISC - Lock bit is in the misc register instead of the * base register. * TEGRA_PLL_BYPASS - PLL has bypass bit + * TEGRA_PLL_HAS_LOCK_ENABLE - PLL has bit to enable lock monitoring */ struct tegra_clk_pll { struct clk_hw hw; @@ -215,6 +216,7 @@ struct tegra_clk_pll { #define TEGRA_PLLE_CONFIGURE BIT(7) #define TEGRA_PLL_LOCK_MISC BIT(8) #define TEGRA_PLL_BYPASS BIT(9) +#define TEGRA_PLL_HAS_LOCK_ENABLE BIT(10) extern const struct clk_ops tegra_clk_pll_ops; extern const struct clk_ops tegra_clk_plle_ops; From 0b6525acd13f2d33cd3be86d0dbd2ddd1ffeda8f Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 3 Apr 2013 17:40:39 +0300 Subject: [PATCH 10/20] clk: tegra: Add PLL post divider table Some PLLs in Tegra114 don't use a power of 2 mapping for the post divider. Introduce a table based approach and switch PLLU to it. Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-pll.c | 38 +++++++++++++++++++++++++++------ drivers/clk/tegra/clk-tegra20.c | 7 ++++++ drivers/clk/tegra/clk-tegra30.c | 7 ++++++ drivers/clk/tegra/clk.h | 13 +++++++++++ 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index eaab060cda24..ccb367ee7e78 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -266,6 +266,7 @@ 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; @@ -299,7 +300,6 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, cfg->output_rate <<= 1) p_div++; - cfg->p = p_div; cfg->m = parent_rate / cfreq; cfg->n = cfg->output_rate / cfreq; cfg->cpcon = OUT_OF_TABLE_CPCON; @@ -312,8 +312,19 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, return -EINVAL; } - if (pll->flags & TEGRA_PLLU) - cfg->p ^= 1; + 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; + } else + cfg->p = p_div; return 0; } @@ -460,8 +471,10 @@ 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; val = pll_readl_base(pll); @@ -480,10 +493,23 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, _get_pll_mnp(pll, &cfg); - if (pll->flags & TEGRA_PLLU) - cfg.p ^= 1; + if (p_tohw) { + while (p_tohw->pdiv) { + if (cfg.p == p_tohw->hw_val) { + pdiv = p_tohw->pdiv; + break; + } + p_tohw++; + } - cfg.m *= 1 << cfg.p; + if (!p_tohw->pdiv) { + WARN_ON(1); + pdiv = 1; + } + } else + pdiv = 1 << cfg.p; + + cfg.m *= pdiv; rate *= cfg.n; do_div(rate, cfg.m); diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index c2a1c4cae47c..f215bf10c9ff 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -441,6 +441,12 @@ static struct tegra_clk_pll_params pll_d_params = { .lock_delay = 1000, }; +static struct pdiv_map pllu_p[] = { + { .pdiv = 1, .hw_val = 1 }, + { .pdiv = 2, .hw_val = 0 }, + { .pdiv = 0, .hw_val = 0 }, +}; + static struct tegra_clk_pll_params pll_u_params = { .input_min = 2000000, .input_max = 40000000, @@ -453,6 +459,7 @@ static struct tegra_clk_pll_params pll_u_params = { .lock_bit_idx = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, + .pdiv_tohw = pllu_p, }; static struct tegra_clk_pll_params pll_x_params = { diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 02609d125e0e..fe768fe769b2 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -467,6 +467,12 @@ static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { { 0, 0, 0, 0, 0, 0 }, }; +static struct pdiv_map pllu_p[] = { + { .pdiv = 1, .hw_val = 1 }, + { .pdiv = 2, .hw_val = 0 }, + { .pdiv = 0, .hw_val = 0 }, +}; + static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { { 12000000, 480000000, 960, 12, 0, 12}, { 13000000, 480000000, 960, 13, 0, 12}, @@ -640,6 +646,7 @@ static struct tegra_clk_pll_params pll_u_params = { .lock_bit_idx = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, + .pdiv_tohw = pllu_p, }; static struct tegra_clk_pll_params pll_x_params = { diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 17ddb22f7a50..925da451bd19 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -116,6 +116,17 @@ struct tegra_clk_pll_freq_table { u8 cpcon; }; +/** + * struct pdiv_map - map post divider to hw value + * + * @pdiv: post divider + * @hw_val: value to be written to the PLL hw + */ +struct pdiv_map { + u8 pdiv; + u8 hw_val; +}; + /** * struct clk_pll_params - PLL parameters * @@ -146,6 +157,8 @@ struct tegra_clk_pll_params { u32 lock_bit_idx; u32 lock_enable_bit_idx; int lock_delay; + int max_p; + struct pdiv_map *pdiv_tohw; }; /** From 3e72771e210348fbd7ff0ea1b9e14cd88380c05b Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 3 Apr 2013 17:40:40 +0300 Subject: [PATCH 11/20] clk: tegra: move from a lock bit idx to a lock mask PLLC2 and PLLC3 on Tegra114 have separate phaselock and frequencylock bits. So switch to a lock mask to be able to test both at the same time. Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-pll.c | 6 +++--- drivers/clk/tegra/clk-tegra20.c | 20 ++++++++++---------- drivers/clk/tegra/clk-tegra30.c | 22 +++++++++++----------- drivers/clk/tegra/clk.h | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index ccb367ee7e78..0b963522479b 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -119,7 +119,7 @@ static void clk_pll_enable_lock(struct tegra_clk_pll *pll) static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll) { int i; - u32 val, lock_bit; + u32 val, lock_mask; void __iomem *lock_addr; if (!(pll->flags & TEGRA_PLL_USE_LOCK)) { @@ -133,11 +133,11 @@ static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll) else lock_addr += pll->params->base_reg; - lock_bit = BIT(pll->params->lock_bit_idx); + lock_mask = pll->params->lock_mask; for (i = 0; i < pll->params->lock_delay; i++) { val = readl_relaxed(lock_addr); - if (val & lock_bit) { + if ((val & lock_mask) == lock_mask) { udelay(PLL_POST_LOCK_DELAY); return 0; } diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index f215bf10c9ff..5c7b58b96911 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -86,8 +86,8 @@ #define PLLE_BASE 0xe8 #define PLLE_MISC 0xec -#define PLL_BASE_LOCK 27 -#define PLLE_MISC_LOCK 11 +#define PLL_BASE_LOCK BIT(27) +#define PLLE_MISC_LOCK BIT(11) #define PLL_MISC_LOCK_ENABLE 18 #define PLLDU_MISC_LOCK_ENABLE 22 @@ -380,7 +380,7 @@ static struct tegra_clk_pll_params pll_c_params = { .vco_max = 1400000000, .base_reg = PLLC_BASE, .misc_reg = PLLC_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -394,7 +394,7 @@ static struct tegra_clk_pll_params pll_m_params = { .vco_max = 1200000000, .base_reg = PLLM_BASE, .misc_reg = PLLM_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -408,7 +408,7 @@ static struct tegra_clk_pll_params pll_p_params = { .vco_max = 1400000000, .base_reg = PLLP_BASE, .misc_reg = PLLP_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -422,7 +422,7 @@ static struct tegra_clk_pll_params pll_a_params = { .vco_max = 1400000000, .base_reg = PLLA_BASE, .misc_reg = PLLA_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -436,7 +436,7 @@ static struct tegra_clk_pll_params pll_d_params = { .vco_max = 1000000000, .base_reg = PLLD_BASE, .misc_reg = PLLD_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, }; @@ -456,7 +456,7 @@ static struct tegra_clk_pll_params pll_u_params = { .vco_max = 960000000, .base_reg = PLLU_BASE, .misc_reg = PLLU_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, .pdiv_tohw = pllu_p, @@ -471,7 +471,7 @@ static struct tegra_clk_pll_params pll_x_params = { .vco_max = 1200000000, .base_reg = PLLX_BASE, .misc_reg = PLLX_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -485,7 +485,7 @@ static struct tegra_clk_pll_params pll_e_params = { .vco_max = 0, .base_reg = PLLE_BASE, .misc_reg = PLLE_MISC, - .lock_bit_idx = PLLE_MISC_LOCK, + .lock_mask = PLLE_MISC_LOCK, .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, .lock_delay = 0, }; diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index fe768fe769b2..735f964edc65 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -116,8 +116,8 @@ #define PLLDU_MISC_LOCK_ENABLE 22 #define PLLE_MISC_LOCK_ENABLE 9 -#define PLL_BASE_LOCK 27 -#define PLLE_MISC_LOCK 11 +#define PLL_BASE_LOCK BIT(27) +#define PLLE_MISC_LOCK BIT(11) #define PLLE_AUX 0x48c #define PLLC_OUT 0x84 @@ -559,7 +559,7 @@ static struct tegra_clk_pll_params pll_c_params = { .vco_max = 1400000000, .base_reg = PLLC_BASE, .misc_reg = PLLC_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -573,7 +573,7 @@ static struct tegra_clk_pll_params pll_m_params = { .vco_max = 1200000000, .base_reg = PLLM_BASE, .misc_reg = PLLM_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -587,7 +587,7 @@ static struct tegra_clk_pll_params pll_p_params = { .vco_max = 1400000000, .base_reg = PLLP_BASE, .misc_reg = PLLP_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -601,7 +601,7 @@ static struct tegra_clk_pll_params pll_a_params = { .vco_max = 1400000000, .base_reg = PLLA_BASE, .misc_reg = PLLA_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -615,7 +615,7 @@ static struct tegra_clk_pll_params pll_d_params = { .vco_max = 1000000000, .base_reg = PLLD_BASE, .misc_reg = PLLD_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, }; @@ -629,7 +629,7 @@ static struct tegra_clk_pll_params pll_d2_params = { .vco_max = 1000000000, .base_reg = PLLD2_BASE, .misc_reg = PLLD2_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, }; @@ -643,7 +643,7 @@ static struct tegra_clk_pll_params pll_u_params = { .vco_max = 960000000, .base_reg = PLLU_BASE, .misc_reg = PLLU_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, .pdiv_tohw = pllu_p, @@ -658,7 +658,7 @@ static struct tegra_clk_pll_params pll_x_params = { .vco_max = 1700000000, .base_reg = PLLX_BASE, .misc_reg = PLLX_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -672,7 +672,7 @@ static struct tegra_clk_pll_params pll_e_params = { .vco_max = 2400000000U, .base_reg = PLLE_BASE, .misc_reg = PLLE_MISC, - .lock_bit_idx = PLLE_MISC_LOCK, + .lock_mask = PLLE_MISC_LOCK, .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, .lock_delay = 300, }; diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 925da451bd19..3b498e0c8ae5 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -154,7 +154,7 @@ struct tegra_clk_pll_params { u32 base_reg; u32 misc_reg; u32 lock_reg; - u32 lock_bit_idx; + u32 lock_mask; u32 lock_enable_bit_idx; int lock_delay; int max_p; From c1d1939c5163088e5f12011c6b3a6a9fab40215f Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 3 Apr 2013 17:40:41 +0300 Subject: [PATCH 12/20] clk: tegra: Add new fields and PLL types for Tegra114 Tegra114 introduces new PLL types. This requires new clocktypes as well as some new fields in the pll structure. Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-pll.c | 839 ++++++++++++++++++++++++++++++++++++ drivers/clk/tegra/clk.h | 50 ++- 2 files changed, 888 insertions(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 0b963522479b..17c2cc086eb4 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -79,6 +79,48 @@ #define PLLE_SS_CTRL 0x68 #define PLLE_SS_DISABLE (7 << 10) +#define PLLE_AUX_PLLP_SEL BIT(2) +#define PLLE_AUX_ENABLE_SWCTL BIT(4) +#define PLLE_AUX_SEQ_ENABLE BIT(24) +#define PLLE_AUX_PLLRE_SEL BIT(28) + +#define PLLE_MISC_PLLE_PTS BIT(8) +#define PLLE_MISC_IDDQ_SW_VALUE BIT(13) +#define PLLE_MISC_IDDQ_SW_CTRL BIT(14) +#define PLLE_MISC_VREG_BG_CTRL_SHIFT 4 +#define PLLE_MISC_VREG_BG_CTRL_MASK (3 << PLLE_MISC_VREG_BG_CTRL_SHIFT) +#define PLLE_MISC_VREG_CTRL_SHIFT 2 +#define PLLE_MISC_VREG_CTRL_MASK (2 << PLLE_MISC_VREG_CTRL_SHIFT) + +#define PLLCX_MISC_STROBE BIT(31) +#define PLLCX_MISC_RESET BIT(30) +#define PLLCX_MISC_SDM_DIV_SHIFT 28 +#define PLLCX_MISC_SDM_DIV_MASK (0x3 << PLLCX_MISC_SDM_DIV_SHIFT) +#define PLLCX_MISC_FILT_DIV_SHIFT 26 +#define PLLCX_MISC_FILT_DIV_MASK (0x3 << PLLCX_MISC_FILT_DIV_SHIFT) +#define PLLCX_MISC_ALPHA_SHIFT 18 +#define PLLCX_MISC_DIV_LOW_RANGE \ + ((0x1 << PLLCX_MISC_SDM_DIV_SHIFT) | \ + (0x1 << PLLCX_MISC_FILT_DIV_SHIFT)) +#define PLLCX_MISC_DIV_HIGH_RANGE \ + ((0x2 << PLLCX_MISC_SDM_DIV_SHIFT) | \ + (0x2 << PLLCX_MISC_FILT_DIV_SHIFT)) +#define PLLCX_MISC_COEF_LOW_RANGE \ + ((0x14 << PLLCX_MISC_KA_SHIFT) | (0x38 << PLLCX_MISC_KB_SHIFT)) +#define PLLCX_MISC_KA_SHIFT 2 +#define PLLCX_MISC_KB_SHIFT 9 +#define PLLCX_MISC_DEFAULT (PLLCX_MISC_COEF_LOW_RANGE | \ + (0x19 << PLLCX_MISC_ALPHA_SHIFT) | \ + PLLCX_MISC_DIV_LOW_RANGE | \ + PLLCX_MISC_RESET) +#define PLLCX_MISC1_DEFAULT 0x000d2308 +#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) @@ -101,6 +143,24 @@ #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 +}; +#endif + static void clk_pll_enable_lock(struct tegra_clk_pll *pll) { u32 val; @@ -646,6 +706,520 @@ const struct clk_ops tegra_clk_plle_ops = { .enable = clk_plle_enable, }; +#ifdef CONFIG_ARCH_TEGRA_114_SOC + +static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params, + unsigned long parent_rate) +{ + if (parent_rate > pll_params->cf_max) + return 2; + else + return 1; +} + +static int clk_pll_iddq_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + + u32 val; + int ret; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + val = pll_readl(pll->params->iddq_reg, pll); + val &= ~BIT(pll->params->iddq_bit_idx); + pll_writel(val, pll->params->iddq_reg, pll); + udelay(2); + + _clk_pll_enable(hw); + + ret = clk_pll_wait_for_lock(pll); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return 0; +} + +static void clk_pll_iddq_disable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + u32 val; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _clk_pll_disable(hw); + + val = pll_readl(pll->params->iddq_reg, pll); + val |= BIT(pll->params->iddq_bit_idx); + pll_writel(val, pll->params->iddq_reg, pll); + udelay(2); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); +} + +static int _calc_dynamic_ramp_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); + unsigned int p; + + 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->n = cfg->output_rate * cfg->m / parent_rate; + + if (cfg->n > divn_max(pll) || cfg->output_rate > pll->params->vco_max) + return -EINVAL; + + return 0; +} + +static int _pll_ramp_calc_pll(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); + int err = 0; + + 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)) { + WARN_ON(1); + err = -EINVAL; + goto out; + } + + if (!cfg->p || (cfg->p > pll->params->max_p)) + err = -EINVAL; + +out: + return err; +} + +static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + 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) + return ret; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _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; + ret = _program_pll(hw, &cfg, rate); + } + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +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; + u64 output_rate = *prate; + + ret = _pll_ramp_calc_pll(hw, &cfg, rate, *prate); + if (ret < 0) + return ret; + + output_rate *= cfg.n; + do_div(output_rate, cfg.m * cfg.p); + + return output_rate; +} + +static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_clk_pll_freq_table cfg; + 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); + + state = clk_pll_is_enabled(hw); + if (state) { + if (rate != clk_get_rate(hw->clk)) { + pr_err("%s: Cannot change active PLLM\n", __func__); + ret = -EINVAL; + goto out; + } + goto out; + } + + ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_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); + + +out: + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +static void _pllcx_strobe(struct tegra_clk_pll *pll) +{ + u32 val; + + val = pll_readl_misc(pll); + val |= PLLCX_MISC_STROBE; + pll_writel_misc(val, pll); + udelay(2); + + val &= ~PLLCX_MISC_STROBE; + pll_writel_misc(val, pll); +} + +static int clk_pllc_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val; + int ret = 0; + unsigned long flags = 0; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _clk_pll_enable(hw); + udelay(2); + + val = pll_readl_misc(pll); + val &= ~PLLCX_MISC_RESET; + pll_writel_misc(val, pll); + udelay(2); + + _pllcx_strobe(pll); + + ret = clk_pll_wait_for_lock(pll); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +static void _clk_pllc_disable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val; + + _clk_pll_disable(hw); + + val = pll_readl_misc(pll); + val |= PLLCX_MISC_RESET; + pll_writel_misc(val, pll); + udelay(2); +} + +static void clk_pllc_disable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _clk_pllc_disable(hw); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); +} + +static int _pllcx_update_dynamic_coef(struct tegra_clk_pll *pll, + unsigned long input_rate, u32 n) +{ + u32 val, n_threshold; + + switch (input_rate) { + case 12000000: + n_threshold = 70; + break; + case 13000000: + case 26000000: + n_threshold = 71; + break; + case 16800000: + n_threshold = 55; + break; + case 19200000: + n_threshold = 48; + break; + default: + pr_err("%s: Unexpected reference rate %lu\n", + __func__, input_rate); + return -EINVAL; + } + + val = pll_readl_misc(pll); + val &= ~(PLLCX_MISC_SDM_DIV_MASK | PLLCX_MISC_FILT_DIV_MASK); + val |= n <= n_threshold ? + PLLCX_MISC_DIV_LOW_RANGE : PLLCX_MISC_DIV_HIGH_RANGE; + pll_writel_misc(val, pll); + + return 0; +} + +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 *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); + + ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_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))]; + + if (cfg.m != old_m) { + WARN_ON(1); + goto out; + } + + if (old_n == cfg.n && old_p == cfg.p) + goto out; + + cfg.p -= 1; + + state = clk_pll_is_enabled(hw); + if (state) + _clk_pllc_disable(hw); + + ret = _pllcx_update_dynamic_coef(pll, parent_rate, cfg.n); + if (ret < 0) + goto out; + + _update_pll_mnp(pll, &cfg); + + if (state) + ret = clk_pllc_enable(hw); + +out: + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +static long _pllre_calc_rate(struct tegra_clk_pll *pll, + struct tegra_clk_pll_freq_table *cfg, + unsigned long rate, unsigned long parent_rate) +{ + u16 m, n; + u64 output_rate = parent_rate; + + m = _pll_fixed_mdiv(pll->params, parent_rate); + n = rate * m / parent_rate; + + output_rate *= n; + do_div(output_rate, m); + + if (cfg) { + cfg->m = m; + cfg->n = n; + } + + return output_rate; +} +static int clk_pllre_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + 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; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _pllre_calc_rate(pll, &cfg, rate, parent_rate); + _get_pll_mnp(pll, &old_cfg); + cfg.p = old_cfg.p; + + if (cfg.m != old_cfg.m || cfg.n != old_cfg.n) { + state = clk_pll_is_enabled(hw); + if (state) + _clk_pll_disable(hw); + + _update_pll_mnp(pll, &cfg); + + if (state) { + _clk_pll_enable(hw); + ret = clk_pll_wait_for_lock(pll); + } + } + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +static unsigned long clk_pllre_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_pll_freq_table cfg; + struct tegra_clk_pll *pll = to_clk_pll(hw); + u64 rate = parent_rate; + + _get_pll_mnp(pll, &cfg); + + rate *= cfg.n; + do_div(rate, cfg.m); + + return rate; +} + +static long clk_pllre_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + + return _pllre_calc_rate(pll, NULL, rate, *prate); +} + +static int clk_plle_tegra114_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + struct tegra_clk_pll_freq_table sel; + u32 val; + int ret; + unsigned long flags = 0; + unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk)); + + if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate)) + return -EINVAL; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + val = pll_readl_base(pll); + val &= ~BIT(29); /* Disable lock override */ + pll_writel_base(val, pll); + + val = pll_readl(pll->params->aux_reg, pll); + val |= PLLE_AUX_ENABLE_SWCTL; + val &= ~PLLE_AUX_SEQ_ENABLE; + pll_writel(val, pll->params->aux_reg, pll); + udelay(1); + + val = pll_readl_misc(pll); + val |= PLLE_MISC_LOCK_ENABLE; + val |= PLLE_MISC_IDDQ_SW_CTRL; + val &= ~PLLE_MISC_IDDQ_SW_VALUE; + val |= PLLE_MISC_PLLE_PTS; + val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK; + pll_writel_misc(val, pll); + udelay(5); + + val = pll_readl(PLLE_SS_CTRL, pll); + val |= PLLE_SS_DISABLE; + pll_writel(val, PLLE_SS_CTRL, pll); + + 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.cpcon << PLLE_BASE_DIVCML_SHIFT; + pll_writel_base(val, pll); + udelay(1); + + _clk_pll_enable(hw); + ret = clk_pll_wait_for_lock(pll); + + if (ret < 0) + goto out; + + /* TODO: enable hw control of xusb brick pll */ + +out: + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +static void clk_plle_tegra114_disable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + u32 val; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _clk_pll_disable(hw); + + val = pll_readl_misc(pll); + val |= PLLE_MISC_IDDQ_SW_CTRL | PLLE_MISC_IDDQ_SW_VALUE; + pll_writel_misc(val, pll); + udelay(1); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); +} +#endif + static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base, void __iomem *pmc, unsigned long fixed_rate, struct tegra_clk_pll_params *pll_params, u32 pll_flags, @@ -741,3 +1315,268 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, return clk; } + +#ifdef CONFIG_ARCH_TEGRA_114_SOC +const struct clk_ops tegra_clk_pllxc_ops = { + .is_enabled = clk_pll_is_enabled, + .enable = clk_pll_iddq_enable, + .disable = clk_pll_iddq_disable, + .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_ramp_round_rate, + .set_rate = clk_pllxc_set_rate, +}; + +const struct clk_ops tegra_clk_pllm_ops = { + .is_enabled = clk_pll_is_enabled, + .enable = clk_pll_iddq_enable, + .disable = clk_pll_iddq_disable, + .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_ramp_round_rate, + .set_rate = clk_pllm_set_rate, +}; + +const struct clk_ops tegra_clk_pllc_ops = { + .is_enabled = clk_pll_is_enabled, + .enable = clk_pllc_enable, + .disable = clk_pllc_disable, + .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_ramp_round_rate, + .set_rate = clk_pllc_set_rate, +}; + +const struct clk_ops tegra_clk_pllre_ops = { + .is_enabled = clk_pll_is_enabled, + .enable = clk_pll_iddq_enable, + .disable = clk_pll_iddq_disable, + .recalc_rate = clk_pllre_recalc_rate, + .round_rate = clk_pllre_round_rate, + .set_rate = clk_pllre_set_rate, +}; + +const struct clk_ops tegra_clk_plle_tegra114_ops = { + .is_enabled = clk_pll_is_enabled, + .enable = clk_plle_tegra114_enable, + .disable = clk_plle_tegra114_disable, + .recalc_rate = clk_pll_recalc_rate, +}; + + +struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock) +{ + struct tegra_clk_pll *pll; + struct clk *clk; + + if (!pll_params->pdiv_tohw) + return ERR_PTR(-EINVAL); + + pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, + freq_table, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_pllxc_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + +struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock, unsigned long parent_rate) +{ + u32 val; + struct tegra_clk_pll *pll; + struct clk *clk; + + pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, + freq_table, 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(val & pll_params->iddq_bit_idx); + else { + int m; + + m = _pll_fixed_mdiv(pll_params, parent_rate); + val = m << PLL_BASE_DIVM_SHIFT; + val |= (pll_params->vco_min / parent_rate) + << PLL_BASE_DIVN_SHIFT; + pll_writel_base(val, pll); + } + + /* disable lock override */ + + val = pll_readl_misc(pll); + 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)) + kfree(pll); + + return clk; +} + +struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock) +{ + struct tegra_clk_pll *pll; + struct clk *clk; + + if (!pll_params->pdiv_tohw) + return ERR_PTR(-EINVAL); + + pll_flags |= TEGRA_PLL_BYPASS; + pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, + freq_table, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_pllm_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + +struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock) +{ + struct clk *parent, *clk; + struct pdiv_map *p_tohw = pll_params->pdiv_tohw; + struct tegra_clk_pll *pll; + struct tegra_clk_pll_freq_table cfg; + unsigned long parent_rate; + + if (!p_tohw) + return ERR_PTR(-EINVAL); + + parent = __clk_lookup(parent_name); + if (IS_ERR(parent)) { + WARN(1, "parent clk %s of %s must be registered first\n", + name, parent_name); + return ERR_PTR(-EINVAL); + } + + pll_flags |= TEGRA_PLL_BYPASS; + pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, + freq_table, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + parent_rate = __clk_get_rate(parent); + + /* + * Most of PLLC register fields are shadowed, and can not be read + * directly from PLL h/w. Hence, actual PLLC boot state is unknown. + * Initialize PLL to default state: disabled, reset; shadow registers + * loaded with default parameters; dividers are preset for half of + * minimum VCO rate (the latter assured that shadowed divider settings + * are within supported range). + */ + + cfg.m = _pll_fixed_mdiv(pll_params, parent_rate); + cfg.n = cfg.m * pll_params->vco_min / parent_rate; + + while (p_tohw->pdiv) { + if (p_tohw->pdiv == 2) { + cfg.p = p_tohw->hw_val; + break; + } + p_tohw++; + } + + if (!p_tohw->pdiv) { + WARN_ON(1); + return ERR_PTR(-EINVAL); + } + + pll_writel_base(0, pll); + _update_pll_mnp(pll, &cfg); + + pll_writel_misc(PLLCX_MISC_DEFAULT, pll); + pll_writel(PLLCX_MISC1_DEFAULT, pll_params->ext_misc_reg[0], pll); + pll_writel(PLLCX_MISC2_DEFAULT, pll_params->ext_misc_reg[1], pll); + pll_writel(PLLCX_MISC3_DEFAULT, pll_params->ext_misc_reg[2], pll); + + _pllcx_update_dynamic_coef(pll, parent_rate, cfg.n); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_pllc_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + +struct clk *tegra_clk_register_plle_tegra114(const char *name, + const char *parent_name, + void __iomem *clk_base, unsigned long flags, + unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock) +{ + struct tegra_clk_pll *pll; + struct clk *clk; + u32 val, val_aux; + + pll = _tegra_init_pll(clk_base, NULL, fixed_rate, pll_params, + TEGRA_PLL_HAS_LOCK_ENABLE, freq_table, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + /* ensure parent is set to pll_re_vco */ + + val = pll_readl_base(pll); + val_aux = pll_readl(pll_params->aux_reg, pll); + + if (val & PLL_BASE_ENABLE) { + if (!(val_aux & PLLE_AUX_PLLRE_SEL)) + WARN(1, "pll_e enabled with unsupported parent %s\n", + (val & PLLE_AUX_PLLP_SEL) ? "pllp_out0" : "pll_ref"); + } else { + val_aux |= PLLE_AUX_PLLRE_SEL; + pll_writel(val, pll_params->aux_reg, pll); + } + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_plle_tegra114_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} +#endif diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 3b498e0c8ae5..8cedb092a239 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -1,4 +1,4 @@ -/* + /* * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -156,6 +156,13 @@ struct tegra_clk_pll_params { u32 lock_reg; u32 lock_mask; u32 lock_enable_bit_idx; + u32 iddq_reg; + u32 iddq_bit_idx; + u32 aux_reg; + u32 dyn_ramp_reg; + u32 ext_misc_reg[3]; + int stepa_shift; + int stepb_shift; int lock_delay; int max_p; struct pdiv_map *pdiv_tohw; @@ -238,12 +245,53 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, unsigned long flags, unsigned long fixed_rate, struct tegra_clk_pll_params *pll_params, u32 pll_flags, struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); + struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, unsigned long flags, unsigned long fixed_rate, struct tegra_clk_pll_params *pll_params, u32 pll_flags, struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); +struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock); + +struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock); + +struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock); + +struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + 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, + unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock); + /** * struct tegra_clk_pll_out - PLL divider down clock * From a26a029893096204f08a3ff5e262f99e1a75e273 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 3 Apr 2013 17:40:42 +0300 Subject: [PATCH 13/20] clk: tegra: Add flags to tegra_clk_periph() We will need some tegra peripheral clocks with the CLK_IGNORE_UNUSED flag, most notably mselect, which is a bridge between AXI and most peripherals. Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-periph.c | 11 ++++++----- drivers/clk/tegra/clk-tegra20.c | 2 +- drivers/clk/tegra/clk-tegra30.c | 2 +- drivers/clk/tegra/clk.h | 9 ++++++--- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index 9dbd301ace77..b2309d37a963 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -173,14 +173,15 @@ const struct clk_ops tegra_clk_periph_nodiv_ops = { static struct clk *_tegra_clk_register_periph(const char *name, const char **parent_names, int num_parents, struct tegra_clk_periph *periph, - void __iomem *clk_base, u32 offset, bool div) + void __iomem *clk_base, u32 offset, bool div, + unsigned long flags) { struct clk *clk; struct clk_init_data init; init.name = name; init.ops = div ? &tegra_clk_periph_ops : &tegra_clk_periph_nodiv_ops; - init.flags = div ? 0 : CLK_SET_RATE_PARENT; + init.flags = flags; init.parent_names = parent_names; init.num_parents = num_parents; @@ -205,10 +206,10 @@ static struct clk *_tegra_clk_register_periph(const char *name, struct clk *tegra_clk_register_periph(const char *name, const char **parent_names, int num_parents, struct tegra_clk_periph *periph, void __iomem *clk_base, - u32 offset) + u32 offset, unsigned long flags) { return _tegra_clk_register_periph(name, parent_names, num_parents, - periph, clk_base, offset, true); + periph, clk_base, offset, true, flags); } struct clk *tegra_clk_register_periph_nodiv(const char *name, @@ -217,5 +218,5 @@ struct clk *tegra_clk_register_periph_nodiv(const char *name, u32 offset) { return _tegra_clk_register_periph(name, parent_names, num_parents, - periph, clk_base, offset, false); + periph, clk_base, offset, false, CLK_SET_RATE_PARENT); } diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 5c7b58b96911..b0405b67f49c 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -1019,7 +1019,7 @@ static void __init tegra20_periph_clk_init(void) data = &tegra_periph_clk_list[i]; clk = tegra_clk_register_periph(data->name, data->parent_names, data->num_parents, &data->periph, - clk_base, data->offset); + clk_base, data->offset, data->flags); clk_register_clkdev(clk, data->con_id, data->dev_id); clks[data->clk_id] = clk; } diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 735f964edc65..2dc0c5602613 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -1668,7 +1668,7 @@ static void __init tegra30_periph_clk_init(void) data = &tegra_periph_clk_list[i]; clk = tegra_clk_register_periph(data->name, data->parent_names, data->num_parents, &data->periph, - clk_base, data->offset); + clk_base, data->offset, data->flags); clk_register_clkdev(clk, data->con_id, data->dev_id); clks[data->clk_id] = clk; } diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 8cedb092a239..fd12b77c985d 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -417,7 +417,7 @@ extern const struct clk_ops tegra_clk_periph_ops; struct clk *tegra_clk_register_periph(const char *name, const char **parent_names, int num_parents, struct tegra_clk_periph *periph, void __iomem *clk_base, - u32 offset); + u32 offset, unsigned long flags); struct clk *tegra_clk_register_periph_nodiv(const char *name, const char **parent_names, int num_parents, struct tegra_clk_periph *periph, void __iomem *clk_base, @@ -460,12 +460,14 @@ struct tegra_periph_init_data { u32 offset; const char *con_id; const char *dev_id; + unsigned long flags; }; #define TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\ _mux_shift, _mux_mask, _mux_flags, _div_shift, \ _div_width, _div_frac_width, _div_flags, _regs, \ - _clk_num, _enb_refcnt, _gate_flags, _clk_id, _table) \ + _clk_num, _enb_refcnt, _gate_flags, _clk_id, _table,\ + _flags) \ { \ .name = _name, \ .clk_id = _clk_id, \ @@ -480,6 +482,7 @@ struct tegra_periph_init_data { .offset = _offset, \ .con_id = _con_id, \ .dev_id = _dev_id, \ + .flags = _flags \ } #define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset,\ @@ -490,7 +493,7 @@ struct tegra_periph_init_data { _mux_shift, BIT(_mux_width) - 1, _mux_flags, \ _div_shift, _div_width, _div_frac_width, _div_flags, \ _regs, _clk_num, _enb_refcnt, _gate_flags, _clk_id,\ - NULL) + NULL, 0) /** * struct clk_super_mux - super clock From fdcccbd804088eb96881c9f6532de04868f9dbc1 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 3 Apr 2013 17:40:44 +0300 Subject: [PATCH 14/20] clk: tegra: Workaround for Tegra114 MSENC problem Workaround a hardware bug in MSENC during clock enable. Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-periph-gate.c | 9 +++++++++ drivers/clk/tegra/clk.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c index d87e1cece9fa..bafee9895a24 100644 --- a/drivers/clk/tegra/clk-periph-gate.c +++ b/drivers/clk/tegra/clk-periph-gate.c @@ -43,6 +43,8 @@ static DEFINE_SPINLOCK(periph_ref_lock); #define periph_clk_to_bit(gate) (1 << (gate->clk_num % 32)) +#define LVL2_CLK_GATE_OVRE 0x554 + /* Peripheral gate clock ops */ static int clk_periph_is_enabled(struct clk_hw *hw) { @@ -83,6 +85,13 @@ static int clk_periph_enable(struct clk_hw *hw) } } + if (gate->flags & TEGRA_PERIPH_WAR_1005168) { + writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(BIT(22), gate->clk_base + LVL2_CLK_GATE_OVRE); + udelay(1); + writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE); + } + spin_unlock_irqrestore(&periph_ref_lock, flags); return 0; diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index fd12b77c985d..fb48f0467b9d 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -358,6 +358,7 @@ struct tegra_clk_periph_regs { * TEGRA_PERIPH_ON_APB - If peripheral is in the APB bus then read the * bus to flush the write operation in apb bus. This flag indicates * that this peripheral is in apb bus. + * TEGRA_PERIPH_WAR_1005168 - Apply workaround for Tegra114 MSENC bug */ struct tegra_clk_periph_gate { u32 magic; @@ -377,6 +378,7 @@ struct tegra_clk_periph_gate { #define TEGRA_PERIPH_NO_RESET BIT(0) #define TEGRA_PERIPH_MANUAL_RESET BIT(1) #define TEGRA_PERIPH_ON_APB BIT(2) +#define TEGRA_PERIPH_WAR_1005168 BIT(3) void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert); extern const struct clk_ops tegra_clk_periph_gate_ops; From 16d50f4da4123c04ef9ee2097668a80268147b37 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Thu, 4 Apr 2013 20:48:28 +0300 Subject: [PATCH 15/20] ARM: tegra: Define Tegra114 CAR binding The device tree binding models Tegra114 CAR (Clock And Reset) as a single monolithic clock provider. Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- .../bindings/clock/nvidia,tegra114-car.txt | 303 ++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt new file mode 100644 index 000000000000..d6cb083b90a2 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt @@ -0,0 +1,303 @@ +NVIDIA Tegra114 Clock And Reset Controller + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The CAR (Clock And Reset) Controller on Tegra is the HW module responsible +for muxing and gating Tegra's clocks, and setting their rates. + +Required properties : +- compatible : Should be "nvidia,tegra114-car" +- reg : Should contain CAR registers location and length +- clocks : Should contain phandle and clock specifiers for two clocks: + the 32 KHz "32k_in", and the board-specific oscillator "osc". +- #clock-cells : Should be 1. + In clock consumers, this cell represents the clock ID exposed by the CAR. + + The first 160 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB + registers. These IDs often match those in the CAR's RST_DEVICES registers, + but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In + this case, those clocks are assigned IDs above 160 in order to highlight + this issue. Implementations that interpret these clock IDs as bit values + within the CLK_OUT_ENB or RST_DEVICES registers should be careful to + explicitly handle these special cases. + + The balance of the clocks controlled by the CAR are assigned IDs of 160 and + above. + + 0 unassigned + 1 unassigned + 2 unassigned + 3 unassigned + 4 rtc + 5 timer + 6 uarta + 7 unassigned (register bit affects uartb and vfir) + 8 unassigned + 9 sdmmc2 + 10 unassigned (register bit affects spdif_in and spdif_out) + 11 i2s1 + 12 i2c1 + 13 ndflash + 14 sdmmc1 + 15 sdmmc4 + 16 unassigned + 17 pwm + 18 i2s2 + 19 epp + 20 unassigned (register bit affects vi and vi_sensor) + 21 2d + 22 usbd + 23 isp + 24 3d + 25 unassigned + 26 disp2 + 27 disp1 + 28 host1x + 29 vcp + 30 i2s0 + 31 unassigned + + 32 unassigned + 33 unassigned + 34 apbdma + 35 unassigned + 36 kbc + 37 unassigned + 38 unassigned + 39 unassigned (register bit affects fuse and fuse_burn) + 40 kfuse + 41 sbc1 + 42 nor + 43 unassigned + 44 sbc2 + 45 unassigned + 46 sbc3 + 47 i2c5 + 48 dsia + 49 unassigned + 50 mipi + 51 hdmi + 52 csi + 53 unassigned + 54 i2c2 + 55 uartc + 56 mipi-cal + 57 emc + 58 usb2 + 59 usb3 + 60 msenc + 61 vde + 62 bsea + 63 bsev + + 64 unassigned + 65 uartd + 66 unassigned + 67 i2c3 + 68 sbc4 + 69 sdmmc3 + 70 unassigned + 71 owr + 72 afi + 73 csite + 74 unassigned + 75 unassigned + 76 la + 77 trace + 78 soc_therm + 79 dtv + 80 ndspeed + 81 i2cslow + 82 dsib + 83 tsec + 84 unassigned + 85 unassigned + 86 unassigned + 87 unassigned + 88 unassigned + 89 xusb_host + 90 unassigned + 91 msenc + 92 csus + 93 unassigned + 94 unassigned + 95 unassigned (bit affects xusb_dev and xusb_dev_src) + + 96 unassigned + 97 unassigned + 98 unassigned + 99 mselect + 100 tsensor + 101 i2s3 + 102 i2s4 + 103 i2c4 + 104 sbc5 + 105 sbc6 + 106 d_audio + 107 apbif + 108 dam0 + 109 dam1 + 110 dam2 + 111 hda2codec_2x + 112 unassigned + 113 audio0_2x + 114 audio1_2x + 115 audio2_2x + 116 audio3_2x + 117 audio4_2x + 118 spdif_2x + 119 actmon + 120 extern1 + 121 extern2 + 122 extern3 + 123 unassigned + 124 unassigned + 125 hda + 126 unassigned + 127 se + + 128 hda2hdmi + 129 unassigned + 130 unassigned + 131 unassigned + 132 unassigned + 133 unassigned + 134 unassigned + 135 unassigned + 136 unassigned + 137 unassigned + 138 unassigned + 139 unassigned + 140 unassigned + 141 unassigned + 142 unassigned + 143 unassigned (bit affects xusb_falcon_src, xusb_fs_src, + xusb_host_src and xusb_ss_src) + 144 cilab + 145 cilcd + 146 cile + 147 dsialp + 148 dsiblp + 149 unassigned + 150 dds + 151 unassigned + 152 dp2 + 153 amx + 154 adx + 155 unassigned (bit affects dfll_ref and dfll_soc) + 156 xusb_ss + + 192 uartb + 193 vfir + 194 spdif_in + 195 spdif_out + 196 vi + 197 vi_sensor + 198 fuse + 199 fuse_burn + 200 clk_32k + 201 clk_m + 202 clk_m_div2 + 203 clk_m_div4 + 204 pll_ref + 205 pll_c + 206 pll_c_out1 + 207 pll_c2 + 208 pll_c3 + 209 pll_m + 210 pll_m_out1 + 211 pll_p + 212 pll_p_out1 + 213 pll_p_out2 + 214 pll_p_out3 + 215 pll_p_out4 + 216 pll_a + 217 pll_a_out0 + 218 pll_d + 219 pll_d_out0 + 220 pll_d2 + 221 pll_d2_out0 + 222 pll_u + 223 pll_u_480M + 224 pll_u_60M + 225 pll_u_48M + 226 pll_u_12M + 227 pll_x + 228 pll_x_out0 + 229 pll_re_vco + 230 pll_re_out + 231 pll_e_out0 + 232 spdif_in_sync + 233 i2s0_sync + 234 i2s1_sync + 235 i2s2_sync + 236 i2s3_sync + 237 i2s4_sync + 238 vimclk_sync + 239 audio0 + 240 audio1 + 241 audio2 + 242 audio3 + 243 audio4 + 244 spdif + 245 clk_out_1 + 246 clk_out_2 + 247 clk_out_3 + 248 blink + 252 xusb_host_src + 253 xusb_falcon_src + 254 xusb_fs_src + 255 xusb_ss_src + 256 xusb_dev_src + 257 xusb_dev + 258 xusb_hs_src + 259 sclk + 260 hclk + 261 pclk + 262 cclk_g + 263 cclk_lp + 264 dfll_ref + 265 dfll_soc + +Example SoC include file: + +/ { + tegra_car: clock { + compatible = "nvidia,tegra114-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + }; + + usb@c5004000 { + clocks = <&tegra_car 58>; /* usb2 */ + }; +}; + +Example board file: + +/ { + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + osc: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + + clk_32k: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + &tegra_car { + clocks = <&clk_32k> <&osc>; + }; +}; From 2cb5efefd6f7d3e7df9a7430b910a80515821256 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 3 Apr 2013 17:40:45 +0300 Subject: [PATCH 16/20] clk: tegra: Implement clocks for Tegra114 Implement clocks for Tegra114. Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/Makefile | 1 + drivers/clk/tegra/clk-tegra114.c | 2085 ++++++++++++++++++++++++++++++ 2 files changed, 2086 insertions(+) create mode 100644 drivers/clk/tegra/clk-tegra114.c diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index 2b41b0f4f731..f49fac2d193a 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -9,3 +9,4 @@ obj-y += clk-super.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o +obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c new file mode 100644 index 000000000000..e2a7fa16c5de --- /dev/null +++ b/drivers/clk/tegra/clk-tegra114.c @@ -0,0 +1,2085 @@ +/* + * Copyright (c) 2012, 2013, 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define RST_DEVICES_L 0x004 +#define RST_DEVICES_H 0x008 +#define RST_DEVICES_U 0x00C +#define RST_DEVICES_V 0x358 +#define RST_DEVICES_W 0x35C +#define RST_DEVICES_X 0x28C +#define RST_DEVICES_SET_L 0x300 +#define RST_DEVICES_CLR_L 0x304 +#define RST_DEVICES_SET_H 0x308 +#define RST_DEVICES_CLR_H 0x30c +#define RST_DEVICES_SET_U 0x310 +#define RST_DEVICES_CLR_U 0x314 +#define RST_DEVICES_SET_V 0x430 +#define RST_DEVICES_CLR_V 0x434 +#define RST_DEVICES_SET_W 0x438 +#define RST_DEVICES_CLR_W 0x43c +#define RST_DEVICES_NUM 5 + +#define CLK_OUT_ENB_L 0x010 +#define CLK_OUT_ENB_H 0x014 +#define CLK_OUT_ENB_U 0x018 +#define CLK_OUT_ENB_V 0x360 +#define CLK_OUT_ENB_W 0x364 +#define CLK_OUT_ENB_X 0x280 +#define CLK_OUT_ENB_SET_L 0x320 +#define CLK_OUT_ENB_CLR_L 0x324 +#define CLK_OUT_ENB_SET_H 0x328 +#define CLK_OUT_ENB_CLR_H 0x32c +#define CLK_OUT_ENB_SET_U 0x330 +#define CLK_OUT_ENB_CLR_U 0x334 +#define CLK_OUT_ENB_SET_V 0x440 +#define CLK_OUT_ENB_CLR_V 0x444 +#define CLK_OUT_ENB_SET_W 0x448 +#define CLK_OUT_ENB_CLR_W 0x44c +#define CLK_OUT_ENB_SET_X 0x284 +#define CLK_OUT_ENB_CLR_X 0x288 +#define CLK_OUT_ENB_NUM 6 + +#define PLLC_BASE 0x80 +#define PLLC_MISC2 0x88 +#define PLLC_MISC 0x8c +#define PLLC2_BASE 0x4e8 +#define PLLC2_MISC 0x4ec +#define PLLC3_BASE 0x4fc +#define PLLC3_MISC 0x500 +#define PLLM_BASE 0x90 +#define PLLM_MISC 0x9c +#define PLLP_BASE 0xa0 +#define PLLP_MISC 0xac +#define PLLX_BASE 0xe0 +#define PLLX_MISC 0xe4 +#define PLLX_MISC2 0x514 +#define PLLX_MISC3 0x518 +#define PLLD_BASE 0xd0 +#define PLLD_MISC 0xdc +#define PLLD2_BASE 0x4b8 +#define PLLD2_MISC 0x4bc +#define PLLE_BASE 0xe8 +#define PLLE_MISC 0xec +#define PLLA_BASE 0xb0 +#define PLLA_MISC 0xbc +#define PLLU_BASE 0xc0 +#define PLLU_MISC 0xcc +#define PLLRE_BASE 0x4c4 +#define PLLRE_MISC 0x4c8 + +#define PLL_MISC_LOCK_ENABLE 18 +#define PLLC_MISC_LOCK_ENABLE 24 +#define PLLDU_MISC_LOCK_ENABLE 22 +#define PLLE_MISC_LOCK_ENABLE 9 +#define PLLRE_MISC_LOCK_ENABLE 30 + +#define PLLC_IDDQ_BIT 26 +#define PLLX_IDDQ_BIT 3 +#define PLLRE_IDDQ_BIT 16 + +#define PLL_BASE_LOCK BIT(27) +#define PLLE_MISC_LOCK BIT(11) +#define PLLRE_MISC_LOCK BIT(24) +#define PLLCX_BASE_LOCK (BIT(26)|BIT(27)) + +#define PLLE_AUX 0x48c +#define PLLC_OUT 0x84 +#define PLLM_OUT 0x94 +#define PLLP_OUTA 0xa4 +#define PLLP_OUTB 0xa8 +#define PLLA_OUT 0xb4 + +#define AUDIO_SYNC_CLK_I2S0 0x4a0 +#define AUDIO_SYNC_CLK_I2S1 0x4a4 +#define AUDIO_SYNC_CLK_I2S2 0x4a8 +#define AUDIO_SYNC_CLK_I2S3 0x4ac +#define AUDIO_SYNC_CLK_I2S4 0x4b0 +#define AUDIO_SYNC_CLK_SPDIF 0x4b4 + +#define AUDIO_SYNC_DOUBLER 0x49c + +#define PMC_CLK_OUT_CNTRL 0x1a8 +#define PMC_DPD_PADS_ORIDE 0x1c +#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 +#define PMC_CTRL 0 +#define PMC_CTRL_BLINK_ENB 7 + +#define OSC_CTRL 0x50 +#define OSC_CTRL_OSC_FREQ_SHIFT 28 +#define OSC_CTRL_PLL_REF_DIV_SHIFT 26 + +#define PLLXC_SW_MAX_P 6 + +#define CCLKG_BURST_POLICY 0x368 +#define CCLKLP_BURST_POLICY 0x370 +#define SCLK_BURST_POLICY 0x028 +#define SYSTEM_CLK_RATE 0x030 + +#define UTMIP_PLL_CFG2 0x488 +#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6) +#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4) + +#define UTMIP_PLL_CFG1 0x484 +#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6) +#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) +#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP BIT(17) +#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16) +#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP BIT(15) +#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14) +#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12) + +#define UTMIPLL_HW_PWRDN_CFG0 0x52c +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE BIT(25) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE BIT(24) +#define UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET BIT(6) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_RESET_INPUT_VALUE BIT(5) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_IN_SWCTL BIT(4) +#define UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL BIT(2) +#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE BIT(1) +#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0) + +#define CLK_SOURCE_I2S0 0x1d8 +#define CLK_SOURCE_I2S1 0x100 +#define CLK_SOURCE_I2S2 0x104 +#define CLK_SOURCE_NDFLASH 0x160 +#define CLK_SOURCE_I2S3 0x3bc +#define CLK_SOURCE_I2S4 0x3c0 +#define CLK_SOURCE_SPDIF_OUT 0x108 +#define CLK_SOURCE_SPDIF_IN 0x10c +#define CLK_SOURCE_PWM 0x110 +#define CLK_SOURCE_ADX 0x638 +#define CLK_SOURCE_AMX 0x63c +#define CLK_SOURCE_HDA 0x428 +#define CLK_SOURCE_HDA2CODEC_2X 0x3e4 +#define CLK_SOURCE_SBC1 0x134 +#define CLK_SOURCE_SBC2 0x118 +#define CLK_SOURCE_SBC3 0x11c +#define CLK_SOURCE_SBC4 0x1b4 +#define CLK_SOURCE_SBC5 0x3c8 +#define CLK_SOURCE_SBC6 0x3cc +#define CLK_SOURCE_SATA_OOB 0x420 +#define CLK_SOURCE_SATA 0x424 +#define CLK_SOURCE_NDSPEED 0x3f8 +#define CLK_SOURCE_VFIR 0x168 +#define CLK_SOURCE_SDMMC1 0x150 +#define CLK_SOURCE_SDMMC2 0x154 +#define CLK_SOURCE_SDMMC3 0x1bc +#define CLK_SOURCE_SDMMC4 0x164 +#define CLK_SOURCE_VDE 0x1c8 +#define CLK_SOURCE_CSITE 0x1d4 +#define CLK_SOURCE_LA 0x1f8 +#define CLK_SOURCE_TRACE 0x634 +#define CLK_SOURCE_OWR 0x1cc +#define CLK_SOURCE_NOR 0x1d0 +#define CLK_SOURCE_MIPI 0x174 +#define CLK_SOURCE_I2C1 0x124 +#define CLK_SOURCE_I2C2 0x198 +#define CLK_SOURCE_I2C3 0x1b8 +#define CLK_SOURCE_I2C4 0x3c4 +#define CLK_SOURCE_I2C5 0x128 +#define CLK_SOURCE_UARTA 0x178 +#define CLK_SOURCE_UARTB 0x17c +#define CLK_SOURCE_UARTC 0x1a0 +#define CLK_SOURCE_UARTD 0x1c0 +#define CLK_SOURCE_UARTE 0x1c4 +#define CLK_SOURCE_UARTA_DBG 0x178 +#define CLK_SOURCE_UARTB_DBG 0x17c +#define CLK_SOURCE_UARTC_DBG 0x1a0 +#define CLK_SOURCE_UARTD_DBG 0x1c0 +#define CLK_SOURCE_UARTE_DBG 0x1c4 +#define CLK_SOURCE_3D 0x158 +#define CLK_SOURCE_2D 0x15c +#define CLK_SOURCE_VI_SENSOR 0x1a8 +#define CLK_SOURCE_VI 0x148 +#define CLK_SOURCE_EPP 0x16c +#define CLK_SOURCE_MSENC 0x1f0 +#define CLK_SOURCE_TSEC 0x1f4 +#define CLK_SOURCE_HOST1X 0x180 +#define CLK_SOURCE_HDMI 0x18c +#define CLK_SOURCE_DISP1 0x138 +#define CLK_SOURCE_DISP2 0x13c +#define CLK_SOURCE_CILAB 0x614 +#define CLK_SOURCE_CILCD 0x618 +#define CLK_SOURCE_CILE 0x61c +#define CLK_SOURCE_DSIALP 0x620 +#define CLK_SOURCE_DSIBLP 0x624 +#define CLK_SOURCE_TSENSOR 0x3b8 +#define CLK_SOURCE_D_AUDIO 0x3d0 +#define CLK_SOURCE_DAM0 0x3d8 +#define CLK_SOURCE_DAM1 0x3dc +#define CLK_SOURCE_DAM2 0x3e0 +#define CLK_SOURCE_ACTMON 0x3e8 +#define CLK_SOURCE_EXTERN1 0x3ec +#define CLK_SOURCE_EXTERN2 0x3f0 +#define CLK_SOURCE_EXTERN3 0x3f4 +#define CLK_SOURCE_I2CSLOW 0x3fc +#define CLK_SOURCE_SE 0x42c +#define CLK_SOURCE_MSELECT 0x3b4 +#define CLK_SOURCE_SOC_THERM 0x644 +#define CLK_SOURCE_XUSB_HOST_SRC 0x600 +#define CLK_SOURCE_XUSB_FALCON_SRC 0x604 +#define CLK_SOURCE_XUSB_FS_SRC 0x608 +#define CLK_SOURCE_XUSB_SS_SRC 0x610 +#define CLK_SOURCE_XUSB_DEV_SRC 0x60c +#define CLK_SOURCE_EMC 0x19c + +static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; + +static void __iomem *clk_base; +static void __iomem *pmc_base; + +static DEFINE_SPINLOCK(pll_d_lock); +static DEFINE_SPINLOCK(pll_d2_lock); +static DEFINE_SPINLOCK(pll_u_lock); +static DEFINE_SPINLOCK(pll_div_lock); +static DEFINE_SPINLOCK(pll_re_lock); +static DEFINE_SPINLOCK(clk_doubler_lock); +static DEFINE_SPINLOCK(clk_out_lock); +static DEFINE_SPINLOCK(sysrate_lock); + +static struct pdiv_map pllxc_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 3, .hw_val = 2 }, + { .pdiv = 4, .hw_val = 3 }, + { .pdiv = 5, .hw_val = 4 }, + { .pdiv = 6, .hw_val = 5 }, + { .pdiv = 8, .hw_val = 6 }, + { .pdiv = 10, .hw_val = 7 }, + { .pdiv = 12, .hw_val = 8 }, + { .pdiv = 16, .hw_val = 9 }, + { .pdiv = 12, .hw_val = 10 }, + { .pdiv = 16, .hw_val = 11 }, + { .pdiv = 20, .hw_val = 12 }, + { .pdiv = 24, .hw_val = 13 }, + { .pdiv = 32, .hw_val = 14 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { + { 12000000, 624000000, 104, 0, 2}, + { 12000000, 600000000, 100, 0, 2}, + { 13000000, 600000000, 92, 0, 2}, /* actual: 598.0 MHz */ + { 16800000, 600000000, 71, 0, 2}, /* actual: 596.4 MHz */ + { 19200000, 600000000, 62, 0, 2}, /* actual: 595.2 MHz */ + { 26000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */ + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_params pll_c_params = { + .input_min = 12000000, + .input_max = 800000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */ + .vco_min = 600000000, + .vco_max = 1400000000, + .base_reg = PLLC_BASE, + .misc_reg = PLLC_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLC_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLC_MISC, + .iddq_bit_idx = PLLC_IDDQ_BIT, + .max_p = PLLXC_SW_MAX_P, + .dyn_ramp_reg = PLLC_MISC2, + .stepa_shift = 17, + .stepb_shift = 9, + .pdiv_tohw = pllxc_p, +}; + +static struct pdiv_map pllc_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 4, .hw_val = 3 }, + { .pdiv = 8, .hw_val = 5 }, + { .pdiv = 16, .hw_val = 7 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = { + {12000000, 600000000, 100, 0, 2}, + {13000000, 600000000, 92, 0, 2}, /* actual: 598.0 MHz */ + {16800000, 600000000, 71, 0, 2}, /* actual: 596.4 MHz */ + {19200000, 600000000, 62, 0, 2}, /* actual: 595.2 MHz */ + {26000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */ + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_c2_params = { + .input_min = 12000000, + .input_max = 48000000, + .cf_min = 12000000, + .cf_max = 19200000, + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLC2_BASE, + .misc_reg = PLLC2_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .pdiv_tohw = pllc_p, + .ext_misc_reg[0] = 0x4f0, + .ext_misc_reg[1] = 0x4f4, + .ext_misc_reg[2] = 0x4f8, +}; + +static struct tegra_clk_pll_params pll_c3_params = { + .input_min = 12000000, + .input_max = 48000000, + .cf_min = 12000000, + .cf_max = 19200000, + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLC3_BASE, + .misc_reg = PLLC3_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .pdiv_tohw = pllc_p, + .ext_misc_reg[0] = 0x504, + .ext_misc_reg[1] = 0x508, + .ext_misc_reg[2] = 0x50c, +}; + +static struct pdiv_map pllm_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_m_freq_table[] = { + {12000000, 800000000, 66, 0, 1}, /* actual: 792.0 MHz */ + {13000000, 800000000, 61, 0, 1}, /* actual: 793.0 MHz */ + {16800000, 800000000, 47, 0, 1}, /* actual: 789.6 MHz */ + {19200000, 800000000, 41, 0, 1}, /* actual: 787.2 MHz */ + {26000000, 800000000, 61, 1, 1}, /* actual: 793.0 MHz */ + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_m_params = { + .input_min = 12000000, + .input_max = 500000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */ + .vco_min = 400000000, + .vco_max = 1066000000, + .base_reg = PLLM_BASE, + .misc_reg = PLLM_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .max_p = 2, + .pdiv_tohw = pllm_p, +}; + +static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { + {12000000, 216000000, 432, 12, 1, 8}, + {13000000, 216000000, 432, 13, 1, 8}, + {16800000, 216000000, 360, 14, 1, 8}, + {19200000, 216000000, 360, 16, 1, 8}, + {26000000, 216000000, 432, 26, 1, 8}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_p_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 200000000, + .vco_max = 700000000, + .base_reg = PLLP_BASE, + .misc_reg = PLLP_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { + {9600000, 282240000, 147, 5, 0, 4}, + {9600000, 368640000, 192, 5, 0, 4}, + {9600000, 240000000, 200, 8, 0, 8}, + + {28800000, 282240000, 245, 25, 0, 8}, + {28800000, 368640000, 320, 25, 0, 8}, + {28800000, 240000000, 200, 24, 0, 8}, + {0, 0, 0, 0, 0, 0}, +}; + + +static struct tegra_clk_pll_params pll_a_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 200000000, + .vco_max = 700000000, + .base_reg = PLLA_BASE, + .misc_reg = PLLA_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { + {12000000, 216000000, 864, 12, 2, 12}, + {13000000, 216000000, 864, 13, 2, 12}, + {16800000, 216000000, 720, 14, 2, 12}, + {19200000, 216000000, 720, 16, 2, 12}, + {26000000, 216000000, 864, 26, 2, 12}, + + {12000000, 594000000, 594, 12, 0, 12}, + {13000000, 594000000, 594, 13, 0, 12}, + {16800000, 594000000, 495, 14, 0, 12}, + {19200000, 594000000, 495, 16, 0, 12}, + {26000000, 594000000, 594, 26, 0, 12}, + + {12000000, 1000000000, 1000, 12, 0, 12}, + {13000000, 1000000000, 1000, 13, 0, 12}, + {19200000, 1000000000, 625, 12, 0, 12}, + {26000000, 1000000000, 1000, 26, 0, 12}, + + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_d_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 500000000, + .vco_max = 1000000000, + .base_reg = PLLD_BASE, + .misc_reg = PLLD_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, +}; + +static struct tegra_clk_pll_params pll_d2_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 500000000, + .vco_max = 1000000000, + .base_reg = PLLD2_BASE, + .misc_reg = PLLD2_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, +}; + +static struct pdiv_map pllu_p[] = { + { .pdiv = 1, .hw_val = 1 }, + { .pdiv = 2, .hw_val = 0 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { + {12000000, 480000000, 960, 12, 0, 12}, + {13000000, 480000000, 960, 13, 0, 12}, + {16800000, 480000000, 400, 7, 0, 5}, + {19200000, 480000000, 200, 4, 0, 3}, + {26000000, 480000000, 960, 26, 0, 12}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_u_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 480000000, + .vco_max = 960000000, + .base_reg = PLLU_BASE, + .misc_reg = PLLU_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, + .pdiv_tohw = pllu_p, +}; + +static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { + /* 1 GHz */ + {12000000, 1000000000, 83, 0, 1}, /* actual: 996.0 MHz */ + {13000000, 1000000000, 76, 0, 1}, /* actual: 988.0 MHz */ + {16800000, 1000000000, 59, 0, 1}, /* actual: 991.2 MHz */ + {19200000, 1000000000, 52, 0, 1}, /* actual: 998.4 MHz */ + {26000000, 1000000000, 76, 1, 1}, /* actual: 988.0 MHz */ + + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_x_params = { + .input_min = 12000000, + .input_max = 800000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */ + .vco_min = 700000000, + .vco_max = 2400000000U, + .base_reg = PLLX_BASE, + .misc_reg = PLLX_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLX_MISC3, + .iddq_bit_idx = PLLX_IDDQ_BIT, + .max_p = PLLXC_SW_MAX_P, + .dyn_ramp_reg = PLLX_MISC2, + .stepa_shift = 16, + .stepb_shift = 24, + .pdiv_tohw = pllxc_p, +}; + +static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { + /* PLLE special case: use cpcon field to store cml divider value */ + {336000000, 100000000, 100, 21, 16, 11}, + {312000000, 100000000, 200, 26, 24, 13}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_e_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 75000000, + .vco_min = 1600000000, + .vco_max = 2400000000U, + .base_reg = PLLE_BASE, + .misc_reg = PLLE_MISC, + .aux_reg = PLLE_AUX, + .lock_mask = PLLE_MISC_LOCK, + .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_re_vco_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 38 MHz */ + .vco_min = 300000000, + .vco_max = 600000000, + .base_reg = PLLRE_BASE, + .misc_reg = PLLRE_MISC, + .lock_mask = PLLRE_MISC_LOCK, + .lock_enable_bit_idx = PLLRE_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLRE_MISC, + .iddq_bit_idx = PLLRE_IDDQ_BIT, +}; + +/* Peripheral clock registers */ + +static struct tegra_clk_periph_regs periph_l_regs = { + .enb_reg = CLK_OUT_ENB_L, + .enb_set_reg = CLK_OUT_ENB_SET_L, + .enb_clr_reg = CLK_OUT_ENB_CLR_L, + .rst_reg = RST_DEVICES_L, + .rst_set_reg = RST_DEVICES_SET_L, + .rst_clr_reg = RST_DEVICES_CLR_L, +}; + +static struct tegra_clk_periph_regs periph_h_regs = { + .enb_reg = CLK_OUT_ENB_H, + .enb_set_reg = CLK_OUT_ENB_SET_H, + .enb_clr_reg = CLK_OUT_ENB_CLR_H, + .rst_reg = RST_DEVICES_H, + .rst_set_reg = RST_DEVICES_SET_H, + .rst_clr_reg = RST_DEVICES_CLR_H, +}; + +static struct tegra_clk_periph_regs periph_u_regs = { + .enb_reg = CLK_OUT_ENB_U, + .enb_set_reg = CLK_OUT_ENB_SET_U, + .enb_clr_reg = CLK_OUT_ENB_CLR_U, + .rst_reg = RST_DEVICES_U, + .rst_set_reg = RST_DEVICES_SET_U, + .rst_clr_reg = RST_DEVICES_CLR_U, +}; + +static struct tegra_clk_periph_regs periph_v_regs = { + .enb_reg = CLK_OUT_ENB_V, + .enb_set_reg = CLK_OUT_ENB_SET_V, + .enb_clr_reg = CLK_OUT_ENB_CLR_V, + .rst_reg = RST_DEVICES_V, + .rst_set_reg = RST_DEVICES_SET_V, + .rst_clr_reg = RST_DEVICES_CLR_V, +}; + +static struct tegra_clk_periph_regs periph_w_regs = { + .enb_reg = CLK_OUT_ENB_W, + .enb_set_reg = CLK_OUT_ENB_SET_W, + .enb_clr_reg = CLK_OUT_ENB_CLR_W, + .rst_reg = RST_DEVICES_W, + .rst_set_reg = RST_DEVICES_SET_W, + .rst_clr_reg = RST_DEVICES_CLR_W, +}; + +/* possible OSC frequencies in Hz */ +static unsigned long tegra114_input_freq[] = { + [0] = 13000000, + [1] = 16800000, + [4] = 19200000, + [5] = 38400000, + [8] = 12000000, + [9] = 48000000, + [12] = 260000000, +}; + +#define MASK(x) (BIT(x) - 1) + +#define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 30, MASK(2), 0, 0, 8, 1, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, _gate_flags, _clk_id, \ + _parents##_idx, 0) + +#define TEGRA_INIT_DATA_MUX_FLAGS(_name, _con_id, _dev_id, _parents, _offset,\ + _clk_num, _regs, _gate_flags, _clk_id, flags)\ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 30, MASK(2), 0, 0, 8, 1, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, _gate_flags, _clk_id, \ + _parents##_idx, flags) + +#define TEGRA_INIT_DATA_MUX8(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 29, MASK(3), 0, 0, 8, 1, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, _gate_flags, _clk_id, \ + _parents##_idx, 0) + +#define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 30, MASK(2), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs,\ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id, _parents##_idx, 0) + +#define TEGRA_INIT_DATA_INT_FLAGS(_name, _con_id, _dev_id, _parents, _offset,\ + _clk_num, _regs, _gate_flags, _clk_id, flags)\ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 30, MASK(2), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs,\ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id, _parents##_idx, flags) + +#define TEGRA_INIT_DATA_INT8(_name, _con_id, _dev_id, _parents, _offset,\ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 29, MASK(3), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs,\ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id, _parents##_idx, 0) + +#define TEGRA_INIT_DATA_UART(_name, _con_id, _dev_id, _parents, _offset,\ + _clk_num, _regs, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 30, MASK(2), 0, 0, 16, 1, TEGRA_DIVIDER_UART, _regs,\ + _clk_num, periph_clk_enb_refcnt, 0, _clk_id, \ + _parents##_idx, 0) + +#define TEGRA_INIT_DATA_I2C(_name, _con_id, _dev_id, _parents, _offset,\ + _clk_num, _regs, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 30, MASK(2), 0, 0, 16, 0, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, 0, _clk_id, _parents##_idx, 0) + +#define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \ + _mux_shift, _mux_mask, _clk_num, _regs, \ + _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + _mux_shift, _mux_mask, 0, 0, 0, 0, 0, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id, _parents##_idx, 0) + +#define TEGRA_INIT_DATA_XUSB(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset, \ + 29, MASK(3), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id, _parents##_idx, 0) + +#define TEGRA_INIT_DATA_AUDIO(_name, _con_id, _dev_id, _offset, _clk_num,\ + _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, mux_d_audio_clk, \ + _offset, 16, 0xE01F, 0, 0, 8, 1, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, _gate_flags , _clk_id, \ + mux_d_audio_clk_idx, 0) + +enum tegra114_clk { + rtc = 4, timer = 5, uarta = 6, sdmmc2 = 9, i2s1 = 11, i2c1 = 12, + ndflash = 13, sdmmc1 = 14, sdmmc4 = 15, pwm = 17, i2s2 = 18, epp = 19, + gr_2d = 21, usbd = 22, isp = 23, gr_3d = 24, disp2 = 26, disp1 = 27, + host1x = 28, vcp = 29, i2s0 = 30, apbdma = 34, kbc = 36, kfuse = 40, + sbc1 = 41, nor = 42, sbc2 = 44, sbc3 = 46, i2c5 = 47, dsia = 48, + mipi = 50, hdmi = 51, csi = 52, i2c2 = 54, uartc = 55, mipi_cal = 56, + emc, usb2, usb3, vde = 61, bsea = 62, bsev = 63, uartd = 65, + i2c3 = 67, sbc4 = 68, sdmmc3 = 69, owr = 71, csite = 73, + la = 76, trace = 77, soc_therm = 78, dtv = 79, ndspeed = 80, + i2cslow = 81, dsib = 82, tsec = 83, xusb_host = 89, msenc = 91, + csus = 92, mselect = 99, tsensor = 100, i2s3 = 101, i2s4 = 102, + i2c4 = 103, sbc5 = 104, sbc6 = 105, d_audio, apbif = 107, dam0, dam1, + dam2, hda2codec_2x = 111, audio0_2x = 113, audio1_2x, audio2_2x, + audio3_2x, audio4_2x, spdif_2x, actmon = 119, extern1 = 120, + extern2 = 121, extern3 = 122, hda = 125, se = 127, hda2hdmi = 128, + cilab = 144, cilcd = 145, cile = 146, dsialp = 147, dsiblp = 148, + dds = 150, dp2 = 152, amx = 153, adx = 154, xusb_ss = 156, uartb = 192, + vfir, spdif_in, spdif_out, vi, vi_sensor, fuse, fuse_burn, clk_32k, + clk_m, clk_m_div2, clk_m_div4, pll_ref, pll_c, pll_c_out1, pll_c2, + pll_c3, pll_m, pll_m_out1, pll_p, pll_p_out1, pll_p_out2, pll_p_out3, + pll_p_out4, pll_a, pll_a_out0, pll_d, pll_d_out0, pll_d2, pll_d2_out0, + pll_u, pll_u_480M, pll_u_60M, pll_u_48M, pll_u_12M, pll_x, pll_x_out0, + pll_re_vco, pll_re_out, pll_e_out0, spdif_in_sync, i2s0_sync, + i2s1_sync, i2s2_sync, i2s3_sync, i2s4_sync, vimclk_sync, audio0, + audio1, audio2, audio3, audio4, spdif, clk_out_1, clk_out_2, clk_out_3, + blink, xusb_host_src, xusb_falcon_src, xusb_fs_src, xusb_ss_src, + xusb_dev_src, xusb_dev, xusb_hs_src, sclk, hclk, pclk, cclk_g, cclk_lp, + + /* Mux clocks */ + + audio0_mux = 300, audio1_mux, audio2_mux, audio3_mux, audio4_mux, + spdif_mux, clk_out_1_mux, clk_out_2_mux, clk_out_3_mux, dsia_mux, + dsib_mux, clk_max, +}; + +struct utmi_clk_param { + /* Oscillator Frequency in KHz */ + u32 osc_frequency; + /* UTMIP PLL Enable Delay Count */ + u8 enable_delay_count; + /* UTMIP PLL Stable count */ + u8 stable_count; + /* UTMIP PLL Active delay count */ + u8 active_delay_count; + /* UTMIP PLL Xtal frequency count */ + u8 xtal_freq_count; +}; + +static const struct utmi_clk_param utmi_parameters[] = { + {.osc_frequency = 13000000, .enable_delay_count = 0x02, + .stable_count = 0x33, .active_delay_count = 0x05, + .xtal_freq_count = 0x7F}, + {.osc_frequency = 19200000, .enable_delay_count = 0x03, + .stable_count = 0x4B, .active_delay_count = 0x06, + .xtal_freq_count = 0xBB}, + {.osc_frequency = 12000000, .enable_delay_count = 0x02, + .stable_count = 0x2F, .active_delay_count = 0x04, + .xtal_freq_count = 0x76}, + {.osc_frequency = 26000000, .enable_delay_count = 0x04, + .stable_count = 0x66, .active_delay_count = 0x09, + .xtal_freq_count = 0xFE}, + {.osc_frequency = 16800000, .enable_delay_count = 0x03, + .stable_count = 0x41, .active_delay_count = 0x0A, + .xtal_freq_count = 0xA4}, +}; + +/* peripheral mux definitions */ + +#define MUX_I2S_SPDIF(_id) \ +static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { "pll_a_out0", \ + #_id, "pll_p",\ + "clk_m"}; +MUX_I2S_SPDIF(audio0) +MUX_I2S_SPDIF(audio1) +MUX_I2S_SPDIF(audio2) +MUX_I2S_SPDIF(audio3) +MUX_I2S_SPDIF(audio4) +MUX_I2S_SPDIF(audio) + +#define mux_pllaout0_audio0_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio1_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio2_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio3_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio4_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio_2x_pllp_clkm_idx NULL + +static const char *mux_pllp_pllc_pllm_clkm[] = { + "pll_p", "pll_c", "pll_m", "clk_m" +}; +#define mux_pllp_pllc_pllm_clkm_idx NULL + +static const char *mux_pllp_pllc_pllm[] = { "pll_p", "pll_c", "pll_m" }; +#define mux_pllp_pllc_pllm_idx NULL + +static const char *mux_pllp_pllc_clk32_clkm[] = { + "pll_p", "pll_c", "clk_32k", "clk_m" +}; +#define mux_pllp_pllc_clk32_clkm_idx NULL + +static const char *mux_plla_pllc_pllp_clkm[] = { + "pll_a_out0", "pll_c", "pll_p", "clk_m" +}; +#define mux_plla_pllc_pllp_clkm_idx mux_pllp_pllc_pllm_clkm_idx + +static const char *mux_pllp_pllc2_c_c3_pllm_clkm[] = { + "pll_p", "pll_c2", "pll_c", "pll_c3", "pll_m", "clk_m" +}; +static u32 mux_pllp_pllc2_c_c3_pllm_clkm_idx[] = { + [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6, +}; + +static const char *mux_pllp_clkm[] = { + "pll_p", "clk_m" +}; +static u32 mux_pllp_clkm_idx[] = { + [0] = 0, [1] = 3, +}; + +static const char *mux_pllm_pllc2_c_c3_pllp_plla[] = { + "pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0" +}; +#define mux_pllm_pllc2_c_c3_pllp_plla_idx mux_pllp_pllc2_c_c3_pllm_clkm_idx + +static const char *mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = { + "pll_p", "pll_m", "pll_d_out0", "pll_a_out0", "pll_c", + "pll_d2_out0", "clk_m" +}; +#define mux_pllp_pllm_plld_plla_pllc_plld2_clkm_idx NULL + +static const char *mux_pllm_pllc_pllp_plla[] = { + "pll_m", "pll_c", "pll_p", "pll_a_out0" +}; +#define mux_pllm_pllc_pllp_plla_idx mux_pllp_pllc_pllm_clkm_idx + +static const char *mux_pllp_pllc_clkm[] = { + "pll_p", "pll_c", "pll_m" +}; +static u32 mux_pllp_pllc_clkm_idx[] = { + [0] = 0, [1] = 1, [2] = 3, +}; + +static const char *mux_pllp_pllc_clkm_clk32[] = { + "pll_p", "pll_c", "clk_m", "clk_32k" +}; +#define mux_pllp_pllc_clkm_clk32_idx NULL + +static const char *mux_plla_clk32_pllp_clkm_plle[] = { + "pll_a_out0", "clk_32k", "pll_p", "clk_m", "pll_e_out0" +}; +#define mux_plla_clk32_pllp_clkm_plle_idx NULL + +static const char *mux_clkm_pllp_pllc_pllre[] = { + "clk_m", "pll_p", "pll_c", "pll_re_out" +}; +static u32 mux_clkm_pllp_pllc_pllre_idx[] = { + [0] = 0, [1] = 1, [2] = 3, [3] = 5, +}; + +static const char *mux_clkm_48M_pllp_480M[] = { + "clk_m", "pll_u_48M", "pll_p", "pll_u_480M" +}; +#define mux_clkm_48M_pllp_480M_idx NULL + +static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = { + "clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref" +}; +static u32 mux_clkm_pllre_clk32_480M_pllc_ref_idx[] = { + [0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7, +}; + +static const char *mux_plld_out0_plld2_out0[] = { + "pll_d_out0", "pll_d2_out0", +}; +#define mux_plld_out0_plld2_out0_idx NULL + +static const char *mux_d_audio_clk[] = { + "pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync", + "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync", +}; +static u32 mux_d_audio_clk_idx[] = { + [0] = 0, [1] = 0x8000, [2] = 0xc000, [3] = 0xE000, [4] = 0xE001, + [5] = 0xE002, [6] = 0xE003, [7] = 0xE004, [8] = 0xE005, [9] = 0xE007, +}; + +static const char *mux_pllmcp_clkm[] = { + "pll_m_out0", "pll_c_out0", "pll_p_out0", "clk_m", "pll_m_ud", +}; + +static const struct clk_div_table pll_re_div_table[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 3 }, + { .val = 3, .div = 4 }, + { .val = 4, .div = 5 }, + { .val = 5, .div = 6 }, + { .val = 0, .div = 0 }, +}; + +static struct clk *clks[clk_max]; +static struct clk_onecell_data clk_data; + +static unsigned long osc_freq; +static unsigned long pll_ref_freq; + +static int __init tegra114_osc_clk_init(void __iomem *clk_base) +{ + struct clk *clk; + u32 val, pll_ref_div; + + val = readl_relaxed(clk_base + OSC_CTRL); + + osc_freq = tegra114_input_freq[val >> OSC_CTRL_OSC_FREQ_SHIFT]; + if (!osc_freq) { + WARN_ON(1); + return -EINVAL; + } + + /* clk_m */ + clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT, + osc_freq); + clk_register_clkdev(clk, "clk_m", NULL); + clks[clk_m] = clk; + + /* pll_ref */ + val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3; + pll_ref_div = 1 << val; + clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m", + CLK_SET_RATE_PARENT, 1, pll_ref_div); + clk_register_clkdev(clk, "pll_ref", NULL); + clks[pll_ref] = clk; + + pll_ref_freq = osc_freq / pll_ref_div; + + return 0; +} + +static void __init tegra114_fixed_clk_init(void __iomem *clk_base) +{ + struct clk *clk; + + /* clk_32k */ + clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, CLK_IS_ROOT, + 32768); + clk_register_clkdev(clk, "clk_32k", NULL); + clks[clk_32k] = clk; + + /* clk_m_div2 */ + clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "clk_m_div2", NULL); + clks[clk_m_div2] = clk; + + /* clk_m_div4 */ + clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m", + CLK_SET_RATE_PARENT, 1, 4); + clk_register_clkdev(clk, "clk_m_div4", NULL); + clks[clk_m_div4] = clk; + +} + +static __init void tegra114_utmi_param_configure(void __iomem *clk_base) +{ + u32 reg; + int i; + + for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) { + if (osc_freq == utmi_parameters[i].osc_frequency) + break; + } + + if (i >= ARRAY_SIZE(utmi_parameters)) { + pr_err("%s: Unexpected oscillator freq %lu\n", __func__, + osc_freq); + return; + } + + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2); + + /* Program UTMIP PLL stable and active counts */ + /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */ + reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0); + reg |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count); + + reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0); + + reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(utmi_parameters[i]. + active_delay_count); + + /* Remove power downs from UTMIP PLL control bits */ + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN; + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN; + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN; + + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2); + + /* Program UTMIP PLL delay and oscillator frequency counts */ + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1); + reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0); + + reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(utmi_parameters[i]. + enable_delay_count); + + reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0); + reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(utmi_parameters[i]. + xtal_freq_count); + + /* Remove power downs from UTMIP PLL control bits */ + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN; + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1); + + /* Setup HW control of UTMIPLL */ + reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0); + reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET; + reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL; + reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE; + writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); + + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1); + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1); + + udelay(1); + + /* Setup SW override of UTMIPLL assuming USB2.0 + ports are assigned to USB2 */ + reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0); + reg |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL; + reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE; + writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); + + udelay(1); + + /* Enable HW control UTMIPLL */ + reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0); + reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE; + writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); +} + +static void __init _clip_vco_min(struct tegra_clk_pll_params *pll_params) +{ + pll_params->vco_min = + DIV_ROUND_UP(pll_params->vco_min, pll_ref_freq) * pll_ref_freq; +} + +static int __init _setup_dynamic_ramp(struct tegra_clk_pll_params *pll_params, + void __iomem *clk_base) +{ + u32 val; + u32 step_a, step_b; + + switch (pll_ref_freq) { + case 12000000: + case 13000000: + case 26000000: + step_a = 0x2B; + step_b = 0x0B; + break; + case 16800000: + step_a = 0x1A; + step_b = 0x09; + break; + case 19200000: + step_a = 0x12; + step_b = 0x08; + break; + default: + pr_err("%s: Unexpected reference rate %lu\n", + __func__, pll_ref_freq); + WARN_ON(1); + return -EINVAL; + } + + val = step_a << pll_params->stepa_shift; + val |= step_b << pll_params->stepb_shift; + writel_relaxed(val, clk_base + pll_params->dyn_ramp_reg); + + return 0; +} + +static void __init _init_iddq(struct tegra_clk_pll_params *pll_params, + void __iomem *clk_base) +{ + u32 val, val_iddq; + + val = readl_relaxed(clk_base + pll_params->base_reg); + val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg); + + if (val & BIT(30)) + WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx)); + else { + val_iddq |= BIT(pll_params->iddq_bit_idx); + writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg); + } +} + +static void __init tegra114_pll_init(void __iomem *clk_base, + void __iomem *pmc) +{ + u32 val; + struct clk *clk; + + /* PLLC */ + _clip_vco_min(&pll_c_params); + if (_setup_dynamic_ramp(&pll_c_params, clk_base) >= 0) { + _init_iddq(&pll_c_params, clk_base); + clk = tegra_clk_register_pllxc("pll_c", "pll_ref", clk_base, + pmc, 0, 0, &pll_c_params, TEGRA_PLL_USE_LOCK, + pll_c_freq_table, NULL); + clk_register_clkdev(clk, "pll_c", NULL); + clks[pll_c] = clk; + + /* PLLC_OUT1 */ + clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", + clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", + clk_base + PLLC_OUT, 1, 0, + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_c_out1", NULL); + clks[pll_c_out1] = clk; + } + + /* PLLC2 */ + _clip_vco_min(&pll_c2_params); + clk = tegra_clk_register_pllc("pll_c2", "pll_ref", clk_base, pmc, 0, 0, + &pll_c2_params, TEGRA_PLL_USE_LOCK, + pll_cx_freq_table, NULL); + clk_register_clkdev(clk, "pll_c2", NULL); + clks[pll_c2] = clk; + + /* PLLC3 */ + _clip_vco_min(&pll_c3_params); + clk = tegra_clk_register_pllc("pll_c3", "pll_ref", clk_base, pmc, 0, 0, + &pll_c3_params, TEGRA_PLL_USE_LOCK, + pll_cx_freq_table, NULL); + clk_register_clkdev(clk, "pll_c3", NULL); + clks[pll_c3] = clk; + + /* PLLP */ + clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, pmc, 0, + 408000000, &pll_p_params, + TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK, + pll_p_freq_table, NULL); + clk_register_clkdev(clk, "pll_p", NULL); + clks[pll_p] = clk; + + /* PLLP_OUT1 */ + clk = tegra_clk_register_divider("pll_p_out1_div", "pll_p", + clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED | + TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out1", "pll_p_out1_div", + clk_base + PLLP_OUTA, 1, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out1", NULL); + clks[pll_p_out1] = clk; + + /* 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); + 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, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out2", NULL); + clks[pll_p_out2] = clk; + + /* PLLP_OUT3 */ + clk = tegra_clk_register_divider("pll_p_out3_div", "pll_p", + clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED | + TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out3", "pll_p_out3_div", + clk_base + PLLP_OUTB, 1, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out3", NULL); + clks[pll_p_out3] = clk; + + /* PLLP_OUT4 */ + clk = tegra_clk_register_divider("pll_p_out4_div", "pll_p", + clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED | + TEGRA_DIVIDER_ROUND_UP, 24, 8, 1, + &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out4", "pll_p_out4_div", + clk_base + PLLP_OUTB, 17, 16, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out4", NULL); + clks[pll_p_out4] = clk; + + /* PLLM */ + _clip_vco_min(&pll_m_params); + clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc, + CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0, + &pll_m_params, TEGRA_PLL_USE_LOCK, + pll_m_freq_table, NULL); + clk_register_clkdev(clk, "pll_m", NULL); + clks[pll_m] = clk; + + /* PLLM_OUT1 */ + clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m", + clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", + clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_m_out1", NULL); + clks[pll_m_out1] = clk; + + /* PLLM_UD */ + clk = clk_register_fixed_factor(NULL, "pll_m_ud", "pll_m", + CLK_SET_RATE_PARENT, 1, 1); + + /* PLLX */ + _clip_vco_min(&pll_x_params); + if (_setup_dynamic_ramp(&pll_x_params, clk_base) >= 0) { + _init_iddq(&pll_x_params, clk_base); + clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base, + pmc, CLK_IGNORE_UNUSED, 0, &pll_x_params, + TEGRA_PLL_USE_LOCK, pll_x_freq_table, NULL); + clk_register_clkdev(clk, "pll_x", NULL); + clks[pll_x] = clk; + } + + /* PLLX_OUT0 */ + clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_x_out0", NULL); + clks[pll_x_out0] = clk; + + /* PLLU */ + val = readl(clk_base + pll_u_params.base_reg); + val &= ~BIT(24); /* disable PLLU_OVERRIDE */ + writel(val, clk_base + pll_u_params.base_reg); + + clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc, 0, + 0, &pll_u_params, TEGRA_PLLU | + TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, pll_u_freq_table, &pll_u_lock); + clk_register_clkdev(clk, "pll_u", NULL); + clks[pll_u] = clk; + + tegra114_utmi_param_configure(clk_base); + + /* PLLU_480M */ + clk = clk_register_gate(NULL, "pll_u_480M", "pll_u", + CLK_SET_RATE_PARENT, clk_base + PLLU_BASE, + 22, 0, &pll_u_lock); + clk_register_clkdev(clk, "pll_u_480M", NULL); + clks[pll_u_480M] = clk; + + /* PLLU_60M */ + clk = clk_register_fixed_factor(NULL, "pll_u_60M", "pll_u", + CLK_SET_RATE_PARENT, 1, 8); + clk_register_clkdev(clk, "pll_u_60M", NULL); + clks[pll_u_60M] = clk; + + /* PLLU_48M */ + clk = clk_register_fixed_factor(NULL, "pll_u_48M", "pll_u", + CLK_SET_RATE_PARENT, 1, 10); + clk_register_clkdev(clk, "pll_u_48M", NULL); + clks[pll_u_48M] = clk; + + /* PLLU_12M */ + clk = clk_register_fixed_factor(NULL, "pll_u_12M", "pll_u", + CLK_SET_RATE_PARENT, 1, 40); + clk_register_clkdev(clk, "pll_u_12M", NULL); + clks[pll_u_12M] = clk; + + /* PLLD */ + clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc, 0, + 0, &pll_d_params, + TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, pll_d_freq_table, &pll_d_lock); + clk_register_clkdev(clk, "pll_d", NULL); + clks[pll_d] = clk; + + /* PLLD_OUT0 */ + clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_d_out0", NULL); + clks[pll_d_out0] = clk; + + /* PLLD2 */ + clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc, 0, + 0, &pll_d2_params, + TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, pll_d_freq_table, &pll_d2_lock); + clk_register_clkdev(clk, "pll_d2", NULL); + clks[pll_d2] = clk; + + /* PLLD2_OUT0 */ + clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_d2_out0", NULL); + clks[pll_d2_out0] = clk; + + /* PLLA */ + clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, pmc, 0, + 0, &pll_a_params, TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_USE_LOCK, pll_a_freq_table, NULL); + clk_register_clkdev(clk, "pll_a", NULL); + clks[pll_a] = clk; + + /* PLLA_OUT0 */ + clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a", + clk_base + PLLA_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div", + clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED | + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_a_out0", NULL); + clks[pll_a_out0] = clk; + + /* PLLRE */ + _clip_vco_min(&pll_re_vco_params); + clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc, + 0, 0, &pll_re_vco_params, TEGRA_PLL_USE_LOCK, + NULL, &pll_re_lock, pll_ref_freq); + clk_register_clkdev(clk, "pll_re_vco", NULL); + clks[pll_re_vco] = clk; + + clk = clk_register_divider_table(NULL, "pll_re_out", "pll_re_vco", 0, + clk_base + PLLRE_BASE, 16, 4, 0, + pll_re_div_table, &pll_re_lock); + clk_register_clkdev(clk, "pll_re_out", NULL); + clks[pll_re_out] = clk; + + /* PLLE */ + clk = tegra_clk_register_plle_tegra114("pll_e_out0", "pll_re_vco", + clk_base, 0, 100000000, &pll_e_params, + pll_e_freq_table, NULL); + clk_register_clkdev(clk, "pll_e_out0", NULL); + clks[pll_e_out0] = clk; +} + +static const char *mux_audio_sync_clk[] = { "spdif_in_sync", "i2s0_sync", + "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync", +}; + +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2", + "clk_m_div4", "extern1", +}; + +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2", + "clk_m_div4", "extern2", +}; + +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2", + "clk_m_div4", "extern3", +}; + +static void __init tegra114_audio_clk_init(void __iomem *clk_base) +{ + struct clk *clk; + + /* spdif_in_sync */ + clk = tegra_clk_register_sync_source("spdif_in_sync", 24000000, + 24000000); + clk_register_clkdev(clk, "spdif_in_sync", NULL); + clks[spdif_in_sync] = clk; + + /* i2s0_sync */ + clk = tegra_clk_register_sync_source("i2s0_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s0_sync", NULL); + clks[i2s0_sync] = clk; + + /* i2s1_sync */ + clk = tegra_clk_register_sync_source("i2s1_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s1_sync", NULL); + clks[i2s1_sync] = clk; + + /* i2s2_sync */ + clk = tegra_clk_register_sync_source("i2s2_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s2_sync", NULL); + clks[i2s2_sync] = clk; + + /* i2s3_sync */ + clk = tegra_clk_register_sync_source("i2s3_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s3_sync", NULL); + clks[i2s3_sync] = clk; + + /* i2s4_sync */ + clk = tegra_clk_register_sync_source("i2s4_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s4_sync", NULL); + clks[i2s4_sync] = clk; + + /* vimclk_sync */ + clk = tegra_clk_register_sync_source("vimclk_sync", 24000000, 24000000); + clk_register_clkdev(clk, "vimclk_sync", NULL); + clks[vimclk_sync] = clk; + + /* audio0 */ + clk = clk_register_mux(NULL, "audio0_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S0, 0, 3, 0, + NULL); + clks[audio0_mux] = clk; + clk = clk_register_gate(NULL, "audio0", "audio0_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S0, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio0", NULL); + clks[audio0] = clk; + + /* audio1 */ + clk = clk_register_mux(NULL, "audio1_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S1, 0, 3, 0, + NULL); + clks[audio1_mux] = clk; + clk = clk_register_gate(NULL, "audio1", "audio1_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S1, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio1", NULL); + clks[audio1] = clk; + + /* audio2 */ + clk = clk_register_mux(NULL, "audio2_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S2, 0, 3, 0, + NULL); + clks[audio2_mux] = clk; + clk = clk_register_gate(NULL, "audio2", "audio2_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S2, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio2", NULL); + clks[audio2] = clk; + + /* audio3 */ + clk = clk_register_mux(NULL, "audio3_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S3, 0, 3, 0, + NULL); + clks[audio3_mux] = clk; + clk = clk_register_gate(NULL, "audio3", "audio3_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S3, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio3", NULL); + clks[audio3] = clk; + + /* audio4 */ + clk = clk_register_mux(NULL, "audio4_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S4, 0, 3, 0, + NULL); + clks[audio4_mux] = clk; + clk = clk_register_gate(NULL, "audio4", "audio4_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S4, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio4", NULL); + clks[audio4] = clk; + + /* spdif */ + clk = clk_register_mux(NULL, "spdif_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_SPDIF, 0, 3, 0, + NULL); + clks[spdif_mux] = clk; + clk = clk_register_gate(NULL, "spdif", "spdif_mux", 0, + clk_base + AUDIO_SYNC_CLK_SPDIF, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "spdif", NULL); + clks[spdif] = clk; + + /* audio0_2x */ + clk = clk_register_fixed_factor(NULL, "audio0_doubler", "audio0", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio0_div", "audio0_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 24, 1, + 0, &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio0_2x", "audio0_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 113, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio0_2x", NULL); + clks[audio0_2x] = clk; + + /* audio1_2x */ + clk = clk_register_fixed_factor(NULL, "audio1_doubler", "audio1", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio1_div", "audio1_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 25, 1, + 0, &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio1_2x", "audio1_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 114, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio1_2x", NULL); + clks[audio1_2x] = clk; + + /* audio2_2x */ + clk = clk_register_fixed_factor(NULL, "audio2_doubler", "audio2", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio2_div", "audio2_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 26, 1, + 0, &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio2_2x", "audio2_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 115, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio2_2x", NULL); + clks[audio2_2x] = clk; + + /* audio3_2x */ + clk = clk_register_fixed_factor(NULL, "audio3_doubler", "audio3", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio3_div", "audio3_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 27, 1, + 0, &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio3_2x", "audio3_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 116, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio3_2x", NULL); + clks[audio3_2x] = clk; + + /* audio4_2x */ + clk = clk_register_fixed_factor(NULL, "audio4_doubler", "audio4", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio4_div", "audio4_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 28, 1, + 0, &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio4_2x", "audio4_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 117, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio4_2x", NULL); + clks[audio4_2x] = clk; + + /* spdif_2x */ + clk = clk_register_fixed_factor(NULL, "spdif_doubler", "spdif", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("spdif_div", "spdif_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 29, 1, + 0, &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("spdif_2x", "spdif_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 118, + &periph_v_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "spdif_2x", NULL); + clks[spdif_2x] = clk; +} + +static void __init tegra114_pmc_clk_init(void __iomem *pmc_base) +{ + struct clk *clk; + + /* clk_out_1 */ + clk = clk_register_mux(NULL, "clk_out_1_mux", clk_out1_parents, + ARRAY_SIZE(clk_out1_parents), 0, + pmc_base + PMC_CLK_OUT_CNTRL, 6, 3, 0, + &clk_out_lock); + clks[clk_out_1_mux] = clk; + clk = clk_register_gate(NULL, "clk_out_1", "clk_out_1_mux", 0, + pmc_base + PMC_CLK_OUT_CNTRL, 2, 0, + &clk_out_lock); + clk_register_clkdev(clk, "extern1", "clk_out_1"); + clks[clk_out_1] = clk; + + /* clk_out_2 */ + clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents, + ARRAY_SIZE(clk_out1_parents), 0, + pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0, + &clk_out_lock); + clks[clk_out_2_mux] = clk; + clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0, + pmc_base + PMC_CLK_OUT_CNTRL, 10, 0, + &clk_out_lock); + clk_register_clkdev(clk, "extern2", "clk_out_2"); + clks[clk_out_2] = clk; + + /* clk_out_3 */ + clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents, + ARRAY_SIZE(clk_out1_parents), 0, + pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0, + &clk_out_lock); + clks[clk_out_3_mux] = clk; + clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0, + pmc_base + PMC_CLK_OUT_CNTRL, 18, 0, + &clk_out_lock); + clk_register_clkdev(clk, "extern3", "clk_out_3"); + clks[clk_out_3] = clk; + + /* blink */ + clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0, + pmc_base + PMC_DPD_PADS_ORIDE, + PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); + clk = clk_register_gate(NULL, "blink", "blink_override", 0, + pmc_base + PMC_CTRL, + PMC_CTRL_BLINK_ENB, 0, NULL); + clk_register_clkdev(clk, "blink", NULL); + clks[blink] = clk; + +} + +static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", + "pll_p_out3", "pll_p_out2", "unused", + "clk_32k", "pll_m_out1" }; + +static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", + "pll_p", "pll_p_out4", "unused", + "unused", "pll_x" }; + +static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", + "pll_p", "pll_p_out4", "unused", + "unused", "pll_x", "pll_x_out0" }; + +static void __init tegra114_super_clk_init(void __iomem *clk_base) +{ + struct clk *clk; + + /* CCLKG */ + clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents, + ARRAY_SIZE(cclk_g_parents), + CLK_SET_RATE_PARENT, + clk_base + CCLKG_BURST_POLICY, + 0, 4, 0, 0, NULL); + clk_register_clkdev(clk, "cclk_g", NULL); + clks[cclk_g] = clk; + + /* CCLKLP */ + clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents, + ARRAY_SIZE(cclk_lp_parents), + CLK_SET_RATE_PARENT, + clk_base + CCLKLP_BURST_POLICY, + 0, 4, 8, 9, NULL); + clk_register_clkdev(clk, "cclk_lp", NULL); + clks[cclk_lp] = clk; + + /* SCLK */ + clk = tegra_clk_register_super_mux("sclk", sclk_parents, + ARRAY_SIZE(sclk_parents), + CLK_SET_RATE_PARENT, + clk_base + SCLK_BURST_POLICY, + 0, 4, 0, 0, NULL); + clk_register_clkdev(clk, "sclk", NULL); + clks[sclk] = clk; + + /* HCLK */ + clk = clk_register_divider(NULL, "hclk_div", "sclk", 0, + clk_base + SYSTEM_CLK_RATE, 4, 2, 0, + &sysrate_lock); + clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT | + CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE, + 7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); + clk_register_clkdev(clk, "hclk", NULL); + clks[hclk] = clk; + + /* PCLK */ + clk = clk_register_divider(NULL, "pclk_div", "hclk", 0, + clk_base + SYSTEM_CLK_RATE, 0, 2, 0, + &sysrate_lock); + clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT | + CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE, + 3, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); + clk_register_clkdev(clk, "pclk", NULL); + clks[pclk] = clk; +} + +static struct tegra_periph_init_data tegra_periph_clk_list[] = { + TEGRA_INIT_DATA_MUX("i2s0", NULL, "tegra30-i2s.0", mux_pllaout0_audio0_2x_pllp_clkm, CLK_SOURCE_I2S0, 30, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s0), + TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra30-i2s.1", mux_pllaout0_audio1_2x_pllp_clkm, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1), + TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra30-i2s.2", mux_pllaout0_audio2_2x_pllp_clkm, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2), + TEGRA_INIT_DATA_MUX("i2s3", NULL, "tegra30-i2s.3", mux_pllaout0_audio3_2x_pllp_clkm, CLK_SOURCE_I2S3, 101, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s3), + TEGRA_INIT_DATA_MUX("i2s4", NULL, "tegra30-i2s.4", mux_pllaout0_audio4_2x_pllp_clkm, CLK_SOURCE_I2S4, 102, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s4), + TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra30-spdif", mux_pllaout0_audio_2x_pllp_clkm, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out), + TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra30-spdif", mux_pllp_pllc_pllm, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in), + TEGRA_INIT_DATA_MUX("pwm", NULL, "pwm", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_PWM, 17, &periph_l_regs, TEGRA_PERIPH_ON_APB, pwm), + TEGRA_INIT_DATA_MUX("adx", NULL, "adx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX, 154, &periph_w_regs, TEGRA_PERIPH_ON_APB, adx), + TEGRA_INIT_DATA_MUX("amx", NULL, "amx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX, 153, &periph_w_regs, TEGRA_PERIPH_ON_APB, amx), + TEGRA_INIT_DATA_MUX("hda", "hda", "tegra30-hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA, 125, &periph_v_regs, TEGRA_PERIPH_ON_APB, hda), + TEGRA_INIT_DATA_MUX("hda2codec_2x", "hda2codec", "tegra30-hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, &periph_v_regs, TEGRA_PERIPH_ON_APB, hda2codec_2x), + TEGRA_INIT_DATA_MUX("sbc1", NULL, "tegra11-spi.0", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1), + TEGRA_INIT_DATA_MUX("sbc2", NULL, "tegra11-spi.1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2), + TEGRA_INIT_DATA_MUX("sbc3", NULL, "tegra11-spi.2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3), + TEGRA_INIT_DATA_MUX("sbc4", NULL, "tegra11-spi.3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4), + TEGRA_INIT_DATA_MUX("sbc5", NULL, "tegra11-spi.4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC5, 104, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc5), + TEGRA_INIT_DATA_MUX("sbc6", NULL, "tegra11-spi.5", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC6, 105, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc6), + TEGRA_INIT_DATA_MUX8("ndflash", NULL, "tegra_nand", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_u_regs, TEGRA_PERIPH_ON_APB, ndspeed), + TEGRA_INIT_DATA_MUX8("ndspeed", NULL, "tegra_nand_speed", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDSPEED, 80, &periph_u_regs, TEGRA_PERIPH_ON_APB, ndspeed), + TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir), + TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1), + TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2), + TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3), + TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4), + TEGRA_INIT_DATA_INT("vde", NULL, "vde", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde), + TEGRA_INIT_DATA_MUX_FLAGS("csite", NULL, "csite", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, TEGRA_PERIPH_ON_APB, csite, CLK_IGNORE_UNUSED), + TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, TEGRA_PERIPH_ON_APB, la), + TEGRA_INIT_DATA_MUX("trace", NULL, "trace", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_TRACE, 77, &periph_u_regs, TEGRA_PERIPH_ON_APB, trace), + TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr), + TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor), + TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi), + TEGRA_INIT_DATA_I2C("i2c1", "div-clk", "tegra11-i2c.0", mux_pllp_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, i2c1), + TEGRA_INIT_DATA_I2C("i2c2", "div-clk", "tegra11-i2c.1", mux_pllp_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, i2c2), + TEGRA_INIT_DATA_I2C("i2c3", "div-clk", "tegra11-i2c.2", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, i2c3), + TEGRA_INIT_DATA_I2C("i2c4", "div-clk", "tegra11-i2c.3", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, &periph_v_regs, i2c4), + TEGRA_INIT_DATA_I2C("i2c5", "div-clk", "tegra11-i2c.4", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, &periph_h_regs, i2c5), + TEGRA_INIT_DATA_UART("uarta", NULL, "tegra_uart.0", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTA, 6, &periph_l_regs, uarta), + TEGRA_INIT_DATA_UART("uartb", NULL, "tegra_uart.1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, &periph_l_regs, uartb), + TEGRA_INIT_DATA_UART("uartc", NULL, "tegra_uart.2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, &periph_h_regs, uartc), + TEGRA_INIT_DATA_UART("uartd", NULL, "tegra_uart.3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, &periph_u_regs, uartd), + TEGRA_INIT_DATA_INT("3d", NULL, "3d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_3D, 24, &periph_l_regs, 0, gr_3d), + TEGRA_INIT_DATA_INT("2d", NULL, "2d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr_2d), + 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("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), + TEGRA_INIT_DATA_MUX("cilab", "cilab", "tegra_camera", mux_pllp_pllc_clkm, CLK_SOURCE_CILAB, 144, &periph_w_regs, 0, cilab), + TEGRA_INIT_DATA_MUX("cilcd", "cilcd", "tegra_camera", mux_pllp_pllc_clkm, CLK_SOURCE_CILCD, 145, &periph_w_regs, 0, cilcd), + TEGRA_INIT_DATA_MUX("cile", "cile", "tegra_camera", mux_pllp_pllc_clkm, CLK_SOURCE_CILE, 146, &periph_w_regs, 0, cile), + TEGRA_INIT_DATA_MUX("dsialp", "dsialp", "tegradc.0", mux_pllp_pllc_clkm, CLK_SOURCE_DSIALP, 147, &periph_w_regs, 0, dsialp), + TEGRA_INIT_DATA_MUX("dsiblp", "dsiblp", "tegradc.1", mux_pllp_pllc_clkm, CLK_SOURCE_DSIBLP, 148, &periph_w_regs, 0, dsiblp), + TEGRA_INIT_DATA_MUX("tsensor", NULL, "tegra-tsensor", mux_pllp_pllc_clkm_clk32, CLK_SOURCE_TSENSOR, 100, &periph_v_regs, TEGRA_PERIPH_ON_APB, tsensor), + TEGRA_INIT_DATA_MUX("actmon", NULL, "actmon", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_ACTMON, 119, &periph_v_regs, 0, actmon), + TEGRA_INIT_DATA_MUX8("extern1", NULL, "extern1", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, &periph_v_regs, 0, extern1), + TEGRA_INIT_DATA_MUX8("extern2", NULL, "extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, &periph_v_regs, 0, extern2), + TEGRA_INIT_DATA_MUX8("extern3", NULL, "extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, &periph_v_regs, 0, extern3), + 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_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), + TEGRA_INIT_DATA_XUSB("xusb_fs_src", "fs_src", "tegra_xhci", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_fs_src), + TEGRA_INIT_DATA_XUSB("xusb_ss_src", "ss_src", "tegra_xhci", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_ss_src), + TEGRA_INIT_DATA_XUSB("xusb_dev_src", "dev_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, &periph_u_regs, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, xusb_dev_src), + TEGRA_INIT_DATA_AUDIO("d_audio", "d_audio", "tegra30-ahub", CLK_SOURCE_D_AUDIO, 106, &periph_v_regs, TEGRA_PERIPH_ON_APB, d_audio), + TEGRA_INIT_DATA_AUDIO("dam0", NULL, "tegra30-dam.0", CLK_SOURCE_DAM0, 108, &periph_v_regs, TEGRA_PERIPH_ON_APB, dam0), + TEGRA_INIT_DATA_AUDIO("dam1", NULL, "tegra30-dam.1", CLK_SOURCE_DAM1, 109, &periph_v_regs, TEGRA_PERIPH_ON_APB, dam1), + TEGRA_INIT_DATA_AUDIO("dam2", NULL, "tegra30-dam.2", CLK_SOURCE_DAM2, 110, &periph_v_regs, TEGRA_PERIPH_ON_APB, dam2), +}; + +static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = { + TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP1, 29, 7, 27, &periph_l_regs, 0, disp1), + TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP2, 29, 7, 26, &periph_l_regs, 0, disp2), +}; + +static __init void tegra114_periph_clk_init(void __iomem *clk_base) +{ + struct tegra_periph_init_data *data; + struct clk *clk; + int i; + u32 val; + + /* apbdma */ + clk = tegra_clk_register_periph_gate("apbdma", "clk_m", 0, clk_base, + 0, 34, &periph_h_regs, + periph_clk_enb_refcnt); + clks[apbdma] = clk; + + /* rtc */ + clk = tegra_clk_register_periph_gate("rtc", "clk_32k", + TEGRA_PERIPH_ON_APB | + TEGRA_PERIPH_NO_RESET, clk_base, + 0, 4, &periph_l_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "rtc-tegra"); + clks[rtc] = clk; + + /* kbc */ + clk = tegra_clk_register_periph_gate("kbc", "clk_32k", + TEGRA_PERIPH_ON_APB | + TEGRA_PERIPH_NO_RESET, clk_base, + 0, 36, &periph_h_regs, + periph_clk_enb_refcnt); + clks[kbc] = clk; + + /* timer */ + clk = tegra_clk_register_periph_gate("timer", "clk_m", 0, clk_base, + 0, 5, &periph_l_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "timer"); + clks[timer] = clk; + + /* kfuse */ + clk = tegra_clk_register_periph_gate("kfuse", "clk_m", + TEGRA_PERIPH_ON_APB, clk_base, 0, 40, + &periph_h_regs, periph_clk_enb_refcnt); + clks[kfuse] = clk; + + /* fuse */ + clk = tegra_clk_register_periph_gate("fuse", "clk_m", + TEGRA_PERIPH_ON_APB, clk_base, 0, 39, + &periph_h_regs, periph_clk_enb_refcnt); + clks[fuse] = clk; + + /* fuse_burn */ + clk = tegra_clk_register_periph_gate("fuse_burn", "clk_m", + TEGRA_PERIPH_ON_APB, clk_base, 0, 39, + &periph_h_regs, periph_clk_enb_refcnt); + clks[fuse_burn] = clk; + + /* apbif */ + clk = tegra_clk_register_periph_gate("apbif", "clk_m", + TEGRA_PERIPH_ON_APB, clk_base, 0, 107, + &periph_v_regs, periph_clk_enb_refcnt); + clks[apbif] = clk; + + /* hda2hdmi */ + clk = tegra_clk_register_periph_gate("hda2hdmi", "clk_m", + TEGRA_PERIPH_ON_APB, clk_base, 0, 128, + &periph_w_regs, periph_clk_enb_refcnt); + clks[hda2hdmi] = clk; + + /* vcp */ + clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0, clk_base, 0, + 29, &periph_l_regs, + periph_clk_enb_refcnt); + clks[vcp] = clk; + + /* bsea */ + clk = tegra_clk_register_periph_gate("bsea", "clk_m", 0, clk_base, + 0, 62, &periph_h_regs, + periph_clk_enb_refcnt); + clks[bsea] = clk; + + /* bsev */ + clk = tegra_clk_register_periph_gate("bsev", "clk_m", 0, clk_base, + 0, 63, &periph_h_regs, + periph_clk_enb_refcnt); + clks[bsev] = clk; + + /* mipi-cal */ + clk = tegra_clk_register_periph_gate("mipi-cal", "clk_m", 0, clk_base, + 0, 56, &periph_h_regs, + periph_clk_enb_refcnt); + clks[mipi_cal] = clk; + + /* usbd */ + clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base, + 0, 22, &periph_l_regs, + periph_clk_enb_refcnt); + clks[usbd] = clk; + + /* usb2 */ + clk = tegra_clk_register_periph_gate("usb2", "clk_m", 0, clk_base, + 0, 58, &periph_h_regs, + periph_clk_enb_refcnt); + clks[usb2] = clk; + + /* usb3 */ + clk = tegra_clk_register_periph_gate("usb3", "clk_m", 0, clk_base, + 0, 59, &periph_h_regs, + periph_clk_enb_refcnt); + clks[usb3] = clk; + + /* csi */ + clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base, + 0, 52, &periph_h_regs, + periph_clk_enb_refcnt); + clks[csi] = clk; + + /* isp */ + clk = tegra_clk_register_periph_gate("isp", "clk_m", 0, clk_base, 0, + 23, &periph_l_regs, + periph_clk_enb_refcnt); + clks[isp] = clk; + + /* csus */ + clk = tegra_clk_register_periph_gate("csus", "clk_m", + TEGRA_PERIPH_NO_RESET, clk_base, 0, 92, + &periph_u_regs, periph_clk_enb_refcnt); + clks[csus] = clk; + + /* dds */ + clk = tegra_clk_register_periph_gate("dds", "clk_m", + TEGRA_PERIPH_ON_APB, clk_base, 0, 150, + &periph_w_regs, periph_clk_enb_refcnt); + clks[dds] = clk; + + /* dp2 */ + clk = tegra_clk_register_periph_gate("dp2", "clk_m", + TEGRA_PERIPH_ON_APB, clk_base, 0, 152, + &periph_w_regs, periph_clk_enb_refcnt); + clks[dp2] = clk; + + /* dtv */ + clk = tegra_clk_register_periph_gate("dtv", "clk_m", + TEGRA_PERIPH_ON_APB, clk_base, 0, 79, + &periph_u_regs, periph_clk_enb_refcnt); + clks[dtv] = clk; + + /* dsia */ + clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0, + ARRAY_SIZE(mux_plld_out0_plld2_out0), 0, + clk_base + PLLD_BASE, 25, 1, 0, &pll_d_lock); + clks[dsia_mux] = clk; + clk = tegra_clk_register_periph_gate("dsia", "dsia_mux", 0, clk_base, + 0, 48, &periph_h_regs, + periph_clk_enb_refcnt); + clks[dsia] = clk; + + /* dsib */ + clk = clk_register_mux(NULL, "dsib_mux", mux_plld_out0_plld2_out0, + ARRAY_SIZE(mux_plld_out0_plld2_out0), 0, + clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock); + clks[dsib_mux] = clk; + clk = tegra_clk_register_periph_gate("dsib", "dsib_mux", 0, clk_base, + 0, 82, &periph_u_regs, + periph_clk_enb_refcnt); + clks[dsib] = clk; + + /* xusb_hs_src */ + val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC); + val |= BIT(25); /* always select PLLU_60M */ + writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC); + + clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0, + 1, 1); + clks[xusb_hs_src] = clk; + + /* xusb_host */ + clk = tegra_clk_register_periph_gate("xusb_host", "xusb_host_src", 0, + clk_base, 0, 89, &periph_u_regs, + periph_clk_enb_refcnt); + clks[xusb_host] = clk; + + /* xusb_ss */ + clk = tegra_clk_register_periph_gate("xusb_ss", "xusb_ss_src", 0, + clk_base, 0, 156, &periph_w_regs, + periph_clk_enb_refcnt); + clks[xusb_host] = clk; + + /* xusb_dev */ + clk = tegra_clk_register_periph_gate("xusb_dev", "xusb_dev_src", 0, + clk_base, 0, 95, &periph_u_regs, + periph_clk_enb_refcnt); + clks[xusb_dev] = clk; + + /* emc */ + clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, + ARRAY_SIZE(mux_pllmcp_clkm), 0, + clk_base + CLK_SOURCE_EMC, + 29, 3, 0, NULL); + clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, + CLK_IGNORE_UNUSED, 57, &periph_h_regs, + periph_clk_enb_refcnt); + clks[emc] = 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, data->parent_names, + data->num_parents, &data->periph, + clk_base, data->offset, data->flags); + clks[data->clk_id] = clk; + } + + for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) { + data = &tegra_periph_nodiv_clk_list[i]; + clk = tegra_clk_register_periph_nodiv(data->name, + data->parent_names, data->num_parents, + &data->periph, clk_base, data->offset); + clks[data->clk_id] = clk; + } +} + +static struct tegra_cpu_car_ops tegra114_cpu_car_ops; + +static const struct of_device_id pmc_match[] __initconst = { + { .compatible = "nvidia,tegra114-pmc" }, + {}, +}; + +static __initdata struct tegra_clk_init_table init_table[] = { + {uarta, pll_p, 408000000, 0}, + {uartb, pll_p, 408000000, 0}, + {uartc, pll_p, 408000000, 0}, + {uartd, pll_p, 408000000, 1}, + {pll_a, clk_max, 564480000, 1}, + {pll_a_out0, clk_max, 11289600, 1}, + {extern1, pll_a_out0, 0, 1}, + {clk_out_1_mux, extern1, 0, 1}, + {clk_out_1, clk_max, 0, 1}, + {i2s0, pll_a_out0, 11289600, 0}, + {i2s1, pll_a_out0, 11289600, 0}, + {i2s2, pll_a_out0, 11289600, 0}, + {i2s3, pll_a_out0, 11289600, 0}, + {i2s4, pll_a_out0, 11289600, 0}, + {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */ +}; + +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) +{ + struct device_node *node; + int i; + + clk_base = of_iomap(np, 0); + if (!clk_base) { + pr_err("ioremap tegra114 CAR failed\n"); + return; + } + + node = of_find_matching_node(NULL, pmc_match); + if (!node) { + pr_err("Failed to find pmc node\n"); + WARN_ON(1); + return; + } + + pmc_base = of_iomap(node, 0); + if (!pmc_base) { + pr_err("Can't map pmc registers\n"); + WARN_ON(1); + return; + } + + if (tegra114_osc_clk_init(clk_base) < 0) + return; + + tegra114_fixed_clk_init(clk_base); + tegra114_pll_init(clk_base, pmc_base); + tegra114_periph_clk_init(clk_base); + tegra114_audio_clk_init(clk_base); + tegra114_pmc_clk_init(pmc_base); + tegra114_super_clk_init(clk_base); + + for (i = 0; i < ARRAY_SIZE(clks); i++) { + if (IS_ERR(clks[i])) { + pr_err + ("Tegra114 clk %d: register failed with %ld\n", + i, PTR_ERR(clks[i])); + } + if (!clks[i]) + clks[i] = ERR_PTR(-EINVAL); + } + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + + tegra_clk_apply_init_table = tegra114_clock_apply_init_table; + + tegra_cpu_car_ops = &tegra114_cpu_car_ops; +} From 27aa99dc0ec188771bd22f2188e56a571368303e Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 3 Apr 2013 17:40:46 +0300 Subject: [PATCH 17/20] clk: tegra: devicetree match for nvidia,tegra114-car Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk.c | 1 + drivers/clk/tegra/clk.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index 70b7a4783bee..923ca7ee4694 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -77,6 +77,7 @@ 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 }, { } }; diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index fb48f0467b9d..e0565620d68e 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -583,6 +583,12 @@ void tegra30_clock_init(struct device_node *np); 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 */ + typedef void (*tegra_clk_apply_init_table_func)(void); extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table; From 672d889c0a8969e8cc63d62c28b7073ae1370471 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 3 Apr 2013 17:40:48 +0300 Subject: [PATCH 18/20] ARM: dt: Add references to tegra_car clocks Add references to tegra_car clocks for the basic device nodes. Also remove the clock-frequency property of the serial node as the UART driver can now use the clock framework to obtain the frequency. Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra114-dalmore.dts | 1 - arch/arm/boot/dts/tegra114-pluto.dts | 1 - arch/arm/boot/dts/tegra114.dtsi | 8 +++++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/tegra114-dalmore.dts b/arch/arm/boot/dts/tegra114-dalmore.dts index 6ebc1b704190..616990dc92db 100644 --- a/arch/arm/boot/dts/tegra114-dalmore.dts +++ b/arch/arm/boot/dts/tegra114-dalmore.dts @@ -12,7 +12,6 @@ serial@70006300 { status = "okay"; - clock-frequency = <408000000>; }; pmc { diff --git a/arch/arm/boot/dts/tegra114-pluto.dts b/arch/arm/boot/dts/tegra114-pluto.dts index 5deb8692b350..6bbc8efae9c0 100644 --- a/arch/arm/boot/dts/tegra114-pluto.dts +++ b/arch/arm/boot/dts/tegra114-pluto.dts @@ -12,7 +12,6 @@ serial@70006300 { status = "okay"; - clock-frequency = <408000000>; }; pmc { diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index c0b527d15fda..c1110a9b2a91 100644 --- a/arch/arm/boot/dts/tegra114.dtsi +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -24,10 +24,11 @@ 0 42 0x04 0 121 0x04 0 122 0x04>; + clocks = <&tegra_car 5>; }; tegra_car: clock { - compatible = "nvidia,tegra114-car, nvidia,tegra30-car"; + compatible = "nvidia,tegra114-car"; reg = <0x60006000 0x1000>; #clock-cells = <1>; }; @@ -66,6 +67,7 @@ reg-shift = <2>; interrupts = <0 36 0x04>; status = "disabled"; + clocks = <&tegra_car 6>; }; serial@70006040 { @@ -74,6 +76,7 @@ reg-shift = <2>; interrupts = <0 37 0x04>; status = "disabled"; + clocks = <&tegra_car 192>; }; serial@70006200 { @@ -82,6 +85,7 @@ reg-shift = <2>; interrupts = <0 46 0x04>; status = "disabled"; + clocks = <&tegra_car 55>; }; serial@70006300 { @@ -90,12 +94,14 @@ reg-shift = <2>; interrupts = <0 90 0x04>; status = "disabled"; + clocks = <&tegra_car 65>; }; rtc { compatible = "nvidia,tegra114-rtc", "nvidia,tegra20-rtc"; reg = <0x7000e000 0x100>; interrupts = <0 2 0x04>; + clocks = <&tegra_car 4>; }; pmc { From c604283f52855a4568c18cfd4011bdcfeccf2c52 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 3 Apr 2013 17:40:49 +0300 Subject: [PATCH 19/20] clk: tegra: Remove forced clk_enable of uartd The UART driver enables the console uart clock, so we don't need to do that anymore in this file. Signed-off-by: Peter De Schrijver Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-tegra114.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index e2a7fa16c5de..0db81dd05fce 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -2011,7 +2011,7 @@ static __initdata struct tegra_clk_init_table init_table[] = { {uarta, pll_p, 408000000, 0}, {uartb, pll_p, 408000000, 0}, {uartc, pll_p, 408000000, 0}, - {uartd, pll_p, 408000000, 1}, + {uartd, pll_p, 408000000, 0}, {pll_a, clk_max, 564480000, 1}, {pll_a_out0, clk_max, 11289600, 1}, {extern1, pll_a_out0, 0, 1}, From 964ea47572b89589b61b553e44bbe9907d4f12a6 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 4 Apr 2013 17:13:54 -0600 Subject: [PATCH 20/20] clk: tegra: fix enum tegra114_clk to match binding A gap exists in the binding's clock ID definitions. Fix the clock driver to be consistent. This allows pclk to be looked up through device tree and prevents: ERROR: could not get clock /pmc:pclk(0) Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-tegra114.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 0db81dd05fce..d78e16ee161c 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -760,7 +760,7 @@ enum tegra114_clk { pll_re_vco, pll_re_out, pll_e_out0, spdif_in_sync, i2s0_sync, i2s1_sync, i2s2_sync, i2s3_sync, i2s4_sync, vimclk_sync, audio0, audio1, audio2, audio3, audio4, spdif, clk_out_1, clk_out_2, clk_out_3, - blink, xusb_host_src, xusb_falcon_src, xusb_fs_src, xusb_ss_src, + 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, /* Mux clocks */