diff options
Diffstat (limited to 'drivers/clk')
92 files changed, 3041 insertions, 819 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 68ca2d9fcd73..fdc99082a343 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -31,6 +31,13 @@ config COMMON_CLK_WM831X source "drivers/clk/versatile/Kconfig" +config CLK_HSDK + bool "PLL Driver for HSDK platform" + depends on OF || COMPILE_TEST + ---help--- + This driver supports the HSDK core, system, ddr, tunnel and hdmi PLLs + control. + config COMMON_CLK_MAX77686 tristate "Clock driver for Maxim 77620/77686/77802 MFD" depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST @@ -210,14 +217,14 @@ config COMMON_CLK_OXNAS Support for the OXNAS SoC Family clocks. config COMMON_CLK_VC5 - tristate "Clock driver for IDT VersaClock5 devices" + tristate "Clock driver for IDT VersaClock 5,6 devices" depends on I2C depends on OF select REGMAP_I2C help ---help--- - This driver supports the IDT VersaClock5 programmable clock - generator. + This driver supports the IDT VersaClock 5 and VersaClock 6 + programmable clock generators. source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index cd376b3fb47a..72e7c0eef32f 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o +obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o obj-$(CONFIG_ARCH_MB86S7X) += clk-mb86s7x.o obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o diff --git a/drivers/clk/axs10x/Makefile b/drivers/clk/axs10x/Makefile index 01996b871b06..d747deafbf1e 100644 --- a/drivers/clk/axs10x/Makefile +++ b/drivers/clk/axs10x/Makefile @@ -1 +1,2 @@ obj-y += i2s_pll_clock.o +obj-y += pll_clock.o diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c new file mode 100644 index 000000000000..25d8c240ddfb --- /dev/null +++ b/drivers/clk/axs10x/pll_clock.c @@ -0,0 +1,346 @@ +/* + * Synopsys AXS10X SDP Generic PLL clock driver + * + * Copyright (C) 2017 Synopsys + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/device.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/slab.h> +#include <linux/of.h> + +/* PLL registers addresses */ +#define PLL_REG_IDIV 0x0 +#define PLL_REG_FBDIV 0x4 +#define PLL_REG_ODIV 0x8 + +/* + * Bit fields of the PLL IDIV/FBDIV/ODIV registers: + * ________________________________________________________________________ + * |31 15| 14 | 13 | 12 |11 6|5 0| + * |-------RESRVED------|-NOUPDATE-|-BYPASS-|-EDGE-|--HIGHTIME--|--LOWTIME--| + * |____________________|__________|________|______|____________|___________| + * + * Following macros determine the way of access to these registers + * They should be set up only using the macros. + * reg should be an u32 variable. + */ + +#define PLL_REG_GET_LOW(reg) \ + (((reg) & (0x3F << 0)) >> 0) +#define PLL_REG_GET_HIGH(reg) \ + (((reg) & (0x3F << 6)) >> 6) +#define PLL_REG_GET_EDGE(reg) \ + (((reg) & (BIT(12))) ? 1 : 0) +#define PLL_REG_GET_BYPASS(reg) \ + (((reg) & (BIT(13))) ? 1 : 0) +#define PLL_REG_GET_NOUPD(reg) \ + (((reg) & (BIT(14))) ? 1 : 0) +#define PLL_REG_GET_PAD(reg) \ + (((reg) & (0x1FFFF << 15)) >> 15) + +#define PLL_REG_SET_LOW(reg, value) \ + { reg |= (((value) & 0x3F) << 0); } +#define PLL_REG_SET_HIGH(reg, value) \ + { reg |= (((value) & 0x3F) << 6); } +#define PLL_REG_SET_EDGE(reg, value) \ + { reg |= (((value) & 0x01) << 12); } +#define PLL_REG_SET_BYPASS(reg, value) \ + { reg |= (((value) & 0x01) << 13); } +#define PLL_REG_SET_NOUPD(reg, value) \ + { reg |= (((value) & 0x01) << 14); } +#define PLL_REG_SET_PAD(reg, value) \ + { reg |= (((value) & 0x1FFFF) << 15); } + +#define PLL_LOCK BIT(0) +#define PLL_ERROR BIT(1) +#define PLL_MAX_LOCK_TIME 100 /* 100 us */ + +struct axs10x_pll_cfg { + u32 rate; + u32 idiv; + u32 fbdiv; + u32 odiv; +}; + +static const struct axs10x_pll_cfg arc_pll_cfg[] = { + { 33333333, 1, 1, 1 }, + { 50000000, 1, 30, 20 }, + { 75000000, 2, 45, 10 }, + { 90000000, 2, 54, 10 }, + { 100000000, 1, 30, 10 }, + { 125000000, 2, 45, 6 }, + {} +}; + +static const struct axs10x_pll_cfg pgu_pll_cfg[] = { + { 25200000, 1, 84, 90 }, + { 50000000, 1, 100, 54 }, + { 74250000, 1, 44, 16 }, + {} +}; + +struct axs10x_pll_clk { + struct clk_hw hw; + void __iomem *base; + void __iomem *lock; + const struct axs10x_pll_cfg *pll_cfg; + struct device *dev; +}; + +static inline void axs10x_pll_write(struct axs10x_pll_clk *clk, u32 reg, + u32 val) +{ + iowrite32(val, clk->base + reg); +} + +static inline u32 axs10x_pll_read(struct axs10x_pll_clk *clk, u32 reg) +{ + return ioread32(clk->base + reg); +} + +static inline struct axs10x_pll_clk *to_axs10x_pll_clk(struct clk_hw *hw) +{ + return container_of(hw, struct axs10x_pll_clk, hw); +} + +static inline u32 axs10x_div_get_value(u32 reg) +{ + if (PLL_REG_GET_BYPASS(reg)) + return 1; + + return PLL_REG_GET_HIGH(reg) + PLL_REG_GET_LOW(reg); +} + +static inline u32 axs10x_encode_div(unsigned int id, int upd) +{ + u32 div = 0; + + PLL_REG_SET_LOW(div, (id % 2 == 0) ? id >> 1 : (id >> 1) + 1); + PLL_REG_SET_HIGH(div, id >> 1); + PLL_REG_SET_EDGE(div, id % 2); + PLL_REG_SET_BYPASS(div, id == 1 ? 1 : 0); + PLL_REG_SET_NOUPD(div, upd == 0 ? 1 : 0); + + return div; +} + +static unsigned long axs10x_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + u64 rate; + u32 idiv, fbdiv, odiv; + struct axs10x_pll_clk *clk = to_axs10x_pll_clk(hw); + + idiv = axs10x_div_get_value(axs10x_pll_read(clk, PLL_REG_IDIV)); + fbdiv = axs10x_div_get_value(axs10x_pll_read(clk, PLL_REG_FBDIV)); + odiv = axs10x_div_get_value(axs10x_pll_read(clk, PLL_REG_ODIV)); + + rate = (u64)parent_rate * fbdiv; + do_div(rate, idiv * odiv); + + return rate; +} + +static long axs10x_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int i; + long best_rate; + struct axs10x_pll_clk *clk = to_axs10x_pll_clk(hw); + const struct axs10x_pll_cfg *pll_cfg = clk->pll_cfg; + + if (pll_cfg[0].rate == 0) + return -EINVAL; + + best_rate = pll_cfg[0].rate; + + for (i = 1; pll_cfg[i].rate != 0; i++) { + if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate)) + best_rate = pll_cfg[i].rate; + } + + return best_rate; +} + +static int axs10x_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int i; + struct axs10x_pll_clk *clk = to_axs10x_pll_clk(hw); + const struct axs10x_pll_cfg *pll_cfg = clk->pll_cfg; + + for (i = 0; pll_cfg[i].rate != 0; i++) { + if (pll_cfg[i].rate == rate) { + axs10x_pll_write(clk, PLL_REG_IDIV, + axs10x_encode_div(pll_cfg[i].idiv, 0)); + axs10x_pll_write(clk, PLL_REG_FBDIV, + axs10x_encode_div(pll_cfg[i].fbdiv, 0)); + axs10x_pll_write(clk, PLL_REG_ODIV, + axs10x_encode_div(pll_cfg[i].odiv, 1)); + + /* + * Wait until CGU relocks and check error status. + * If after timeout CGU is unlocked yet return error + */ + udelay(PLL_MAX_LOCK_TIME); + if (!(ioread32(clk->lock) & PLL_LOCK)) + return -ETIMEDOUT; + + if (ioread32(clk->lock) & PLL_ERROR) + return -EINVAL; + + return 0; + } + } + + dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate, + parent_rate); + return -EINVAL; +} + +static const struct clk_ops axs10x_pll_ops = { + .recalc_rate = axs10x_pll_recalc_rate, + .round_rate = axs10x_pll_round_rate, + .set_rate = axs10x_pll_set_rate, +}; + +static int axs10x_pll_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const char *parent_name; + struct axs10x_pll_clk *pll_clk; + struct resource *mem; + struct clk_init_data init = { }; + int ret; + + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL); + if (!pll_clk) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pll_clk->base = devm_ioremap_resource(dev, mem); + if (IS_ERR(pll_clk->base)) + return PTR_ERR(pll_clk->base); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + pll_clk->lock = devm_ioremap_resource(dev, mem); + if (IS_ERR(pll_clk->lock)) + return PTR_ERR(pll_clk->lock); + + init.name = dev->of_node->name; + init.ops = &axs10x_pll_ops; + parent_name = of_clk_get_parent_name(dev->of_node, 0); + init.parent_names = &parent_name; + init.num_parents = 1; + pll_clk->hw.init = &init; + pll_clk->dev = dev; + pll_clk->pll_cfg = of_device_get_match_data(dev); + + if (!pll_clk->pll_cfg) { + dev_err(dev, "No OF match data provided\n"); + return -EINVAL; + } + + ret = devm_clk_hw_register(dev, &pll_clk->hw); + if (ret) { + dev_err(dev, "failed to register %s clock\n", init.name); + return ret; + } + + return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get, + &pll_clk->hw); +} + +static int axs10x_pll_clk_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + return 0; +} + +static void __init of_axs10x_pll_clk_setup(struct device_node *node) +{ + const char *parent_name; + struct axs10x_pll_clk *pll_clk; + struct clk_init_data init = { }; + int ret; + + pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); + if (!pll_clk) + return; + + pll_clk->base = of_iomap(node, 0); + if (!pll_clk->base) { + pr_err("failed to map pll div registers\n"); + goto err_free_pll_clk; + } + + pll_clk->lock = of_iomap(node, 1); + if (!pll_clk->lock) { + pr_err("failed to map pll lock register\n"); + goto err_unmap_base; + } + + init.name = node->name; + init.ops = &axs10x_pll_ops; + parent_name = of_clk_get_parent_name(node, 0); + init.parent_names = &parent_name; + init.num_parents = parent_name ? 1 : 0; + pll_clk->hw.init = &init; + pll_clk->pll_cfg = arc_pll_cfg; + + ret = clk_hw_register(NULL, &pll_clk->hw); + if (ret) { + pr_err("failed to register %s clock\n", node->name); + goto err_unmap_lock; + } + + ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw); + if (ret) { + pr_err("failed to add hw provider for %s clock\n", node->name); + goto err_unregister_clk; + } + + return; + +err_unregister_clk: + clk_hw_unregister(&pll_clk->hw); +err_unmap_lock: + iounmap(pll_clk->lock); +err_unmap_base: + iounmap(pll_clk->base); +err_free_pll_clk: + kfree(pll_clk); +} +CLK_OF_DECLARE(axs10x_pll_clock, "snps,axs10x-arc-pll-clock", + of_axs10x_pll_clk_setup); + +static const struct of_device_id axs10x_pll_clk_id[] = { + { .compatible = "snps,axs10x-pgu-pll-clock", .data = &pgu_pll_cfg}, + { } +}; +MODULE_DEVICE_TABLE(of, axs10x_pll_clk_id); + +static struct platform_driver axs10x_pll_clk_driver = { + .driver = { + .name = "axs10x-pll-clock", + .of_match_table = axs10x_pll_clk_id, + }, + .probe = axs10x_pll_clk_probe, + .remove = axs10x_pll_clk_remove, +}; +builtin_platform_driver(axs10x_pll_clk_driver); + +MODULE_AUTHOR("Vlad Zakharov <vzakhar@synopsys.com>"); +MODULE_DESCRIPTION("Synopsys AXS10X SDP Generic PLL Clock Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c index 1d99292e2039..e7331ace0337 100644 --- a/drivers/clk/berlin/bg2.c +++ b/drivers/clk/berlin/bg2.c @@ -679,8 +679,7 @@ static void __init berlin2_clock_setup(struct device_node *np) if (!IS_ERR(hws[n])) continue; - pr_err("%s: Unable to register leaf clock %d\n", - np->full_name, n); + pr_err("%pOF: Unable to register leaf clock %d\n", np, n); goto bg2_fail; } diff --git a/drivers/clk/berlin/bg2q.c b/drivers/clk/berlin/bg2q.c index 3b784b593afd..67c270b143f7 100644 --- a/drivers/clk/berlin/bg2q.c +++ b/drivers/clk/berlin/bg2q.c @@ -304,14 +304,14 @@ static void __init berlin2q_clock_setup(struct device_node *np) gbase = of_iomap(parent_np, 0); if (!gbase) { - pr_err("%s: Unable to map global base\n", np->full_name); + pr_err("%pOF: Unable to map global base\n", np); return; } /* BG2Q CPU PLL is not part of global registers */ cpupll_base = of_iomap(parent_np, 1); if (!cpupll_base) { - pr_err("%s: Unable to map cpupll base\n", np->full_name); + pr_err("%pOF: Unable to map cpupll base\n", np); iounmap(gbase); return; } @@ -376,8 +376,7 @@ static void __init berlin2q_clock_setup(struct device_node *np) if (!IS_ERR(hws[n])) continue; - pr_err("%s: Unable to register leaf clock %d\n", - np->full_name, n); + pr_err("%pOF: Unable to register leaf clock %d\n", np, n); goto bg2q_fail; } diff --git a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c index ea8568536193..bf0582cbbf38 100644 --- a/drivers/clk/clk-asm9260.c +++ b/drivers/clk/clk-asm9260.c @@ -338,8 +338,8 @@ static void __init asm9260_acc_init(struct device_node *np) if (!IS_ERR(hws[n])) continue; - pr_err("%s: Unable to register leaf clock %d\n", - np->full_name, n); + pr_err("%pOF: Unable to register leaf clock %d\n", + np, n); goto fail; } diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c index 7ec36722f8ab..49819b546134 100644 --- a/drivers/clk/clk-conf.c +++ b/drivers/clk/clk-conf.c @@ -23,8 +23,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) num_parents = of_count_phandle_with_args(node, "assigned-clock-parents", "#clock-cells"); if (num_parents == -EINVAL) - pr_err("clk: invalid value of clock-parents property at %s\n", - node->full_name); + pr_err("clk: invalid value of clock-parents property at %pOF\n", + node); for (index = 0; index < num_parents; index++) { rc = of_parse_phandle_with_args(node, "assigned-clock-parents", @@ -41,8 +41,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) pclk = of_clk_get_from_provider(&clkspec); if (IS_ERR(pclk)) { if (PTR_ERR(pclk) != -EPROBE_DEFER) - pr_warn("clk: couldn't get parent clock %d for %s\n", - index, node->full_name); + pr_warn("clk: couldn't get parent clock %d for %pOF\n", + index, node); return PTR_ERR(pclk); } @@ -57,8 +57,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) clk = of_clk_get_from_provider(&clkspec); if (IS_ERR(clk)) { if (PTR_ERR(clk) != -EPROBE_DEFER) - pr_warn("clk: couldn't get assigned clock %d for %s\n", - index, node->full_name); + pr_warn("clk: couldn't get assigned clock %d for %pOF\n", + index, node); rc = PTR_ERR(clk); goto err; } @@ -102,8 +102,8 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier) clk = of_clk_get_from_provider(&clkspec); if (IS_ERR(clk)) { if (PTR_ERR(clk) != -EPROBE_DEFER) - pr_warn("clk: couldn't get clock %d for %s\n", - index, node->full_name); + pr_warn("clk: couldn't get clock %d for %pOF\n", + index, node); return PTR_ERR(clk); } diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index aab904618eb6..fdf625fb10fa 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -49,16 +49,12 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, return ret; } -static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static void clk_fd_general_approximation(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate, + unsigned long *m, unsigned long *n) { struct clk_fractional_divider *fd = to_clk_fd(hw); unsigned long scale; - unsigned long m, n; - u64 ret; - - if (!rate || rate >= *parent_rate) - return *parent_rate; /* * Get rate closer to *parent_rate to guarantee there is no overflow @@ -71,7 +67,23 @@ static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate, rational_best_approximation(rate, *parent_rate, GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), - &m, &n); + m, n); +} + +static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_fractional_divider *fd = to_clk_fd(hw); + unsigned long m, n; + u64 ret; + + if (!rate || rate >= *parent_rate) + return *parent_rate; + + if (fd->approximation) + fd->approximation(hw, rate, parent_rate, &m, &n); + else + clk_fd_general_approximation(hw, rate, parent_rate, &m, &n); ret = (u64)*parent_rate * m; do_div(ret, n); diff --git a/drivers/clk/clk-gemini.c b/drivers/clk/clk-gemini.c index c391a49aaaff..f940e5af845b 100644 --- a/drivers/clk/clk-gemini.c +++ b/drivers/clk/clk-gemini.c @@ -37,7 +37,6 @@ static DEFINE_SPINLOCK(gemini_clk_lock); #define GEMINI_GLOBAL_MISC_CONTROL 0x30 #define PCI_CLK_66MHZ BIT(18) -#define PCI_CLK_OE BIT(17) #define GEMINI_GLOBAL_CLOCK_CONTROL 0x34 #define PCI_CLKRUN_EN BIT(16) @@ -159,9 +158,6 @@ static int gemini_pci_enable(struct clk_hw *hw) regmap_update_bits(pciclk->map, GEMINI_GLOBAL_CLOCK_CONTROL, 0, PCI_CLKRUN_EN); - regmap_update_bits(pciclk->map, - GEMINI_GLOBAL_MISC_CONTROL, - 0, PCI_CLK_OE); return 0; } @@ -169,9 +165,6 @@ static void gemini_pci_disable(struct clk_hw *hw) { struct clk_gemini_pci *pciclk = to_pciclk(hw); - regmap_update_bits(pciclk->map, - GEMINI_GLOBAL_MISC_CONTROL, - PCI_CLK_OE, 0); regmap_update_bits(pciclk->map, GEMINI_GLOBAL_CLOCK_CONTROL, PCI_CLKRUN_EN, 0); } @@ -237,6 +230,18 @@ static int gemini_reset(struct reset_controller_dev *rcdev, BIT(GEMINI_RESET_CPU1) | BIT(id)); } +static int gemini_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return 0; +} + +static int gemini_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return 0; +} + static int gemini_reset_status(struct reset_controller_dev *rcdev, unsigned long id) { @@ -253,6 +258,8 @@ static int gemini_reset_status(struct reset_controller_dev *rcdev, static const struct reset_control_ops gemini_reset_ops = { .reset = gemini_reset, + .assert = gemini_reset_assert, + .deassert = gemini_reset_deassert, .status = gemini_reset_status, }; diff --git a/drivers/clk/clk-hsdk-pll.c b/drivers/clk/clk-hsdk-pll.c new file mode 100644 index 000000000000..bbf237173b37 --- /dev/null +++ b/drivers/clk/clk-hsdk-pll.c @@ -0,0 +1,431 @@ +/* + * Synopsys HSDK SDP Generic PLL clock driver + * + * Copyright (C) 2017 Synopsys + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define CGU_PLL_CTRL 0x000 /* ARC PLL control register */ +#define CGU_PLL_STATUS 0x004 /* ARC PLL status register */ +#define CGU_PLL_FMEAS 0x008 /* ARC PLL frequency measurement register */ +#define CGU_PLL_MON 0x00C /* ARC PLL monitor register */ + +#define CGU_PLL_CTRL_ODIV_SHIFT 2 +#define CGU_PLL_CTRL_IDIV_SHIFT 4 +#define CGU_PLL_CTRL_FBDIV_SHIFT 9 +#define CGU_PLL_CTRL_BAND_SHIFT 20 + +#define CGU_PLL_CTRL_ODIV_MASK GENMASK(3, CGU_PLL_CTRL_ODIV_SHIFT) +#define CGU_PLL_CTRL_IDIV_MASK GENMASK(8, CGU_PLL_CTRL_IDIV_SHIFT) +#define CGU_PLL_CTRL_FBDIV_MASK GENMASK(15, CGU_PLL_CTRL_FBDIV_SHIFT) + +#define CGU_PLL_CTRL_PD BIT(0) +#define CGU_PLL_CTRL_BYPASS BIT(1) + +#define CGU_PLL_STATUS_LOCK BIT(0) +#define CGU_PLL_STATUS_ERR BIT(1) + +#define HSDK_PLL_MAX_LOCK_TIME 100 /* 100 us */ + +#define CGU_PLL_SOURCE_MAX 1 + +#define CORE_IF_CLK_THRESHOLD_HZ 500000000 +#define CREG_CORE_IF_CLK_DIV_1 0x0 +#define CREG_CORE_IF_CLK_DIV_2 0x1 + +struct hsdk_pll_cfg { + u32 rate; + u32 idiv; + u32 fbdiv; + u32 odiv; + u32 band; +}; + +static const struct hsdk_pll_cfg asdt_pll_cfg[] = { + { 100000000, 0, 11, 3, 0 }, + { 133000000, 0, 15, 3, 0 }, + { 200000000, 1, 47, 3, 0 }, + { 233000000, 1, 27, 2, 0 }, + { 300000000, 1, 35, 2, 0 }, + { 333000000, 1, 39, 2, 0 }, + { 400000000, 1, 47, 2, 0 }, + { 500000000, 0, 14, 1, 0 }, + { 600000000, 0, 17, 1, 0 }, + { 700000000, 0, 20, 1, 0 }, + { 800000000, 0, 23, 1, 0 }, + { 900000000, 1, 26, 0, 0 }, + { 1000000000, 1, 29, 0, 0 }, + { 1100000000, 1, 32, 0, 0 }, + { 1200000000, 1, 35, 0, 0 }, + { 1300000000, 1, 38, 0, 0 }, + { 1400000000, 1, 41, 0, 0 }, + { 1500000000, 1, 44, 0, 0 }, + { 1600000000, 1, 47, 0, 0 }, + {} +}; + +static const struct hsdk_pll_cfg hdmi_pll_cfg[] = { + { 297000000, 0, 21, 2, 0 }, + { 540000000, 0, 19, 1, 0 }, + { 594000000, 0, 21, 1, 0 }, + {} +}; + +struct hsdk_pll_clk { + struct clk_hw hw; + void __iomem *regs; + void __iomem *spec_regs; + const struct hsdk_pll_devdata *pll_devdata; + struct device *dev; +}; + +struct hsdk_pll_devdata { + const struct hsdk_pll_cfg *pll_cfg; + int (*update_rate)(struct hsdk_pll_clk *clk, unsigned long rate, + const struct hsdk_pll_cfg *cfg); +}; + +static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *, unsigned long, + const struct hsdk_pll_cfg *); +static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *, unsigned long, + const struct hsdk_pll_cfg *); + +static const struct hsdk_pll_devdata core_pll_devdata = { + .pll_cfg = asdt_pll_cfg, + .update_rate = hsdk_pll_core_update_rate, +}; + +static const struct hsdk_pll_devdata sdt_pll_devdata = { + .pll_cfg = asdt_pll_cfg, + .update_rate = hsdk_pll_comm_update_rate, +}; + +static const struct hsdk_pll_devdata hdmi_pll_devdata = { + .pll_cfg = hdmi_pll_cfg, + .update_rate = hsdk_pll_comm_update_rate, +}; + +static inline void hsdk_pll_write(struct hsdk_pll_clk *clk, u32 reg, u32 val) +{ + iowrite32(val, clk->regs + reg); +} + +static inline u32 hsdk_pll_read(struct hsdk_pll_clk *clk, u32 reg) +{ + return ioread32(clk->regs + reg); +} + +static inline void hsdk_pll_set_cfg(struct hsdk_pll_clk *clk, + const struct hsdk_pll_cfg *cfg) +{ + u32 val = 0; + + /* Powerdown and Bypass bits should be cleared */ + val |= cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT; + val |= cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT; + val |= cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT; + val |= cfg->band << CGU_PLL_CTRL_BAND_SHIFT; + + dev_dbg(clk->dev, "write configurarion: %#x\n", val); + + hsdk_pll_write(clk, CGU_PLL_CTRL, val); +} + +static inline bool hsdk_pll_is_locked(struct hsdk_pll_clk *clk) +{ + return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_LOCK); +} + +static inline bool hsdk_pll_is_err(struct hsdk_pll_clk *clk) +{ + return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_ERR); +} + +static inline struct hsdk_pll_clk *to_hsdk_pll_clk(struct clk_hw *hw) +{ + return container_of(hw, struct hsdk_pll_clk, hw); +} + +static unsigned long hsdk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + u32 val; + u64 rate; + u32 idiv, fbdiv, odiv; + struct hsdk_pll_clk *clk = to_hsdk_pll_clk(hw); + + val = hsdk_pll_read(clk, CGU_PLL_CTRL); + + dev_dbg(clk->dev, "current configurarion: %#x\n", val); + + /* Check if PLL is disabled */ + if (val & CGU_PLL_CTRL_PD) + return 0; + + /* Check if PLL is bypassed */ + if (val & CGU_PLL_CTRL_BYPASS) + return parent_rate; + + /* input divider = reg.idiv + 1 */ + idiv = 1 + ((val & CGU_PLL_CTRL_IDIV_MASK) >> CGU_PLL_CTRL_IDIV_SHIFT); + /* fb divider = 2*(reg.fbdiv + 1) */ + fbdiv = 2 * (1 + ((val & CGU_PLL_CTRL_FBDIV_MASK) >> CGU_PLL_CTRL_FBDIV_SHIFT)); + /* output divider = 2^(reg.odiv) */ + odiv = 1 << ((val & CGU_PLL_CTRL_ODIV_MASK) >> CGU_PLL_CTRL_ODIV_SHIFT); + + rate = (u64)parent_rate * fbdiv; + do_div(rate, idiv * odiv); + + return rate; +} + +static long hsdk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int i; + unsigned long best_rate; + struct hsdk_pll_clk *clk = to_hsdk_pll_clk(hw); + const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg; + + if (pll_cfg[0].rate == 0) + return -EINVAL; + + best_rate = pll_cfg[0].rate; + + for (i = 1; pll_cfg[i].rate != 0; i++) { + if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate)) + best_rate = pll_cfg[i].rate; + } + + dev_dbg(clk->dev, "chosen best rate: %lu\n", best_rate); + + return best_rate; +} + +static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *clk, + unsigned long rate, + const struct hsdk_pll_cfg *cfg) +{ + hsdk_pll_set_cfg(clk, cfg); + + /* + * Wait until CGU relocks and check error status. + * If after timeout CGU is unlocked yet return error. + */ + udelay(HSDK_PLL_MAX_LOCK_TIME); + if (!hsdk_pll_is_locked(clk)) + return -ETIMEDOUT; + + if (hsdk_pll_is_err(clk)) + return -EINVAL; + + return 0; +} + +static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *clk, + unsigned long rate, + const struct hsdk_pll_cfg *cfg) +{ + /* + * When core clock exceeds 500MHz, the divider for the interface + * clock must be programmed to div-by-2. + */ + if (rate > CORE_IF_CLK_THRESHOLD_HZ) + iowrite32(CREG_CORE_IF_CLK_DIV_2, clk->spec_regs); + + hsdk_pll_set_cfg(clk, cfg); + + /* + * Wait until CGU relocks and check error status. + * If after timeout CGU is unlocked yet return error. + */ + udelay(HSDK_PLL_MAX_LOCK_TIME); + if (!hsdk_pll_is_locked(clk)) + return -ETIMEDOUT; + + if (hsdk_pll_is_err(clk)) + return -EINVAL; + + /* + * Program divider to div-by-1 if we succesfuly set core clock below + * 500MHz threshold. + */ + if (rate <= CORE_IF_CLK_THRESHOLD_HZ) + iowrite32(CREG_CORE_IF_CLK_DIV_1, clk->spec_regs); + + return 0; +} + +static int hsdk_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int i; + struct hsdk_pll_clk *clk = to_hsdk_pll_clk(hw); + const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg; + + for (i = 0; pll_cfg[i].rate != 0; i++) { + if (pll_cfg[i].rate == rate) { + return clk->pll_devdata->update_rate(clk, rate, + &pll_cfg[i]); + } + } + + dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate, + parent_rate); + + return -EINVAL; +} + +static const struct clk_ops hsdk_pll_ops = { + .recalc_rate = hsdk_pll_recalc_rate, + .round_rate = hsdk_pll_round_rate, + .set_rate = hsdk_pll_set_rate, +}; + +static int hsdk_pll_clk_probe(struct platform_device *pdev) +{ + int ret; + struct resource *mem; + const char *parent_name; + unsigned int num_parents; + struct hsdk_pll_clk *pll_clk; + struct clk_init_data init = { }; + struct device *dev = &pdev->dev; + + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL); + if (!pll_clk) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pll_clk->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(pll_clk->regs)) + return PTR_ERR(pll_clk->regs); + + init.name = dev->of_node->name; + init.ops = &hsdk_pll_ops; + parent_name = of_clk_get_parent_name(dev->of_node, 0); + init.parent_names = &parent_name; + num_parents = of_clk_get_parent_count(dev->of_node); + if (num_parents == 0 || num_parents > CGU_PLL_SOURCE_MAX) { + dev_err(dev, "wrong clock parents number: %u\n", num_parents); + return -EINVAL; + } + init.num_parents = num_parents; + + pll_clk->hw.init = &init; + pll_clk->dev = dev; + pll_clk->pll_devdata = of_device_get_match_data(dev); + + if (!pll_clk->pll_devdata) { + dev_err(dev, "No OF match data provided\n"); + return -EINVAL; + } + + ret = devm_clk_hw_register(dev, &pll_clk->hw); + if (ret) { + dev_err(dev, "failed to register %s clock\n", init.name); + return ret; + } + + return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get, + &pll_clk->hw); +} + +static int hsdk_pll_clk_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + return 0; +} + +static void __init of_hsdk_pll_clk_setup(struct device_node *node) +{ + int ret; + const char *parent_name; + unsigned int num_parents; + struct hsdk_pll_clk *pll_clk; + struct clk_init_data init = { }; + + pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); + if (!pll_clk) + return; + + pll_clk->regs = of_iomap(node, 0); + if (!pll_clk->regs) { + pr_err("failed to map pll registers\n"); + goto err_free_pll_clk; + } + + pll_clk->spec_regs = of_iomap(node, 1); + if (!pll_clk->spec_regs) { + pr_err("failed to map pll registers\n"); + goto err_unmap_comm_regs; + } + + init.name = node->name; + init.ops = &hsdk_pll_ops; + parent_name = of_clk_get_parent_name(node, 0); + init.parent_names = &parent_name; + num_parents = of_clk_get_parent_count(node); + if (num_parents > CGU_PLL_SOURCE_MAX) { + pr_err("too much clock parents: %u\n", num_parents); + goto err_unmap_spec_regs; + } + init.num_parents = num_parents; + + pll_clk->hw.init = &init; + pll_clk->pll_devdata = &core_pll_devdata; + + ret = clk_hw_register(NULL, &pll_clk->hw); + if (ret) { + pr_err("failed to register %s clock\n", node->name); + goto err_unmap_spec_regs; + } + + ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw); + if (ret) { + pr_err("failed to add hw provider for %s clock\n", node->name); + goto err_unmap_spec_regs; + } + + return; + +err_unmap_spec_regs: + iounmap(pll_clk->spec_regs); +err_unmap_comm_regs: + iounmap(pll_clk->regs); +err_free_pll_clk: + kfree(pll_clk); +} + +/* Core PLL needed early for ARC cpus timers */ +CLK_OF_DECLARE(hsdk_pll_clock, "snps,hsdk-core-pll-clock", +of_hsdk_pll_clk_setup); + +static const struct of_device_id hsdk_pll_clk_id[] = { + { .compatible = "snps,hsdk-gp-pll-clock", .data = &sdt_pll_devdata}, + { .compatible = "snps,hsdk-hdmi-pll-clock", .data = &hdmi_pll_devdata}, + { } +}; + +static struct platform_driver hsdk_pll_clk_driver = { + .driver = { + .name = "hsdk-gp-pll-clock", + .of_match_table = hsdk_pll_clk_id, + }, + .probe = hsdk_pll_clk_probe, + .remove = hsdk_pll_clk_remove, +}; +builtin_platform_driver(hsdk_pll_clk_driver); diff --git a/drivers/clk/clk-moxart.c b/drivers/clk/clk-moxart.c index b86dac851116..58428d0043fd 100644 --- a/drivers/clk/clk-moxart.c +++ b/drivers/clk/clk-moxart.c @@ -18,7 +18,7 @@ static void __init moxart_of_pll_clk_init(struct device_node *node) { - static void __iomem *base; + void __iomem *base; struct clk_hw *hw; struct clk *ref_clk; unsigned int mul; @@ -30,7 +30,7 @@ static void __init moxart_of_pll_clk_init(struct device_node *node) base = of_iomap(node, 0); if (!base) { - pr_err("%s: of_iomap failed\n", node->full_name); + pr_err("%pOF: of_iomap failed\n", node); return; } @@ -39,13 +39,13 @@ static void __init moxart_of_pll_clk_init(struct device_node *node) ref_clk = of_clk_get(node, 0); if (IS_ERR(ref_clk)) { - pr_err("%s: of_clk_get failed\n", node->full_name); + pr_err("%pOF: of_clk_get failed\n", node); return; } hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mul, 1); if (IS_ERR(hw)) { - pr_err("%s: failed to register clock\n", node->full_name); + pr_err("%pOF: failed to register clock\n", node); return; } @@ -57,7 +57,7 @@ CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock", static void __init moxart_of_apb_clk_init(struct device_node *node) { - static void __iomem *base; + void __iomem *base; struct clk_hw *hw; struct clk *pll_clk; unsigned int div, val; @@ -70,7 +70,7 @@ static void __init moxart_of_apb_clk_init(struct device_node *node) base = of_iomap(node, 0); if (!base) { - pr_err("%s: of_iomap failed\n", node->full_name); + pr_err("%pOF: of_iomap failed\n", node); return; } @@ -83,13 +83,13 @@ static void __init moxart_of_apb_clk_init(struct device_node *node) pll_clk = of_clk_get(node, 0); if (IS_ERR(pll_clk)) { - pr_err("%s: of_clk_get failed\n", node->full_name); + pr_err("%pOF: of_clk_get failed\n", node); return; } hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, 1, div); if (IS_ERR(hw)) { - pr_err("%s: failed to register clock\n", node->full_name); + pr_err("%pOF: failed to register clock\n", node); return; } diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index f3931e38fac0..b0ea753b8709 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -12,6 +12,7 @@ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/clkdev.h> #include <linux/fsl/guts.h> #include <linux/io.h> #include <linux/kernel.h> @@ -537,6 +538,17 @@ static const struct clockgen_chipinfo chipinfo[] = { .flags = CG_PLL_8BIT, }, { + .compat = "fsl,ls1088a-clockgen", + .cmux_groups = { + &clockgen2_cmux_cga12 + }, + .cmux_to_group = { + 0, 0, -1 + }, + .pll_mask = 0x07, + .flags = CG_VER3 | CG_LITTLE_ENDIAN, + }, + { .compat = "fsl,ls1012a-clockgen", .cmux_groups = { &ls1012a_cmux @@ -1113,6 +1125,7 @@ static void __init create_one_pll(struct clockgen *cg, int idx) for (i = 0; i < ARRAY_SIZE(pll->div); i++) { struct clk *clk; + int ret; snprintf(pll->div[i].name, sizeof(pll->div[i].name), "cg-pll%d-div%d", idx, i + 1); @@ -1126,6 +1139,11 @@ static void __init create_one_pll(struct clockgen *cg, int idx) } pll->div[i].clk = clk; + ret = clk_register_clkdev(clk, pll->div[i].name, NULL); + if (ret != 0) + pr_err("%s: %s: register to lookup table failed %ld\n", + __func__, pll->div[i].name, PTR_ERR(clk)); + } } @@ -1348,8 +1366,7 @@ static void __init clockgen_init(struct device_node *np) } if (i == ARRAY_SIZE(chipinfo)) { - pr_err("%s: unknown clockgen node %s\n", __func__, - np->full_name); + pr_err("%s: unknown clockgen node %pOF\n", __func__, np); goto err; } clockgen.info = chipinfo[i]; @@ -1362,8 +1379,8 @@ static void __init clockgen_init(struct device_node *np) if (guts) { clockgen.guts = of_iomap(guts, 0); if (!clockgen.guts) { - pr_err("%s: Couldn't map %s regs\n", __func__, - guts->full_name); + pr_err("%s: Couldn't map %pOF regs\n", __func__, + guts); } } @@ -1398,6 +1415,7 @@ CLK_OF_DECLARE(qoriq_clockgen_ls1012a, "fsl,ls1012a-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_ls1021a, "fsl,ls1021a-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init); +CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init); /* Legacy nodes */ diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index 68e2a4e499f1..96c6b6bc8f0e 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -1541,8 +1541,8 @@ static void __init stm32f4_rcc_init(struct device_node *np) base + gd->offset, gd->bit_idx, 0, &stm32f4_clk_lock); if (IS_ERR(clks[idx])) { - pr_err("%s: Unable to register leaf clock %s\n", - np->full_name, gd->name); + pr_err("%pOF: Unable to register leaf clock %s\n", + np, gd->name); goto fail; } } diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c index ea7d552a2f2b..decffb3826ec 100644 --- a/drivers/clk/clk-versaclock5.c +++ b/drivers/clk/clk-versaclock5.c @@ -57,6 +57,7 @@ #define VC5_PRIM_SRC_SHDN 0x10 #define VC5_PRIM_SRC_SHDN_EN_XTAL BIT(7) #define VC5_PRIM_SRC_SHDN_EN_CLKIN BIT(6) +#define VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ BIT(3) #define VC5_PRIM_SRC_SHDN_SP BIT(1) #define VC5_PRIM_SRC_SHDN_EN_GBL_SHDN BIT(0) @@ -122,12 +123,16 @@ /* flags to describe chip features */ /* chip has built-in oscilator */ #define VC5_HAS_INTERNAL_XTAL BIT(0) +/* chip has PFD requency doubler */ +#define VC5_HAS_PFD_FREQ_DBL BIT(1) /* Supported IDT VC5 models. */ enum vc5_model { IDT_VC5_5P49V5923, + IDT_VC5_5P49V5925, IDT_VC5_5P49V5933, IDT_VC5_5P49V5935, + IDT_VC6_5P49V6901, }; /* Structure to describe features of a particular VC5 model */ @@ -157,6 +162,8 @@ struct vc5_driver_data { struct clk *pin_clkin; unsigned char clk_mux_ins; struct clk_hw clk_mux; + struct clk_hw clk_mul; + struct clk_hw clk_pfd; struct vc5_hw_data clk_pll; struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM]; struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM]; @@ -166,6 +173,14 @@ static const char * const vc5_mux_names[] = { "mux" }; +static const char * const vc5_dbl_names[] = { + "dbl" +}; + +static const char * const vc5_pfd_names[] = { + "pfd" +}; + static const char * const vc5_pll_names[] = { "pll" }; @@ -254,11 +269,64 @@ static int vc5_mux_set_parent(struct clk_hw *hw, u8 index) return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, mask, src); } -static unsigned long vc5_mux_recalc_rate(struct clk_hw *hw, +static const struct clk_ops vc5_mux_ops = { + .set_parent = vc5_mux_set_parent, + .get_parent = vc5_mux_get_parent, +}; + +static unsigned long vc5_dbl_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct vc5_driver_data *vc5 = - container_of(hw, struct vc5_driver_data, clk_mux); + container_of(hw, struct vc5_driver_data, clk_mul); + unsigned int premul; + + regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &premul); + if (premul & VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ) + parent_rate *= 2; + + return parent_rate; +} + +static long vc5_dbl_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + if ((*parent_rate == rate) || ((*parent_rate * 2) == rate)) + return rate; + else + return -EINVAL; +} + +static int vc5_dbl_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct vc5_driver_data *vc5 = + container_of(hw, struct vc5_driver_data, clk_mul); + u32 mask; + + if ((parent_rate * 2) == rate) + mask = VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ; + else + mask = 0; + + regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, + VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ, + mask); + + return 0; +} + +static const struct clk_ops vc5_dbl_ops = { + .recalc_rate = vc5_dbl_recalc_rate, + .round_rate = vc5_dbl_round_rate, + .set_rate = vc5_dbl_set_rate, +}; + +static unsigned long vc5_pfd_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct vc5_driver_data *vc5 = + container_of(hw, struct vc5_driver_data, clk_pfd); unsigned int prediv, div; regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv); @@ -276,7 +344,7 @@ static unsigned long vc5_mux_recalc_rate(struct clk_hw *hw, return parent_rate / VC5_REF_DIVIDER_REF_DIV(div); } -static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate, +static long vc5_pfd_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { unsigned long idiv; @@ -296,11 +364,11 @@ static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate, return *parent_rate / idiv; } -static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate, +static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct vc5_driver_data *vc5 = - container_of(hw, struct vc5_driver_data, clk_mux); + container_of(hw, struct vc5_driver_data, clk_pfd); unsigned long idiv; u8 div; @@ -328,12 +396,10 @@ static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -static const struct clk_ops vc5_mux_ops = { - .set_parent = vc5_mux_set_parent, - .get_parent = vc5_mux_get_parent, - .recalc_rate = vc5_mux_recalc_rate, - .round_rate = vc5_mux_round_rate, - .set_rate = vc5_mux_set_rate, +static const struct clk_ops vc5_pfd_ops = { + .recalc_rate = vc5_pfd_recalc_rate, + .round_rate = vc5_pfd_round_rate, + .set_rate = vc5_pfd_set_rate, }; /* @@ -426,6 +492,10 @@ static unsigned long vc5_fod_recalc_rate(struct clk_hw *hw, div_frc = (od_frc[0] << 22) | (od_frc[1] << 14) | (od_frc[2] << 6) | (od_frc[3] >> 2); + /* Avoid division by zero if the output is not configured. */ + if (div_int == 0 && div_frc == 0) + return 0; + /* The PLL divider has 12 integer bits and 30 fractional bits */ return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc); } @@ -503,6 +573,25 @@ static int vc5_clk_out_prepare(struct clk_hw *hw) { struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); struct vc5_driver_data *vc5 = hwdata->vc5; + const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM | + VC5_OUT_DIV_CONTROL_SEL_EXT | + VC5_OUT_DIV_CONTROL_EN_FOD; + unsigned int src; + int ret; + + /* + * If the input mux is disabled, enable it first and + * select source from matching FOD. + */ + regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src); + if ((src & mask) == 0) { + src = VC5_OUT_DIV_CONTROL_RESET | VC5_OUT_DIV_CONTROL_EN_FOD; + ret = regmap_update_bits(vc5->regmap, + VC5_OUT_DIV_CONTROL(hwdata->num), + mask | VC5_OUT_DIV_CONTROL_RESET, src); + if (ret) + return ret; + } /* Enable the clock buffer */ regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1), @@ -516,7 +605,7 @@ static void vc5_clk_out_unprepare(struct clk_hw *hw) struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); struct vc5_driver_data *vc5 = hwdata->vc5; - /* Enable the clock buffer */ + /* Disable the clock buffer */ regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1), VC5_CLK_OUTPUT_CFG1_EN_CLKBUF, 0); } @@ -537,6 +626,9 @@ static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw) regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src); src &= mask; + if (src == 0) /* Input mux set to DISABLED */ + return 0; + if ((src & fodclkmask) == VC5_OUT_DIV_CONTROL_EN_FOD) return 0; @@ -595,7 +687,9 @@ static int vc5_map_index_to_output(const enum vc5_model model, case IDT_VC5_5P49V5933: return (n == 0) ? 0 : 3; case IDT_VC5_5P49V5923: + case IDT_VC5_5P49V5925: case IDT_VC5_5P49V5935: + case IDT_VC6_5P49V6901: default: return n; } @@ -672,12 +766,46 @@ static int vc5_probe(struct i2c_client *client, goto err_clk; } + if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) { + /* Register frequency doubler */ + memset(&init, 0, sizeof(init)); + init.name = vc5_dbl_names[0]; + init.ops = &vc5_dbl_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = vc5_mux_names; + init.num_parents = 1; + vc5->clk_mul.init = &init; + ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul); + if (ret) { + dev_err(&client->dev, "unable to register %s\n", + init.name); + goto err_clk; + } + } + + /* Register PFD */ + memset(&init, 0, sizeof(init)); + init.name = vc5_pfd_names[0]; + init.ops = &vc5_pfd_ops; + init.flags = CLK_SET_RATE_PARENT; + if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) + init.parent_names = vc5_dbl_names; + else + init.parent_names = vc5_mux_names; + init.num_parents = 1; + vc5->clk_pfd.init = &init; + ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd); + if (ret) { + dev_err(&client->dev, "unable to register %s\n", init.name); + goto err_clk; + } + /* Register PLL */ memset(&init, 0, sizeof(init)); init.name = vc5_pll_names[0]; init.ops = &vc5_pll_ops; init.flags = CLK_SET_RATE_PARENT; - init.parent_names = vc5_mux_names; + init.parent_names = vc5_pfd_names; init.num_parents = 1; vc5->clk_pll.num = 0; vc5->clk_pll.vc5 = vc5; @@ -785,6 +913,13 @@ static const struct vc5_chip_info idt_5p49v5923_info = { .flags = 0, }; +static const struct vc5_chip_info idt_5p49v5925_info = { + .model = IDT_VC5_5P49V5925, + .clk_fod_cnt = 4, + .clk_out_cnt = 5, + .flags = 0, +}; + static const struct vc5_chip_info idt_5p49v5933_info = { .model = IDT_VC5_5P49V5933, .clk_fod_cnt = 2, @@ -799,18 +934,29 @@ static const struct vc5_chip_info idt_5p49v5935_info = { .flags = VC5_HAS_INTERNAL_XTAL, }; +static const struct vc5_chip_info idt_5p49v6901_info = { + .model = IDT_VC6_5P49V6901, + .clk_fod_cnt = 4, + .clk_out_cnt = 5, + .flags = VC5_HAS_PFD_FREQ_DBL, +}; + static const struct i2c_device_id vc5_id[] = { { "5p49v5923", .driver_data = IDT_VC5_5P49V5923 }, + { "5p49v5925", .driver_data = IDT_VC5_5P49V5925 }, { "5p49v5933", .driver_data = IDT_VC5_5P49V5933 }, { "5p49v5935", .driver_data = IDT_VC5_5P49V5935 }, + { "5p49v6901", .driver_data = IDT_VC6_5P49V6901 }, { } }; MODULE_DEVICE_TABLE(i2c, vc5_id); static const struct of_device_id clk_vc5_of_match[] = { { .compatible = "idt,5p49v5923", .data = &idt_5p49v5923_info }, + { .compatible = "idt,5p49v5925", .data = &idt_5p49v5925_info }, { .compatible = "idt,5p49v5933", .data = &idt_5p49v5933_info }, { .compatible = "idt,5p49v5935", .data = &idt_5p49v5935_info }, + { .compatible = "idt,5p49v6901", .data = &idt_5p49v6901_info }, { }, }; MODULE_DEVICE_TABLE(of, clk_vc5_of_match); diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c index bc37030e38ba..4c75821a3933 100644 --- a/drivers/clk/clk-xgene.c +++ b/drivers/clk/clk-xgene.c @@ -192,7 +192,7 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty reg = of_iomap(np, 0); if (reg == NULL) { - pr_err("Unable to map CSR register for %s\n", np->full_name); + pr_err("Unable to map CSR register for %pOF\n", np); return; } of_property_read_string(np, "clock-output-names", &clk_name); @@ -409,12 +409,12 @@ static void xgene_pmdclk_init(struct device_node *np) /* Parse the DTS register for resource */ rc = of_address_to_resource(np, 0, &res); if (rc != 0) { - pr_err("no DTS register for %s\n", np->full_name); + pr_err("no DTS register for %pOF\n", np); return; } csr_reg = of_iomap(np, 0); if (!csr_reg) { - pr_err("Unable to map resource for %s\n", np->full_name); + pr_err("Unable to map resource for %pOF\n", np); return; } of_property_read_string(np, "clock-output-names", &clk_name); @@ -703,16 +703,14 @@ static void __init xgene_devclk_init(struct device_node *np) rc = of_address_to_resource(np, i, &res); if (rc != 0) { if (i == 0) { - pr_err("no DTS register for %s\n", - np->full_name); + pr_err("no DTS register for %pOF\n", np); return; } break; } map_res = of_iomap(np, i); if (map_res == NULL) { - pr_err("Unable to map resource %d for %s\n", - i, np->full_name); + pr_err("Unable to map resource %d for %pOF\n", i, np); goto err; } if (strcmp(res.name, "div-reg") == 0) @@ -747,8 +745,7 @@ static void __init xgene_devclk_init(struct device_node *np) pr_debug("Add %s clock\n", clk_name); rc = of_clk_add_provider(np, of_clk_src_simple_get, clk); if (rc != 0) - pr_err("%s: could register provider clk %s\n", __func__, - np->full_name); + pr_err("%s: could register provider clk %pOF\n", __func__, np); return; diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index fc58c52a26b4..c8d83acda006 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3132,7 +3132,7 @@ int of_clk_add_provider(struct device_node *np, mutex_lock(&of_clk_mutex); list_add(&cp->link, &of_clk_providers); mutex_unlock(&of_clk_mutex); - pr_debug("Added clock from %s\n", np->full_name); + pr_debug("Added clock from %pOF\n", np); ret = of_clk_set_defaults(np, true); if (ret < 0) @@ -3167,7 +3167,7 @@ int of_clk_add_hw_provider(struct device_node *np, mutex_lock(&of_clk_mutex); list_add(&cp->link, &of_clk_providers); mutex_unlock(&of_clk_mutex); - pr_debug("Added clk_hw provider from %s\n", np->full_name); + pr_debug("Added clk_hw provider from %pOF\n", np); ret = of_clk_set_defaults(np, true); if (ret < 0) diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index bb8a77a5985f..6b2f29df3f70 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -77,8 +77,8 @@ static struct clk *__of_clk_get_by_name(struct device_node *np, break; } else if (name && index >= 0) { if (PTR_ERR(clk) != -EPROBE_DEFER) - pr_err("ERROR: could not get clock %s:%s(%i)\n", - np->full_name, name ? name : "", index); + pr_err("ERROR: could not get clock %pOF:%s(%i)\n", + np, name ? name : "", index); return clk; } diff --git a/drivers/clk/imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c index 5fd4ddac1bf1..9642cdf0fb88 100644 --- a/drivers/clk/imx/clk-imx6sl.c +++ b/drivers/clk/imx/clk-imx6sl.c @@ -71,7 +71,7 @@ static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", }; static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", }; static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", }; -static struct clk_div_table clk_enet_ref_table[] = { +static const struct clk_div_table clk_enet_ref_table[] = { { .val = 0, .div = 20, }, { .val = 1, .div = 10, }, { .val = 2, .div = 5, }, @@ -79,14 +79,14 @@ static struct clk_div_table clk_enet_ref_table[] = { { } }; -static struct clk_div_table post_div_table[] = { +static const struct clk_div_table post_div_table[] = { { .val = 2, .div = 1, }, { .val = 1, .div = 2, }, { .val = 0, .div = 4, }, { } }; -static struct clk_div_table video_div_table[] = { +static const struct clk_div_table video_div_table[] = { { .val = 0, .div = 1, }, { .val = 1, .div = 2, }, { .val = 2, .div = 1, }, diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c index b5c96de41ccf..e6d389e333d7 100644 --- a/drivers/clk/imx/clk-imx6sx.c +++ b/drivers/clk/imx/clk-imx6sx.c @@ -105,7 +105,7 @@ static int const clks_init_on[] __initconst = { IMX6SX_CLK_EPIT2, }; -static struct clk_div_table clk_enet_ref_table[] = { +static const struct clk_div_table clk_enet_ref_table[] = { { .val = 0, .div = 20, }, { .val = 1, .div = 10, }, { .val = 2, .div = 5, }, @@ -113,14 +113,14 @@ static struct clk_div_table clk_enet_ref_table[] = { { } }; -static struct clk_div_table post_div_table[] = { +static const struct clk_div_table post_div_table[] = { { .val = 2, .div = 1, }, { .val = 1, .div = 2, }, { .val = 0, .div = 4, }, { } }; -static struct clk_div_table video_div_table[] = { +static const struct clk_div_table video_div_table[] = { { .val = 0, .div = 1, }, { .val = 1, .div = 2, }, { .val = 2, .div = 1, }, diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index b4e0dff3c8c2..5e8c18afce9a 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -78,7 +78,7 @@ static int const clks_init_on[] __initconst = { IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG, }; -static struct clk_div_table clk_enet_ref_table[] = { +static const struct clk_div_table clk_enet_ref_table[] = { { .val = 0, .div = 20, }, { .val = 1, .div = 10, }, { .val = 2, .div = 5, }, @@ -86,14 +86,14 @@ static struct clk_div_table clk_enet_ref_table[] = { { } }; -static struct clk_div_table post_div_table[] = { +static const struct clk_div_table post_div_table[] = { { .val = 2, .div = 1, }, { .val = 1, .div = 2, }, { .val = 0, .div = 4, }, { } }; -static struct clk_div_table video_div_table[] = { +static const struct clk_div_table video_div_table[] = { { .val = 0, .div = 1, }, { .val = 1, .div = 2, }, { .val = 2, .div = 1, }, diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 3da121826b1b..2305699db467 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -27,7 +27,7 @@ static u32 share_count_sai2; static u32 share_count_sai3; static u32 share_count_nand; -static struct clk_div_table test_div_table[] = { +static const struct clk_div_table test_div_table[] = { { .val = 3, .div = 1, }, { .val = 2, .div = 1, }, { .val = 1, .div = 2, }, @@ -35,7 +35,7 @@ static struct clk_div_table test_div_table[] = { { } }; -static struct clk_div_table post_div_table[] = { +static const struct clk_div_table post_div_table[] = { { .val = 3, .div = 4, }, { .val = 2, .div = 1, }, { .val = 1, .div = 2, }, diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index 59b1863deb88..6dae54325a91 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -102,7 +102,7 @@ static const char *ftm_ext_sels[] = {"sirc_128k", "sxosc", "fxosc_half", "audio_ static const char *ftm_fix_sels[] = { "sxosc", "ipg_bus", }; -static struct clk_div_table pll4_audio_div_table[] = { +static const struct clk_div_table pll4_audio_div_table[] = { { .val = 0, .div = 1 }, { .val = 1, .div = 2 }, { .val = 2, .div = 6 }, diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c index 43b0f2f08df2..9cdf9d5050ac 100644 --- a/drivers/clk/keystone/sci-clk.c +++ b/drivers/clk/keystone/sci-clk.c @@ -22,6 +22,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/soc/ti/ti_sci_protocol.h> +#include <linux/bsearch.h> #define SCI_CLK_SSC_ENABLE BIT(0) #define SCI_CLK_ALLOW_FREQ_CHANGE BIT(1) @@ -44,6 +45,7 @@ struct sci_clk_data { * @dev: Device pointer for the clock provider * @clk_data: Clock data * @clocks: Clocks array for this device + * @num_clocks: Total number of clocks for this provider */ struct sci_clk_provider { const struct ti_sci_handle *sci; @@ -51,6 +53,7 @@ struct sci_clk_provider { struct device *dev; const struct sci_clk_data *clk_data; struct clk_hw **clocks; + int num_clocks; }; /** @@ -58,7 +61,6 @@ struct sci_clk_provider { * @hw: Hardware clock cookie for common clock framework * @dev_id: Device index * @clk_id: Clock index - * @node: Clocks list link * @provider: Master clock provider * @flags: Flags for the clock */ @@ -66,7 +68,6 @@ struct sci_clk { struct clk_hw hw; u16 dev_id; u8 clk_id; - struct list_head node; struct sci_clk_provider *provider; u8 flags; }; @@ -367,6 +368,19 @@ err: return &sci_clk->hw; } +static int _cmp_sci_clk(const void *a, const void *b) +{ + const struct sci_clk *ca = a; + const struct sci_clk *cb = *(struct sci_clk **)b; + + if (ca->dev_id == cb->dev_id && ca->clk_id == cb->clk_id) + return 0; + if (ca->dev_id > cb->dev_id || + (ca->dev_id == cb->dev_id && ca->clk_id > cb->clk_id)) + return 1; + return -1; +} + /** * sci_clk_get - Xlate function for getting clock handles * @clkspec: device tree clock specifier @@ -380,29 +394,22 @@ err: static struct clk_hw *sci_clk_get(struct of_phandle_args *clkspec, void *data) { struct sci_clk_provider *provider = data; - u16 dev_id; - u8 clk_id; - const struct sci_clk_data *clks = provider->clk_data; - struct clk_hw **clocks = provider->clocks; + struct sci_clk **clk; + struct sci_clk key; if (clkspec->args_count != 2) return ERR_PTR(-EINVAL); - dev_id = clkspec->args[0]; - clk_id = clkspec->args[1]; + key.dev_id = clkspec->args[0]; + key.clk_id = clkspec->args[1]; - while (clks->num_clks) { - if (clks->dev == dev_id) { - if (clk_id >= clks->num_clks) - return ERR_PTR(-EINVAL); - - return clocks[clk_id]; - } + clk = bsearch(&key, provider->clocks, provider->num_clocks, + sizeof(clk), _cmp_sci_clk); - clks++; - } + if (!clk) + return ERR_PTR(-ENODEV); - return ERR_PTR(-ENODEV); + return &(*clk)->hw; } static int ti_sci_init_clocks(struct sci_clk_provider *p) @@ -410,18 +417,29 @@ static int ti_sci_init_clocks(struct sci_clk_provider *p) const struct sci_clk_data *data = p->clk_data; struct clk_hw *hw; int i; + int num_clks = 0; while (data->num_clks) { - p->clocks = devm_kcalloc(p->dev, data->num_clks, - sizeof(struct sci_clk), - GFP_KERNEL); - if (!p->clocks) - return -ENOMEM; + num_clks += data->num_clks; + data++; + } + p->num_clocks = num_clks; + + p->clocks = devm_kcalloc(p->dev, num_clks, sizeof(struct sci_clk), + GFP_KERNEL); + if (!p->clocks) + return -ENOMEM; + + num_clks = 0; + + data = p->clk_data; + + while (data->num_clks) { for (i = 0; i < data->num_clks; i++) { hw = _sci_clk_build(p, data->dev, i); if (!IS_ERR(hw)) { - p->clocks[i] = hw; + p->clocks[num_clks++] = hw; continue; } diff --git a/drivers/clk/mediatek/clk-cpumux.c b/drivers/clk/mediatek/clk-cpumux.c index edd8e6918050..16e56772d280 100644 --- a/drivers/clk/mediatek/clk-cpumux.c +++ b/drivers/clk/mediatek/clk-cpumux.c @@ -27,7 +27,6 @@ static inline struct mtk_clk_cpumux *to_mtk_clk_cpumux(struct clk_hw *_hw) static u8 clk_cpumux_get_parent(struct clk_hw *hw) { struct mtk_clk_cpumux *mux = to_mtk_clk_cpumux(hw); - int num_parents = clk_hw_get_num_parents(hw); unsigned int val; regmap_read(mux->regmap, mux->reg, &val); @@ -35,9 +34,6 @@ static u8 clk_cpumux_get_parent(struct clk_hw *hw) val >>= mux->shift; val &= mux->mask; - if (val >= num_parents) - return -EINVAL; - return val; } @@ -98,7 +94,7 @@ int __init mtk_clk_register_cpumuxes(struct device_node *node, regmap = syscon_node_to_regmap(node); if (IS_ERR(regmap)) { - pr_err("Cannot find regmap for %s: %ld\n", node->full_name, + pr_err("Cannot find regmap for %pOF: %ld\n", node, PTR_ERR(regmap)); return PTR_ERR(regmap); } diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index 0541df78141c..9c0ae4278a94 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -114,7 +114,7 @@ int mtk_clk_register_gates(struct device_node *node, regmap = syscon_node_to_regmap(node); if (IS_ERR(regmap)) { - pr_err("Cannot find regmap for %s: %ld\n", node->full_name, + pr_err("Cannot find regmap for %pOF: %ld\n", node, PTR_ERR(regmap)); return PTR_ERR(regmap); } diff --git a/drivers/clk/mediatek/reset.c b/drivers/clk/mediatek/reset.c index 309049d41f1b..d3551d5efef2 100644 --- a/drivers/clk/mediatek/reset.c +++ b/drivers/clk/mediatek/reset.c @@ -72,7 +72,7 @@ void mtk_register_reset_controller(struct device_node *np, regmap = syscon_node_to_regmap(np); if (IS_ERR(regmap)) { - pr_err("Cannot find regmap for %s: %ld\n", np->full_name, + pr_err("Cannot find regmap for %pOF: %ld\n", np, PTR_ERR(regmap)); return; } diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 5588f75a8414..d2d0174a6eca 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -6,6 +6,7 @@ config COMMON_CLK_AMLOGIC config COMMON_CLK_MESON8B bool depends on COMMON_CLK_AMLOGIC + select RESET_CONTROLLER help Support for the clock controller on AmLogic S802 (Meson8), S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 83b6d9d65aa1..b139d41b25da 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o clk-audio-divider.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o -obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o +obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-regmap.o gxbb-aoclk-32k.o diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c index 39eab69fe51a..44a5a535ca63 100644 --- a/drivers/clk/meson/clk-mpll.c +++ b/drivers/clk/meson/clk-mpll.c @@ -161,6 +161,13 @@ static int mpll_set_rate(struct clk_hw *hw, reg = PARM_SET(p->width, p->shift, reg, 1); writel(reg, mpll->base + p->reg_off); + p = &mpll->ssen; + if (p->width != 0) { + reg = readl(mpll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, 1); + writel(reg, mpll->base + p->reg_off); + } + p = &mpll->n2; reg = readl(mpll->base + p->reg_off); reg = PARM_SET(p->width, p->shift, reg, n2); diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index d6feafe8bd6c..1629da9b4141 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -118,6 +118,7 @@ struct meson_clk_mpll { struct parm sdm_en; struct parm n2; struct parm en; + struct parm ssen; spinlock_t *lock; }; diff --git a/drivers/clk/meson/gxbb-aoclk-32k.c b/drivers/clk/meson/gxbb-aoclk-32k.c new file mode 100644 index 000000000000..491634dbc985 --- /dev/null +++ b/drivers/clk/meson/gxbb-aoclk-32k.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2017 BayLibre, SAS. + * Author: Neil Armstrong <narmstrong@baylibre.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/clk-provider.h> +#include <linux/bitfield.h> +#include <linux/regmap.h> +#include "gxbb-aoclk.h" + +/* + * The AO Domain embeds a dual/divider to generate a more precise + * 32,768KHz clock for low-power suspend mode and CEC. + * ______ ______ + * | | | | + * ______ | Div1 |-| Cnt1 | ______ + * | | /|______| |______|\ | | + * Xtal-->| Gate |---| ______ ______ X-X--| Gate |--> + * |______| | \| | | |/ | |______| + * | | Div2 |-| Cnt2 | | + * | |______| |______| | + * |_______________________| + * + * The dividing can be switched to single or dual, with a counter + * for each divider to set when the switching is done. + * The entire dividing mechanism can be also bypassed. + */ + +#define CLK_CNTL0_N1_MASK GENMASK(11, 0) +#define CLK_CNTL0_N2_MASK GENMASK(23, 12) +#define CLK_CNTL0_DUALDIV_EN BIT(28) +#define CLK_CNTL0_OUT_GATE_EN BIT(30) +#define CLK_CNTL0_IN_GATE_EN BIT(31) + +#define CLK_CNTL1_M1_MASK GENMASK(11, 0) +#define CLK_CNTL1_M2_MASK GENMASK(23, 12) +#define CLK_CNTL1_BYPASS_EN BIT(24) +#define CLK_CNTL1_SELECT_OSC BIT(27) + +#define PWR_CNTL_ALT_32K_SEL GENMASK(13, 10) + +struct cec_32k_freq_table { + unsigned long parent_rate; + unsigned long target_rate; + bool dualdiv; + unsigned int n1; + unsigned int n2; + unsigned int m1; + unsigned int m2; +}; + +static const struct cec_32k_freq_table aoclk_cec_32k_table[] = { + [0] = { + .parent_rate = 24000000, + .target_rate = 32768, + .dualdiv = true, + .n1 = 733, + .n2 = 732, + .m1 = 8, + .m2 = 11, + }, +}; + +/* + * If CLK_CNTL0_DUALDIV_EN == 0 + * - will use N1 divider only + * If CLK_CNTL0_DUALDIV_EN == 1 + * - hold M1 cycles of N1 divider then changes to N2 + * - hold M2 cycles of N2 divider then changes to N1 + * Then we can get more accurate division. + */ +static unsigned long aoclk_cec_32k_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw); + unsigned long n1; + u32 reg0, reg1; + + regmap_read(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, ®0); + regmap_read(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL1, ®1); + + if (reg1 & CLK_CNTL1_BYPASS_EN) + return parent_rate; + + if (reg0 & CLK_CNTL0_DUALDIV_EN) { + unsigned long n2, m1, m2, f1, f2, p1, p2; + + n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1; + n2 = FIELD_GET(CLK_CNTL0_N2_MASK, reg0) + 1; + + m1 = FIELD_GET(CLK_CNTL1_M1_MASK, reg1) + 1; + m2 = FIELD_GET(CLK_CNTL1_M2_MASK, reg1) + 1; + + f1 = DIV_ROUND_CLOSEST(parent_rate, n1); + f2 = DIV_ROUND_CLOSEST(parent_rate, n2); + + p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2)); + p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2)); + + return DIV_ROUND_UP(100000000, p1 + p2); + } + + n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1; + + return DIV_ROUND_CLOSEST(parent_rate, n1); +} + +static const struct cec_32k_freq_table *find_cec_32k_freq(unsigned long rate, + unsigned long prate) +{ + int i; + + for (i = 0 ; i < ARRAY_SIZE(aoclk_cec_32k_table) ; ++i) + if (aoclk_cec_32k_table[i].parent_rate == prate && + aoclk_cec_32k_table[i].target_rate == rate) + return &aoclk_cec_32k_table[i]; + + return NULL; +} + +static long aoclk_cec_32k_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate, + *prate); + + /* If invalid return first one */ + if (!freq) + return aoclk_cec_32k_table[0].target_rate; + + return freq->target_rate; +} + +/* + * From the Amlogic init procedure, the IN and OUT gates needs to be handled + * in the init procedure to avoid any glitches. + */ + +static int aoclk_cec_32k_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate, + parent_rate); + struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw); + u32 reg = 0; + + if (!freq) + return -EINVAL; + + /* Disable clock */ + regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, + CLK_CNTL0_IN_GATE_EN | CLK_CNTL0_OUT_GATE_EN, 0); + + reg = FIELD_PREP(CLK_CNTL0_N1_MASK, freq->n1 - 1); + if (freq->dualdiv) + reg |= CLK_CNTL0_DUALDIV_EN | + FIELD_PREP(CLK_CNTL0_N2_MASK, freq->n2 - 1); + + regmap_write(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, reg); + + reg = FIELD_PREP(CLK_CNTL1_M1_MASK, freq->m1 - 1); + if (freq->dualdiv) + reg |= FIELD_PREP(CLK_CNTL1_M2_MASK, freq->m2 - 1); + + regmap_write(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL1, reg); + + /* Enable clock */ + regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, + CLK_CNTL0_IN_GATE_EN, CLK_CNTL0_IN_GATE_EN); + + udelay(200); + + regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, + CLK_CNTL0_OUT_GATE_EN, CLK_CNTL0_OUT_GATE_EN); + + regmap_update_bits(cec_32k->regmap, AO_CRT_CLK_CNTL1, + CLK_CNTL1_SELECT_OSC, CLK_CNTL1_SELECT_OSC); + + /* Select 32k from XTAL */ + regmap_update_bits(cec_32k->regmap, + AO_RTI_PWR_CNTL_REG0, + PWR_CNTL_ALT_32K_SEL, + FIELD_PREP(PWR_CNTL_ALT_32K_SEL, 4)); + + return 0; +} + +const struct clk_ops meson_aoclk_cec_32k_ops = { + .recalc_rate = aoclk_cec_32k_recalc_rate, + .round_rate = aoclk_cec_32k_round_rate, + .set_rate = aoclk_cec_32k_set_rate, +}; diff --git a/drivers/clk/meson/gxbb-aoclk-regmap.c b/drivers/clk/meson/gxbb-aoclk-regmap.c new file mode 100644 index 000000000000..2515fbfa0467 --- /dev/null +++ b/drivers/clk/meson/gxbb-aoclk-regmap.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017 BayLibre, SAS. + * Author: Neil Armstrong <narmstrong@baylibre.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/clk-provider.h> +#include <linux/bitfield.h> +#include <linux/regmap.h> +#include "gxbb-aoclk.h" + +static int aoclk_gate_regmap_enable(struct clk_hw *hw) +{ + struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw); + + return regmap_update_bits(gate->regmap, AO_RTI_GEN_CNTL_REG0, + BIT(gate->bit_idx), BIT(gate->bit_idx)); +} + +static void aoclk_gate_regmap_disable(struct clk_hw *hw) +{ + struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw); + + regmap_update_bits(gate->regmap, AO_RTI_GEN_CNTL_REG0, + BIT(gate->bit_idx), 0); +} + +static int aoclk_gate_regmap_is_enabled(struct clk_hw *hw) +{ + struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw); + unsigned int val; + int ret; + + ret = regmap_read(gate->regmap, AO_RTI_GEN_CNTL_REG0, &val); + if (ret) + return ret; + + return (val & BIT(gate->bit_idx)) != 0; +} + +const struct clk_ops meson_aoclk_gate_regmap_ops = { + .enable = aoclk_gate_regmap_enable, + .disable = aoclk_gate_regmap_disable, + .is_enabled = aoclk_gate_regmap_is_enabled, +}; diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index b45c5fba7e35..6c161e0a8e59 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -56,16 +56,20 @@ #include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/reset-controller.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> #include <linux/init.h> +#include <linux/delay.h> #include <dt-bindings/clock/gxbb-aoclkc.h> #include <dt-bindings/reset/gxbb-aoclkc.h> +#include "gxbb-aoclk.h" static DEFINE_SPINLOCK(gxbb_aoclk_lock); struct gxbb_aoclk_reset_controller { struct reset_controller_dev reset; unsigned int *data; - void __iomem *base; + struct regmap *regmap; }; static int gxbb_aoclk_do_reset(struct reset_controller_dev *rcdev, @@ -74,9 +78,8 @@ static int gxbb_aoclk_do_reset(struct reset_controller_dev *rcdev, struct gxbb_aoclk_reset_controller *reset = container_of(rcdev, struct gxbb_aoclk_reset_controller, reset); - writel(BIT(reset->data[id]), reset->base); - - return 0; + return regmap_write(reset->regmap, AO_RTI_GEN_CNTL_REG0, + BIT(reset->data[id])); } static const struct reset_control_ops gxbb_aoclk_reset_ops = { @@ -84,13 +87,12 @@ static const struct reset_control_ops gxbb_aoclk_reset_ops = { }; #define GXBB_AO_GATE(_name, _bit) \ -static struct clk_gate _name##_ao = { \ - .reg = (void __iomem *)0, \ +static struct aoclk_gate_regmap _name##_ao = { \ .bit_idx = (_bit), \ .lock = &gxbb_aoclk_lock, \ .hw.init = &(struct clk_init_data) { \ .name = #_name "_ao", \ - .ops = &clk_gate_ops, \ + .ops = &meson_aoclk_gate_regmap_ops, \ .parent_names = (const char *[]){ "clk81" }, \ .num_parents = 1, \ .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ @@ -104,6 +106,17 @@ GXBB_AO_GATE(uart1, 3); GXBB_AO_GATE(uart2, 5); GXBB_AO_GATE(ir_blaster, 6); +static struct aoclk_cec_32k cec_32k_ao = { + .lock = &gxbb_aoclk_lock, + .hw.init = &(struct clk_init_data) { + .name = "cec_32k_ao", + .ops = &meson_aoclk_cec_32k_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED, + }, +}; + static unsigned int gxbb_aoclk_reset[] = { [RESET_AO_REMOTE] = 16, [RESET_AO_I2C_MASTER] = 18, @@ -113,7 +126,7 @@ static unsigned int gxbb_aoclk_reset[] = { [RESET_AO_IR_BLASTER] = 23, }; -static struct clk_gate *gxbb_aoclk_gate[] = { +static struct aoclk_gate_regmap *gxbb_aoclk_gate[] = { [CLKID_AO_REMOTE] = &remote_ao, [CLKID_AO_I2C_MASTER] = &i2c_master_ao, [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao, @@ -130,30 +143,30 @@ static struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { [CLKID_AO_UART1] = &uart1_ao.hw, [CLKID_AO_UART2] = &uart2_ao.hw, [CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw, + [CLKID_AO_CEC_32K] = &cec_32k_ao.hw, }, - .num = ARRAY_SIZE(gxbb_aoclk_gate), + .num = 7, }; static int gxbb_aoclkc_probe(struct platform_device *pdev) { - struct resource *res; - void __iomem *base; - int ret, clkid; - struct device *dev = &pdev->dev; struct gxbb_aoclk_reset_controller *rstc; + struct device *dev = &pdev->dev; + struct regmap *regmap; + int ret, clkid; rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL); if (!rstc) return -ENOMEM; - /* Generic clocks */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); + regmap = syscon_node_to_regmap(of_get_parent(dev->of_node)); + if (IS_ERR(regmap)) { + dev_err(dev, "failed to get regmap\n"); + return -ENODEV; + } /* Reset Controller */ - rstc->base = base; + rstc->regmap = regmap; rstc->data = gxbb_aoclk_reset; rstc->reset.ops = &gxbb_aoclk_reset_ops; rstc->reset.nr_resets = ARRAY_SIZE(gxbb_aoclk_reset); @@ -161,10 +174,10 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev) ret = devm_reset_controller_register(dev, &rstc->reset); /* - * Populate base address and register all clks + * Populate regmap and register all clks */ - for (clkid = 0; clkid < gxbb_aoclk_onecell_data.num; clkid++) { - gxbb_aoclk_gate[clkid]->reg = base; + for (clkid = 0; clkid < ARRAY_SIZE(gxbb_aoclk_gate); clkid++) { + gxbb_aoclk_gate[clkid]->regmap = regmap; ret = devm_clk_hw_register(dev, gxbb_aoclk_onecell_data.hws[clkid]); @@ -172,12 +185,18 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev) return ret; } + /* Specific clocks */ + cec_32k_ao.regmap = regmap; + ret = devm_clk_hw_register(dev, &cec_32k_ao.hw); + if (ret) + return ret; + return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, &gxbb_aoclk_onecell_data); } static const struct of_device_id gxbb_aoclkc_match_table[] = { - { .compatible = "amlogic,gxbb-aoclkc" }, + { .compatible = "amlogic,meson-gx-aoclkc" }, { } }; diff --git a/drivers/clk/meson/gxbb-aoclk.h b/drivers/clk/meson/gxbb-aoclk.h new file mode 100644 index 000000000000..e8604c8f7eee --- /dev/null +++ b/drivers/clk/meson/gxbb-aoclk.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017 BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __GXBB_AOCLKC_H +#define __GXBB_AOCLKC_H + +/* AO Configuration Clock registers offsets */ +#define AO_RTI_PWR_CNTL_REG1 0x0c +#define AO_RTI_PWR_CNTL_REG0 0x10 +#define AO_RTI_GEN_CNTL_REG0 0x40 +#define AO_OSCIN_CNTL 0x58 +#define AO_CRT_CLK_CNTL1 0x68 +#define AO_RTC_ALT_CLK_CNTL0 0x94 +#define AO_RTC_ALT_CLK_CNTL1 0x98 + +struct aoclk_gate_regmap { + struct clk_hw hw; + unsigned bit_idx; + struct regmap *regmap; + spinlock_t *lock; +}; + +#define to_aoclk_gate_regmap(_hw) \ + container_of(_hw, struct aoclk_gate_regmap, hw) + +extern const struct clk_ops meson_aoclk_gate_regmap_ops; + +struct aoclk_cec_32k { + struct clk_hw hw; + struct regmap *regmap; + spinlock_t *lock; +}; + +#define to_aoclk_cec_32k(_hw) container_of(_hw, struct aoclk_cec_32k, hw) + +extern const struct clk_ops meson_aoclk_cec_32k_ops; + +#endif /* __GXBB_AOCLKC_H */ diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index a897ea45327c..b2d1e8ed7152 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -528,6 +528,11 @@ static struct meson_clk_mpll gxbb_mpll0 = { .shift = 14, .width = 1, }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, .lock = &clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll0", @@ -845,13 +850,14 @@ static struct meson_clk_audio_divider gxbb_cts_amclk_div = { .shift = 0, .width = 8, }, + .flags = CLK_DIVIDER_ROUND_CLOSEST, .lock = &clk_lock, .hw.init = &(struct clk_init_data){ .name = "cts_amclk_div", .ops = &meson_clk_audio_divider_ops, .parent_names = (const char *[]){ "cts_amclk_sel" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -875,7 +881,7 @@ static struct clk_mux gxbb_cts_mclk_i958_sel = { /* Default parent unknown (register reset value: 0) */ .table = (u32[]){ 1, 2, 3 }, .lock = &clk_lock, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_sel", .ops = &clk_mux_ops, .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, @@ -889,12 +895,13 @@ static struct clk_divider gxbb_cts_mclk_i958_div = { .shift = 16, .width = 8, .lock = &clk_lock, - .hw.init = &(struct clk_init_data){ + .flags = CLK_DIVIDER_ROUND_CLOSEST, + .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_div", .ops = &clk_divider_ops, .parent_names = (const char *[]){ "cts_mclk_i958_sel" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -974,6 +981,156 @@ static struct clk_mux gxbb_32k_clk_sel = { }, }; +static const char * const gxbb_sd_emmc_clk0_parent_names[] = { + "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", + + /* + * Following these parent clocks, we should also have had mpll2, mpll3 + * and gp0_pll but these clocks are too precious to be used here. All + * the necessary rates for MMC and NAND operation can be acheived using + * xtal or fclk_div clocks + */ +}; + +/* SDIO clock */ +static struct clk_mux gxbb_sd_emmc_a_clk0_sel = { + .reg = (void *)HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_sel", + .ops = &clk_mux_ops, + .parent_names = gxbb_sd_emmc_clk0_parent_names, + .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_divider gxbb_sd_emmc_a_clk0_div = { + .reg = (void *)HHI_SD_EMMC_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &clk_lock, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_gate gxbb_sd_emmc_a_clk0 = { + .reg = (void *)HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_a_clk0", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "sd_emmc_a_clk0_div" }, + .num_parents = 1, + + /* + * FIXME: + * We need CLK_IGNORE_UNUSED because mmc DT node point to xtal + * instead of this clock. CCF would gate this on boot, killing + * the mmc controller. Please remove this flag once DT properly + * point to this clock instead of xtal + * + * Same goes for emmc B and C clocks + */ + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +/* SDcard clock */ +static struct clk_mux gxbb_sd_emmc_b_clk0_sel = { + .reg = (void *)HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_sel", + .ops = &clk_mux_ops, + .parent_names = gxbb_sd_emmc_clk0_parent_names, + .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_divider gxbb_sd_emmc_b_clk0_div = { + .reg = (void *)HHI_SD_EMMC_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &clk_lock, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_gate gxbb_sd_emmc_b_clk0 = { + .reg = (void *)HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 23, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_b_clk0", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +/* EMMC/NAND clock */ +static struct clk_mux gxbb_sd_emmc_c_clk0_sel = { + .reg = (void *)HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_sel", + .ops = &clk_mux_ops, + .parent_names = gxbb_sd_emmc_clk0_parent_names, + .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_divider gxbb_sd_emmc_c_clk0_div = { + .reg = (void *)HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &clk_lock, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_gate gxbb_sd_emmc_c_clk0 = { + .reg = (void *)HHI_NAND_CLK_CNTL, + .bit_idx = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_c_clk0", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + /* Everything Else (EE) domain gates */ static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0); static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1); @@ -1183,6 +1340,16 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_32K_CLK] = &gxbb_32k_clk.hw, [CLKID_32K_CLK_SEL] = &gxbb_32k_clk_sel.hw, [CLKID_32K_CLK_DIV] = &gxbb_32k_clk_div.hw, + [CLKID_SD_EMMC_A_CLK0_SEL] = &gxbb_sd_emmc_a_clk0_sel.hw, + [CLKID_SD_EMMC_A_CLK0_DIV] = &gxbb_sd_emmc_a_clk0_div.hw, + [CLKID_SD_EMMC_A_CLK0] = &gxbb_sd_emmc_a_clk0.hw, + [CLKID_SD_EMMC_B_CLK0_SEL] = &gxbb_sd_emmc_b_clk0_sel.hw, + [CLKID_SD_EMMC_B_CLK0_DIV] = &gxbb_sd_emmc_b_clk0_div.hw, + [CLKID_SD_EMMC_B_CLK0] = &gxbb_sd_emmc_b_clk0.hw, + [CLKID_SD_EMMC_C_CLK0_SEL] = &gxbb_sd_emmc_c_clk0_sel.hw, + [CLKID_SD_EMMC_C_CLK0_DIV] = &gxbb_sd_emmc_c_clk0_div.hw, + [CLKID_SD_EMMC_C_CLK0] = &gxbb_sd_emmc_c_clk0.hw, + [NR_CLKS] = NULL, }, .num = NR_CLKS, }; @@ -1305,6 +1472,16 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_32K_CLK] = &gxbb_32k_clk.hw, [CLKID_32K_CLK_SEL] = &gxbb_32k_clk_sel.hw, [CLKID_32K_CLK_DIV] = &gxbb_32k_clk_div.hw, + [CLKID_SD_EMMC_A_CLK0_SEL] = &gxbb_sd_emmc_a_clk0_sel.hw, + [CLKID_SD_EMMC_A_CLK0_DIV] = &gxbb_sd_emmc_a_clk0_div.hw, + [CLKID_SD_EMMC_A_CLK0] = &gxbb_sd_emmc_a_clk0.hw, + [CLKID_SD_EMMC_B_CLK0_SEL] = &gxbb_sd_emmc_b_clk0_sel.hw, + [CLKID_SD_EMMC_B_CLK0_DIV] = &gxbb_sd_emmc_b_clk0_div.hw, + [CLKID_SD_EMMC_B_CLK0] = &gxbb_sd_emmc_b_clk0.hw, + [CLKID_SD_EMMC_C_CLK0_SEL] = &gxbb_sd_emmc_c_clk0_sel.hw, + [CLKID_SD_EMMC_C_CLK0_DIV] = &gxbb_sd_emmc_c_clk0_div.hw, + [CLKID_SD_EMMC_C_CLK0] = &gxbb_sd_emmc_c_clk0.hw, + [NR_CLKS] = NULL, }, .num = NR_CLKS, }; @@ -1420,6 +1597,9 @@ static struct clk_gate *const gxbb_clk_gates[] = { &gxbb_cts_amclk, &gxbb_cts_mclk_i958, &gxbb_32k_clk, + &gxbb_sd_emmc_a_clk0, + &gxbb_sd_emmc_b_clk0, + &gxbb_sd_emmc_c_clk0, }; static struct clk_mux *const gxbb_clk_muxes[] = { @@ -1432,6 +1612,9 @@ static struct clk_mux *const gxbb_clk_muxes[] = { &gxbb_cts_mclk_i958_sel, &gxbb_cts_i958, &gxbb_32k_clk_sel, + &gxbb_sd_emmc_a_clk0_sel, + &gxbb_sd_emmc_b_clk0_sel, + &gxbb_sd_emmc_c_clk0_sel, }; static struct clk_divider *const gxbb_clk_dividers[] = { @@ -1441,6 +1624,9 @@ static struct clk_divider *const gxbb_clk_dividers[] = { &gxbb_mali_1_div, &gxbb_cts_mclk_i958_div, &gxbb_32k_clk_div, + &gxbb_sd_emmc_a_clk0_div, + &gxbb_sd_emmc_b_clk0_div, + &gxbb_sd_emmc_c_clk0_div, }; static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = { diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index d63e77e8433d..5b1d4b374d1c 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -167,130 +167,33 @@ * CLKID index values * * These indices are entirely contrived and do not map onto the hardware. - * Migrate them out of this header and into the DT header file when they need - * to be exposed to client nodes in DT: include/dt-bindings/clock/gxbb-clkc.h + * It has now been decided to expose everything by default in the DT header: + * include/dt-bindings/clock/gxbb-clkc.h. Only the clocks ids we don't want + * to expose, such as the internal muxes and dividers of composite clocks, + * will remain defined here. */ -#define CLKID_SYS_PLL 0 /* ID 1 is unused (it was used by the non-existing CLKID_CPUCLK before) */ -/* CLKID_HDMI_PLL */ -#define CLKID_FIXED_PLL 3 -/* CLKID_FCLK_DIV2 */ -/* CLKID_FCLK_DIV3 */ -/* CLKID_FCLK_DIV4 */ -#define CLKID_FCLK_DIV5 7 -#define CLKID_FCLK_DIV7 8 -/* CLKID_GP0_PLL */ #define CLKID_MPEG_SEL 10 #define CLKID_MPEG_DIV 11 -/* CLKID_CLK81 */ -#define CLKID_MPLL0 13 -#define CLKID_MPLL1 14 -/* CLKID_MPLL2 */ -#define CLKID_DDR 16 -#define CLKID_DOS 17 -#define CLKID_ISA 18 -#define CLKID_PL301 19 -#define CLKID_PERIPHS 20 -/* CLKID_SPICC */ -/* CLKID_I2C */ -/* #define CLKID_SAR_ADC */ -#define CLKID_SMART_CARD 24 -/* CLKID_RNG0 */ -/* CLKID_UART0 */ -#define CLKID_SDHC 27 -#define CLKID_STREAM 28 -#define CLKID_ASYNC_FIFO 29 -#define CLKID_SDIO 30 -#define CLKID_ABUF 31 -#define CLKID_HIU_IFACE 32 -#define CLKID_ASSIST_MISC 33 -/* CLKID_SPI */ -#define CLKID_I2S_SPDIF 35 -/* CLKID_ETH */ -#define CLKID_DEMUX 37 -/* CLKID_AIU_GLUE */ -/* CLKID_IEC958 */ -/* CLKID_I2S_OUT */ -#define CLKID_AMCLK 41 -#define CLKID_AIFIFO2 42 -#define CLKID_MIXER 43 -/* CLKID_MIXER_IFACE */ -#define CLKID_ADC 45 -#define CLKID_BLKMV 46 -/* CLKID_AIU */ -/* CLKID_UART1 */ -#define CLKID_G2D 49 -/* CLKID_USB0 */ -/* CLKID_USB1 */ -#define CLKID_RESET 52 -#define CLKID_NAND 53 -#define CLKID_DOS_PARSER 54 -/* CLKID_USB */ -#define CLKID_VDIN1 56 -#define CLKID_AHB_ARB0 57 -#define CLKID_EFUSE 58 -#define CLKID_BOOT_ROM 59 -#define CLKID_AHB_DATA_BUS 60 -#define CLKID_AHB_CTRL_BUS 61 -#define CLKID_HDMI_INTR_SYNC 62 -/* CLKID_HDMI_PCLK */ -/* CLKID_USB1_DDR_BRIDGE */ -/* CLKID_USB0_DDR_BRIDGE */ -#define CLKID_MMC_PCLK 66 -#define CLKID_DVIN 67 -/* CLKID_UART2 */ -/* #define CLKID_SANA */ -#define CLKID_VPU_INTR 70 -#define CLKID_SEC_AHB_AHB3_BRIDGE 71 -#define CLKID_CLK81_A53 72 -#define CLKID_VCLK2_VENCI0 73 -#define CLKID_VCLK2_VENCI1 74 -#define CLKID_VCLK2_VENCP0 75 -#define CLKID_VCLK2_VENCP1 76 -/* CLKID_GCLK_VENCI_INT0 */ -#define CLKID_GCLK_VENCI_INT 78 -#define CLKID_DAC_CLK 79 -/* CLKID_AOCLK_GATE */ -/* CLKID_IEC958_GATE */ -#define CLKID_ENC480P 82 -#define CLKID_RNG1 83 -#define CLKID_GCLK_VENCI_INT1 84 -#define CLKID_VCLK2_VENCLMCC 85 -#define CLKID_VCLK2_VENCL 86 -#define CLKID_VCLK_OTHER 87 -#define CLKID_EDP 88 -#define CLKID_AO_MEDIA_CPU 89 -#define CLKID_AO_AHB_SRAM 90 -#define CLKID_AO_AHB_BUS 91 -#define CLKID_AO_IFACE 92 -/* CLKID_AO_I2C */ -/* CLKID_SD_EMMC_A */ -/* CLKID_SD_EMMC_B */ -/* CLKID_SD_EMMC_C */ -/* CLKID_SAR_ADC_CLK */ -/* CLKID_SAR_ADC_SEL */ #define CLKID_SAR_ADC_DIV 99 -/* CLKID_MALI_0_SEL */ -#define CLKID_MALI_0_DIV 101 -/* CLKID_MALI_0 */ -/* CLKID_MALI_1_SEL */ -#define CLKID_MALI_1_DIV 104 -/* CLKID_MALI_1 */ -/* CLKID_MALI */ -/* CLKID_CTS_AMCLK */ +#define CLKID_MALI_0_DIV 101 +#define CLKID_MALI_1_DIV 104 #define CLKID_CTS_AMCLK_SEL 108 #define CLKID_CTS_AMCLK_DIV 109 -/* CLKID_CTS_MCLK_I958 */ #define CLKID_CTS_MCLK_I958_SEL 111 #define CLKID_CTS_MCLK_I958_DIV 112 -/* CLKID_CTS_I958 */ -#define CLKID_32K_CLK 114 #define CLKID_32K_CLK_SEL 115 #define CLKID_32K_CLK_DIV 116 +#define CLKID_SD_EMMC_A_CLK0_SEL 117 +#define CLKID_SD_EMMC_A_CLK0_DIV 118 +#define CLKID_SD_EMMC_B_CLK0_SEL 120 +#define CLKID_SD_EMMC_B_CLK0_DIV 121 +#define CLKID_SD_EMMC_C_CLK0_SEL 123 +#define CLKID_SD_EMMC_C_CLK0_DIV 124 -#define NR_CLKS 117 +#define NR_CLKS 126 -/* include the CLKIDs that have been made part of the stable DT binding */ +/* include the CLKIDs that have been made part of the DT binding */ #include <dt-bindings/clock/gxbb-clkc.h> #endif /* __GXBB_H */ diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index bb3f1de876b1..20ab7190d328 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -25,6 +25,8 @@ #include <linux/clk-provider.h> #include <linux/of_address.h> #include <linux/platform_device.h> +#include <linux/reset-controller.h> +#include <linux/slab.h> #include <linux/init.h> #include "clkc.h" @@ -32,6 +34,13 @@ static DEFINE_SPINLOCK(clk_lock); +static void __iomem *clk_base; + +struct meson8b_clk_reset { + struct reset_controller_dev reset; + void __iomem *base; +}; + static const struct pll_rate_table sys_pll_rate_table[] = { PLL_RATE(312000000, 52, 1, 2), PLL_RATE(336000000, 56, 1, 2), @@ -267,6 +276,11 @@ static struct meson_clk_mpll meson8b_mpll0 = { .shift = 14, .width = 1, }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, .lock = &clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll0", @@ -585,6 +599,7 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_MPLL0] = &meson8b_mpll0.hw, [CLKID_MPLL1] = &meson8b_mpll1.hw, [CLKID_MPLL2] = &meson8b_mpll2.hw, + [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, }; @@ -690,20 +705,114 @@ static struct clk_divider *const meson8b_clk_dividers[] = { &meson8b_mpeg_clk_div, }; +static const struct meson8b_clk_reset_line { + u32 reg; + u8 bit_idx; +} meson8b_clk_reset_bits[] = { + [CLKC_RESET_L2_CACHE_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 30 + }, + [CLKC_RESET_AXI_64_TO_128_BRIDGE_A5_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 29 + }, + [CLKC_RESET_SCU_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 28 + }, + [CLKC_RESET_CPU3_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 27 + }, + [CLKC_RESET_CPU2_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 26 + }, + [CLKC_RESET_CPU1_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 25 + }, + [CLKC_RESET_CPU0_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 24 + }, + [CLKC_RESET_A5_GLOBAL_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 18 + }, + [CLKC_RESET_A5_AXI_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 17 + }, + [CLKC_RESET_A5_ABP_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 16 + }, + [CLKC_RESET_AXI_64_TO_128_BRIDGE_MMC_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL1, .bit_idx = 30 + }, + [CLKC_RESET_VID_CLK_CNTL_SOFT_RESET] = { + .reg = HHI_VID_CLK_CNTL, .bit_idx = 15 + }, + [CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_POST] = { + .reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 7 + }, + [CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_PRE] = { + .reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 3 + }, + [CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_POST] = { + .reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 1 + }, + [CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_PRE] = { + .reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 0 + }, +}; + +static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct meson8b_clk_reset *meson8b_clk_reset = + container_of(rcdev, struct meson8b_clk_reset, reset); + unsigned long flags; + const struct meson8b_clk_reset_line *reset; + u32 val; + + if (id >= ARRAY_SIZE(meson8b_clk_reset_bits)) + return -EINVAL; + + reset = &meson8b_clk_reset_bits[id]; + + spin_lock_irqsave(&clk_lock, flags); + + val = readl(meson8b_clk_reset->base + reset->reg); + if (assert) + val |= BIT(reset->bit_idx); + else + val &= ~BIT(reset->bit_idx); + writel(val, meson8b_clk_reset->base + reset->reg); + + spin_unlock_irqrestore(&clk_lock, flags); + + return 0; +} + +static int meson8b_clk_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson8b_clk_reset_update(rcdev, id, true); +} + +static int meson8b_clk_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson8b_clk_reset_update(rcdev, id, false); +} + +static const struct reset_control_ops meson8b_clk_reset_ops = { + .assert = meson8b_clk_reset_assert, + .deassert = meson8b_clk_reset_deassert, +}; + static int meson8b_clkc_probe(struct platform_device *pdev) { - void __iomem *clk_base; int ret, clkid, i; struct clk_hw *parent_hw; struct clk *parent_clk; struct device *dev = &pdev->dev; - /* Generic clocks and PLLs */ - clk_base = of_iomap(dev->of_node, 1); - if (!clk_base) { - pr_err("%s: Unable to map clk base\n", __func__); + if (!clk_base) return -ENXIO; - } /* Populate base address for PLLs */ for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++) @@ -743,7 +852,7 @@ static int meson8b_clkc_probe(struct platform_device *pdev) /* FIXME convert to devm_clk_register */ ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[clkid]); if (ret) - goto iounmap; + return ret; } /* @@ -766,15 +875,11 @@ static int meson8b_clkc_probe(struct platform_device *pdev) if (ret) { pr_err("%s: failed to register clock notifier for cpu_clk\n", __func__); - goto iounmap; + return ret; } return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, &meson8b_hw_onecell_data); - -iounmap: - iounmap(clk_base); - return ret; } static const struct of_device_id meson8b_clkc_match_table[] = { @@ -793,3 +898,39 @@ static struct platform_driver meson8b_driver = { }; builtin_platform_driver(meson8b_driver); + +static void __init meson8b_clkc_reset_init(struct device_node *np) +{ + struct meson8b_clk_reset *rstc; + int ret; + + /* Generic clocks, PLLs and some of the reset-bits */ + clk_base = of_iomap(np, 1); + if (!clk_base) { + pr_err("%s: Unable to map clk base\n", __func__); + return; + } + + rstc = kzalloc(sizeof(*rstc), GFP_KERNEL); + if (!rstc) + return; + + /* Reset Controller */ + rstc->base = clk_base; + rstc->reset.ops = &meson8b_clk_reset_ops; + rstc->reset.nr_resets = ARRAY_SIZE(meson8b_clk_reset_bits); + rstc->reset.of_node = np; + ret = reset_controller_register(&rstc->reset); + if (ret) { + pr_err("%s: Failed to register clkc reset controller: %d\n", + __func__, ret); + return; + } +} + +CLK_OF_DECLARE_DRIVER(meson8_clkc, "amlogic,meson8-clkc", + meson8b_clkc_reset_init); +CLK_OF_DECLARE_DRIVER(meson8b_clkc, "amlogic,meson8b-clkc", + meson8b_clkc_reset_init); +CLK_OF_DECLARE_DRIVER(meson8m2_clkc, "amlogic,meson8m2-clkc", + meson8b_clkc_reset_init); diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index a687e02547dc..2eaf8a52e7dd 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -37,6 +37,9 @@ #define HHI_GCLK_AO 0x154 /* 0x55 offset in data sheet */ #define HHI_SYS_CPU_CLK_CNTL1 0x15c /* 0x57 offset in data sheet */ #define HHI_MPEG_CLK_CNTL 0x174 /* 0x5d offset in data sheet */ +#define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */ +#define HHI_VID_DIVIDER_CNTL 0x198 /* 0x66 offset in data sheet */ +#define HHI_SYS_CPU_CLK_CNTL0 0x19c /* 0x67 offset in data sheet */ #define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */ #define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */ #define HHI_VID_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ @@ -60,110 +63,19 @@ * CLKID index values * * These indices are entirely contrived and do not map onto the hardware. - * Migrate them out of this header and into the DT header file when they need - * to be exposed to client nodes in DT: include/dt-bindings/clock/meson8b-clkc.h + * It has now been decided to expose everything by default in the DT header: + * include/dt-bindings/clock/gxbb-clkc.h. Only the clocks ids we don't want + * to expose, such as the internal muxes and dividers of composite clocks, + * will remain defined here. */ -/* CLKID_UNUSED */ -/* CLKID_XTAL */ -/* CLKID_PLL_FIXED */ -/* CLKID_PLL_VID */ -/* CLKID_PLL_SYS */ -/* CLKID_FCLK_DIV2 */ -/* CLKID_FCLK_DIV3 */ -/* CLKID_FCLK_DIV4 */ -/* CLKID_FCLK_DIV5 */ -/* CLKID_FCLK_DIV7 */ -/* CLKID_CLK81 */ -/* CLKID_MALI */ -/* CLKID_CPUCLK */ -/* CLKID_ZERO */ -/* CLKID_MPEG_SEL */ -/* CLKID_MPEG_DIV */ -#define CLKID_DDR 16 -#define CLKID_DOS 17 -#define CLKID_ISA 18 -#define CLKID_PL301 19 -#define CLKID_PERIPHS 20 -#define CLKID_SPICC 21 -#define CLKID_I2C 22 -/* #define CLKID_SAR_ADC */ -#define CLKID_SMART_CARD 24 -/* #define CLKID_RNG0 */ -#define CLKID_UART0 26 -#define CLKID_SDHC 27 -#define CLKID_STREAM 28 -#define CLKID_ASYNC_FIFO 29 -/* #define CLKID_SDIO */ -#define CLKID_ABUF 31 -#define CLKID_HIU_IFACE 32 -#define CLKID_ASSIST_MISC 33 -#define CLKID_SPI 34 -#define CLKID_I2S_SPDIF 35 -/* #define CLKID_ETH */ -#define CLKID_DEMUX 37 -#define CLKID_AIU_GLUE 38 -#define CLKID_IEC958 39 -#define CLKID_I2S_OUT 40 -#define CLKID_AMCLK 41 -#define CLKID_AIFIFO2 42 -#define CLKID_MIXER 43 -#define CLKID_MIXER_IFACE 44 -#define CLKID_ADC 45 -#define CLKID_BLKMV 46 -#define CLKID_AIU 47 -#define CLKID_UART1 48 -#define CLKID_G2D 49 -/* #define CLKID_USB0 */ -/* #define CLKID_USB1 */ -#define CLKID_RESET 52 -#define CLKID_NAND 53 -#define CLKID_DOS_PARSER 54 -/* #define CLKID_USB */ -#define CLKID_VDIN1 56 -#define CLKID_AHB_ARB0 57 -#define CLKID_EFUSE 58 -#define CLKID_BOOT_ROM 59 -#define CLKID_AHB_DATA_BUS 60 -#define CLKID_AHB_CTRL_BUS 61 -#define CLKID_HDMI_INTR_SYNC 62 -#define CLKID_HDMI_PCLK 63 -/* CLKID_USB1_DDR_BRIDGE */ -/* CLKID_USB0_DDR_BRIDGE */ -#define CLKID_MMC_PCLK 66 -#define CLKID_DVIN 67 -#define CLKID_UART2 68 -/* #define CLKID_SANA */ -#define CLKID_VPU_INTR 70 -#define CLKID_SEC_AHB_AHB3_BRIDGE 71 -#define CLKID_CLK81_A9 72 -#define CLKID_VCLK2_VENCI0 73 -#define CLKID_VCLK2_VENCI1 74 -#define CLKID_VCLK2_VENCP0 75 -#define CLKID_VCLK2_VENCP1 76 -#define CLKID_GCLK_VENCI_INT 77 -#define CLKID_GCLK_VENCP_INT 78 -#define CLKID_DAC_CLK 79 -#define CLKID_AOCLK_GATE 80 -#define CLKID_IEC958_GATE 81 -#define CLKID_ENC480P 82 -#define CLKID_RNG1 83 -#define CLKID_GCLK_VENCL_INT 84 -#define CLKID_VCLK2_VENCLMCC 85 -#define CLKID_VCLK2_VENCL 86 -#define CLKID_VCLK2_OTHER 87 -#define CLKID_EDP 88 -#define CLKID_AO_MEDIA_CPU 89 -#define CLKID_AO_AHB_SRAM 90 -#define CLKID_AO_AHB_BUS 91 -#define CLKID_AO_IFACE 92 -#define CLKID_MPLL0 93 -#define CLKID_MPLL1 94 -#define CLKID_MPLL2 95 - #define CLK_NR_CLKS 96 -/* include the CLKIDs that have been made part of the stable DT binding */ +/* + * include the CLKID and RESETID that have + * been made part of the stable DT binding + */ #include <dt-bindings/clock/meson8b-clkc.h> +#include <dt-bindings/reset/amlogic,meson8b-clkc-reset.h> #endif /* __MESON8B_H */ diff --git a/drivers/clk/mmp/clk.c b/drivers/clk/mmp/clk.c index 61893fe73251..089927e4cda2 100644 --- a/drivers/clk/mmp/clk.c +++ b/drivers/clk/mmp/clk.c @@ -9,7 +9,7 @@ void mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit, int nr_clks) { - static struct clk **clk_table; + struct clk **clk_table; clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL); if (!clk_table) diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index d990fe44aef3..cc03d5508627 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -412,8 +412,6 @@ static const struct clk_ops clk_smd_rpm_ops = { static const struct clk_ops clk_smd_rpm_branch_ops = { .prepare = clk_smd_rpm_prepare, .unprepare = clk_smd_rpm_unprepare, - .round_rate = clk_smd_rpm_round_rate, - .recalc_rate = clk_smd_rpm_recalc_rate, }; /* msm8916 */ diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c index 2cfe7000fc60..3410ee68d4bc 100644 --- a/drivers/clk/qcom/gcc-msm8916.c +++ b/drivers/clk/qcom/gcc-msm8916.c @@ -1176,7 +1176,7 @@ static struct clk_rcg2 bimc_gpu_clk_src = { .parent_names = gcc_xo_gpll0_bimc, .num_parents = 3, .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_ops, }, }; diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 8abc200d4fd3..7ddec886fcd3 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -2730,6 +2730,32 @@ static struct clk_fixed_factor ufs_rx_cfg_clk_src = { }, }; +static struct clk_branch gcc_hlos1_vote_lpass_core_smmu_clk = { + .halt_reg = 0x7d010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x7d010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "hlos1_vote_lpass_core_smmu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_hlos1_vote_lpass_adsp_smmu_clk = { + .halt_reg = 0x7d014, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x7d014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "hlos1_vote_lpass_adsp_smmu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_ufs_rx_cfg_clk = { .halt_reg = 0x75014, .clkr = { @@ -3307,6 +3333,8 @@ static struct clk_regmap *gcc_msm8996_clocks[] = { [GCC_UFS_AHB_CLK] = &gcc_ufs_ahb_clk.clkr, [GCC_UFS_TX_CFG_CLK] = &gcc_ufs_tx_cfg_clk.clkr, [GCC_UFS_RX_CFG_CLK] = &gcc_ufs_rx_cfg_clk.clkr, + [GCC_HLOS1_VOTE_LPASS_CORE_SMMU_CLK] = &gcc_hlos1_vote_lpass_core_smmu_clk.clkr, + [GCC_HLOS1_VOTE_LPASS_ADSP_SMMU_CLK] = &gcc_hlos1_vote_lpass_adsp_smmu_clk.clkr, [GCC_UFS_TX_SYMBOL_0_CLK] = &gcc_ufs_tx_symbol_0_clk.clkr, [GCC_UFS_RX_SYMBOL_0_CLK] = &gcc_ufs_rx_symbol_0_clk.clkr, [GCC_UFS_RX_SYMBOL_1_CLK] = &gcc_ufs_rx_symbol_1_clk.clkr, diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 78d1df9112ba..acbb38151ba1 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -15,6 +15,7 @@ config CLK_RENESAS select CLK_R8A7794 if ARCH_R8A7794 select CLK_R8A7795 if ARCH_R8A7795 select CLK_R8A7796 if ARCH_R8A7796 + select CLK_R8A77995 if ARCH_R8A77995 select CLK_SH73A0 if ARCH_SH73A0 if CLK_RENESAS @@ -34,94 +35,103 @@ config CLK_EMEV2 bool "Emma Mobile EV2 clock support" if COMPILE_TEST config CLK_RZA1 - bool + bool "RZ/A1H clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSTP config CLK_R8A73A4 - bool + bool "R-Mobile APE6 clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSTP select CLK_RENESAS_DIV6 config CLK_R8A7740 - bool + bool "R-Mobile A1 clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSTP select CLK_RENESAS_DIV6 config CLK_R8A7743 - bool + bool "RZ/G1M clock support" if COMPILE_TEST select CLK_RCAR_GEN2_CPG config CLK_R8A7745 - bool + bool "RZ/G1E clock support" if COMPILE_TEST select CLK_RCAR_GEN2_CPG config CLK_R8A7778 - bool + bool "R-Car M1A clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSTP config CLK_R8A7779 - bool + bool "R-Car H1 clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSTP config CLK_R8A7790 - bool + bool "R-Car H2 clock support" if COMPILE_TEST select CLK_RCAR_GEN2 if CLK_RENESAS_LEGACY select CLK_RCAR_GEN2_CPG select CLK_RENESAS_DIV6 config CLK_R8A7791 - bool + bool "R-Car M2-W/N clock support" if COMPILE_TEST select CLK_RCAR_GEN2 if CLK_RENESAS_LEGACY select CLK_RCAR_GEN2_CPG select CLK_RENESAS_DIV6 config CLK_R8A7792 - bool + bool "R-Car V2H clock support" if COMPILE_TEST select CLK_RCAR_GEN2 if CLK_RENESAS_LEGACY select CLK_RCAR_GEN2_CPG config CLK_R8A7794 - bool + bool "R-Car E2 clock support" if COMPILE_TEST select CLK_RCAR_GEN2 if CLK_RENESAS_LEGACY select CLK_RCAR_GEN2_CPG select CLK_RENESAS_DIV6 config CLK_R8A7795 - bool + bool "R-Car H3 clock support" if COMPILE_TEST select CLK_RCAR_GEN3_CPG config CLK_R8A7796 - bool + bool "R-Car M3-W clock support" if COMPILE_TEST + select CLK_RCAR_GEN3_CPG + +config CLK_R8A77995 + bool "R-Car D3 clock support" if COMPILE_TEST select CLK_RCAR_GEN3_CPG config CLK_SH73A0 - bool + bool "SH-Mobile AG5 clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSTP select CLK_RENESAS_DIV6 # Family config CLK_RCAR_GEN2 - bool + bool "R-Car Gen2 legacy clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSTP select CLK_RENESAS_DIV6 config CLK_RCAR_GEN2_CPG - bool + bool "R-Car Gen2 CPG clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSSR config CLK_RCAR_GEN3_CPG - bool + bool "R-Car Gen3 CPG clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSSR +config CLK_RCAR_USB2_CLOCK_SEL + bool "Renesas R-Car USB2 clock selector support" + depends on ARCH_RENESAS || COMPILE_TEST + help + This is a driver for R-Car USB2 clock selector # Generic config CLK_RENESAS_CPG_MSSR - bool + bool "CPG/MSSR clock support" if COMPILE_TEST select CLK_RENESAS_DIV6 config CLK_RENESAS_CPG_MSTP - bool + bool "MSTP clock support" if COMPILE_TEST config CLK_RENESAS_DIV6 bool "DIV6 clock support" if COMPILE_TEST diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index 02d04124371f..9bda3ec5b199 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -13,12 +13,14 @@ obj-$(CONFIG_CLK_R8A7792) += r8a7792-cpg-mssr.o obj-$(CONFIG_CLK_R8A7794) += r8a7794-cpg-mssr.o obj-$(CONFIG_CLK_R8A7795) += r8a7795-cpg-mssr.o obj-$(CONFIG_CLK_R8A7796) += r8a7796-cpg-mssr.o +obj-$(CONFIG_CLK_R8A77995) += r8a77995-cpg-mssr.o obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o # Family obj-$(CONFIG_CLK_RCAR_GEN2) += clk-rcar-gen2.o obj-$(CONFIG_CLK_RCAR_GEN2_CPG) += rcar-gen2-cpg.o obj-$(CONFIG_CLK_RCAR_GEN3_CPG) += rcar-gen3-cpg.o +obj-$(CONFIG_CLK_RCAR_USB2_CLOCK_SEL) += rcar-usb2-clock-sel.o # Generic obj-$(CONFIG_CLK_RENESAS_CPG_MSSR) += renesas-cpg-mssr.o diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c index 0627860233cb..3e0040c0ac87 100644 --- a/drivers/clk/renesas/clk-div6.c +++ b/drivers/clk/renesas/clk-div6.c @@ -29,6 +29,9 @@ * @hw: handle between common and hardware-specific interfaces * @reg: IO-remapped register * @div: divisor value (1-64) + * @src_shift: Shift to access the register bits to select the parent clock + * @src_width: Number of register bits to select the parent clock (may be 0) + * @parents: Array to map from valid parent clocks indices to hardware indices */ struct div6_clock { struct clk_hw hw; diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index f1617dd044cb..500a9e4e03c4 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c @@ -335,7 +335,7 @@ void __init cpg_mstp_add_clk_domain(struct device_node *np) u32 ncells; if (of_property_read_u32(np, "#power-domain-cells", &ncells)) { - pr_warn("%s lacks #power-domain-cells\n", np->full_name); + pr_warn("%pOF lacks #power-domain-cells\n", np); return; } diff --git a/drivers/clk/renesas/clk-rcar-gen2.c b/drivers/clk/renesas/clk-rcar-gen2.c index 51a2479ed5d7..0b2e56d0d94b 100644 --- a/drivers/clk/renesas/clk-rcar-gen2.c +++ b/drivers/clk/renesas/clk-rcar-gen2.c @@ -407,8 +407,7 @@ static void __init rcar_gen2_cpg_clocks_init(struct device_node *np) if (rcar_rst_read_mode_pins(&cpg_mode)) { /* Backward-compatibility with old DT */ - pr_warn("%s: failed to obtain mode pins from RST\n", - np->full_name); + pr_warn("%pOF: failed to obtain mode pins from RST\n", np); cpg_mode = rcar_gen2_read_mode_pins(); } diff --git a/drivers/clk/renesas/r8a7792-cpg-mssr.c b/drivers/clk/renesas/r8a7792-cpg-mssr.c index a832b9b6f7b0..7f85bbf20bf7 100644 --- a/drivers/clk/renesas/r8a7792-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7792-cpg-mssr.c @@ -118,6 +118,13 @@ static const struct mssr_mod_clk r8a7792_mod_clks[] __initconst = { DEF_MOD("vin1", 810, R8A7792_CLK_ZG), DEF_MOD("vin0", 811, R8A7792_CLK_ZG), DEF_MOD("etheravb", 812, R8A7792_CLK_HP), + DEF_MOD("imr-lx3", 821, R8A7792_CLK_ZG), + DEF_MOD("imr-lsx3-1", 822, R8A7792_CLK_ZG), + DEF_MOD("imr-lsx3-0", 823, R8A7792_CLK_ZG), + DEF_MOD("imr-lsx3-5", 825, R8A7792_CLK_ZG), + DEF_MOD("imr-lsx3-4", 826, R8A7792_CLK_ZG), + DEF_MOD("imr-lsx3-3", 827, R8A7792_CLK_ZG), + DEF_MOD("imr-lsx3-2", 828, R8A7792_CLK_ZG), DEF_MOD("gyro-adc", 901, R8A7792_CLK_P), DEF_MOD("gpio7", 904, R8A7792_CLK_CP), DEF_MOD("gpio6", 905, R8A7792_CLK_CP), diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index c091a8e024b8..762b2f8824f1 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -305,23 +305,23 @@ static const unsigned int r8a7795_crit_mod_clks[] __initconst = { (((md) & BIT(17)) >> 17)) static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = { - /* EXTAL div PLL1 mult PLL3 mult */ - { 1, 192, 192, }, - { 1, 192, 128, }, - { 0, /* Prohibited setting */ }, - { 1, 192, 192, }, - { 1, 160, 160, }, - { 1, 160, 106, }, - { 0, /* Prohibited setting */ }, - { 1, 160, 160, }, - { 1, 128, 128, }, - { 1, 128, 84, }, - { 0, /* Prohibited setting */ }, - { 1, 128, 128, }, - { 2, 192, 192, }, - { 2, 192, 128, }, - { 0, /* Prohibited setting */ }, - { 2, 192, 192, }, + /* EXTAL div PLL1 mult/div PLL3 mult/div */ + { 1, 192, 1, 192, 1, }, + { 1, 192, 1, 128, 1, }, + { 0, /* Prohibited setting */ }, + { 1, 192, 1, 192, 1, }, + { 1, 160, 1, 160, 1, }, + { 1, 160, 1, 106, 1, }, + { 0, /* Prohibited setting */ }, + { 1, 160, 1, 160, 1, }, + { 1, 128, 1, 128, 1, }, + { 1, 128, 1, 84, 1, }, + { 0, /* Prohibited setting */ }, + { 1, 128, 1, 128, 1, }, + { 2, 192, 1, 192, 1, }, + { 2, 192, 1, 128, 1, }, + { 0, /* Prohibited setting */ }, + { 2, 192, 1, 192, 1, }, }; static const struct soc_device_attribute r8a7795es1[] __initconst = { diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index acc6d0f153e1..e5e7fb212288 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -138,6 +138,7 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { DEF_MOD("sdif0", 314, R8A7796_CLK_SD0), DEF_MOD("pcie1", 318, R8A7796_CLK_S3D1), DEF_MOD("pcie0", 319, R8A7796_CLK_S3D1), + DEF_MOD("usb3-if0", 328, R8A7796_CLK_S3D1), DEF_MOD("usb-dmac0", 330, R8A7796_CLK_S3D1), DEF_MOD("usb-dmac1", 331, R8A7796_CLK_S3D1), DEF_MOD("rwdt", 402, R8A7796_CLK_R), @@ -277,23 +278,23 @@ static const unsigned int r8a7796_crit_mod_clks[] __initconst = { (((md) & BIT(17)) >> 17)) static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = { - /* EXTAL div PLL1 mult PLL3 mult */ - { 1, 192, 192, }, - { 1, 192, 128, }, - { 0, /* Prohibited setting */ }, - { 1, 192, 192, }, - { 1, 160, 160, }, - { 1, 160, 106, }, - { 0, /* Prohibited setting */ }, - { 1, 160, 160, }, - { 1, 128, 128, }, - { 1, 128, 84, }, - { 0, /* Prohibited setting */ }, - { 1, 128, 128, }, - { 2, 192, 192, }, - { 2, 192, 128, }, - { 0, /* Prohibited setting */ }, - { 2, 192, 192, }, + /* EXTAL div PLL1 mult/div PLL3 mult/div */ + { 1, 192, 1, 192, 1, }, + { 1, 192, 1, 128, 1, }, + { 0, /* Prohibited setting */ }, + { 1, 192, 1, 192, 1, }, + { 1, 160, 1, 160, 1, }, + { 1, 160, 1, 106, 1, }, + { 0, /* Prohibited setting */ }, + { 1, 160, 1, 160, 1, }, + { 1, 128, 1, 128, 1, }, + { 1, 128, 1, 84, 1, }, + { 0, /* Prohibited setting */ }, + { 1, 128, 1, 128, 1, }, + { 2, 192, 1, 192, 1, }, + { 2, 192, 1, 128, 1, }, + { 0, /* Prohibited setting */ }, + { 2, 192, 1, 192, 1, }, }; static int __init r8a7796_cpg_mssr_init(struct device *dev) diff --git a/drivers/clk/renesas/r8a77995-cpg-mssr.c b/drivers/clk/renesas/r8a77995-cpg-mssr.c new file mode 100644 index 000000000000..e594cf8ee63b --- /dev/null +++ b/drivers/clk/renesas/r8a77995-cpg-mssr.c @@ -0,0 +1,236 @@ +/* + * r8a77995 Clock Pulse Generator / Module Standby and Software Reset + * + * Copyright (C) 2017 Glider bvba + * + * Based on r8a7795-cpg-mssr.c + * + * Copyright (C) 2015 Glider bvba + * Copyright (C) 2015 Renesas Electronics Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include <linux/device.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/soc/renesas/rcar-rst.h> + +#include <dt-bindings/clock/r8a77995-cpg-mssr.h> + +#include "renesas-cpg-mssr.h" +#include "rcar-gen3-cpg.h" + +enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R8A77995_CLK_CP, + + /* External Input Clocks */ + CLK_EXTAL, + + /* Internal Core Clocks */ + CLK_MAIN, + CLK_PLL0, + CLK_PLL1, + CLK_PLL3, + CLK_PLL0D2, + CLK_PLL0D3, + CLK_PLL0D5, + CLK_PLL1D2, + CLK_PE, + CLK_S0, + CLK_S1, + CLK_S2, + CLK_S3, + CLK_SDSRC, + CLK_SSPSRC, + + /* Module Clocks */ + MOD_CLK_BASE +}; + +static const struct cpg_core_clk r8a77995_core_clks[] __initconst = { + /* External Clock Inputs */ + DEF_INPUT("extal", CLK_EXTAL), + + /* Internal Core Clocks */ + DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL), + DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN), + DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN), + + DEF_FIXED(".pll0", CLK_PLL0, CLK_MAIN, 4, 250), + DEF_FIXED(".pll0d2", CLK_PLL0D2, CLK_PLL0, 2, 1), + DEF_FIXED(".pll0d3", CLK_PLL0D3, CLK_PLL0, 3, 1), + DEF_FIXED(".pll0d5", CLK_PLL0D5, CLK_PLL0, 5, 1), + DEF_FIXED(".pll1d2", CLK_PLL1D2, CLK_PLL1, 2, 1), + DEF_FIXED(".pe", CLK_PE, CLK_PLL0D3, 4, 1), + DEF_FIXED(".s0", CLK_S0, CLK_PLL1, 2, 1), + DEF_FIXED(".s1", CLK_S1, CLK_PLL1, 3, 1), + DEF_FIXED(".s2", CLK_S2, CLK_PLL1, 4, 1), + DEF_FIXED(".s3", CLK_S3, CLK_PLL1, 6, 1), + DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1, 2, 1), + + /* Core Clock Outputs */ + DEF_FIXED("z2", R8A77995_CLK_Z2, CLK_PLL0D3, 1, 1), + DEF_FIXED("ztr", R8A77995_CLK_ZTR, CLK_PLL1, 6, 1), + DEF_FIXED("zt", R8A77995_CLK_ZT, CLK_PLL1, 4, 1), + DEF_FIXED("zx", R8A77995_CLK_ZX, CLK_PLL1, 3, 1), + DEF_FIXED("s0d1", R8A77995_CLK_S0D1, CLK_S0, 1, 1), + DEF_FIXED("s1d1", R8A77995_CLK_S1D1, CLK_S1, 1, 1), + DEF_FIXED("s1d2", R8A77995_CLK_S1D2, CLK_S1, 2, 1), + DEF_FIXED("s1d4", R8A77995_CLK_S1D4, CLK_S1, 4, 1), + DEF_FIXED("s2d1", R8A77995_CLK_S2D1, CLK_S2, 1, 1), + DEF_FIXED("s2d2", R8A77995_CLK_S2D2, CLK_S2, 2, 1), + DEF_FIXED("s2d4", R8A77995_CLK_S2D4, CLK_S2, 4, 1), + DEF_FIXED("s3d1", R8A77995_CLK_S3D1, CLK_S3, 1, 1), + DEF_FIXED("s3d2", R8A77995_CLK_S3D2, CLK_S3, 2, 1), + DEF_FIXED("s3d4", R8A77995_CLK_S3D4, CLK_S3, 4, 1), + + DEF_FIXED("cl", R8A77995_CLK_CL, CLK_PLL1, 48, 1), + DEF_FIXED("cp", R8A77995_CLK_CP, CLK_EXTAL, 2, 1), + DEF_FIXED("osc", R8A77995_CLK_OSC, CLK_EXTAL, 384, 1), + DEF_FIXED("r", R8A77995_CLK_R, CLK_EXTAL, 1536, 1), + + DEF_GEN3_PE("s1d4c", R8A77995_CLK_S1D4C, CLK_S1, 4, CLK_PE, 2), + DEF_GEN3_PE("s3d1c", R8A77995_CLK_S3D1C, CLK_S3, 1, CLK_PE, 1), + DEF_GEN3_PE("s3d2c", R8A77995_CLK_S3D2C, CLK_S3, 2, CLK_PE, 2), + DEF_GEN3_PE("s3d4c", R8A77995_CLK_S3D4C, CLK_S3, 4, CLK_PE, 4), + + DEF_GEN3_SD("sd0", R8A77995_CLK_SD0, CLK_SDSRC, 0x268), + + DEF_DIV6P1("canfd", R8A77995_CLK_CANFD, CLK_PLL0D3, 0x244), + DEF_DIV6P1("mso", R8A77995_CLK_MSO, CLK_PLL1D2, 0x014), +}; + +static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = { + DEF_MOD("scif5", 202, R8A77995_CLK_S3D4C), + DEF_MOD("scif4", 203, R8A77995_CLK_S3D4C), + DEF_MOD("scif3", 204, R8A77995_CLK_S3D4C), + DEF_MOD("scif1", 206, R8A77995_CLK_S3D4C), + DEF_MOD("scif0", 207, R8A77995_CLK_S3D4C), + DEF_MOD("msiof3", 208, R8A77995_CLK_MSO), + DEF_MOD("msiof2", 209, R8A77995_CLK_MSO), + DEF_MOD("msiof1", 210, R8A77995_CLK_MSO), + DEF_MOD("msiof0", 211, R8A77995_CLK_MSO), + DEF_MOD("sys-dmac2", 217, R8A77995_CLK_S3D1), + DEF_MOD("sys-dmac1", 218, R8A77995_CLK_S3D1), + DEF_MOD("sys-dmac0", 219, R8A77995_CLK_S3D1), + DEF_MOD("cmt3", 300, R8A77995_CLK_R), + DEF_MOD("cmt2", 301, R8A77995_CLK_R), + DEF_MOD("cmt1", 302, R8A77995_CLK_R), + DEF_MOD("cmt0", 303, R8A77995_CLK_R), + DEF_MOD("scif2", 310, R8A77995_CLK_S3D4C), + DEF_MOD("emmc0", 312, R8A77995_CLK_SD0), + DEF_MOD("usb-dmac0", 330, R8A77995_CLK_S3D1), + DEF_MOD("usb-dmac1", 331, R8A77995_CLK_S3D1), + DEF_MOD("rwdt", 402, R8A77995_CLK_R), + DEF_MOD("intc-ex", 407, R8A77995_CLK_CP), + DEF_MOD("intc-ap", 408, R8A77995_CLK_S3D1), + DEF_MOD("audmac0", 502, R8A77995_CLK_S3D1), + DEF_MOD("hscif3", 517, R8A77995_CLK_S3D1C), + DEF_MOD("hscif0", 520, R8A77995_CLK_S3D1C), + DEF_MOD("thermal", 522, R8A77995_CLK_CP), + DEF_MOD("pwm", 523, R8A77995_CLK_S3D4C), + DEF_MOD("fcpvd1", 602, R8A77995_CLK_S1D2), + DEF_MOD("fcpvd0", 603, R8A77995_CLK_S1D2), + DEF_MOD("fcpvbs", 607, R8A77995_CLK_S0D1), + DEF_MOD("vspd1", 622, R8A77995_CLK_S1D2), + DEF_MOD("vspd0", 623, R8A77995_CLK_S1D2), + DEF_MOD("vspbs", 627, R8A77995_CLK_S0D1), + DEF_MOD("ehci0", 703, R8A77995_CLK_S3D2), + DEF_MOD("hsusb", 704, R8A77995_CLK_S3D2), + DEF_MOD("du1", 723, R8A77995_CLK_S2D1), + DEF_MOD("du0", 724, R8A77995_CLK_S2D1), + DEF_MOD("lvds", 727, R8A77995_CLK_S2D1), + DEF_MOD("vin7", 804, R8A77995_CLK_S1D2), + DEF_MOD("vin6", 805, R8A77995_CLK_S1D2), + DEF_MOD("vin5", 806, R8A77995_CLK_S1D2), + DEF_MOD("vin4", 807, R8A77995_CLK_S1D2), + DEF_MOD("etheravb", 812, R8A77995_CLK_S3D2), + DEF_MOD("imr0", 823, R8A77995_CLK_S1D2), + DEF_MOD("gpio6", 906, R8A77995_CLK_S3D4), + DEF_MOD("gpio5", 907, R8A77995_CLK_S3D4), + DEF_MOD("gpio4", 908, R8A77995_CLK_S3D4), + DEF_MOD("gpio3", 909, R8A77995_CLK_S3D4), + DEF_MOD("gpio2", 910, R8A77995_CLK_S3D4), + DEF_MOD("gpio1", 911, R8A77995_CLK_S3D4), + DEF_MOD("gpio0", 912, R8A77995_CLK_S3D4), + DEF_MOD("can-fd", 914, R8A77995_CLK_S3D2), + DEF_MOD("can-if1", 915, R8A77995_CLK_S3D4), + DEF_MOD("can-if0", 916, R8A77995_CLK_S3D4), + DEF_MOD("i2c3", 928, R8A77995_CLK_S3D2), + DEF_MOD("i2c2", 929, R8A77995_CLK_S3D2), + DEF_MOD("i2c1", 930, R8A77995_CLK_S3D2), + DEF_MOD("i2c0", 931, R8A77995_CLK_S3D2), + DEF_MOD("ssi-all", 1005, R8A77995_CLK_S3D4), + DEF_MOD("ssi4", 1011, MOD_CLK_ID(1005)), + DEF_MOD("ssi3", 1012, MOD_CLK_ID(1005)), + DEF_MOD("scu-all", 1017, R8A77995_CLK_S3D4), + DEF_MOD("scu-dvc1", 1018, MOD_CLK_ID(1017)), + DEF_MOD("scu-dvc0", 1019, MOD_CLK_ID(1017)), + DEF_MOD("scu-ctu1-mix1", 1020, MOD_CLK_ID(1017)), + DEF_MOD("scu-ctu0-mix0", 1021, MOD_CLK_ID(1017)), + DEF_MOD("scu-src6", 1025, MOD_CLK_ID(1017)), + DEF_MOD("scu-src5", 1026, MOD_CLK_ID(1017)), +}; + +static const unsigned int r8a77995_crit_mod_clks[] __initconst = { + MOD_CLK_ID(408), /* INTC-AP (GIC) */ +}; + + +/* + * CPG Clock Data + */ + +/* + * MD19 EXTAL (MHz) PLL0 PLL1 PLL3 + *-------------------------------------------------------------------- + * 0 48 x 1 x250/4 x100/3 x100/3 + * 1 48 x 1 x250/4 x100/3 x116/6 + */ +#define CPG_PLL_CONFIG_INDEX(md) (((md) & BIT(19)) >> 19) + +static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[2] __initconst = { + /* EXTAL div PLL1 mult/div PLL3 mult/div */ + { 1, 100, 3, 100, 3, }, + { 1, 100, 3, 116, 6, }, +}; + +static int __init r8a77995_cpg_mssr_init(struct device *dev) +{ + const struct rcar_gen3_cpg_pll_config *cpg_pll_config; + u32 cpg_mode; + int error; + + error = rcar_rst_read_mode_pins(&cpg_mode); + if (error) + return error; + + cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; + + return rcar_gen3_cpg_init(cpg_pll_config, 0, cpg_mode); +} + +const struct cpg_mssr_info r8a77995_cpg_mssr_info __initconst = { + /* Core Clocks */ + .core_clks = r8a77995_core_clks, + .num_core_clks = ARRAY_SIZE(r8a77995_core_clks), + .last_dt_core_clk = LAST_DT_CORE_CLK, + .num_total_core_clks = MOD_CLK_BASE, + + /* Module Clocks */ + .mod_clks = r8a77995_mod_clks, + .num_mod_clks = ARRAY_SIZE(r8a77995_mod_clks), + .num_hw_mod_clks = 12 * 32, + + /* Critical Module Clocks */ + .crit_mod_clks = r8a77995_crit_mod_clks, + .num_crit_mod_clks = ARRAY_SIZE(r8a77995_crit_mod_clks), + + /* Callbacks */ + .init = r8a77995_cpg_mssr_init, + .cpg_clk_register = rcar_gen3_cpg_clk_register, +}; diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index 3dee900522b7..951105816547 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -60,6 +60,7 @@ struct sd_clock { unsigned int div_num; unsigned int div_min; unsigned int div_max; + unsigned int cur_div_idx; }; /* SDn divider @@ -96,21 +97,10 @@ static const struct sd_div_table cpg_sd_div_table[] = { static int cpg_sd_clock_enable(struct clk_hw *hw) { struct sd_clock *clock = to_sd_clock(hw); - u32 val, sd_fc; - unsigned int i; - - val = readl(clock->reg); - - sd_fc = val & CPG_SD_FC_MASK; - for (i = 0; i < clock->div_num; i++) - if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK)) - break; - - if (i >= clock->div_num) - return -EINVAL; + u32 val = readl(clock->reg); val &= ~(CPG_SD_STP_MASK); - val |= clock->div_table[i].val & CPG_SD_STP_MASK; + val |= clock->div_table[clock->cur_div_idx].val & CPG_SD_STP_MASK; writel(val, clock->reg); @@ -135,21 +125,9 @@ static unsigned long cpg_sd_clock_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct sd_clock *clock = to_sd_clock(hw); - unsigned long rate = parent_rate; - u32 val, sd_fc; - unsigned int i; - val = readl(clock->reg); - - sd_fc = val & CPG_SD_FC_MASK; - for (i = 0; i < clock->div_num; i++) - if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK)) - break; - - if (i >= clock->div_num) - return -EINVAL; - - return DIV_ROUND_CLOSEST(rate, clock->div_table[i].div); + return DIV_ROUND_CLOSEST(parent_rate, + clock->div_table[clock->cur_div_idx].div); } static unsigned int cpg_sd_clock_calc_div(struct sd_clock *clock, @@ -190,6 +168,8 @@ static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate, if (i >= clock->div_num) return -EINVAL; + clock->cur_div_idx = i; + val = readl(clock->reg); val &= ~(CPG_SD_STP_MASK | CPG_SD_FC_MASK); val |= clock->div_table[i].val & (CPG_SD_STP_MASK | CPG_SD_FC_MASK); @@ -215,6 +195,7 @@ static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core, struct sd_clock *clock; struct clk *clk; unsigned int i; + u32 sd_fc; clock = kzalloc(sizeof(*clock), GFP_KERNEL); if (!clock) @@ -231,6 +212,18 @@ static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core, clock->div_table = cpg_sd_div_table; clock->div_num = ARRAY_SIZE(cpg_sd_div_table); + sd_fc = readl(clock->reg) & CPG_SD_FC_MASK; + for (i = 0; i < clock->div_num; i++) + if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK)) + break; + + if (WARN_ON(i >= clock->div_num)) { + kfree(clock); + return ERR_PTR(-EINVAL); + } + + clock->cur_div_idx = i; + clock->div_max = clock->div_table[0].div; clock->div_min = clock->div_max; for (i = 1; i < clock->div_num; i++) { @@ -279,7 +272,7 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, unsigned int div = 1; u32 value; - parent = clks[core->parent]; + parent = clks[core->parent & 0xffff]; /* CLK_TYPE_PE uses high bits */ if (IS_ERR(parent)) return ERR_CAST(parent); @@ -303,6 +296,7 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, case CLK_TYPE_GEN3_PLL1: mult = cpg_pll_config->pll1_mult; + div = cpg_pll_config->pll1_div; break; case CLK_TYPE_GEN3_PLL2: @@ -320,6 +314,7 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, case CLK_TYPE_GEN3_PLL3: mult = cpg_pll_config->pll3_mult; + div = cpg_pll_config->pll3_div; break; case CLK_TYPE_GEN3_PLL4: @@ -360,6 +355,24 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, parent = clks[cpg_clk_extalr]; break; + case CLK_TYPE_GEN3_PE: + /* + * Peripheral clock with a fixed divider, selectable between + * clean and spread spectrum parents using MD12 + */ + if (cpg_mode & BIT(12)) { + /* Clean */ + div = core->div & 0xffff; + } else { + /* SCCG */ + parent = clks[core->parent >> 16]; + if (IS_ERR(parent)) + return ERR_CAST(parent); + div = core->div >> 16; + } + mult = 1; + break; + default: return ERR_PTR(-EINVAL); } diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index 073be54b5d03..d756ef8b78eb 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -20,15 +20,24 @@ enum rcar_gen3_clk_types { CLK_TYPE_GEN3_PLL4, CLK_TYPE_GEN3_SD, CLK_TYPE_GEN3_R, + CLK_TYPE_GEN3_PE, }; #define DEF_GEN3_SD(_name, _id, _parent, _offset) \ DEF_BASE(_name, _id, CLK_TYPE_GEN3_SD, _parent, .offset = _offset) +#define DEF_GEN3_PE(_name, _id, _parent_sscg, _div_sscg, _parent_clean, \ + _div_clean) \ + DEF_BASE(_name, _id, CLK_TYPE_GEN3_PE, \ + (_parent_sscg) << 16 | (_parent_clean), \ + .div = (_div_sscg) << 16 | (_div_clean)) + struct rcar_gen3_cpg_pll_config { - unsigned int extal_div; - unsigned int pll1_mult; - unsigned int pll3_mult; + u8 extal_div; + u8 pll1_mult; + u8 pll1_div; + u8 pll3_mult; + u8 pll3_div; }; #define CPG_RCKCR 0x240 diff --git a/drivers/clk/renesas/rcar-usb2-clock-sel.c b/drivers/clk/renesas/rcar-usb2-clock-sel.c new file mode 100644 index 000000000000..6cd030a58964 --- /dev/null +++ b/drivers/clk/renesas/rcar-usb2-clock-sel.c @@ -0,0 +1,188 @@ +/* + * Renesas R-Car USB2.0 clock selector + * + * Copyright (C) 2017 Renesas Electronics Corp. + * + * Based on renesas-cpg-mssr.c + * + * Copyright (C) 2015 Glider bvba + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> + +#define USB20_CLKSET0 0x00 +#define CLKSET0_INTCLK_EN BIT(11) +#define CLKSET0_PRIVATE BIT(0) +#define CLKSET0_EXTAL_ONLY (CLKSET0_INTCLK_EN | CLKSET0_PRIVATE) + +struct usb2_clock_sel_priv { + void __iomem *base; + struct clk_hw hw; + bool extal; + bool xtal; +}; +#define to_priv(_hw) container_of(_hw, struct usb2_clock_sel_priv, hw) + +static void usb2_clock_sel_enable_extal_only(struct usb2_clock_sel_priv *priv) +{ + u16 val = readw(priv->base + USB20_CLKSET0); + + pr_debug("%s: enter %d %d %x\n", __func__, + priv->extal, priv->xtal, val); + + if (priv->extal && !priv->xtal && val != CLKSET0_EXTAL_ONLY) + writew(CLKSET0_EXTAL_ONLY, priv->base + USB20_CLKSET0); +} + +static void usb2_clock_sel_disable_extal_only(struct usb2_clock_sel_priv *priv) +{ + if (priv->extal && !priv->xtal) + writew(CLKSET0_PRIVATE, priv->base + USB20_CLKSET0); +} + +static int usb2_clock_sel_enable(struct clk_hw *hw) +{ + usb2_clock_sel_enable_extal_only(to_priv(hw)); + + return 0; +} + +static void usb2_clock_sel_disable(struct clk_hw *hw) +{ + usb2_clock_sel_disable_extal_only(to_priv(hw)); +} + +/* + * This module seems a mux, but this driver assumes a gate because + * ehci/ohci platform drivers don't support clk_set_parent() for now. + * If this driver acts as a gate, ehci/ohci-platform drivers don't need + * any modification. + */ +static const struct clk_ops usb2_clock_sel_clock_ops = { + .enable = usb2_clock_sel_enable, + .disable = usb2_clock_sel_disable, +}; + +static const struct of_device_id rcar_usb2_clock_sel_match[] = { + { .compatible = "renesas,rcar-gen3-usb2-clock-sel" }, + { } +}; + +static int rcar_usb2_clock_sel_suspend(struct device *dev) +{ + struct usb2_clock_sel_priv *priv = dev_get_drvdata(dev); + + usb2_clock_sel_disable_extal_only(priv); + pm_runtime_put(dev); + + return 0; +} + +static int rcar_usb2_clock_sel_resume(struct device *dev) +{ + struct usb2_clock_sel_priv *priv = dev_get_drvdata(dev); + + pm_runtime_get_sync(dev); + usb2_clock_sel_enable_extal_only(priv); + + return 0; +} + +static int rcar_usb2_clock_sel_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct usb2_clock_sel_priv *priv = platform_get_drvdata(pdev); + + of_clk_del_provider(dev->of_node); + clk_hw_unregister(&priv->hw); + pm_runtime_put(dev); + pm_runtime_disable(dev); + + return 0; +} + +static int rcar_usb2_clock_sel_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct usb2_clock_sel_priv *priv; + struct resource *res; + struct clk *clk; + struct clk_init_data init; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + + clk = devm_clk_get(dev, "usb_extal"); + if (!IS_ERR(clk) && !clk_prepare_enable(clk)) { + priv->extal = !!clk_get_rate(clk); + clk_disable_unprepare(clk); + } + clk = devm_clk_get(dev, "usb_xtal"); + if (!IS_ERR(clk) && !clk_prepare_enable(clk)) { + priv->xtal = !!clk_get_rate(clk); + clk_disable_unprepare(clk); + } + + if (!priv->extal && !priv->xtal) { + dev_err(dev, "This driver needs usb_extal or usb_xtal\n"); + return -ENOENT; + } + + platform_set_drvdata(pdev, priv); + dev_set_drvdata(dev, priv); + + init.name = "rcar_usb2_clock_sel"; + init.ops = &usb2_clock_sel_clock_ops; + init.flags = 0; + init.parent_names = NULL; + init.num_parents = 0; + priv->hw.init = &init; + + clk = clk_register(NULL, &priv->hw); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + return of_clk_add_hw_provider(np, of_clk_hw_simple_get, &priv->hw); +} + +static const struct dev_pm_ops rcar_usb2_clock_sel_pm_ops = { + .suspend = rcar_usb2_clock_sel_suspend, + .resume = rcar_usb2_clock_sel_resume, +}; + +static struct platform_driver rcar_usb2_clock_sel_driver = { + .driver = { + .name = "rcar-usb2-clock-sel", + .of_match_table = rcar_usb2_clock_sel_match, + .pm = &rcar_usb2_clock_sel_pm_ops, + }, + .probe = rcar_usb2_clock_sel_probe, + .remove = rcar_usb2_clock_sel_remove, +}; +builtin_platform_driver(rcar_usb2_clock_sel_driver); + +MODULE_DESCRIPTION("Renesas R-Car USB2 clock selector Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 1f607c806f9b..e580a5e6346c 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -680,6 +680,12 @@ static const struct of_device_id cpg_mssr_match[] = { .data = &r8a7796_cpg_mssr_info, }, #endif +#ifdef CONFIG_CLK_R8A77995 + { + .compatible = "renesas,r8a77995-cpg-mssr", + .data = &r8a77995_cpg_mssr_info, + }, +#endif { /* sentinel */ } }; diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h index 43d7c7f6832d..94b9071d1061 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.h +++ b/drivers/clk/renesas/renesas-cpg-mssr.h @@ -138,6 +138,7 @@ extern const struct cpg_mssr_info r8a7792_cpg_mssr_info; extern const struct cpg_mssr_info r8a7794_cpg_mssr_info; extern const struct cpg_mssr_info r8a7795_cpg_mssr_info; extern const struct cpg_mssr_info r8a7796_cpg_mssr_info; +extern const struct cpg_mssr_info r8a77995_cpg_mssr_info; /* diff --git a/drivers/clk/rockchip/clk-rk3128.c b/drivers/clk/rockchip/clk-rk3128.c index e243f2eae68f..62d7854e4b87 100644 --- a/drivers/clk/rockchip/clk-rk3128.c +++ b/drivers/clk/rockchip/clk-rk3128.c @@ -201,7 +201,7 @@ static struct rockchip_clk_branch rk3128_uart2_fracmux __initdata = MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(15), 8, 2, MFLAGS); -static struct rockchip_clk_branch rk3128_clk_branches[] __initdata = { +static struct rockchip_clk_branch common_clk_branches[] __initdata = { /* * Clock-Architecture Diagram 1 */ @@ -459,10 +459,6 @@ static struct rockchip_clk_branch rk3128_clk_branches[] __initdata = { RK2928_CLKSEL_CON(2), 14, 2, MFLAGS, 8, 5, DFLAGS, RK2928_CLKGATE_CON(10), 15, GFLAGS), - COMPOSITE(SCLK_SFC, "sclk_sfc", mux_sclk_sfc_src_p, 0, - RK2928_CLKSEL_CON(11), 14, 2, MFLAGS, 8, 5, DFLAGS, - RK2928_CLKGATE_CON(3), 15, GFLAGS), - COMPOSITE_NOMUX(PCLK_PMU_PRE, "pclk_pmu_pre", "cpll", 0, RK2928_CLKSEL_CON(29), 8, 6, DFLAGS, RK2928_CLKGATE_CON(1), 0, GFLAGS), @@ -495,7 +491,6 @@ static struct rockchip_clk_branch rk3128_clk_branches[] __initdata = { GATE(ACLK_DMAC, "aclk_dmac", "aclk_peri", 0, RK2928_CLKGATE_CON(5), 1, GFLAGS), GATE(0, "aclk_peri_niu", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 15, GFLAGS), GATE(0, "aclk_cpu_to_peri", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 2, GFLAGS), - GATE(HCLK_GPS, "hclk_gps", "aclk_peri", 0, RK2928_CLKGATE_CON(3), 14, GFLAGS), GATE(HCLK_I2S_8CH, "hclk_i2s_8ch", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS), GATE(0, "hclk_peri_matrix", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 0, GFLAGS), @@ -541,7 +536,6 @@ static struct rockchip_clk_branch rk3128_clk_branches[] __initdata = { GATE(0, "hclk_rom", "hclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 6, GFLAGS), GATE(HCLK_CRYPTO, "hclk_crypto", "hclk_cpu", 0, RK2928_CLKGATE_CON(3), 5, GFLAGS), - GATE(PCLK_HDMI, "pclk_hdmi", "pclk_cpu", 0, RK2928_CLKGATE_CON(3), 8, GFLAGS), GATE(PCLK_ACODEC, "pclk_acodec", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 14, GFLAGS), GATE(0, "pclk_ddrupctl", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 7, GFLAGS), GATE(0, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 4, GFLAGS), @@ -561,6 +555,21 @@ static struct rockchip_clk_branch rk3128_clk_branches[] __initdata = { MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 0), }; +static struct rockchip_clk_branch rk3126_clk_branches[] __initdata = { + GATE(0, "pclk_stimer", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 15, GFLAGS), + GATE(0, "pclk_s_efuse", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 14, GFLAGS), + GATE(0, "pclk_sgrf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 8, GFLAGS), +}; + +static struct rockchip_clk_branch rk3128_clk_branches[] __initdata = { + COMPOSITE(SCLK_SFC, "sclk_sfc", mux_sclk_sfc_src_p, 0, + RK2928_CLKSEL_CON(11), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 15, GFLAGS), + + GATE(HCLK_GPS, "hclk_gps", "aclk_peri", 0, RK2928_CLKGATE_CON(3), 14, GFLAGS), + GATE(PCLK_HDMI, "pclk_hdmi", "pclk_cpu", 0, RK2928_CLKGATE_CON(3), 8, GFLAGS), +}; + static const char *const rk3128_critical_clocks[] __initconst = { "aclk_cpu", "hclk_cpu", @@ -570,7 +579,7 @@ static const char *const rk3128_critical_clocks[] __initconst = { "pclk_peri", }; -static void __init rk3128_clk_init(struct device_node *np) +static struct rockchip_clk_provider *__init rk3128_common_clk_init(struct device_node *np) { struct rockchip_clk_provider *ctx; void __iomem *reg_base; @@ -578,23 +587,21 @@ static void __init rk3128_clk_init(struct device_node *np) reg_base = of_iomap(np, 0); if (!reg_base) { pr_err("%s: could not map cru region\n", __func__); - return; + return ERR_PTR(-ENOMEM); } ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); if (IS_ERR(ctx)) { pr_err("%s: rockchip clk init failed\n", __func__); iounmap(reg_base); - return; + return ERR_PTR(-ENOMEM); } rockchip_clk_register_plls(ctx, rk3128_pll_clks, ARRAY_SIZE(rk3128_pll_clks), RK3128_GRF_SOC_STATUS0); - rockchip_clk_register_branches(ctx, rk3128_clk_branches, - ARRAY_SIZE(rk3128_clk_branches)); - rockchip_clk_protect_critical(rk3128_critical_clocks, - ARRAY_SIZE(rk3128_critical_clocks)); + rockchip_clk_register_branches(ctx, common_clk_branches, + ARRAY_SIZE(common_clk_branches)); rockchip_clk_register_armclk(ctx, ARMCLK, "armclk", mux_armclk_p, ARRAY_SIZE(mux_armclk_p), @@ -606,6 +613,40 @@ static void __init rk3128_clk_init(struct device_node *np) rockchip_register_restart_notifier(ctx, RK2928_GLB_SRST_FST, NULL); + return ctx; +} + +static void __init rk3126_clk_init(struct device_node *np) +{ + struct rockchip_clk_provider *ctx; + + ctx = rk3128_common_clk_init(np); + if (IS_ERR(ctx)) + return; + + rockchip_clk_register_branches(ctx, rk3126_clk_branches, + ARRAY_SIZE(rk3126_clk_branches)); + rockchip_clk_protect_critical(rk3128_critical_clocks, + ARRAY_SIZE(rk3128_critical_clocks)); + + rockchip_clk_of_add_provider(np, ctx); +} + +CLK_OF_DECLARE(rk3126_cru, "rockchip,rk3126-cru", rk3126_clk_init); + +static void __init rk3128_clk_init(struct device_node *np) +{ + struct rockchip_clk_provider *ctx; + + ctx = rk3128_common_clk_init(np); + if (IS_ERR(ctx)) + return; + + rockchip_clk_register_branches(ctx, rk3128_clk_branches, + ARRAY_SIZE(rk3128_clk_branches)); + rockchip_clk_protect_critical(rk3128_critical_clocks, + ARRAY_SIZE(rk3128_critical_clocks)); + rockchip_clk_of_add_provider(np, ctx); } diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c index bb405d9044a3..11e7f2d1c054 100644 --- a/drivers/clk/rockchip/clk-rk3228.c +++ b/drivers/clk/rockchip/clk-rk3228.c @@ -391,7 +391,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { RK2928_CLKSEL_CON(11), 8, 2, MFLAGS, 0, 8, DFLAGS, RK2928_CLKGATE_CON(2), 11, GFLAGS), - COMPOSITE_NODIV(0, "sclk_sdio_src", mux_mmc_src_p, 0, + COMPOSITE_NODIV(SCLK_SDIO_SRC, "sclk_sdio_src", mux_mmc_src_p, 0, RK2928_CLKSEL_CON(11), 10, 2, MFLAGS, RK2928_CLKGATE_CON(2), 13, GFLAGS), DIV(SCLK_SDIO, "sclk_sdio", "sclk_sdio_src", 0, diff --git a/drivers/clk/rockchip/clk-rv1108.c b/drivers/clk/rockchip/clk-rv1108.c index 7c05ab366348..089cb17925e5 100644 --- a/drivers/clk/rockchip/clk-rv1108.c +++ b/drivers/clk/rockchip/clk-rv1108.c @@ -93,9 +93,24 @@ static struct rockchip_pll_rate_table rv1108_pll_rates[] = { } static struct rockchip_cpuclk_rate_table rv1108_cpuclk_rates[] __initdata = { - RV1108_CPUCLK_RATE(816000000, 4), - RV1108_CPUCLK_RATE(600000000, 4), - RV1108_CPUCLK_RATE(312000000, 4), + RV1108_CPUCLK_RATE(1608000000, 7), + RV1108_CPUCLK_RATE(1512000000, 7), + RV1108_CPUCLK_RATE(1488000000, 5), + RV1108_CPUCLK_RATE(1416000000, 5), + RV1108_CPUCLK_RATE(1392000000, 5), + RV1108_CPUCLK_RATE(1296000000, 5), + RV1108_CPUCLK_RATE(1200000000, 5), + RV1108_CPUCLK_RATE(1104000000, 5), + RV1108_CPUCLK_RATE(1008000000, 5), + RV1108_CPUCLK_RATE(912000000, 5), + RV1108_CPUCLK_RATE(816000000, 3), + RV1108_CPUCLK_RATE(696000000, 3), + RV1108_CPUCLK_RATE(600000000, 3), + RV1108_CPUCLK_RATE(500000000, 3), + RV1108_CPUCLK_RATE(408000000, 1), + RV1108_CPUCLK_RATE(312000000, 1), + RV1108_CPUCLK_RATE(216000000, 1), + RV1108_CPUCLK_RATE(96000000, 1), }; static const struct rockchip_cpuclk_reg_data rv1108_cpuclk_data = { @@ -105,7 +120,7 @@ static const struct rockchip_cpuclk_reg_data rv1108_cpuclk_data = { .mux_core_alt = 1, .mux_core_main = 0, .mux_core_shift = 8, - .mux_core_mask = 0x1, + .mux_core_mask = 0x3, }; PNAME(mux_pll_p) = { "xin24m", "xin24m"}; @@ -114,30 +129,42 @@ PNAME(mux_armclk_p) = { "apll_core", "gpll_core", "dpll_core" }; PNAME(mux_usb480m_pre_p) = { "usbphy", "xin24m" }; PNAME(mux_hdmiphy_phy_p) = { "hdmiphy", "xin24m" }; PNAME(mux_dclk_hdmiphy_pre_p) = { "dclk_hdmiphy_src_gpll", "dclk_hdmiphy_src_dpll" }; -PNAME(mux_pll_src_4plls_p) = { "dpll", "hdmiphy", "gpll", "usb480m" }; +PNAME(mux_pll_src_4plls_p) = { "dpll", "gpll", "hdmiphy", "usb480m" }; PNAME(mux_pll_src_3plls_p) = { "apll", "gpll", "dpll" }; PNAME(mux_pll_src_2plls_p) = { "dpll", "gpll" }; PNAME(mux_pll_src_apll_gpll_p) = { "apll", "gpll" }; -PNAME(mux_aclk_peri_src_p) = { "aclk_peri_src_dpll", "aclk_peri_src_gpll" }; +PNAME(mux_aclk_peri_src_p) = { "aclk_peri_src_gpll", "aclk_peri_src_dpll" }; PNAME(mux_aclk_bus_src_p) = { "aclk_bus_src_gpll", "aclk_bus_src_apll", "aclk_bus_src_dpll" }; PNAME(mux_mmc_src_p) = { "dpll", "gpll", "xin24m", "usb480m" }; PNAME(mux_pll_src_dpll_gpll_usb480m_p) = { "dpll", "gpll", "usb480m" }; PNAME(mux_uart0_p) = { "uart0_src", "uart0_frac", "xin24m" }; PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" }; PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" }; -PNAME(mux_sclk_macphy_p) = { "sclk_macphy_pre", "ext_gmac" }; +PNAME(mux_sclk_mac_p) = { "sclk_mac_pre", "ext_gmac" }; PNAME(mux_i2s0_pre_p) = { "i2s0_src", "i2s0_frac", "ext_i2s", "xin12m" }; PNAME(mux_i2s_out_p) = { "i2s0_pre", "xin12m" }; -PNAME(mux_i2s1_p) = { "i2s1_src", "i2s1_frac", "xin12m" }; -PNAME(mux_i2s2_p) = { "i2s2_src", "i2s2_frac", "xin12m" }; +PNAME(mux_i2s1_p) = { "i2s1_src", "i2s1_frac", "dummy", "xin12m" }; +PNAME(mux_i2s2_p) = { "i2s2_src", "i2s2_frac", "dummy", "xin12m" }; +PNAME(mux_wifi_src_p) = { "gpll", "xin24m" }; +PNAME(mux_cifout_src_p) = { "hdmiphy", "gpll" }; +PNAME(mux_cifout_p) = { "sclk_cifout_src", "xin24m" }; +PNAME(mux_sclk_cif0_src_p) = { "pclk_vip", "clk_cif0_chn_out", "pclkin_cvbs2cif" }; +PNAME(mux_sclk_cif1_src_p) = { "pclk_vip", "clk_cif1_chn_out", "pclkin_cvbs2cif" }; +PNAME(mux_sclk_cif2_src_p) = { "pclk_vip", "clk_cif2_chn_out", "pclkin_cvbs2cif" }; +PNAME(mux_sclk_cif3_src_p) = { "pclk_vip", "clk_cif3_chn_out", "pclkin_cvbs2cif" }; +PNAME(mux_dsp_src_p) = { "dpll", "gpll", "apll", "usb480m" }; +PNAME(mux_dclk_hdmiphy_p) = { "hdmiphy", "xin24m" }; +PNAME(mux_dclk_vop_p) = { "dclk_hdmiphy", "dclk_vop_src" }; +PNAME(mux_hdmi_cec_src_p) = { "dpll", "gpll", "xin24m" }; +PNAME(mux_cvbs_src_p) = { "apll", "io_cvbs_clkin", "hdmiphy", "gpll" }; static struct rockchip_pll_clock rv1108_pll_clks[] __initdata = { [apll] = PLL(pll_rk3399, PLL_APLL, "apll", mux_pll_p, 0, RV1108_PLL_CON(0), - RV1108_PLL_CON(3), 8, 31, 0, rv1108_pll_rates), + RV1108_PLL_CON(3), 8, 0, 0, rv1108_pll_rates), [dpll] = PLL(pll_rk3399, PLL_DPLL, "dpll", mux_pll_p, 0, RV1108_PLL_CON(8), - RV1108_PLL_CON(11), 8, 31, 0, NULL), + RV1108_PLL_CON(11), 8, 1, 0, NULL), [gpll] = PLL(pll_rk3399, PLL_GPLL, "gpll", mux_pll_p, 0, RV1108_PLL_CON(16), - RV1108_PLL_CON(19), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rv1108_pll_rates), + RV1108_PLL_CON(19), 8, 2, 0, rv1108_pll_rates), }; #define MFLAGS CLK_MUX_HIWORD_MASK @@ -170,10 +197,10 @@ static struct rockchip_clk_branch rv1108_i2s2_fracmux __initdata = RV1108_CLKSEL_CON(7), 12, 2, MFLAGS); static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = { - MUX(0, "hdmi_phy", mux_hdmiphy_phy_p, CLK_SET_RATE_PARENT, - RV1108_MISC_CON, 13, 2, MFLAGS), + MUX(0, "hdmiphy", mux_hdmiphy_phy_p, CLK_SET_RATE_PARENT, + RV1108_MISC_CON, 13, 1, MFLAGS), MUX(0, "usb480m", mux_usb480m_pre_p, CLK_SET_RATE_PARENT, - RV1108_MISC_CON, 15, 2, MFLAGS), + RV1108_MISC_CON, 15, 1, MFLAGS), /* * Clock-Architecture Diagram 2 */ @@ -197,50 +224,212 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = { RV1108_CLKGATE_CON(11), 1, GFLAGS), /* PD_RKVENC */ + COMPOSITE(0, "aclk_rkvenc_pre", mux_pll_src_4plls_p, 0, + RV1108_CLKSEL_CON(37), 6, 2, MFLAGS, 0, 5, DFLAGS, + RV1108_CLKGATE_CON(8), 8, GFLAGS), + FACTOR_GATE(0, "hclk_rkvenc_pre", "aclk_rkvenc_pre", 0, 1, 4, + RV1108_CLKGATE_CON(8), 10, GFLAGS), + COMPOSITE(SCLK_VENC_CORE, "clk_venc_core", mux_pll_src_4plls_p, 0, + RV1108_CLKSEL_CON(37), 14, 2, MFLAGS, 8, 5, DFLAGS, + RV1108_CLKGATE_CON(8), 9, GFLAGS), + GATE(ACLK_RKVENC, "aclk_rkvenc", "aclk_rkvenc_pre", 0, + RV1108_CLKGATE_CON(19), 8, GFLAGS), + GATE(HCLK_RKVENC, "hclk_rkvenc", "hclk_rkvenc_pre", 0, + RV1108_CLKGATE_CON(19), 9, GFLAGS), + GATE(0, "aclk_rkvenc_niu", "aclk_rkvenc_pre", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(19), 11, GFLAGS), + GATE(0, "hclk_rkvenc_niu", "hclk_rkvenc_pre", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(19), 10, GFLAGS), /* PD_RKVDEC */ + COMPOSITE(SCLK_HEVC_CORE, "sclk_hevc_core", mux_pll_src_4plls_p, 0, + RV1108_CLKSEL_CON(36), 6, 2, MFLAGS, 0, 5, DFLAGS, + RV1108_CLKGATE_CON(8), 2, GFLAGS), + FACTOR_GATE(0, "hclk_rkvdec_pre", "sclk_hevc_core", 0, 1, 4, + RV1108_CLKGATE_CON(8), 10, GFLAGS), + COMPOSITE(SCLK_HEVC_CABAC, "clk_hevc_cabac", mux_pll_src_4plls_p, 0, + RV1108_CLKSEL_CON(35), 14, 2, MFLAGS, 8, 5, DFLAGS, + RV1108_CLKGATE_CON(8), 1, GFLAGS), + + COMPOSITE(0, "aclk_rkvdec_pre", mux_pll_src_4plls_p, 0, + RV1108_CLKSEL_CON(35), 6, 2, MFLAGS, 0, 5, DFLAGS, + RV1108_CLKGATE_CON(8), 0, GFLAGS), + COMPOSITE(0, "aclk_vpu_pre", mux_pll_src_4plls_p, 0, + RV1108_CLKSEL_CON(36), 14, 2, MFLAGS, 8, 5, DFLAGS, + RV1108_CLKGATE_CON(8), 3, GFLAGS), + GATE(ACLK_RKVDEC, "aclk_rkvdec", "aclk_rkvdec_pre", 0, + RV1108_CLKGATE_CON(19), 0, GFLAGS), + GATE(ACLK_VPU, "aclk_vpu", "aclk_vpu_pre", 0, + RV1108_CLKGATE_CON(19), 1, GFLAGS), + GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", 0, + RV1108_CLKGATE_CON(19), 2, GFLAGS), + GATE(HCLK_VPU, "hclk_vpu", "hclk_rkvdec_pre", 0, + RV1108_CLKGATE_CON(19), 3, GFLAGS), + GATE(0, "aclk_rkvdec_niu", "aclk_rkvdec_pre", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(19), 4, GFLAGS), + GATE(0, "hclk_rkvdec_niu", "hclk_rkvdec_pre", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(19), 5, GFLAGS), + GATE(0, "aclk_vpu_niu", "aclk_vpu_pre", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(19), 6, GFLAGS), /* PD_PMU_wrapper */ COMPOSITE_NOMUX(0, "pmu_24m_ena", "gpll", CLK_IGNORE_UNUSED, RV1108_CLKSEL_CON(38), 0, 5, DFLAGS, RV1108_CLKGATE_CON(8), 12, GFLAGS), - GATE(0, "pmu", "pmu_24m_ena", CLK_IGNORE_UNUSED, + GATE(0, "pclk_pmu", "pmu_24m_ena", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(10), 0, GFLAGS), - GATE(0, "intmem1", "pmu_24m_ena", CLK_IGNORE_UNUSED, + GATE(0, "pclk_intmem1", "pmu_24m_ena", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(10), 1, GFLAGS), - GATE(0, "gpio0_pmu", "pmu_24m_ena", CLK_IGNORE_UNUSED, + GATE(PCLK_GPIO0_PMU, "pclk_gpio0_pmu", "pmu_24m_ena", 0, RV1108_CLKGATE_CON(10), 2, GFLAGS), - GATE(0, "pmugrf", "pmu_24m_ena", CLK_IGNORE_UNUSED, + GATE(0, "pclk_pmugrf", "pmu_24m_ena", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(10), 3, GFLAGS), - GATE(0, "pmu_noc", "pmu_24m_ena", CLK_IGNORE_UNUSED, + GATE(0, "pclk_pmu_niu", "pmu_24m_ena", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(10), 4, GFLAGS), - GATE(0, "i2c0_pmu_pclk", "pmu_24m_ena", CLK_IGNORE_UNUSED, + GATE(PCLK_I2C0_PMU, "pclk_i2c0_pmu", "pmu_24m_ena", 0, RV1108_CLKGATE_CON(10), 5, GFLAGS), - GATE(0, "pwm0_pmu_pclk", "pmu_24m_ena", CLK_IGNORE_UNUSED, + GATE(PCLK_PWM0_PMU, "pclk_pwm0_pmu", "pmu_24m_ena", 0, RV1108_CLKGATE_CON(10), 6, GFLAGS), - COMPOSITE(0, "pwm0_pmu_clk", mux_pll_src_2plls_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_PWM0_PMU, "sclk_pwm0_pmu", mux_pll_src_2plls_p, 0, RV1108_CLKSEL_CON(12), 7, 1, MFLAGS, 0, 7, DFLAGS, RV1108_CLKGATE_CON(8), 15, GFLAGS), - COMPOSITE(0, "i2c0_pmu_clk", mux_pll_src_2plls_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_I2C0_PMU, "sclk_i2c0_pmu", mux_pll_src_2plls_p, 0, RV1108_CLKSEL_CON(19), 7, 1, MFLAGS, 0, 7, DFLAGS, RV1108_CLKGATE_CON(8), 14, GFLAGS), GATE(0, "pvtm_pmu", "xin24m", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(8), 13, GFLAGS), /* + * Clock-Architecture Diagram 3 + */ + COMPOSITE(SCLK_WIFI, "sclk_wifi", mux_wifi_src_p, 0, + RV1108_CLKSEL_CON(28), 15, 1, MFLAGS, 8, 6, DFLAGS, + RV1108_CLKGATE_CON(9), 8, GFLAGS), + COMPOSITE_NODIV(0, "sclk_cifout_src", mux_cifout_src_p, 0, + RV1108_CLKSEL_CON(40), 8, 1, MFLAGS, + RV1108_CLKGATE_CON(9), 11, GFLAGS), + COMPOSITE_NOGATE(SCLK_CIFOUT, "sclk_cifout", mux_cifout_p, 0, + RV1108_CLKSEL_CON(40), 12, 1, MFLAGS, 0, 5, DFLAGS), + COMPOSITE_NOMUX(SCLK_MIPI_CSI_OUT, "sclk_mipi_csi_out", "xin24m", 0, + RV1108_CLKSEL_CON(41), 0, 5, DFLAGS, + RV1108_CLKGATE_CON(9), 12, GFLAGS), + + GATE(0, "pclk_acodecphy", "pclk_top_pre", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(14), 6, GFLAGS), + GATE(0, "pclk_usbgrf", "pclk_top_pre", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(14), 14, GFLAGS), + + GATE(ACLK_CIF0, "aclk_cif0", "aclk_vio1_pre", 0, + RV1108_CLKGATE_CON(18), 10, GFLAGS), + GATE(HCLK_CIF0, "hclk_cif0", "hclk_vio_pre", 0, + RV1108_CLKGATE_CON(18), 10, GFLAGS), + COMPOSITE_NODIV(SCLK_CIF0, "sclk_cif0", mux_sclk_cif0_src_p, 0, + RV1108_CLKSEL_CON(31), 0, 2, MFLAGS, + RV1108_CLKGATE_CON(7), 9, GFLAGS), + GATE(ACLK_CIF1, "aclk_cif1", "aclk_vio1_pre", 0, + RV1108_CLKGATE_CON(17), 6, GFLAGS), + GATE(HCLK_CIF1, "hclk_cif1", "hclk_vio_pre", 0, + RV1108_CLKGATE_CON(17), 7, GFLAGS), + COMPOSITE_NODIV(SCLK_CIF1, "sclk_cif1", mux_sclk_cif1_src_p, 0, + RV1108_CLKSEL_CON(31), 2, 2, MFLAGS, + RV1108_CLKGATE_CON(7), 10, GFLAGS), + GATE(ACLK_CIF2, "aclk_cif2", "aclk_vio1_pre", 0, + RV1108_CLKGATE_CON(17), 8, GFLAGS), + GATE(HCLK_CIF2, "hclk_cif2", "hclk_vio_pre", 0, + RV1108_CLKGATE_CON(17), 9, GFLAGS), + COMPOSITE_NODIV(SCLK_CIF2, "sclk_cif2", mux_sclk_cif2_src_p, 0, + RV1108_CLKSEL_CON(31), 4, 2, MFLAGS, + RV1108_CLKGATE_CON(7), 11, GFLAGS), + GATE(ACLK_CIF3, "aclk_cif3", "aclk_vio1_pre", 0, + RV1108_CLKGATE_CON(17), 10, GFLAGS), + GATE(HCLK_CIF3, "hclk_cif3", "hclk_vio_pre", 0, + RV1108_CLKGATE_CON(17), 11, GFLAGS), + COMPOSITE_NODIV(SCLK_CIF3, "sclk_cif3", mux_sclk_cif3_src_p, 0, + RV1108_CLKSEL_CON(31), 6, 2, MFLAGS, + RV1108_CLKGATE_CON(7), 12, GFLAGS), + GATE(0, "pclk_cif1to4", "pclk_vip", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(7), 8, GFLAGS), + + /* PD_DSP_wrapper */ + COMPOSITE(SCLK_DSP, "sclk_dsp", mux_dsp_src_p, 0, + RV1108_CLKSEL_CON(42), 8, 2, MFLAGS, 0, 5, DFLAGS, + RV1108_CLKGATE_CON(9), 0, GFLAGS), + GATE(0, "clk_dsp_sys_wd", "sclk_dsp", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 0, GFLAGS), + GATE(0, "clk_dsp_epp_wd", "sclk_dsp", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 1, GFLAGS), + GATE(0, "clk_dsp_edp_wd", "sclk_dsp", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 2, GFLAGS), + GATE(0, "clk_dsp_iop_wd", "sclk_dsp", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 3, GFLAGS), + GATE(0, "clk_dsp_free", "sclk_dsp", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 13, GFLAGS), + COMPOSITE_NOMUX(SCLK_DSP_IOP, "sclk_dsp_iop", "sclk_dsp", 0, + RV1108_CLKSEL_CON(44), 0, 5, DFLAGS, + RV1108_CLKGATE_CON(9), 1, GFLAGS), + COMPOSITE_NOMUX(SCLK_DSP_EPP, "sclk_dsp_epp", "sclk_dsp", 0, + RV1108_CLKSEL_CON(44), 8, 5, DFLAGS, + RV1108_CLKGATE_CON(9), 2, GFLAGS), + COMPOSITE_NOMUX(SCLK_DSP_EDP, "sclk_dsp_edp", "sclk_dsp", 0, + RV1108_CLKSEL_CON(45), 0, 5, DFLAGS, + RV1108_CLKGATE_CON(9), 3, GFLAGS), + COMPOSITE_NOMUX(SCLK_DSP_EDAP, "sclk_dsp_edap", "sclk_dsp", 0, + RV1108_CLKSEL_CON(45), 8, 5, DFLAGS, + RV1108_CLKGATE_CON(9), 4, GFLAGS), + GATE(0, "pclk_dsp_iop_niu", "sclk_dsp_iop", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 4, GFLAGS), + GATE(0, "aclk_dsp_epp_niu", "sclk_dsp_epp", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 5, GFLAGS), + GATE(0, "aclk_dsp_edp_niu", "sclk_dsp_edp", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 6, GFLAGS), + GATE(0, "pclk_dsp_dbg_niu", "sclk_dsp", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 7, GFLAGS), + GATE(0, "aclk_dsp_edap_niu", "sclk_dsp_edap", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 14, GFLAGS), + COMPOSITE_NOMUX(SCLK_DSP_PFM, "sclk_dsp_pfm", "sclk_dsp", 0, + RV1108_CLKSEL_CON(43), 0, 5, DFLAGS, + RV1108_CLKGATE_CON(9), 5, GFLAGS), + COMPOSITE_NOMUX(PCLK_DSP_CFG, "pclk_dsp_cfg", "sclk_dsp", 0, + RV1108_CLKSEL_CON(43), 8, 5, DFLAGS, + RV1108_CLKGATE_CON(9), 6, GFLAGS), + GATE(0, "pclk_dsp_cfg_niu", "pclk_dsp_cfg", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 8, GFLAGS), + GATE(0, "pclk_dsp_pfm_mon", "pclk_dsp_cfg", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 9, GFLAGS), + GATE(0, "pclk_intc", "pclk_dsp_cfg", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 10, GFLAGS), + GATE(0, "pclk_dsp_grf", "pclk_dsp_cfg", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 11, GFLAGS), + GATE(0, "pclk_mailbox", "pclk_dsp_cfg", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 12, GFLAGS), + GATE(0, "aclk_dsp_epp_perf", "sclk_dsp_epp", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(16), 15, GFLAGS), + GATE(0, "aclk_dsp_edp_perf", "sclk_dsp_edp", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(11), 8, GFLAGS), + + /* * Clock-Architecture Diagram 4 */ - COMPOSITE(0, "aclk_vio0_2wrap_occ", mux_pll_src_4plls_p, CLK_IGNORE_UNUSED, + COMPOSITE(0, "aclk_vio0_pre", mux_pll_src_4plls_p, CLK_IGNORE_UNUSED, RV1108_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 5, DFLAGS, RV1108_CLKGATE_CON(6), 0, GFLAGS), - GATE(0, "aclk_vio0_pre", "aclk_vio0_2wrap_occ", CLK_IGNORE_UNUSED, + GATE(ACLK_VIO0, "aclk_vio0", "aclk_vio0_pre", 0, RV1108_CLKGATE_CON(17), 0, GFLAGS), COMPOSITE_NOMUX(0, "hclk_vio_pre", "aclk_vio0_pre", 0, RV1108_CLKSEL_CON(29), 0, 5, DFLAGS, RV1108_CLKGATE_CON(7), 2, GFLAGS), + GATE(HCLK_VIO, "hclk_vio", "hclk_vio_pre", 0, + RV1108_CLKGATE_CON(17), 2, GFLAGS), COMPOSITE_NOMUX(0, "pclk_vio_pre", "aclk_vio0_pre", 0, RV1108_CLKSEL_CON(29), 8, 5, DFLAGS, RV1108_CLKGATE_CON(7), 3, GFLAGS), + GATE(PCLK_VIO, "pclk_vio", "pclk_vio_pre", 0, + RV1108_CLKGATE_CON(17), 3, GFLAGS), + COMPOSITE(0, "aclk_vio1_pre", mux_pll_src_4plls_p, CLK_IGNORE_UNUSED, + RV1108_CLKSEL_CON(28), 14, 2, MFLAGS, 8, 5, DFLAGS, + RV1108_CLKGATE_CON(6), 1, GFLAGS), + GATE(ACLK_VIO1, "aclk_vio1", "aclk_vio1_pre", 0, + RV1108_CLKGATE_CON(17), 1, GFLAGS), INVERTER(0, "pclk_vip", "ext_vip", RV1108_CLKSEL_CON(31), 8, IFLAGS), @@ -252,8 +441,63 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = { RV1108_CLKGATE_CON(6), 5, GFLAGS), GATE(0, "dclk_hdmiphy_src_dpll", "dpll", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(6), 4, GFLAGS), - COMPOSITE_NOGATE(0, "dclk_hdmiphy", mux_dclk_hdmiphy_pre_p, 0, - RV1108_CLKSEL_CON(32), 6, 2, MFLAGS, 8, 6, DFLAGS), + COMPOSITE_NOGATE(0, "dclk_hdmiphy_pre", mux_dclk_hdmiphy_pre_p, 0, + RV1108_CLKSEL_CON(32), 6, 1, MFLAGS, 8, 6, DFLAGS), + COMPOSITE_NOGATE(DCLK_VOP_SRC, "dclk_vop_src", mux_dclk_hdmiphy_pre_p, 0, + RV1108_CLKSEL_CON(32), 6, 1, MFLAGS, 0, 6, DFLAGS), + MUX(DCLK_HDMIPHY, "dclk_hdmiphy", mux_dclk_hdmiphy_p, CLK_SET_RATE_PARENT, + RV1108_CLKSEL_CON(32), 15, 1, MFLAGS), + MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, CLK_SET_RATE_PARENT, + RV1108_CLKSEL_CON(32), 7, 1, MFLAGS), + GATE(ACLK_VOP, "aclk_vop", "aclk_vio0_pre", 0, + RV1108_CLKGATE_CON(18), 0, GFLAGS), + GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0, + RV1108_CLKGATE_CON(18), 1, GFLAGS), + GATE(ACLK_IEP, "aclk_iep", "aclk_vio0_pre", 0, + RV1108_CLKGATE_CON(18), 2, GFLAGS), + GATE(HCLK_IEP, "hclk_iep", "hclk_vio_pre", 0, + RV1108_CLKGATE_CON(18), 3, GFLAGS), + + GATE(ACLK_RGA, "aclk_rga", "aclk_vio1_pre", 0, + RV1108_CLKGATE_CON(18), 4, GFLAGS), + GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0, + RV1108_CLKGATE_CON(18), 5, GFLAGS), + COMPOSITE(SCLK_RGA, "sclk_rga", mux_pll_src_4plls_p, 0, + RV1108_CLKSEL_CON(33), 6, 2, MFLAGS, 0, 5, DFLAGS, + RV1108_CLKGATE_CON(6), 6, GFLAGS), + + COMPOSITE(SCLK_CVBS_HOST, "sclk_cvbs_host", mux_cvbs_src_p, 0, + RV1108_CLKSEL_CON(33), 13, 2, MFLAGS, 8, 5, DFLAGS, + RV1108_CLKGATE_CON(6), 7, GFLAGS), + FACTOR(0, "sclk_cvbs_27m", "sclk_cvbs_host", 0, 1, 2), + + GATE(SCLK_HDMI_SFR, "sclk_hdmi_sfr", "xin24m", 0, + RV1108_CLKGATE_CON(6), 8, GFLAGS), + + COMPOSITE(SCLK_HDMI_CEC, "sclk_hdmi_cec", mux_hdmi_cec_src_p, 0, + RV1108_CLKSEL_CON(34), 14, 2, MFLAGS, 0, 14, DFLAGS, + RV1108_CLKGATE_CON(6), 9, GFLAGS), + GATE(PCLK_MIPI_DSI, "pclk_mipi_dsi", "pclk_vio_pre", 0, + RV1108_CLKGATE_CON(18), 8, GFLAGS), + GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "pclk_vio_pre", 0, + RV1108_CLKGATE_CON(18), 9, GFLAGS), + + GATE(ACLK_ISP, "aclk_isp", "aclk_vio1_pre", 0, + RV1108_CLKGATE_CON(18), 12, GFLAGS), + GATE(HCLK_ISP, "hclk_isp", "hclk_vio_pre", 0, + RV1108_CLKGATE_CON(18), 11, GFLAGS), + COMPOSITE(SCLK_ISP, "sclk_isp", mux_pll_src_4plls_p, 0, + RV1108_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS, + RV1108_CLKGATE_CON(6), 3, GFLAGS), + + GATE(0, "clk_dsiphy24m", "xin24m", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(9), 10, GFLAGS), + GATE(0, "pclk_vdacphy", "pclk_top_pre", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(14), 9, GFLAGS), + GATE(0, "pclk_mipi_dsiphy", "pclk_top_pre", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(14), 11, GFLAGS), + GATE(0, "pclk_mipi_csiphy", "pclk_top_pre", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(14), 12, GFLAGS), /* * Clock-Architecture Diagram 5 @@ -261,10 +505,11 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = { FACTOR(0, "xin12m", "xin24m", 0, 1, 2), - COMPOSITE(0, "i2s0_src", mux_pll_src_2plls_p, 0, + + COMPOSITE(SCLK_I2S0_SRC, "i2s0_src", mux_pll_src_2plls_p, 0, RV1108_CLKSEL_CON(5), 8, 1, MFLAGS, 0, 7, DFLAGS, RV1108_CLKGATE_CON(2), 0, GFLAGS), - COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_src", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_src", CLK_SET_RATE_PARENT, RV1108_CLKSEL_CON(8), 0, RV1108_CLKGATE_CON(2), 1, GFLAGS, &rv1108_i2s0_fracmux), @@ -274,7 +519,7 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = { RV1108_CLKSEL_CON(5), 15, 1, MFLAGS, RV1108_CLKGATE_CON(2), 3, GFLAGS), - COMPOSITE(0, "i2s1_src", mux_pll_src_2plls_p, 0, + COMPOSITE(SCLK_I2S1_SRC, "i2s1_src", mux_pll_src_2plls_p, 0, RV1108_CLKSEL_CON(6), 8, 1, MFLAGS, 0, 7, DFLAGS, RV1108_CLKGATE_CON(2), 4, GFLAGS), COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_src", CLK_SET_RATE_PARENT, @@ -284,7 +529,7 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = { GATE(SCLK_I2S1, "sclk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT, RV1108_CLKGATE_CON(2), 6, GFLAGS), - COMPOSITE(0, "i2s2_src", mux_pll_src_2plls_p, 0, + COMPOSITE(SCLK_I2S2_SRC, "i2s2_src", mux_pll_src_2plls_p, 0, RV1108_CLKSEL_CON(7), 8, 1, MFLAGS, 0, 7, DFLAGS, RV1108_CLKGATE_CON(3), 8, GFLAGS), COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_src", CLK_SET_RATE_PARENT, @@ -303,32 +548,53 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = { RV1108_CLKGATE_CON(1), 2, GFLAGS), COMPOSITE_NOGATE(ACLK_PRE, "aclk_bus_pre", mux_aclk_bus_src_p, 0, RV1108_CLKSEL_CON(2), 8, 2, MFLAGS, 0, 5, DFLAGS), - COMPOSITE_NOMUX(0, "hclk_bus_pre", "aclk_bus_2wrap_occ", 0, + COMPOSITE_NOMUX(HCLK_BUS, "hclk_bus_pre", "aclk_bus_pre", 0, RV1108_CLKSEL_CON(3), 0, 5, DFLAGS, RV1108_CLKGATE_CON(1), 4, GFLAGS), - COMPOSITE_NOMUX(0, "pclken_bus", "aclk_bus_2wrap_occ", 0, + COMPOSITE_NOMUX(0, "pclk_bus_pre", "aclk_bus_pre", 0, RV1108_CLKSEL_CON(3), 8, 5, DFLAGS, RV1108_CLKGATE_CON(1), 5, GFLAGS), - GATE(0, "pclk_bus_pre", "pclken_bus", CLK_IGNORE_UNUSED, + GATE(PCLK_BUS, "pclk_bus", "pclk_bus_pre", 0, RV1108_CLKGATE_CON(1), 6, GFLAGS), - GATE(0, "pclk_top_pre", "pclken_bus", CLK_IGNORE_UNUSED, + GATE(0, "pclk_top_pre", "pclk_bus_pre", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(1), 7, GFLAGS), - GATE(0, "pclk_ddr_pre", "pclken_bus", CLK_IGNORE_UNUSED, + GATE(0, "pclk_ddr_pre", "pclk_bus_pre", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(1), 8, GFLAGS), - GATE(0, "clk_timer0", "mux_pll_p", CLK_IGNORE_UNUSED, + GATE(SCLK_TIMER0, "clk_timer0", "xin24m", 0, RV1108_CLKGATE_CON(1), 9, GFLAGS), - GATE(0, "clk_timer1", "mux_pll_p", CLK_IGNORE_UNUSED, + GATE(SCLK_TIMER1, "clk_timer1", "xin24m", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(1), 10, GFLAGS), - GATE(0, "pclk_timer", "pclk_bus_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_TIMER, "pclk_timer", "pclk_bus_pre", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(13), 4, GFLAGS), - COMPOSITE(0, "uart0_src", mux_pll_src_dpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, + GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_bus_pre", 0, + RV1108_CLKGATE_CON(12), 7, GFLAGS), + GATE(HCLK_I2S1_2CH, "hclk_i2s1_2ch", "hclk_bus_pre", 0, + RV1108_CLKGATE_CON(12), 8, GFLAGS), + GATE(HCLK_I2S2_2CH, "hclk_i2s2_2ch", "hclk_bus_pre", 0, + RV1108_CLKGATE_CON(12), 9, GFLAGS), + + GATE(HCLK_CRYPTO_MST, "hclk_crypto_mst", "hclk_bus_pre", 0, + RV1108_CLKGATE_CON(12), 10, GFLAGS), + GATE(HCLK_CRYPTO_SLV, "hclk_crypto_slv", "hclk_bus_pre", 0, + RV1108_CLKGATE_CON(12), 11, GFLAGS), + COMPOSITE(SCLK_CRYPTO, "sclk_crypto", mux_pll_src_2plls_p, 0, + RV1108_CLKSEL_CON(11), 7, 1, MFLAGS, 0, 5, DFLAGS, + RV1108_CLKGATE_CON(2), 12, GFLAGS), + + COMPOSITE(SCLK_SPI, "sclk_spi", mux_pll_src_2plls_p, 0, + RV1108_CLKSEL_CON(11), 15, 1, MFLAGS, 8, 5, DFLAGS, + RV1108_CLKGATE_CON(3), 0, GFLAGS), + GATE(PCLK_SPI, "pclk_spi", "pclk_bus_pre", 0, + RV1108_CLKGATE_CON(13), 5, GFLAGS), + + COMPOSITE(SCLK_UART0_SRC, "uart0_src", mux_pll_src_dpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, RV1108_CLKSEL_CON(13), 12, 2, MFLAGS, 0, 7, DFLAGS, RV1108_CLKGATE_CON(3), 1, GFLAGS), - COMPOSITE(0, "uart1_src", mux_pll_src_dpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_UART1_SRC, "uart1_src", mux_pll_src_dpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, RV1108_CLKSEL_CON(14), 12, 2, MFLAGS, 0, 7, DFLAGS, RV1108_CLKGATE_CON(3), 3, GFLAGS), - COMPOSITE(0, "uart21_src", mux_pll_src_dpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_UART2_SRC, "uart2_src", mux_pll_src_dpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, RV1108_CLKSEL_CON(15), 12, 2, MFLAGS, 0, 7, DFLAGS, RV1108_CLKGATE_CON(3), 5, GFLAGS), @@ -344,44 +610,58 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = { RV1108_CLKSEL_CON(18), 0, RV1108_CLKGATE_CON(3), 6, GFLAGS, &rv1108_uart2_fracmux), - GATE(PCLK_UART0, "pclk_uart0", "pclk_bus_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_UART0, "pclk_uart0", "pclk_bus_pre", 0, RV1108_CLKGATE_CON(13), 10, GFLAGS), - GATE(PCLK_UART1, "pclk_uart1", "pclk_bus_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_UART1, "pclk_uart1", "pclk_bus_pre", 0, RV1108_CLKGATE_CON(13), 11, GFLAGS), - GATE(PCLK_UART2, "pclk_uart2", "pclk_bus_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_UART2, "pclk_uart2", "pclk_bus_pre", 0, RV1108_CLKGATE_CON(13), 12, GFLAGS), - COMPOSITE(0, "clk_i2c1", mux_pll_src_2plls_p, CLK_IGNORE_UNUSED, - RV1108_CLKSEL_CON(19), 15, 2, MFLAGS, 8, 7, DFLAGS, + COMPOSITE(SCLK_I2C1, "clk_i2c1", mux_pll_src_2plls_p, 0, + RV1108_CLKSEL_CON(19), 15, 1, MFLAGS, 8, 7, DFLAGS, RV1108_CLKGATE_CON(3), 7, GFLAGS), - COMPOSITE(0, "clk_i2c2", mux_pll_src_2plls_p, CLK_IGNORE_UNUSED, - RV1108_CLKSEL_CON(20), 7, 2, MFLAGS, 0, 7, DFLAGS, + COMPOSITE(SCLK_I2C2, "clk_i2c2", mux_pll_src_2plls_p, 0, + RV1108_CLKSEL_CON(20), 7, 1, MFLAGS, 0, 7, DFLAGS, RV1108_CLKGATE_CON(3), 8, GFLAGS), - COMPOSITE(0, "clk_i2c3", mux_pll_src_2plls_p, CLK_IGNORE_UNUSED, - RV1108_CLKSEL_CON(20), 15, 2, MFLAGS, 8, 7, DFLAGS, + COMPOSITE(SCLK_I2C3, "clk_i2c3", mux_pll_src_2plls_p, 0, + RV1108_CLKSEL_CON(20), 15, 1, MFLAGS, 8, 7, DFLAGS, RV1108_CLKGATE_CON(3), 9, GFLAGS), - GATE(0, "pclk_i2c1", "pclk_bus_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus_pre", 0, RV1108_CLKGATE_CON(13), 0, GFLAGS), - GATE(0, "pclk_i2c2", "pclk_bus_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_I2C2, "pclk_i2c2", "pclk_bus_pre", 0, RV1108_CLKGATE_CON(13), 1, GFLAGS), - GATE(0, "pclk_i2c3", "pclk_bus_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_I2C3, "pclk_i2c3", "pclk_bus_pre", 0, RV1108_CLKGATE_CON(13), 2, GFLAGS), - COMPOSITE(0, "clk_pwm1", mux_pll_src_2plls_p, CLK_IGNORE_UNUSED, + COMPOSITE(SCLK_PWM, "clk_pwm", mux_pll_src_2plls_p, 0, RV1108_CLKSEL_CON(12), 15, 2, MFLAGS, 8, 7, DFLAGS, RV1108_CLKGATE_CON(3), 10, GFLAGS), - GATE(0, "pclk_pwm1", "pclk_bus_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_PWM, "pclk_pwm", "pclk_bus_pre", 0, RV1108_CLKGATE_CON(13), 6, GFLAGS), - GATE(0, "pclk_wdt", "pclk_bus_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_WDT, "pclk_wdt", "pclk_bus_pre", 0, RV1108_CLKGATE_CON(13), 3, GFLAGS), - GATE(0, "pclk_gpio1", "pclk_bus_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_bus_pre", 0, RV1108_CLKGATE_CON(13), 7, GFLAGS), - GATE(0, "pclk_gpio2", "pclk_bus_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_bus_pre", 0, RV1108_CLKGATE_CON(13), 8, GFLAGS), - GATE(0, "pclk_gpio3", "pclk_bus_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_bus_pre", 0, RV1108_CLKGATE_CON(13), 9, GFLAGS), GATE(0, "pclk_grf", "pclk_bus_pre", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(14), 0, GFLAGS), + GATE(PCLK_EFUSE0, "pclk_efuse0", "pclk_bus_pre", 0, + RV1108_CLKGATE_CON(12), 12, GFLAGS), + GATE(PCLK_EFUSE1, "pclk_efuse1", "pclk_bus_pre", 0, + RV1108_CLKGATE_CON(12), 13, GFLAGS), + GATE(PCLK_TSADC, "pclk_tsadc", "pclk_bus_pre", 0, + RV1108_CLKGATE_CON(13), 13, GFLAGS), + COMPOSITE_NOMUX(SCLK_TSADC, "sclk_tsadc", "xin24m", 0, + RV1108_CLKSEL_CON(21), 0, 10, DFLAGS, + RV1108_CLKGATE_CON(3), 11, GFLAGS), + GATE(PCLK_SARADC, "pclk_saradc", "pclk_bus_pre", 0, + RV1108_CLKGATE_CON(13), 14, GFLAGS), + COMPOSITE_NOMUX(SCLK_SARADC, "sclk_saradc", "xin24m", 0, + RV1108_CLKSEL_CON(22), 0, 10, DFLAGS, + RV1108_CLKGATE_CON(3), 12, GFLAGS), GATE(ACLK_DMAC, "aclk_dmac", "aclk_bus_pre", 0, RV1108_CLKGATE_CON(12), 2, GFLAGS), @@ -397,18 +677,24 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = { RV1108_CLKGATE_CON(0), 9, GFLAGS), GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(0), 10, GFLAGS), - COMPOSITE(0, "ddrphy4x", mux_ddrphy_p, CLK_IGNORE_UNUSED, + COMPOSITE_NOGATE(0, "clk_ddrphy_src", mux_ddrphy_p, CLK_IGNORE_UNUSED, RV1108_CLKSEL_CON(4), 8, 2, MFLAGS, 0, 3, - DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + DFLAGS | CLK_DIVIDER_POWER_OF_TWO), + FACTOR(0, "clk_ddr", "clk_ddrphy_src", 0, 1, 2), + GATE(0, "clk_ddrphy4x", "clk_ddr", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(10), 9, GFLAGS), - GATE(0, "ddrupctl", "ddrphy_pre", CLK_IGNORE_UNUSED, + GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(12), 4, GFLAGS), - GATE(0, "ddrc", "ddrphy", CLK_IGNORE_UNUSED, + GATE(0, "nclk_ddrupctl", "clk_ddr", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(12), 5, GFLAGS), - GATE(0, "ddrmon", "ddrphy_pre", CLK_IGNORE_UNUSED, + GATE(0, "pclk_ddrmon", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(12), 6, GFLAGS), GATE(0, "timer_clk", "xin24m", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(0), 11, GFLAGS), + GATE(0, "pclk_mschniu", "pclk_ddr_pre", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(14), 2, GFLAGS), + GATE(0, "pclk_ddrphy", "pclk_ddr_pre", CLK_IGNORE_UNUSED, + RV1108_CLKGATE_CON(14), 4, GFLAGS), /* * Clock-Architecture Diagram 6 @@ -418,23 +704,23 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "pclk_periph_pre", "gpll", 0, RV1108_CLKSEL_CON(23), 10, 5, DFLAGS, RV1108_CLKGATE_CON(4), 5, GFLAGS), - GATE(0, "pclk_periph", "pclk_periph_pre", CLK_IGNORE_UNUSED, + GATE(PCLK_PERI, "pclk_periph", "pclk_periph_pre", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(15), 13, GFLAGS), COMPOSITE_NOMUX(0, "hclk_periph_pre", "gpll", 0, RV1108_CLKSEL_CON(23), 5, 5, DFLAGS, RV1108_CLKGATE_CON(4), 4, GFLAGS), - GATE(0, "hclk_periph", "hclk_periph_pre", CLK_IGNORE_UNUSED, + GATE(HCLK_PERI, "hclk_periph", "hclk_periph_pre", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(15), 12, GFLAGS), GATE(0, "aclk_peri_src_dpll", "dpll", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(4), 1, GFLAGS), GATE(0, "aclk_peri_src_gpll", "gpll", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(4), 2, GFLAGS), - COMPOSITE(0, "aclk_periph", mux_aclk_peri_src_p, CLK_IGNORE_UNUSED, - RV1108_CLKSEL_CON(23), 15, 2, MFLAGS, 0, 5, DFLAGS, + COMPOSITE(ACLK_PERI, "aclk_periph", mux_aclk_peri_src_p, 0, + RV1108_CLKSEL_CON(23), 15, 1, MFLAGS, 0, 5, DFLAGS, RV1108_CLKGATE_CON(15), 11, GFLAGS), - COMPOSITE(SCLK_SDMMC, "sclk_sdmmc0", mux_mmc_src_p, 0, + COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0, RV1108_CLKSEL_CON(25), 8, 2, MFLAGS, 0, 8, DFLAGS, RV1108_CLKGATE_CON(5), 0, GFLAGS), @@ -454,23 +740,31 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = { GATE(HCLK_EMMC, "hclk_emmc", "hclk_periph", 0, RV1108_CLKGATE_CON(15), 2, GFLAGS), COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_2plls_p, 0, - RV1108_CLKSEL_CON(27), 14, 2, MFLAGS, 8, 5, DFLAGS, + RV1108_CLKSEL_CON(27), 14, 1, MFLAGS, 8, 5, DFLAGS, RV1108_CLKGATE_CON(5), 3, GFLAGS), GATE(HCLK_NANDC, "hclk_nandc", "hclk_periph", 0, RV1108_CLKGATE_CON(15), 3, GFLAGS), + GATE(HCLK_HOST0, "hclk_host0", "hclk_periph", 0, RV1108_CLKGATE_CON(15), 6, GFLAGS), + GATE(0, "hclk_host0_arb", "hclk_periph", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(15), 7, GFLAGS), + GATE(HCLK_OTG, "hclk_otg", "hclk_periph", 0, RV1108_CLKGATE_CON(15), 8, GFLAGS), + GATE(0, "hclk_otg_pmu", "hclk_periph", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(15), 9, GFLAGS), + GATE(SCLK_USBPHY, "clk_usbphy", "xin24m", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(5), 5, GFLAGS), + COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_2plls_p, 0, - RV1108_CLKSEL_CON(27), 7, 2, MFLAGS, 0, 7, DFLAGS, + RV1108_CLKSEL_CON(27), 7, 1, MFLAGS, 0, 7, DFLAGS, RV1108_CLKGATE_CON(5), 4, GFLAGS), GATE(HCLK_SFC, "hclk_sfc", "hclk_periph", 0, RV1108_CLKGATE_CON(15), 10, GFLAGS), - COMPOSITE(0, "sclk_macphy_pre", mux_pll_src_apll_gpll_p, 0, - RV1108_CLKSEL_CON(24), 12, 2, MFLAGS, 0, 5, DFLAGS, + COMPOSITE(SCLK_MAC_PRE, "sclk_mac_pre", mux_pll_src_apll_gpll_p, 0, + RV1108_CLKSEL_CON(24), 12, 1, MFLAGS, 0, 5, DFLAGS, RV1108_CLKGATE_CON(4), 10, GFLAGS), - MUX(0, "sclk_macphy", mux_sclk_macphy_p, CLK_SET_RATE_PARENT, - RV1108_CLKSEL_CON(24), 8, 2, MFLAGS), - GATE(0, "sclk_macphy_rx", "sclk_macphy", 0, RV1108_CLKGATE_CON(4), 8, GFLAGS), - GATE(0, "sclk_mac_ref", "sclk_macphy", 0, RV1108_CLKGATE_CON(4), 6, GFLAGS), - GATE(0, "sclk_mac_refout", "sclk_macphy", 0, RV1108_CLKGATE_CON(4), 7, GFLAGS), + MUX(SCLK_MAC, "sclk_mac", mux_sclk_mac_p, CLK_SET_RATE_PARENT, + RV1108_CLKSEL_CON(24), 8, 1, MFLAGS), + GATE(SCLK_MAC_RX, "sclk_mac_rx", "sclk_mac", 0, RV1108_CLKGATE_CON(4), 8, GFLAGS), + GATE(SCLK_MAC_REF, "sclk_mac_ref", "sclk_mac", 0, RV1108_CLKGATE_CON(4), 6, GFLAGS), + GATE(SCLK_MAC_REFOUT, "sclk_mac_refout", "sclk_mac", 0, RV1108_CLKGATE_CON(4), 7, GFLAGS), + GATE(ACLK_GMAC, "aclk_gmac", "aclk_periph", 0, RV1108_CLKGATE_CON(15), 4, GFLAGS), + GATE(PCLK_GMAC, "pclk_gmac", "pclk_periph", 0, RV1108_CLKGATE_CON(15), 5, GFLAGS), MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RV1108_SDMMC_CON0, 1), MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RV1108_SDMMC_CON1, 1), @@ -484,10 +778,16 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = { static const char *const rv1108_critical_clocks[] __initconst = { "aclk_core", - "aclk_bus_src_gpll", + "aclk_bus", + "hclk_bus", + "pclk_bus", "aclk_periph", "hclk_periph", "pclk_periph", + "nclk_ddrupctl", + "pclk_ddrmon", + "pclk_acodecphy", + "pclk_pmu", }; static void __init rv1108_clk_init(struct device_node *np) diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index fe1d393cf678..35dbd63c2f49 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -29,6 +29,7 @@ #include <linux/mfd/syscon.h> #include <linux/regmap.h> #include <linux/reboot.h> +#include <linux/rational.h> #include "clk.h" /** @@ -164,6 +165,40 @@ static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb, return notifier_from_errno(ret); } +/** + * fractional divider must set that denominator is 20 times larger than + * numerator to generate precise clock frequency. + */ +static void rockchip_fractional_approximation(struct clk_hw *hw, + unsigned long rate, unsigned long *parent_rate, + unsigned long *m, unsigned long *n) +{ + struct clk_fractional_divider *fd = to_clk_fd(hw); + unsigned long p_rate, p_parent_rate; + struct clk_hw *p_parent; + unsigned long scale; + + p_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); + if ((rate * 20 > p_rate) && (p_rate % rate != 0)) { + p_parent = clk_hw_get_parent(clk_hw_get_parent(hw)); + p_parent_rate = clk_hw_get_rate(p_parent); + *parent_rate = p_parent_rate; + } + + /* + * Get rate closer to *parent_rate to guarantee there is no overflow + * for m and n. In the result it will be the nearest rate left shifted + * by (scale - fd->nwidth) bits. + */ + scale = fls_long(*parent_rate / rate - 1); + if (scale > fd->nwidth) + rate <<= scale - fd->nwidth; + + rational_best_approximation(rate, *parent_rate, + GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), + m, n); +} + static struct clk *rockchip_clk_register_frac_branch( struct rockchip_clk_provider *ctx, const char *name, const char *const *parent_names, u8 num_parents, @@ -210,6 +245,7 @@ static struct clk *rockchip_clk_register_frac_branch( div->nwidth = 16; div->nmask = GENMASK(div->nwidth - 1, 0) << div->nshift; div->lock = lock; + div->approximation = rockchip_fractional_approximation; div_ops = &clk_fractional_divider_ops; clk = clk_register_composite(NULL, name, parent_names, num_parents, diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 1fab56f396d4..b117783ed404 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -180,7 +180,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) } clk_table[EXYNOS_MOUT_AUDSS] = clk_hw_register_mux(NULL, "mout_audss", mout_audss_p, ARRAY_SIZE(mout_audss_p), - CLK_SET_RATE_NO_REPARENT, + CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg_base + ASS_CLK_SRC, 0, 1, 0, &lock); cdclk = devm_clk_get(&pdev->dev, "cdclk"); @@ -195,11 +195,11 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) reg_base + ASS_CLK_SRC, 2, 2, 0, &lock); clk_table[EXYNOS_DOUT_SRP] = clk_hw_register_divider(NULL, "dout_srp", - "mout_audss", 0, reg_base + ASS_CLK_DIV, 0, 4, - 0, &lock); + "mout_audss", CLK_SET_RATE_PARENT, + reg_base + ASS_CLK_DIV, 0, 4, 0, &lock); clk_table[EXYNOS_DOUT_AUD_BUS] = clk_hw_register_divider(NULL, - "dout_aud_bus", "dout_srp", 0, + "dout_aud_bus", "dout_srp", CLK_SET_RATE_PARENT, reg_base + ASS_CLK_DIV, 4, 4, 0, &lock); clk_table[EXYNOS_DOUT_I2S] = clk_hw_register_divider(NULL, "dout_i2s", diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 0748a0b333c5..25601967d1cd 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -537,8 +537,8 @@ static const struct samsung_mux_clock exynos5800_mux_clks[] __initconst = { MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore", mout_mx_mspll_ccore_p, SRC_TOP7, 16, 2), - MUX(CLK_MOUT_MAU_EPLL, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p, - SRC_TOP7, 20, 2), + MUX_F(CLK_MOUT_MAU_EPLL, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p, + SRC_TOP7, 20, 2, CLK_SET_RATE_PARENT, 0), MUX(0, "sclk_bpll", mout_bpll_p, SRC_TOP7, 24, 1), MUX(0, "mout_epll2", mout_epll2_5800_p, SRC_TOP7, 28, 1), @@ -547,8 +547,8 @@ static const struct samsung_mux_clock exynos5800_mux_clks[] __initconst = { MUX(0, "mout_aclk432_cam", mout_group6_5800_p, SRC_TOP8, 24, 2), MUX(0, "mout_aclk432_scaler", mout_group6_5800_p, SRC_TOP8, 28, 2), - MUX(CLK_MOUT_USER_MAU_EPLL, "mout_user_mau_epll", mout_group16_5800_p, - SRC_TOP9, 8, 1), + MUX_F(CLK_MOUT_USER_MAU_EPLL, "mout_user_mau_epll", mout_group16_5800_p, + SRC_TOP9, 8, 1, CLK_SET_RATE_PARENT, 0), MUX(0, "mout_user_aclk550_cam", mout_group15_5800_p, SRC_TOP9, 16, 1), MUX(0, "mout_user_aclkfl1_550_cam", mout_group13_5800_p, @@ -590,6 +590,8 @@ static const struct samsung_gate_clock exynos5800_gate_clks[] __initconst = { GATE_BUS_TOP, 24, 0, 0), GATE(CLK_ACLK432_SCALER, "aclk432_scaler", "mout_user_aclk432_scaler", GATE_BUS_TOP, 27, CLK_IS_CRITICAL, 0), + GATE(CLK_MAU_EPLL, "mau_epll", "mout_user_mau_epll", + SRC_MASK_TOP7, 20, CLK_SET_RATE_PARENT, 0), }; static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = { @@ -629,6 +631,11 @@ static const struct samsung_div_clock exynos5420_div_clks[] __initconst = { "mout_aclk400_wcore_bpll", DIV_TOP0, 16, 3), }; +static const struct samsung_gate_clock exynos5420_gate_clks[] __initconst = { + GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk", + SRC_MASK_TOP7, 20, CLK_SET_RATE_PARENT, 0), +}; + static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = { MUX(0, "mout_user_pclk66_gpio", mout_user_pclk66_gpio_p, SRC_TOP7, 4, 1), @@ -706,7 +713,8 @@ static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = { MUX(0, "mout_sclk_spll", mout_spll_p, SRC_TOP6, 8, 1), MUX(0, "mout_sclk_ipll", mout_ipll_p, SRC_TOP6, 12, 1), MUX(0, "mout_sclk_rpll", mout_rpll_p, SRC_TOP6, 16, 1), - MUX(CLK_MOUT_EPLL, "mout_sclk_epll", mout_epll_p, SRC_TOP6, 20, 1), + MUX_F(CLK_MOUT_EPLL, "mout_sclk_epll", mout_epll_p, SRC_TOP6, 20, 1, + CLK_SET_RATE_PARENT, 0), MUX(0, "mout_sclk_dpll", mout_dpll_p, SRC_TOP6, 24, 1), MUX(0, "mout_sclk_cpll", mout_cpll_p, SRC_TOP6, 28, 1), @@ -1001,9 +1009,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(0, "aclk300_disp1", "mout_user_aclk300_disp1", SRC_MASK_TOP2, 24, CLK_IS_CRITICAL, 0), - GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk", - SRC_MASK_TOP7, 20, 0, 0), - /* sclk */ GATE(CLK_SCLK_UART0, "sclk_uart0", "dout_uart0", GATE_TOP_SCLK_PERIC, 0, CLK_SET_RATE_PARENT, 0), @@ -1283,16 +1288,16 @@ static const struct samsung_pll_rate_table exynos5420_pll2550x_24mhz_tbl[] __ini static const struct samsung_pll_rate_table exynos5420_epll_24mhz_tbl[] = { PLL_36XX_RATE(600000000U, 100, 2, 1, 0), PLL_36XX_RATE(400000000U, 200, 3, 2, 0), - PLL_36XX_RATE(393216000U, 197, 3, 2, 25690), - PLL_36XX_RATE(361267200U, 301, 5, 2, 3671), + PLL_36XX_RATE(393216003U, 197, 3, 2, -25690), + PLL_36XX_RATE(361267218U, 301, 5, 2, 3671), PLL_36XX_RATE(200000000U, 200, 3, 3, 0), - PLL_36XX_RATE(196608000U, 197, 3, 3, -25690), - PLL_36XX_RATE(180633600U, 301, 5, 3, 3671), - PLL_36XX_RATE(131072000U, 131, 3, 3, 4719), + PLL_36XX_RATE(196608001U, 197, 3, 3, -25690), + PLL_36XX_RATE(180633609U, 301, 5, 3, 3671), + PLL_36XX_RATE(131072006U, 131, 3, 3, 4719), PLL_36XX_RATE(100000000U, 200, 3, 4, 0), - PLL_36XX_RATE(65536000U, 131, 3, 4, 4719), - PLL_36XX_RATE(49152000U, 197, 3, 5, 25690), - PLL_36XX_RATE(32768000U, 131, 3, 5, 4719), + PLL_36XX_RATE( 65536003U, 131, 3, 4, 4719), + PLL_36XX_RATE( 49152000U, 197, 3, 5, -25690), + PLL_36XX_RATE( 32768001U, 131, 3, 5, 4719), }; static struct samsung_pll_clock exynos5x_plls[nr_plls] __initdata = { @@ -1440,6 +1445,8 @@ static void __init exynos5x_clk_init(struct device_node *np, ARRAY_SIZE(exynos5420_mux_clks)); samsung_clk_register_div(ctx, exynos5420_div_clks, ARRAY_SIZE(exynos5420_div_clks)); + samsung_clk_register_gate(ctx, exynos5420_gate_clks, + ARRAY_SIZE(exynos5420_gate_clks)); } else { samsung_clk_register_fixed_factor( ctx, exynos5800_fixed_factor_clks, diff --git a/drivers/clk/sunxi-ng/ccu-sun5i.c b/drivers/clk/sunxi-ng/ccu-sun5i.c index 5372bf8be5e6..ab9e850b3707 100644 --- a/drivers/clk/sunxi-ng/ccu-sun5i.c +++ b/drivers/clk/sunxi-ng/ccu-sun5i.c @@ -184,7 +184,7 @@ static struct ccu_mux cpu_clk = { .hw.init = CLK_HW_INIT_PARENTS("cpu", cpu_parents, &ccu_mux_ops, - CLK_IS_CRITICAL), + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), } }; @@ -976,8 +976,7 @@ static void __init sun5i_ccu_init(struct device_node *node, reg = of_io_request_and_map(node, 0, of_node_full_name(node)); if (IS_ERR(reg)) { - pr_err("%s: Could not map the clock registers\n", - of_node_full_name(node)); + pr_err("%pOF: Could not map the clock registers\n", node); return; } diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c index 4d6078fca9ac..8af434815fba 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -1217,8 +1217,7 @@ static void __init sun6i_a31_ccu_setup(struct device_node *node) reg = of_io_request_and_map(node, 0, of_node_full_name(node)); if (IS_ERR(reg)) { - pr_err("%s: Could not map the clock registers\n", - of_node_full_name(node)); + pr_err("%pOF: Could not map the clock registers\n", node); return; } diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c index 8a753ed0426d..d93b452f0df9 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c @@ -716,8 +716,7 @@ static void __init sun8i_a23_ccu_setup(struct device_node *node) reg = of_io_request_and_map(node, 0, of_node_full_name(node)); if (IS_ERR(reg)) { - pr_err("%s: Could not map the clock registers\n", - of_node_full_name(node)); + pr_err("%pOF: Could not map the clock registers\n", node); return; } diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c index 10b38dc46f75..13eb5b23c5e7 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c @@ -777,8 +777,7 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node) reg = of_io_request_and_map(node, 0, of_node_full_name(node)); if (IS_ERR(reg)) { - pr_err("%s: Could not map the clock registers\n", - of_node_full_name(node)); + pr_err("%pOF: Could not map the clock registers\n", node); return; } diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index 4cdbc88f2783..1729ff6a5aae 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -1125,8 +1125,7 @@ static void __init sunxi_h3_h5_ccu_init(struct device_node *node, reg = of_io_request_and_map(node, 0, of_node_full_name(node)); if (IS_ERR(reg)) { - pr_err("%s: Could not map the clock registers\n", - of_node_full_name(node)); + pr_err("%pOF: Could not map the clock registers\n", node); return; } diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r.c b/drivers/clk/sunxi-ng/ccu-sun8i-r.c index e54816ec1dbe..71feb7b24e8a 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r.c @@ -290,8 +290,7 @@ static void __init sunxi_r_ccu_init(struct device_node *node, reg = of_io_request_and_map(node, 0, of_node_full_name(node)); if (IS_ERR(reg)) { - pr_err("%s: Could not map the clock registers\n", - of_node_full_name(node)); + pr_err("%pOF: Could not map the clock registers\n", node); return; } diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c index a34a78d7fb28..621b1cd996db 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c @@ -575,8 +575,7 @@ static void __init sun8i_v3s_ccu_setup(struct device_node *node) reg = of_io_request_and_map(node, 0, of_node_full_name(node)); if (IS_ERR(reg)) { - pr_err("%s: Could not map the clock registers\n", - of_node_full_name(node)); + pr_err("%pOF: Could not map the clock registers\n", node); return; } diff --git a/drivers/clk/sunxi/clk-sun8i-bus-gates.c b/drivers/clk/sunxi/clk-sun8i-bus-gates.c index 63fdb790df29..bee305bdddbe 100644 --- a/drivers/clk/sunxi/clk-sun8i-bus-gates.c +++ b/drivers/clk/sunxi/clk-sun8i-bus-gates.c @@ -78,6 +78,10 @@ static void __init sun8i_h3_bus_gates_init(struct device_node *node) clk_parent = APB1; else if (index >= 96 && index <= 127) clk_parent = APB2; + else { + WARN_ON(true); + continue; + } clk_reg = reg + 4 * (index / 32); clk_bit = index % 32; diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index f2c9274b8bd5..aa4add580516 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -666,15 +666,14 @@ static struct clk * __init sunxi_mux_clk_setup(struct device_node *node, reg = of_iomap(node, 0); if (!reg) { - pr_err("Could not map registers for mux-clk: %s\n", - of_node_full_name(node)); + pr_err("Could not map registers for mux-clk: %pOF\n", node); return NULL; } i = of_clk_parent_fill(node, parents, SUNXI_MAX_PARENTS); if (of_property_read_string(node, "clock-output-names", &clk_name)) { - pr_err("%s: could not read clock-output-names from \"%s\"\n", - __func__, of_node_full_name(node)); + pr_err("%s: could not read clock-output-names from \"%pOF\"\n", + __func__, node); goto out_unmap; } @@ -797,16 +796,15 @@ static void __init sunxi_divider_clk_setup(struct device_node *node, reg = of_iomap(node, 0); if (!reg) { - pr_err("Could not map registers for mux-clk: %s\n", - of_node_full_name(node)); + pr_err("Could not map registers for mux-clk: %pOF\n", node); return; } clk_parent = of_clk_get_parent_name(node, 0); if (of_property_read_string(node, "clock-output-names", &clk_name)) { - pr_err("%s: could not read clock-output-names from \"%s\"\n", - __func__, of_node_full_name(node)); + pr_err("%s: could not read clock-output-names from \"%pOF\"\n", + __func__, node); goto out_unmap; } @@ -1010,8 +1008,7 @@ static struct clk ** __init sunxi_divs_clk_setup(struct device_node *node, reg = of_iomap(node, 0); if (!reg) { - pr_err("Could not map registers for divs-clk: %s\n", - of_node_full_name(node)); + pr_err("Could not map registers for divs-clk: %pOF\n", node); return NULL; } diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c index 74e7544f861b..11a5066e5c27 100644 --- a/drivers/clk/tegra/clk-emc.c +++ b/drivers/clk/tegra/clk-emc.c @@ -378,7 +378,7 @@ static int load_one_timing_from_dt(struct tegra_clk_emc *tegra, err = of_property_read_u32(node, "clock-frequency", &tmp); if (err) { - pr_err("timing %s: failed to read rate\n", node->full_name); + pr_err("timing %pOF: failed to read rate\n", node); return err; } @@ -386,8 +386,7 @@ static int load_one_timing_from_dt(struct tegra_clk_emc *tegra, err = of_property_read_u32(node, "nvidia,parent-clock-frequency", &tmp); if (err) { - pr_err("timing %s: failed to read parent rate\n", - node->full_name); + pr_err("timing %pOF: failed to read parent rate\n", node); return err; } @@ -395,8 +394,7 @@ static int load_one_timing_from_dt(struct tegra_clk_emc *tegra, timing->parent = of_clk_get_by_name(node, "emc-parent"); if (IS_ERR(timing->parent)) { - pr_err("timing %s: failed to get parent clock\n", - node->full_name); + pr_err("timing %pOF: failed to get parent clock\n", node); return PTR_ERR(timing->parent); } @@ -409,8 +407,8 @@ static int load_one_timing_from_dt(struct tegra_clk_emc *tegra, } } if (timing->parent_index == 0xff) { - pr_err("timing %s: %s is not a valid parent\n", - node->full_name, __clk_get_name(timing->parent)); + pr_err("timing %pOF: %s is not a valid parent\n", + node, __clk_get_name(timing->parent)); clk_put(timing->parent); return -EINVAL; } diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 159a854779e6..7c369e21c91c 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -363,7 +363,7 @@ static void _clk_pll_enable(struct clk_hw *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); + udelay(5); } if (pll->params->reset_reg) { @@ -418,6 +418,26 @@ static void _clk_pll_disable(struct clk_hw *hw) } } +static void pll_clk_start_ss(struct tegra_clk_pll *pll) +{ + if (pll->params->defaults_set && pll->params->ssc_ctrl_reg) { + u32 val = pll_readl(pll->params->ssc_ctrl_reg, pll); + + val |= pll->params->ssc_ctrl_en_mask; + pll_writel(val, pll->params->ssc_ctrl_reg, pll); + } +} + +static void pll_clk_stop_ss(struct tegra_clk_pll *pll) +{ + if (pll->params->defaults_set && pll->params->ssc_ctrl_reg) { + u32 val = pll_readl(pll->params->ssc_ctrl_reg, pll); + + val &= ~pll->params->ssc_ctrl_en_mask; + pll_writel(val, pll->params->ssc_ctrl_reg, pll); + } +} + static int clk_pll_enable(struct clk_hw *hw) { struct tegra_clk_pll *pll = to_clk_pll(hw); @@ -431,6 +451,8 @@ static int clk_pll_enable(struct clk_hw *hw) ret = clk_pll_wait_for_lock(pll); + pll_clk_start_ss(pll); + if (pll->lock) spin_unlock_irqrestore(pll->lock, flags); @@ -445,6 +467,8 @@ static void clk_pll_disable(struct clk_hw *hw) if (pll->lock) spin_lock_irqsave(pll->lock, flags); + pll_clk_stop_ss(pll); + _clk_pll_disable(hw); if (pll->lock) @@ -666,6 +690,8 @@ static void _get_pll_mnp(struct tegra_clk_pll *pll, struct tegra_clk_pll_params *params = pll->params; struct div_nmp *div_nmp = params->div_nmp; + *cfg = (struct tegra_clk_pll_freq_table) { }; + if ((params->flags & (TEGRA_PLLM | TEGRA_PLLMB)) && (pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) { @@ -716,26 +742,6 @@ static void _update_pll_cpcon(struct tegra_clk_pll *pll, pll_writel_misc(val, pll); } -static void pll_clk_start_ss(struct tegra_clk_pll *pll) -{ - if (pll->params->defaults_set && pll->params->ssc_ctrl_reg) { - u32 val = pll_readl(pll->params->ssc_ctrl_reg, pll); - - val |= pll->params->ssc_ctrl_en_mask; - pll_writel(val, pll->params->ssc_ctrl_reg, pll); - } -} - -static void pll_clk_stop_ss(struct tegra_clk_pll *pll) -{ - if (pll->params->defaults_set && pll->params->ssc_ctrl_reg) { - u32 val = pll_readl(pll->params->ssc_ctrl_reg, pll); - - val &= ~pll->params->ssc_ctrl_en_mask; - pll_writel(val, pll->params->ssc_ctrl_reg, pll); - } -} - static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, unsigned long rate) { @@ -2251,7 +2257,7 @@ tegra_clk_register_pllu_tegra114(const char *name, const char *parent_name, } #endif -#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) +#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) || defined(CONFIG_ARCH_TEGRA_210_SOC) static const struct clk_ops tegra_clk_pllss_ops = { .is_enabled = clk_pll_is_enabled, .enable = clk_pll_enable, @@ -2349,7 +2355,6 @@ struct clk *tegra_clk_register_pllre_tegra210(const char *name, struct tegra_clk_pll_params *pll_params, spinlock_t *lock, unsigned long parent_rate) { - u32 val; struct tegra_clk_pll *pll; struct clk *clk; @@ -2363,26 +2368,8 @@ struct clk *tegra_clk_register_pllre_tegra210(const char *name, 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); + &tegra_clk_pll_ops); if (IS_ERR(clk)) kfree(pll); @@ -2604,46 +2591,6 @@ struct clk *tegra_clk_register_pllc_tegra210(const char *name, return clk; } -struct clk *tegra_clk_register_pllxc_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) -{ - struct tegra_clk_pll *pll; - struct clk *clk, *parent; - unsigned long parent_rate; - - parent = __clk_lookup(parent_name); - if (!parent) { - WARN(1, "parent clk %s of %s must be registered first\n", - name, parent_name); - return ERR_PTR(-EINVAL); - } - - if (!pll_params->pdiv_tohw) - return ERR_PTR(-EINVAL); - - parent_rate = clk_get_rate(parent); - - 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); - - 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_pllss_tegra210(const char *name, const char *parent_name, void __iomem *clk_base, unsigned long flags, @@ -2652,10 +2599,8 @@ struct clk *tegra_clk_register_pllss_tegra210(const char *name, { struct tegra_clk_pll *pll; struct clk *clk, *parent; - struct tegra_clk_pll_freq_table cfg; unsigned long parent_rate; u32 val; - int i; if (!pll_params->div_nmp) return ERR_PTR(-EINVAL); @@ -2667,13 +2612,11 @@ struct clk *tegra_clk_register_pllss_tegra210(const char *name, return ERR_PTR(-EINVAL); } - pll = _tegra_init_pll(clk_base, NULL, pll_params, lock); - if (IS_ERR(pll)) - return ERR_CAST(pll); - - val = pll_readl_base(pll); - val &= ~PLLSS_REF_SRC_SEL_MASK; - pll_writel_base(val, pll); + val = readl_relaxed(clk_base + pll_params->base_reg); + if (val & PLLSS_REF_SRC_SEL_MASK) { + WARN(1, "not supported reference clock for %s\n", name); + return ERR_PTR(-EINVAL); + } parent_rate = clk_get_rate(parent); @@ -2683,36 +2626,10 @@ struct clk *tegra_clk_register_pllss_tegra210(const char *name, pll_params->vco_min = pll_params->adjust_vco(pll_params, parent_rate); - /* initialize PLL to minimum rate */ - - cfg.m = _pll_fixed_mdiv(pll_params, parent_rate); - cfg.n = cfg.m * pll_params->vco_min / parent_rate; - - for (i = 0; pll_params->pdiv_tohw[i].pdiv; i++) - ; - if (!i) { - kfree(pll); - return ERR_PTR(-EINVAL); - } - - cfg.p = pll_params->pdiv_tohw[i-1].hw_val; - - _update_pll_mnp(pll, &cfg); - - pll_writel_misc(PLLSS_MISC_DEFAULT, pll); - - val = pll_readl_base(pll); - if (val & PLL_BASE_ENABLE) { - if (val & BIT(pll_params->iddq_bit_idx)) { - WARN(1, "%s is on but IDDQ set\n", name); - kfree(pll); - return ERR_PTR(-EINVAL); - } - } else - val |= BIT(pll_params->iddq_bit_idx); - - val &= ~PLLSS_LOCK_OVERRIDE; - pll_writel_base(val, pll); + pll_params->flags |= TEGRA_PLL_BYPASS; + pll = _tegra_init_pll(clk_base, NULL, pll_params, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); clk = _tegra_clk_register_pll(pll, name, parent_name, flags, &tegra_clk_pll_ops); diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index 294bfe40a4f5..848255cc0209 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -216,7 +216,8 @@ _clk_num, _clk_id) \ TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\ 30, MASK(2), 0, 0, 16, 0, TEGRA_DIVIDER_ROUND_UP,\ - _clk_num, 0, _clk_id, _parents##_idx, 0, NULL) + _clk_num, TEGRA_PERIPH_ON_APB, _clk_id, \ + _parents##_idx, 0, NULL) #define XUSB(_name, _parents, _offset, \ _clk_num, _gate_flags, _clk_id) \ diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c index 474de0f0c26d..4f6fd307cb70 100644 --- a/drivers/clk/tegra/clk-tegra-super-gen4.c +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c @@ -232,8 +232,15 @@ static void __init tegra_super_clk_init(void __iomem *clk_base, if (!dt_clk) return; - clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base, - pmc_base, CLK_IGNORE_UNUSED, params, NULL); +#if defined(CONFIG_ARCH_TEGRA_210_SOC) + if (gen_info->gen == gen5) + clk = tegra_clk_register_pllc_tegra210("pll_x", "pll_ref", + clk_base, pmc_base, CLK_IGNORE_UNUSED, params, NULL); + else +#endif + clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base, + pmc_base, CLK_IGNORE_UNUSED, params, NULL); + *dt_clk = clk; /* PLLX_OUT0 */ diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 1024e853ea65..6d7a613f2656 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -146,7 +146,7 @@ #define PLLD_SDM_EN_MASK BIT(16) #define PLLD2_SDM_EN_MASK BIT(31) -#define PLLD2_SSC_EN_MASK BIT(30) +#define PLLD2_SSC_EN_MASK 0 #define PLLDP_SS_CFG 0x598 #define PLLDP_SDM_EN_MASK BIT(31) @@ -241,6 +241,9 @@ #define PLL_SDM_COEFF BIT(13) #define sdin_din_to_data(din) ((u16)((din) ? : 0xFFFFU)) #define sdin_data_to_din(dat) (((dat) == 0xFFFFU) ? 0 : (s16)dat) +/* This macro returns ndiv effective scaled to SDM range */ +#define sdin_get_n_eff(cfg) ((cfg)->n * PLL_SDM_COEFF + ((cfg)->sdm_data ? \ + (PLL_SDM_COEFF/2 + sdin_data_to_din((cfg)->sdm_data)) : 0)) /* Tegra CPU clock and reset control regs */ #define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470 @@ -715,8 +718,6 @@ static void plldss_defaults(const char *pll_name, struct tegra_clk_pll *plldss, plldss->params->defaults_set = true; if (val & PLL_ENABLE) { - pr_warn("%s already enabled. Postponing set full defaults\n", - pll_name); /* * PLL is ON: check if defaults already set, then set those @@ -755,6 +756,10 @@ static void plldss_defaults(const char *pll_name, struct tegra_clk_pll *plldss, (~PLLDSS_MISC1_CFG_EN_SDM)); } + if (!plldss->params->defaults_set) + pr_warn("%s already enabled. Postponing set full defaults\n", + pll_name); + /* Enable lock detect */ if (val & PLLDSS_BASE_LOCK_OVERRIDE) { val &= ~PLLDSS_BASE_LOCK_OVERRIDE; @@ -1288,8 +1293,7 @@ static int tegra210_pll_fixed_mdiv_cfg(struct clk_hw *hw, s -= PLL_SDM_COEFF / 2; cfg->sdm_data = sdin_din_to_data(s); } - cfg->output_rate *= cfg->n * PLL_SDM_COEFF + PLL_SDM_COEFF/2 + - sdin_data_to_din(cfg->sdm_data); + cfg->output_rate *= sdin_get_n_eff(cfg); cfg->output_rate /= p * cfg->m * PLL_SDM_COEFF; } else { cfg->output_rate *= cfg->n; @@ -1314,8 +1318,7 @@ static int tegra210_pll_fixed_mdiv_cfg(struct clk_hw *hw, */ static void tegra210_clk_pll_set_gain(struct tegra_clk_pll_freq_table *cfg) { - cfg->n = cfg->n * PLL_SDM_COEFF + PLL_SDM_COEFF/2 + - sdin_data_to_din(cfg->sdm_data); + cfg->n = sdin_get_n_eff(cfg); cfg->m *= PLL_SDM_COEFF; } @@ -2204,7 +2207,6 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = { [tegra_clk_gpu] = { .dt_id = TEGRA210_CLK_GPU, .present = true }, [tegra_clk_pll_g_ref] = { .dt_id = TEGRA210_CLK_PLL_G_REF, .present = true, }, [tegra_clk_uartb_8] = { .dt_id = TEGRA210_CLK_UARTB, .present = true }, - [tegra_clk_vfir] = { .dt_id = TEGRA210_CLK_VFIR, .present = true }, [tegra_clk_spdif_in_8] = { .dt_id = TEGRA210_CLK_SPDIF_IN, .present = true }, [tegra_clk_spdif_out] = { .dt_id = TEGRA210_CLK_SPDIF_OUT, .present = true }, [tegra_clk_vi_10] = { .dt_id = TEGRA210_CLK_VI, .present = true }, @@ -2470,15 +2472,14 @@ static void tegra210_utmi_param_configure(void) 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); 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(~0); reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(utmi_parameters[i].enable_delay_count); @@ -2494,7 +2495,8 @@ static void tegra210_utmi_param_configure(void) reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; reg |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP; writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1); - udelay(1); + + udelay(20); /* Enable samplers for SNPS, XUSB_HOST, XUSB_DEV */ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2); @@ -2552,6 +2554,7 @@ static int tegra210_enable_pllu(void) reg = readl_relaxed(clk_base + pllu.params->ext_misc_reg[0]); reg &= ~BIT(pllu.params->iddq_bit_idx); writel_relaxed(reg, clk_base + pllu.params->ext_misc_reg[0]); + udelay(5); reg = readl_relaxed(clk_base + PLLU_BASE); reg &= ~GENMASK(20, 0); @@ -2559,6 +2562,7 @@ static int tegra210_enable_pllu(void) reg |= fentry->n << 8; reg |= fentry->p << 16; writel(reg, clk_base + PLLU_BASE); + udelay(1); reg |= PLL_ENABLE; writel(reg, clk_base + PLLU_BASE); @@ -2699,7 +2703,7 @@ static void __init tegra210_pll_init(void __iomem *clk_base, struct clk *clk; /* PLLC */ - clk = tegra_clk_register_pllxc_tegra210("pll_c", "pll_ref", clk_base, + clk = tegra_clk_register_pllc_tegra210("pll_c", "pll_ref", clk_base, pmc, 0, &pll_c_params, NULL); if (!WARN_ON(IS_ERR(clk))) clk_register_clkdev(clk, "pll_c", NULL); @@ -2798,14 +2802,14 @@ static void __init tegra210_pll_init(void __iomem *clk_base, /* PLLU_60M */ clk = clk_register_gate(NULL, "pll_u_60M", "pll_u_out2", CLK_SET_RATE_PARENT, clk_base + PLLU_BASE, - 23, 0, NULL); + 23, 0, &pll_u_lock); clk_register_clkdev(clk, "pll_u_60M", NULL); clks[TEGRA210_CLK_PLL_U_60M] = clk; /* PLLU_48M */ clk = clk_register_gate(NULL, "pll_u_48M", "pll_u_out1", CLK_SET_RATE_PARENT, clk_base + PLLU_BASE, - 25, 0, NULL); + 25, 0, &pll_u_lock); clk_register_clkdev(clk, "pll_u_48M", NULL); clks[TEGRA210_CLK_PLL_U_48M] = clk; diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 945b07093afa..872f1189ad7f 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -362,12 +362,6 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name, struct tegra_clk_pll_params *pll_params, spinlock_t *lock); -struct clk *tegra_clk_register_pllxc_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); - struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, unsigned long flags, diff --git a/drivers/clk/ti/adpll.c b/drivers/clk/ti/adpll.c index 255cafb18336..d5c6db446316 100644 --- a/drivers/clk/ti/adpll.c +++ b/drivers/clk/ti/adpll.c @@ -486,7 +486,7 @@ static u8 ti_adpll_get_parent(struct clk_hw *hw) return 0; } -static struct clk_ops ti_adpll_ops = { +static const struct clk_ops ti_adpll_ops = { .prepare = ti_adpll_prepare, .unprepare = ti_adpll_unprepare, .is_prepared = ti_adpll_is_prepared, diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c index 06f486b3488c..83b148f8037c 100644 --- a/drivers/clk/ti/apll.c +++ b/drivers/clk/ti/apll.c @@ -304,7 +304,7 @@ static void omap2_apll_disable(struct clk_hw *hw) ti_clk_ll_ops->clk_writel(v, &ad->control_reg); } -static struct clk_ops omap2_apll_ops = { +static const struct clk_ops omap2_apll_ops = { .enable = &omap2_apll_enable, .disable = &omap2_apll_disable, .is_enabled = &omap2_apll_is_enabled, diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index fbedc6a9fed0..07a805125e98 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c @@ -138,8 +138,8 @@ static void __init of_ti_clockdomain_setup(struct device_node *node) for (i = 0; i < num_clks; i++) { clk = of_clk_get(node, i); if (IS_ERR(clk)) { - pr_err("%s: Failed get %s' clock nr %d (%ld)\n", - __func__, node->full_name, i, PTR_ERR(clk)); + pr_err("%s: Failed get %pOF' clock nr %d (%ld)\n", + __func__, node, i, PTR_ERR(clk)); continue; } clk_hw = __clk_get_hw(clk); diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c index 66a0d0ed8b55..071af44b1ba8 100644 --- a/drivers/clk/ti/fapll.c +++ b/drivers/clk/ti/fapll.c @@ -268,7 +268,7 @@ static int ti_fapll_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -static struct clk_ops ti_fapll_ops = { +static const struct clk_ops ti_fapll_ops = { .enable = ti_fapll_enable, .disable = ti_fapll_disable, .is_enabled = ti_fapll_is_enabled, @@ -478,7 +478,7 @@ static int ti_fapll_synth_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -static struct clk_ops ti_fapll_synt_ops = { +static const struct clk_ops ti_fapll_synt_ops = { .enable = ti_fapll_synth_enable, .disable = ti_fapll_synth_disable, .is_enabled = ti_fapll_synth_is_enabled, diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c index 2cf386347f0c..cb6ae261bb36 100644 --- a/drivers/clk/uniphier/clk-uniphier-core.c +++ b/drivers/clk/uniphier/clk-uniphier-core.c @@ -111,10 +111,6 @@ static int uniphier_clk_remove(struct platform_device *pdev) static const struct of_device_id uniphier_clk_match[] = { /* System clock */ { - .compatible = "socionext,uniphier-sld3-clock", - .data = uniphier_sld3_sys_clk_data, - }, - { .compatible = "socionext,uniphier-ld4-clock", .data = uniphier_ld4_sys_clk_data, }, @@ -144,20 +140,16 @@ static const struct of_device_id uniphier_clk_match[] = { }, /* Media I/O clock, SD clock */ { - .compatible = "socionext,uniphier-sld3-mio-clock", - .data = uniphier_sld3_mio_clk_data, - }, - { .compatible = "socionext,uniphier-ld4-mio-clock", - .data = uniphier_sld3_mio_clk_data, + .data = uniphier_ld4_mio_clk_data, }, { .compatible = "socionext,uniphier-pro4-mio-clock", - .data = uniphier_sld3_mio_clk_data, + .data = uniphier_ld4_mio_clk_data, }, { .compatible = "socionext,uniphier-sld8-mio-clock", - .data = uniphier_sld3_mio_clk_data, + .data = uniphier_ld4_mio_clk_data, }, { .compatible = "socionext,uniphier-pro5-sd-clock", @@ -169,7 +161,7 @@ static const struct of_device_id uniphier_clk_match[] = { }, { .compatible = "socionext,uniphier-ld11-mio-clock", - .data = uniphier_sld3_mio_clk_data, + .data = uniphier_ld4_mio_clk_data, }, { .compatible = "socionext,uniphier-ld20-sd-clock", diff --git a/drivers/clk/uniphier/clk-uniphier-mio.c b/drivers/clk/uniphier/clk-uniphier-mio.c index 218d20f099ce..16e4d303f535 100644 --- a/drivers/clk/uniphier/clk-uniphier-mio.c +++ b/drivers/clk/uniphier/clk-uniphier-mio.c @@ -76,7 +76,7 @@ #define UNIPHIER_MIO_CLK_DMAC(idx) \ UNIPHIER_CLK_GATE("miodmac", (idx), "stdmac", 0x20, 25) -const struct uniphier_clk_data uniphier_sld3_mio_clk_data[] = { +const struct uniphier_clk_data uniphier_ld4_mio_clk_data[] = { UNIPHIER_MIO_CLK_SD_FIXED, UNIPHIER_MIO_CLK_SD(0, 0), UNIPHIER_MIO_CLK_SD(1, 1), @@ -85,11 +85,9 @@ const struct uniphier_clk_data uniphier_sld3_mio_clk_data[] = { UNIPHIER_MIO_CLK_USB2(8, 0), UNIPHIER_MIO_CLK_USB2(9, 1), UNIPHIER_MIO_CLK_USB2(10, 2), - UNIPHIER_MIO_CLK_USB2(11, 3), UNIPHIER_MIO_CLK_USB2_PHY(12, 0), UNIPHIER_MIO_CLK_USB2_PHY(13, 1), UNIPHIER_MIO_CLK_USB2_PHY(14, 2), - UNIPHIER_MIO_CLK_USB2_PHY(15, 3), { /* sentinel */ } }; diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c index ad0218182a9f..01da1414ec37 100644 --- a/drivers/clk/uniphier/clk-uniphier-sys.c +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -17,7 +17,7 @@ #include "clk-uniphier.h" -#define UNIPHIER_SLD3_SYS_CLK_SD \ +#define UNIPHIER_LD4_SYS_CLK_SD \ UNIPHIER_CLK_FACTOR("sd-200m", -1, "spll", 1, 8), \ UNIPHIER_CLK_FACTOR("sd-133m", -1, "vpll27a", 1, 2) @@ -30,7 +30,7 @@ UNIPHIER_CLK_FACTOR("sd-133m", -1, "spll", 1, 15) /* Denali driver requires clk_x rate (clk: 50MHz, clk_x & ecc_clk: 200MHz) */ -#define UNIPHIER_SLD3_SYS_CLK_NAND(idx) \ +#define UNIPHIER_LD4_SYS_CLK_NAND(idx) \ UNIPHIER_CLK_FACTOR("nand-200m", -1, "spll", 1, 8), \ UNIPHIER_CLK_GATE("nand", (idx), "nand-200m", 0x2104, 2) @@ -45,7 +45,7 @@ #define UNIPHIER_LD11_SYS_CLK_EMMC(idx) \ UNIPHIER_CLK_GATE("emmc", (idx), NULL, 0x210c, 2) -#define UNIPHIER_SLD3_SYS_CLK_STDMAC(idx) \ +#define UNIPHIER_LD4_SYS_CLK_STDMAC(idx) \ UNIPHIER_CLK_GATE("stdmac", (idx), NULL, 0x2104, 10) #define UNIPHIER_LD11_SYS_CLK_STDMAC(idx) \ @@ -57,19 +57,11 @@ #define UNIPHIER_PRO4_SYS_CLK_USB3(idx, ch) \ UNIPHIER_CLK_GATE("usb3" #ch, (idx), NULL, 0x2104, 16 + (ch)) -const struct uniphier_clk_data uniphier_sld3_sys_clk_data[] = { - UNIPHIER_CLK_FACTOR("spll", -1, "ref", 65, 1), /* 1597.44 MHz */ - UNIPHIER_CLK_FACTOR("upll", -1, "ref", 6000, 512), /* 288 MHz */ - UNIPHIER_CLK_FACTOR("a2pll", -1, "ref", 24, 1), /* 589.824 MHz */ - UNIPHIER_CLK_FACTOR("vpll27a", -1, "ref", 5625, 512), /* 270 MHz */ - UNIPHIER_CLK_FACTOR("uart", 0, "a2pll", 1, 16), - UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 16), - UNIPHIER_SLD3_SYS_CLK_NAND(2), - UNIPHIER_SLD3_SYS_CLK_SD, - UNIPHIER_CLK_FACTOR("usb2", -1, "upll", 1, 12), - UNIPHIER_SLD3_SYS_CLK_STDMAC(8), - { /* sentinel */ } -}; +#define UNIPHIER_PRO4_SYS_CLK_ETHER(idx) \ + UNIPHIER_CLK_GATE("ether", (idx), NULL, 0x2104, 12) + +#define UNIPHIER_LD11_SYS_CLK_ETHER(idx) \ + UNIPHIER_CLK_GATE("ether", (idx), NULL, 0x210c, 6) const struct uniphier_clk_data uniphier_ld4_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("spll", -1, "ref", 65, 1), /* 1597.44 MHz */ @@ -78,10 +70,10 @@ const struct uniphier_clk_data uniphier_ld4_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("vpll27a", -1, "ref", 5625, 512), /* 270 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "a2pll", 1, 16), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 16), - UNIPHIER_SLD3_SYS_CLK_NAND(2), - UNIPHIER_SLD3_SYS_CLK_SD, + UNIPHIER_LD4_SYS_CLK_NAND(2), + UNIPHIER_LD4_SYS_CLK_SD, UNIPHIER_CLK_FACTOR("usb2", -1, "upll", 1, 12), - UNIPHIER_SLD3_SYS_CLK_STDMAC(8), /* Ether, HSC, MIO */ + UNIPHIER_LD4_SYS_CLK_STDMAC(8), /* Ether, HSC, MIO */ { /* sentinel */ } }; @@ -92,10 +84,11 @@ const struct uniphier_clk_data uniphier_pro4_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("vpll27a", -1, "ref", 270, 25), /* 270 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "a2pll", 1, 8), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 32), - UNIPHIER_SLD3_SYS_CLK_NAND(2), - UNIPHIER_SLD3_SYS_CLK_SD, + UNIPHIER_LD4_SYS_CLK_NAND(2), + UNIPHIER_LD4_SYS_CLK_SD, UNIPHIER_CLK_FACTOR("usb2", -1, "upll", 1, 12), - UNIPHIER_SLD3_SYS_CLK_STDMAC(8), /* HSC, MIO, RLE */ + UNIPHIER_PRO4_SYS_CLK_ETHER(6), + UNIPHIER_LD4_SYS_CLK_STDMAC(8), /* HSC, MIO, RLE */ UNIPHIER_PRO4_SYS_CLK_GIO(12), /* Ether, SATA, USB3 */ UNIPHIER_PRO4_SYS_CLK_USB3(14, 0), UNIPHIER_PRO4_SYS_CLK_USB3(15, 1), @@ -108,10 +101,10 @@ const struct uniphier_clk_data uniphier_sld8_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("vpll27a", -1, "ref", 270, 25), /* 270 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 20), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 16), - UNIPHIER_SLD3_SYS_CLK_NAND(2), - UNIPHIER_SLD3_SYS_CLK_SD, + UNIPHIER_LD4_SYS_CLK_NAND(2), + UNIPHIER_LD4_SYS_CLK_SD, UNIPHIER_CLK_FACTOR("usb2", -1, "upll", 1, 12), - UNIPHIER_SLD3_SYS_CLK_STDMAC(8), /* Ether, HSC, MIO */ + UNIPHIER_LD4_SYS_CLK_STDMAC(8), /* Ether, HSC, MIO */ { /* sentinel */ } }; @@ -123,7 +116,7 @@ const struct uniphier_clk_data uniphier_pro5_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 48), UNIPHIER_PRO5_SYS_CLK_NAND(2), UNIPHIER_PRO5_SYS_CLK_SD, - UNIPHIER_SLD3_SYS_CLK_STDMAC(8), /* HSC */ + UNIPHIER_LD4_SYS_CLK_STDMAC(8), /* HSC */ UNIPHIER_PRO4_SYS_CLK_GIO(12), /* PCIe, USB3 */ UNIPHIER_PRO4_SYS_CLK_USB3(14, 0), UNIPHIER_PRO4_SYS_CLK_USB3(15, 1), @@ -136,7 +129,8 @@ const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 48), UNIPHIER_PRO5_SYS_CLK_NAND(2), UNIPHIER_PRO5_SYS_CLK_SD, - UNIPHIER_SLD3_SYS_CLK_STDMAC(8), /* HSC, RLE */ + UNIPHIER_PRO4_SYS_CLK_ETHER(6), + UNIPHIER_LD4_SYS_CLK_STDMAC(8), /* HSC, RLE */ /* GIO is always clock-enabled: no function for 0x2104 bit6 */ UNIPHIER_PRO4_SYS_CLK_USB3(14, 0), UNIPHIER_PRO4_SYS_CLK_USB3(15, 1), @@ -156,6 +150,7 @@ const struct uniphier_clk_data uniphier_ld11_sys_clk_data[] = { UNIPHIER_LD11_SYS_CLK_NAND(2), UNIPHIER_LD11_SYS_CLK_EMMC(4), /* Index 5 reserved for eMMC PHY */ + UNIPHIER_LD11_SYS_CLK_ETHER(6), UNIPHIER_LD11_SYS_CLK_STDMAC(8), /* HSC, MIO */ UNIPHIER_CLK_FACTOR("usb2", -1, "ref", 24, 25), /* CPU gears */ @@ -185,6 +180,7 @@ const struct uniphier_clk_data uniphier_ld20_sys_clk_data[] = { UNIPHIER_LD11_SYS_CLK_EMMC(4), /* Index 5 reserved for eMMC PHY */ UNIPHIER_LD20_SYS_CLK_SD, + UNIPHIER_LD11_SYS_CLK_ETHER(6), UNIPHIER_LD11_SYS_CLK_STDMAC(8), /* HSC */ /* GIO is always clock-enabled: no function for 0x210c bit5 */ /* diff --git a/drivers/clk/uniphier/clk-uniphier.h b/drivers/clk/uniphier/clk-uniphier.h index 01c16ecec48f..827164093172 100644 --- a/drivers/clk/uniphier/clk-uniphier.h +++ b/drivers/clk/uniphier/clk-uniphier.h @@ -147,7 +147,6 @@ struct clk_hw *uniphier_clk_register_mux(struct device *dev, const char *name, const struct uniphier_clk_mux_data *data); -extern const struct uniphier_clk_data uniphier_sld3_sys_clk_data[]; extern const struct uniphier_clk_data uniphier_ld4_sys_clk_data[]; extern const struct uniphier_clk_data uniphier_pro4_sys_clk_data[]; extern const struct uniphier_clk_data uniphier_sld8_sys_clk_data[]; @@ -155,7 +154,7 @@ extern const struct uniphier_clk_data uniphier_pro5_sys_clk_data[]; extern const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[]; extern const struct uniphier_clk_data uniphier_ld11_sys_clk_data[]; extern const struct uniphier_clk_data uniphier_ld20_sys_clk_data[]; -extern const struct uniphier_clk_data uniphier_sld3_mio_clk_data[]; +extern const struct uniphier_clk_data uniphier_ld4_mio_clk_data[]; extern const struct uniphier_clk_data uniphier_pro5_sd_clk_data[]; extern const struct uniphier_clk_data uniphier_ld4_peri_clk_data[]; extern const struct uniphier_clk_data uniphier_pro4_peri_clk_data[]; diff --git a/drivers/clk/ux500/clk-prcc.c b/drivers/clk/ux500/clk-prcc.c index 0e950769ed03..f50592775c9d 100644 --- a/drivers/clk/ux500/clk-prcc.c +++ b/drivers/clk/ux500/clk-prcc.c @@ -79,13 +79,13 @@ static int clk_prcc_is_enabled(struct clk_hw *hw) return clk->is_enabled; } -static struct clk_ops clk_prcc_pclk_ops = { +static const struct clk_ops clk_prcc_pclk_ops = { .enable = clk_prcc_pclk_enable, .disable = clk_prcc_pclk_disable, .is_enabled = clk_prcc_is_enabled, }; -static struct clk_ops clk_prcc_kclk_ops = { +static const struct clk_ops clk_prcc_kclk_ops = { .enable = clk_prcc_kclk_enable, .disable = clk_prcc_kclk_disable, .is_enabled = clk_prcc_is_enabled, @@ -96,7 +96,7 @@ static struct clk *clk_reg_prcc(const char *name, resource_size_t phy_base, u32 cg_sel, unsigned long flags, - struct clk_ops *clk_prcc_ops) + const struct clk_ops *clk_prcc_ops) { struct clk_prcc *clk; struct clk_init_data clk_prcc_init; diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c index 7f343821f4e4..6e3e16b2e5ca 100644 --- a/drivers/clk/ux500/clk-prcmu.c +++ b/drivers/clk/ux500/clk-prcmu.c @@ -186,7 +186,7 @@ static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw) clk->is_prepared = 0; } -static struct clk_ops clk_prcmu_scalable_ops = { +static const struct clk_ops clk_prcmu_scalable_ops = { .prepare = clk_prcmu_prepare, .unprepare = clk_prcmu_unprepare, .is_prepared = clk_prcmu_is_prepared, @@ -198,7 +198,7 @@ static struct clk_ops clk_prcmu_scalable_ops = { .set_rate = clk_prcmu_set_rate, }; -static struct clk_ops clk_prcmu_gate_ops = { +static const struct clk_ops clk_prcmu_gate_ops = { .prepare = clk_prcmu_prepare, .unprepare = clk_prcmu_unprepare, .is_prepared = clk_prcmu_is_prepared, @@ -208,19 +208,19 @@ static struct clk_ops clk_prcmu_gate_ops = { .recalc_rate = clk_prcmu_recalc_rate, }; -static struct clk_ops clk_prcmu_scalable_rate_ops = { +static const struct clk_ops clk_prcmu_scalable_rate_ops = { .is_enabled = clk_prcmu_is_enabled, .recalc_rate = clk_prcmu_recalc_rate, .round_rate = clk_prcmu_round_rate, .set_rate = clk_prcmu_set_rate, }; -static struct clk_ops clk_prcmu_rate_ops = { +static const struct clk_ops clk_prcmu_rate_ops = { .is_enabled = clk_prcmu_is_enabled, .recalc_rate = clk_prcmu_recalc_rate, }; -static struct clk_ops clk_prcmu_opp_gate_ops = { +static const struct clk_ops clk_prcmu_opp_gate_ops = { .prepare = clk_prcmu_opp_prepare, .unprepare = clk_prcmu_opp_unprepare, .is_prepared = clk_prcmu_is_prepared, @@ -230,7 +230,7 @@ static struct clk_ops clk_prcmu_opp_gate_ops = { .recalc_rate = clk_prcmu_recalc_rate, }; -static struct clk_ops clk_prcmu_opp_volt_scalable_ops = { +static const struct clk_ops clk_prcmu_opp_volt_scalable_ops = { .prepare = clk_prcmu_opp_volt_prepare, .unprepare = clk_prcmu_opp_volt_unprepare, .is_prepared = clk_prcmu_is_prepared, @@ -247,7 +247,7 @@ static struct clk *clk_reg_prcmu(const char *name, u8 cg_sel, unsigned long rate, unsigned long flags, - struct clk_ops *clk_prcmu_ops) + const struct clk_ops *clk_prcmu_ops) { struct clk_prcmu *clk; struct clk_init_data clk_prcmu_init; diff --git a/drivers/clk/ux500/clk-sysctrl.c b/drivers/clk/ux500/clk-sysctrl.c index 266ddea630d2..8a4e93ce1e42 100644 --- a/drivers/clk/ux500/clk-sysctrl.c +++ b/drivers/clk/ux500/clk-sysctrl.c @@ -98,18 +98,18 @@ static u8 clk_sysctrl_get_parent(struct clk_hw *hw) return clk->parent_index; } -static struct clk_ops clk_sysctrl_gate_ops = { +static const struct clk_ops clk_sysctrl_gate_ops = { .prepare = clk_sysctrl_prepare, .unprepare = clk_sysctrl_unprepare, }; -static struct clk_ops clk_sysctrl_gate_fixed_rate_ops = { +static const struct clk_ops clk_sysctrl_gate_fixed_rate_ops = { .prepare = clk_sysctrl_prepare, .unprepare = clk_sysctrl_unprepare, .recalc_rate = clk_sysctrl_recalc_rate, }; -static struct clk_ops clk_sysctrl_set_parent_ops = { +static const struct clk_ops clk_sysctrl_set_parent_ops = { .set_parent = clk_sysctrl_set_parent, .get_parent = clk_sysctrl_get_parent, }; @@ -124,7 +124,7 @@ static struct clk *clk_reg_sysctrl(struct device *dev, unsigned long rate, unsigned long enable_delay_us, unsigned long flags, - struct clk_ops *clk_sysctrl_ops) + const struct clk_ops *clk_sysctrl_ops) { struct clk_sysctrl *clk; struct clk_init_data clk_sysctrl_init; diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c index 7e5add7d7752..e7a868b83fe5 100644 --- a/drivers/clk/versatile/clk-vexpress-osc.c +++ b/drivers/clk/versatile/clk-vexpress-osc.c @@ -61,7 +61,7 @@ static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate, return regmap_write(osc->reg, 0, rate); } -static struct clk_ops vexpress_osc_ops = { +static const struct clk_ops vexpress_osc_ops = { .recalc_rate = vexpress_osc_recalc_rate, .round_rate = vexpress_osc_round_rate, .set_rate = vexpress_osc_set_rate, diff --git a/drivers/clk/x86/clk-pmc-atom.c b/drivers/clk/x86/clk-pmc-atom.c index f99abc1106f0..08ef69945ffb 100644 --- a/drivers/clk/x86/clk-pmc-atom.c +++ b/drivers/clk/x86/clk-pmc-atom.c @@ -186,6 +186,13 @@ static struct clk_plt *plt_clk_register(struct platform_device *pdev, int id, pclk->reg = base + PMC_CLK_CTL_OFFSET + id * PMC_CLK_CTL_SIZE; spin_lock_init(&pclk->lock); + /* + * If the clock was already enabled by the firmware mark it as critical + * to avoid it being gated by the clock framework if no driver owns it. + */ + if (plt_clk_is_enabled(&pclk->hw)) + init.flags |= CLK_IS_CRITICAL; + ret = devm_clk_hw_register(&pdev->dev, &pclk->hw); if (ret) { pclk = ERR_PTR(ret); diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c index 27f853d4c76b..354dd508c516 100644 --- a/drivers/clk/zte/clk-zx296718.c +++ b/drivers/clk/zte/clk-zx296718.c @@ -451,7 +451,7 @@ static struct zx_clk_fixed_factor top_ffactor_clk[] = { FFACTOR(0, "emmc_mux_div2", "emmc_mux", 1, 2, CLK_SET_RATE_PARENT), }; -static struct clk_div_table noc_div_table[] = { +static const struct clk_div_table noc_div_table[] = { { .val = 1, .div = 2, }, { .val = 3, .div = 4, }, }; @@ -644,7 +644,7 @@ static int __init top_clocks_init(struct device_node *np) return 0; } -static struct clk_div_table common_even_div_table[] = { +static const struct clk_div_table common_even_div_table[] = { { .val = 0, .div = 1, }, { .val = 1, .div = 2, }, { .val = 3, .div = 4, }, @@ -656,7 +656,7 @@ static struct clk_div_table common_even_div_table[] = { { .val = 15, .div = 16, }, }; -static struct clk_div_table common_div_table[] = { +static const struct clk_div_table common_div_table[] = { { .val = 0, .div = 1, }, { .val = 1, .div = 2, }, { .val = 2, .div = 3, }, |