From 3358d2d9f47af86bdd71edb24b361f72a54ec04e Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Thu, 18 Jun 2015 17:28:40 -0400 Subject: clk: tegra: Add interface to enable hardware control of SATA/XUSB PLLs On Tegra210, hardware control of the SATA and XUSB pad PLLs must be done during the UPHY enable sequence rather than the PLLE enable sequence. Export functions to do this so that hardware control can be enabled from the XUSB padctl driver. Signed-off-by: Andrew Bresticker Signed-off-by: Rhyland Klein Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra210.c | 58 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 637041fd53ad..3d0edee1f9fe 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -175,6 +175,19 @@ #define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14) #define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12) +#define SATA_PLL_CFG0 0x490 +#define SATA_PLL_CFG0_PADPLL_RESET_SWCTL BIT(0) +#define SATA_PLL_CFG0_PADPLL_USE_LOCKDET BIT(2) +#define SATA_PLL_CFG0_PADPLL_SLEEP_IDDQ BIT(13) +#define SATA_PLL_CFG0_SEQ_ENABLE BIT(24) + +#define XUSBIO_PLL_CFG0 0x51c +#define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL BIT(0) +#define XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL BIT(2) +#define XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET BIT(6) +#define XUSBIO_PLL_CFG0_PADPLL_SLEEP_IDDQ BIT(13) +#define XUSBIO_PLL_CFG0_SEQ_ENABLE BIT(24) + #define UTMIPLL_HW_PWRDN_CFG0 0x52c #define UTMIPLL_HW_PWRDN_CFG0_UTMIPLL_LOCK BIT(31) #define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE BIT(25) @@ -416,6 +429,51 @@ static const char *mux_pllmcp_clkm[] = { #define PLLU_MISC0_WRITE_MASK 0xbfffffff #define PLLU_MISC1_WRITE_MASK 0x00000007 +void tegra210_xusb_pll_hw_control_enable(void) +{ + u32 val; + + val = readl_relaxed(clk_base + XUSBIO_PLL_CFG0); + val &= ~(XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL | + XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL); + val |= XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET | + XUSBIO_PLL_CFG0_PADPLL_SLEEP_IDDQ; + writel_relaxed(val, clk_base + XUSBIO_PLL_CFG0); +} +EXPORT_SYMBOL_GPL(tegra210_xusb_pll_hw_control_enable); + +void tegra210_xusb_pll_hw_sequence_start(void) +{ + u32 val; + + val = readl_relaxed(clk_base + XUSBIO_PLL_CFG0); + val |= XUSBIO_PLL_CFG0_SEQ_ENABLE; + writel_relaxed(val, clk_base + XUSBIO_PLL_CFG0); +} +EXPORT_SYMBOL_GPL(tegra210_xusb_pll_hw_sequence_start); + +void tegra210_sata_pll_hw_control_enable(void) +{ + u32 val; + + val = readl_relaxed(clk_base + SATA_PLL_CFG0); + val &= ~SATA_PLL_CFG0_PADPLL_RESET_SWCTL; + val |= SATA_PLL_CFG0_PADPLL_USE_LOCKDET | + SATA_PLL_CFG0_PADPLL_SLEEP_IDDQ; + writel_relaxed(val, clk_base + SATA_PLL_CFG0); +} +EXPORT_SYMBOL_GPL(tegra210_sata_pll_hw_control_enable); + +void tegra210_sata_pll_hw_sequence_start(void) +{ + u32 val; + + val = readl_relaxed(clk_base + SATA_PLL_CFG0); + val |= SATA_PLL_CFG0_SEQ_ENABLE; + writel_relaxed(val, clk_base + SATA_PLL_CFG0); +} +EXPORT_SYMBOL_GPL(tegra210_sata_pll_hw_sequence_start); + static inline void _pll_misc_chk_default(void __iomem *base, struct tegra_clk_pll_params *params, u8 misc_num, u32 default_val, u32 mask) -- cgit v1.2.3 From 7e14f22305b09bd57fc2da3bf2fd3bfd53dc285b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 14:38:39 +0200 Subject: clk: tegra: Constify peripheral clock registers The peripheral clock registers are defined in static tables. These tables never need to be modified at runtime, so they can reside in read-only memory. Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-periph-gate.c | 2 +- drivers/clk/tegra/clk-periph.c | 2 +- drivers/clk/tegra/clk-tegra-periph.c | 2 +- drivers/clk/tegra/clk.c | 4 ++-- drivers/clk/tegra/clk.h | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c index d28d6e95020f..88127828befe 100644 --- a/drivers/clk/tegra/clk-periph-gate.c +++ b/drivers/clk/tegra/clk-periph-gate.c @@ -134,7 +134,7 @@ struct clk *tegra_clk_register_periph_gate(const char *name, struct tegra_clk_periph_gate *gate; struct clk *clk; struct clk_init_data init; - struct tegra_clk_periph_regs *pregs; + const struct tegra_clk_periph_regs *pregs; pregs = get_reg_bank(clk_num); if (!pregs) diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index ec5b6113b012..a17ca6d7f649 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -145,7 +145,7 @@ static struct clk *_tegra_clk_register_periph(const char *name, { struct clk *clk; struct clk_init_data init; - struct tegra_clk_periph_regs *bank; + const struct tegra_clk_periph_regs *bank; bool div = !(periph->gate.flags & TEGRA_PERIPH_NO_DIV); if (periph->gate.flags & TEGRA_PERIPH_NO_DIV) { diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index ea2b9cbf9e70..b4e226a2f42c 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -877,7 +877,7 @@ static void __init periph_clk_init(void __iomem *clk_base, struct clk **dt_clk; for (i = 0; i < ARRAY_SIZE(periph_clks); i++) { - struct tegra_clk_periph_regs *bank; + const struct tegra_clk_periph_regs *bank; struct tegra_periph_init_data *data; data = periph_clks + i; diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index 2a3a4fe803d6..98e65ca9f925 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -84,7 +84,7 @@ static int (*special_reset_assert)(unsigned long); static int (*special_reset_deassert)(unsigned long); static unsigned int num_special_reset; -static struct tegra_clk_periph_regs periph_regs[] = { +static const struct tegra_clk_periph_regs periph_regs[] = { [0] = { .enb_reg = CLK_OUT_ENB_L, .enb_set_reg = CLK_OUT_ENB_SET_L, @@ -182,7 +182,7 @@ static int tegra_clk_rst_deassert(struct reset_controller_dev *rcdev, return -EINVAL; } -struct tegra_clk_periph_regs *get_reg_bank(int clkid) +const struct tegra_clk_periph_regs *get_reg_bank(int clkid) { int reg_bank = clkid / 32; diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 4dbcfaec576a..3ef530a8989d 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -496,7 +496,7 @@ struct tegra_clk_periph_gate { u8 flags; int clk_num; int *enable_refcnt; - struct tegra_clk_periph_regs *regs; + const struct tegra_clk_periph_regs *regs; }; #define to_clk_periph_gate(_hw) \ @@ -716,7 +716,7 @@ void tegra_init_from_table(struct tegra_clk_init_table *tbl, void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, struct clk *clks[], int clk_max); -struct tegra_clk_periph_regs *get_reg_bank(int clkid); +const struct tegra_clk_periph_regs *get_reg_bank(int clkid); struct clk **tegra_clk_init(void __iomem *clk_base, int num, int periph_banks); struct clk **tegra_lookup_dt_id(int clk_id, struct tegra_clk *tegra_clk); -- cgit v1.2.3 From a9caa8481258576b59b46067dfd8fd6fbd72f3e3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 15:26:42 +0200 Subject: clk: tegra: Remove trailing blank line Trailing blank lines are undesirable (several tools, such as git, complain about them), so remove it. Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra-fixed.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c index d64ec7a1b976..91c38f1666c1 100644 --- a/drivers/clk/tegra/clk-tegra-fixed.c +++ b/drivers/clk/tegra/clk-tegra-fixed.c @@ -107,4 +107,3 @@ void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks) *dt_clk = clk; } } - -- cgit v1.2.3 From 07314fc108e195044c074f4b443974b5aaa2d5d7 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 8 Apr 2015 16:48:26 +0200 Subject: clk: tegra: Special-case mipi-cal parent on Tegra114 Starting with Tegra124, the mipi-cal clock uses the 72 MHz clock as its source. On Tegra114 this clock's parent was clk_m, so it is the one-off chip. Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra-periph.c | 2 +- drivers/clk/tegra/clk-tegra114.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index b4e226a2f42c..463c114358e6 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -803,7 +803,7 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("hda2hdmi", "clk_m", 128, TEGRA_PERIPH_ON_APB, tegra_clk_hda2hdmi, 0), GATE("bsea", "clk_m", 62, 0, tegra_clk_bsea, 0), GATE("bsev", "clk_m", 63, 0, tegra_clk_bsev, 0), - GATE("mipi-cal", "clk_m", 56, 0, tegra_clk_mipi_cal, 0), + GATE("mipi-cal", "clk72mhz", 56, 0, tegra_clk_mipi_cal, 0), GATE("usbd", "clk_m", 22, 0, tegra_clk_usbd, 0), GATE("usb2", "clk_m", 58, 0, tegra_clk_usb2, 0), GATE("usb3", "clk_m", 59, 0, tegra_clk_usb3, 0), diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index df47ec3169c3..b78054fac0a8 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -743,7 +743,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { [tegra_clk_csi] = { .dt_id = TEGRA114_CLK_CSI, .present = true }, [tegra_clk_i2c2] = { .dt_id = TEGRA114_CLK_I2C2, .present = true }, [tegra_clk_uartc] = { .dt_id = TEGRA114_CLK_UARTC, .present = true }, - [tegra_clk_mipi_cal] = { .dt_id = TEGRA114_CLK_MIPI_CAL, .present = true }, [tegra_clk_emc] = { .dt_id = TEGRA114_CLK_EMC, .present = true }, [tegra_clk_usb2] = { .dt_id = TEGRA114_CLK_USB2, .present = true }, [tegra_clk_usb3] = { .dt_id = TEGRA114_CLK_USB3, .present = true }, @@ -1237,6 +1236,11 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base, &emc_lock); clks[TEGRA114_CLK_MC] = clk; + clk = tegra_clk_register_periph_gate("mipi-cal", "clk_m", 0, clk_base, + CLK_SET_RATE_PARENT, 56, + periph_clk_enb_refcnt); + clks[TEGRA114_CLK_MIPI_CAL] = clk; + for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { data = &tegra_periph_clk_list[i]; clk = tegra_clk_register_periph(data->name, -- cgit v1.2.3 From 1ec7032ad517714108cc53a6ee7067276ca21e80 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 14:34:57 +0200 Subject: clk: tegra: Add fixed factor peripheral clock type Some of the peripheral clocks on Tegra are derived from one of the top- level PLLs with a fixed factor. Support these clocks by implementing the ->enable() and ->disable() callbacks using the peripheral clock register banks and the ->recalc_rate() by dividing the parent rate by the fixed factor. Signed-off-by: Thierry Reding --- drivers/clk/tegra/Makefile | 1 + drivers/clk/tegra/clk-periph-fixed.c | 120 +++++++++++++++++++++++++++++++++++ drivers/clk/tegra/clk.h | 17 +++++ 3 files changed, 138 insertions(+) create mode 100644 drivers/clk/tegra/clk-periph-fixed.c (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index 97984c503bbb..33fd0938d79e 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -3,6 +3,7 @@ obj-y += clk-audio-sync.o obj-y += clk-dfll.o obj-y += clk-divider.o obj-y += clk-periph.o +obj-y += clk-periph-fixed.o obj-y += clk-periph-gate.o obj-y += clk-pll.o obj-y += clk-pll-out.o diff --git a/drivers/clk/tegra/clk-periph-fixed.c b/drivers/clk/tegra/clk-periph-fixed.c new file mode 100644 index 000000000000..c57dfb037b10 --- /dev/null +++ b/drivers/clk/tegra/clk-periph-fixed.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "clk.h" + +static inline struct tegra_clk_periph_fixed * +to_tegra_clk_periph_fixed(struct clk_hw *hw) +{ + return container_of(hw, struct tegra_clk_periph_fixed, hw); +} + +static int tegra_clk_periph_fixed_is_enabled(struct clk_hw *hw) +{ + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); + u32 mask = 1 << (fixed->num % 32), value; + + value = readl(fixed->base + fixed->regs->enb_reg); + if (value & mask) { + value = readl(fixed->base + fixed->regs->rst_reg); + if ((value & mask) == 0) + return 1; + } + + return 0; +} + +static int tegra_clk_periph_fixed_enable(struct clk_hw *hw) +{ + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); + u32 mask = 1 << (fixed->num % 32); + + writel(mask, fixed->base + fixed->regs->enb_set_reg); + + return 0; +} + +static void tegra_clk_periph_fixed_disable(struct clk_hw *hw) +{ + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); + u32 mask = 1 << (fixed->num % 32); + + writel(mask, fixed->base + fixed->regs->enb_clr_reg); +} + +static unsigned long +tegra_clk_periph_fixed_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); + unsigned long long rate; + + rate = (unsigned long long)parent_rate * fixed->mul; + do_div(rate, fixed->div); + + return (unsigned long)rate; +} + +static const struct clk_ops tegra_clk_periph_fixed_ops = { + .is_enabled = tegra_clk_periph_fixed_is_enabled, + .enable = tegra_clk_periph_fixed_enable, + .disable = tegra_clk_periph_fixed_disable, + .recalc_rate = tegra_clk_periph_fixed_recalc_rate, +}; + +struct clk *tegra_clk_register_periph_fixed(const char *name, + const char *parent, + unsigned long flags, + void __iomem *base, + unsigned int mul, + unsigned int div, + unsigned int num) +{ + const struct tegra_clk_periph_regs *regs; + struct tegra_clk_periph_fixed *fixed; + struct clk_init_data init; + struct clk *clk; + + regs = get_reg_bank(num); + if (!regs) + return ERR_PTR(-EINVAL); + + fixed = kzalloc(sizeof(*fixed), GFP_KERNEL); + if (!fixed) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.flags = flags; + init.parent_names = parent ? &parent : NULL; + init.num_parents = parent ? 1 : 0; + init.ops = &tegra_clk_periph_fixed_ops; + + fixed->base = base; + fixed->regs = regs; + fixed->mul = mul; + fixed->div = div; + fixed->num = num; + + fixed->hw.init = &init; + + clk = clk_register(NULL, &fixed->hw); + if (IS_ERR(clk)) + kfree(fixed); + + return clk; +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 3ef530a8989d..7264f17e269e 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -516,6 +516,23 @@ struct clk *tegra_clk_register_periph_gate(const char *name, const char *parent_name, u8 gate_flags, void __iomem *clk_base, unsigned long flags, int clk_num, int *enable_refcnt); +struct tegra_clk_periph_fixed { + struct clk_hw hw; + void __iomem *base; + const struct tegra_clk_periph_regs *regs; + unsigned int mul; + unsigned int div; + unsigned int num; +}; + +struct clk *tegra_clk_register_periph_fixed(const char *name, + const char *parent, + unsigned long flags, + void __iomem *base, + unsigned int mul, + unsigned int div, + unsigned int num); + /** * struct clk-periph - peripheral clock * -- cgit v1.2.3 From 3d0f4e5f7a7c9ef2d8504f2b42f9c4d3233ba707 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 14:47:25 +0200 Subject: clk: tegra: Use correct parent for dpaux clock The dpaux clock is derived from pll_p_out0 (pll_p), not clk_m. Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra-periph.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index 463c114358e6..d758f2169d41 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -821,7 +821,7 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("ispb", "clk_m", 3, 0, tegra_clk_ispb, 0), GATE("vim2_clk", "clk_m", 11, 0, tegra_clk_vim2_clk, 0), GATE("pcie", "clk_m", 70, 0, tegra_clk_pcie, 0), - GATE("dpaux", "clk_m", 181, 0, tegra_clk_dpaux, 0), + GATE("dpaux", "pll_p", 181, 0, tegra_clk_dpaux, 0), GATE("gpu", "pll_ref", 184, 0, tegra_clk_gpu, 0), GATE("pllg_ref", "pll_ref", 189, 0, tegra_clk_pll_g_ref, 0), GATE("hsic_trk", "usb2_hsic_trk", 209, TEGRA_PERIPH_NO_RESET, tegra_clk_hsic_trk, 0), -- cgit v1.2.3 From 98c4b3661b5aee0e583d17d6304f6489c0f41155 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 15:05:33 +0200 Subject: clk: tegra: Add dpaux1 clock This clock is of the same type as dpaux and is added to feed into the second DPAUX block used in conjunction with SOR1. Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-id.h | 1 + drivers/clk/tegra/clk-tegra-periph.c | 1 + drivers/clk/tegra/clk-tegra210.c | 1 + 3 files changed, 3 insertions(+) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index 62ea38187b71..fe6c6afcfa60 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -71,6 +71,7 @@ enum clk_id { tegra_clk_disp2_8, tegra_clk_dp2, tegra_clk_dpaux, + tegra_clk_dpaux1, tegra_clk_dsialp, tegra_clk_dsia_mux, tegra_clk_dsiblp, diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index d758f2169d41..c716b2885207 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -822,6 +822,7 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("vim2_clk", "clk_m", 11, 0, tegra_clk_vim2_clk, 0), GATE("pcie", "clk_m", 70, 0, tegra_clk_pcie, 0), GATE("dpaux", "pll_p", 181, 0, tegra_clk_dpaux, 0), + GATE("dpaux1", "pll_p", 207, 0, tegra_clk_dpaux1, 0), GATE("gpu", "pll_ref", 184, 0, tegra_clk_gpu, 0), GATE("pllg_ref", "pll_ref", 189, 0, tegra_clk_pll_g_ref, 0), GATE("hsic_trk", "usb2_hsic_trk", 209, TEGRA_PERIPH_NO_RESET, tegra_clk_hsic_trk, 0), diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 3d0edee1f9fe..4f72d1a4347b 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -2150,6 +2150,7 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = { [tegra_clk_clk72Mhz_8] = { .dt_id = TEGRA210_CLK_CLK72MHZ, .present = true }, [tegra_clk_vic03_8] = { .dt_id = TEGRA210_CLK_VIC03, .present = true }, [tegra_clk_dpaux] = { .dt_id = TEGRA210_CLK_DPAUX, .present = true }, + [tegra_clk_dpaux1] = { .dt_id = TEGRA210_CLK_DPAUX1, .present = true }, [tegra_clk_sor0] = { .dt_id = TEGRA210_CLK_SOR0, .present = true }, [tegra_clk_sor0_lvds] = { .dt_id = TEGRA210_CLK_SOR0_LVDS, .present = true }, [tegra_clk_gpu] = { .dt_id = TEGRA210_CLK_GPU, .present = true }, -- cgit v1.2.3 From eede7113aabd3f40f8d9c32b1690f2859fcb101a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 15:10:43 +0200 Subject: clk: tegra: dpaux and dpaux1 are fixed factor clocks The dpaux (on Tegra124 and Tegra210) and dpaux1 (on Tegra210) are fixed factor clocks (1:17) and derived from pll_p_out0 (pll_p). They also have a gate bit in the peripheral clock registers. Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra-periph.c | 2 -- drivers/clk/tegra/clk-tegra124.c | 4 ++++ drivers/clk/tegra/clk-tegra210.c | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index c716b2885207..29d04c663abf 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -821,8 +821,6 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("ispb", "clk_m", 3, 0, tegra_clk_ispb, 0), GATE("vim2_clk", "clk_m", 11, 0, tegra_clk_vim2_clk, 0), GATE("pcie", "clk_m", 70, 0, tegra_clk_pcie, 0), - GATE("dpaux", "pll_p", 181, 0, tegra_clk_dpaux, 0), - GATE("dpaux1", "pll_p", 207, 0, tegra_clk_dpaux1, 0), GATE("gpu", "pll_ref", 184, 0, tegra_clk_gpu, 0), GATE("pllg_ref", "pll_ref", 189, 0, tegra_clk_pll_g_ref, 0), GATE("hsic_trk", "usb2_hsic_trk", 209, TEGRA_PERIPH_NO_RESET, tegra_clk_hsic_trk, 0), diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 1627258292d2..f4fbbf16a056 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1155,6 +1155,10 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base, 1, 2); clks[TEGRA124_CLK_XUSB_SS_DIV2] = clk; + clk = tegra_clk_register_periph_fixed("dpaux", "pll_p", 0, clk_base, + 1, 17, 181); + clks[TEGRA124_CLK_DPAUX] = clk; + clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0, clk_base + PLLD_MISC, 30, 0, &pll_d_lock); clks[TEGRA124_CLK_PLL_D_DSI_OUT] = clk; diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 4f72d1a4347b..8133f92361fc 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -2462,6 +2462,14 @@ static __init void tegra210_periph_clk_init(void __iomem *clk_base, 1, 2); clks[TEGRA210_CLK_XUSB_SS_DIV2] = clk; + clk = tegra_clk_register_periph_fixed("dpaux", "pll_p", 0, clk_base, + 1, 17, 181); + clks[TEGRA210_CLK_DPAUX] = clk; + + clk = tegra_clk_register_periph_fixed("dpaux1", "pll_p", 0, clk_base, + 1, 17, 207); + clks[TEGRA210_CLK_DPAUX1] = clk; + /* pll_d_dsi_out */ clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0, clk_base + PLLD_MISC0, 21, 0, &pll_d_lock); -- cgit v1.2.3 From a91bb605ec5f93676e503267c89469d02c5b4cbc Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Apr 2015 15:13:36 +0200 Subject: clk: tegra: Add sor_safe clock The sor_safe clock is a fixed factor (1:17) clock derived from pll_p. It has a gate bit in the peripheral clock registers. While the SOR is being powered up, sor_safe can be used as the source until the SOR brick can generate its own clock. Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-id.h | 1 + drivers/clk/tegra/clk-tegra210.c | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index fe6c6afcfa60..36c974916d4f 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -307,6 +307,7 @@ enum clk_id { tegra_clk_xusb_ss_div2, tegra_clk_xusb_ssp_src, tegra_clk_sclk_mux, + tegra_clk_sor_safe, tegra_clk_max, }; diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 8133f92361fc..6f661717e593 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -2470,6 +2470,10 @@ static __init void tegra210_periph_clk_init(void __iomem *clk_base, 1, 17, 207); clks[TEGRA210_CLK_DPAUX1] = clk; + clk = tegra_clk_register_periph_fixed("sor_safe", "pll_p", 0, clk_base, + 1, 17, 222); + clks[TEGRA210_CLK_SOR_SAFE] = clk; + /* pll_d_dsi_out */ clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0, clk_base + PLLD_MISC0, 21, 0, &pll_d_lock); -- cgit v1.2.3 From 926655f929063619b13db8b4f2ef8c9a08605492 Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Mon, 21 Mar 2016 15:58:52 -0400 Subject: clk: tegra: Fix pllre Tegra210 and add pll_re_out1 Use a new Tegra210 version of the pll_register_pllre function to allow setting the proper settings for the m and n div fields. Additionally define PLL_RE_OUT1 on Tegra210. Signed-off-by: Rhyland Klein [treding@nvidia.com: define PLLRE_OUT1 register offset] Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-pll.c | 46 ++++++++++++++++++++++++++++++++ drivers/clk/tegra/clk-tegra210.c | 16 +++++++++-- drivers/clk/tegra/clk.h | 6 +++++ include/dt-bindings/clock/tegra210-car.h | 2 +- 4 files changed, 67 insertions(+), 3 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 6ac3f843e7ca..4e194ecc8d5e 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -2013,6 +2013,52 @@ struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name, #endif #if defined(CONFIG_ARCH_TEGRA_210_SOC) +struct clk *tegra_clk_register_pllre_tegra210(const char *name, + const char *parent_name, void __iomem *clk_base, + void __iomem *pmc, unsigned long flags, + struct tegra_clk_pll_params *pll_params, + spinlock_t *lock, unsigned long parent_rate) +{ + u32 val; + struct tegra_clk_pll *pll; + struct clk *clk; + + pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate); + + if (pll_params->adjust_vco) + pll_params->vco_min = pll_params->adjust_vco(pll_params, + parent_rate); + + pll = _tegra_init_pll(clk_base, pmc, pll_params, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + /* program minimum rate by default */ + + val = pll_readl_base(pll); + if (val & PLL_BASE_ENABLE) + WARN_ON(readl_relaxed(clk_base + pll_params->iddq_reg) & + BIT(pll_params->iddq_bit_idx)); + else { + val = 0x4 << divm_shift(pll); + val |= 0x41 << divn_shift(pll); + pll_writel_base(val, pll); + } + + /* disable lock override */ + + val = pll_readl_misc(pll); + val &= ~BIT(29); + pll_writel_misc(val, pll); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_pllre_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + static int clk_plle_tegra210_enable(struct clk_hw *hw) { struct tegra_clk_pll *pll = to_clk_pll(hw); diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 6f661717e593..b8551813ec43 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -92,6 +92,7 @@ #define PLLE_AUX 0x48c #define PLLRE_BASE 0x4c4 #define PLLRE_MISC0 0x4c8 +#define PLLRE_OUT1 0x4cc #define PLLDP_BASE 0x590 #define PLLDP_MISC 0x594 @@ -2653,8 +2654,10 @@ static void __init tegra210_pll_init(void __iomem *clk_base, clks[TEGRA210_CLK_PLL_D_OUT0] = clk; /* PLLRE */ - clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc, - 0, &pll_re_vco_params, &pll_re_lock, pll_ref_freq); + clk = tegra_clk_register_pllre_tegra210("pll_re_vco", "pll_ref", + clk_base, pmc, 0, + &pll_re_vco_params, + &pll_re_lock, pll_ref_freq); clk_register_clkdev(clk, "pll_re_vco", NULL); clks[TEGRA210_CLK_PLL_RE_VCO] = clk; @@ -2664,6 +2667,15 @@ static void __init tegra210_pll_init(void __iomem *clk_base, clk_register_clkdev(clk, "pll_re_out", NULL); clks[TEGRA210_CLK_PLL_RE_OUT] = clk; + clk = tegra_clk_register_divider("pll_re_out1_div", "pll_re_vco", + clk_base + PLLRE_OUT1, 0, + TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_re_out1", "pll_re_out1_div", + clk_base + PLLRE_OUT1, 1, 0, + CLK_SET_RATE_PARENT, 0, NULL); + clks[TEGRA210_CLK_PLL_RE_OUT1] = clk; + /* PLLE */ clk = tegra_clk_register_plle_tegra210("pll_e", "pll_ref", clk_base, 0, &pll_e_params, NULL); diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 7264f17e269e..9421f0310999 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -386,6 +386,12 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name, struct tegra_clk_pll_params *pll_params, spinlock_t *lock, unsigned long parent_rate); +struct clk *tegra_clk_register_pllre_tegra210(const char *name, + const char *parent_name, void __iomem *clk_base, + void __iomem *pmc, unsigned long flags, + struct tegra_clk_pll_params *pll_params, + spinlock_t *lock, unsigned long parent_rate); + struct clk *tegra_clk_register_plle_tegra114(const char *name, const char *parent_name, void __iomem *clk_base, unsigned long flags, diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h index 0a05b0d36ae7..bd3530e56d46 100644 --- a/include/dt-bindings/clock/tegra210-car.h +++ b/include/dt-bindings/clock/tegra210-car.h @@ -346,7 +346,7 @@ #define TEGRA210_CLK_PLL_P_OUT_HSIO 316 #define TEGRA210_CLK_PLL_P_OUT_XUSB 317 #define TEGRA210_CLK_XUSB_SSP_SRC 318 -/* 319 */ +#define TEGRA210_CLK_PLL_RE_OUT1 319 /* 320 */ /* 321 */ /* 322 */ -- cgit v1.2.3 From a02cc84a31d3bd46a10546ff7024e7b5a186d339 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 29 Feb 2016 21:46:06 +0100 Subject: clk: tegra: Initialize PLL_C to sane rate on Tegra30 If the bootloader does not touch PLL_C it will stay in its reset state, failing to lock when enabled. This leads to consumers of this clock to fail probing. Fix this by always programming the PLL with a sane rate, which allows it to lock, at startup. Signed-off-by: Lucas Stach Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra30.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 0478565cf292..236e2db9a716 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -1372,6 +1372,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_SBC4, TEGRA30_CLK_PLL_P, 100000000, 0 }, { TEGRA30_CLK_SBC5, TEGRA30_CLK_PLL_P, 100000000, 0 }, { TEGRA30_CLK_SBC6, TEGRA30_CLK_PLL_P, 100000000, 0 }, + { TEGRA30_CLK_PLL_C, TEGRA30_CLK_CLK_MAX, 600000000, 0 }, { TEGRA30_CLK_HOST1X, TEGRA30_CLK_PLL_C, 150000000, 0 }, { TEGRA30_CLK_DISP1, TEGRA30_CLK_PLL_P, 600000000, 0 }, { TEGRA30_CLK_DISP2, TEGRA30_CLK_PLL_P, 600000000, 0 }, -- cgit v1.2.3 From 797097301860c64b63346d068ba4fe4992bd5021 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 29 Feb 2016 21:46:07 +0100 Subject: clk: tegra: Fix PLL_U post divider and initial rate on Tegra30 The post divider value in the frequency table is wrong as it would lead to the PLL producing an output rate of 960 MHz instead of the desired 480 MHz. This wasn't a problem as nothing used the table to actually initialize the PLL rate, but the bootloader configuration was used unaltered. If the bootloader does not set up the PLL it will fail to come when used under Linux. To fix this don't rely on the bootloader, but set the correct rate in the clock driver. Signed-off-by: Lucas Stach Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra30.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 236e2db9a716..9396f4930da7 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -339,11 +339,11 @@ static const struct pdiv_map pllu_p[] = { }; static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { - { 12000000, 480000000, 960, 12, 1, 12 }, - { 13000000, 480000000, 960, 13, 1, 12 }, - { 16800000, 480000000, 400, 7, 1, 5 }, - { 19200000, 480000000, 200, 4, 1, 3 }, - { 26000000, 480000000, 960, 26, 1, 12 }, + { 12000000, 480000000, 960, 12, 2, 12 }, + { 13000000, 480000000, 960, 13, 2, 12 }, + { 16800000, 480000000, 400, 7, 2, 5 }, + { 19200000, 480000000, 200, 4, 2, 3 }, + { 26000000, 480000000, 960, 26, 2, 12 }, { 0, 0, 0, 0, 0, 0 }, }; @@ -1380,6 +1380,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_GR2D, TEGRA30_CLK_PLL_C, 300000000, 0 }, { TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0 }, { TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0 }, + { TEGRA30_CLK_PLL_U, TEGRA30_CLK_CLK_MAX, 480000000, 0 }, /* must be the last entry */ { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 }, }; -- cgit v1.2.3 From 8eaaae9937649f54beac7da582fa6cc6c79ae936 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 8 Apr 2016 14:57:09 +0200 Subject: clk: tegra: dfll: Update kerneldoc The kerneldoc for struct tegra_dfll_soc_data is stale. Update it to match the current structure definition. Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-dfll.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h index 2e4c0772a5dc..7e66c07c4d2b 100644 --- a/drivers/clk/tegra/clk-dfll.h +++ b/drivers/clk/tegra/clk-dfll.h @@ -24,15 +24,14 @@ /** * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver - * @opp_dev: struct device * that holds the OPP table for the DFLL + * @dev: struct device * that holds the OPP table for the DFLL * @min_millivolts: minimum voltage (in mV) that the DFLL can operate * @tune0_low: DFLL tuning register 0 (low voltage range) * @tune0_high: DFLL tuning register 0 (high voltage range) * @tune1: DFLL tuning register 1 - * @assert_dvco_reset: fn ptr to place the DVCO in reset - * @deassert_dvco_reset: fn ptr to release the DVCO reset - * @set_clock_trimmers_high: fn ptr to tune clock trimmers for high voltage - * @set_clock_trimmers_low: fn ptr to tune clock trimmers for low voltage + * @init_clock_trimmers: callback to initialize clock trimmers + * @set_clock_trimmers_high: callback to tune clock trimmers for high voltage + * @set_clock_trimmers_low: callback to tune clock trimmers for low voltage */ struct tegra_dfll_soc_data { struct device *dev; @@ -40,6 +39,7 @@ struct tegra_dfll_soc_data { u32 tune0_low; u32 tune0_high; u32 tune1; + void (*init_clock_trimmers)(void); void (*set_clock_trimmers_high)(void); void (*set_clock_trimmers_low)(void); -- cgit v1.2.3 From 27ed2f7e7ca5c38a8ce695e58e6cf270c26f370b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 8 Apr 2016 15:02:06 +0200 Subject: clk: tegra: dfll: Reference CVB table instead of copying data Instead of copying parts of the CVB table into a separate structure, keep track of the selected CVB table and directly reference data from it. Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-dfll.c | 11 ++++++----- drivers/clk/tegra/clk-dfll.h | 10 ++-------- drivers/clk/tegra/clk-tegra124-dfll-fcpu.c | 23 +++++++++-------------- 3 files changed, 17 insertions(+), 27 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c index 19bfa07e24b1..f010562534eb 100644 --- a/drivers/clk/tegra/clk-dfll.c +++ b/drivers/clk/tegra/clk-dfll.c @@ -55,6 +55,7 @@ #include #include "clk-dfll.h" +#include "cvb.h" /* * DFLL control registers - access via dfll_{readl,writel} @@ -442,8 +443,8 @@ static void dfll_tune_low(struct tegra_dfll *td) { td->tune_range = DFLL_TUNE_LOW; - dfll_writel(td, td->soc->tune0_low, DFLL_TUNE0); - dfll_writel(td, td->soc->tune1, DFLL_TUNE1); + dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune0_low, DFLL_TUNE0); + dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune1, DFLL_TUNE1); dfll_wmb(td); if (td->soc->set_clock_trimmers_low) @@ -1449,7 +1450,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) } v_max = dev_pm_opp_get_voltage(opp); - v = td->soc->min_millivolts * 1000; + v = td->soc->cvb->min_millivolts * 1000; lut = find_vdd_map_entry_exact(td, v); if (lut < 0) goto out; @@ -1461,7 +1462,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) break; v_opp = dev_pm_opp_get_voltage(opp); - if (v_opp <= td->soc->min_millivolts * 1000) + if (v_opp <= td->soc->cvb->min_millivolts * 1000) td->dvco_rate_min = dev_pm_opp_get_freq(opp); for (;;) { @@ -1490,7 +1491,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) if (!td->dvco_rate_min) dev_err(td->dev, "no opp above DFLL minimum voltage %d mV\n", - td->soc->min_millivolts); + td->soc->cvb->min_millivolts); else ret = 0; diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h index 7e66c07c4d2b..d192982b1f96 100644 --- a/drivers/clk/tegra/clk-dfll.h +++ b/drivers/clk/tegra/clk-dfll.h @@ -25,20 +25,14 @@ /** * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver * @dev: struct device * that holds the OPP table for the DFLL - * @min_millivolts: minimum voltage (in mV) that the DFLL can operate - * @tune0_low: DFLL tuning register 0 (low voltage range) - * @tune0_high: DFLL tuning register 0 (high voltage range) - * @tune1: DFLL tuning register 1 + * @cvb: CPU frequency table for this SoC * @init_clock_trimmers: callback to initialize clock trimmers * @set_clock_trimmers_high: callback to tune clock trimmers for high voltage * @set_clock_trimmers_low: callback to tune clock trimmers for low voltage */ struct tegra_dfll_soc_data { struct device *dev; - unsigned int min_millivolts; - u32 tune0_low; - u32 tune0_high; - u32 tune1; + const struct cvb_table *cvb; void (*init_clock_trimmers)(void); void (*set_clock_trimmers_high)(void); diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index 61253330c12b..6bfa5ca40d02 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -86,7 +86,6 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) { int process_id, speedo_id, speedo_value; struct tegra_dfll_soc_data *soc; - const struct cvb_table *cvb; process_id = tegra_sku_info.cpu_process_id; speedo_id = tegra_sku_info.cpu_speedo_id; @@ -108,21 +107,17 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) return -ENODEV; } - cvb = tegra_cvb_build_opp_table(tegra124_cpu_cvb_tables, - ARRAY_SIZE(tegra124_cpu_cvb_tables), - process_id, speedo_id, speedo_value, - cpu_max_freq_table[speedo_id], - soc->dev); - if (IS_ERR(cvb)) { - dev_err(&pdev->dev, "couldn't build OPP table: %ld\n", - PTR_ERR(cvb)); - return PTR_ERR(cvb); + soc->cvb = tegra_cvb_build_opp_table(tegra124_cpu_cvb_tables, + ARRAY_SIZE(tegra124_cpu_cvb_tables), + process_id, speedo_id, speedo_value, + cpu_max_freq_table[speedo_id], + soc->dev); + if (IS_ERR(soc->cvb)) { + dev_err(&pdev->dev, "couldn't add OPP table: %ld\n", + PTR_ERR(soc->cvb)); + return PTR_ERR(soc->cvb); } - soc->min_millivolts = cvb->min_millivolts; - soc->tune0_low = cvb->cpu_dfll_data.tune0_low; - soc->tune0_high = cvb->cpu_dfll_data.tune0_high; - soc->tune1 = cvb->cpu_dfll_data.tune1; return tegra_dfll_register(pdev, soc); } -- cgit v1.2.3 From e8f6a68c508b5d1cc4612ada028d87c74ab279d5 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 8 Apr 2016 15:09:56 +0200 Subject: clk: tegra: dfll: Make code more comprehensible Rename some variables and structure fields to make the code more comprehensible. Also change the prototype of internal functions to be more in line with the OPP core functions. Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra124-dfll-fcpu.c | 11 +++--- drivers/clk/tegra/cvb.c | 55 +++++++++++++++--------------- drivers/clk/tegra/cvb.h | 12 +++---- 3 files changed, 37 insertions(+), 41 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index 6bfa5ca40d02..c7ffd4fd2231 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -47,7 +47,7 @@ static const struct cvb_table tegra124_cpu_cvb_tables[] = { }, .speedo_scale = 100, .voltage_scale = 1000, - .cvb_table = { + .entries = { {204000000UL, {1112619, -29295, 402} }, {306000000UL, {1150460, -30585, 402} }, {408000000UL, {1190122, -31865, 402} }, @@ -107,11 +107,10 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) return -ENODEV; } - soc->cvb = tegra_cvb_build_opp_table(tegra124_cpu_cvb_tables, - ARRAY_SIZE(tegra124_cpu_cvb_tables), - process_id, speedo_id, speedo_value, - cpu_max_freq_table[speedo_id], - soc->dev); + soc->cvb = tegra_cvb_add_opp_table(soc->dev, tegra124_cpu_cvb_tables, + ARRAY_SIZE(tegra124_cpu_cvb_tables), + process_id, speedo_id, speedo_value, + cpu_max_freq_table[speedo_id]); if (IS_ERR(soc->cvb)) { dev_err(&pdev->dev, "couldn't add OPP table: %ld\n", PTR_ERR(soc->cvb)); diff --git a/drivers/clk/tegra/cvb.c b/drivers/clk/tegra/cvb.c index 69c74eec3a4b..7a099b18c368 100644 --- a/drivers/clk/tegra/cvb.c +++ b/drivers/clk/tegra/cvb.c @@ -61,29 +61,28 @@ static int round_voltage(int mv, const struct rail_alignment *align, int up) return mv; } -static int build_opp_table(const struct cvb_table *d, - int speedo_value, - unsigned long max_freq, - struct device *opp_dev) +static int build_opp_table(struct device *dev, const struct cvb_table *table, + int speedo_value, unsigned long max_freq) { + const struct rail_alignment *align = &table->alignment; int i, ret, dfll_mv, min_mv, max_mv; - const struct cvb_table_freq_entry *table = NULL; - const struct rail_alignment *align = &d->alignment; - min_mv = round_voltage(d->min_millivolts, align, UP); - max_mv = round_voltage(d->max_millivolts, align, DOWN); + min_mv = round_voltage(table->min_millivolts, align, UP); + max_mv = round_voltage(table->max_millivolts, align, DOWN); for (i = 0; i < MAX_DVFS_FREQS; i++) { - table = &d->cvb_table[i]; - if (!table->freq || (table->freq > max_freq)) + const struct cvb_table_freq_entry *entry = &table->entries[i]; + + if (!entry->freq || (entry->freq > max_freq)) break; - dfll_mv = get_cvb_voltage( - speedo_value, d->speedo_scale, &table->coefficients); - dfll_mv = round_cvb_voltage(dfll_mv, d->voltage_scale, align); + dfll_mv = get_cvb_voltage(speedo_value, table->speedo_scale, + &entry->coefficients); + dfll_mv = round_cvb_voltage(dfll_mv, table->voltage_scale, + align); dfll_mv = clamp(dfll_mv, min_mv, max_mv); - ret = dev_pm_opp_add(opp_dev, table->freq, dfll_mv * 1000); + ret = dev_pm_opp_add(dev, entry->freq, dfll_mv * 1000); if (ret) return ret; } @@ -92,7 +91,7 @@ static int build_opp_table(const struct cvb_table *d, } /** - * tegra_cvb_build_opp_table - build OPP table from Tegra CVB tables + * tegra_cvb_add_opp_table - build OPP table from Tegra CVB tables * @cvb_tables: array of CVB tables * @sz: size of the previously mentioned array * @process_id: process id of the HW module @@ -108,25 +107,25 @@ static int build_opp_table(const struct cvb_table *d, * given @opp_dev. Returns a pointer to the struct cvb_table that matched * or an ERR_PTR on failure. */ -const struct cvb_table *tegra_cvb_build_opp_table( - const struct cvb_table *cvb_tables, - size_t sz, int process_id, - int speedo_id, int speedo_value, - unsigned long max_rate, - struct device *opp_dev) +const struct cvb_table * +tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *tables, + size_t count, int process_id, int speedo_id, + int speedo_value, unsigned long max_freq) { - int i, ret; + size_t i; + int ret; - for (i = 0; i < sz; i++) { - const struct cvb_table *d = &cvb_tables[i]; + for (i = 0; i < count; i++) { + const struct cvb_table *table = &tables[i]; - if (d->speedo_id != -1 && d->speedo_id != speedo_id) + if (table->speedo_id != -1 && table->speedo_id != speedo_id) continue; - if (d->process_id != -1 && d->process_id != process_id) + + if (table->process_id != -1 && table->process_id != process_id) continue; - ret = build_opp_table(d, speedo_value, max_rate, opp_dev); - return ret ? ERR_PTR(ret) : d; + ret = build_opp_table(dev, table, speedo_value, max_freq); + return ret ? ERR_PTR(ret) : table; } return ERR_PTR(-EINVAL); diff --git a/drivers/clk/tegra/cvb.h b/drivers/clk/tegra/cvb.h index f62cdc4f4234..e6bf8581badd 100644 --- a/drivers/clk/tegra/cvb.h +++ b/drivers/clk/tegra/cvb.h @@ -53,15 +53,13 @@ struct cvb_table { int speedo_scale; int voltage_scale; - struct cvb_table_freq_entry cvb_table[MAX_DVFS_FREQS]; + struct cvb_table_freq_entry entries[MAX_DVFS_FREQS]; struct cvb_cpu_dfll_data cpu_dfll_data; }; -const struct cvb_table *tegra_cvb_build_opp_table( - const struct cvb_table *cvb_tables, - size_t sz, int process_id, - int speedo_id, int speedo_value, - unsigned long max_rate, - struct device *opp_dev); +const struct cvb_table * +tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *cvb_tables, + size_t count, int process_id, int speedo_id, + int speedo_value, unsigned long max_freq); #endif -- cgit v1.2.3 From f7c42d98621739d416cc4a739b721574fcbe910c Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 8 Apr 2016 15:16:28 +0200 Subject: clk: tegra: dfll: Properly clean up on failure and removal Upon failure to probe the DFLL, the OPP table will not be cleaned up properly. Fix this and while at it make sure the OPP table will also be cleared upon driver removal. Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-dfll.h | 2 ++ drivers/clk/tegra/clk-tegra124-dfll-fcpu.c | 31 ++++++++++++++++++++++++++---- drivers/clk/tegra/cvb.c | 16 +++++++++++++++ drivers/clk/tegra/cvb.h | 3 +++ 4 files changed, 48 insertions(+), 4 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h index d192982b1f96..ed2ad888268f 100644 --- a/drivers/clk/tegra/clk-dfll.h +++ b/drivers/clk/tegra/clk-dfll.h @@ -25,6 +25,7 @@ /** * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver * @dev: struct device * that holds the OPP table for the DFLL + * @max_freq: maximum frequency supported on this SoC * @cvb: CPU frequency table for this SoC * @init_clock_trimmers: callback to initialize clock trimmers * @set_clock_trimmers_high: callback to tune clock trimmers for high voltage @@ -32,6 +33,7 @@ */ struct tegra_dfll_soc_data { struct device *dev; + unsigned long max_freq; const struct cvb_table *cvb; void (*init_clock_trimmers)(void); diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index c7ffd4fd2231..d052d9fa8230 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -84,7 +84,7 @@ static const struct cvb_table tegra124_cpu_cvb_tables[] = { static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) { - int process_id, speedo_id, speedo_value; + int process_id, speedo_id, speedo_value, err; struct tegra_dfll_soc_data *soc; process_id = tegra_sku_info.cpu_process_id; @@ -107,18 +107,41 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) return -ENODEV; } + soc->max_freq = cpu_max_freq_table[speedo_id]; + soc->cvb = tegra_cvb_add_opp_table(soc->dev, tegra124_cpu_cvb_tables, ARRAY_SIZE(tegra124_cpu_cvb_tables), process_id, speedo_id, speedo_value, - cpu_max_freq_table[speedo_id]); + soc->max_freq); if (IS_ERR(soc->cvb)) { dev_err(&pdev->dev, "couldn't add OPP table: %ld\n", PTR_ERR(soc->cvb)); return PTR_ERR(soc->cvb); } + err = tegra_dfll_register(pdev, soc); + if (err < 0) { + tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq); + return err; + } + + platform_set_drvdata(pdev, soc); + + return 0; +} + +static int tegra124_dfll_fcpu_remove(struct platform_device *pdev) +{ + struct tegra_dfll_soc_data *soc = platform_get_drvdata(pdev); + int err; + + err = tegra_dfll_unregister(pdev); + if (err < 0) + dev_err(&pdev->dev, "failed to unregister DFLL: %d\n", err); + + tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq); - return tegra_dfll_register(pdev, soc); + return 0; } static const struct of_device_id tegra124_dfll_fcpu_of_match[] = { @@ -134,7 +157,7 @@ static const struct dev_pm_ops tegra124_dfll_pm_ops = { static struct platform_driver tegra124_dfll_fcpu_driver = { .probe = tegra124_dfll_fcpu_probe, - .remove = tegra_dfll_unregister, + .remove = tegra124_dfll_fcpu_remove, .driver = { .name = "tegra124-dfll", .of_match_table = tegra124_dfll_fcpu_of_match, diff --git a/drivers/clk/tegra/cvb.c b/drivers/clk/tegra/cvb.c index 7a099b18c368..624115e82ff9 100644 --- a/drivers/clk/tegra/cvb.c +++ b/drivers/clk/tegra/cvb.c @@ -130,3 +130,19 @@ tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *tables, return ERR_PTR(-EINVAL); } + +void tegra_cvb_remove_opp_table(struct device *dev, + const struct cvb_table *table, + unsigned long max_freq) +{ + unsigned int i; + + for (i = 0; i < MAX_DVFS_FREQS; i++) { + const struct cvb_table_freq_entry *entry = &table->entries[i]; + + if (!entry->freq || (entry->freq > max_freq)) + break; + + dev_pm_opp_remove(dev, entry->freq); + } +} diff --git a/drivers/clk/tegra/cvb.h b/drivers/clk/tegra/cvb.h index e6bf8581badd..c1f077993b2a 100644 --- a/drivers/clk/tegra/cvb.h +++ b/drivers/clk/tegra/cvb.h @@ -61,5 +61,8 @@ const struct cvb_table * tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *cvb_tables, size_t count, int process_id, int speedo_id, int speedo_value, unsigned long max_freq); +void tegra_cvb_remove_opp_table(struct device *dev, + const struct cvb_table *table, + unsigned long max_freq); #endif -- cgit v1.2.3 From 2690e912644e610854c4c3b23d0a0daec9d030ca Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 8 Apr 2016 15:17:27 +0200 Subject: clk: tegra: dfll: Reformat CVB frequency table Increase the readability of the CVB frequency table by reformatting it a little. Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra124-dfll-fcpu.c | 50 +++++++++++++++--------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index d052d9fa8230..c205809ba580 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -48,31 +48,31 @@ static const struct cvb_table tegra124_cpu_cvb_tables[] = { .speedo_scale = 100, .voltage_scale = 1000, .entries = { - {204000000UL, {1112619, -29295, 402} }, - {306000000UL, {1150460, -30585, 402} }, - {408000000UL, {1190122, -31865, 402} }, - {510000000UL, {1231606, -33155, 402} }, - {612000000UL, {1274912, -34435, 402} }, - {714000000UL, {1320040, -35725, 402} }, - {816000000UL, {1366990, -37005, 402} }, - {918000000UL, {1415762, -38295, 402} }, - {1020000000UL, {1466355, -39575, 402} }, - {1122000000UL, {1518771, -40865, 402} }, - {1224000000UL, {1573009, -42145, 402} }, - {1326000000UL, {1629068, -43435, 402} }, - {1428000000UL, {1686950, -44715, 402} }, - {1530000000UL, {1746653, -46005, 402} }, - {1632000000UL, {1808179, -47285, 402} }, - {1734000000UL, {1871526, -48575, 402} }, - {1836000000UL, {1936696, -49855, 402} }, - {1938000000UL, {2003687, -51145, 402} }, - {2014500000UL, {2054787, -52095, 402} }, - {2116500000UL, {2124957, -53385, 402} }, - {2218500000UL, {2196950, -54665, 402} }, - {2320500000UL, {2270765, -55955, 402} }, - {2422500000UL, {2346401, -57235, 402} }, - {2524500000UL, {2437299, -58535, 402} }, - {0, { 0, 0, 0} }, + { 204000000UL, { 1112619, -29295, 402 } }, + { 306000000UL, { 1150460, -30585, 402 } }, + { 408000000UL, { 1190122, -31865, 402 } }, + { 510000000UL, { 1231606, -33155, 402 } }, + { 612000000UL, { 1274912, -34435, 402 } }, + { 714000000UL, { 1320040, -35725, 402 } }, + { 816000000UL, { 1366990, -37005, 402 } }, + { 918000000UL, { 1415762, -38295, 402 } }, + { 1020000000UL, { 1466355, -39575, 402 } }, + { 1122000000UL, { 1518771, -40865, 402 } }, + { 1224000000UL, { 1573009, -42145, 402 } }, + { 1326000000UL, { 1629068, -43435, 402 } }, + { 1428000000UL, { 1686950, -44715, 402 } }, + { 1530000000UL, { 1746653, -46005, 402 } }, + { 1632000000UL, { 1808179, -47285, 402 } }, + { 1734000000UL, { 1871526, -48575, 402 } }, + { 1836000000UL, { 1936696, -49855, 402 } }, + { 1938000000UL, { 2003687, -51145, 402 } }, + { 2014500000UL, { 2054787, -52095, 402 } }, + { 2116500000UL, { 2124957, -53385, 402 } }, + { 2218500000UL, { 2196950, -54665, 402 } }, + { 2320500000UL, { 2270765, -55955, 402 } }, + { 2422500000UL, { 2346401, -57235, 402 } }, + { 2524500000UL, { 2437299, -58535, 402 } }, + { 0UL, { 0, 0, 0 } }, }, .cpu_dfll_data = { .tune0_low = 0x005020ff, -- cgit v1.2.3