From 10a7436e511264720c4c5b3ec97f6dae25b0c3cb Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:13:57 -0800 Subject: clk: Port of_clk_set_defaults() Port of_clk_set_defautls() from Linux kernel in order to support DT configurations that require it (e. g. Vybrid). Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/clk/Makefile | 2 +- drivers/clk/clk-conf.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/clk.c | 2 + 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/clk-conf.c (limited to 'drivers') diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 47ed7b1b6e..0fe8f1e200 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed.o clk-divider.o clk-fixed-factor.o \ clk-mux.o clk-gate.o clk-composite.o \ - clk-fractional-divider.o + clk-fractional-divider.o clk-conf.o obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_ARCH_MVEBU) += mvebu/ diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c new file mode 100644 index 0000000000..93271b4f99 --- /dev/null +++ b/drivers/clk/clk-conf.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2014 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK_OF_PROVIDER) + +static int __set_clk_parents(struct device_node *node, bool clk_supplier) +{ + struct of_phandle_args clkspec; + int index, rc, num_parents; + struct clk *clk, *pclk; + + 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); + + for (index = 0; index < num_parents; index++) { + rc = of_parse_phandle_with_args(node, "assigned-clock-parents", + "#clock-cells", index, &clkspec); + if (rc < 0) { + /* skip empty (null) phandles */ + if (rc == -ENOENT) + continue; + else + return rc; + } + if (clkspec.np == node && !clk_supplier) + return 0; + pclk = of_clk_get_from_provider(&clkspec); + if (IS_ERR(pclk)) { + pr_warn("clk: couldn't get parent clock %d for %s\n", + index, node->full_name); + return PTR_ERR(pclk); + } + + rc = of_parse_phandle_with_args(node, "assigned-clocks", + "#clock-cells", index, &clkspec); + if (rc < 0) + goto err; + if (clkspec.np == node && !clk_supplier) { + rc = 0; + goto err; + } + clk = of_clk_get_from_provider(&clkspec); + if (IS_ERR(clk)) { + pr_warn("clk: couldn't get parent clock %d for %s\n", + index, node->full_name); + rc = PTR_ERR(clk); + goto err; + } + + rc = clk_set_parent(clk, pclk); + if (rc < 0) + pr_err("clk: failed to reparent %s to %s: %d\n", + __clk_get_name(clk), __clk_get_name(pclk), rc); + clk_put(clk); + clk_put(pclk); + } + return 0; +err: + clk_put(pclk); + return rc; +} + +static int __set_clk_rates(struct device_node *node, bool clk_supplier) +{ + struct of_phandle_args clkspec; + struct property *prop; + const __be32 *cur; + int rc, index = 0; + struct clk *clk; + u32 rate; + + of_property_for_each_u32(node, "assigned-clock-rates", prop, cur, rate) { + if (rate) { + rc = of_parse_phandle_with_args(node, "assigned-clocks", + "#clock-cells", index, &clkspec); + if (rc < 0) { + /* skip empty (null) phandles */ + if (rc == -ENOENT) + continue; + else + return rc; + } + if (clkspec.np == node && !clk_supplier) + return 0; + + clk = of_clk_get_from_provider(&clkspec); + if (IS_ERR(clk)) { + pr_warn("clk: couldn't get clock %d for %s\n", + index, node->full_name); + return PTR_ERR(clk); + } + + rc = clk_set_rate(clk, rate); + if (rc < 0) + pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n", + __clk_get_name(clk), rate, rc, + clk_get_rate(clk)); + clk_put(clk); + } + index++; + } + return 0; +} + +/** + * of_clk_set_defaults() - parse and set assigned clocks configuration + * @node: device node to apply clock settings for + * @clk_supplier: true if clocks supplied by @node should also be considered + * + * This function parses 'assigned-{clocks/clock-parents/clock-rates}' properties + * and sets any specified clock parents and rates. The @clk_supplier argument + * should be set to true if @node may be also a clock supplier of any clock + * listed in its 'assigned-clocks' or 'assigned-clock-parents' properties. + * If @clk_supplier is false the function exits returning 0 as soon as it + * determines the @node is also a supplier of any of the clocks. + */ +int of_clk_set_defaults(struct device_node *node, bool clk_supplier) +{ + int rc; + + if (!node) + return 0; + + rc = __set_clk_parents(node, clk_supplier); + if (rc < 0) + return rc; + + return __set_clk_rates(node, clk_supplier); +} +EXPORT_SYMBOL_GPL(of_clk_set_defaults); + +#endif diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 19377b893c..1566beabda 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -21,6 +21,7 @@ #include #include #include +#include static LIST_HEAD(clks); @@ -527,6 +528,7 @@ int of_clk_init(struct device_node *root, const struct of_device_id *matches) if (force || parent_ready(clk_provider->np)) { clk_provider->clk_init_cb(clk_provider->np); + of_clk_set_defaults(clk_provider->np, true); list_del(&clk_provider->node); free(clk_provider); -- cgit v1.2.3 From e187942b9a8552b1ada3475af42aabe2f4335a62 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:13:58 -0800 Subject: i.MX: Move clk code from 'mach-imx' to 'drivers' Move clk code from 'mach-imx' to 'drivers' to keep the code tree structure closer to that of analogous one from Linux kernel and, arguably although subjective, to keep 'mach-imx' less cluttered. Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/Makefile | 22 +- arch/arm/mach-imx/clk-gate-exclusive.c | 103 ------- arch/arm/mach-imx/clk-gate2.c | 145 --------- arch/arm/mach-imx/clk-imx1.c | 121 -------- arch/arm/mach-imx/clk-imx21.c | 196 ------------ arch/arm/mach-imx/clk-imx25.c | 200 ------------ arch/arm/mach-imx/clk-imx27.c | 270 ---------------- arch/arm/mach-imx/clk-imx31.c | 146 --------- arch/arm/mach-imx/clk-imx35.c | 219 ------------- arch/arm/mach-imx/clk-imx5.c | 533 -------------------------------- arch/arm/mach-imx/clk-imx6.c | 541 --------------------------------- arch/arm/mach-imx/clk-imx6sx.c | 483 ----------------------------- arch/arm/mach-imx/clk-pfd.c | 148 --------- arch/arm/mach-imx/clk-pllv1.c | 95 ------ arch/arm/mach-imx/clk-pllv2.c | 230 -------------- arch/arm/mach-imx/clk-pllv3.c | 326 -------------------- arch/arm/mach-imx/clk.h | 104 ------- drivers/clk/Makefile | 1 + drivers/clk/imx/Makefile | 20 ++ drivers/clk/imx/clk-gate-exclusive.c | 103 +++++++ drivers/clk/imx/clk-gate2.c | 145 +++++++++ drivers/clk/imx/clk-imx1.c | 121 ++++++++ drivers/clk/imx/clk-imx21.c | 196 ++++++++++++ drivers/clk/imx/clk-imx25.c | 200 ++++++++++++ drivers/clk/imx/clk-imx27.c | 270 ++++++++++++++++ drivers/clk/imx/clk-imx31.c | 146 +++++++++ drivers/clk/imx/clk-imx35.c | 219 +++++++++++++ drivers/clk/imx/clk-imx5.c | 533 ++++++++++++++++++++++++++++++++ drivers/clk/imx/clk-imx6.c | 541 +++++++++++++++++++++++++++++++++ drivers/clk/imx/clk-imx6sx.c | 483 +++++++++++++++++++++++++++++ drivers/clk/imx/clk-pfd.c | 148 +++++++++ drivers/clk/imx/clk-pllv1.c | 95 ++++++ drivers/clk/imx/clk-pllv2.c | 230 ++++++++++++++ drivers/clk/imx/clk-pllv3.c | 326 ++++++++++++++++++++ drivers/clk/imx/clk.h | 104 +++++++ 35 files changed, 3891 insertions(+), 3872 deletions(-) delete mode 100644 arch/arm/mach-imx/clk-gate-exclusive.c delete mode 100644 arch/arm/mach-imx/clk-gate2.c delete mode 100644 arch/arm/mach-imx/clk-imx1.c delete mode 100644 arch/arm/mach-imx/clk-imx21.c delete mode 100644 arch/arm/mach-imx/clk-imx25.c delete mode 100644 arch/arm/mach-imx/clk-imx27.c delete mode 100644 arch/arm/mach-imx/clk-imx31.c delete mode 100644 arch/arm/mach-imx/clk-imx35.c delete mode 100644 arch/arm/mach-imx/clk-imx5.c delete mode 100644 arch/arm/mach-imx/clk-imx6.c delete mode 100644 arch/arm/mach-imx/clk-imx6sx.c delete mode 100644 arch/arm/mach-imx/clk-pfd.c delete mode 100644 arch/arm/mach-imx/clk-pllv1.c delete mode 100644 arch/arm/mach-imx/clk-pllv2.c delete mode 100644 arch/arm/mach-imx/clk-pllv3.c delete mode 100644 arch/arm/mach-imx/clk.h create mode 100644 drivers/clk/imx/Makefile create mode 100644 drivers/clk/imx/clk-gate-exclusive.c create mode 100644 drivers/clk/imx/clk-gate2.c create mode 100644 drivers/clk/imx/clk-imx1.c create mode 100644 drivers/clk/imx/clk-imx21.c create mode 100644 drivers/clk/imx/clk-imx25.c create mode 100644 drivers/clk/imx/clk-imx27.c create mode 100644 drivers/clk/imx/clk-imx31.c create mode 100644 drivers/clk/imx/clk-imx35.c create mode 100644 drivers/clk/imx/clk-imx5.c create mode 100644 drivers/clk/imx/clk-imx6.c create mode 100644 drivers/clk/imx/clk-imx6sx.c create mode 100644 drivers/clk/imx/clk-pfd.c create mode 100644 drivers/clk/imx/clk-pllv1.c create mode 100644 drivers/clk/imx/clk-pllv2.c create mode 100644 drivers/clk/imx/clk-pllv3.c create mode 100644 drivers/clk/imx/clk.h (limited to 'drivers') diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 1f1a099209..1a153250ab 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -1,26 +1,24 @@ obj-y += clocksource.o -obj-$(CONFIG_ARCH_IMX1) += imx1.o clk-imx1.o -obj-$(CONFIG_ARCH_IMX25) += imx25.o clk-imx25.o -obj-$(CONFIG_ARCH_IMX21) += imx21.o clk-imx21.o -obj-$(CONFIG_ARCH_IMX27) += imx27.o clk-imx27.o -obj-$(CONFIG_ARCH_IMX31) += imx31.o clk-imx31.o -obj-$(CONFIG_ARCH_IMX35) += imx35.o clk-imx35.o -obj-$(CONFIG_ARCH_IMX50) += imx50.o imx5.o clk-imx5.o +obj-$(CONFIG_ARCH_IMX1) += imx1.o +obj-$(CONFIG_ARCH_IMX25) += imx25.o +obj-$(CONFIG_ARCH_IMX21) += imx21.o +obj-$(CONFIG_ARCH_IMX27) += imx27.o +obj-$(CONFIG_ARCH_IMX31) += imx31.o +obj-$(CONFIG_ARCH_IMX35) += imx35.o +obj-$(CONFIG_ARCH_IMX50) += imx50.o imx5.o pbl-$(CONFIG_ARCH_IMX50) += imx50.o imx5.o -obj-$(CONFIG_ARCH_IMX51) += imx51.o imx5.o clk-imx5.o +obj-$(CONFIG_ARCH_IMX51) += imx51.o imx5.o pbl-$(CONFIG_ARCH_IMX51) += imx51.o imx5.o -obj-$(CONFIG_ARCH_IMX53) += imx53.o imx5.o clk-imx5.o esdctl-v4.o +obj-$(CONFIG_ARCH_IMX53) += imx53.o imx5.o esdctl-v4.o pbl-$(CONFIG_ARCH_IMX53) += imx53.o imx5.o esdctl-v4.o -obj-$(CONFIG_ARCH_IMX6) += imx6.o usb-imx6.o clk-imx6.o +obj-$(CONFIG_ARCH_IMX6) += imx6.o usb-imx6.o lwl-$(CONFIG_ARCH_IMX6) += imx6-mmdc.o -obj-$(CONFIG_ARCH_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_ARCH_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_ARCH_IMX_XLOAD) += xload.o obj-$(CONFIG_IMX_IIM) += iim.o obj-$(CONFIG_IMX_OCOTP) += ocotp.o obj-$(CONFIG_NAND_IMX) += nand.o lwl-$(CONFIG_ARCH_IMX_EXTERNAL_BOOT_NAND) += external-nand-boot.o -obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-pfd.o clk-gate2.o clk-gate-exclusive.o obj-y += devices.o imx.o obj-pbl-y += esdctl.o boot.o obj-$(CONFIG_BAREBOX_UPDATE) += imx-bbu-internal.o diff --git a/arch/arm/mach-imx/clk-gate-exclusive.c b/arch/arm/mach-imx/clk-gate-exclusive.c deleted file mode 100644 index db88db0237..0000000000 --- a/arch/arm/mach-imx/clk-gate-exclusive.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2014 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include - -#include "clk.h" - -/** - * struct clk_gate_exclusive - i.MX specific gate clock which is mutually - * exclusive with other gate clocks - * - * @gate: the parent class - * @exclusive_mask: mask of gate bits which are mutually exclusive to this - * gate clock - * - * The imx exclusive gate clock is a subclass of basic clk_gate - * with an addtional mask to indicate which other gate bits in the same - * register is mutually exclusive to this gate clock. - */ -struct clk_gate_exclusive { - struct clk clk; - void __iomem *reg; - int shift; - const char *parent; - u32 exclusive_mask; -}; - -static int clk_gate_exclusive_enable(struct clk *clk) -{ - struct clk_gate_exclusive *exgate = container_of(clk, - struct clk_gate_exclusive, clk); - u32 val = readl(exgate->reg); - - if (val & exgate->exclusive_mask) - return -EBUSY; - - val |= 1 << exgate->shift; - - writel(val, exgate->reg); - - return 0; -} - -static void clk_gate_exclusive_disable(struct clk *clk) -{ - struct clk_gate_exclusive *exgate = container_of(clk, - struct clk_gate_exclusive, clk); - u32 val = readl(exgate->reg); - - val &= ~(1 << exgate->shift); - - writel(val, exgate->reg); -} - -static int clk_gate_exclusive_is_enabled(struct clk *clk) -{ - struct clk_gate_exclusive *exgate = container_of(clk, - struct clk_gate_exclusive, clk); - - return readl(exgate->reg) & (1 << exgate->shift); -} - -static const struct clk_ops clk_gate_exclusive_ops = { - .enable = clk_gate_exclusive_enable, - .disable = clk_gate_exclusive_disable, - .is_enabled = clk_gate_exclusive_is_enabled, -}; - -struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, - void __iomem *reg, u8 shift, u32 exclusive_mask) -{ - struct clk_gate_exclusive *exgate; - int ret; - - exgate = xzalloc(sizeof(*exgate)); - exgate->parent = parent; - exgate->clk.name = name; - exgate->clk.ops = &clk_gate_exclusive_ops; - exgate->clk.flags = CLK_SET_RATE_PARENT; - exgate->clk.parent_names = &exgate->parent; - exgate->clk.num_parents = 1; - - exgate->reg = reg; - exgate->shift = shift; - exgate->exclusive_mask = exclusive_mask; - - ret = clk_register(&exgate->clk); - if (ret) { - free(exgate); - return ERR_PTR(ret); - } - - return &exgate->clk; -} diff --git a/arch/arm/mach-imx/clk-gate2.c b/arch/arm/mach-imx/clk-gate2.c deleted file mode 100644 index faed6313fb..0000000000 --- a/arch/arm/mach-imx/clk-gate2.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * clk-gate2.c - barebox 2-bit clock support. Based on Linux clk support - * - * 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; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include - -#include "clk.h" - - -struct clk_gate2 { - struct clk clk; - void __iomem *reg; - int shift; - const char *parent; -#define CLK_GATE_INVERTED (1 << 0) - unsigned flags; -}; - -#define to_clk_gate2(_clk) container_of(_clk, struct clk_gate2, clk) - -static int clk_gate2_enable(struct clk *clk) -{ - struct clk_gate2 *g = to_clk_gate2(clk); - u32 val; - - val = readl(g->reg); - - if (g->flags & CLK_GATE_INVERTED) - val &= ~(3 << g->shift); - else - val |= 3 << g->shift; - - writel(val, g->reg); - - return 0; -} - -static void clk_gate2_disable(struct clk *clk) -{ - struct clk_gate2 *g = to_clk_gate2(clk); - u32 val; - - val = readl(g->reg); - - if (g->flags & CLK_GATE_INVERTED) - val |= 3 << g->shift; - else - val &= ~(3 << g->shift); - - writel(val, g->reg); -} - -static int clk_gate2_is_enabled(struct clk *clk) -{ - struct clk_gate2 *g = to_clk_gate2(clk); - u32 val; - - val = readl(g->reg); - - if (val & (1 << g->shift)) - return g->flags & CLK_GATE_INVERTED ? 0 : 1; - else - return g->flags & CLK_GATE_INVERTED ? 1 : 0; -} - -static struct clk_ops clk_gate2_ops = { - .set_rate = clk_parent_set_rate, - .round_rate = clk_parent_round_rate, - .enable = clk_gate2_enable, - .disable = clk_gate2_disable, - .is_enabled = clk_gate2_is_enabled, -}; - -struct clk *clk_gate2_alloc(const char *name, const char *parent, - void __iomem *reg, u8 shift) -{ - struct clk_gate2 *g = xzalloc(sizeof(*g)); - - g->parent = parent; - g->reg = reg; - g->shift = shift; - g->clk.ops = &clk_gate2_ops; - g->clk.name = name; - g->clk.parent_names = &g->parent; - g->clk.num_parents = 1; - g->clk.flags = CLK_SET_RATE_PARENT; - - return &g->clk; -} - -void clk_gate2_free(struct clk *clk) -{ - struct clk_gate2 *g = to_clk_gate2(clk); - - free(g); -} - -struct clk *clk_gate2(const char *name, const char *parent, void __iomem *reg, - u8 shift) -{ - struct clk *g; - int ret; - - g = clk_gate2_alloc(name , parent, reg, shift); - - ret = clk_register(g); - if (ret) { - free(to_clk_gate2(g)); - return ERR_PTR(ret); - } - - return g; -} - -struct clk *clk_gate2_inverted(const char *name, const char *parent, - void __iomem *reg, u8 shift) -{ - struct clk *clk; - struct clk_gate2 *g; - - clk = clk_gate2(name, parent, reg, shift); - if (IS_ERR(clk)) - return clk; - - g = to_clk_gate2(clk); - - g->flags = CLK_GATE_INVERTED; - - return clk; -} diff --git a/arch/arm/mach-imx/clk-imx1.c b/arch/arm/mach-imx/clk-imx1.c deleted file mode 100644 index 5f600a9da3..0000000000 --- a/arch/arm/mach-imx/clk-imx1.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2008 Sascha Hauer , Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -#define CCM_CSCR 0x0 -#define CCM_MPCTL0 0x4 -#define CCM_SPCTL0 0xc -#define CCM_PCDR 0x20 - -enum imx1_clks { - dummy, clk32, clk16m, clk32_premult, prem, mpll, spll, mcu, - fclk, hclk, clk48m, per1, per2, per3, clko, dma_gate, csi_gate, - mma_gate, usbd_gate, clk_max -}; - -static struct clk *clks[clk_max]; - -static const char *prem_sel_clks[] = { - "clk32_premult", - "clk16m", -}; - -static const char *clko_sel_clks[] = { - "per1", - "hclk", - "clk48m", - "clk16m", - "prem", - "fclk", -}; - -int __init mx1_clocks_init(void __iomem *regs, unsigned long fref) -{ - clks[dummy] = clk_fixed("dummy", 0); - clks[clk32] = clk_fixed("clk32", fref); - clks[clk16m] = clk_fixed("clk16m", 16000000); - clks[clk32_premult] = imx_clk_fixed_factor("clk32_premult", "clk32", 512, 1); - clks[prem] = imx_clk_mux("prem", regs + CCM_CSCR, 16, 1, prem_sel_clks, - ARRAY_SIZE(prem_sel_clks)); - clks[mpll] = imx_clk_pllv1("mpll", "clk32_premult", regs + CCM_MPCTL0); - clks[spll] = imx_clk_pllv1("spll", "prem", regs + CCM_SPCTL0); - clks[mcu] = imx_clk_divider("mcu", "clk32_premult", regs + CCM_CSCR, 15, 1); - clks[fclk] = imx_clk_divider("fclk", "mpll", regs + CCM_CSCR, 15, 1); - clks[hclk] = imx_clk_divider("hclk", "spll", regs + CCM_CSCR, 10, 4); - clks[clk48m] = imx_clk_divider("clk48m", "spll", regs + CCM_CSCR, 26, 3); - clks[per1] = imx_clk_divider("per1", "spll", regs + CCM_PCDR, 0, 4); - clks[per2] = imx_clk_divider("per2", "spll", regs + CCM_PCDR, 4, 4); - clks[per3] = imx_clk_divider("per3", "spll", regs + CCM_PCDR, 16, 7); - clks[clko] = imx_clk_mux("clko", regs + CCM_CSCR, 29, 3, clko_sel_clks, - ARRAY_SIZE(clko_sel_clks)); - - clkdev_add_physbase(clks[per1], MX1_TIM1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1], MX1_TIM2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per2], MX1_LCDC_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1], MX1_UART1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1], MX1_UART2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per2], MX1_CSPI1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per2], MX1_CSPI2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[hclk], MX1_I2C_BASE_ADDR, NULL); - - return 0; -} - -static int imx1_ccm_probe(struct device_d *dev) -{ - struct resource *iores; - void __iomem *regs; - - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - regs = IOMEM(iores->start); - - mx1_clocks_init(regs, 32000); - - return 0; -} - -static __maybe_unused struct of_device_id imx1_ccm_dt_ids[] = { - { - .compatible = "fsl,imx1-ccm", - }, { - /* sentinel */ - } -}; - -static struct driver_d imx1_ccm_driver = { - .probe = imx1_ccm_probe, - .name = "imx1-ccm", - .of_compatible = DRV_OF_COMPAT(imx1_ccm_dt_ids), -}; - -static int imx1_ccm_init(void) -{ - return platform_driver_register(&imx1_ccm_driver); -} -core_initcall(imx1_ccm_init); diff --git a/arch/arm/mach-imx/clk-imx21.c b/arch/arm/mach-imx/clk-imx21.c deleted file mode 100644 index 546461b8ee..0000000000 --- a/arch/arm/mach-imx/clk-imx21.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright 2008 Juergen Beisert, kernel@pengutronix.de - * Copyright 2008 Martin Fuzzey, mfuzzey@gmail.com - * - * 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; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -/* Register offsets */ -#define CCM_CSCR 0x0 -#define CCM_MPCTL0 0x4 -#define CCM_MPCTL1 0x8 -#define CCM_SPCTL0 0xc -#define CCM_SPCTL1 0x10 -#define CCM_OSC26MCTL 0x14 -#define CCM_PCDR0 0x18 -#define CCM_PCDR1 0x1c -#define CCM_PCCR0 0x20 -#define CCM_PCCR1 0x24 -#define CCM_CCSR 0x28 -#define CCM_PMCTL 0x2c -#define CCM_PMCOUNT 0x30 -#define CCM_WKGDCTL 0x34 - -#define PCCR0_UART1_EN (1 << 0) -#define PCCR0_UART2_EN (1 << 1) -#define PCCR0_UART3_EN (1 << 2) -#define PCCR0_UART4_EN (1 << 3) -#define PCCR0_CSPI1_EN (1 << 4) -#define PCCR0_CSPI2_EN (1 << 5) -#define PCCR0_SSI1_EN (1 << 6) -#define PCCR0_SSI2_EN (1 << 7) -#define PCCR0_FIRI_EN (1 << 8) -#define PCCR0_SDHC1_EN (1 << 9) -#define PCCR0_SDHC2_EN (1 << 10) -#define PCCR0_GPIO_EN (1 << 11) -#define PCCR0_I2C_EN (1 << 12) -#define PCCR0_DMA_EN (1 << 13) -#define PCCR0_USBOTG_EN (1 << 14) -#define PCCR0_EMMA_EN (1 << 15) -#define PCCR0_SSI2_BAUD_EN (1 << 16) -#define PCCR0_SSI1_BAUD_EN (1 << 17) -#define PCCR0_PERCLK3_EN (1 << 18) -#define PCCR0_NFC_EN (1 << 19) -#define PCCR0_FRI_BAUD_EN (1 << 20) -#define PCCR0_SLDC_EN (1 << 21) -#define PCCR0_PERCLK4_EN (1 << 22) -#define PCCR0_HCLK_BMI_EN (1 << 23) -#define PCCR0_HCLK_USBOTG_EN (1 << 24) -#define PCCR0_HCLK_SLCDC_EN (1 << 25) -#define PCCR0_HCLK_LCDC_EN (1 << 26) -#define PCCR0_HCLK_EMMA_EN (1 << 27) -#define PCCR0_HCLK_BROM_EN (1 << 28) -#define PCCR0_HCLK_DMA_EN (1 << 30) -#define PCCR0_HCLK_CSI_EN (1 << 31) - -#define PCCR1_CSPI3_EN (1 << 23) -#define PCCR1_WDT_EN (1 << 24) -#define PCCR1_GPT1_EN (1 << 25) -#define PCCR1_GPT2_EN (1 << 26) -#define PCCR1_GPT3_EN (1 << 27) -#define PCCR1_PWM_EN (1 << 28) -#define PCCR1_RTC_EN (1 << 29) -#define PCCR1_KPP_EN (1 << 30) -#define PCCR1_OWIRE_EN (1 << 31) - -enum imx21_clks { - ckil, ckih, fpm, mpll_sel, spll_sel, mpll, spll, fclk, hclk, ipg, per1, - per2, per3, per4, usb_div, nfc_div, lcdc_per_gate, lcdc_ahb_gate, - lcdc_ipg_gate, clk_max -}; - -static struct clk *clks[clk_max]; - -static const char *mpll_sel_clks[] = { - "fpm", - "ckih", -}; - -static const char *spll_sel_clks[] = { - "fpm", - "ckih", -}; - -static int imx21_ccm_probe(struct device_d *dev) -{ - struct resource *iores; - void __iomem *base; - unsigned long lref = 32768; - unsigned long href = 26000000; - - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - base = IOMEM(iores->start); - - writel(PCCR0_UART1_EN | PCCR0_UART2_EN | PCCR0_UART3_EN | PCCR0_UART4_EN | - PCCR0_CSPI1_EN | PCCR0_CSPI2_EN | PCCR0_SDHC1_EN | - PCCR0_SDHC2_EN | PCCR0_GPIO_EN | PCCR0_I2C_EN | PCCR0_DMA_EN | - PCCR0_USBOTG_EN | PCCR0_NFC_EN | PCCR0_PERCLK4_EN | - PCCR0_HCLK_USBOTG_EN | PCCR0_HCLK_DMA_EN, - base + CCM_PCCR0); - - writel(PCCR1_CSPI3_EN | PCCR1_WDT_EN | PCCR1_GPT1_EN | PCCR1_GPT2_EN | - PCCR1_GPT3_EN | PCCR1_PWM_EN | PCCR1_RTC_EN | PCCR1_KPP_EN | - PCCR1_OWIRE_EN, - base + CCM_PCCR1); - - clks[ckil] = clk_fixed("ckil", lref); - clks[ckih] = clk_fixed("ckih", href); - clks[fpm] = imx_clk_fixed_factor("fpm", "ckil", 512, 1); - clks[mpll_sel] = imx_clk_mux("mpll_sel", base + CCM_CSCR, 16, 1, mpll_sel_clks, - ARRAY_SIZE(mpll_sel_clks)); - clks[spll_sel] = imx_clk_mux("spll_sel", base + CCM_CSCR, 17, 1, spll_sel_clks, - ARRAY_SIZE(spll_sel_clks)); - clks[mpll] = imx_clk_pllv1("mpll", "mpll_sel", base + CCM_MPCTL0); - clks[spll] = imx_clk_pllv1("spll", "spll_sel", base + CCM_SPCTL0); - clks[fclk] = imx_clk_divider("fclk", "mpll", base + CCM_CSCR, 29, 3); - clks[hclk] = imx_clk_divider("hclk", "fclk", base + CCM_CSCR, 10, 4); - clks[ipg] = imx_clk_divider("ipg", "hclk", base + CCM_CSCR, 9, 1); - clks[per1] = imx_clk_divider("per1", "mpll", base + CCM_PCDR1, 0, 6); - clks[per2] = imx_clk_divider("per2", "mpll", base + CCM_PCDR1, 8, 6); - clks[per3] = imx_clk_divider("per3", "mpll", base + CCM_PCDR1, 16, 6); - clks[per4] = imx_clk_divider("per4", "mpll", base + CCM_PCDR1, 24, 6); - clks[usb_div] = imx_clk_divider("usb_div", "spll", base + CCM_CSCR, 26, 3); - clks[nfc_div] = imx_clk_divider("nfc_div", "ipg", base + CCM_PCDR0, 12, 4); - clks[lcdc_per_gate] = imx_clk_gate("lcdc_per_gate", "per3", base + CCM_PCCR0, 18); - clks[lcdc_ahb_gate] = imx_clk_gate("lcdc_ahb_gate", "ahb", base + CCM_PCCR0, 26); - /* - * i.MX21 doesn't have an IPG clock for the LCD. To avoid even more conditionals - * in the framebuffer code, provide a dummy clock. - */ - clks[lcdc_ipg_gate] = clk_fixed("dummy", 0); - - clkdev_add_physbase(clks[per1], MX21_GPT1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1], MX21_GPT2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1], MX21_GPT3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1], MX21_UART1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1], MX21_UART2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1], MX21_UART3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1], MX21_UART4_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per2], MX21_CSPI1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per2], MX21_CSPI2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per2], MX21_CSPI3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX21_I2C_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX21_SDHC1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX21_SDHC2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[lcdc_per_gate], MX21_LCDC_BASE_ADDR, "per"); - clkdev_add_physbase(clks[lcdc_ahb_gate], MX21_LCDC_BASE_ADDR, "ahb"); - clkdev_add_physbase(clks[lcdc_ipg_gate], MX21_LCDC_BASE_ADDR, "ipg"); - - return 0; -} - -static __maybe_unused struct of_device_id imx21_ccm_dt_ids[] = { - { - .compatible = "fsl,imx21-ccm", - }, { - /* sentinel */ - } -}; - -static struct driver_d imx21_ccm_driver = { - .probe = imx21_ccm_probe, - .name = "imx21-ccm", - .of_compatible = DRV_OF_COMPAT(imx21_ccm_dt_ids), -}; - -static int imx21_ccm_init(void) -{ - return platform_driver_register(&imx21_ccm_driver); -} -core_initcall(imx21_ccm_init); diff --git a/arch/arm/mach-imx/clk-imx25.c b/arch/arm/mach-imx/clk-imx25.c deleted file mode 100644 index 864d06e195..0000000000 --- a/arch/arm/mach-imx/clk-imx25.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2009 by Sascha Hauer, Pengutronix - * - * 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; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -#define CCM_MPCTL 0x00 -#define CCM_UPCTL 0x04 -#define CCM_CCTL 0x08 -#define CCM_CGCR0 0x0C -#define CCM_CGCR1 0x10 -#define CCM_CGCR2 0x14 -#define CCM_PCDR0 0x18 -#define CCM_PCDR1 0x1C -#define CCM_PCDR2 0x20 -#define CCM_PCDR3 0x24 -#define CCM_RCSR 0x28 -#define CCM_CRDR 0x2C -#define CCM_DCVR0 0x30 -#define CCM_DCVR1 0x34 -#define CCM_DCVR2 0x38 -#define CCM_DCVR3 0x3c -#define CCM_LTR0 0x40 -#define CCM_LTR1 0x44 -#define CCM_LTR2 0x48 -#define CCM_LTR3 0x4c -#define CCM_MCR 0x64 - -enum mx25_clks { - dummy, osc, mpll, upll, mpll_cpu_3_4, cpu_sel, cpu, ahb, usb_div, ipg, - per0_sel, per1_sel, per2_sel, per3_sel, per4_sel, per5_sel, per6_sel, - per7_sel, per8_sel, per9_sel, per10_sel, per11_sel, per12_sel, - per13_sel, per14_sel, per15_sel, per0, per1, per2, per3, per4, per5, - per6, per7, per8, per9, per10, per11, per12, per13, per14, per15, - csi_ipg_per, epit_ipg_per, esai_ipg_per, esdhc1_ipg_per, esdhc2_ipg_per, - gpt_ipg_per, i2c_ipg_per, lcdc_ipg_per, nfc_ipg_per, owire_ipg_per, - pwm_ipg_per, sim1_ipg_per, sim2_ipg_per, ssi1_ipg_per, ssi2_ipg_per, - uart_ipg_per, ata_ahb, reserved1, csi_ahb, emi_ahb, esai_ahb, esdhc1_ahb, - esdhc2_ahb, fec_ahb, lcdc_ahb, rtic_ahb, sdma_ahb, slcdc_ahb, usbotg_ahb, - reserved2, reserved3, reserved4, reserved5, can1_ipg, can2_ipg, csi_ipg, - cspi1_ipg, cspi2_ipg, cspi3_ipg, dryice_ipg, ect_ipg, epit1_ipg, epit2_ipg, - reserved6, esdhc1_ipg, esdhc2_ipg, fec_ipg, reserved7, reserved8, reserved9, - gpt1_ipg, gpt2_ipg, gpt3_ipg, gpt4_ipg, reserved10, reserved11, reserved12, - iim_ipg, reserved13, reserved14, kpp_ipg, lcdc_ipg, reserved15, pwm1_ipg, - pwm2_ipg, pwm3_ipg, pwm4_ipg, rngb_ipg, reserved16, scc_ipg, sdma_ipg, - sim1_ipg, sim2_ipg, slcdc_ipg, spba_ipg, ssi1_ipg, ssi2_ipg, tsc_ipg, - uart1_ipg, uart2_ipg, uart3_ipg, uart4_ipg, uart5_ipg, reserved17, - wdt_ipg, clk_max -}; - -static struct clk *clks[clk_max]; - -static const char *cpu_sel_clks[] = { - "mpll", - "mpll_cpu_3_4", -}; - -static const char *per_sel_clks[] = { - "ahb", - "upll", -}; - -static int imx25_ccm_probe(struct device_d *dev) -{ - struct resource *iores; - void __iomem *base; - - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - base = IOMEM(iores->start); - - writel((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 8) | (1 << 9) | - (1 << 10) | (1 << 15) | (1 << 19) | (1 << 21) | (1 << 22) | - (1 << 23) | (1 << 24) | (1 << 28), - base + CCM_CGCR0); - - writel((1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 13) | (1 << 14) | - (1 << 15) | (1 << 19) | (1 << 20) | (1 << 21) | (1 << 22) | - (1 << 26) | (1 << 31), - base + CCM_CGCR1); - - writel((1 << 0) | (1 << 1) | (1 << 2) | (1 << 10) | (1 << 13) | (1 << 14) | - (1 << 15) | (1 << 16) | (1 << 17) | (1 << 18), - base + CCM_CGCR2); - - clks[dummy] = clk_fixed("dummy", 0); - clks[osc] = clk_fixed("osc", 24000000); - clks[mpll] = imx_clk_pllv1("mpll", "osc", base + CCM_MPCTL); - clks[upll] = imx_clk_pllv1("upll", "osc", base + CCM_UPCTL); - clks[mpll_cpu_3_4] = imx_clk_fixed_factor("mpll_cpu_3_4", "mpll", 3, 4); - clks[cpu_sel] = imx_clk_mux("cpu_sel", base + CCM_CCTL, 14, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks)); - clks[cpu] = imx_clk_divider("cpu", "cpu_sel", base + CCM_CCTL, 30, 2); - clks[ahb] = imx_clk_divider("ahb", "cpu", base + CCM_CCTL, 28, 2); - clks[usb_div] = imx_clk_divider("usb_div", "upll", base + CCM_CCTL, 16, 6); - clks[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2); - clks[per0_sel] = imx_clk_mux("per0_sel", base + CCM_MCR, 0, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per1_sel] = imx_clk_mux("per1_sel", base + CCM_MCR, 1, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per2_sel] = imx_clk_mux("per2_sel", base + CCM_MCR, 2, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per3_sel] = imx_clk_mux("per3_sel", base + CCM_MCR, 3, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per4_sel] = imx_clk_mux("per4_sel", base + CCM_MCR, 4, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per5_sel] = imx_clk_mux("per5_sel", base + CCM_MCR, 5, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per6_sel] = imx_clk_mux("per6_sel", base + CCM_MCR, 6, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per7_sel] = imx_clk_mux("per7_sel", base + CCM_MCR, 7, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per8_sel] = imx_clk_mux("per8_sel", base + CCM_MCR, 8, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per9_sel] = imx_clk_mux("per9_sel", base + CCM_MCR, 9, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per10_sel] = imx_clk_mux("per10_sel", base + CCM_MCR, 10, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per11_sel] = imx_clk_mux("per11_sel", base + CCM_MCR, 11, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per12_sel] = imx_clk_mux("per12_sel", base + CCM_MCR, 12, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per13_sel] = imx_clk_mux("per13_sel", base + CCM_MCR, 13, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per14_sel] = imx_clk_mux("per14_sel", base + CCM_MCR, 14, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per15_sel] = imx_clk_mux("per15_sel", base + CCM_MCR, 15, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); - clks[per0] = imx_clk_divider("per0", "per0_sel", base + CCM_PCDR0, 0, 6); - clks[per1] = imx_clk_divider("per1", "per1_sel", base + CCM_PCDR0, 8, 6); - clks[per2] = imx_clk_divider("per2", "per2_sel", base + CCM_PCDR0, 16, 6); - clks[per3] = imx_clk_divider("per3", "per3_sel", base + CCM_PCDR0, 24, 6); - clks[per4] = imx_clk_divider("per4", "per4_sel", base + CCM_PCDR1, 0, 6); - clks[per5] = imx_clk_divider("per5", "per5_sel", base + CCM_PCDR1, 8, 6); - clks[per6] = imx_clk_divider("per6", "per6_sel", base + CCM_PCDR1, 16, 6); - clks[per7] = imx_clk_divider("per7", "per7_sel", base + CCM_PCDR1, 24, 6); - clks[per8] = imx_clk_divider("per8", "per8_sel", base + CCM_PCDR2, 0, 6); - clks[per9] = imx_clk_divider("per9", "per9_sel", base + CCM_PCDR2, 8, 6); - clks[per10] = imx_clk_divider("per10", "per10_sel", base + CCM_PCDR2, 16, 6); - clks[per11] = imx_clk_divider("per11", "per11_sel", base + CCM_PCDR2, 24, 6); - clks[per12] = imx_clk_divider("per12", "per12_sel", base + CCM_PCDR3, 0, 6); - clks[per13] = imx_clk_divider("per13", "per13_sel", base + CCM_PCDR3, 8, 6); - clks[per14] = imx_clk_divider("per14", "per14_sel", base + CCM_PCDR3, 16, 6); - clks[per15] = imx_clk_divider("per15", "per15_sel", base + CCM_PCDR3, 24, 6); - clks[lcdc_ahb] = imx_clk_gate("lcdc_ahb", "ahb", base + CCM_CGCR0, 24); - clks[lcdc_ipg] = imx_clk_gate("lcdc_ipg", "ipg", base + CCM_CGCR1, 29); - clks[lcdc_ipg_per] = imx_clk_gate("lcdc_ipg_per", "per7", base + CCM_CGCR0, 7); - - clkdev_add_physbase(clks[per15], MX25_UART1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per15], MX25_UART2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per15], MX25_UART3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per15], MX25_UART4_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per15], MX25_UART5_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per5], MX25_GPT1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per5], MX25_GPT2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per5], MX25_GPT3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per5], MX25_GPT4_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX25_FEC_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX25_I2C1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX25_I2C2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX25_I2C3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX25_CSPI1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX25_CSPI2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX25_CSPI3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per3], MX25_ESDHC1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per4], MX25_ESDHC2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per8], MX25_NFC_BASE_ADDR, NULL); - clkdev_add_physbase(clks[lcdc_ipg_per], MX25_LCDC_BASE_ADDR, "per"); - clkdev_add_physbase(clks[lcdc_ipg], MX25_LCDC_BASE_ADDR, "ipg"); - clkdev_add_physbase(clks[lcdc_ahb], MX25_LCDC_BASE_ADDR, "ahb"); - - return 0; -} - -static __maybe_unused struct of_device_id imx25_ccm_dt_ids[] = { - { - .compatible = "fsl,imx25-ccm", - }, { - /* sentinel */ - } -}; - -static struct driver_d imx25_ccm_driver = { - .probe = imx25_ccm_probe, - .name = "imx25-ccm", - .of_compatible = DRV_OF_COMPAT(imx25_ccm_dt_ids), -}; - -static int imx25_ccm_init(void) -{ - return platform_driver_register(&imx25_ccm_driver); -} -core_initcall(imx25_ccm_init); diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c deleted file mode 100644 index 4b63244211..0000000000 --- a/arch/arm/mach-imx/clk-imx27.c +++ /dev/null @@ -1,270 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -/* Register offsets */ -#define CCM_CSCR 0x0 -#define CCM_MPCTL0 0x4 -#define CCM_MPCTL1 0x8 -#define CCM_SPCTL0 0xc -#define CCM_SPCTL1 0x10 -#define CCM_OSC26MCTL 0x14 -#define CCM_PCDR0 0x18 -#define CCM_PCDR1 0x1c -#define CCM_PCCR0 0x20 -#define CCM_PCCR1 0x24 -#define CCM_CCSR 0x28 -#define CCM_PMCTL 0x2c -#define CCM_PMCOUNT 0x30 -#define CCM_WKGDCTL 0x34 - -#define PCCR0_SSI2_EN (1 << 0) -#define PCCR0_SSI1_EN (1 << 1) -#define PCCR0_SLCDC_EN (1 << 2) -#define PCCR0_SDHC3_EN (1 << 3) -#define PCCR0_SDHC2_EN (1 << 4) -#define PCCR0_SDHC1_EN (1 << 5) -#define PCCR0_SDC_EN (1 << 6) -#define PCCR0_SAHARA_EN (1 << 7) -#define PCCR0_RTIC_EN (1 << 8) -#define PCCR0_RTC_EN (1 << 9) -#define PCCR0_PWM_EN (1 << 11) -#define PCCR0_OWIRE_EN (1 << 12) -#define PCCR0_MSHC_EN (1 << 13) -#define PCCR0_LCDC_EN (1 << 14) -#define PCCR0_KPP_EN (1 << 15) -#define PCCR0_IIM_EN (1 << 16) -#define PCCR0_I2C2_EN (1 << 17) -#define PCCR0_I2C1_EN (1 << 18) -#define PCCR0_GPT6_EN (1 << 19) -#define PCCR0_GPT5_EN (1 << 20) -#define PCCR0_GPT4_EN (1 << 21) -#define PCCR0_GPT3_EN (1 << 22) -#define PCCR0_GPT2_EN (1 << 23) -#define PCCR0_GPT1_EN (1 << 24) -#define PCCR0_GPIO_EN (1 << 25) -#define PCCR0_FEC_EN (1 << 26) -#define PCCR0_EMMA_EN (1 << 27) -#define PCCR0_DMA_EN (1 << 28) -#define PCCR0_CSPI3_EN (1 << 29) -#define PCCR0_CSPI2_EN (1 << 30) -#define PCCR0_CSPI1_EN (1 << 31) - -#define PCCR1_MSHC_BAUDEN (1 << 2) -#define PCCR1_NFC_BAUDEN (1 << 3) -#define PCCR1_SSI2_BAUDEN (1 << 4) -#define PCCR1_SSI1_BAUDEN (1 << 5) -#define PCCR1_H264_BAUDEN (1 << 6) -#define PCCR1_PERCLK4_EN (1 << 7) -#define PCCR1_PERCLK3_EN (1 << 8) -#define PCCR1_PERCLK2_EN (1 << 9) -#define PCCR1_PERCLK1_EN (1 << 10) -#define PCCR1_HCLK_USB (1 << 11) -#define PCCR1_HCLK_SLCDC (1 << 12) -#define PCCR1_HCLK_SAHARA (1 << 13) -#define PCCR1_HCLK_RTIC (1 << 14) -#define PCCR1_HCLK_LCDC (1 << 15) -#define PCCR1_HCLK_H264 (1 << 16) -#define PCCR1_HCLK_FEC (1 << 17) -#define PCCR1_HCLK_EMMA (1 << 18) -#define PCCR1_HCLK_EMI (1 << 19) -#define PCCR1_HCLK_DMA (1 << 20) -#define PCCR1_HCLK_CSI (1 << 21) -#define PCCR1_HCLK_BROM (1 << 22) -#define PCCR1_HCLK_ATA (1 << 23) -#define PCCR1_WDT_EN (1 << 24) -#define PCCR1_USB_EN (1 << 25) -#define PCCR1_UART6_EN (1 << 26) -#define PCCR1_UART5_EN (1 << 27) -#define PCCR1_UART4_EN (1 << 28) -#define PCCR1_UART3_EN (1 << 29) -#define PCCR1_UART2_EN (1 << 30) -#define PCCR1_UART1_EN (1 << 31) - -enum mx27_clks { - dummy, ckih, ckil, mpll, spll, mpll_main2, ahb, ipg, nfc_div, per1_div, - per2_div, per3_div, per4_div, vpu_sel, vpu_div, usb_div, cpu_sel, - clko_sel, cpu_div, clko_div, ssi1_sel, ssi2_sel, ssi1_div, ssi2_div, - clko_en, ssi2_ipg_gate, ssi1_ipg_gate, slcdc_ipg_gate, sdhc3_ipg_gate, - sdhc2_ipg_gate, sdhc1_ipg_gate, scc_ipg_gate, sahara_ipg_gate, - rtc_ipg_gate, pwm_ipg_gate, owire_ipg_gate, lcdc_ipg_gate, - kpp_ipg_gate, iim_ipg_gate, i2c2_ipg_gate, i2c1_ipg_gate, - gpt6_ipg_gate, gpt5_ipg_gate, gpt4_ipg_gate, gpt3_ipg_gate, - gpt2_ipg_gate, gpt1_ipg_gate, gpio_ipg_gate, fec_ipg_gate, - emma_ipg_gate, dma_ipg_gate, cspi3_ipg_gate, cspi2_ipg_gate, - cspi1_ipg_gate, nfc_baud_gate, ssi2_baud_gate, ssi1_baud_gate, - vpu_baud_gate, per4_gate, per3_gate, per2_gate, per1_gate, - usb_ahb_gate, slcdc_ahb_gate, sahara_ahb_gate, lcdc_ahb_gate, - vpu_ahb_gate, fec_ahb_gate, emma_ahb_gate, emi_ahb_gate, dma_ahb_gate, - csi_ahb_gate, brom_ahb_gate, ata_ahb_gate, wdog_ipg_gate, usb_ipg_gate, - uart6_ipg_gate, uart5_ipg_gate, uart4_ipg_gate, uart3_ipg_gate, - uart2_ipg_gate, uart1_ipg_gate, ckih_div1p5, fpm, mpll_osc_sel, - mpll_sel, spll_gate, clk_max -}; - -static struct clk *clks[clk_max]; - -static const char *cpu_sel_clks[] = { - "mpll_main2", - "mpll", -}; - -static const char *mpll_sel_clks[] = { - "fpm", - "mpll_osc_sel", -}; - -static const char *mpll_osc_sel_clks[] = { - "ckih", - "ckih_div1p5", -}; - -static const char *clko_sel_clks[] = { - "ckil", - NULL, - "ckih", - "ckih", - "ckih", - "mpll", - "spll", - "cpu_div", - "ahb", - "ipg", - "per1_div", - "per2_div", - "per3_div", - "per4_div", - NULL, - NULL, - "nfc_div", - NULL, - NULL, - NULL, - "ckil", - "usb_div", - NULL, -}; - -static int imx27_ccm_probe(struct device_d *dev) -{ - struct resource *iores; - void __iomem *base; - - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - base = IOMEM(iores->start); - - writel(PCCR0_SDHC3_EN | PCCR0_SDHC2_EN | PCCR0_SDHC1_EN | - PCCR0_PWM_EN | PCCR0_KPP_EN | PCCR0_IIM_EN | - PCCR0_I2C2_EN | PCCR0_I2C1_EN | PCCR0_GPT6_EN | PCCR0_GPT5_EN | - PCCR0_GPT4_EN | PCCR0_GPT3_EN | PCCR0_GPT2_EN | PCCR0_GPT1_EN | - PCCR0_GPIO_EN | PCCR0_FEC_EN | PCCR0_CSPI3_EN | PCCR0_CSPI2_EN | - PCCR0_CSPI1_EN, - base + CCM_PCCR0); - - writel(PCCR1_NFC_BAUDEN | PCCR1_PERCLK4_EN | PCCR1_PERCLK2_EN | PCCR1_PERCLK1_EN | - PCCR1_HCLK_USB | PCCR1_HCLK_FEC | PCCR1_HCLK_EMI | PCCR1_WDT_EN | - PCCR1_USB_EN | PCCR1_UART6_EN | PCCR1_UART5_EN | PCCR1_UART4_EN | - PCCR1_UART3_EN | PCCR1_UART2_EN | PCCR1_UART1_EN, - base + CCM_PCCR1); - - clks[dummy] = clk_fixed("dummy", 0); - clks[ckih] = clk_fixed("ckih", 26000000); - clks[ckil] = clk_fixed("ckil", 32768); - clks[fpm] = imx_clk_fixed_factor("fpm", "ckil", 1024, 1); - clks[ckih_div1p5] = imx_clk_fixed_factor("ckih_div1p5", "ckih", 2, 3); - - clks[mpll_osc_sel] = imx_clk_mux("mpll_osc_sel", base + CCM_CSCR, 4, 1, - mpll_osc_sel_clks, - ARRAY_SIZE(mpll_osc_sel_clks)); - clks[mpll_sel] = imx_clk_mux("mpll_sel", base + CCM_CSCR, 16, 1, mpll_sel_clks, - ARRAY_SIZE(mpll_sel_clks)); - - clks[mpll] = imx_clk_pllv1("mpll", "mpll_sel", base + CCM_MPCTL0); - clks[spll] = imx_clk_pllv1("spll", "ckih", base + CCM_SPCTL0); - clks[mpll_main2] = imx_clk_fixed_factor("mpll_main2", "mpll", 2, 3); - - if (imx_silicon_revision() >= IMX_CHIP_REV_2_0) { - clks[ahb] = imx_clk_divider("ahb", "mpll_main2", base + CCM_CSCR, 8, 2); - clks[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2); - } else { - clks[ahb] = imx_clk_divider("ahb", "mpll_main2", base + CCM_CSCR, 9, 4); - clks[ipg] = imx_clk_divider("ipg", "ahb", base + CCM_CSCR, 8, 1); - } - - clks[nfc_div] = imx_clk_divider("nfc_div", "ahb", base + CCM_PCDR0, 6, 4); - clks[per1_div] = imx_clk_divider("per1_div", "mpll_main2", base + CCM_PCDR1, 0, 6); - clks[per2_div] = imx_clk_divider("per2_div", "mpll_main2", base + CCM_PCDR1, 8, 6); - clks[per3_div] = imx_clk_divider("per3_div", "mpll_main2", base + CCM_PCDR1, 16, 6); - clks[per4_div] = imx_clk_divider("per4_div", "mpll_main2", base + CCM_PCDR1, 24, 6); - clks[usb_div] = imx_clk_divider("usb_div", "spll", base + CCM_CSCR, 28, 3); - clks[cpu_sel] = imx_clk_mux("cpu_sel", base + CCM_CSCR, 15, 1, cpu_sel_clks, - ARRAY_SIZE(cpu_sel_clks)); - clks[clko_sel] = imx_clk_mux("clko_sel", base + CCM_CCSR, 0, 5, clko_sel_clks, - ARRAY_SIZE(clko_sel_clks)); - if (imx_silicon_revision() >= IMX_CHIP_REV_2_0) - clks[cpu_div] = imx_clk_divider("cpu_div", "cpu_sel", base + CCM_CSCR, 12, 2); - else - clks[cpu_div] = imx_clk_divider("cpu_div", "cpu_sel", base + CCM_CSCR, 13, 3); - clks[clko_div] = imx_clk_divider("clko_div", "clko_sel", base + CCM_PCDR0, 22, 3); - clks[per3_gate] = imx_clk_gate("per3_gate", "per3_div", base + CCM_PCCR1, 8); - clks[lcdc_ahb_gate] = imx_clk_gate("lcdc_ahb_gate", "ahb", base + CCM_PCCR1, 15); - clks[lcdc_ipg_gate] = imx_clk_gate("lcdc_ipg_gate", "ipg", base + CCM_PCCR0, 14); - - clkdev_add_physbase(clks[per1_div], MX27_GPT1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1_div], MX27_GPT2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1_div], MX27_GPT3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1_div], MX27_GPT4_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1_div], MX27_GPT5_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1_div], MX27_GPT6_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1_div], MX27_UART1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1_div], MX27_UART2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1_div], MX27_UART3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1_div], MX27_UART4_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1_div], MX27_UART5_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per1_div], MX27_UART6_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX27_CSPI1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX27_CSPI2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX27_CSPI3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX27_I2C1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX27_I2C2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per2_div], MX27_SDHC1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per2_div], MX27_SDHC2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per2_div], MX27_SDHC3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per3_gate], MX27_LCDC_BASE_ADDR, "per"); - clkdev_add_physbase(clks[lcdc_ahb_gate], MX27_LCDC_BASE_ADDR, "ahb"); - clkdev_add_physbase(clks[lcdc_ipg_gate], MX27_LCDC_BASE_ADDR, "ipg"); - clkdev_add_physbase(clks[ipg], MX27_FEC_BASE_ADDR, NULL); - - return 0; -} - -static __maybe_unused struct of_device_id imx27_ccm_dt_ids[] = { - { - .compatible = "fsl,imx27-ccm", - }, { - /* sentinel */ - } -}; - -static struct driver_d imx27_ccm_driver = { - .probe = imx27_ccm_probe, - .name = "imx27-ccm", - .of_compatible = DRV_OF_COMPAT(imx27_ccm_dt_ids), -}; - -static int imx27_ccm_init(void) -{ - return platform_driver_register(&imx27_ccm_driver); -} -core_initcall(imx27_ccm_init); diff --git a/arch/arm/mach-imx/clk-imx31.c b/arch/arm/mach-imx/clk-imx31.c deleted file mode 100644 index 8d135c9a1f..0000000000 --- a/arch/arm/mach-imx/clk-imx31.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2012 Sascha Hauer - * - * 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; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -/* Register addresses */ -#define CCM_CCMR 0x00 -#define CCM_PDR0 0x04 -#define CCM_PDR1 0x08 -//#define CCM_RCSR 0x0C -#define CCM_MPCTL 0x10 -#define CCM_UPCTL 0x14 -#define CCM_SRPCTL 0x18 -#define CCM_COSR 0x1C -#define CCM_CGR0 0x20 -#define CCM_CGR1 0x24 -#define CCM_CGR2 0x28 -#define CCM_WIMR 0x2C -#define CCM_LDC 0x30 -#define CCM_DCVR0 0x34 -#define CCM_DCVR1 0x38 -#define CCM_DCVR2 0x3C -#define CCM_DCVR3 0x40 -#define CCM_LTR0 0x44 -#define CCM_LTR1 0x48 -#define CCM_LTR2 0x4C -#define CCM_LTR3 0x50 -#define CCM_LTBR0 0x54 -#define CCM_LTBR1 0x58 -#define CCM_PMCR0 0x5C -#define CCM_PMCR1 0x60 -#define CCM_PDR2 0x64 - -enum mx31_clks { - ckih, ckil, mpll, spll, upll, mcu_main, hsp, ahb, nfc, ipg, per_div, - per, csi, fir, csi_div, usb_div_pre, usb_div_post, fir_div_pre, - fir_div_post, sdhc1_gate, sdhc2_gate, gpt_gate, epit1_gate, epit2_gate, - iim_gate, ata_gate, sdma_gate, cspi3_gate, rng_gate, uart1_gate, - uart2_gate, ssi1_gate, i2c1_gate, i2c2_gate, i2c3_gate, hantro_gate, - mstick1_gate, mstick2_gate, csi_gate, rtc_gate, wdog_gate, pwm_gate, - sim_gate, ect_gate, usb_gate, kpp_gate, ipu_gate, uart3_gate, - uart4_gate, uart5_gate, owire_gate, ssi2_gate, cspi1_gate, cspi2_gate, - gacc_gate, emi_gate, rtic_gate, firi_gate, clk_max -}; - -static struct clk *clks[clk_max]; - -static const char *mcu_main_sel[] = { - "spll", - "mpll", -}; - -static const char *per_sel[] = { - "per_div", - "ipg", -}; - -static int imx31_ccm_probe(struct device_d *dev) -{ - struct resource *iores; - void __iomem *base; - - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - base = IOMEM(iores->start); - - writel(0xffffffff, base + CCM_CGR0); - writel(0xffffffff, base + CCM_CGR1); - writel(0xffffffff, base + CCM_CGR2); - - clks[ckih] = clk_fixed("ckih", 26000000); - clks[ckil] = clk_fixed("ckil", 32768); - clks[mpll] = imx_clk_pllv1("mpll", "ckih", base + CCM_MPCTL); - clks[spll] = imx_clk_pllv1("spll", "ckih", base + CCM_SRPCTL); - clks[upll] = imx_clk_pllv1("upll", "ckih", base + CCM_UPCTL); - clks[mcu_main] = imx_clk_mux("mcu_main", base + CCM_PMCR0, 31, 1, - mcu_main_sel, ARRAY_SIZE(mcu_main_sel)); - clks[hsp] = imx_clk_divider("hsp", "mcu_main", base + CCM_PDR0, 11, 3); - clks[ahb] = imx_clk_divider("ahb", "mcu_main", base + CCM_PDR0, 3, 3); - clks[nfc] = imx_clk_divider("nfc", "ahb", base + CCM_PDR0, 8, 3); - clks[ipg] = imx_clk_divider("ipg", "ahb", base + CCM_PDR0, 6, 2); - clks[per_div] = imx_clk_divider("per_div", "upll", base + CCM_PDR0, 16, 5); - clks[per] = imx_clk_mux("per", base + CCM_CCMR, 24, 1, per_sel, ARRAY_SIZE(per_sel)); - - clkdev_add_physbase(clks[per], MX31_UART1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per], MX31_UART2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per], MX31_UART3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per], MX31_UART4_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per], MX31_UART5_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per], MX31_I2C1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per], MX31_I2C2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per], MX31_I2C3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX31_CSPI1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX31_CSPI2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX31_CSPI3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per], MX31_SDHC1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per], MX31_SDHC2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[per], MX31_GPT1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[hsp], MX31_IPU_CTRL_BASE_ADDR, NULL); - - return 0; -} - -static __maybe_unused struct of_device_id imx31_ccm_dt_ids[] = { - { - .compatible = "fsl,imx31-ccm", - }, { - /* sentinel */ - } -}; - -static struct driver_d imx31_ccm_driver = { - .probe = imx31_ccm_probe, - .name = "imx31-ccm", - .of_compatible = DRV_OF_COMPAT(imx31_ccm_dt_ids), -}; - -static int imx31_ccm_init(void) -{ - return platform_driver_register(&imx31_ccm_driver); -} -core_initcall(imx31_ccm_init); diff --git a/arch/arm/mach-imx/clk-imx35.c b/arch/arm/mach-imx/clk-imx35.c deleted file mode 100644 index af6c4058d7..0000000000 --- a/arch/arm/mach-imx/clk-imx35.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2012 Sascha Hauer, Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -#define CCM_CCMR 0x00 -#define CCM_PDR0 0x04 -#define CCM_PDR1 0x08 -#define CCM_PDR2 0x0C -#define CCM_PDR3 0x10 -#define CCM_PDR4 0x14 -#define CCM_RCSR 0x18 -#define CCM_MPCTL 0x1C -#define CCM_PPCTL 0x20 -#define CCM_ACMR 0x24 -#define CCM_COSR 0x28 -#define CCM_CGR0 0x2C -#define CCM_CGR1 0x30 -#define CCM_CGR2 0x34 -#define CCM_CGR3 0x38 - -struct arm_ahb_div { - unsigned char arm, ahb, sel; -}; - -static struct arm_ahb_div clk_consumer[] = { - { .arm = 1, .ahb = 4, .sel = 0}, - { .arm = 1, .ahb = 3, .sel = 1}, - { .arm = 2, .ahb = 2, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 4, .ahb = 1, .sel = 0}, - { .arm = 1, .ahb = 5, .sel = 0}, - { .arm = 1, .ahb = 8, .sel = 0}, - { .arm = 1, .ahb = 6, .sel = 1}, - { .arm = 2, .ahb = 4, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 4, .ahb = 2, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, -}; - -static char hsp_div_532[] = { 4, 8, 3, 0 }; -static char hsp_div_400[] = { 3, 6, 3, 0 }; - -enum mx35_clks { - ckih, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg, - arm_per_div, ahb_per_div, ipg_per, uart_sel, uart_div, esdhc_sel, - esdhc1_div, esdhc2_div, esdhc3_div, spdif_sel, spdif_div_pre, - spdif_div_post, ssi_sel, ssi1_div_pre, ssi1_div_post, ssi2_div_pre, - ssi2_div_post, usb_sel, usb_div, nfc_div, asrc_gate, pata_gate, - audmux_gate, can1_gate, can2_gate, cspi1_gate, cspi2_gate, ect_gate, - edio_gate, emi_gate, epit1_gate, epit2_gate, esai_gate, esdhc1_gate, - esdhc2_gate, esdhc3_gate, fec_gate, gpio1_gate, gpio2_gate, gpio3_gate, - gpt_gate, i2c1_gate, i2c2_gate, i2c3_gate, iomuxc_gate, ipu_gate, - kpp_gate, mlb_gate, mshc_gate, owire_gate, pwm_gate, rngc_gate, - rtc_gate, rtic_gate, scc_gate, sdma_gate, spba_gate, spdif_gate, - ssi1_gate, ssi2_gate, uart1_gate, uart2_gate, uart3_gate, usbotg_gate, - wdog_gate, max_gate, admux_gate, csi_gate, iim_gate, gpu2d_gate, - clk_max -}; - -static struct clk *clks[clk_max]; - -static const char *std_sel[] = { - "ppll", - "arm", -}; - -static const char *ipg_per_sel[] = { - "ahb_per_div", - "arm_per_div", -}; - -static int imx35_ccm_probe(struct device_d *dev) -{ - struct resource *iores; - u32 pdr0, consumer_sel, hsp_sel; - struct arm_ahb_div *aad; - unsigned char *hsp_div; - void __iomem *base; - u32 reg; - - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - base = IOMEM(iores->start); - - /* Check reset source */ - reg = readl(base + CCM_RCSR); - - switch (reg & 0x0F) { - case 0x00: - reset_source_set_priority(RESET_POR, 200); - break; - case 0x02: - reset_source_set_priority(RESET_JTAG, 200); - break; - case 0x04: - reset_source_set_priority(RESET_RST, 200); - break; - case 0x08: - reset_source_set_priority(RESET_WDG, 200); - break; - } - - writel(0xffffffff, base + CCM_CGR0); - writel(0xffffffff, base + CCM_CGR1); - writel(0xfbffffff, base + CCM_CGR2); - writel(0xffffffff, base + CCM_CGR3); - - pdr0 = __raw_readl(base + CCM_PDR0); - consumer_sel = (pdr0 >> 16) & 0xf; - aad = &clk_consumer[consumer_sel]; - if (!aad->arm) { - pr_err("i.MX35 clk: illegal consumer mux selection 0x%x\n", consumer_sel); - /* - * We are basically stuck. Continue with a default entry and hope we - * get far enough to actually show the above message - */ - aad = &clk_consumer[0]; - } - - clks[ckih] = clk_fixed("ckih", 24000000); - clks[mpll] = imx_clk_pllv1("mpll", "ckih", base + CCM_MPCTL); - clks[ppll] = imx_clk_pllv1("ppll", "ckih", base + CCM_PPCTL); - - clks[mpll_075] = imx_clk_fixed_factor("mpll_075", "mpll", 3, 4); - - if (aad->sel) - clks[arm] = imx_clk_fixed_factor("arm", "mpll_075", 1, aad->arm); - else - clks[arm] = imx_clk_fixed_factor("arm", "mpll", 1, aad->arm); - - if (clk_get_rate(clks[arm]) > 400000000) - hsp_div = hsp_div_532; - else - hsp_div = hsp_div_400; - - hsp_sel = (pdr0 >> 20) & 0x3; - if (!hsp_div[hsp_sel]) { - pr_err("i.MX35 clk: illegal hsp clk selection 0x%x\n", hsp_sel); - hsp_sel = 0; - } - - clks[hsp] = imx_clk_fixed_factor("hsp", "arm", 1, hsp_div[hsp_sel]); - - clks[ahb] = imx_clk_fixed_factor("ahb", "arm", 1, aad->ahb); - clks[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2); - - clks[arm_per_div] = imx_clk_divider("arm_per_div", "arm", base + CCM_PDR4, 16, 6); - clks[ahb_per_div] = imx_clk_divider("ahb_per_div", "ahb", base + CCM_PDR0, 12, 3); - clks[ipg_per] = imx_clk_mux("ipg_per", base + CCM_PDR0, 26, 1, ipg_per_sel, ARRAY_SIZE(ipg_per_sel)); - - clks[uart_sel] = imx_clk_mux("uart_sel", base + CCM_PDR3, 14, 1, std_sel, ARRAY_SIZE(std_sel)); - clks[uart_div] = imx_clk_divider("uart_div", "uart_sel", base + CCM_PDR4, 10, 6); - - clks[esdhc_sel] = imx_clk_mux("esdhc_sel", base + CCM_PDR4, 9, 1, std_sel, ARRAY_SIZE(std_sel)); - clks[esdhc1_div] = imx_clk_divider("esdhc1_div", "esdhc_sel", base + CCM_PDR3, 0, 6); - clks[esdhc2_div] = imx_clk_divider("esdhc2_div", "esdhc_sel", base + CCM_PDR3, 8, 6); - clks[esdhc3_div] = imx_clk_divider("esdhc3_div", "esdhc_sel", base + CCM_PDR3, 16, 6); - - clks[usb_sel] = imx_clk_mux("usb_sel", base + CCM_PDR4, 9, 1, std_sel, ARRAY_SIZE(std_sel)); - clks[usb_div] = imx_clk_divider("usb_div", "usb_sel", base + CCM_PDR4, 22, 6); - - clkdev_add_physbase(clks[uart_div], MX35_UART1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[uart_div], MX35_UART2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[uart_div], MX35_UART3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg_per], MX35_I2C1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg_per], MX35_I2C2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg_per], MX35_I2C3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX35_CSPI1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX35_CSPI2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX35_FEC_BASE_ADDR, NULL); - clkdev_add_physbase(clks[ipg], MX35_GPT1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[esdhc1_div], MX35_ESDHC1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[esdhc2_div], MX35_ESDHC2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[esdhc3_div], MX35_ESDHC3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[hsp], MX35_IPU_CTRL_BASE_ADDR, NULL); - - return 0; -} - -static __maybe_unused struct of_device_id imx35_ccm_dt_ids[] = { - { - .compatible = "fsl,imx35-ccm", - }, { - /* sentinel */ - } -}; - -static struct driver_d imx35_ccm_driver = { - .probe = imx35_ccm_probe, - .name = "imx35-ccm", - .of_compatible = DRV_OF_COMPAT(imx35_ccm_dt_ids), -}; - -static int imx35_ccm_init(void) -{ - return platform_driver_register(&imx35_ccm_driver); -} -core_initcall(imx35_ccm_init); diff --git a/arch/arm/mach-imx/clk-imx5.c b/arch/arm/mach-imx/clk-imx5.c deleted file mode 100644 index c4c47a6d87..0000000000 --- a/arch/arm/mach-imx/clk-imx5.c +++ /dev/null @@ -1,533 +0,0 @@ -/* - * Copyright (C) 2011 Sascha Hauer, Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -/* Register addresses of CCM*/ -#define CCM_CCR 0x00 -#define CCM_CCDR 0x04 -#define CCM_CSR 0x08 -#define CCM_CCSR 0x0C -#define CCM_CACRR 0x10 -#define CCM_CBCDR 0x14 -#define CCM_CBCMR 0x18 -#define CCM_CSCMR1 0x1C -#define CCM_CSCMR2 0x20 -#define CCM_CSCDR1 0x24 -#define CCM_CS1CDR 0x28 -#define CCM_CS2CDR 0x2C -#define CCM_CDCDR 0x30 -#define CCM_CHSCDR 0x34 -#define CCM_CSCDR2 0x38 -#define CCM_CSCDR3 0x3C -#define CCM_CSCDR4 0x40 -#define CCM_CWDR 0x44 -#define CCM_CDHIPR 0x48 -#define CCM_CDCR 0x4C -#define CCM_CTOR 0x50 -#define CCM_CLPCR 0x54 -#define CCM_CISR 0x58 -#define CCM_CIMR 0x5C -#define CCM_CCOSR 0x60 -#define CCM_CGPR 0x64 -#define CCM_CCGR0 0x68 -#define CCM_CCGR1 0x6C -#define CCM_CCGR2 0x70 -#define CCM_CCGR3 0x74 -#define CCM_CCGR4 0x78 -#define CCM_CCGR5 0x7C -#define CCM_CCGR6 0x80 -#define CCM_CCGR7 0x84 - -#define CCM_CMEOR 0x84 - -static struct clk *clks[IMX5_CLK_END]; - -/* This is used multiple times */ -static const char *standard_pll_sel[] = { - "pll1_sw", - "pll2_sw", - "pll3_sw", - "lp_apm", -}; - -static const char *mx50_3bit_clk_sel[] = { - "pll1_sw", - "pll2_sw", - "pll3_sw", - "lp_apm", - "pfd0", - "pfd1", - "pfd4", - "osc", -}; - -static const char *lp_apm_sel[] = { - "osc", -}; - -static const char *periph_apm_sel[] = { - "pll1_sw", - "pll3_sw", - "lp_apm", -}; - -static const char *main_bus_sel[] = { - "pll2_sw", - "periph_apm", -}; - -static const char *mx50_periph_clk_sel[] = { - "pll1_sw", - "pll2_sw", - "pll3_sw", - "lp_apm", -}; - -static const char *per_lp_apm_sel[] = { - "main_bus", - "lp_apm", -}; - -static const char *per_root_sel[] = { - "per_podf", - "ipg", -}; - -static const char *esdhc_c_sel[] = { - "esdhc_a_podf", - "esdhc_b_podf", -}; - -static const char *esdhc_d_sel[] = { - "esdhc_a_podf", - "esdhc_b_podf", -}; - -static const char *emi_slow_sel[] = { - "main_bus", - "ahb", -}; - -static const char *usb_phy_sel_str[] = { - "osc", - "usb_phy_podf", -}; - -static const char *mx51_ipu_di0_sel[] = { - "di_pred", - "osc", - "ckih1", - "tve_di", -}; - -static const char *mx53_ipu_di0_sel[] = { - "di_pred", - "osc", - "ckih1", - "di_pll4_podf", - "dummy", - "ldb_di0_div", -}; - -static const char *mx53_ldb_di0_sel[] = { - "pll3_sw", - "pll4_sw", -}; - -static const char *mx51_ipu_di1_sel[] = { - "di_pred", - "osc", - "ckih1", - "tve_di", - "ipp_di1", -}; - -static const char *mx53_ipu_di1_sel[] = { - "di_pred", - "osc", - "ckih1", - "tve_di", - "ipp_di1", - "ldb_di1_div", -}; - -static const char *mx53_ldb_di1_sel[] = { - "pll3_sw", - "pll4_sw", -}; - -static const char *mx51_tve_ext_sel[] = { - "osc", - "ckih1", -}; - -static const char *mx53_tve_ext_sel[] = { - "pll4_sw", - "ckih1", -}; - -static const char *mx51_tve_sel[] = { - "tve_pred", - "tve_ext_sel", -}; - -static const char *ipu_sel[] = { - "axi_a", - "axi_b", - "emi_slow_gate", - "ahb", -}; - -static void __init mx5_clocks_common_init(struct device_d *dev, void __iomem *base) -{ - writel(0xffffffff, base + CCM_CCGR0); - writel(0xffffffff, base + CCM_CCGR1); - writel(0xffffffff, base + CCM_CCGR2); - writel(0xffffffff, base + CCM_CCGR3); - writel(0xffffffff, base + CCM_CCGR4); - writel(0xffffffff, base + CCM_CCGR5); - writel(0xffffffff, base + CCM_CCGR6); - writel(0xffffffff, base + CCM_CCGR7); - - if (!IS_ENABLED(CONFIG_COMMON_CLK_OF_PROVIDER) || !dev->device_node) { - clks[IMX5_CLK_CKIL] = clk_fixed("ckil", 32768); - clks[IMX5_CLK_OSC] = clk_fixed("osc", 24000000); - } - - clks[IMX5_CLK_PER_LP_APM] = imx_clk_mux("per_lp_apm", base + CCM_CBCMR, 1, 1, - per_lp_apm_sel, ARRAY_SIZE(per_lp_apm_sel)); - clks[IMX5_CLK_PER_PRED1] = imx_clk_divider("per_pred1", "per_lp_apm", base + CCM_CBCDR, 6, 2); - clks[IMX5_CLK_PER_PRED2] = imx_clk_divider("per_pred2", "per_pred1", base + CCM_CBCDR, 3, 3); - clks[IMX5_CLK_PER_PODF] = imx_clk_divider("per_podf", "per_pred2", base + CCM_CBCDR, 0, 3); - clks[IMX5_CLK_PER_ROOT] = imx_clk_mux("per_root", base + CCM_CBCMR, 0, 1, - per_root_sel, ARRAY_SIZE(per_root_sel)); - clks[IMX5_CLK_AHB] = imx_clk_divider("ahb", "main_bus", base + CCM_CBCDR, 10, 3); - clks[IMX5_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + CCM_CBCDR, 8, 2); - clks[IMX5_CLK_AXI_A] = imx_clk_divider("axi_a", "main_bus", base + CCM_CBCDR, 16, 3); - clks[IMX5_CLK_AXI_B] = imx_clk_divider("axi_b", "main_bus", base + CCM_CBCDR, 19, 3); - clks[IMX5_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + CCM_CSCMR1, 24, 2, - standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); - clks[IMX5_CLK_UART_PRED] = imx_clk_divider("uart_pred", "uart_sel", base + CCM_CSCDR1, 3, 3); - clks[IMX5_CLK_UART_ROOT] = imx_clk_divider("uart_root", "uart_pred", base + CCM_CSCDR1, 0, 3); - clks[IMX5_CLK_ESDHC_A_PRED] = imx_clk_divider("esdhc_a_pred", - "esdhc_a_sel", base + CCM_CSCDR1, 16, 3); - clks[IMX5_CLK_ESDHC_A_PODF] = imx_clk_divider("esdhc_a_podf", - "esdhc_a_pred", base + CCM_CSCDR1, 11, 3); - clks[IMX5_CLK_ESDHC_B_PRED] = imx_clk_divider("esdhc_b_pred", - "esdhc_b_sel", base + CCM_CSCDR1, 22, 3); - clks[IMX5_CLK_ESDHC_B_PODF] = imx_clk_divider("esdhc_b_podf", - "esdhc_b_pred", base + CCM_CSCDR1, 19, 3); - clks[IMX5_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + CCM_CSCMR1, - 4, 2, standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); - clks[IMX5_CLK_ECSPI_PRED] = imx_clk_divider("ecspi_pred", - "ecspi_sel", base + CCM_CSCDR2, 25, 3); - clks[IMX5_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", - "ecspi_pred", base + CCM_CSCDR2, 19, 6); - clks[IMX5_CLK_CPU_PODF] = imx_clk_divider("cpu_podf", - "pll1_sw", base + CCM_CACRR, 0, 3); -} - -static void mx5_clocks_mx51_mx53_init(void __iomem *base) -{ - clks[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", base + CCM_CCSR, 9, 1, - lp_apm_sel, ARRAY_SIZE(lp_apm_sel)); - clks[IMX5_CLK_PERIPH_APM] = imx_clk_mux("periph_apm", base + CCM_CBCMR, 12, 2, - periph_apm_sel, ARRAY_SIZE(periph_apm_sel)); - clks[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", base + CCM_CBCDR, 25, 1, - main_bus_sel, ARRAY_SIZE(main_bus_sel)); - clks[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", base + CCM_CSCMR1, 20, 2, - standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); - clks[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", base + CCM_CSCMR1, 16, 2, - standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); - clks[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", base + CCM_CSCMR1, 19, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel)); - clks[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", base + CCM_CSCMR1, 18, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel)); - clks[IMX5_CLK_EMI_SEL] = imx_clk_mux("emi_sel", base + CCM_CBCDR, 26, 1, - emi_slow_sel, ARRAY_SIZE(emi_slow_sel)); - clks[IMX5_CLK_EMI_SLOW_PODF] = imx_clk_divider("emi_slow_podf", "emi_sel", base + CCM_CBCDR, 22, 3); - clks[IMX5_CLK_NFC_PODF] = imx_clk_divider("nfc_podf", "emi_slow_podf", base + CCM_CBCDR, 13, 3); - clks[IMX5_CLK_USBOH3_SEL] = imx_clk_mux("usboh3_sel", base + CCM_CSCMR1, 22, 2, - standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); - clks[IMX5_CLK_USBOH3_PRED] = imx_clk_divider("usboh3_pred", "usboh3_sel", base + CCM_CSCDR1, 8, 3); - clks[IMX5_CLK_USBOH3_PODF] = imx_clk_divider("usboh3_podf", "usboh3_pred", base + CCM_CSCDR1, 6, 2); - clks[IMX5_CLK_USB_PHY_PRED] = imx_clk_divider("usb_phy_pred", "pll3_sw", base + CCM_CDCDR, 3, 3); - clks[IMX5_CLK_USB_PHY_PODF] = imx_clk_divider("usb_phy_podf", "usb_phy_pred", base + CCM_CDCDR, 0, 3); - clks[IMX5_CLK_USB_PHY_SEL] = imx_clk_mux("usb_phy_sel", base + CCM_CSCMR1, 26, 1, - usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str)); -} - -static void mx5_clocks_ipu_init(void __iomem *regs) -{ - clks[IMX5_CLK_IPU_SEL] = imx_clk_mux("ipu_sel", regs + CCM_CBCMR, 6, 2, ipu_sel, ARRAY_SIZE(ipu_sel)); -} - -int __init mx50_clocks_init(struct device_d *dev, void __iomem *regs) -{ - clks[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", - (void *)MX50_PLL1_BASE_ADDR); - clks[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", - (void *)MX50_PLL2_BASE_ADDR); - clks[IMX5_CLK_PLL3_SW] = imx_clk_pllv2("pll3_sw", "osc", - (void *)MX50_PLL3_BASE_ADDR); - - mx5_clocks_common_init(dev, regs); - - clks[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", regs + CCM_CCSR, 10, 1, lp_apm_sel, ARRAY_SIZE(lp_apm_sel)); - clks[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", regs + CCM_CBCDR, 25, 2, mx50_periph_clk_sel, ARRAY_SIZE(mx50_periph_clk_sel)); - clks[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", regs + CCM_CSCMR1, 21, 2, standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); - clks[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", regs + CCM_CSCMR1, 16, 3, mx50_3bit_clk_sel, ARRAY_SIZE(mx50_3bit_clk_sel)); - clks[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", regs + CCM_CSCMR1, 20, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel)); - clks[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", regs + CCM_CSCMR1, 19, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel)); - clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX50_UART1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX50_UART2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX50_UART3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_I2C1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_I2C2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_I2C3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_GPT1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_IPG], MX50_CSPI_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX50_ECSPI1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX50_ECSPI2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_IPG], MX50_FEC_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ESDHC_A_PODF], MX50_ESDHC1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ESDHC_C_SEL], MX50_ESDHC2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ESDHC_B_PODF], MX50_ESDHC3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ESDHC_D_SEL], MX50_ESDHC4_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_PWM1_BASE_ADDR, "per"); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_PWM2_BASE_ADDR, "per"); - - return 0; -} - -static int imx50_ccm_probe(struct device_d *dev) -{ - struct resource *iores; - void __iomem *regs; - - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - regs = IOMEM(iores->start); - - mx50_clocks_init(dev, regs); - - return 0; -} - -static __maybe_unused struct of_device_id imx50_ccm_dt_ids[] = { - { - .compatible = "fsl,imx50-ccm", - }, { - /* sentinel */ - } -}; - -static struct driver_d imx50_ccm_driver = { - .probe = imx50_ccm_probe, - .name = "imx50-ccm", - .of_compatible = DRV_OF_COMPAT(imx50_ccm_dt_ids), -}; - -static void mx51_clocks_ipu_init(void __iomem *regs) -{ - clks[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux_p("ipu_di0_sel", regs + CCM_CSCMR2, 26, 3, - mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel)); - clks[IMX5_CLK_IPU_DI1_SEL] = imx_clk_mux_p("ipu_di1_sel", regs + CCM_CSCMR2, 29, 3, - mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel)); - clks[IMX5_CLK_TVE_EXT_SEL] = imx_clk_mux_p("tve_ext_sel", regs + CCM_CSCMR1, 6, 1, - mx51_tve_ext_sel, ARRAY_SIZE(mx51_tve_ext_sel)); - clks[IMX5_CLK_TVE_SEL] = imx_clk_mux("tve_sel", regs + CCM_CSCMR1, 7, 1, - mx51_tve_sel, ARRAY_SIZE(mx51_tve_sel)); - clks[IMX5_CLK_TVE_PRED] = imx_clk_divider("tve_pred", "pll3_sw", regs + CCM_CDCDR, 28, 3); - - mx5_clocks_ipu_init(regs); - - clkdev_add_physbase(clks[IMX5_CLK_IPU_SEL], MX51_IPU_BASE_ADDR, "bus"); - clkdev_add_physbase(clks[IMX5_CLK_IPU_DI0_SEL], MX51_IPU_BASE_ADDR, "di0"); - clkdev_add_physbase(clks[IMX5_CLK_IPU_DI1_SEL], MX51_IPU_BASE_ADDR, "di1"); -} - -int __init mx51_clocks_init(struct device_d *dev, void __iomem *regs) -{ - clks[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", (void *)MX51_PLL1_BASE_ADDR); - clks[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", (void *)MX51_PLL2_BASE_ADDR); - clks[IMX5_CLK_PLL3_SW] = imx_clk_pllv2("pll3_sw", "osc", (void *)MX51_PLL3_BASE_ADDR); - - mx5_clocks_common_init(dev, regs); - mx5_clocks_mx51_mx53_init(regs); - - clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX51_UART1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX51_UART2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX51_UART3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_I2C1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_I2C2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_GPT1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_IPG], MX51_CSPI_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX51_ECSPI1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX51_ECSPI2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_IPG], MX51_MXC_FEC_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ESDHC_A_PODF], MX51_MMC_SDHC1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ESDHC_B_PODF], MX51_MMC_SDHC2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ESDHC_C_SEL], MX51_MMC_SDHC3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ESDHC_D_SEL], MX51_MMC_SDHC4_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_IPG], MX51_ATA_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_PWM1_BASE_ADDR, "per"); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_PWM2_BASE_ADDR, "per"); - - if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3)) - mx51_clocks_ipu_init(regs); - - return 0; -} - -static int imx51_ccm_probe(struct device_d *dev) -{ - struct resource *iores; - void __iomem *regs; - - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - regs = IOMEM(iores->start); - - mx51_clocks_init(dev, regs); - - return 0; -} - -static __maybe_unused struct of_device_id imx51_ccm_dt_ids[] = { - { - .compatible = "fsl,imx51-ccm", - }, { - /* sentinel */ - } -}; - -static struct driver_d imx51_ccm_driver = { - .probe = imx51_ccm_probe, - .name = "imx51-ccm", - .of_compatible = DRV_OF_COMPAT(imx51_ccm_dt_ids), -}; - -static void mx53_clocks_ipu_init(void __iomem *regs) -{ - clks[IMX5_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); - clks[IMX5_CLK_LDB_DI1_DIV] = imx_clk_divider_np("ldb_di1_div", "ldb_di1_div_3_5", regs + CCM_CSCMR2, 11, 1); - clks[IMX5_CLK_LDB_DI1_SEL] = imx_clk_mux_p("ldb_di1_sel", regs + CCM_CSCMR2, 9, 1, - mx53_ldb_di1_sel, ARRAY_SIZE(mx53_ldb_di1_sel)); - clks[IMX5_CLK_DI_PLL4_PODF] = imx_clk_divider("di_pll4_podf", "pll4_sw", regs + CCM_CDCDR, 16, 3); - clks[IMX5_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); - clks[IMX5_CLK_LDB_DI0_DIV] = imx_clk_divider("ldb_di0_div", "ldb_di0_div_3_5", regs + CCM_CSCMR2, 10, 1); - clks[IMX5_CLK_LDB_DI0_SEL] = imx_clk_mux_p("ldb_di0_sel", regs + CCM_CSCMR2, 8, 1, - mx53_ldb_di0_sel, ARRAY_SIZE(mx53_ldb_di0_sel)); - clks[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux_p("ipu_di0_sel", regs + CCM_CSCMR2, 26, 3, - mx53_ipu_di0_sel, ARRAY_SIZE(mx53_ipu_di0_sel)); - clks[IMX5_CLK_IPU_DI1_SEL] = imx_clk_mux_p("ipu_di1_sel", regs + CCM_CSCMR2, 29, 3, - mx53_ipu_di1_sel, ARRAY_SIZE(mx53_ipu_di1_sel)); - clks[IMX5_CLK_TVE_EXT_SEL] = imx_clk_mux_p("tve_ext_sel", regs + CCM_CSCMR1, 6, 1, - mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel)); - clks[IMX5_CLK_TVE_PRED] = imx_clk_divider("tve_pred", "tve_ext_sel", regs + CCM_CDCDR, 28, 3); - - mx5_clocks_ipu_init(regs); - - clkdev_add_physbase(clks[IMX5_CLK_IPU_SEL], MX53_IPU_BASE_ADDR, "bus"); - clkdev_add_physbase(clks[IMX5_CLK_IPU_DI0_SEL], MX53_IPU_BASE_ADDR, "di0"); - clkdev_add_physbase(clks[IMX5_CLK_IPU_DI1_SEL], MX53_IPU_BASE_ADDR, "di1"); -} - -int __init mx53_clocks_init(struct device_d *dev, void __iomem *regs) -{ - clks[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", (void *)MX53_PLL1_BASE_ADDR); - clks[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", (void *)MX53_PLL2_BASE_ADDR); - clks[IMX5_CLK_PLL3_SW] = imx_clk_pllv2("pll3_sw", "osc", (void *)MX53_PLL3_BASE_ADDR); - clks[IMX5_CLK_PLL4_SW] = imx_clk_pllv2("pll4_sw", "osc", (void *)MX53_PLL4_BASE_ADDR); - - mx5_clocks_common_init(dev, regs); - mx5_clocks_mx51_mx53_init(regs); - - clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART4_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART5_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_I2C1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_I2C2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_I2C3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_GPT1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_IPG], MX53_CSPI_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX53_ECSPI1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX53_ECSPI2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_IPG], MX53_FEC_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ESDHC_A_PODF], MX53_ESDHC1_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ESDHC_C_SEL], MX53_ESDHC2_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ESDHC_B_PODF], MX53_ESDHC3_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_ESDHC_D_SEL], MX53_ESDHC4_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_AHB], MX53_SATA_BASE_ADDR, NULL); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_PWM1_BASE_ADDR, "per"); - clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_PWM2_BASE_ADDR, "per"); - - if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3)) - mx53_clocks_ipu_init(regs); - - return 0; -} - -static int imx53_ccm_probe(struct device_d *dev) -{ - struct resource *iores; - void __iomem *regs; - - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - regs = IOMEM(iores->start); - - mx53_clocks_init(dev, regs); - - return 0; -} - -static __maybe_unused struct of_device_id imx53_ccm_dt_ids[] = { - { - .compatible = "fsl,imx53-ccm", - }, { - /* sentinel */ - } -}; - -static struct driver_d imx53_ccm_driver = { - .probe = imx53_ccm_probe, - .name = "imx53-ccm", - .of_compatible = DRV_OF_COMPAT(imx53_ccm_dt_ids), -}; - -static int imx5_ccm_init(void) -{ - if (IS_ENABLED(CONFIG_ARCH_IMX50)) - platform_driver_register(&imx50_ccm_driver); - if (IS_ENABLED(CONFIG_ARCH_IMX51)) - platform_driver_register(&imx51_ccm_driver); - if (IS_ENABLED(CONFIG_ARCH_IMX53)) - platform_driver_register(&imx53_ccm_driver); - - return 0; -} -core_initcall(imx5_ccm_init); diff --git a/arch/arm/mach-imx/clk-imx6.c b/arch/arm/mach-imx/clk-imx6.c deleted file mode 100644 index 8ac43bebb0..0000000000 --- a/arch/arm/mach-imx/clk-imx6.c +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Copyright 2011 Freescale Semiconductor, Inc. - * Copyright 2011 Linaro Ltd. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -#define CCGR0 0x68 -#define CCGR1 0x6c -#define CCGR2 0x70 -#define CCGR3 0x74 -#define CCGR4 0x78 -#define CCGR5 0x7c -#define CCGR6 0x80 -#define CCGR7 0x84 - -#define CLPCR 0x54 -#define BP_CLPCR_LPM 0 -#define BM_CLPCR_LPM (0x3 << 0) -#define BM_CLPCR_BYPASS_PMIC_READY (0x1 << 2) -#define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) -#define BM_CLPCR_SBYOS (0x1 << 6) -#define BM_CLPCR_DIS_REF_OSC (0x1 << 7) -#define BM_CLPCR_VSTBY (0x1 << 8) -#define BP_CLPCR_STBY_COUNT 9 -#define BM_CLPCR_STBY_COUNT (0x3 << 9) -#define BM_CLPCR_COSC_PWRDOWN (0x1 << 11) -#define BM_CLPCR_WB_PER_AT_LPM (0x1 << 16) -#define BM_CLPCR_WB_CORE_AT_LPM (0x1 << 17) -#define BM_CLPCR_BYP_MMDC_CH0_LPM_HS (0x1 << 19) -#define BM_CLPCR_BYP_MMDC_CH1_LPM_HS (0x1 << 21) -#define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22) -#define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23) -#define BM_CLPCR_MASK_CORE2_WFI (0x1 << 24) -#define BM_CLPCR_MASK_CORE3_WFI (0x1 << 25) -#define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) -#define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) - -static struct clk *clks[IMX6QDL_CLK_END]; -static struct clk_onecell_data clk_data; - -static const char *step_sels[] = { - "osc", - "pll2_pfd2_396m", -}; - -static const char *pll1_sw_sels[] = { - "pll1_sys", - "step", -}; - -static const char *periph_pre_sels[] = { - "pll2_bus", - "pll2_pfd2_396m", - "pll2_pfd0_352m", - "pll2_198m", -}; - -static const char *periph_clk2_sels[] = { - "pll3_usb_otg", - "osc", -}; - -static const char *periph_sels[] = { - "periph_pre", - "periph_clk2", -}; - -static const char *periph2_sels[] = { - "periph2_pre", - "periph2_clk2", -}; - -static const char *axi_sels[] = { - "periph", - "pll2_pfd2_396m", - "pll3_pfd1_540m", -}; - -static const char *usdhc_sels[] = { - "pll2_pfd2_396m", - "pll2_pfd0_352m", -}; - -static const char *enfc_sels[] = { - "pll2_pfd0_352m", - "pll2_bus", - "pll3_usb_otg", - "pll2_pfd2_396m", -}; - -static const char *eim_sels[] = { - "axi", - "pll3_usb_otg", - "pll2_pfd2_396m", - "pll2_pfd0_352m", -}; - -static const char *vdo_axi_sels[] = { - "axi", - "ahb", -}; - -static const char *cko_sels[] = { - "cko1", - "cko2", -}; - -static const char *cko1_sels[] = { - "pll3_usb_otg", - "pll2_bus", - "pll1_sys", - "pll5_video", - "dummy", - "axi", - "enfc", - "ipu1_di0", - "ipu1_di1", - "ipu2_di0", - "ipu2_di1", - "ahb", - "ipg", - "ipg_per", - "ckil", - "pll4_audio", -}; - -static const char *cko2_sels[] = { - "mmdc_ch0_axi", - "mmdc_ch1_axi", - "usdhc4", - "usdhc1", - "gpu2d_axi", - "dummy", - "ecspi_root", - "gpu3d_axi", - "usdhc3", - "dummy", - "arm", - "ipu1", - "ipu2", - "vdo_axi", - "osc", - "gpu2d_core", - "gpu3d_core", - "usdhc2", - "ssi1", - "ssi2", - "ssi3", - "gpu3d_shader", - "vpu_axi", - "can_root", - "ldb_di0", - "ldb_di1", - "esai", - "eim_slow", - "uart_serial", - "spdif", - "asrc", - "hsi_tx", -}; - -static const char *ipu_sels[] = { - "mmdc_ch0_axi_podf", - "pll2_pfd2_396m", - "pll3_120m", - "pll3_pfd1_540m", -}; - -static const char *ldb_di_sels[] = { - "pll5_video_div", - "pll2_pfd0_352m", - "pll2_pfd2_396m", - "mmdc_ch1_axi_podf", - "pll3_usb_otg", -}; - -static const char *ipu_di_pre_sels[] = { - "mmdc_ch0_axi", - "pll3_usb_otg", - "pll5_video_div", - "pll2_pfd0_352m", - "pll2_pfd2_396m", - "pll3_pfd1_540m", -}; - -static const char *ipu1_di0_sels[] = { - "ipu1_di0_pre", - "dummy", - "dummy", - "ldb_di0_podf", - "ldb_di1_podf", -}; - -static const char *ipu1_di1_sels[] = { - "ipu1_di1_pre", - "dummy", - "dummy", - "ldb_di0_podf", - "ldb_di1_podf", -}; - -static const char *ipu2_di0_sels[] = { - "ipu2_di0_pre", - "dummy", - "dummy", - "ldb_di0_podf", - "ldb_di1_podf", -}; - -static const char *ipu2_di1_sels[] = { - "ipu2_di1_pre", - "dummy", - "dummy", - "ldb_di0_podf", - "ldb_di1_podf", -}; - -static const char *lvds_sels[] = { - "dummy", - "dummy", - "dummy", - "dummy", - "dummy", - "dummy", - "pll4_audio", - "pll5_video", - "pll8_mlb", - "enet_ref", - "pcie_ref_125m", - "sata_ref_100m", -}; - -static const char *pcie_axi_sels[] = { - "axi", - "ahb", -}; - -static struct clk_div_table clk_enet_ref_table[] = { - { .val = 0, .div = 20, }, - { .val = 1, .div = 10, }, - { .val = 2, .div = 5, }, - { .val = 3, .div = 4, }, - { }, -}; - -static struct clk_div_table post_div_table[] = { - { .val = 2, .div = 1, }, - { .val = 1, .div = 2, }, - { .val = 0, .div = 4, }, - { /* sentinel */ } -}; - -static struct clk_div_table video_div_table[] = { - { .val = 0, .div = 1, }, - { .val = 1, .div = 2, }, - { .val = 2, .div = 1, }, - { .val = 3, .div = 4, }, - { /* sentinel */ } -}; - -static void imx6_add_video_clks(void __iomem *anab, void __iomem *cb) -{ - clks[IMX6QDL_CLK_PLL5_POST_DIV] = imx_clk_divider_table("pll5_post_div", "pll5_video", anab + 0xa0, 19, 2, post_div_table); - clks[IMX6QDL_CLK_PLL5_VIDEO_DIV] = imx_clk_divider_table("pll5_video_div", "pll5_post_div", anab + 0x170, 30, 2, video_div_table); - - clks[IMX6QDL_CLK_IPU1_SEL] = imx_clk_mux("ipu1_sel", cb + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); - clks[IMX6QDL_CLK_IPU2_SEL] = imx_clk_mux("ipu2_sel", cb + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); - clks[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_p("ldb_di0_sel", cb + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); - clks[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_p("ldb_di1_sel", cb + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); - clks[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_mux_p("ipu1_di0_pre_sel", cb + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); - clks[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_mux_p("ipu1_di1_pre_sel", cb + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); - clks[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_mux_p("ipu2_di0_pre_sel", cb + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); - clks[IMX6QDL_CLK_IPU2_DI1_PRE_SEL] = imx_clk_mux_p("ipu2_di1_pre_sel", cb + 0x38, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); - clks[IMX6QDL_CLK_IPU1_DI0_SEL] = imx_clk_mux_p("ipu1_di0_sel", cb + 0x34, 0, 3, ipu1_di0_sels, ARRAY_SIZE(ipu1_di0_sels)); - clks[IMX6QDL_CLK_IPU1_DI1_SEL] = imx_clk_mux_p("ipu1_di1_sel", cb + 0x34, 9, 3, ipu1_di1_sels, ARRAY_SIZE(ipu1_di1_sels)); - clks[IMX6QDL_CLK_IPU2_DI0_SEL] = imx_clk_mux_p("ipu2_di0_sel", cb + 0x38, 0, 3, ipu2_di0_sels, ARRAY_SIZE(ipu2_di0_sels)); - clks[IMX6QDL_CLK_IPU2_DI1_SEL] = imx_clk_mux_p("ipu2_di1_sel", cb + 0x38, 9, 3, ipu2_di1_sels, ARRAY_SIZE(ipu2_di1_sels)); - - clks[IMX6QDL_CLK_IPU1_PODF] = imx_clk_divider("ipu1_podf", "ipu1_sel", cb + 0x3c, 11, 3); - clks[IMX6QDL_CLK_IPU2_PODF] = imx_clk_divider("ipu2_podf", "ipu2_sel", cb + 0x3c, 16, 3); - clks[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); - clks[IMX6QDL_CLK_LDB_DI0_PODF] = imx_clk_divider_np("ldb_di0_podf", "ldb_di0_div_3_5", cb + 0x20, 10, 1); - clks[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); - clks[IMX6QDL_CLK_LDB_DI1_PODF] = imx_clk_divider_np("ldb_di1_podf", "ldb_di1_div_3_5", cb + 0x20, 11, 1); - clks[IMX6QDL_CLK_IPU1_DI0_PRE] = imx_clk_divider("ipu1_di0_pre", "ipu1_di0_pre_sel", cb + 0x34, 3, 3); - clks[IMX6QDL_CLK_IPU1_DI1_PRE] = imx_clk_divider("ipu1_di1_pre", "ipu1_di1_pre_sel", cb + 0x34, 12, 3); - clks[IMX6QDL_CLK_IPU2_DI0_PRE] = imx_clk_divider("ipu2_di0_pre", "ipu2_di0_pre_sel", cb + 0x38, 3, 3); - clks[IMX6QDL_CLK_IPU2_DI1_PRE] = imx_clk_divider("ipu2_di1_pre", "ipu2_di1_pre_sel", cb + 0x38, 12, 3); - - clks[IMX6QDL_CLK_IPU1] = imx_clk_gate2("ipu1", "ipu1_podf", cb + 0x74, 0); - clks[IMX6QDL_CLK_IPU1_DI0] = imx_clk_gate2("ipu1_di0", "ipu1_di0_sel", cb + 0x74, 2); - clks[IMX6QDL_CLK_IPU1_DI1] = imx_clk_gate2("ipu1_di1", "ipu1_di1_sel", cb + 0x74, 4); - clks[IMX6QDL_CLK_IPU2] = imx_clk_gate2("ipu2", "ipu2_podf", cb + 0x74, 6); - clks[IMX6QDL_CLK_IPU2_DI0] = imx_clk_gate2("ipu2_di0", "ipu2_di0_sel", cb + 0x74, 8); - clks[IMX6QDL_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_podf", cb + 0x74, 12); - clks[IMX6QDL_CLK_LDB_DI1] = imx_clk_gate2("ldb_di1", "ldb_di1_podf", cb + 0x74, 14); - clks[IMX6QDL_CLK_IPU2_DI1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", cb + 0x74, 10); - - clk_set_parent(clks[IMX6QDL_CLK_IPU1_DI0_SEL], clks[IMX6QDL_CLK_IPU1_DI0_PRE]); - clk_set_parent(clks[IMX6QDL_CLK_IPU1_DI1_SEL], clks[IMX6QDL_CLK_IPU1_DI1_PRE]); - clk_set_parent(clks[IMX6QDL_CLK_IPU2_DI0_SEL], clks[IMX6QDL_CLK_IPU2_DI0_PRE]); - clk_set_parent(clks[IMX6QDL_CLK_IPU2_DI1_SEL], clks[IMX6QDL_CLK_IPU2_DI1_PRE]); - - clk_set_parent(clks[IMX6QDL_CLK_IPU1_DI0_PRE_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]); - clk_set_parent(clks[IMX6QDL_CLK_IPU1_DI1_PRE_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]); - clk_set_parent(clks[IMX6QDL_CLK_IPU2_DI0_PRE_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]); - clk_set_parent(clks[IMX6QDL_CLK_IPU2_DI1_PRE_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]); - - if ((imx_silicon_revision() != IMX_CHIP_REV_1_0) || - cpu_is_mx6dl()) { - clk_set_parent(clks[IMX6QDL_CLK_LDB_DI0_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]); - clk_set_parent(clks[IMX6QDL_CLK_LDB_DI1_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]); - } - -} - -static int imx6_ccm_probe(struct device_d *dev) -{ - struct resource *iores; - void __iomem *base, *anatop_base, *ccm_base; - - anatop_base = (void *)MX6_ANATOP_BASE_ADDR; - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - ccm_base = IOMEM(iores->start); - - base = anatop_base; - - /* type name parent_name base div_mask */ - clks[IMX6QDL_CLK_PLL1_SYS] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f); - clks[IMX6QDL_CLK_PLL2_BUS] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc", base + 0x30, 0x1); - clks[IMX6QDL_CLK_PLL3_USB_OTG] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc", base + 0x10, 0x3); - clks[IMX6QDL_CLK_PLL4_AUDIO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4_audio", "osc", base + 0x70, 0x7f); - clks[IMX6QDL_CLK_PLL5_VIDEO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "osc", base + 0xa0, 0x7f); - clks[IMX6QDL_CLK_PLL8_MLB] = imx_clk_pllv3(IMX_PLLV3_MLB, "pll8_mlb", "osc", base + 0xd0, 0x0); - clks[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_usb_host","osc", base + 0x20, 0x3); - clks[IMX6QDL_CLK_PLL6_ENET] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6_enet", "osc", base + 0xe0, 0x3); - - clks[IMX6QDL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 6); - clks[IMX6QDL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 6); - - clks[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5); - clks[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4); - clks[IMX6QDL_CLK_SATA_REF_100M] = imx_clk_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20); - clks[IMX6QDL_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19); - - clks[IMX6QDL_CLK_ENET_REF] = imx_clk_divider_table("enet_ref", "pll6_enet", base + 0xe0, 0, 2, clk_enet_ref_table); - - clks[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); - clks[IMX6QDL_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); - - clks[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12)); - clks[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13)); - - /* name parent_name reg idx */ - clks[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); - clks[IMX6QDL_CLK_PLL2_PFD1_594M] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); - clks[IMX6QDL_CLK_PLL2_PFD2_396M] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2); - clks[IMX6QDL_CLK_PLL3_PFD0_720M] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0); - clks[IMX6QDL_CLK_PLL3_PFD1_540M] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1); - clks[IMX6QDL_CLK_PLL3_PFD2_508M] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2); - clks[IMX6QDL_CLK_PLL3_PFD3_454M] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3); - - /* name parent_name mult div */ - clks[IMX6QDL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2); - clks[IMX6QDL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4); - clks[IMX6QDL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); - clks[IMX6QDL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); - clks[IMX6QDL_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2); - - base = ccm_base; - - /* name reg shift width parent_names num_parents */ - clks[IMX6QDL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); - clks[IMX6QDL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); - clks[IMX6QDL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); - clks[IMX6QDL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); - clks[IMX6QDL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 1, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); - clks[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); - clks[IMX6QDL_CLK_AXI_SEL] = imx_clk_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_sels)); - clks[IMX6QDL_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); - clks[IMX6QDL_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); - clks[IMX6QDL_CLK_USDHC3_SEL] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); - clks[IMX6QDL_CLK_USDHC4_SEL] = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); - clks[IMX6QDL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 16, 2, enfc_sels, ARRAY_SIZE(enfc_sels)); - clks[IMX6QDL_CLK_EIM_SEL] = imx_clk_mux("eim_sel", base + 0x1c, 27, 2, eim_sels, ARRAY_SIZE(eim_sels)); - clks[IMX6QDL_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_sels, ARRAY_SIZE(eim_sels)); - clks[IMX6QDL_CLK_VDO_AXI_SEL] = imx_clk_mux("vdo_axi_sel", base + 0x18, 11, 1, vdo_axi_sels, ARRAY_SIZE(vdo_axi_sels)); - clks[IMX6QDL_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels)); - clks[IMX6QDL_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels)); - clks[IMX6QDL_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels)); - clks[IMX6QDL_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels)); - - /* name reg shift width busy: reg, shift parent_names num_parents */ - clks[IMX6QDL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); - clks[IMX6QDL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); - - /* name parent_name reg shift width */ - clks[IMX6QDL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); - clks[IMX6QDL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); - clks[IMX6QDL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); - clks[IMX6QDL_CLK_IPG_PER] = imx_clk_divider("ipg_per", "ipg", base + 0x1c, 0, 6); - clks[IMX6QDL_CLK_CAN_ROOT] = imx_clk_divider("can_root", "pll3_usb_otg", base + 0x20, 2, 6); - clks[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6); - clks[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6); - clks[IMX6QDL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); - clks[IMX6QDL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); - clks[IMX6QDL_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3); - clks[IMX6QDL_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3); - clks[IMX6QDL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3); - clks[IMX6QDL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6); - clks[IMX6QDL_CLK_EIM_PODF] = imx_clk_divider("eim_podf", "eim_sel", base + 0x1c, 20, 3); - clks[IMX6QDL_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3); - clks[IMX6QDL_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3); - clks[IMX6QDL_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3); - - /* name parent_name reg shift width busy: reg, shift */ - clks[IMX6QDL_CLK_AXI] = imx_clk_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0); - clks[IMX6QDL_CLK_MMDC_CH0_AXI_PODF] = imx_clk_busy_divider("mmdc_ch0_axi_podf", "periph", base + 0x14, 19, 3, base + 0x48, 4); - clks[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_busy_divider("mmdc_ch1_axi_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2); - clks[IMX6QDL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); - clks[IMX6QDL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); - - /* name parent_name reg shift */ - clks[IMX6QDL_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4); - clks[IMX6QDL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8); - clks[IMX6QDL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10); - clks[IMX6QDL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12); - clks[IMX6QDL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0); - clks[IMX6QDL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2); - clks[IMX6QDL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4); - clks[IMX6QDL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6); - if (cpu_is_mx6dl()) - clks[IMX6DL_CLK_I2C4] = imx_clk_gate2("i2c4", "ipg_per", base + 0x6c, 8); - else - clks[IMX6Q_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8); - clks[IMX6QDL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10); - clks[IMX6QDL_CLK_GPT_IPG] = imx_clk_gate2("gpt_ipg", "ipg", base + 0x6c, 20); - clks[IMX6QDL_CLK_GPT_IPG_PER] = imx_clk_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22); - clks[IMX6QDL_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6); - clks[IMX6QDL_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8); - clks[IMX6QDL_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10); - clks[IMX6QDL_CLK_IIM] = imx_clk_gate2("iim", "ipg", base + 0x70, 12); - clks[IMX6QDL_CLK_ENFC] = imx_clk_gate2("enfc", "enfc_podf", base + 0x70, 14); - clks[IMX6QDL_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0); - clks[IMX6QDL_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12); - clks[IMX6QDL_CLK_PWM1] = imx_clk_gate2("pwm1", "ipg_per", base + 0x78, 16); - clks[IMX6QDL_CLK_PWM2] = imx_clk_gate2("pwm2", "ipg_per", base + 0x78, 18); - clks[IMX6QDL_CLK_PWM3] = imx_clk_gate2("pwm3", "ipg_per", base + 0x78, 20); - clks[IMX6QDL_CLK_PWM4] = imx_clk_gate2("pwm4", "ipg_per", base + 0x78, 22); - clks[IMX6QDL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24); - clks[IMX6QDL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26); - clks[IMX6QDL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc", base + 0x78, 28); - clks[IMX6QDL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30); - clks[IMX6QDL_CLK_SATA] = imx_clk_gate2("sata", "ipg", base + 0x7c, 4); - clks[IMX6QDL_CLK_UART_IPG] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24); - clks[IMX6QDL_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_serial_podf", base + 0x7c, 26); - clks[IMX6QDL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); - clks[IMX6QDL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); - clks[IMX6QDL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); - clks[IMX6QDL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6); - clks[IMX6QDL_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8); - clks[IMX6QDL_CLK_EIM_SLOW] = imx_clk_gate2("eim_slow", "eim_slow_podf", base + 0x80, 10); - clks[IMX6QDL_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7); - clks[IMX6QDL_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24); - - clkdev_add_physbase(clks[IMX6QDL_CLK_IPG], MX6_OCOTP_BASE_ADDR, NULL); - - if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3)) - imx6_add_video_clks(anatop_base, ccm_base); - - writel(0xffffffff, ccm_base + CCGR0); - writel(0xf0ffffff, ccm_base + CCGR1); /* gate GPU3D, GPU2D */ - writel(0xffffffff, ccm_base + CCGR2); - if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3)) - writel(0x3fffffff, ccm_base + CCGR3); /* gate OpenVG */ - else - writel(0x3fff0000, ccm_base + CCGR3); /* gate OpenVG, LDB, IPU1, IPU2 */ - if (IS_ENABLED(CONFIG_PCI_IMX6)) - writel(0xffffffff, ccm_base + CCGR4); - else - writel(0xfffffffc, ccm_base + CCGR4); /* gate PCIe */ - writel(0xffffffff, ccm_base + CCGR5); - writel(0xffff3fff, ccm_base + CCGR6); /* gate VPU */ - writel(0xffffffff, ccm_base + CCGR7); - - clk_data.clks = clks; - clk_data.clk_num = IMX6QDL_CLK_END; - of_clk_add_provider(dev->device_node, of_clk_src_onecell_get, &clk_data); - - clk_enable(clks[IMX6QDL_CLK_MMDC_CH0_AXI_PODF]); - clk_enable(clks[IMX6QDL_CLK_PLL6_ENET]); - clk_enable(clks[IMX6QDL_CLK_SATA_REF_100M]); - clk_enable(clks[IMX6QDL_CLK_ENFC_PODF]); - - clk_set_parent(clks[IMX6QDL_CLK_LVDS1_SEL], clks[IMX6QDL_CLK_SATA_REF_100M]); - - return 0; -} - -static __maybe_unused struct of_device_id imx6_ccm_dt_ids[] = { - { - .compatible = "fsl,imx6q-ccm", - }, { - /* sentinel */ - } -}; - -static struct driver_d imx6_ccm_driver = { - .probe = imx6_ccm_probe, - .name = "imx6-ccm", - .of_compatible = DRV_OF_COMPAT(imx6_ccm_dt_ids), -}; - -static int imx6_ccm_init(void) -{ - return platform_driver_register(&imx6_ccm_driver); -} -core_initcall(imx6_ccm_init); diff --git a/arch/arm/mach-imx/clk-imx6sx.c b/arch/arm/mach-imx/clk-imx6sx.c deleted file mode 100644 index d758957d4d..0000000000 --- a/arch/arm/mach-imx/clk-imx6sx.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Copyright (C) 2014 Freescale Semiconductor, Inc. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" -#include "common.h" - -#define CCDR 0x4 -#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16) - -static const char *step_sels[] = { "osc", "pll2_pfd2_396m", }; -static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; -static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", }; -static const char *periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll4_audio_div", }; -static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", }; -static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "osc", }; -static const char *periph_sels[] = { "periph_pre", "periph_clk2", }; -static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", }; -static const char *ocram_sels[] = { "periph", "pll2_pfd2_396m", "periph", "pll3_pfd1_540m", }; -static const char *gpu_axi_sels[] = { "pll2_pfd2_396m", "pll3_pfd0_720m", "pll3_pfd1_540m", "pll2_bus", }; -static const char *gpu_core_sels[] = { "pll3_pfd1_540m", "pll3_pfd0_720m", "pll2_bus", "pll2_pfd2_396m", }; -static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", }; -static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", }; -static const char *ldb_di0_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_pfd3_594m", "pll2_pfd1_594m", "pll3_pfd3_454m", }; -static const char *ldb_di1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", }; -static const char *pcie_axi_sels[] = { "axi", "ahb", }; -static const char *qspi1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", }; -static const char *perclk_sels[] = { "ipg", "osc", }; -static const char *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; -static const char *vid_sels[] = { "pll3_pfd1_540m", "pll3_usb_otg", "pll3_pfd3_454m", "pll4_audio_div", "pll5_video_div", }; -static const char *uart_sels[] = { "pll3_80m", "osc", }; -static const char *qspi2_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd3_454m", "dummy", "dummy", "dummy", }; -static const char *enet_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", }; -static const char *enet_sels[] = { "enet_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; -static const char *m4_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "osc", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd3_454m", }; -static const char *m4_sels[] = { "m4_pre_sel", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; -static const char *eim_slow_sels[] = { "ocram", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", }; -static const char *ecspi_sels[] = { "pll3_60m", "osc", }; -static const char *lcdif1_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_540m", }; -static const char *lcdif1_sels[] = { "lcdif1_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; -static const char *lcdif2_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd3_594m", "pll3_pfd1_540m", }; -static const char *lcdif2_sels[] = { "lcdif2_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; -static const char *display_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll3_usb_otg", "pll3_pfd1_540m", }; -static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", }; -static const char *cko1_sels[] = { - "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div", - "dummy", "ocram", "dummy", "pxp_axi", "epdc_axi", "lcdif_pix", - "epdc_pix", "ahb", "ipg", "perclk", "ckil", "pll4_audio_div", -}; -static const char *cko2_sels[] = { - "dummy", "mmdc_p0_fast", "usdhc4", "usdhc1", "dummy", "wrck", - "ecspi_root", "dummy", "usdhc3", "pcie", "arm", "csi_core", - "lcdif_axi", "dummy", "osc", "dummy", "gpu2d_ovg_core", - "usdhc2", "ssi1", "ssi2", "ssi3", "gpu2d_core", "dummy", - "dummy", "dummy", "dummy", "esai_extal", "eim_slow", "uart_serial", - "spdif", "asrc", "dummy", -}; -static const char *cko_sels[] = { "cko1", "cko2", }; -static const char *lvds_sels[] = { - "arm", "pll1_sys", "dummy", "dummy", "dummy", "dummy", "dummy", "pll5_video_div", - "dummy", "dummy", "pcie_ref_125m", "dummy", "usbphy1", "usbphy2", -}; -static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", }; -static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", }; -static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", }; -static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", }; -static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", }; -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 *clks[IMX6SX_CLK_CLK_END]; -static struct clk_onecell_data clk_data; - -static struct clk_div_table clk_enet_ref_table[] = { - { .val = 0, .div = 20, }, - { .val = 1, .div = 10, }, - { .val = 2, .div = 5, }, - { .val = 3, .div = 4, }, - { } -}; - -static 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[] = { - { .val = 0, .div = 1, }, - { .val = 1, .div = 2, }, - { .val = 2, .div = 1, }, - { .val = 3, .div = 4, }, - { } -}; - -static int imx6sx_ccm_probe(struct device_d *dev) -{ - struct resource *iores; - void __iomem *base, *anatop_base, *ccm_base; - struct device_node *ccm_node = dev->device_node; - - clks[IMX6SX_CLK_DUMMY] = clk_fixed("dummy", 0); - - anatop_base = (void *)MX6_ANATOP_BASE_ADDR; - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - ccm_base = IOMEM(iores->start); - - base = anatop_base; - - clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - clks[IMX6SX_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - clks[IMX6SX_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - clks[IMX6SX_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - clks[IMX6SX_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - clks[IMX6SX_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - - /* type name parent_name base div_mask */ - clks[IMX6SX_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f); - clks[IMX6SX_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1); - clks[IMX6SX_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3); - clks[IMX6SX_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f); - clks[IMX6SX_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f); - clks[IMX6SX_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3); - clks[IMX6SX_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3); - - clks[IMX6SX_PLL1_BYPASS] = imx_clk_mux_p("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels)); - clks[IMX6SX_PLL2_BYPASS] = imx_clk_mux_p("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels)); - clks[IMX6SX_PLL3_BYPASS] = imx_clk_mux_p("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels)); - clks[IMX6SX_PLL4_BYPASS] = imx_clk_mux_p("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels)); - clks[IMX6SX_PLL5_BYPASS] = imx_clk_mux_p("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels)); - clks[IMX6SX_PLL6_BYPASS] = imx_clk_mux_p("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels)); - clks[IMX6SX_PLL7_BYPASS] = imx_clk_mux_p("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels)); - - /* Do not bypass PLLs initially */ - clk_set_parent(clks[IMX6SX_PLL1_BYPASS], clks[IMX6SX_CLK_PLL1]); - clk_set_parent(clks[IMX6SX_PLL2_BYPASS], clks[IMX6SX_CLK_PLL2]); - clk_set_parent(clks[IMX6SX_PLL3_BYPASS], clks[IMX6SX_CLK_PLL3]); - clk_set_parent(clks[IMX6SX_PLL4_BYPASS], clks[IMX6SX_CLK_PLL4]); - clk_set_parent(clks[IMX6SX_PLL5_BYPASS], clks[IMX6SX_CLK_PLL5]); - clk_set_parent(clks[IMX6SX_PLL6_BYPASS], clks[IMX6SX_CLK_PLL6]); - clk_set_parent(clks[IMX6SX_PLL7_BYPASS], clks[IMX6SX_CLK_PLL7]); - - clks[IMX6SX_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13); - clks[IMX6SX_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13); - clks[IMX6SX_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13); - clks[IMX6SX_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13); - clks[IMX6SX_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13); - clks[IMX6SX_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13); - clks[IMX6SX_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13); - - /* - * Bit 20 is the reserved and read-only bit, we do this only for: - * - Do nothing for usbphy clk_enable/disable - * - Keep refcount when do usbphy clk_enable/disable, in that case, - * the clk framework may need to enable/disable usbphy's parent - */ - clks[IMX6SX_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20); - clks[IMX6SX_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20); - - /* - * usbphy*_gate needs to be on after system boots up, and software - * never needs to control it anymore. - */ - clks[IMX6SX_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6); - clks[IMX6SX_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6); - - /* FIXME 100Mhz is used for pcie ref for all imx6 pcie, excepted imx6q */ - clks[IMX6SX_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 5); - clks[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19); - - clks[IMX6SX_CLK_ENET_REF] = imx_clk_divider_table("enet_ref", "pll6_enet", - base + 0xe0, 0, 2, clk_enet_ref_table); - clks[IMX6SX_CLK_ENET2_REF] = imx_clk_divider_table("enet2_ref", "pll6_enet", - base + 0xe0, 2, 2, clk_enet_ref_table); - clks[IMX6SX_CLK_ENET2_REF_125M] = imx_clk_gate("enet2_ref_125m", "enet2_ref", base + 0xe0, 20); - - clks[IMX6SX_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20); - clks[IMX6SX_CLK_ENET_PTP] = imx_clk_gate("enet_ptp_25m", "enet_ptp_ref", base + 0xe0, 21); - - /* name parent_name reg idx */ - clks[IMX6SX_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); - clks[IMX6SX_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); - clks[IMX6SX_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2); - clks[IMX6SX_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3); - clks[IMX6SX_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0); - clks[IMX6SX_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1); - clks[IMX6SX_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2); - clks[IMX6SX_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3); - - /* name parent_name mult div */ - clks[IMX6SX_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2); - clks[IMX6SX_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4); - clks[IMX6SX_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); - clks[IMX6SX_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); - clks[IMX6SX_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2); - clks[IMX6SX_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8); - - clks[IMX6SX_CLK_PLL4_POST_DIV] = imx_clk_divider_table("pll4_post_div", "pll4_audio", - base + 0x70, 19, 2, post_div_table); - clks[IMX6SX_CLK_PLL4_AUDIO_DIV] = imx_clk_divider("pll4_audio_div", "pll4_post_div", - base + 0x170, 15, 1); - clks[IMX6SX_CLK_PLL5_POST_DIV] = imx_clk_divider_table("pll5_post_div", "pll5_video", - base + 0xa0, 19, 2, post_div_table); - clks[IMX6SX_CLK_PLL5_VIDEO_DIV] = imx_clk_divider_table("pll5_video_div", "pll5_post_div", - base + 0x170, 30, 2, video_div_table); - - /* name reg shift width parent_names num_parents */ - clks[IMX6SX_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); - - base = ccm_base; - - /* name reg shift width parent_names num_parents */ - clks[IMX6SX_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); - clks[IMX6SX_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); - clks[IMX6SX_CLK_OCRAM_SEL] = imx_clk_mux("ocram_sel", base + 0x14, 6, 2, ocram_sels, ARRAY_SIZE(ocram_sels)); - clks[IMX6SX_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); - clks[IMX6SX_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels)); - clks[IMX6SX_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); - clks[IMX6SX_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)); - clks[IMX6SX_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels)); - clks[IMX6SX_CLK_GPU_AXI_SEL] = imx_clk_mux("gpu_axi_sel", base + 0x18, 8, 2, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); - clks[IMX6SX_CLK_GPU_CORE_SEL] = imx_clk_mux("gpu_core_sel", base + 0x18, 4, 2, gpu_core_sels, ARRAY_SIZE(gpu_core_sels)); - clks[IMX6SX_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels)); - clks[IMX6SX_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); - clks[IMX6SX_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); - clks[IMX6SX_CLK_USDHC3_SEL] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); - clks[IMX6SX_CLK_USDHC4_SEL] = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); - clks[IMX6SX_CLK_QSPI1_SEL] = imx_clk_mux_p("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels)); - clks[IMX6SX_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels)); - clks[IMX6SX_CLK_VID_SEL] = imx_clk_mux("vid_sel", base + 0x20, 21, 3, vid_sels, ARRAY_SIZE(vid_sels)); - clks[IMX6SX_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels)); - clks[IMX6SX_CLK_QSPI2_SEL] = imx_clk_mux_p("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels)); - clks[IMX6SX_CLK_ENET_PRE_SEL] = imx_clk_mux("enet_pre_sel", base + 0x34, 15, 3, enet_pre_sels, ARRAY_SIZE(enet_pre_sels)); - clks[IMX6SX_CLK_ENET_SEL] = imx_clk_mux("enet_sel", base + 0x34, 9, 3, enet_sels, ARRAY_SIZE(enet_sels)); - clks[IMX6SX_CLK_M4_PRE_SEL] = imx_clk_mux("m4_pre_sel", base + 0x34, 6, 3, m4_pre_sels, ARRAY_SIZE(m4_pre_sels)); - clks[IMX6SX_CLK_M4_SEL] = imx_clk_mux("m4_sel", base + 0x34, 0, 3, m4_sels, ARRAY_SIZE(m4_sels)); - clks[IMX6SX_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels)); - clks[IMX6SX_CLK_LCDIF2_PRE_SEL] = imx_clk_mux("lcdif2_pre_sel", base + 0x38, 6, 3, lcdif2_pre_sels, ARRAY_SIZE(lcdif2_pre_sels)); - clks[IMX6SX_CLK_LCDIF2_SEL] = imx_clk_mux("lcdif2_sel", base + 0x38, 0, 3, lcdif2_sels, ARRAY_SIZE(lcdif2_sels)); - clks[IMX6SX_CLK_DISPLAY_SEL] = imx_clk_mux("display_sel", base + 0x3c, 14, 2, display_sels, ARRAY_SIZE(display_sels)); - clks[IMX6SX_CLK_CSI_SEL] = imx_clk_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels)); - clks[IMX6SX_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels)); - clks[IMX6SX_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels)); - clks[IMX6SX_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels)); - - clks[IMX6SX_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux_p("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels)); - clks[IMX6SX_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux_p("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels)); - clks[IMX6SX_CLK_LDB_DI1_SEL] = imx_clk_mux_p("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels)); - clks[IMX6SX_CLK_LDB_DI0_SEL] = imx_clk_mux_p("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels)); - clks[IMX6SX_CLK_LCDIF1_PRE_SEL] = imx_clk_mux_p("lcdif1_pre_sel", base + 0x38, 15, 3, lcdif1_pre_sels, ARRAY_SIZE(lcdif1_pre_sels)); - clks[IMX6SX_CLK_LCDIF1_SEL] = imx_clk_mux_p("lcdif1_sel", base + 0x38, 9, 3, lcdif1_sels, ARRAY_SIZE(lcdif1_sels)); - - /* name parent_name reg shift width */ - clks[IMX6SX_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); - clks[IMX6SX_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); - clks[IMX6SX_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); - clks[IMX6SX_CLK_GPU_CORE_PODF] = imx_clk_divider("gpu_core_podf", "gpu_core_sel", base + 0x18, 29, 3); - clks[IMX6SX_CLK_GPU_AXI_PODF] = imx_clk_divider("gpu_axi_podf", "gpu_axi_sel", base + 0x18, 26, 3); - clks[IMX6SX_CLK_LCDIF1_PODF] = imx_clk_divider("lcdif1_podf", "lcdif1_pred", base + 0x18, 23, 3); - clks[IMX6SX_CLK_QSPI1_PODF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3); - clks[IMX6SX_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3); - clks[IMX6SX_CLK_LCDIF2_PODF] = imx_clk_divider("lcdif2_podf", "lcdif2_pred", base + 0x1c, 20, 3); - clks[IMX6SX_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6); - clks[IMX6SX_CLK_VID_PODF] = imx_clk_divider("vid_podf", "vid_sel", base + 0x20, 24, 2); - clks[IMX6SX_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3); - clks[IMX6SX_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3); - clks[IMX6SX_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); - clks[IMX6SX_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); - clks[IMX6SX_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6); - clks[IMX6SX_CLK_QSPI2_PRED] = imx_clk_divider("qspi2_pred", "qspi2_sel", base + 0x2c, 18, 3); - clks[IMX6SX_CLK_QSPI2_PODF] = imx_clk_divider("qspi2_podf", "qspi2_pred", base + 0x2c, 21, 6); - clks[IMX6SX_CLK_ENET_PODF] = imx_clk_divider("enet_podf", "enet_pre_sel", base + 0x34, 12, 3); - clks[IMX6SX_CLK_M4_PODF] = imx_clk_divider("m4_podf", "m4_sel", base + 0x34, 3, 3); - clks[IMX6SX_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6); - clks[IMX6SX_CLK_LCDIF1_PRED] = imx_clk_divider("lcdif1_pred", "lcdif1_pre_sel", base + 0x38, 12, 3); - clks[IMX6SX_CLK_LCDIF2_PRED] = imx_clk_divider("lcdif2_pred", "lcdif2_pre_sel", base + 0x38, 3, 3); - clks[IMX6SX_CLK_DISPLAY_PODF] = imx_clk_divider("display_podf", "display_sel", base + 0x3c, 16, 3); - clks[IMX6SX_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3); - clks[IMX6SX_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3); - clks[IMX6SX_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3); - - clks[IMX6SX_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); - clks[IMX6SX_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7); - clks[IMX6SX_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); - clks[IMX6SX_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7); - - /* name reg shift width busy: reg, shift parent_names num_parents */ - clks[IMX6SX_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); - clks[IMX6SX_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); - /* name parent_name reg shift width busy: reg, shift */ - clks[IMX6SX_CLK_OCRAM_PODF] = imx_clk_busy_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3, base + 0x48, 0); - clks[IMX6SX_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); - clks[IMX6SX_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2); - clks[IMX6SX_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); - - /* name parent_name reg shift */ - /* CCGR0 */ - clks[IMX6SX_CLK_AIPS_TZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0); - clks[IMX6SX_CLK_AIPS_TZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2); - clks[IMX6SX_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4); - clks[IMX6SX_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8); - clks[IMX6SX_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10); - clks[IMX6SX_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12); - clks[IMX6SX_CLK_DCIC1] = imx_clk_gate2("dcic1", "display_podf", base + 0x68, 24); - clks[IMX6SX_CLK_DCIC2] = imx_clk_gate2("dcic2", "display_podf", base + 0x68, 26); - clks[IMX6SX_CLK_AIPS_TZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30); - - /* CCGR1 */ - clks[IMX6SX_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); - clks[IMX6SX_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2); - clks[IMX6SX_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4); - clks[IMX6SX_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6); - clks[IMX6SX_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_podf", base + 0x6c, 8); - clks[IMX6SX_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12); - clks[IMX6SX_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14); - clks[IMX6SX_CLK_WAKEUP] = imx_clk_gate2("wakeup", "ipg", base + 0x6c, 18); - clks[IMX6SX_CLK_GPT_BUS] = imx_clk_gate2("gpt_bus", "perclk", base + 0x6c, 20); - clks[IMX6SX_CLK_GPT_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x6c, 22); - clks[IMX6SX_CLK_GPU] = imx_clk_gate2("gpu", "gpu_core_podf", base + 0x6c, 26); - - /* CCGR2 */ - clks[IMX6SX_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2); - clks[IMX6SX_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6); - clks[IMX6SX_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8); - clks[IMX6SX_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); - clks[IMX6SX_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); - clks[IMX6SX_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif1_podf", base + 0x70, 14); - clks[IMX6SX_CLK_IPMUX1] = imx_clk_gate2("ipmux1", "ahb", base + 0x70, 16); - clks[IMX6SX_CLK_IPMUX2] = imx_clk_gate2("ipmux2", "ahb", base + 0x70, 18); - clks[IMX6SX_CLK_IPMUX3] = imx_clk_gate2("ipmux3", "ahb", base + 0x70, 20); - clks[IMX6SX_CLK_TZASC1] = imx_clk_gate2("tzasc1", "mmdc_podf", base + 0x70, 22); - clks[IMX6SX_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "display_podf", base + 0x70, 28); - clks[IMX6SX_CLK_PXP_AXI] = imx_clk_gate2("pxp_axi", "display_podf", base + 0x70, 30); - - /* CCGR3 */ - clks[IMX6SX_CLK_M4] = imx_clk_gate2("m4", "m4_podf", base + 0x74, 2); - clks[IMX6SX_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4); - clks[IMX6SX_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "enet_sel", base + 0x74, 4); - clks[IMX6SX_CLK_DISPLAY_AXI] = imx_clk_gate2("display_axi", "display_podf", base + 0x74, 6); - clks[IMX6SX_CLK_LCDIF2_PIX] = imx_clk_gate2("lcdif2_pix", "lcdif2_sel", base + 0x74, 8); - clks[IMX6SX_CLK_LCDIF1_PIX] = imx_clk_gate2("lcdif1_pix", "lcdif1_sel", base + 0x74, 10); - clks[IMX6SX_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_div_sel", base + 0x74, 12); - clks[IMX6SX_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14); - clks[IMX6SX_CLK_MLB] = imx_clk_gate2("mlb", "ahb", base + 0x74, 18); - clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20); - clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24); - clks[IMX6SX_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28); - - /* CCGR4 */ - clks[IMX6SX_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "display_podf", base + 0x78, 0); - clks[IMX6SX_CLK_QSPI2] = imx_clk_gate2("qspi2", "qspi2_podf", base + 0x78, 10); - clks[IMX6SX_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12); - clks[IMX6SX_CLK_PER2_MAIN] = imx_clk_gate2("per2_main", "ahb", base + 0x78, 14); - clks[IMX6SX_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16); - clks[IMX6SX_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18); - clks[IMX6SX_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20); - clks[IMX6SX_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22); - clks[IMX6SX_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24); - clks[IMX6SX_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26); - clks[IMX6SX_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "qspi2_podf", base + 0x78, 28); - clks[IMX6SX_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30); - - /* CCGR5 */ - clks[IMX6SX_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); - clks[IMX6SX_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); - clks[IMX6SX_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); - clks[IMX6SX_CLK_UART_IPG] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24); - clks[IMX6SX_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_podf", base + 0x7c, 26); - clks[IMX6SX_CLK_SAI1_IPG] = imx_clk_gate2("sai1_ipg", "ipg", base + 0x7c, 28); - clks[IMX6SX_CLK_SAI2_IPG] = imx_clk_gate2("sai2_ipg", "ipg", base + 0x7c, 30); - - /* CCGR6 */ - clks[IMX6SX_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); - clks[IMX6SX_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); - clks[IMX6SX_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); - clks[IMX6SX_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6); - clks[IMX6SX_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8); - clks[IMX6SX_CLK_EIM_SLOW] = imx_clk_gate2("eim_slow", "eim_slow_podf", base + 0x80, 10); - clks[IMX6SX_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16); - clks[IMX6SX_CLK_VADC] = imx_clk_gate2("vadc", "vid_podf", base + 0x80, 20); - clks[IMX6SX_CLK_GIS] = imx_clk_gate2("gis", "display_podf", base + 0x80, 22); - clks[IMX6SX_CLK_I2C4] = imx_clk_gate2("i2c4", "perclk", base + 0x80, 24); - clks[IMX6SX_CLK_PWM5] = imx_clk_gate2("pwm5", "perclk", base + 0x80, 26); - clks[IMX6SX_CLK_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28); - clks[IMX6SX_CLK_PWM7] = imx_clk_gate2("pwm7", "perclk", base + 0x80, 30); - - clks[IMX6SX_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7); - clks[IMX6SX_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24); - - /* mask handshake of mmdc */ - writel(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR); - - clk_data.clks = clks; - clk_data.clk_num = ARRAY_SIZE(clks); - of_clk_add_provider(ccm_node, of_clk_src_onecell_get, &clk_data); - - if (IS_ENABLED(CONFIG_USB_IMX_PHY)) { - clk_enable(clks[IMX6SX_CLK_USBPHY1_GATE]); - clk_enable(clks[IMX6SX_CLK_USBPHY2_GATE]); - } - - return 0; -}; - -static int imx6sx_clocks_init(void) -{ - if (!of_machine_is_compatible("fsl,imx6sx")) - return 0; - - /* Set the default 132MHz for EIM module */ - clk_set_parent(clks[IMX6SX_CLK_EIM_SLOW_SEL], clks[IMX6SX_CLK_PLL2_PFD2]); - clk_set_rate(clks[IMX6SX_CLK_EIM_SLOW], 132000000); - - /* set parent clock for LCDIF1 pixel clock */ - clk_set_parent(clks[IMX6SX_CLK_LCDIF1_PRE_SEL], clks[IMX6SX_CLK_PLL5_VIDEO_DIV]); - clk_set_parent(clks[IMX6SX_CLK_LCDIF1_SEL], clks[IMX6SX_CLK_LCDIF1_PODF]); - - /* - * Init enet system AHB clock, set to 200Mhz - * pll2_pfd2_396m-> ENET_PODF-> ENET_AHB - */ - clk_set_parent(clks[IMX6SX_CLK_ENET_PRE_SEL], clks[IMX6SX_CLK_PLL2_PFD2]); - clk_set_parent(clks[IMX6SX_CLK_ENET_SEL], clks[IMX6SX_CLK_ENET_PODF]); - clk_set_rate(clks[IMX6SX_CLK_ENET_PODF], 200000000); - clk_set_rate(clks[IMX6SX_CLK_ENET_REF], 125000000); - clk_set_rate(clks[IMX6SX_CLK_ENET2_REF], 125000000); - - /* Set parent clock for vadc */ - clk_set_parent(clks[IMX6SX_CLK_VID_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]); - - /* Update gpu clock from default 528M to 720M */ - clk_set_parent(clks[IMX6SX_CLK_GPU_CORE_SEL], clks[IMX6SX_CLK_PLL3_PFD0]); - clk_set_parent(clks[IMX6SX_CLK_GPU_AXI_SEL], clks[IMX6SX_CLK_PLL3_PFD0]); - - return 0; -} -coredevice_initcall(imx6sx_clocks_init); - -static __maybe_unused struct of_device_id imx6sx_ccm_dt_ids[] = { - { - .compatible = "fsl,imx6sx-ccm", - }, { - /* sentinel */ - } -}; - -static struct driver_d imx6sx_ccm_driver = { - .probe = imx6sx_ccm_probe, - .name = "imx6-ccm", - .of_compatible = DRV_OF_COMPAT(imx6sx_ccm_dt_ids), -}; - -static int imx6sx_ccm_init(void) -{ - return platform_driver_register(&imx6sx_ccm_driver); -} -core_initcall(imx6sx_ccm_init); diff --git a/arch/arm/mach-imx/clk-pfd.c b/arch/arm/mach-imx/clk-pfd.c deleted file mode 100644 index 8f6d5ad7a8..0000000000 --- a/arch/arm/mach-imx/clk-pfd.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2012 Freescale Semiconductor, Inc. - * Copyright 2012 Linaro Ltd. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -/** - * struct clk_pfd - IMX PFD clock - * @clk_hw: clock source - * @reg: PFD register address - * @idx: the index of PFD encoded in the register - * - * PFD clock found on i.MX6 series. Each register for PFD has 4 clk_pfd - * data encoded, and member idx is used to specify the one. And each - * register has SET, CLR and TOG registers at offset 0x4 0x8 and 0xc. - */ -struct clk_pfd { - struct clk clk; - void __iomem *reg; - u8 idx; - const char *parent; -}; - -#define to_clk_pfd(_clk) container_of(_clk, struct clk_pfd, clk) - -#define SET 0x4 -#define CLR 0x8 -#define OTG 0xc - -static int clk_pfd_enable(struct clk *clk) -{ - struct clk_pfd *pfd = to_clk_pfd(clk); - writel(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR); - - return 0; -} - -static void clk_pfd_disable(struct clk *clk) -{ - struct clk_pfd *pfd = to_clk_pfd(clk); - - writel(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET); -} - -static unsigned long clk_pfd_recalc_rate(struct clk *clk, - unsigned long parent_rate) -{ - struct clk_pfd *pfd = to_clk_pfd(clk); - u64 tmp = parent_rate; - u8 frac = (readl(pfd->reg) >> (pfd->idx * 8)) & 0x3f; - - tmp *= 18; - do_div(tmp, frac); - - return tmp; -} - -static long clk_pfd_round_rate(struct clk *clk, unsigned long rate, - unsigned long *prate) -{ - u64 tmp = *prate; - u8 frac; - - tmp = tmp * 18 + rate / 2; - do_div(tmp, rate); - frac = tmp; - if (frac < 12) - frac = 12; - else if (frac > 35) - frac = 35; - tmp = *prate; - tmp *= 18; - do_div(tmp, frac); - - return tmp; -} - -static int clk_pfd_set_rate(struct clk *clk, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_pfd *pfd = to_clk_pfd(clk); - u64 tmp = parent_rate; - u8 frac; - - tmp = tmp * 18 + rate / 2; - do_div(tmp, rate); - frac = tmp; - if (frac < 12) - frac = 12; - else if (frac > 35) - frac = 35; - - writel(0x3f << (pfd->idx * 8), pfd->reg + CLR); - writel(frac << (pfd->idx * 8), pfd->reg + SET); - - return 0; -} - -static const struct clk_ops clk_pfd_ops = { - .enable = clk_pfd_enable, - .disable = clk_pfd_disable, - .recalc_rate = clk_pfd_recalc_rate, - .round_rate = clk_pfd_round_rate, - .set_rate = clk_pfd_set_rate, -}; - -struct clk *imx_clk_pfd(const char *name, const char *parent, - void __iomem *reg, u8 idx) -{ - struct clk_pfd *pfd; - int ret; - - pfd = xzalloc(sizeof(*pfd)); - - pfd->reg = reg; - pfd->idx = idx; - pfd->parent = parent; - pfd->clk.name = name; - pfd->clk.ops = &clk_pfd_ops; - pfd->clk.parent_names = &pfd->parent; - pfd->clk.num_parents = 1; - - ret = clk_register(&pfd->clk); - if (ret) { - free(pfd); - return ERR_PTR(ret); - } - - return &pfd->clk; -} diff --git a/arch/arm/mach-imx/clk-pllv1.c b/arch/arm/mach-imx/clk-pllv1.c deleted file mode 100644 index f992134f7e..0000000000 --- a/arch/arm/mach-imx/clk-pllv1.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -struct clk_pllv1 { - struct clk clk; - void __iomem *reg; - const char *parent; -}; - -static unsigned long clk_pllv1_recalc_rate(struct clk *clk, - unsigned long parent_rate) -{ - struct clk_pllv1 *pll = container_of(clk, struct clk_pllv1, clk); - unsigned long long ll; - int mfn_abs; - unsigned int mfi, mfn, mfd, pd; - u32 reg_val = readl(pll->reg); - unsigned long freq = parent_rate; - - mfi = (reg_val >> 10) & 0xf; - mfn = reg_val & 0x3ff; - mfd = (reg_val >> 16) & 0x3ff; - pd = (reg_val >> 26) & 0xf; - - mfi = mfi <= 5 ? 5 : mfi; - - mfn_abs = mfn; - -#if !defined CONFIG_ARCH_MX1 && !defined CONFIG_ARCH_MX21 - if (mfn >= 0x200) { - mfn |= 0xFFFFFE00; - mfn_abs = -mfn; - } -#endif - - freq *= 2; - freq /= pd + 1; - - ll = (unsigned long long)freq * mfn_abs; - - do_div(ll, mfd + 1); - if (mfn < 0) - ll = (freq * mfi) - ll; - else - ll = (freq * mfi) + ll; - - return ll; -} - -struct clk_ops clk_pllv1_ops = { - .recalc_rate = clk_pllv1_recalc_rate, -}; - -struct clk *imx_clk_pllv1(const char *name, const char *parent, - void __iomem *base) -{ - struct clk_pllv1 *pll = xzalloc(sizeof(*pll)); - int ret; - - pll->parent = parent; - pll->reg = base; - pll->clk.ops = &clk_pllv1_ops; - pll->clk.name = name; - pll->clk.parent_names = &pll->parent; - pll->clk.num_parents = 1; - - ret = clk_register(&pll->clk); - if (ret) { - free(pll); - return ERR_PTR(ret); - } - - return &pll->clk; -} diff --git a/arch/arm/mach-imx/clk-pllv2.c b/arch/arm/mach-imx/clk-pllv2.c deleted file mode 100644 index 5ba07fa5e6..0000000000 --- a/arch/arm/mach-imx/clk-pllv2.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -/* PLL Register Offsets */ -#define MXC_PLL_DP_CTL 0x00 -#define MXC_PLL_DP_CONFIG 0x04 -#define MXC_PLL_DP_OP 0x08 -#define MXC_PLL_DP_MFD 0x0C -#define MXC_PLL_DP_MFN 0x10 -#define MXC_PLL_DP_MFNMINUS 0x14 -#define MXC_PLL_DP_MFNPLUS 0x18 -#define MXC_PLL_DP_HFS_OP 0x1C -#define MXC_PLL_DP_HFS_MFD 0x20 -#define MXC_PLL_DP_HFS_MFN 0x24 -#define MXC_PLL_DP_MFN_TOGC 0x28 -#define MXC_PLL_DP_DESTAT 0x2c - -/* PLL Register Bit definitions */ -#define MXC_PLL_DP_CTL_MUL_CTRL 0x2000 -#define MXC_PLL_DP_CTL_DPDCK0_2_EN 0x1000 -#define MXC_PLL_DP_CTL_DPDCK0_2_OFFSET 12 -#define MXC_PLL_DP_CTL_ADE 0x800 -#define MXC_PLL_DP_CTL_REF_CLK_DIV 0x400 -#define MXC_PLL_DP_CTL_REF_CLK_SEL_MASK (3 << 8) -#define MXC_PLL_DP_CTL_REF_CLK_SEL_OFFSET 8 -#define MXC_PLL_DP_CTL_HFSM 0x80 -#define MXC_PLL_DP_CTL_PRE 0x40 -#define MXC_PLL_DP_CTL_UPEN 0x20 -#define MXC_PLL_DP_CTL_RST 0x10 -#define MXC_PLL_DP_CTL_RCP 0x8 -#define MXC_PLL_DP_CTL_PLM 0x4 -#define MXC_PLL_DP_CTL_BRM0 0x2 -#define MXC_PLL_DP_CTL_LRF 0x1 - -#define MXC_PLL_DP_CONFIG_BIST 0x8 -#define MXC_PLL_DP_CONFIG_SJC_CE 0x4 -#define MXC_PLL_DP_CONFIG_AREN 0x2 -#define MXC_PLL_DP_CONFIG_LDREQ 0x1 - -#define MXC_PLL_DP_OP_MFI_OFFSET 4 -#define MXC_PLL_DP_OP_MFI_MASK (0xF << 4) -#define MXC_PLL_DP_OP_PDF_OFFSET 0 -#define MXC_PLL_DP_OP_PDF_MASK 0xF - -#define MXC_PLL_DP_MFD_OFFSET 0 -#define MXC_PLL_DP_MFD_MASK 0x07FFFFFF - -#define MXC_PLL_DP_MFN_OFFSET 0x0 -#define MXC_PLL_DP_MFN_MASK 0x07FFFFFF - -#define MXC_PLL_DP_MFN_TOGC_TOG_DIS (1 << 17) -#define MXC_PLL_DP_MFN_TOGC_TOG_EN (1 << 16) -#define MXC_PLL_DP_MFN_TOGC_CNT_OFFSET 0x0 -#define MXC_PLL_DP_MFN_TOGC_CNT_MASK 0xFFFF - -#define MXC_PLL_DP_DESTAT_TOG_SEL (1 << 31) -#define MXC_PLL_DP_DESTAT_MFN 0x07FFFFFF - -#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */ - -struct clk_pllv2 { - struct clk clk; - void __iomem *reg; - const char *parent; -}; - -static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate, - u32 dp_ctl, u32 dp_op, u32 dp_mfd, u32 dp_mfn) -{ - long mfi, mfn, mfd, pdf, ref_clk, mfn_abs; - unsigned long dbl; - uint64_t temp; - - dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN; - - pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK; - mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET; - mfi = (mfi <= 5) ? 5 : mfi; - mfd = dp_mfd & MXC_PLL_DP_MFD_MASK; - mfn = mfn_abs = dp_mfn & MXC_PLL_DP_MFN_MASK; - /* Sign extend to 32-bits */ - if (mfn >= 0x04000000) { - mfn |= 0xFC000000; - mfn_abs = -mfn; - } - - ref_clk = 2 * parent_rate; - if (dbl != 0) - ref_clk *= 2; - - ref_clk /= (pdf + 1); - temp = (u64) ref_clk * mfn_abs; - do_div(temp, mfd + 1); - if (mfn < 0) - temp = (ref_clk * mfi) - temp; - else - temp = (ref_clk * mfi) + temp; - - return temp; -} - -static unsigned long clk_pllv2_recalc_rate(struct clk *clk, - unsigned long parent_rate) -{ - u32 dp_op, dp_mfd, dp_mfn, dp_ctl; - void __iomem *pllbase; - struct clk_pllv2 *pll = container_of(clk, struct clk_pllv2, clk); - - pllbase = pll->reg; - - dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); - dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP); - dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD); - dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN); - - return __clk_pllv2_recalc_rate(parent_rate, dp_ctl, dp_op, dp_mfd, dp_mfn); -} - -static int __clk_pllv2_set_rate(unsigned long rate, unsigned long parent_rate, - u32 *dp_op, u32 *dp_mfd, u32 *dp_mfn) -{ - u32 reg; - long mfi, pdf, mfn, mfd = 999999; - u64 temp64; - unsigned long quad_parent_rate; - - quad_parent_rate = 4 * parent_rate; - pdf = mfi = -1; - while (++pdf < 16 && mfi < 5) - mfi = rate * (pdf+1) / quad_parent_rate; - if (mfi > 15) - return -EINVAL; - pdf--; - - temp64 = rate * (pdf + 1) - quad_parent_rate * mfi; - do_div(temp64, quad_parent_rate / 1000000); - mfn = (long)temp64; - - reg = mfi << 4 | pdf; - - *dp_op = reg; - *dp_mfd = mfd; - *dp_mfn = mfn; - - return 0; -} - -static int clk_pllv2_set_rate(struct clk *clk, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_pllv2 *pll = container_of(clk, struct clk_pllv2, clk); - void __iomem *pllbase; - u32 dp_ctl, dp_op, dp_mfd, dp_mfn; - int ret; - - pllbase = pll->reg; - - ret = __clk_pllv2_set_rate(rate, parent_rate, &dp_op, &dp_mfd, &dp_mfn); - if (ret) - return ret; - - dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); - /* use dpdck0_2 */ - __raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL); - - __raw_writel(dp_op, pllbase + MXC_PLL_DP_OP); - __raw_writel(dp_mfd, pllbase + MXC_PLL_DP_MFD); - __raw_writel(dp_mfn, pllbase + MXC_PLL_DP_MFN); - - return 0; -} - -static long clk_pllv2_round_rate(struct clk *clk, unsigned long rate, - unsigned long *prate) -{ - u32 dp_op, dp_mfd, dp_mfn; - - __clk_pllv2_set_rate(rate, *prate, &dp_op, &dp_mfd, &dp_mfn); - return __clk_pllv2_recalc_rate(*prate, MXC_PLL_DP_CTL_DPDCK0_2_EN, - dp_op, dp_mfd, dp_mfn); -} - -struct clk_ops clk_pllv2_ops = { - .recalc_rate = clk_pllv2_recalc_rate, - .round_rate = clk_pllv2_round_rate, - .set_rate = clk_pllv2_set_rate, -}; - -struct clk *imx_clk_pllv2(const char *name, const char *parent, - void __iomem *base) -{ - struct clk_pllv2 *pll = xzalloc(sizeof(*pll)); - int ret; - - pll->parent = parent; - pll->reg = base; - pll->clk.ops = &clk_pllv2_ops; - pll->clk.name = name; - pll->clk.parent_names = &pll->parent; - pll->clk.num_parents = 1; - - ret = clk_register(&pll->clk); - if (ret) { - free(pll); - return ERR_PTR(ret); - } - - return &pll->clk; -} diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c deleted file mode 100644 index e38dcdfdaa..0000000000 --- a/arch/arm/mach-imx/clk-pllv3.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * 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; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -#define PLL_NUM_OFFSET 0x10 -#define PLL_DENOM_OFFSET 0x20 - -#define BM_PLL_POWER (0x1 << 12) -#define BM_PLL_ENABLE (0x1 << 13) -#define BM_PLL_BYPASS (0x1 << 16) -#define BM_PLL_LOCK (0x1 << 31) - -struct clk_pllv3 { - struct clk clk; - void __iomem *base; - bool powerup_set; - u32 div_mask; - const char *parent; -}; - -#define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk) - -static int clk_pllv3_enable(struct clk *clk) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - u32 val; - int timeout = 10000; - - val = readl(pll->base); - val &= ~BM_PLL_BYPASS; - if (pll->powerup_set) - val |= BM_PLL_POWER; - else - val &= ~BM_PLL_POWER; - writel(val, pll->base); - - /* Wait for PLL to lock */ - while (timeout--) { - if (readl(pll->base) & BM_PLL_LOCK) - break; - } - - if (!timeout) - return -ETIMEDOUT; - - val = readl(pll->base); - val |= BM_PLL_ENABLE; - writel(val, pll->base); - - return 0; -} - -static void clk_pllv3_disable(struct clk *clk) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - u32 val; - - val = readl(pll->base); - val &= ~BM_PLL_ENABLE; - writel(val, pll->base); - - val |= BM_PLL_BYPASS; - if (pll->powerup_set) - val &= ~BM_PLL_POWER; - else - val |= BM_PLL_POWER; - writel(val, pll->base); -} - -static unsigned long clk_pllv3_recalc_rate(struct clk *clk, - unsigned long parent_rate) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - u32 div = readl(pll->base) & pll->div_mask; - - return (div == 1) ? parent_rate * 22 : parent_rate * 20; -} - -static long clk_pllv3_round_rate(struct clk *clk, unsigned long rate, - unsigned long *prate) -{ - unsigned long parent_rate = *prate; - - return (rate >= parent_rate * 22) ? parent_rate * 22 : - parent_rate * 20; -} - -static int clk_pllv3_set_rate(struct clk *clk, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - u32 val, div; - - if (rate == parent_rate * 22) - div = 1; - else if (rate == parent_rate * 20) - div = 0; - else - return -EINVAL; - - val = readl(pll->base); - val &= ~pll->div_mask; - val |= div; - writel(val, pll->base); - - return 0; -} - -static const struct clk_ops clk_pllv3_ops = { - .enable = clk_pllv3_enable, - .disable = clk_pllv3_disable, - .recalc_rate = clk_pllv3_recalc_rate, - .round_rate = clk_pllv3_round_rate, - .set_rate = clk_pllv3_set_rate, -}; - -static unsigned long clk_pllv3_sys_recalc_rate(struct clk *clk, - unsigned long parent_rate) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - u32 div = readl(pll->base) & pll->div_mask; - - return parent_rate * div / 2; -} - -static long clk_pllv3_sys_round_rate(struct clk *clk, unsigned long rate, - unsigned long *prate) -{ - unsigned long parent_rate = *prate; - unsigned long min_rate = parent_rate * 54 / 2; - unsigned long max_rate = parent_rate * 108 / 2; - u32 div; - - if (rate > max_rate) - rate = max_rate; - else if (rate < min_rate) - rate = min_rate; - div = rate * 2 / parent_rate; - - return parent_rate * div / 2; -} - -static int clk_pllv3_sys_set_rate(struct clk *clk, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - unsigned long min_rate = parent_rate * 54 / 2; - unsigned long max_rate = parent_rate * 108 / 2; - u32 val, div; - - if (rate < min_rate || rate > max_rate) - return -EINVAL; - - div = rate * 2 / parent_rate; - val = readl(pll->base); - val &= ~pll->div_mask; - val |= div; - writel(val, pll->base); - - return 0; -} - -static const struct clk_ops clk_pllv3_sys_ops = { - .enable = clk_pllv3_enable, - .disable = clk_pllv3_disable, - .recalc_rate = clk_pllv3_sys_recalc_rate, - .round_rate = clk_pllv3_sys_round_rate, - .set_rate = clk_pllv3_sys_set_rate, -}; - -static unsigned long clk_pllv3_av_recalc_rate(struct clk *clk, - unsigned long parent_rate) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - u32 mfn = readl(pll->base + PLL_NUM_OFFSET); - u32 mfd = readl(pll->base + PLL_DENOM_OFFSET); - u32 div = readl(pll->base) & pll->div_mask; - - return (parent_rate * div) + ((parent_rate / mfd) * mfn); -} - -static long clk_pllv3_av_round_rate(struct clk *clk, unsigned long rate, - unsigned long *prate) -{ - unsigned long parent_rate = *prate; - unsigned long min_rate = parent_rate * 27; - unsigned long max_rate = parent_rate * 54; - u32 div; - u32 mfn, mfd = 1000000; - u64 temp64; - - if (rate > max_rate) - rate = max_rate; - else if (rate < min_rate) - rate = min_rate; - - div = rate / parent_rate; - temp64 = (u64) (rate - div * parent_rate); - temp64 *= mfd; - do_div(temp64, parent_rate); - mfn = temp64; - - return parent_rate * div + parent_rate / mfd * mfn; -} - -static int clk_pllv3_av_set_rate(struct clk *clk, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - unsigned long min_rate = parent_rate * 27; - unsigned long max_rate = parent_rate * 54; - u32 val, div; - u32 mfn, mfd = 1000000; - u64 temp64; - - if (rate < min_rate || rate > max_rate) - return -EINVAL; - - div = rate / parent_rate; - temp64 = (u64) (rate - div * parent_rate); - temp64 *= mfd; - do_div(temp64, parent_rate); - mfn = temp64; - - val = readl(pll->base); - val &= ~pll->div_mask; - val |= div; - writel(val, pll->base); - writel(mfn, pll->base + PLL_NUM_OFFSET); - writel(mfd, pll->base + PLL_DENOM_OFFSET); - - return 0; -} - -static const struct clk_ops clk_pllv3_av_ops = { - .enable = clk_pllv3_enable, - .disable = clk_pllv3_disable, - .recalc_rate = clk_pllv3_av_recalc_rate, - .round_rate = clk_pllv3_av_round_rate, - .set_rate = clk_pllv3_av_set_rate, -}; - -static unsigned long clk_pllv3_enet_recalc_rate(struct clk *clk, - unsigned long parent_rate) -{ - return 500000000; -} - -static const struct clk_ops clk_pllv3_enet_ops = { - .enable = clk_pllv3_enable, - .disable = clk_pllv3_disable, - .recalc_rate = clk_pllv3_enet_recalc_rate, -}; - -static const struct clk_ops clk_pllv3_mlb_ops = { - .enable = clk_pllv3_enable, - .disable = clk_pllv3_disable, -}; - -struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, - const char *parent, void __iomem *base, - u32 div_mask) -{ - struct clk_pllv3 *pll; - const struct clk_ops *ops; - int ret; - - pll = xzalloc(sizeof(*pll)); - - switch (type) { - case IMX_PLLV3_SYS: - ops = &clk_pllv3_sys_ops; - break; - case IMX_PLLV3_USB: - ops = &clk_pllv3_ops; - pll->powerup_set = true; - break; - case IMX_PLLV3_AV: - ops = &clk_pllv3_av_ops; - break; - case IMX_PLLV3_ENET: - ops = &clk_pllv3_enet_ops; - break; - case IMX_PLLV3_MLB: - ops = &clk_pllv3_mlb_ops; - break; - default: - ops = &clk_pllv3_ops; - } - pll->base = base; - pll->div_mask = div_mask; - pll->parent = parent; - pll->clk.ops = ops; - pll->clk.name = name; - pll->clk.parent_names = &pll->parent; - pll->clk.num_parents = 1; - - ret = clk_register(&pll->clk); - if (ret) { - free(pll); - return ERR_PTR(ret); - } - - return &pll->clk; -} diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h deleted file mode 100644 index c5913e1879..0000000000 --- a/arch/arm/mach-imx/clk.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef __IMX_CLK_H -#define __IMX_CLK_H - -struct clk *clk_gate2(const char *name, const char *parent, void __iomem *reg, - u8 shift); - -static inline struct clk *imx_clk_divider(const char *name, const char *parent, - void __iomem *reg, u8 shift, u8 width) -{ - return clk_divider(name, parent, reg, shift, width, CLK_SET_RATE_PARENT); -} - -static inline struct clk *imx_clk_divider_np(const char *name, const char *parent, - void __iomem *reg, u8 shift, u8 width) -{ - return clk_divider(name, parent, reg, shift, width, 0); -} - -static inline struct clk *imx_clk_divider_table(const char *name, - const char *parent, void __iomem *reg, u8 shift, u8 width, - const struct clk_div_table *table) -{ - return clk_divider_table(name, parent, reg, shift, width, table, - CLK_SET_RATE_PARENT); -} - -static inline struct clk *imx_clk_fixed_factor(const char *name, - const char *parent, unsigned int mult, unsigned int div) -{ - return clk_fixed_factor(name, parent, mult, div, CLK_SET_RATE_PARENT); -} - -static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, u8 num_parents) -{ - return clk_mux(name, reg, shift, width, parents, num_parents, 0); -} - -static inline struct clk *imx_clk_mux_p(const char *name, void __iomem *reg, - u8 shift, u8 width, const char **parents, u8 num_parents) -{ - return clk_mux(name, reg, shift, width, parents, num_parents, CLK_SET_RATE_PARENT); -} - -static inline struct clk *imx_clk_gate(const char *name, const char *parent, - void __iomem *reg, u8 shift) -{ - return clk_gate(name, parent, reg, shift, CLK_SET_RATE_PARENT, 0); -} - -static inline struct clk *imx_clk_gate2(const char *name, const char *parent, - void __iomem *reg, u8 shift) -{ - return clk_gate2(name, parent, reg, shift); -} - -struct clk *imx_clk_pllv1(const char *name, const char *parent, - void __iomem *base); - -struct clk *imx_clk_pllv2(const char *name, const char *parent, - void __iomem *base); - -enum imx_pllv3_type { - IMX_PLLV3_GENERIC, - IMX_PLLV3_SYS, - IMX_PLLV3_USB, - IMX_PLLV3_AV, - IMX_PLLV3_ENET, - IMX_PLLV3_MLB, -}; - -struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, - const char *parent, void __iomem *base, - u32 div_mask); - -struct clk *imx_clk_pfd(const char *name, const char *parent, - void __iomem *reg, u8 idx); - -static inline struct clk *imx_clk_busy_divider(const char *name, const char *parent, - void __iomem *reg, u8 shift, u8 width, - void __iomem *busy_reg, u8 busy_shift) -{ - /* - * For now we do not support rate setting, so just fall back to - * regular divider. - */ - return imx_clk_divider(name, parent, reg, shift, width); -} - -static inline struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, - u8 width, void __iomem *busy_reg, u8 busy_shift, - const char **parents, int num_parents) -{ - /* - * For now we do not support mux switching, so just fall back to - * regular mux. - */ - return imx_clk_mux(name, reg, shift, width, parents, num_parents); -} - -struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, - void __iomem *reg, u8 shift, u32 exclusive_mask); - -#endif /* __IMX_CLK_H */ diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 0fe8f1e200..a4e4ed0241 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_CLK_SOCFPGA) += socfpga.o obj-$(CONFIG_MACH_MIPS_ATH79) += clk-ar933x.o +obj-$(CONFIG_ARCH_IMX) += imx/ diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile new file mode 100644 index 0000000000..99dbe7d17c --- /dev/null +++ b/drivers/clk/imx/Makefile @@ -0,0 +1,20 @@ +obj-$(CONFIG_COMMON_CLK) += \ + clk-pllv1.o \ + clk-pllv2.o \ + clk-pllv3.o \ + clk-pfd.o \ + clk-gate2.o \ + clk-gate-exclusive.o + +obj-$(CONFIG_ARCH_IMX1) += clk-imx1.o +obj-$(CONFIG_ARCH_IMX25) += clk-imx25.o +obj-$(CONFIG_ARCH_IMX21) += clk-imx21.o +obj-$(CONFIG_ARCH_IMX27) += clk-imx27.o +obj-$(CONFIG_ARCH_IMX31) += clk-imx31.o +obj-$(CONFIG_ARCH_IMX35) += clk-imx35.o +obj-$(CONFIG_ARCH_IMX50) += clk-imx5.o +obj-$(CONFIG_ARCH_IMX51) += clk-imx5.o +obj-$(CONFIG_ARCH_IMX53) += clk-imx5.o +obj-$(CONFIG_ARCH_IMX6) += clk-imx6.o +obj-$(CONFIG_ARCH_IMX6SX) += clk-imx6sx.o +obj-$(CONFIG_ARCH_IMX6UL) += clk-imx6ul.o diff --git a/drivers/clk/imx/clk-gate-exclusive.c b/drivers/clk/imx/clk-gate-exclusive.c new file mode 100644 index 0000000000..db88db0237 --- /dev/null +++ b/drivers/clk/imx/clk-gate-exclusive.c @@ -0,0 +1,103 @@ +/* + * Copyright 2014 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include "clk.h" + +/** + * struct clk_gate_exclusive - i.MX specific gate clock which is mutually + * exclusive with other gate clocks + * + * @gate: the parent class + * @exclusive_mask: mask of gate bits which are mutually exclusive to this + * gate clock + * + * The imx exclusive gate clock is a subclass of basic clk_gate + * with an addtional mask to indicate which other gate bits in the same + * register is mutually exclusive to this gate clock. + */ +struct clk_gate_exclusive { + struct clk clk; + void __iomem *reg; + int shift; + const char *parent; + u32 exclusive_mask; +}; + +static int clk_gate_exclusive_enable(struct clk *clk) +{ + struct clk_gate_exclusive *exgate = container_of(clk, + struct clk_gate_exclusive, clk); + u32 val = readl(exgate->reg); + + if (val & exgate->exclusive_mask) + return -EBUSY; + + val |= 1 << exgate->shift; + + writel(val, exgate->reg); + + return 0; +} + +static void clk_gate_exclusive_disable(struct clk *clk) +{ + struct clk_gate_exclusive *exgate = container_of(clk, + struct clk_gate_exclusive, clk); + u32 val = readl(exgate->reg); + + val &= ~(1 << exgate->shift); + + writel(val, exgate->reg); +} + +static int clk_gate_exclusive_is_enabled(struct clk *clk) +{ + struct clk_gate_exclusive *exgate = container_of(clk, + struct clk_gate_exclusive, clk); + + return readl(exgate->reg) & (1 << exgate->shift); +} + +static const struct clk_ops clk_gate_exclusive_ops = { + .enable = clk_gate_exclusive_enable, + .disable = clk_gate_exclusive_disable, + .is_enabled = clk_gate_exclusive_is_enabled, +}; + +struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, + void __iomem *reg, u8 shift, u32 exclusive_mask) +{ + struct clk_gate_exclusive *exgate; + int ret; + + exgate = xzalloc(sizeof(*exgate)); + exgate->parent = parent; + exgate->clk.name = name; + exgate->clk.ops = &clk_gate_exclusive_ops; + exgate->clk.flags = CLK_SET_RATE_PARENT; + exgate->clk.parent_names = &exgate->parent; + exgate->clk.num_parents = 1; + + exgate->reg = reg; + exgate->shift = shift; + exgate->exclusive_mask = exclusive_mask; + + ret = clk_register(&exgate->clk); + if (ret) { + free(exgate); + return ERR_PTR(ret); + } + + return &exgate->clk; +} diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c new file mode 100644 index 0000000000..faed6313fb --- /dev/null +++ b/drivers/clk/imx/clk-gate2.c @@ -0,0 +1,145 @@ +/* + * clk-gate2.c - barebox 2-bit clock support. Based on Linux clk support + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include + +#include "clk.h" + + +struct clk_gate2 { + struct clk clk; + void __iomem *reg; + int shift; + const char *parent; +#define CLK_GATE_INVERTED (1 << 0) + unsigned flags; +}; + +#define to_clk_gate2(_clk) container_of(_clk, struct clk_gate2, clk) + +static int clk_gate2_enable(struct clk *clk) +{ + struct clk_gate2 *g = to_clk_gate2(clk); + u32 val; + + val = readl(g->reg); + + if (g->flags & CLK_GATE_INVERTED) + val &= ~(3 << g->shift); + else + val |= 3 << g->shift; + + writel(val, g->reg); + + return 0; +} + +static void clk_gate2_disable(struct clk *clk) +{ + struct clk_gate2 *g = to_clk_gate2(clk); + u32 val; + + val = readl(g->reg); + + if (g->flags & CLK_GATE_INVERTED) + val |= 3 << g->shift; + else + val &= ~(3 << g->shift); + + writel(val, g->reg); +} + +static int clk_gate2_is_enabled(struct clk *clk) +{ + struct clk_gate2 *g = to_clk_gate2(clk); + u32 val; + + val = readl(g->reg); + + if (val & (1 << g->shift)) + return g->flags & CLK_GATE_INVERTED ? 0 : 1; + else + return g->flags & CLK_GATE_INVERTED ? 1 : 0; +} + +static struct clk_ops clk_gate2_ops = { + .set_rate = clk_parent_set_rate, + .round_rate = clk_parent_round_rate, + .enable = clk_gate2_enable, + .disable = clk_gate2_disable, + .is_enabled = clk_gate2_is_enabled, +}; + +struct clk *clk_gate2_alloc(const char *name, const char *parent, + void __iomem *reg, u8 shift) +{ + struct clk_gate2 *g = xzalloc(sizeof(*g)); + + g->parent = parent; + g->reg = reg; + g->shift = shift; + g->clk.ops = &clk_gate2_ops; + g->clk.name = name; + g->clk.parent_names = &g->parent; + g->clk.num_parents = 1; + g->clk.flags = CLK_SET_RATE_PARENT; + + return &g->clk; +} + +void clk_gate2_free(struct clk *clk) +{ + struct clk_gate2 *g = to_clk_gate2(clk); + + free(g); +} + +struct clk *clk_gate2(const char *name, const char *parent, void __iomem *reg, + u8 shift) +{ + struct clk *g; + int ret; + + g = clk_gate2_alloc(name , parent, reg, shift); + + ret = clk_register(g); + if (ret) { + free(to_clk_gate2(g)); + return ERR_PTR(ret); + } + + return g; +} + +struct clk *clk_gate2_inverted(const char *name, const char *parent, + void __iomem *reg, u8 shift) +{ + struct clk *clk; + struct clk_gate2 *g; + + clk = clk_gate2(name, parent, reg, shift); + if (IS_ERR(clk)) + return clk; + + g = to_clk_gate2(clk); + + g->flags = CLK_GATE_INVERTED; + + return clk; +} diff --git a/drivers/clk/imx/clk-imx1.c b/drivers/clk/imx/clk-imx1.c new file mode 100644 index 0000000000..5f600a9da3 --- /dev/null +++ b/drivers/clk/imx/clk-imx1.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2008 Sascha Hauer , Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define CCM_CSCR 0x0 +#define CCM_MPCTL0 0x4 +#define CCM_SPCTL0 0xc +#define CCM_PCDR 0x20 + +enum imx1_clks { + dummy, clk32, clk16m, clk32_premult, prem, mpll, spll, mcu, + fclk, hclk, clk48m, per1, per2, per3, clko, dma_gate, csi_gate, + mma_gate, usbd_gate, clk_max +}; + +static struct clk *clks[clk_max]; + +static const char *prem_sel_clks[] = { + "clk32_premult", + "clk16m", +}; + +static const char *clko_sel_clks[] = { + "per1", + "hclk", + "clk48m", + "clk16m", + "prem", + "fclk", +}; + +int __init mx1_clocks_init(void __iomem *regs, unsigned long fref) +{ + clks[dummy] = clk_fixed("dummy", 0); + clks[clk32] = clk_fixed("clk32", fref); + clks[clk16m] = clk_fixed("clk16m", 16000000); + clks[clk32_premult] = imx_clk_fixed_factor("clk32_premult", "clk32", 512, 1); + clks[prem] = imx_clk_mux("prem", regs + CCM_CSCR, 16, 1, prem_sel_clks, + ARRAY_SIZE(prem_sel_clks)); + clks[mpll] = imx_clk_pllv1("mpll", "clk32_premult", regs + CCM_MPCTL0); + clks[spll] = imx_clk_pllv1("spll", "prem", regs + CCM_SPCTL0); + clks[mcu] = imx_clk_divider("mcu", "clk32_premult", regs + CCM_CSCR, 15, 1); + clks[fclk] = imx_clk_divider("fclk", "mpll", regs + CCM_CSCR, 15, 1); + clks[hclk] = imx_clk_divider("hclk", "spll", regs + CCM_CSCR, 10, 4); + clks[clk48m] = imx_clk_divider("clk48m", "spll", regs + CCM_CSCR, 26, 3); + clks[per1] = imx_clk_divider("per1", "spll", regs + CCM_PCDR, 0, 4); + clks[per2] = imx_clk_divider("per2", "spll", regs + CCM_PCDR, 4, 4); + clks[per3] = imx_clk_divider("per3", "spll", regs + CCM_PCDR, 16, 7); + clks[clko] = imx_clk_mux("clko", regs + CCM_CSCR, 29, 3, clko_sel_clks, + ARRAY_SIZE(clko_sel_clks)); + + clkdev_add_physbase(clks[per1], MX1_TIM1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1], MX1_TIM2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per2], MX1_LCDC_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1], MX1_UART1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1], MX1_UART2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per2], MX1_CSPI1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per2], MX1_CSPI2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[hclk], MX1_I2C_BASE_ADDR, NULL); + + return 0; +} + +static int imx1_ccm_probe(struct device_d *dev) +{ + struct resource *iores; + void __iomem *regs; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + regs = IOMEM(iores->start); + + mx1_clocks_init(regs, 32000); + + return 0; +} + +static __maybe_unused struct of_device_id imx1_ccm_dt_ids[] = { + { + .compatible = "fsl,imx1-ccm", + }, { + /* sentinel */ + } +}; + +static struct driver_d imx1_ccm_driver = { + .probe = imx1_ccm_probe, + .name = "imx1-ccm", + .of_compatible = DRV_OF_COMPAT(imx1_ccm_dt_ids), +}; + +static int imx1_ccm_init(void) +{ + return platform_driver_register(&imx1_ccm_driver); +} +core_initcall(imx1_ccm_init); diff --git a/drivers/clk/imx/clk-imx21.c b/drivers/clk/imx/clk-imx21.c new file mode 100644 index 0000000000..546461b8ee --- /dev/null +++ b/drivers/clk/imx/clk-imx21.c @@ -0,0 +1,196 @@ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Juergen Beisert, kernel@pengutronix.de + * Copyright 2008 Martin Fuzzey, mfuzzey@gmail.com + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +/* Register offsets */ +#define CCM_CSCR 0x0 +#define CCM_MPCTL0 0x4 +#define CCM_MPCTL1 0x8 +#define CCM_SPCTL0 0xc +#define CCM_SPCTL1 0x10 +#define CCM_OSC26MCTL 0x14 +#define CCM_PCDR0 0x18 +#define CCM_PCDR1 0x1c +#define CCM_PCCR0 0x20 +#define CCM_PCCR1 0x24 +#define CCM_CCSR 0x28 +#define CCM_PMCTL 0x2c +#define CCM_PMCOUNT 0x30 +#define CCM_WKGDCTL 0x34 + +#define PCCR0_UART1_EN (1 << 0) +#define PCCR0_UART2_EN (1 << 1) +#define PCCR0_UART3_EN (1 << 2) +#define PCCR0_UART4_EN (1 << 3) +#define PCCR0_CSPI1_EN (1 << 4) +#define PCCR0_CSPI2_EN (1 << 5) +#define PCCR0_SSI1_EN (1 << 6) +#define PCCR0_SSI2_EN (1 << 7) +#define PCCR0_FIRI_EN (1 << 8) +#define PCCR0_SDHC1_EN (1 << 9) +#define PCCR0_SDHC2_EN (1 << 10) +#define PCCR0_GPIO_EN (1 << 11) +#define PCCR0_I2C_EN (1 << 12) +#define PCCR0_DMA_EN (1 << 13) +#define PCCR0_USBOTG_EN (1 << 14) +#define PCCR0_EMMA_EN (1 << 15) +#define PCCR0_SSI2_BAUD_EN (1 << 16) +#define PCCR0_SSI1_BAUD_EN (1 << 17) +#define PCCR0_PERCLK3_EN (1 << 18) +#define PCCR0_NFC_EN (1 << 19) +#define PCCR0_FRI_BAUD_EN (1 << 20) +#define PCCR0_SLDC_EN (1 << 21) +#define PCCR0_PERCLK4_EN (1 << 22) +#define PCCR0_HCLK_BMI_EN (1 << 23) +#define PCCR0_HCLK_USBOTG_EN (1 << 24) +#define PCCR0_HCLK_SLCDC_EN (1 << 25) +#define PCCR0_HCLK_LCDC_EN (1 << 26) +#define PCCR0_HCLK_EMMA_EN (1 << 27) +#define PCCR0_HCLK_BROM_EN (1 << 28) +#define PCCR0_HCLK_DMA_EN (1 << 30) +#define PCCR0_HCLK_CSI_EN (1 << 31) + +#define PCCR1_CSPI3_EN (1 << 23) +#define PCCR1_WDT_EN (1 << 24) +#define PCCR1_GPT1_EN (1 << 25) +#define PCCR1_GPT2_EN (1 << 26) +#define PCCR1_GPT3_EN (1 << 27) +#define PCCR1_PWM_EN (1 << 28) +#define PCCR1_RTC_EN (1 << 29) +#define PCCR1_KPP_EN (1 << 30) +#define PCCR1_OWIRE_EN (1 << 31) + +enum imx21_clks { + ckil, ckih, fpm, mpll_sel, spll_sel, mpll, spll, fclk, hclk, ipg, per1, + per2, per3, per4, usb_div, nfc_div, lcdc_per_gate, lcdc_ahb_gate, + lcdc_ipg_gate, clk_max +}; + +static struct clk *clks[clk_max]; + +static const char *mpll_sel_clks[] = { + "fpm", + "ckih", +}; + +static const char *spll_sel_clks[] = { + "fpm", + "ckih", +}; + +static int imx21_ccm_probe(struct device_d *dev) +{ + struct resource *iores; + void __iomem *base; + unsigned long lref = 32768; + unsigned long href = 26000000; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + base = IOMEM(iores->start); + + writel(PCCR0_UART1_EN | PCCR0_UART2_EN | PCCR0_UART3_EN | PCCR0_UART4_EN | + PCCR0_CSPI1_EN | PCCR0_CSPI2_EN | PCCR0_SDHC1_EN | + PCCR0_SDHC2_EN | PCCR0_GPIO_EN | PCCR0_I2C_EN | PCCR0_DMA_EN | + PCCR0_USBOTG_EN | PCCR0_NFC_EN | PCCR0_PERCLK4_EN | + PCCR0_HCLK_USBOTG_EN | PCCR0_HCLK_DMA_EN, + base + CCM_PCCR0); + + writel(PCCR1_CSPI3_EN | PCCR1_WDT_EN | PCCR1_GPT1_EN | PCCR1_GPT2_EN | + PCCR1_GPT3_EN | PCCR1_PWM_EN | PCCR1_RTC_EN | PCCR1_KPP_EN | + PCCR1_OWIRE_EN, + base + CCM_PCCR1); + + clks[ckil] = clk_fixed("ckil", lref); + clks[ckih] = clk_fixed("ckih", href); + clks[fpm] = imx_clk_fixed_factor("fpm", "ckil", 512, 1); + clks[mpll_sel] = imx_clk_mux("mpll_sel", base + CCM_CSCR, 16, 1, mpll_sel_clks, + ARRAY_SIZE(mpll_sel_clks)); + clks[spll_sel] = imx_clk_mux("spll_sel", base + CCM_CSCR, 17, 1, spll_sel_clks, + ARRAY_SIZE(spll_sel_clks)); + clks[mpll] = imx_clk_pllv1("mpll", "mpll_sel", base + CCM_MPCTL0); + clks[spll] = imx_clk_pllv1("spll", "spll_sel", base + CCM_SPCTL0); + clks[fclk] = imx_clk_divider("fclk", "mpll", base + CCM_CSCR, 29, 3); + clks[hclk] = imx_clk_divider("hclk", "fclk", base + CCM_CSCR, 10, 4); + clks[ipg] = imx_clk_divider("ipg", "hclk", base + CCM_CSCR, 9, 1); + clks[per1] = imx_clk_divider("per1", "mpll", base + CCM_PCDR1, 0, 6); + clks[per2] = imx_clk_divider("per2", "mpll", base + CCM_PCDR1, 8, 6); + clks[per3] = imx_clk_divider("per3", "mpll", base + CCM_PCDR1, 16, 6); + clks[per4] = imx_clk_divider("per4", "mpll", base + CCM_PCDR1, 24, 6); + clks[usb_div] = imx_clk_divider("usb_div", "spll", base + CCM_CSCR, 26, 3); + clks[nfc_div] = imx_clk_divider("nfc_div", "ipg", base + CCM_PCDR0, 12, 4); + clks[lcdc_per_gate] = imx_clk_gate("lcdc_per_gate", "per3", base + CCM_PCCR0, 18); + clks[lcdc_ahb_gate] = imx_clk_gate("lcdc_ahb_gate", "ahb", base + CCM_PCCR0, 26); + /* + * i.MX21 doesn't have an IPG clock for the LCD. To avoid even more conditionals + * in the framebuffer code, provide a dummy clock. + */ + clks[lcdc_ipg_gate] = clk_fixed("dummy", 0); + + clkdev_add_physbase(clks[per1], MX21_GPT1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1], MX21_GPT2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1], MX21_GPT3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1], MX21_UART1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1], MX21_UART2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1], MX21_UART3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1], MX21_UART4_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per2], MX21_CSPI1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per2], MX21_CSPI2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per2], MX21_CSPI3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX21_I2C_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX21_SDHC1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX21_SDHC2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[lcdc_per_gate], MX21_LCDC_BASE_ADDR, "per"); + clkdev_add_physbase(clks[lcdc_ahb_gate], MX21_LCDC_BASE_ADDR, "ahb"); + clkdev_add_physbase(clks[lcdc_ipg_gate], MX21_LCDC_BASE_ADDR, "ipg"); + + return 0; +} + +static __maybe_unused struct of_device_id imx21_ccm_dt_ids[] = { + { + .compatible = "fsl,imx21-ccm", + }, { + /* sentinel */ + } +}; + +static struct driver_d imx21_ccm_driver = { + .probe = imx21_ccm_probe, + .name = "imx21-ccm", + .of_compatible = DRV_OF_COMPAT(imx21_ccm_dt_ids), +}; + +static int imx21_ccm_init(void) +{ + return platform_driver_register(&imx21_ccm_driver); +} +core_initcall(imx21_ccm_init); diff --git a/drivers/clk/imx/clk-imx25.c b/drivers/clk/imx/clk-imx25.c new file mode 100644 index 0000000000..864d06e195 --- /dev/null +++ b/drivers/clk/imx/clk-imx25.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2009 by Sascha Hauer, Pengutronix + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define CCM_MPCTL 0x00 +#define CCM_UPCTL 0x04 +#define CCM_CCTL 0x08 +#define CCM_CGCR0 0x0C +#define CCM_CGCR1 0x10 +#define CCM_CGCR2 0x14 +#define CCM_PCDR0 0x18 +#define CCM_PCDR1 0x1C +#define CCM_PCDR2 0x20 +#define CCM_PCDR3 0x24 +#define CCM_RCSR 0x28 +#define CCM_CRDR 0x2C +#define CCM_DCVR0 0x30 +#define CCM_DCVR1 0x34 +#define CCM_DCVR2 0x38 +#define CCM_DCVR3 0x3c +#define CCM_LTR0 0x40 +#define CCM_LTR1 0x44 +#define CCM_LTR2 0x48 +#define CCM_LTR3 0x4c +#define CCM_MCR 0x64 + +enum mx25_clks { + dummy, osc, mpll, upll, mpll_cpu_3_4, cpu_sel, cpu, ahb, usb_div, ipg, + per0_sel, per1_sel, per2_sel, per3_sel, per4_sel, per5_sel, per6_sel, + per7_sel, per8_sel, per9_sel, per10_sel, per11_sel, per12_sel, + per13_sel, per14_sel, per15_sel, per0, per1, per2, per3, per4, per5, + per6, per7, per8, per9, per10, per11, per12, per13, per14, per15, + csi_ipg_per, epit_ipg_per, esai_ipg_per, esdhc1_ipg_per, esdhc2_ipg_per, + gpt_ipg_per, i2c_ipg_per, lcdc_ipg_per, nfc_ipg_per, owire_ipg_per, + pwm_ipg_per, sim1_ipg_per, sim2_ipg_per, ssi1_ipg_per, ssi2_ipg_per, + uart_ipg_per, ata_ahb, reserved1, csi_ahb, emi_ahb, esai_ahb, esdhc1_ahb, + esdhc2_ahb, fec_ahb, lcdc_ahb, rtic_ahb, sdma_ahb, slcdc_ahb, usbotg_ahb, + reserved2, reserved3, reserved4, reserved5, can1_ipg, can2_ipg, csi_ipg, + cspi1_ipg, cspi2_ipg, cspi3_ipg, dryice_ipg, ect_ipg, epit1_ipg, epit2_ipg, + reserved6, esdhc1_ipg, esdhc2_ipg, fec_ipg, reserved7, reserved8, reserved9, + gpt1_ipg, gpt2_ipg, gpt3_ipg, gpt4_ipg, reserved10, reserved11, reserved12, + iim_ipg, reserved13, reserved14, kpp_ipg, lcdc_ipg, reserved15, pwm1_ipg, + pwm2_ipg, pwm3_ipg, pwm4_ipg, rngb_ipg, reserved16, scc_ipg, sdma_ipg, + sim1_ipg, sim2_ipg, slcdc_ipg, spba_ipg, ssi1_ipg, ssi2_ipg, tsc_ipg, + uart1_ipg, uart2_ipg, uart3_ipg, uart4_ipg, uart5_ipg, reserved17, + wdt_ipg, clk_max +}; + +static struct clk *clks[clk_max]; + +static const char *cpu_sel_clks[] = { + "mpll", + "mpll_cpu_3_4", +}; + +static const char *per_sel_clks[] = { + "ahb", + "upll", +}; + +static int imx25_ccm_probe(struct device_d *dev) +{ + struct resource *iores; + void __iomem *base; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + base = IOMEM(iores->start); + + writel((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 8) | (1 << 9) | + (1 << 10) | (1 << 15) | (1 << 19) | (1 << 21) | (1 << 22) | + (1 << 23) | (1 << 24) | (1 << 28), + base + CCM_CGCR0); + + writel((1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 13) | (1 << 14) | + (1 << 15) | (1 << 19) | (1 << 20) | (1 << 21) | (1 << 22) | + (1 << 26) | (1 << 31), + base + CCM_CGCR1); + + writel((1 << 0) | (1 << 1) | (1 << 2) | (1 << 10) | (1 << 13) | (1 << 14) | + (1 << 15) | (1 << 16) | (1 << 17) | (1 << 18), + base + CCM_CGCR2); + + clks[dummy] = clk_fixed("dummy", 0); + clks[osc] = clk_fixed("osc", 24000000); + clks[mpll] = imx_clk_pllv1("mpll", "osc", base + CCM_MPCTL); + clks[upll] = imx_clk_pllv1("upll", "osc", base + CCM_UPCTL); + clks[mpll_cpu_3_4] = imx_clk_fixed_factor("mpll_cpu_3_4", "mpll", 3, 4); + clks[cpu_sel] = imx_clk_mux("cpu_sel", base + CCM_CCTL, 14, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks)); + clks[cpu] = imx_clk_divider("cpu", "cpu_sel", base + CCM_CCTL, 30, 2); + clks[ahb] = imx_clk_divider("ahb", "cpu", base + CCM_CCTL, 28, 2); + clks[usb_div] = imx_clk_divider("usb_div", "upll", base + CCM_CCTL, 16, 6); + clks[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2); + clks[per0_sel] = imx_clk_mux("per0_sel", base + CCM_MCR, 0, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per1_sel] = imx_clk_mux("per1_sel", base + CCM_MCR, 1, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per2_sel] = imx_clk_mux("per2_sel", base + CCM_MCR, 2, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per3_sel] = imx_clk_mux("per3_sel", base + CCM_MCR, 3, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per4_sel] = imx_clk_mux("per4_sel", base + CCM_MCR, 4, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per5_sel] = imx_clk_mux("per5_sel", base + CCM_MCR, 5, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per6_sel] = imx_clk_mux("per6_sel", base + CCM_MCR, 6, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per7_sel] = imx_clk_mux("per7_sel", base + CCM_MCR, 7, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per8_sel] = imx_clk_mux("per8_sel", base + CCM_MCR, 8, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per9_sel] = imx_clk_mux("per9_sel", base + CCM_MCR, 9, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per10_sel] = imx_clk_mux("per10_sel", base + CCM_MCR, 10, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per11_sel] = imx_clk_mux("per11_sel", base + CCM_MCR, 11, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per12_sel] = imx_clk_mux("per12_sel", base + CCM_MCR, 12, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per13_sel] = imx_clk_mux("per13_sel", base + CCM_MCR, 13, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per14_sel] = imx_clk_mux("per14_sel", base + CCM_MCR, 14, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per15_sel] = imx_clk_mux("per15_sel", base + CCM_MCR, 15, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clks[per0] = imx_clk_divider("per0", "per0_sel", base + CCM_PCDR0, 0, 6); + clks[per1] = imx_clk_divider("per1", "per1_sel", base + CCM_PCDR0, 8, 6); + clks[per2] = imx_clk_divider("per2", "per2_sel", base + CCM_PCDR0, 16, 6); + clks[per3] = imx_clk_divider("per3", "per3_sel", base + CCM_PCDR0, 24, 6); + clks[per4] = imx_clk_divider("per4", "per4_sel", base + CCM_PCDR1, 0, 6); + clks[per5] = imx_clk_divider("per5", "per5_sel", base + CCM_PCDR1, 8, 6); + clks[per6] = imx_clk_divider("per6", "per6_sel", base + CCM_PCDR1, 16, 6); + clks[per7] = imx_clk_divider("per7", "per7_sel", base + CCM_PCDR1, 24, 6); + clks[per8] = imx_clk_divider("per8", "per8_sel", base + CCM_PCDR2, 0, 6); + clks[per9] = imx_clk_divider("per9", "per9_sel", base + CCM_PCDR2, 8, 6); + clks[per10] = imx_clk_divider("per10", "per10_sel", base + CCM_PCDR2, 16, 6); + clks[per11] = imx_clk_divider("per11", "per11_sel", base + CCM_PCDR2, 24, 6); + clks[per12] = imx_clk_divider("per12", "per12_sel", base + CCM_PCDR3, 0, 6); + clks[per13] = imx_clk_divider("per13", "per13_sel", base + CCM_PCDR3, 8, 6); + clks[per14] = imx_clk_divider("per14", "per14_sel", base + CCM_PCDR3, 16, 6); + clks[per15] = imx_clk_divider("per15", "per15_sel", base + CCM_PCDR3, 24, 6); + clks[lcdc_ahb] = imx_clk_gate("lcdc_ahb", "ahb", base + CCM_CGCR0, 24); + clks[lcdc_ipg] = imx_clk_gate("lcdc_ipg", "ipg", base + CCM_CGCR1, 29); + clks[lcdc_ipg_per] = imx_clk_gate("lcdc_ipg_per", "per7", base + CCM_CGCR0, 7); + + clkdev_add_physbase(clks[per15], MX25_UART1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per15], MX25_UART2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per15], MX25_UART3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per15], MX25_UART4_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per15], MX25_UART5_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per5], MX25_GPT1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per5], MX25_GPT2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per5], MX25_GPT3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per5], MX25_GPT4_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX25_FEC_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX25_I2C1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX25_I2C2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX25_I2C3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX25_CSPI1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX25_CSPI2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX25_CSPI3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per3], MX25_ESDHC1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per4], MX25_ESDHC2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per8], MX25_NFC_BASE_ADDR, NULL); + clkdev_add_physbase(clks[lcdc_ipg_per], MX25_LCDC_BASE_ADDR, "per"); + clkdev_add_physbase(clks[lcdc_ipg], MX25_LCDC_BASE_ADDR, "ipg"); + clkdev_add_physbase(clks[lcdc_ahb], MX25_LCDC_BASE_ADDR, "ahb"); + + return 0; +} + +static __maybe_unused struct of_device_id imx25_ccm_dt_ids[] = { + { + .compatible = "fsl,imx25-ccm", + }, { + /* sentinel */ + } +}; + +static struct driver_d imx25_ccm_driver = { + .probe = imx25_ccm_probe, + .name = "imx25-ccm", + .of_compatible = DRV_OF_COMPAT(imx25_ccm_dt_ids), +}; + +static int imx25_ccm_init(void) +{ + return platform_driver_register(&imx25_ccm_driver); +} +core_initcall(imx25_ccm_init); diff --git a/drivers/clk/imx/clk-imx27.c b/drivers/clk/imx/clk-imx27.c new file mode 100644 index 0000000000..4b63244211 --- /dev/null +++ b/drivers/clk/imx/clk-imx27.c @@ -0,0 +1,270 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +/* Register offsets */ +#define CCM_CSCR 0x0 +#define CCM_MPCTL0 0x4 +#define CCM_MPCTL1 0x8 +#define CCM_SPCTL0 0xc +#define CCM_SPCTL1 0x10 +#define CCM_OSC26MCTL 0x14 +#define CCM_PCDR0 0x18 +#define CCM_PCDR1 0x1c +#define CCM_PCCR0 0x20 +#define CCM_PCCR1 0x24 +#define CCM_CCSR 0x28 +#define CCM_PMCTL 0x2c +#define CCM_PMCOUNT 0x30 +#define CCM_WKGDCTL 0x34 + +#define PCCR0_SSI2_EN (1 << 0) +#define PCCR0_SSI1_EN (1 << 1) +#define PCCR0_SLCDC_EN (1 << 2) +#define PCCR0_SDHC3_EN (1 << 3) +#define PCCR0_SDHC2_EN (1 << 4) +#define PCCR0_SDHC1_EN (1 << 5) +#define PCCR0_SDC_EN (1 << 6) +#define PCCR0_SAHARA_EN (1 << 7) +#define PCCR0_RTIC_EN (1 << 8) +#define PCCR0_RTC_EN (1 << 9) +#define PCCR0_PWM_EN (1 << 11) +#define PCCR0_OWIRE_EN (1 << 12) +#define PCCR0_MSHC_EN (1 << 13) +#define PCCR0_LCDC_EN (1 << 14) +#define PCCR0_KPP_EN (1 << 15) +#define PCCR0_IIM_EN (1 << 16) +#define PCCR0_I2C2_EN (1 << 17) +#define PCCR0_I2C1_EN (1 << 18) +#define PCCR0_GPT6_EN (1 << 19) +#define PCCR0_GPT5_EN (1 << 20) +#define PCCR0_GPT4_EN (1 << 21) +#define PCCR0_GPT3_EN (1 << 22) +#define PCCR0_GPT2_EN (1 << 23) +#define PCCR0_GPT1_EN (1 << 24) +#define PCCR0_GPIO_EN (1 << 25) +#define PCCR0_FEC_EN (1 << 26) +#define PCCR0_EMMA_EN (1 << 27) +#define PCCR0_DMA_EN (1 << 28) +#define PCCR0_CSPI3_EN (1 << 29) +#define PCCR0_CSPI2_EN (1 << 30) +#define PCCR0_CSPI1_EN (1 << 31) + +#define PCCR1_MSHC_BAUDEN (1 << 2) +#define PCCR1_NFC_BAUDEN (1 << 3) +#define PCCR1_SSI2_BAUDEN (1 << 4) +#define PCCR1_SSI1_BAUDEN (1 << 5) +#define PCCR1_H264_BAUDEN (1 << 6) +#define PCCR1_PERCLK4_EN (1 << 7) +#define PCCR1_PERCLK3_EN (1 << 8) +#define PCCR1_PERCLK2_EN (1 << 9) +#define PCCR1_PERCLK1_EN (1 << 10) +#define PCCR1_HCLK_USB (1 << 11) +#define PCCR1_HCLK_SLCDC (1 << 12) +#define PCCR1_HCLK_SAHARA (1 << 13) +#define PCCR1_HCLK_RTIC (1 << 14) +#define PCCR1_HCLK_LCDC (1 << 15) +#define PCCR1_HCLK_H264 (1 << 16) +#define PCCR1_HCLK_FEC (1 << 17) +#define PCCR1_HCLK_EMMA (1 << 18) +#define PCCR1_HCLK_EMI (1 << 19) +#define PCCR1_HCLK_DMA (1 << 20) +#define PCCR1_HCLK_CSI (1 << 21) +#define PCCR1_HCLK_BROM (1 << 22) +#define PCCR1_HCLK_ATA (1 << 23) +#define PCCR1_WDT_EN (1 << 24) +#define PCCR1_USB_EN (1 << 25) +#define PCCR1_UART6_EN (1 << 26) +#define PCCR1_UART5_EN (1 << 27) +#define PCCR1_UART4_EN (1 << 28) +#define PCCR1_UART3_EN (1 << 29) +#define PCCR1_UART2_EN (1 << 30) +#define PCCR1_UART1_EN (1 << 31) + +enum mx27_clks { + dummy, ckih, ckil, mpll, spll, mpll_main2, ahb, ipg, nfc_div, per1_div, + per2_div, per3_div, per4_div, vpu_sel, vpu_div, usb_div, cpu_sel, + clko_sel, cpu_div, clko_div, ssi1_sel, ssi2_sel, ssi1_div, ssi2_div, + clko_en, ssi2_ipg_gate, ssi1_ipg_gate, slcdc_ipg_gate, sdhc3_ipg_gate, + sdhc2_ipg_gate, sdhc1_ipg_gate, scc_ipg_gate, sahara_ipg_gate, + rtc_ipg_gate, pwm_ipg_gate, owire_ipg_gate, lcdc_ipg_gate, + kpp_ipg_gate, iim_ipg_gate, i2c2_ipg_gate, i2c1_ipg_gate, + gpt6_ipg_gate, gpt5_ipg_gate, gpt4_ipg_gate, gpt3_ipg_gate, + gpt2_ipg_gate, gpt1_ipg_gate, gpio_ipg_gate, fec_ipg_gate, + emma_ipg_gate, dma_ipg_gate, cspi3_ipg_gate, cspi2_ipg_gate, + cspi1_ipg_gate, nfc_baud_gate, ssi2_baud_gate, ssi1_baud_gate, + vpu_baud_gate, per4_gate, per3_gate, per2_gate, per1_gate, + usb_ahb_gate, slcdc_ahb_gate, sahara_ahb_gate, lcdc_ahb_gate, + vpu_ahb_gate, fec_ahb_gate, emma_ahb_gate, emi_ahb_gate, dma_ahb_gate, + csi_ahb_gate, brom_ahb_gate, ata_ahb_gate, wdog_ipg_gate, usb_ipg_gate, + uart6_ipg_gate, uart5_ipg_gate, uart4_ipg_gate, uart3_ipg_gate, + uart2_ipg_gate, uart1_ipg_gate, ckih_div1p5, fpm, mpll_osc_sel, + mpll_sel, spll_gate, clk_max +}; + +static struct clk *clks[clk_max]; + +static const char *cpu_sel_clks[] = { + "mpll_main2", + "mpll", +}; + +static const char *mpll_sel_clks[] = { + "fpm", + "mpll_osc_sel", +}; + +static const char *mpll_osc_sel_clks[] = { + "ckih", + "ckih_div1p5", +}; + +static const char *clko_sel_clks[] = { + "ckil", + NULL, + "ckih", + "ckih", + "ckih", + "mpll", + "spll", + "cpu_div", + "ahb", + "ipg", + "per1_div", + "per2_div", + "per3_div", + "per4_div", + NULL, + NULL, + "nfc_div", + NULL, + NULL, + NULL, + "ckil", + "usb_div", + NULL, +}; + +static int imx27_ccm_probe(struct device_d *dev) +{ + struct resource *iores; + void __iomem *base; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + base = IOMEM(iores->start); + + writel(PCCR0_SDHC3_EN | PCCR0_SDHC2_EN | PCCR0_SDHC1_EN | + PCCR0_PWM_EN | PCCR0_KPP_EN | PCCR0_IIM_EN | + PCCR0_I2C2_EN | PCCR0_I2C1_EN | PCCR0_GPT6_EN | PCCR0_GPT5_EN | + PCCR0_GPT4_EN | PCCR0_GPT3_EN | PCCR0_GPT2_EN | PCCR0_GPT1_EN | + PCCR0_GPIO_EN | PCCR0_FEC_EN | PCCR0_CSPI3_EN | PCCR0_CSPI2_EN | + PCCR0_CSPI1_EN, + base + CCM_PCCR0); + + writel(PCCR1_NFC_BAUDEN | PCCR1_PERCLK4_EN | PCCR1_PERCLK2_EN | PCCR1_PERCLK1_EN | + PCCR1_HCLK_USB | PCCR1_HCLK_FEC | PCCR1_HCLK_EMI | PCCR1_WDT_EN | + PCCR1_USB_EN | PCCR1_UART6_EN | PCCR1_UART5_EN | PCCR1_UART4_EN | + PCCR1_UART3_EN | PCCR1_UART2_EN | PCCR1_UART1_EN, + base + CCM_PCCR1); + + clks[dummy] = clk_fixed("dummy", 0); + clks[ckih] = clk_fixed("ckih", 26000000); + clks[ckil] = clk_fixed("ckil", 32768); + clks[fpm] = imx_clk_fixed_factor("fpm", "ckil", 1024, 1); + clks[ckih_div1p5] = imx_clk_fixed_factor("ckih_div1p5", "ckih", 2, 3); + + clks[mpll_osc_sel] = imx_clk_mux("mpll_osc_sel", base + CCM_CSCR, 4, 1, + mpll_osc_sel_clks, + ARRAY_SIZE(mpll_osc_sel_clks)); + clks[mpll_sel] = imx_clk_mux("mpll_sel", base + CCM_CSCR, 16, 1, mpll_sel_clks, + ARRAY_SIZE(mpll_sel_clks)); + + clks[mpll] = imx_clk_pllv1("mpll", "mpll_sel", base + CCM_MPCTL0); + clks[spll] = imx_clk_pllv1("spll", "ckih", base + CCM_SPCTL0); + clks[mpll_main2] = imx_clk_fixed_factor("mpll_main2", "mpll", 2, 3); + + if (imx_silicon_revision() >= IMX_CHIP_REV_2_0) { + clks[ahb] = imx_clk_divider("ahb", "mpll_main2", base + CCM_CSCR, 8, 2); + clks[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2); + } else { + clks[ahb] = imx_clk_divider("ahb", "mpll_main2", base + CCM_CSCR, 9, 4); + clks[ipg] = imx_clk_divider("ipg", "ahb", base + CCM_CSCR, 8, 1); + } + + clks[nfc_div] = imx_clk_divider("nfc_div", "ahb", base + CCM_PCDR0, 6, 4); + clks[per1_div] = imx_clk_divider("per1_div", "mpll_main2", base + CCM_PCDR1, 0, 6); + clks[per2_div] = imx_clk_divider("per2_div", "mpll_main2", base + CCM_PCDR1, 8, 6); + clks[per3_div] = imx_clk_divider("per3_div", "mpll_main2", base + CCM_PCDR1, 16, 6); + clks[per4_div] = imx_clk_divider("per4_div", "mpll_main2", base + CCM_PCDR1, 24, 6); + clks[usb_div] = imx_clk_divider("usb_div", "spll", base + CCM_CSCR, 28, 3); + clks[cpu_sel] = imx_clk_mux("cpu_sel", base + CCM_CSCR, 15, 1, cpu_sel_clks, + ARRAY_SIZE(cpu_sel_clks)); + clks[clko_sel] = imx_clk_mux("clko_sel", base + CCM_CCSR, 0, 5, clko_sel_clks, + ARRAY_SIZE(clko_sel_clks)); + if (imx_silicon_revision() >= IMX_CHIP_REV_2_0) + clks[cpu_div] = imx_clk_divider("cpu_div", "cpu_sel", base + CCM_CSCR, 12, 2); + else + clks[cpu_div] = imx_clk_divider("cpu_div", "cpu_sel", base + CCM_CSCR, 13, 3); + clks[clko_div] = imx_clk_divider("clko_div", "clko_sel", base + CCM_PCDR0, 22, 3); + clks[per3_gate] = imx_clk_gate("per3_gate", "per3_div", base + CCM_PCCR1, 8); + clks[lcdc_ahb_gate] = imx_clk_gate("lcdc_ahb_gate", "ahb", base + CCM_PCCR1, 15); + clks[lcdc_ipg_gate] = imx_clk_gate("lcdc_ipg_gate", "ipg", base + CCM_PCCR0, 14); + + clkdev_add_physbase(clks[per1_div], MX27_GPT1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1_div], MX27_GPT2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1_div], MX27_GPT3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1_div], MX27_GPT4_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1_div], MX27_GPT5_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1_div], MX27_GPT6_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1_div], MX27_UART1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1_div], MX27_UART2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1_div], MX27_UART3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1_div], MX27_UART4_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1_div], MX27_UART5_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per1_div], MX27_UART6_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX27_CSPI1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX27_CSPI2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX27_CSPI3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX27_I2C1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX27_I2C2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per2_div], MX27_SDHC1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per2_div], MX27_SDHC2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per2_div], MX27_SDHC3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per3_gate], MX27_LCDC_BASE_ADDR, "per"); + clkdev_add_physbase(clks[lcdc_ahb_gate], MX27_LCDC_BASE_ADDR, "ahb"); + clkdev_add_physbase(clks[lcdc_ipg_gate], MX27_LCDC_BASE_ADDR, "ipg"); + clkdev_add_physbase(clks[ipg], MX27_FEC_BASE_ADDR, NULL); + + return 0; +} + +static __maybe_unused struct of_device_id imx27_ccm_dt_ids[] = { + { + .compatible = "fsl,imx27-ccm", + }, { + /* sentinel */ + } +}; + +static struct driver_d imx27_ccm_driver = { + .probe = imx27_ccm_probe, + .name = "imx27-ccm", + .of_compatible = DRV_OF_COMPAT(imx27_ccm_dt_ids), +}; + +static int imx27_ccm_init(void) +{ + return platform_driver_register(&imx27_ccm_driver); +} +core_initcall(imx27_ccm_init); diff --git a/drivers/clk/imx/clk-imx31.c b/drivers/clk/imx/clk-imx31.c new file mode 100644 index 0000000000..8d135c9a1f --- /dev/null +++ b/drivers/clk/imx/clk-imx31.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2012 Sascha Hauer + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +/* Register addresses */ +#define CCM_CCMR 0x00 +#define CCM_PDR0 0x04 +#define CCM_PDR1 0x08 +//#define CCM_RCSR 0x0C +#define CCM_MPCTL 0x10 +#define CCM_UPCTL 0x14 +#define CCM_SRPCTL 0x18 +#define CCM_COSR 0x1C +#define CCM_CGR0 0x20 +#define CCM_CGR1 0x24 +#define CCM_CGR2 0x28 +#define CCM_WIMR 0x2C +#define CCM_LDC 0x30 +#define CCM_DCVR0 0x34 +#define CCM_DCVR1 0x38 +#define CCM_DCVR2 0x3C +#define CCM_DCVR3 0x40 +#define CCM_LTR0 0x44 +#define CCM_LTR1 0x48 +#define CCM_LTR2 0x4C +#define CCM_LTR3 0x50 +#define CCM_LTBR0 0x54 +#define CCM_LTBR1 0x58 +#define CCM_PMCR0 0x5C +#define CCM_PMCR1 0x60 +#define CCM_PDR2 0x64 + +enum mx31_clks { + ckih, ckil, mpll, spll, upll, mcu_main, hsp, ahb, nfc, ipg, per_div, + per, csi, fir, csi_div, usb_div_pre, usb_div_post, fir_div_pre, + fir_div_post, sdhc1_gate, sdhc2_gate, gpt_gate, epit1_gate, epit2_gate, + iim_gate, ata_gate, sdma_gate, cspi3_gate, rng_gate, uart1_gate, + uart2_gate, ssi1_gate, i2c1_gate, i2c2_gate, i2c3_gate, hantro_gate, + mstick1_gate, mstick2_gate, csi_gate, rtc_gate, wdog_gate, pwm_gate, + sim_gate, ect_gate, usb_gate, kpp_gate, ipu_gate, uart3_gate, + uart4_gate, uart5_gate, owire_gate, ssi2_gate, cspi1_gate, cspi2_gate, + gacc_gate, emi_gate, rtic_gate, firi_gate, clk_max +}; + +static struct clk *clks[clk_max]; + +static const char *mcu_main_sel[] = { + "spll", + "mpll", +}; + +static const char *per_sel[] = { + "per_div", + "ipg", +}; + +static int imx31_ccm_probe(struct device_d *dev) +{ + struct resource *iores; + void __iomem *base; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + base = IOMEM(iores->start); + + writel(0xffffffff, base + CCM_CGR0); + writel(0xffffffff, base + CCM_CGR1); + writel(0xffffffff, base + CCM_CGR2); + + clks[ckih] = clk_fixed("ckih", 26000000); + clks[ckil] = clk_fixed("ckil", 32768); + clks[mpll] = imx_clk_pllv1("mpll", "ckih", base + CCM_MPCTL); + clks[spll] = imx_clk_pllv1("spll", "ckih", base + CCM_SRPCTL); + clks[upll] = imx_clk_pllv1("upll", "ckih", base + CCM_UPCTL); + clks[mcu_main] = imx_clk_mux("mcu_main", base + CCM_PMCR0, 31, 1, + mcu_main_sel, ARRAY_SIZE(mcu_main_sel)); + clks[hsp] = imx_clk_divider("hsp", "mcu_main", base + CCM_PDR0, 11, 3); + clks[ahb] = imx_clk_divider("ahb", "mcu_main", base + CCM_PDR0, 3, 3); + clks[nfc] = imx_clk_divider("nfc", "ahb", base + CCM_PDR0, 8, 3); + clks[ipg] = imx_clk_divider("ipg", "ahb", base + CCM_PDR0, 6, 2); + clks[per_div] = imx_clk_divider("per_div", "upll", base + CCM_PDR0, 16, 5); + clks[per] = imx_clk_mux("per", base + CCM_CCMR, 24, 1, per_sel, ARRAY_SIZE(per_sel)); + + clkdev_add_physbase(clks[per], MX31_UART1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per], MX31_UART2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per], MX31_UART3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per], MX31_UART4_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per], MX31_UART5_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per], MX31_I2C1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per], MX31_I2C2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per], MX31_I2C3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX31_CSPI1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX31_CSPI2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX31_CSPI3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per], MX31_SDHC1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per], MX31_SDHC2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[per], MX31_GPT1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[hsp], MX31_IPU_CTRL_BASE_ADDR, NULL); + + return 0; +} + +static __maybe_unused struct of_device_id imx31_ccm_dt_ids[] = { + { + .compatible = "fsl,imx31-ccm", + }, { + /* sentinel */ + } +}; + +static struct driver_d imx31_ccm_driver = { + .probe = imx31_ccm_probe, + .name = "imx31-ccm", + .of_compatible = DRV_OF_COMPAT(imx31_ccm_dt_ids), +}; + +static int imx31_ccm_init(void) +{ + return platform_driver_register(&imx31_ccm_driver); +} +core_initcall(imx31_ccm_init); diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c new file mode 100644 index 0000000000..af6c4058d7 --- /dev/null +++ b/drivers/clk/imx/clk-imx35.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2012 Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define CCM_CCMR 0x00 +#define CCM_PDR0 0x04 +#define CCM_PDR1 0x08 +#define CCM_PDR2 0x0C +#define CCM_PDR3 0x10 +#define CCM_PDR4 0x14 +#define CCM_RCSR 0x18 +#define CCM_MPCTL 0x1C +#define CCM_PPCTL 0x20 +#define CCM_ACMR 0x24 +#define CCM_COSR 0x28 +#define CCM_CGR0 0x2C +#define CCM_CGR1 0x30 +#define CCM_CGR2 0x34 +#define CCM_CGR3 0x38 + +struct arm_ahb_div { + unsigned char arm, ahb, sel; +}; + +static struct arm_ahb_div clk_consumer[] = { + { .arm = 1, .ahb = 4, .sel = 0}, + { .arm = 1, .ahb = 3, .sel = 1}, + { .arm = 2, .ahb = 2, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 4, .ahb = 1, .sel = 0}, + { .arm = 1, .ahb = 5, .sel = 0}, + { .arm = 1, .ahb = 8, .sel = 0}, + { .arm = 1, .ahb = 6, .sel = 1}, + { .arm = 2, .ahb = 4, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 4, .ahb = 2, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, +}; + +static char hsp_div_532[] = { 4, 8, 3, 0 }; +static char hsp_div_400[] = { 3, 6, 3, 0 }; + +enum mx35_clks { + ckih, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg, + arm_per_div, ahb_per_div, ipg_per, uart_sel, uart_div, esdhc_sel, + esdhc1_div, esdhc2_div, esdhc3_div, spdif_sel, spdif_div_pre, + spdif_div_post, ssi_sel, ssi1_div_pre, ssi1_div_post, ssi2_div_pre, + ssi2_div_post, usb_sel, usb_div, nfc_div, asrc_gate, pata_gate, + audmux_gate, can1_gate, can2_gate, cspi1_gate, cspi2_gate, ect_gate, + edio_gate, emi_gate, epit1_gate, epit2_gate, esai_gate, esdhc1_gate, + esdhc2_gate, esdhc3_gate, fec_gate, gpio1_gate, gpio2_gate, gpio3_gate, + gpt_gate, i2c1_gate, i2c2_gate, i2c3_gate, iomuxc_gate, ipu_gate, + kpp_gate, mlb_gate, mshc_gate, owire_gate, pwm_gate, rngc_gate, + rtc_gate, rtic_gate, scc_gate, sdma_gate, spba_gate, spdif_gate, + ssi1_gate, ssi2_gate, uart1_gate, uart2_gate, uart3_gate, usbotg_gate, + wdog_gate, max_gate, admux_gate, csi_gate, iim_gate, gpu2d_gate, + clk_max +}; + +static struct clk *clks[clk_max]; + +static const char *std_sel[] = { + "ppll", + "arm", +}; + +static const char *ipg_per_sel[] = { + "ahb_per_div", + "arm_per_div", +}; + +static int imx35_ccm_probe(struct device_d *dev) +{ + struct resource *iores; + u32 pdr0, consumer_sel, hsp_sel; + struct arm_ahb_div *aad; + unsigned char *hsp_div; + void __iomem *base; + u32 reg; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + base = IOMEM(iores->start); + + /* Check reset source */ + reg = readl(base + CCM_RCSR); + + switch (reg & 0x0F) { + case 0x00: + reset_source_set_priority(RESET_POR, 200); + break; + case 0x02: + reset_source_set_priority(RESET_JTAG, 200); + break; + case 0x04: + reset_source_set_priority(RESET_RST, 200); + break; + case 0x08: + reset_source_set_priority(RESET_WDG, 200); + break; + } + + writel(0xffffffff, base + CCM_CGR0); + writel(0xffffffff, base + CCM_CGR1); + writel(0xfbffffff, base + CCM_CGR2); + writel(0xffffffff, base + CCM_CGR3); + + pdr0 = __raw_readl(base + CCM_PDR0); + consumer_sel = (pdr0 >> 16) & 0xf; + aad = &clk_consumer[consumer_sel]; + if (!aad->arm) { + pr_err("i.MX35 clk: illegal consumer mux selection 0x%x\n", consumer_sel); + /* + * We are basically stuck. Continue with a default entry and hope we + * get far enough to actually show the above message + */ + aad = &clk_consumer[0]; + } + + clks[ckih] = clk_fixed("ckih", 24000000); + clks[mpll] = imx_clk_pllv1("mpll", "ckih", base + CCM_MPCTL); + clks[ppll] = imx_clk_pllv1("ppll", "ckih", base + CCM_PPCTL); + + clks[mpll_075] = imx_clk_fixed_factor("mpll_075", "mpll", 3, 4); + + if (aad->sel) + clks[arm] = imx_clk_fixed_factor("arm", "mpll_075", 1, aad->arm); + else + clks[arm] = imx_clk_fixed_factor("arm", "mpll", 1, aad->arm); + + if (clk_get_rate(clks[arm]) > 400000000) + hsp_div = hsp_div_532; + else + hsp_div = hsp_div_400; + + hsp_sel = (pdr0 >> 20) & 0x3; + if (!hsp_div[hsp_sel]) { + pr_err("i.MX35 clk: illegal hsp clk selection 0x%x\n", hsp_sel); + hsp_sel = 0; + } + + clks[hsp] = imx_clk_fixed_factor("hsp", "arm", 1, hsp_div[hsp_sel]); + + clks[ahb] = imx_clk_fixed_factor("ahb", "arm", 1, aad->ahb); + clks[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2); + + clks[arm_per_div] = imx_clk_divider("arm_per_div", "arm", base + CCM_PDR4, 16, 6); + clks[ahb_per_div] = imx_clk_divider("ahb_per_div", "ahb", base + CCM_PDR0, 12, 3); + clks[ipg_per] = imx_clk_mux("ipg_per", base + CCM_PDR0, 26, 1, ipg_per_sel, ARRAY_SIZE(ipg_per_sel)); + + clks[uart_sel] = imx_clk_mux("uart_sel", base + CCM_PDR3, 14, 1, std_sel, ARRAY_SIZE(std_sel)); + clks[uart_div] = imx_clk_divider("uart_div", "uart_sel", base + CCM_PDR4, 10, 6); + + clks[esdhc_sel] = imx_clk_mux("esdhc_sel", base + CCM_PDR4, 9, 1, std_sel, ARRAY_SIZE(std_sel)); + clks[esdhc1_div] = imx_clk_divider("esdhc1_div", "esdhc_sel", base + CCM_PDR3, 0, 6); + clks[esdhc2_div] = imx_clk_divider("esdhc2_div", "esdhc_sel", base + CCM_PDR3, 8, 6); + clks[esdhc3_div] = imx_clk_divider("esdhc3_div", "esdhc_sel", base + CCM_PDR3, 16, 6); + + clks[usb_sel] = imx_clk_mux("usb_sel", base + CCM_PDR4, 9, 1, std_sel, ARRAY_SIZE(std_sel)); + clks[usb_div] = imx_clk_divider("usb_div", "usb_sel", base + CCM_PDR4, 22, 6); + + clkdev_add_physbase(clks[uart_div], MX35_UART1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[uart_div], MX35_UART2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[uart_div], MX35_UART3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg_per], MX35_I2C1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg_per], MX35_I2C2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg_per], MX35_I2C3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX35_CSPI1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX35_CSPI2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX35_FEC_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg], MX35_GPT1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[esdhc1_div], MX35_ESDHC1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[esdhc2_div], MX35_ESDHC2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[esdhc3_div], MX35_ESDHC3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[hsp], MX35_IPU_CTRL_BASE_ADDR, NULL); + + return 0; +} + +static __maybe_unused struct of_device_id imx35_ccm_dt_ids[] = { + { + .compatible = "fsl,imx35-ccm", + }, { + /* sentinel */ + } +}; + +static struct driver_d imx35_ccm_driver = { + .probe = imx35_ccm_probe, + .name = "imx35-ccm", + .of_compatible = DRV_OF_COMPAT(imx35_ccm_dt_ids), +}; + +static int imx35_ccm_init(void) +{ + return platform_driver_register(&imx35_ccm_driver); +} +core_initcall(imx35_ccm_init); diff --git a/drivers/clk/imx/clk-imx5.c b/drivers/clk/imx/clk-imx5.c new file mode 100644 index 0000000000..c4c47a6d87 --- /dev/null +++ b/drivers/clk/imx/clk-imx5.c @@ -0,0 +1,533 @@ +/* + * Copyright (C) 2011 Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +/* Register addresses of CCM*/ +#define CCM_CCR 0x00 +#define CCM_CCDR 0x04 +#define CCM_CSR 0x08 +#define CCM_CCSR 0x0C +#define CCM_CACRR 0x10 +#define CCM_CBCDR 0x14 +#define CCM_CBCMR 0x18 +#define CCM_CSCMR1 0x1C +#define CCM_CSCMR2 0x20 +#define CCM_CSCDR1 0x24 +#define CCM_CS1CDR 0x28 +#define CCM_CS2CDR 0x2C +#define CCM_CDCDR 0x30 +#define CCM_CHSCDR 0x34 +#define CCM_CSCDR2 0x38 +#define CCM_CSCDR3 0x3C +#define CCM_CSCDR4 0x40 +#define CCM_CWDR 0x44 +#define CCM_CDHIPR 0x48 +#define CCM_CDCR 0x4C +#define CCM_CTOR 0x50 +#define CCM_CLPCR 0x54 +#define CCM_CISR 0x58 +#define CCM_CIMR 0x5C +#define CCM_CCOSR 0x60 +#define CCM_CGPR 0x64 +#define CCM_CCGR0 0x68 +#define CCM_CCGR1 0x6C +#define CCM_CCGR2 0x70 +#define CCM_CCGR3 0x74 +#define CCM_CCGR4 0x78 +#define CCM_CCGR5 0x7C +#define CCM_CCGR6 0x80 +#define CCM_CCGR7 0x84 + +#define CCM_CMEOR 0x84 + +static struct clk *clks[IMX5_CLK_END]; + +/* This is used multiple times */ +static const char *standard_pll_sel[] = { + "pll1_sw", + "pll2_sw", + "pll3_sw", + "lp_apm", +}; + +static const char *mx50_3bit_clk_sel[] = { + "pll1_sw", + "pll2_sw", + "pll3_sw", + "lp_apm", + "pfd0", + "pfd1", + "pfd4", + "osc", +}; + +static const char *lp_apm_sel[] = { + "osc", +}; + +static const char *periph_apm_sel[] = { + "pll1_sw", + "pll3_sw", + "lp_apm", +}; + +static const char *main_bus_sel[] = { + "pll2_sw", + "periph_apm", +}; + +static const char *mx50_periph_clk_sel[] = { + "pll1_sw", + "pll2_sw", + "pll3_sw", + "lp_apm", +}; + +static const char *per_lp_apm_sel[] = { + "main_bus", + "lp_apm", +}; + +static const char *per_root_sel[] = { + "per_podf", + "ipg", +}; + +static const char *esdhc_c_sel[] = { + "esdhc_a_podf", + "esdhc_b_podf", +}; + +static const char *esdhc_d_sel[] = { + "esdhc_a_podf", + "esdhc_b_podf", +}; + +static const char *emi_slow_sel[] = { + "main_bus", + "ahb", +}; + +static const char *usb_phy_sel_str[] = { + "osc", + "usb_phy_podf", +}; + +static const char *mx51_ipu_di0_sel[] = { + "di_pred", + "osc", + "ckih1", + "tve_di", +}; + +static const char *mx53_ipu_di0_sel[] = { + "di_pred", + "osc", + "ckih1", + "di_pll4_podf", + "dummy", + "ldb_di0_div", +}; + +static const char *mx53_ldb_di0_sel[] = { + "pll3_sw", + "pll4_sw", +}; + +static const char *mx51_ipu_di1_sel[] = { + "di_pred", + "osc", + "ckih1", + "tve_di", + "ipp_di1", +}; + +static const char *mx53_ipu_di1_sel[] = { + "di_pred", + "osc", + "ckih1", + "tve_di", + "ipp_di1", + "ldb_di1_div", +}; + +static const char *mx53_ldb_di1_sel[] = { + "pll3_sw", + "pll4_sw", +}; + +static const char *mx51_tve_ext_sel[] = { + "osc", + "ckih1", +}; + +static const char *mx53_tve_ext_sel[] = { + "pll4_sw", + "ckih1", +}; + +static const char *mx51_tve_sel[] = { + "tve_pred", + "tve_ext_sel", +}; + +static const char *ipu_sel[] = { + "axi_a", + "axi_b", + "emi_slow_gate", + "ahb", +}; + +static void __init mx5_clocks_common_init(struct device_d *dev, void __iomem *base) +{ + writel(0xffffffff, base + CCM_CCGR0); + writel(0xffffffff, base + CCM_CCGR1); + writel(0xffffffff, base + CCM_CCGR2); + writel(0xffffffff, base + CCM_CCGR3); + writel(0xffffffff, base + CCM_CCGR4); + writel(0xffffffff, base + CCM_CCGR5); + writel(0xffffffff, base + CCM_CCGR6); + writel(0xffffffff, base + CCM_CCGR7); + + if (!IS_ENABLED(CONFIG_COMMON_CLK_OF_PROVIDER) || !dev->device_node) { + clks[IMX5_CLK_CKIL] = clk_fixed("ckil", 32768); + clks[IMX5_CLK_OSC] = clk_fixed("osc", 24000000); + } + + clks[IMX5_CLK_PER_LP_APM] = imx_clk_mux("per_lp_apm", base + CCM_CBCMR, 1, 1, + per_lp_apm_sel, ARRAY_SIZE(per_lp_apm_sel)); + clks[IMX5_CLK_PER_PRED1] = imx_clk_divider("per_pred1", "per_lp_apm", base + CCM_CBCDR, 6, 2); + clks[IMX5_CLK_PER_PRED2] = imx_clk_divider("per_pred2", "per_pred1", base + CCM_CBCDR, 3, 3); + clks[IMX5_CLK_PER_PODF] = imx_clk_divider("per_podf", "per_pred2", base + CCM_CBCDR, 0, 3); + clks[IMX5_CLK_PER_ROOT] = imx_clk_mux("per_root", base + CCM_CBCMR, 0, 1, + per_root_sel, ARRAY_SIZE(per_root_sel)); + clks[IMX5_CLK_AHB] = imx_clk_divider("ahb", "main_bus", base + CCM_CBCDR, 10, 3); + clks[IMX5_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + CCM_CBCDR, 8, 2); + clks[IMX5_CLK_AXI_A] = imx_clk_divider("axi_a", "main_bus", base + CCM_CBCDR, 16, 3); + clks[IMX5_CLK_AXI_B] = imx_clk_divider("axi_b", "main_bus", base + CCM_CBCDR, 19, 3); + clks[IMX5_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + CCM_CSCMR1, 24, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clks[IMX5_CLK_UART_PRED] = imx_clk_divider("uart_pred", "uart_sel", base + CCM_CSCDR1, 3, 3); + clks[IMX5_CLK_UART_ROOT] = imx_clk_divider("uart_root", "uart_pred", base + CCM_CSCDR1, 0, 3); + clks[IMX5_CLK_ESDHC_A_PRED] = imx_clk_divider("esdhc_a_pred", + "esdhc_a_sel", base + CCM_CSCDR1, 16, 3); + clks[IMX5_CLK_ESDHC_A_PODF] = imx_clk_divider("esdhc_a_podf", + "esdhc_a_pred", base + CCM_CSCDR1, 11, 3); + clks[IMX5_CLK_ESDHC_B_PRED] = imx_clk_divider("esdhc_b_pred", + "esdhc_b_sel", base + CCM_CSCDR1, 22, 3); + clks[IMX5_CLK_ESDHC_B_PODF] = imx_clk_divider("esdhc_b_podf", + "esdhc_b_pred", base + CCM_CSCDR1, 19, 3); + clks[IMX5_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + CCM_CSCMR1, + 4, 2, standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clks[IMX5_CLK_ECSPI_PRED] = imx_clk_divider("ecspi_pred", + "ecspi_sel", base + CCM_CSCDR2, 25, 3); + clks[IMX5_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", + "ecspi_pred", base + CCM_CSCDR2, 19, 6); + clks[IMX5_CLK_CPU_PODF] = imx_clk_divider("cpu_podf", + "pll1_sw", base + CCM_CACRR, 0, 3); +} + +static void mx5_clocks_mx51_mx53_init(void __iomem *base) +{ + clks[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", base + CCM_CCSR, 9, 1, + lp_apm_sel, ARRAY_SIZE(lp_apm_sel)); + clks[IMX5_CLK_PERIPH_APM] = imx_clk_mux("periph_apm", base + CCM_CBCMR, 12, 2, + periph_apm_sel, ARRAY_SIZE(periph_apm_sel)); + clks[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", base + CCM_CBCDR, 25, 1, + main_bus_sel, ARRAY_SIZE(main_bus_sel)); + clks[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", base + CCM_CSCMR1, 20, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clks[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", base + CCM_CSCMR1, 16, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clks[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", base + CCM_CSCMR1, 19, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel)); + clks[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", base + CCM_CSCMR1, 18, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel)); + clks[IMX5_CLK_EMI_SEL] = imx_clk_mux("emi_sel", base + CCM_CBCDR, 26, 1, + emi_slow_sel, ARRAY_SIZE(emi_slow_sel)); + clks[IMX5_CLK_EMI_SLOW_PODF] = imx_clk_divider("emi_slow_podf", "emi_sel", base + CCM_CBCDR, 22, 3); + clks[IMX5_CLK_NFC_PODF] = imx_clk_divider("nfc_podf", "emi_slow_podf", base + CCM_CBCDR, 13, 3); + clks[IMX5_CLK_USBOH3_SEL] = imx_clk_mux("usboh3_sel", base + CCM_CSCMR1, 22, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clks[IMX5_CLK_USBOH3_PRED] = imx_clk_divider("usboh3_pred", "usboh3_sel", base + CCM_CSCDR1, 8, 3); + clks[IMX5_CLK_USBOH3_PODF] = imx_clk_divider("usboh3_podf", "usboh3_pred", base + CCM_CSCDR1, 6, 2); + clks[IMX5_CLK_USB_PHY_PRED] = imx_clk_divider("usb_phy_pred", "pll3_sw", base + CCM_CDCDR, 3, 3); + clks[IMX5_CLK_USB_PHY_PODF] = imx_clk_divider("usb_phy_podf", "usb_phy_pred", base + CCM_CDCDR, 0, 3); + clks[IMX5_CLK_USB_PHY_SEL] = imx_clk_mux("usb_phy_sel", base + CCM_CSCMR1, 26, 1, + usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str)); +} + +static void mx5_clocks_ipu_init(void __iomem *regs) +{ + clks[IMX5_CLK_IPU_SEL] = imx_clk_mux("ipu_sel", regs + CCM_CBCMR, 6, 2, ipu_sel, ARRAY_SIZE(ipu_sel)); +} + +int __init mx50_clocks_init(struct device_d *dev, void __iomem *regs) +{ + clks[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", + (void *)MX50_PLL1_BASE_ADDR); + clks[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", + (void *)MX50_PLL2_BASE_ADDR); + clks[IMX5_CLK_PLL3_SW] = imx_clk_pllv2("pll3_sw", "osc", + (void *)MX50_PLL3_BASE_ADDR); + + mx5_clocks_common_init(dev, regs); + + clks[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", regs + CCM_CCSR, 10, 1, lp_apm_sel, ARRAY_SIZE(lp_apm_sel)); + clks[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", regs + CCM_CBCDR, 25, 2, mx50_periph_clk_sel, ARRAY_SIZE(mx50_periph_clk_sel)); + clks[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", regs + CCM_CSCMR1, 21, 2, standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clks[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", regs + CCM_CSCMR1, 16, 3, mx50_3bit_clk_sel, ARRAY_SIZE(mx50_3bit_clk_sel)); + clks[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", regs + CCM_CSCMR1, 20, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel)); + clks[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", regs + CCM_CSCMR1, 19, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel)); + clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX50_UART1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX50_UART2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX50_UART3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_I2C1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_I2C2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_I2C3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_GPT1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_IPG], MX50_CSPI_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX50_ECSPI1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX50_ECSPI2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_IPG], MX50_FEC_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ESDHC_A_PODF], MX50_ESDHC1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ESDHC_C_SEL], MX50_ESDHC2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ESDHC_B_PODF], MX50_ESDHC3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ESDHC_D_SEL], MX50_ESDHC4_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_PWM1_BASE_ADDR, "per"); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_PWM2_BASE_ADDR, "per"); + + return 0; +} + +static int imx50_ccm_probe(struct device_d *dev) +{ + struct resource *iores; + void __iomem *regs; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + regs = IOMEM(iores->start); + + mx50_clocks_init(dev, regs); + + return 0; +} + +static __maybe_unused struct of_device_id imx50_ccm_dt_ids[] = { + { + .compatible = "fsl,imx50-ccm", + }, { + /* sentinel */ + } +}; + +static struct driver_d imx50_ccm_driver = { + .probe = imx50_ccm_probe, + .name = "imx50-ccm", + .of_compatible = DRV_OF_COMPAT(imx50_ccm_dt_ids), +}; + +static void mx51_clocks_ipu_init(void __iomem *regs) +{ + clks[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux_p("ipu_di0_sel", regs + CCM_CSCMR2, 26, 3, + mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel)); + clks[IMX5_CLK_IPU_DI1_SEL] = imx_clk_mux_p("ipu_di1_sel", regs + CCM_CSCMR2, 29, 3, + mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel)); + clks[IMX5_CLK_TVE_EXT_SEL] = imx_clk_mux_p("tve_ext_sel", regs + CCM_CSCMR1, 6, 1, + mx51_tve_ext_sel, ARRAY_SIZE(mx51_tve_ext_sel)); + clks[IMX5_CLK_TVE_SEL] = imx_clk_mux("tve_sel", regs + CCM_CSCMR1, 7, 1, + mx51_tve_sel, ARRAY_SIZE(mx51_tve_sel)); + clks[IMX5_CLK_TVE_PRED] = imx_clk_divider("tve_pred", "pll3_sw", regs + CCM_CDCDR, 28, 3); + + mx5_clocks_ipu_init(regs); + + clkdev_add_physbase(clks[IMX5_CLK_IPU_SEL], MX51_IPU_BASE_ADDR, "bus"); + clkdev_add_physbase(clks[IMX5_CLK_IPU_DI0_SEL], MX51_IPU_BASE_ADDR, "di0"); + clkdev_add_physbase(clks[IMX5_CLK_IPU_DI1_SEL], MX51_IPU_BASE_ADDR, "di1"); +} + +int __init mx51_clocks_init(struct device_d *dev, void __iomem *regs) +{ + clks[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", (void *)MX51_PLL1_BASE_ADDR); + clks[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", (void *)MX51_PLL2_BASE_ADDR); + clks[IMX5_CLK_PLL3_SW] = imx_clk_pllv2("pll3_sw", "osc", (void *)MX51_PLL3_BASE_ADDR); + + mx5_clocks_common_init(dev, regs); + mx5_clocks_mx51_mx53_init(regs); + + clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX51_UART1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX51_UART2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX51_UART3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_I2C1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_I2C2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_GPT1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_IPG], MX51_CSPI_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX51_ECSPI1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX51_ECSPI2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_IPG], MX51_MXC_FEC_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ESDHC_A_PODF], MX51_MMC_SDHC1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ESDHC_B_PODF], MX51_MMC_SDHC2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ESDHC_C_SEL], MX51_MMC_SDHC3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ESDHC_D_SEL], MX51_MMC_SDHC4_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_IPG], MX51_ATA_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_PWM1_BASE_ADDR, "per"); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_PWM2_BASE_ADDR, "per"); + + if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3)) + mx51_clocks_ipu_init(regs); + + return 0; +} + +static int imx51_ccm_probe(struct device_d *dev) +{ + struct resource *iores; + void __iomem *regs; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + regs = IOMEM(iores->start); + + mx51_clocks_init(dev, regs); + + return 0; +} + +static __maybe_unused struct of_device_id imx51_ccm_dt_ids[] = { + { + .compatible = "fsl,imx51-ccm", + }, { + /* sentinel */ + } +}; + +static struct driver_d imx51_ccm_driver = { + .probe = imx51_ccm_probe, + .name = "imx51-ccm", + .of_compatible = DRV_OF_COMPAT(imx51_ccm_dt_ids), +}; + +static void mx53_clocks_ipu_init(void __iomem *regs) +{ + clks[IMX5_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); + clks[IMX5_CLK_LDB_DI1_DIV] = imx_clk_divider_np("ldb_di1_div", "ldb_di1_div_3_5", regs + CCM_CSCMR2, 11, 1); + clks[IMX5_CLK_LDB_DI1_SEL] = imx_clk_mux_p("ldb_di1_sel", regs + CCM_CSCMR2, 9, 1, + mx53_ldb_di1_sel, ARRAY_SIZE(mx53_ldb_di1_sel)); + clks[IMX5_CLK_DI_PLL4_PODF] = imx_clk_divider("di_pll4_podf", "pll4_sw", regs + CCM_CDCDR, 16, 3); + clks[IMX5_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); + clks[IMX5_CLK_LDB_DI0_DIV] = imx_clk_divider("ldb_di0_div", "ldb_di0_div_3_5", regs + CCM_CSCMR2, 10, 1); + clks[IMX5_CLK_LDB_DI0_SEL] = imx_clk_mux_p("ldb_di0_sel", regs + CCM_CSCMR2, 8, 1, + mx53_ldb_di0_sel, ARRAY_SIZE(mx53_ldb_di0_sel)); + clks[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux_p("ipu_di0_sel", regs + CCM_CSCMR2, 26, 3, + mx53_ipu_di0_sel, ARRAY_SIZE(mx53_ipu_di0_sel)); + clks[IMX5_CLK_IPU_DI1_SEL] = imx_clk_mux_p("ipu_di1_sel", regs + CCM_CSCMR2, 29, 3, + mx53_ipu_di1_sel, ARRAY_SIZE(mx53_ipu_di1_sel)); + clks[IMX5_CLK_TVE_EXT_SEL] = imx_clk_mux_p("tve_ext_sel", regs + CCM_CSCMR1, 6, 1, + mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel)); + clks[IMX5_CLK_TVE_PRED] = imx_clk_divider("tve_pred", "tve_ext_sel", regs + CCM_CDCDR, 28, 3); + + mx5_clocks_ipu_init(regs); + + clkdev_add_physbase(clks[IMX5_CLK_IPU_SEL], MX53_IPU_BASE_ADDR, "bus"); + clkdev_add_physbase(clks[IMX5_CLK_IPU_DI0_SEL], MX53_IPU_BASE_ADDR, "di0"); + clkdev_add_physbase(clks[IMX5_CLK_IPU_DI1_SEL], MX53_IPU_BASE_ADDR, "di1"); +} + +int __init mx53_clocks_init(struct device_d *dev, void __iomem *regs) +{ + clks[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", (void *)MX53_PLL1_BASE_ADDR); + clks[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", (void *)MX53_PLL2_BASE_ADDR); + clks[IMX5_CLK_PLL3_SW] = imx_clk_pllv2("pll3_sw", "osc", (void *)MX53_PLL3_BASE_ADDR); + clks[IMX5_CLK_PLL4_SW] = imx_clk_pllv2("pll4_sw", "osc", (void *)MX53_PLL4_BASE_ADDR); + + mx5_clocks_common_init(dev, regs); + mx5_clocks_mx51_mx53_init(regs); + + clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART4_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART5_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_I2C1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_I2C2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_I2C3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_GPT1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_IPG], MX53_CSPI_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX53_ECSPI1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX53_ECSPI2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_IPG], MX53_FEC_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ESDHC_A_PODF], MX53_ESDHC1_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ESDHC_C_SEL], MX53_ESDHC2_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ESDHC_B_PODF], MX53_ESDHC3_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_ESDHC_D_SEL], MX53_ESDHC4_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_AHB], MX53_SATA_BASE_ADDR, NULL); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_PWM1_BASE_ADDR, "per"); + clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_PWM2_BASE_ADDR, "per"); + + if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3)) + mx53_clocks_ipu_init(regs); + + return 0; +} + +static int imx53_ccm_probe(struct device_d *dev) +{ + struct resource *iores; + void __iomem *regs; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + regs = IOMEM(iores->start); + + mx53_clocks_init(dev, regs); + + return 0; +} + +static __maybe_unused struct of_device_id imx53_ccm_dt_ids[] = { + { + .compatible = "fsl,imx53-ccm", + }, { + /* sentinel */ + } +}; + +static struct driver_d imx53_ccm_driver = { + .probe = imx53_ccm_probe, + .name = "imx53-ccm", + .of_compatible = DRV_OF_COMPAT(imx53_ccm_dt_ids), +}; + +static int imx5_ccm_init(void) +{ + if (IS_ENABLED(CONFIG_ARCH_IMX50)) + platform_driver_register(&imx50_ccm_driver); + if (IS_ENABLED(CONFIG_ARCH_IMX51)) + platform_driver_register(&imx51_ccm_driver); + if (IS_ENABLED(CONFIG_ARCH_IMX53)) + platform_driver_register(&imx53_ccm_driver); + + return 0; +} +core_initcall(imx5_ccm_init); diff --git a/drivers/clk/imx/clk-imx6.c b/drivers/clk/imx/clk-imx6.c new file mode 100644 index 0000000000..8ac43bebb0 --- /dev/null +++ b/drivers/clk/imx/clk-imx6.c @@ -0,0 +1,541 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define CCGR0 0x68 +#define CCGR1 0x6c +#define CCGR2 0x70 +#define CCGR3 0x74 +#define CCGR4 0x78 +#define CCGR5 0x7c +#define CCGR6 0x80 +#define CCGR7 0x84 + +#define CLPCR 0x54 +#define BP_CLPCR_LPM 0 +#define BM_CLPCR_LPM (0x3 << 0) +#define BM_CLPCR_BYPASS_PMIC_READY (0x1 << 2) +#define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) +#define BM_CLPCR_SBYOS (0x1 << 6) +#define BM_CLPCR_DIS_REF_OSC (0x1 << 7) +#define BM_CLPCR_VSTBY (0x1 << 8) +#define BP_CLPCR_STBY_COUNT 9 +#define BM_CLPCR_STBY_COUNT (0x3 << 9) +#define BM_CLPCR_COSC_PWRDOWN (0x1 << 11) +#define BM_CLPCR_WB_PER_AT_LPM (0x1 << 16) +#define BM_CLPCR_WB_CORE_AT_LPM (0x1 << 17) +#define BM_CLPCR_BYP_MMDC_CH0_LPM_HS (0x1 << 19) +#define BM_CLPCR_BYP_MMDC_CH1_LPM_HS (0x1 << 21) +#define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22) +#define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23) +#define BM_CLPCR_MASK_CORE2_WFI (0x1 << 24) +#define BM_CLPCR_MASK_CORE3_WFI (0x1 << 25) +#define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) +#define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) + +static struct clk *clks[IMX6QDL_CLK_END]; +static struct clk_onecell_data clk_data; + +static const char *step_sels[] = { + "osc", + "pll2_pfd2_396m", +}; + +static const char *pll1_sw_sels[] = { + "pll1_sys", + "step", +}; + +static const char *periph_pre_sels[] = { + "pll2_bus", + "pll2_pfd2_396m", + "pll2_pfd0_352m", + "pll2_198m", +}; + +static const char *periph_clk2_sels[] = { + "pll3_usb_otg", + "osc", +}; + +static const char *periph_sels[] = { + "periph_pre", + "periph_clk2", +}; + +static const char *periph2_sels[] = { + "periph2_pre", + "periph2_clk2", +}; + +static const char *axi_sels[] = { + "periph", + "pll2_pfd2_396m", + "pll3_pfd1_540m", +}; + +static const char *usdhc_sels[] = { + "pll2_pfd2_396m", + "pll2_pfd0_352m", +}; + +static const char *enfc_sels[] = { + "pll2_pfd0_352m", + "pll2_bus", + "pll3_usb_otg", + "pll2_pfd2_396m", +}; + +static const char *eim_sels[] = { + "axi", + "pll3_usb_otg", + "pll2_pfd2_396m", + "pll2_pfd0_352m", +}; + +static const char *vdo_axi_sels[] = { + "axi", + "ahb", +}; + +static const char *cko_sels[] = { + "cko1", + "cko2", +}; + +static const char *cko1_sels[] = { + "pll3_usb_otg", + "pll2_bus", + "pll1_sys", + "pll5_video", + "dummy", + "axi", + "enfc", + "ipu1_di0", + "ipu1_di1", + "ipu2_di0", + "ipu2_di1", + "ahb", + "ipg", + "ipg_per", + "ckil", + "pll4_audio", +}; + +static const char *cko2_sels[] = { + "mmdc_ch0_axi", + "mmdc_ch1_axi", + "usdhc4", + "usdhc1", + "gpu2d_axi", + "dummy", + "ecspi_root", + "gpu3d_axi", + "usdhc3", + "dummy", + "arm", + "ipu1", + "ipu2", + "vdo_axi", + "osc", + "gpu2d_core", + "gpu3d_core", + "usdhc2", + "ssi1", + "ssi2", + "ssi3", + "gpu3d_shader", + "vpu_axi", + "can_root", + "ldb_di0", + "ldb_di1", + "esai", + "eim_slow", + "uart_serial", + "spdif", + "asrc", + "hsi_tx", +}; + +static const char *ipu_sels[] = { + "mmdc_ch0_axi_podf", + "pll2_pfd2_396m", + "pll3_120m", + "pll3_pfd1_540m", +}; + +static const char *ldb_di_sels[] = { + "pll5_video_div", + "pll2_pfd0_352m", + "pll2_pfd2_396m", + "mmdc_ch1_axi_podf", + "pll3_usb_otg", +}; + +static const char *ipu_di_pre_sels[] = { + "mmdc_ch0_axi", + "pll3_usb_otg", + "pll5_video_div", + "pll2_pfd0_352m", + "pll2_pfd2_396m", + "pll3_pfd1_540m", +}; + +static const char *ipu1_di0_sels[] = { + "ipu1_di0_pre", + "dummy", + "dummy", + "ldb_di0_podf", + "ldb_di1_podf", +}; + +static const char *ipu1_di1_sels[] = { + "ipu1_di1_pre", + "dummy", + "dummy", + "ldb_di0_podf", + "ldb_di1_podf", +}; + +static const char *ipu2_di0_sels[] = { + "ipu2_di0_pre", + "dummy", + "dummy", + "ldb_di0_podf", + "ldb_di1_podf", +}; + +static const char *ipu2_di1_sels[] = { + "ipu2_di1_pre", + "dummy", + "dummy", + "ldb_di0_podf", + "ldb_di1_podf", +}; + +static const char *lvds_sels[] = { + "dummy", + "dummy", + "dummy", + "dummy", + "dummy", + "dummy", + "pll4_audio", + "pll5_video", + "pll8_mlb", + "enet_ref", + "pcie_ref_125m", + "sata_ref_100m", +}; + +static const char *pcie_axi_sels[] = { + "axi", + "ahb", +}; + +static struct clk_div_table clk_enet_ref_table[] = { + { .val = 0, .div = 20, }, + { .val = 1, .div = 10, }, + { .val = 2, .div = 5, }, + { .val = 3, .div = 4, }, + { }, +}; + +static struct clk_div_table post_div_table[] = { + { .val = 2, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 0, .div = 4, }, + { /* sentinel */ } +}; + +static struct clk_div_table video_div_table[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 2, .div = 1, }, + { .val = 3, .div = 4, }, + { /* sentinel */ } +}; + +static void imx6_add_video_clks(void __iomem *anab, void __iomem *cb) +{ + clks[IMX6QDL_CLK_PLL5_POST_DIV] = imx_clk_divider_table("pll5_post_div", "pll5_video", anab + 0xa0, 19, 2, post_div_table); + clks[IMX6QDL_CLK_PLL5_VIDEO_DIV] = imx_clk_divider_table("pll5_video_div", "pll5_post_div", anab + 0x170, 30, 2, video_div_table); + + clks[IMX6QDL_CLK_IPU1_SEL] = imx_clk_mux("ipu1_sel", cb + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); + clks[IMX6QDL_CLK_IPU2_SEL] = imx_clk_mux("ipu2_sel", cb + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); + clks[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_p("ldb_di0_sel", cb + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); + clks[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_p("ldb_di1_sel", cb + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); + clks[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_mux_p("ipu1_di0_pre_sel", cb + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clks[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_mux_p("ipu1_di1_pre_sel", cb + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clks[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_mux_p("ipu2_di0_pre_sel", cb + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clks[IMX6QDL_CLK_IPU2_DI1_PRE_SEL] = imx_clk_mux_p("ipu2_di1_pre_sel", cb + 0x38, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clks[IMX6QDL_CLK_IPU1_DI0_SEL] = imx_clk_mux_p("ipu1_di0_sel", cb + 0x34, 0, 3, ipu1_di0_sels, ARRAY_SIZE(ipu1_di0_sels)); + clks[IMX6QDL_CLK_IPU1_DI1_SEL] = imx_clk_mux_p("ipu1_di1_sel", cb + 0x34, 9, 3, ipu1_di1_sels, ARRAY_SIZE(ipu1_di1_sels)); + clks[IMX6QDL_CLK_IPU2_DI0_SEL] = imx_clk_mux_p("ipu2_di0_sel", cb + 0x38, 0, 3, ipu2_di0_sels, ARRAY_SIZE(ipu2_di0_sels)); + clks[IMX6QDL_CLK_IPU2_DI1_SEL] = imx_clk_mux_p("ipu2_di1_sel", cb + 0x38, 9, 3, ipu2_di1_sels, ARRAY_SIZE(ipu2_di1_sels)); + + clks[IMX6QDL_CLK_IPU1_PODF] = imx_clk_divider("ipu1_podf", "ipu1_sel", cb + 0x3c, 11, 3); + clks[IMX6QDL_CLK_IPU2_PODF] = imx_clk_divider("ipu2_podf", "ipu2_sel", cb + 0x3c, 16, 3); + clks[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); + clks[IMX6QDL_CLK_LDB_DI0_PODF] = imx_clk_divider_np("ldb_di0_podf", "ldb_di0_div_3_5", cb + 0x20, 10, 1); + clks[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); + clks[IMX6QDL_CLK_LDB_DI1_PODF] = imx_clk_divider_np("ldb_di1_podf", "ldb_di1_div_3_5", cb + 0x20, 11, 1); + clks[IMX6QDL_CLK_IPU1_DI0_PRE] = imx_clk_divider("ipu1_di0_pre", "ipu1_di0_pre_sel", cb + 0x34, 3, 3); + clks[IMX6QDL_CLK_IPU1_DI1_PRE] = imx_clk_divider("ipu1_di1_pre", "ipu1_di1_pre_sel", cb + 0x34, 12, 3); + clks[IMX6QDL_CLK_IPU2_DI0_PRE] = imx_clk_divider("ipu2_di0_pre", "ipu2_di0_pre_sel", cb + 0x38, 3, 3); + clks[IMX6QDL_CLK_IPU2_DI1_PRE] = imx_clk_divider("ipu2_di1_pre", "ipu2_di1_pre_sel", cb + 0x38, 12, 3); + + clks[IMX6QDL_CLK_IPU1] = imx_clk_gate2("ipu1", "ipu1_podf", cb + 0x74, 0); + clks[IMX6QDL_CLK_IPU1_DI0] = imx_clk_gate2("ipu1_di0", "ipu1_di0_sel", cb + 0x74, 2); + clks[IMX6QDL_CLK_IPU1_DI1] = imx_clk_gate2("ipu1_di1", "ipu1_di1_sel", cb + 0x74, 4); + clks[IMX6QDL_CLK_IPU2] = imx_clk_gate2("ipu2", "ipu2_podf", cb + 0x74, 6); + clks[IMX6QDL_CLK_IPU2_DI0] = imx_clk_gate2("ipu2_di0", "ipu2_di0_sel", cb + 0x74, 8); + clks[IMX6QDL_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_podf", cb + 0x74, 12); + clks[IMX6QDL_CLK_LDB_DI1] = imx_clk_gate2("ldb_di1", "ldb_di1_podf", cb + 0x74, 14); + clks[IMX6QDL_CLK_IPU2_DI1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", cb + 0x74, 10); + + clk_set_parent(clks[IMX6QDL_CLK_IPU1_DI0_SEL], clks[IMX6QDL_CLK_IPU1_DI0_PRE]); + clk_set_parent(clks[IMX6QDL_CLK_IPU1_DI1_SEL], clks[IMX6QDL_CLK_IPU1_DI1_PRE]); + clk_set_parent(clks[IMX6QDL_CLK_IPU2_DI0_SEL], clks[IMX6QDL_CLK_IPU2_DI0_PRE]); + clk_set_parent(clks[IMX6QDL_CLK_IPU2_DI1_SEL], clks[IMX6QDL_CLK_IPU2_DI1_PRE]); + + clk_set_parent(clks[IMX6QDL_CLK_IPU1_DI0_PRE_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]); + clk_set_parent(clks[IMX6QDL_CLK_IPU1_DI1_PRE_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]); + clk_set_parent(clks[IMX6QDL_CLK_IPU2_DI0_PRE_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]); + clk_set_parent(clks[IMX6QDL_CLK_IPU2_DI1_PRE_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]); + + if ((imx_silicon_revision() != IMX_CHIP_REV_1_0) || + cpu_is_mx6dl()) { + clk_set_parent(clks[IMX6QDL_CLK_LDB_DI0_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]); + clk_set_parent(clks[IMX6QDL_CLK_LDB_DI1_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]); + } + +} + +static int imx6_ccm_probe(struct device_d *dev) +{ + struct resource *iores; + void __iomem *base, *anatop_base, *ccm_base; + + anatop_base = (void *)MX6_ANATOP_BASE_ADDR; + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + ccm_base = IOMEM(iores->start); + + base = anatop_base; + + /* type name parent_name base div_mask */ + clks[IMX6QDL_CLK_PLL1_SYS] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f); + clks[IMX6QDL_CLK_PLL2_BUS] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc", base + 0x30, 0x1); + clks[IMX6QDL_CLK_PLL3_USB_OTG] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc", base + 0x10, 0x3); + clks[IMX6QDL_CLK_PLL4_AUDIO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4_audio", "osc", base + 0x70, 0x7f); + clks[IMX6QDL_CLK_PLL5_VIDEO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "osc", base + 0xa0, 0x7f); + clks[IMX6QDL_CLK_PLL8_MLB] = imx_clk_pllv3(IMX_PLLV3_MLB, "pll8_mlb", "osc", base + 0xd0, 0x0); + clks[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_usb_host","osc", base + 0x20, 0x3); + clks[IMX6QDL_CLK_PLL6_ENET] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6_enet", "osc", base + 0xe0, 0x3); + + clks[IMX6QDL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 6); + clks[IMX6QDL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 6); + + clks[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5); + clks[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4); + clks[IMX6QDL_CLK_SATA_REF_100M] = imx_clk_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20); + clks[IMX6QDL_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19); + + clks[IMX6QDL_CLK_ENET_REF] = imx_clk_divider_table("enet_ref", "pll6_enet", base + 0xe0, 0, 2, clk_enet_ref_table); + + clks[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); + clks[IMX6QDL_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); + + clks[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12)); + clks[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13)); + + /* name parent_name reg idx */ + clks[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); + clks[IMX6QDL_CLK_PLL2_PFD1_594M] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); + clks[IMX6QDL_CLK_PLL2_PFD2_396M] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2); + clks[IMX6QDL_CLK_PLL3_PFD0_720M] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0); + clks[IMX6QDL_CLK_PLL3_PFD1_540M] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1); + clks[IMX6QDL_CLK_PLL3_PFD2_508M] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2); + clks[IMX6QDL_CLK_PLL3_PFD3_454M] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3); + + /* name parent_name mult div */ + clks[IMX6QDL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2); + clks[IMX6QDL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4); + clks[IMX6QDL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); + clks[IMX6QDL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); + clks[IMX6QDL_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2); + + base = ccm_base; + + /* name reg shift width parent_names num_parents */ + clks[IMX6QDL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); + clks[IMX6QDL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); + clks[IMX6QDL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); + clks[IMX6QDL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); + clks[IMX6QDL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 1, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); + clks[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); + clks[IMX6QDL_CLK_AXI_SEL] = imx_clk_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_sels)); + clks[IMX6QDL_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6QDL_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6QDL_CLK_USDHC3_SEL] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6QDL_CLK_USDHC4_SEL] = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6QDL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 16, 2, enfc_sels, ARRAY_SIZE(enfc_sels)); + clks[IMX6QDL_CLK_EIM_SEL] = imx_clk_mux("eim_sel", base + 0x1c, 27, 2, eim_sels, ARRAY_SIZE(eim_sels)); + clks[IMX6QDL_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_sels, ARRAY_SIZE(eim_sels)); + clks[IMX6QDL_CLK_VDO_AXI_SEL] = imx_clk_mux("vdo_axi_sel", base + 0x18, 11, 1, vdo_axi_sels, ARRAY_SIZE(vdo_axi_sels)); + clks[IMX6QDL_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels)); + clks[IMX6QDL_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels)); + clks[IMX6QDL_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels)); + clks[IMX6QDL_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels)); + + /* name reg shift width busy: reg, shift parent_names num_parents */ + clks[IMX6QDL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); + clks[IMX6QDL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); + + /* name parent_name reg shift width */ + clks[IMX6QDL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); + clks[IMX6QDL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); + clks[IMX6QDL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); + clks[IMX6QDL_CLK_IPG_PER] = imx_clk_divider("ipg_per", "ipg", base + 0x1c, 0, 6); + clks[IMX6QDL_CLK_CAN_ROOT] = imx_clk_divider("can_root", "pll3_usb_otg", base + 0x20, 2, 6); + clks[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6); + clks[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6); + clks[IMX6QDL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); + clks[IMX6QDL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); + clks[IMX6QDL_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3); + clks[IMX6QDL_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3); + clks[IMX6QDL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3); + clks[IMX6QDL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6); + clks[IMX6QDL_CLK_EIM_PODF] = imx_clk_divider("eim_podf", "eim_sel", base + 0x1c, 20, 3); + clks[IMX6QDL_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3); + clks[IMX6QDL_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3); + clks[IMX6QDL_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3); + + /* name parent_name reg shift width busy: reg, shift */ + clks[IMX6QDL_CLK_AXI] = imx_clk_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0); + clks[IMX6QDL_CLK_MMDC_CH0_AXI_PODF] = imx_clk_busy_divider("mmdc_ch0_axi_podf", "periph", base + 0x14, 19, 3, base + 0x48, 4); + clks[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_busy_divider("mmdc_ch1_axi_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2); + clks[IMX6QDL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); + clks[IMX6QDL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); + + /* name parent_name reg shift */ + clks[IMX6QDL_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4); + clks[IMX6QDL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8); + clks[IMX6QDL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10); + clks[IMX6QDL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12); + clks[IMX6QDL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0); + clks[IMX6QDL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2); + clks[IMX6QDL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4); + clks[IMX6QDL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6); + if (cpu_is_mx6dl()) + clks[IMX6DL_CLK_I2C4] = imx_clk_gate2("i2c4", "ipg_per", base + 0x6c, 8); + else + clks[IMX6Q_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8); + clks[IMX6QDL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10); + clks[IMX6QDL_CLK_GPT_IPG] = imx_clk_gate2("gpt_ipg", "ipg", base + 0x6c, 20); + clks[IMX6QDL_CLK_GPT_IPG_PER] = imx_clk_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22); + clks[IMX6QDL_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6); + clks[IMX6QDL_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8); + clks[IMX6QDL_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10); + clks[IMX6QDL_CLK_IIM] = imx_clk_gate2("iim", "ipg", base + 0x70, 12); + clks[IMX6QDL_CLK_ENFC] = imx_clk_gate2("enfc", "enfc_podf", base + 0x70, 14); + clks[IMX6QDL_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0); + clks[IMX6QDL_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12); + clks[IMX6QDL_CLK_PWM1] = imx_clk_gate2("pwm1", "ipg_per", base + 0x78, 16); + clks[IMX6QDL_CLK_PWM2] = imx_clk_gate2("pwm2", "ipg_per", base + 0x78, 18); + clks[IMX6QDL_CLK_PWM3] = imx_clk_gate2("pwm3", "ipg_per", base + 0x78, 20); + clks[IMX6QDL_CLK_PWM4] = imx_clk_gate2("pwm4", "ipg_per", base + 0x78, 22); + clks[IMX6QDL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24); + clks[IMX6QDL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26); + clks[IMX6QDL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc", base + 0x78, 28); + clks[IMX6QDL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30); + clks[IMX6QDL_CLK_SATA] = imx_clk_gate2("sata", "ipg", base + 0x7c, 4); + clks[IMX6QDL_CLK_UART_IPG] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24); + clks[IMX6QDL_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_serial_podf", base + 0x7c, 26); + clks[IMX6QDL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); + clks[IMX6QDL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); + clks[IMX6QDL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); + clks[IMX6QDL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6); + clks[IMX6QDL_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8); + clks[IMX6QDL_CLK_EIM_SLOW] = imx_clk_gate2("eim_slow", "eim_slow_podf", base + 0x80, 10); + clks[IMX6QDL_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7); + clks[IMX6QDL_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24); + + clkdev_add_physbase(clks[IMX6QDL_CLK_IPG], MX6_OCOTP_BASE_ADDR, NULL); + + if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3)) + imx6_add_video_clks(anatop_base, ccm_base); + + writel(0xffffffff, ccm_base + CCGR0); + writel(0xf0ffffff, ccm_base + CCGR1); /* gate GPU3D, GPU2D */ + writel(0xffffffff, ccm_base + CCGR2); + if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3)) + writel(0x3fffffff, ccm_base + CCGR3); /* gate OpenVG */ + else + writel(0x3fff0000, ccm_base + CCGR3); /* gate OpenVG, LDB, IPU1, IPU2 */ + if (IS_ENABLED(CONFIG_PCI_IMX6)) + writel(0xffffffff, ccm_base + CCGR4); + else + writel(0xfffffffc, ccm_base + CCGR4); /* gate PCIe */ + writel(0xffffffff, ccm_base + CCGR5); + writel(0xffff3fff, ccm_base + CCGR6); /* gate VPU */ + writel(0xffffffff, ccm_base + CCGR7); + + clk_data.clks = clks; + clk_data.clk_num = IMX6QDL_CLK_END; + of_clk_add_provider(dev->device_node, of_clk_src_onecell_get, &clk_data); + + clk_enable(clks[IMX6QDL_CLK_MMDC_CH0_AXI_PODF]); + clk_enable(clks[IMX6QDL_CLK_PLL6_ENET]); + clk_enable(clks[IMX6QDL_CLK_SATA_REF_100M]); + clk_enable(clks[IMX6QDL_CLK_ENFC_PODF]); + + clk_set_parent(clks[IMX6QDL_CLK_LVDS1_SEL], clks[IMX6QDL_CLK_SATA_REF_100M]); + + return 0; +} + +static __maybe_unused struct of_device_id imx6_ccm_dt_ids[] = { + { + .compatible = "fsl,imx6q-ccm", + }, { + /* sentinel */ + } +}; + +static struct driver_d imx6_ccm_driver = { + .probe = imx6_ccm_probe, + .name = "imx6-ccm", + .of_compatible = DRV_OF_COMPAT(imx6_ccm_dt_ids), +}; + +static int imx6_ccm_init(void) +{ + return platform_driver_register(&imx6_ccm_driver); +} +core_initcall(imx6_ccm_init); diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c new file mode 100644 index 0000000000..d758957d4d --- /dev/null +++ b/drivers/clk/imx/clk-imx6sx.c @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" +#include "common.h" + +#define CCDR 0x4 +#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16) + +static const char *step_sels[] = { "osc", "pll2_pfd2_396m", }; +static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; +static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", }; +static const char *periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll4_audio_div", }; +static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", }; +static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "osc", }; +static const char *periph_sels[] = { "periph_pre", "periph_clk2", }; +static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", }; +static const char *ocram_sels[] = { "periph", "pll2_pfd2_396m", "periph", "pll3_pfd1_540m", }; +static const char *gpu_axi_sels[] = { "pll2_pfd2_396m", "pll3_pfd0_720m", "pll3_pfd1_540m", "pll2_bus", }; +static const char *gpu_core_sels[] = { "pll3_pfd1_540m", "pll3_pfd0_720m", "pll2_bus", "pll2_pfd2_396m", }; +static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", }; +static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", }; +static const char *ldb_di0_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_pfd3_594m", "pll2_pfd1_594m", "pll3_pfd3_454m", }; +static const char *ldb_di1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", }; +static const char *pcie_axi_sels[] = { "axi", "ahb", }; +static const char *qspi1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", }; +static const char *perclk_sels[] = { "ipg", "osc", }; +static const char *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *vid_sels[] = { "pll3_pfd1_540m", "pll3_usb_otg", "pll3_pfd3_454m", "pll4_audio_div", "pll5_video_div", }; +static const char *uart_sels[] = { "pll3_80m", "osc", }; +static const char *qspi2_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd3_454m", "dummy", "dummy", "dummy", }; +static const char *enet_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", }; +static const char *enet_sels[] = { "enet_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; +static const char *m4_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "osc", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd3_454m", }; +static const char *m4_sels[] = { "m4_pre_sel", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; +static const char *eim_slow_sels[] = { "ocram", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *ecspi_sels[] = { "pll3_60m", "osc", }; +static const char *lcdif1_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_540m", }; +static const char *lcdif1_sels[] = { "lcdif1_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; +static const char *lcdif2_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd3_594m", "pll3_pfd1_540m", }; +static const char *lcdif2_sels[] = { "lcdif2_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; +static const char *display_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll3_usb_otg", "pll3_pfd1_540m", }; +static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", }; +static const char *cko1_sels[] = { + "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div", + "dummy", "ocram", "dummy", "pxp_axi", "epdc_axi", "lcdif_pix", + "epdc_pix", "ahb", "ipg", "perclk", "ckil", "pll4_audio_div", +}; +static const char *cko2_sels[] = { + "dummy", "mmdc_p0_fast", "usdhc4", "usdhc1", "dummy", "wrck", + "ecspi_root", "dummy", "usdhc3", "pcie", "arm", "csi_core", + "lcdif_axi", "dummy", "osc", "dummy", "gpu2d_ovg_core", + "usdhc2", "ssi1", "ssi2", "ssi3", "gpu2d_core", "dummy", + "dummy", "dummy", "dummy", "esai_extal", "eim_slow", "uart_serial", + "spdif", "asrc", "dummy", +}; +static const char *cko_sels[] = { "cko1", "cko2", }; +static const char *lvds_sels[] = { + "arm", "pll1_sys", "dummy", "dummy", "dummy", "dummy", "dummy", "pll5_video_div", + "dummy", "dummy", "pcie_ref_125m", "dummy", "usbphy1", "usbphy2", +}; +static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", }; +static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", }; +static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", }; +static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", }; +static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", }; +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 *clks[IMX6SX_CLK_CLK_END]; +static struct clk_onecell_data clk_data; + +static struct clk_div_table clk_enet_ref_table[] = { + { .val = 0, .div = 20, }, + { .val = 1, .div = 10, }, + { .val = 2, .div = 5, }, + { .val = 3, .div = 4, }, + { } +}; + +static 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[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 2, .div = 1, }, + { .val = 3, .div = 4, }, + { } +}; + +static int imx6sx_ccm_probe(struct device_d *dev) +{ + struct resource *iores; + void __iomem *base, *anatop_base, *ccm_base; + struct device_node *ccm_node = dev->device_node; + + clks[IMX6SX_CLK_DUMMY] = clk_fixed("dummy", 0); + + anatop_base = (void *)MX6_ANATOP_BASE_ADDR; + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + ccm_base = IOMEM(iores->start); + + base = anatop_base; + + clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6SX_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6SX_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6SX_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6SX_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6SX_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + + /* type name parent_name base div_mask */ + clks[IMX6SX_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f); + clks[IMX6SX_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1); + clks[IMX6SX_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3); + clks[IMX6SX_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f); + clks[IMX6SX_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f); + clks[IMX6SX_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3); + clks[IMX6SX_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3); + + clks[IMX6SX_PLL1_BYPASS] = imx_clk_mux_p("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels)); + clks[IMX6SX_PLL2_BYPASS] = imx_clk_mux_p("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels)); + clks[IMX6SX_PLL3_BYPASS] = imx_clk_mux_p("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels)); + clks[IMX6SX_PLL4_BYPASS] = imx_clk_mux_p("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels)); + clks[IMX6SX_PLL5_BYPASS] = imx_clk_mux_p("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels)); + clks[IMX6SX_PLL6_BYPASS] = imx_clk_mux_p("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels)); + clks[IMX6SX_PLL7_BYPASS] = imx_clk_mux_p("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels)); + + /* Do not bypass PLLs initially */ + clk_set_parent(clks[IMX6SX_PLL1_BYPASS], clks[IMX6SX_CLK_PLL1]); + clk_set_parent(clks[IMX6SX_PLL2_BYPASS], clks[IMX6SX_CLK_PLL2]); + clk_set_parent(clks[IMX6SX_PLL3_BYPASS], clks[IMX6SX_CLK_PLL3]); + clk_set_parent(clks[IMX6SX_PLL4_BYPASS], clks[IMX6SX_CLK_PLL4]); + clk_set_parent(clks[IMX6SX_PLL5_BYPASS], clks[IMX6SX_CLK_PLL5]); + clk_set_parent(clks[IMX6SX_PLL6_BYPASS], clks[IMX6SX_CLK_PLL6]); + clk_set_parent(clks[IMX6SX_PLL7_BYPASS], clks[IMX6SX_CLK_PLL7]); + + clks[IMX6SX_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13); + clks[IMX6SX_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13); + clks[IMX6SX_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13); + clks[IMX6SX_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13); + clks[IMX6SX_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13); + clks[IMX6SX_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13); + clks[IMX6SX_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13); + + /* + * Bit 20 is the reserved and read-only bit, we do this only for: + * - Do nothing for usbphy clk_enable/disable + * - Keep refcount when do usbphy clk_enable/disable, in that case, + * the clk framework may need to enable/disable usbphy's parent + */ + clks[IMX6SX_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20); + clks[IMX6SX_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20); + + /* + * usbphy*_gate needs to be on after system boots up, and software + * never needs to control it anymore. + */ + clks[IMX6SX_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6); + clks[IMX6SX_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6); + + /* FIXME 100Mhz is used for pcie ref for all imx6 pcie, excepted imx6q */ + clks[IMX6SX_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 5); + clks[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19); + + clks[IMX6SX_CLK_ENET_REF] = imx_clk_divider_table("enet_ref", "pll6_enet", + base + 0xe0, 0, 2, clk_enet_ref_table); + clks[IMX6SX_CLK_ENET2_REF] = imx_clk_divider_table("enet2_ref", "pll6_enet", + base + 0xe0, 2, 2, clk_enet_ref_table); + clks[IMX6SX_CLK_ENET2_REF_125M] = imx_clk_gate("enet2_ref_125m", "enet2_ref", base + 0xe0, 20); + + clks[IMX6SX_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20); + clks[IMX6SX_CLK_ENET_PTP] = imx_clk_gate("enet_ptp_25m", "enet_ptp_ref", base + 0xe0, 21); + + /* name parent_name reg idx */ + clks[IMX6SX_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); + clks[IMX6SX_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); + clks[IMX6SX_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2); + clks[IMX6SX_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3); + clks[IMX6SX_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0); + clks[IMX6SX_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1); + clks[IMX6SX_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2); + clks[IMX6SX_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3); + + /* name parent_name mult div */ + clks[IMX6SX_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2); + clks[IMX6SX_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4); + clks[IMX6SX_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); + clks[IMX6SX_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); + clks[IMX6SX_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2); + clks[IMX6SX_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8); + + clks[IMX6SX_CLK_PLL4_POST_DIV] = imx_clk_divider_table("pll4_post_div", "pll4_audio", + base + 0x70, 19, 2, post_div_table); + clks[IMX6SX_CLK_PLL4_AUDIO_DIV] = imx_clk_divider("pll4_audio_div", "pll4_post_div", + base + 0x170, 15, 1); + clks[IMX6SX_CLK_PLL5_POST_DIV] = imx_clk_divider_table("pll5_post_div", "pll5_video", + base + 0xa0, 19, 2, post_div_table); + clks[IMX6SX_CLK_PLL5_VIDEO_DIV] = imx_clk_divider_table("pll5_video_div", "pll5_post_div", + base + 0x170, 30, 2, video_div_table); + + /* name reg shift width parent_names num_parents */ + clks[IMX6SX_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); + + base = ccm_base; + + /* name reg shift width parent_names num_parents */ + clks[IMX6SX_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); + clks[IMX6SX_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); + clks[IMX6SX_CLK_OCRAM_SEL] = imx_clk_mux("ocram_sel", base + 0x14, 6, 2, ocram_sels, ARRAY_SIZE(ocram_sels)); + clks[IMX6SX_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); + clks[IMX6SX_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels)); + clks[IMX6SX_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); + clks[IMX6SX_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)); + clks[IMX6SX_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels)); + clks[IMX6SX_CLK_GPU_AXI_SEL] = imx_clk_mux("gpu_axi_sel", base + 0x18, 8, 2, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); + clks[IMX6SX_CLK_GPU_CORE_SEL] = imx_clk_mux("gpu_core_sel", base + 0x18, 4, 2, gpu_core_sels, ARRAY_SIZE(gpu_core_sels)); + clks[IMX6SX_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels)); + clks[IMX6SX_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6SX_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6SX_CLK_USDHC3_SEL] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6SX_CLK_USDHC4_SEL] = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6SX_CLK_QSPI1_SEL] = imx_clk_mux_p("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels)); + clks[IMX6SX_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels)); + clks[IMX6SX_CLK_VID_SEL] = imx_clk_mux("vid_sel", base + 0x20, 21, 3, vid_sels, ARRAY_SIZE(vid_sels)); + clks[IMX6SX_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels)); + clks[IMX6SX_CLK_QSPI2_SEL] = imx_clk_mux_p("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels)); + clks[IMX6SX_CLK_ENET_PRE_SEL] = imx_clk_mux("enet_pre_sel", base + 0x34, 15, 3, enet_pre_sels, ARRAY_SIZE(enet_pre_sels)); + clks[IMX6SX_CLK_ENET_SEL] = imx_clk_mux("enet_sel", base + 0x34, 9, 3, enet_sels, ARRAY_SIZE(enet_sels)); + clks[IMX6SX_CLK_M4_PRE_SEL] = imx_clk_mux("m4_pre_sel", base + 0x34, 6, 3, m4_pre_sels, ARRAY_SIZE(m4_pre_sels)); + clks[IMX6SX_CLK_M4_SEL] = imx_clk_mux("m4_sel", base + 0x34, 0, 3, m4_sels, ARRAY_SIZE(m4_sels)); + clks[IMX6SX_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels)); + clks[IMX6SX_CLK_LCDIF2_PRE_SEL] = imx_clk_mux("lcdif2_pre_sel", base + 0x38, 6, 3, lcdif2_pre_sels, ARRAY_SIZE(lcdif2_pre_sels)); + clks[IMX6SX_CLK_LCDIF2_SEL] = imx_clk_mux("lcdif2_sel", base + 0x38, 0, 3, lcdif2_sels, ARRAY_SIZE(lcdif2_sels)); + clks[IMX6SX_CLK_DISPLAY_SEL] = imx_clk_mux("display_sel", base + 0x3c, 14, 2, display_sels, ARRAY_SIZE(display_sels)); + clks[IMX6SX_CLK_CSI_SEL] = imx_clk_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels)); + clks[IMX6SX_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels)); + clks[IMX6SX_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels)); + clks[IMX6SX_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels)); + + clks[IMX6SX_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux_p("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels)); + clks[IMX6SX_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux_p("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels)); + clks[IMX6SX_CLK_LDB_DI1_SEL] = imx_clk_mux_p("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels)); + clks[IMX6SX_CLK_LDB_DI0_SEL] = imx_clk_mux_p("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels)); + clks[IMX6SX_CLK_LCDIF1_PRE_SEL] = imx_clk_mux_p("lcdif1_pre_sel", base + 0x38, 15, 3, lcdif1_pre_sels, ARRAY_SIZE(lcdif1_pre_sels)); + clks[IMX6SX_CLK_LCDIF1_SEL] = imx_clk_mux_p("lcdif1_sel", base + 0x38, 9, 3, lcdif1_sels, ARRAY_SIZE(lcdif1_sels)); + + /* name parent_name reg shift width */ + clks[IMX6SX_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); + clks[IMX6SX_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); + clks[IMX6SX_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); + clks[IMX6SX_CLK_GPU_CORE_PODF] = imx_clk_divider("gpu_core_podf", "gpu_core_sel", base + 0x18, 29, 3); + clks[IMX6SX_CLK_GPU_AXI_PODF] = imx_clk_divider("gpu_axi_podf", "gpu_axi_sel", base + 0x18, 26, 3); + clks[IMX6SX_CLK_LCDIF1_PODF] = imx_clk_divider("lcdif1_podf", "lcdif1_pred", base + 0x18, 23, 3); + clks[IMX6SX_CLK_QSPI1_PODF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3); + clks[IMX6SX_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3); + clks[IMX6SX_CLK_LCDIF2_PODF] = imx_clk_divider("lcdif2_podf", "lcdif2_pred", base + 0x1c, 20, 3); + clks[IMX6SX_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6); + clks[IMX6SX_CLK_VID_PODF] = imx_clk_divider("vid_podf", "vid_sel", base + 0x20, 24, 2); + clks[IMX6SX_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3); + clks[IMX6SX_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3); + clks[IMX6SX_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); + clks[IMX6SX_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); + clks[IMX6SX_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6); + clks[IMX6SX_CLK_QSPI2_PRED] = imx_clk_divider("qspi2_pred", "qspi2_sel", base + 0x2c, 18, 3); + clks[IMX6SX_CLK_QSPI2_PODF] = imx_clk_divider("qspi2_podf", "qspi2_pred", base + 0x2c, 21, 6); + clks[IMX6SX_CLK_ENET_PODF] = imx_clk_divider("enet_podf", "enet_pre_sel", base + 0x34, 12, 3); + clks[IMX6SX_CLK_M4_PODF] = imx_clk_divider("m4_podf", "m4_sel", base + 0x34, 3, 3); + clks[IMX6SX_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6); + clks[IMX6SX_CLK_LCDIF1_PRED] = imx_clk_divider("lcdif1_pred", "lcdif1_pre_sel", base + 0x38, 12, 3); + clks[IMX6SX_CLK_LCDIF2_PRED] = imx_clk_divider("lcdif2_pred", "lcdif2_pre_sel", base + 0x38, 3, 3); + clks[IMX6SX_CLK_DISPLAY_PODF] = imx_clk_divider("display_podf", "display_sel", base + 0x3c, 16, 3); + clks[IMX6SX_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3); + clks[IMX6SX_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3); + clks[IMX6SX_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3); + + clks[IMX6SX_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); + clks[IMX6SX_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7); + clks[IMX6SX_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); + clks[IMX6SX_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7); + + /* name reg shift width busy: reg, shift parent_names num_parents */ + clks[IMX6SX_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); + clks[IMX6SX_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); + /* name parent_name reg shift width busy: reg, shift */ + clks[IMX6SX_CLK_OCRAM_PODF] = imx_clk_busy_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3, base + 0x48, 0); + clks[IMX6SX_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); + clks[IMX6SX_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2); + clks[IMX6SX_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); + + /* name parent_name reg shift */ + /* CCGR0 */ + clks[IMX6SX_CLK_AIPS_TZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0); + clks[IMX6SX_CLK_AIPS_TZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2); + clks[IMX6SX_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4); + clks[IMX6SX_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8); + clks[IMX6SX_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10); + clks[IMX6SX_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12); + clks[IMX6SX_CLK_DCIC1] = imx_clk_gate2("dcic1", "display_podf", base + 0x68, 24); + clks[IMX6SX_CLK_DCIC2] = imx_clk_gate2("dcic2", "display_podf", base + 0x68, 26); + clks[IMX6SX_CLK_AIPS_TZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30); + + /* CCGR1 */ + clks[IMX6SX_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); + clks[IMX6SX_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2); + clks[IMX6SX_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4); + clks[IMX6SX_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6); + clks[IMX6SX_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_podf", base + 0x6c, 8); + clks[IMX6SX_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12); + clks[IMX6SX_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14); + clks[IMX6SX_CLK_WAKEUP] = imx_clk_gate2("wakeup", "ipg", base + 0x6c, 18); + clks[IMX6SX_CLK_GPT_BUS] = imx_clk_gate2("gpt_bus", "perclk", base + 0x6c, 20); + clks[IMX6SX_CLK_GPT_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x6c, 22); + clks[IMX6SX_CLK_GPU] = imx_clk_gate2("gpu", "gpu_core_podf", base + 0x6c, 26); + + /* CCGR2 */ + clks[IMX6SX_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2); + clks[IMX6SX_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6); + clks[IMX6SX_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8); + clks[IMX6SX_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); + clks[IMX6SX_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); + clks[IMX6SX_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif1_podf", base + 0x70, 14); + clks[IMX6SX_CLK_IPMUX1] = imx_clk_gate2("ipmux1", "ahb", base + 0x70, 16); + clks[IMX6SX_CLK_IPMUX2] = imx_clk_gate2("ipmux2", "ahb", base + 0x70, 18); + clks[IMX6SX_CLK_IPMUX3] = imx_clk_gate2("ipmux3", "ahb", base + 0x70, 20); + clks[IMX6SX_CLK_TZASC1] = imx_clk_gate2("tzasc1", "mmdc_podf", base + 0x70, 22); + clks[IMX6SX_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "display_podf", base + 0x70, 28); + clks[IMX6SX_CLK_PXP_AXI] = imx_clk_gate2("pxp_axi", "display_podf", base + 0x70, 30); + + /* CCGR3 */ + clks[IMX6SX_CLK_M4] = imx_clk_gate2("m4", "m4_podf", base + 0x74, 2); + clks[IMX6SX_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4); + clks[IMX6SX_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "enet_sel", base + 0x74, 4); + clks[IMX6SX_CLK_DISPLAY_AXI] = imx_clk_gate2("display_axi", "display_podf", base + 0x74, 6); + clks[IMX6SX_CLK_LCDIF2_PIX] = imx_clk_gate2("lcdif2_pix", "lcdif2_sel", base + 0x74, 8); + clks[IMX6SX_CLK_LCDIF1_PIX] = imx_clk_gate2("lcdif1_pix", "lcdif1_sel", base + 0x74, 10); + clks[IMX6SX_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_div_sel", base + 0x74, 12); + clks[IMX6SX_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14); + clks[IMX6SX_CLK_MLB] = imx_clk_gate2("mlb", "ahb", base + 0x74, 18); + clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20); + clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24); + clks[IMX6SX_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28); + + /* CCGR4 */ + clks[IMX6SX_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "display_podf", base + 0x78, 0); + clks[IMX6SX_CLK_QSPI2] = imx_clk_gate2("qspi2", "qspi2_podf", base + 0x78, 10); + clks[IMX6SX_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12); + clks[IMX6SX_CLK_PER2_MAIN] = imx_clk_gate2("per2_main", "ahb", base + 0x78, 14); + clks[IMX6SX_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16); + clks[IMX6SX_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18); + clks[IMX6SX_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20); + clks[IMX6SX_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22); + clks[IMX6SX_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24); + clks[IMX6SX_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26); + clks[IMX6SX_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "qspi2_podf", base + 0x78, 28); + clks[IMX6SX_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30); + + /* CCGR5 */ + clks[IMX6SX_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); + clks[IMX6SX_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); + clks[IMX6SX_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); + clks[IMX6SX_CLK_UART_IPG] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24); + clks[IMX6SX_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_podf", base + 0x7c, 26); + clks[IMX6SX_CLK_SAI1_IPG] = imx_clk_gate2("sai1_ipg", "ipg", base + 0x7c, 28); + clks[IMX6SX_CLK_SAI2_IPG] = imx_clk_gate2("sai2_ipg", "ipg", base + 0x7c, 30); + + /* CCGR6 */ + clks[IMX6SX_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); + clks[IMX6SX_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); + clks[IMX6SX_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); + clks[IMX6SX_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6); + clks[IMX6SX_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8); + clks[IMX6SX_CLK_EIM_SLOW] = imx_clk_gate2("eim_slow", "eim_slow_podf", base + 0x80, 10); + clks[IMX6SX_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16); + clks[IMX6SX_CLK_VADC] = imx_clk_gate2("vadc", "vid_podf", base + 0x80, 20); + clks[IMX6SX_CLK_GIS] = imx_clk_gate2("gis", "display_podf", base + 0x80, 22); + clks[IMX6SX_CLK_I2C4] = imx_clk_gate2("i2c4", "perclk", base + 0x80, 24); + clks[IMX6SX_CLK_PWM5] = imx_clk_gate2("pwm5", "perclk", base + 0x80, 26); + clks[IMX6SX_CLK_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28); + clks[IMX6SX_CLK_PWM7] = imx_clk_gate2("pwm7", "perclk", base + 0x80, 30); + + clks[IMX6SX_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7); + clks[IMX6SX_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24); + + /* mask handshake of mmdc */ + writel(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR); + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(ccm_node, of_clk_src_onecell_get, &clk_data); + + if (IS_ENABLED(CONFIG_USB_IMX_PHY)) { + clk_enable(clks[IMX6SX_CLK_USBPHY1_GATE]); + clk_enable(clks[IMX6SX_CLK_USBPHY2_GATE]); + } + + return 0; +}; + +static int imx6sx_clocks_init(void) +{ + if (!of_machine_is_compatible("fsl,imx6sx")) + return 0; + + /* Set the default 132MHz for EIM module */ + clk_set_parent(clks[IMX6SX_CLK_EIM_SLOW_SEL], clks[IMX6SX_CLK_PLL2_PFD2]); + clk_set_rate(clks[IMX6SX_CLK_EIM_SLOW], 132000000); + + /* set parent clock for LCDIF1 pixel clock */ + clk_set_parent(clks[IMX6SX_CLK_LCDIF1_PRE_SEL], clks[IMX6SX_CLK_PLL5_VIDEO_DIV]); + clk_set_parent(clks[IMX6SX_CLK_LCDIF1_SEL], clks[IMX6SX_CLK_LCDIF1_PODF]); + + /* + * Init enet system AHB clock, set to 200Mhz + * pll2_pfd2_396m-> ENET_PODF-> ENET_AHB + */ + clk_set_parent(clks[IMX6SX_CLK_ENET_PRE_SEL], clks[IMX6SX_CLK_PLL2_PFD2]); + clk_set_parent(clks[IMX6SX_CLK_ENET_SEL], clks[IMX6SX_CLK_ENET_PODF]); + clk_set_rate(clks[IMX6SX_CLK_ENET_PODF], 200000000); + clk_set_rate(clks[IMX6SX_CLK_ENET_REF], 125000000); + clk_set_rate(clks[IMX6SX_CLK_ENET2_REF], 125000000); + + /* Set parent clock for vadc */ + clk_set_parent(clks[IMX6SX_CLK_VID_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]); + + /* Update gpu clock from default 528M to 720M */ + clk_set_parent(clks[IMX6SX_CLK_GPU_CORE_SEL], clks[IMX6SX_CLK_PLL3_PFD0]); + clk_set_parent(clks[IMX6SX_CLK_GPU_AXI_SEL], clks[IMX6SX_CLK_PLL3_PFD0]); + + return 0; +} +coredevice_initcall(imx6sx_clocks_init); + +static __maybe_unused struct of_device_id imx6sx_ccm_dt_ids[] = { + { + .compatible = "fsl,imx6sx-ccm", + }, { + /* sentinel */ + } +}; + +static struct driver_d imx6sx_ccm_driver = { + .probe = imx6sx_ccm_probe, + .name = "imx6-ccm", + .of_compatible = DRV_OF_COMPAT(imx6sx_ccm_dt_ids), +}; + +static int imx6sx_ccm_init(void) +{ + return platform_driver_register(&imx6sx_ccm_driver); +} +core_initcall(imx6sx_ccm_init); diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c new file mode 100644 index 0000000000..8f6d5ad7a8 --- /dev/null +++ b/drivers/clk/imx/clk-pfd.c @@ -0,0 +1,148 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +/** + * struct clk_pfd - IMX PFD clock + * @clk_hw: clock source + * @reg: PFD register address + * @idx: the index of PFD encoded in the register + * + * PFD clock found on i.MX6 series. Each register for PFD has 4 clk_pfd + * data encoded, and member idx is used to specify the one. And each + * register has SET, CLR and TOG registers at offset 0x4 0x8 and 0xc. + */ +struct clk_pfd { + struct clk clk; + void __iomem *reg; + u8 idx; + const char *parent; +}; + +#define to_clk_pfd(_clk) container_of(_clk, struct clk_pfd, clk) + +#define SET 0x4 +#define CLR 0x8 +#define OTG 0xc + +static int clk_pfd_enable(struct clk *clk) +{ + struct clk_pfd *pfd = to_clk_pfd(clk); + writel(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR); + + return 0; +} + +static void clk_pfd_disable(struct clk *clk) +{ + struct clk_pfd *pfd = to_clk_pfd(clk); + + writel(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET); +} + +static unsigned long clk_pfd_recalc_rate(struct clk *clk, + unsigned long parent_rate) +{ + struct clk_pfd *pfd = to_clk_pfd(clk); + u64 tmp = parent_rate; + u8 frac = (readl(pfd->reg) >> (pfd->idx * 8)) & 0x3f; + + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static long clk_pfd_round_rate(struct clk *clk, unsigned long rate, + unsigned long *prate) +{ + u64 tmp = *prate; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + tmp = *prate; + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static int clk_pfd_set_rate(struct clk *clk, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pfd *pfd = to_clk_pfd(clk); + u64 tmp = parent_rate; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + writel(0x3f << (pfd->idx * 8), pfd->reg + CLR); + writel(frac << (pfd->idx * 8), pfd->reg + SET); + + return 0; +} + +static const struct clk_ops clk_pfd_ops = { + .enable = clk_pfd_enable, + .disable = clk_pfd_disable, + .recalc_rate = clk_pfd_recalc_rate, + .round_rate = clk_pfd_round_rate, + .set_rate = clk_pfd_set_rate, +}; + +struct clk *imx_clk_pfd(const char *name, const char *parent, + void __iomem *reg, u8 idx) +{ + struct clk_pfd *pfd; + int ret; + + pfd = xzalloc(sizeof(*pfd)); + + pfd->reg = reg; + pfd->idx = idx; + pfd->parent = parent; + pfd->clk.name = name; + pfd->clk.ops = &clk_pfd_ops; + pfd->clk.parent_names = &pfd->parent; + pfd->clk.num_parents = 1; + + ret = clk_register(&pfd->clk); + if (ret) { + free(pfd); + return ERR_PTR(ret); + } + + return &pfd->clk; +} diff --git a/drivers/clk/imx/clk-pllv1.c b/drivers/clk/imx/clk-pllv1.c new file mode 100644 index 0000000000..f992134f7e --- /dev/null +++ b/drivers/clk/imx/clk-pllv1.c @@ -0,0 +1,95 @@ +/* + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +struct clk_pllv1 { + struct clk clk; + void __iomem *reg; + const char *parent; +}; + +static unsigned long clk_pllv1_recalc_rate(struct clk *clk, + unsigned long parent_rate) +{ + struct clk_pllv1 *pll = container_of(clk, struct clk_pllv1, clk); + unsigned long long ll; + int mfn_abs; + unsigned int mfi, mfn, mfd, pd; + u32 reg_val = readl(pll->reg); + unsigned long freq = parent_rate; + + mfi = (reg_val >> 10) & 0xf; + mfn = reg_val & 0x3ff; + mfd = (reg_val >> 16) & 0x3ff; + pd = (reg_val >> 26) & 0xf; + + mfi = mfi <= 5 ? 5 : mfi; + + mfn_abs = mfn; + +#if !defined CONFIG_ARCH_MX1 && !defined CONFIG_ARCH_MX21 + if (mfn >= 0x200) { + mfn |= 0xFFFFFE00; + mfn_abs = -mfn; + } +#endif + + freq *= 2; + freq /= pd + 1; + + ll = (unsigned long long)freq * mfn_abs; + + do_div(ll, mfd + 1); + if (mfn < 0) + ll = (freq * mfi) - ll; + else + ll = (freq * mfi) + ll; + + return ll; +} + +struct clk_ops clk_pllv1_ops = { + .recalc_rate = clk_pllv1_recalc_rate, +}; + +struct clk *imx_clk_pllv1(const char *name, const char *parent, + void __iomem *base) +{ + struct clk_pllv1 *pll = xzalloc(sizeof(*pll)); + int ret; + + pll->parent = parent; + pll->reg = base; + pll->clk.ops = &clk_pllv1_ops; + pll->clk.name = name; + pll->clk.parent_names = &pll->parent; + pll->clk.num_parents = 1; + + ret = clk_register(&pll->clk); + if (ret) { + free(pll); + return ERR_PTR(ret); + } + + return &pll->clk; +} diff --git a/drivers/clk/imx/clk-pllv2.c b/drivers/clk/imx/clk-pllv2.c new file mode 100644 index 0000000000..5ba07fa5e6 --- /dev/null +++ b/drivers/clk/imx/clk-pllv2.c @@ -0,0 +1,230 @@ +/* + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +/* PLL Register Offsets */ +#define MXC_PLL_DP_CTL 0x00 +#define MXC_PLL_DP_CONFIG 0x04 +#define MXC_PLL_DP_OP 0x08 +#define MXC_PLL_DP_MFD 0x0C +#define MXC_PLL_DP_MFN 0x10 +#define MXC_PLL_DP_MFNMINUS 0x14 +#define MXC_PLL_DP_MFNPLUS 0x18 +#define MXC_PLL_DP_HFS_OP 0x1C +#define MXC_PLL_DP_HFS_MFD 0x20 +#define MXC_PLL_DP_HFS_MFN 0x24 +#define MXC_PLL_DP_MFN_TOGC 0x28 +#define MXC_PLL_DP_DESTAT 0x2c + +/* PLL Register Bit definitions */ +#define MXC_PLL_DP_CTL_MUL_CTRL 0x2000 +#define MXC_PLL_DP_CTL_DPDCK0_2_EN 0x1000 +#define MXC_PLL_DP_CTL_DPDCK0_2_OFFSET 12 +#define MXC_PLL_DP_CTL_ADE 0x800 +#define MXC_PLL_DP_CTL_REF_CLK_DIV 0x400 +#define MXC_PLL_DP_CTL_REF_CLK_SEL_MASK (3 << 8) +#define MXC_PLL_DP_CTL_REF_CLK_SEL_OFFSET 8 +#define MXC_PLL_DP_CTL_HFSM 0x80 +#define MXC_PLL_DP_CTL_PRE 0x40 +#define MXC_PLL_DP_CTL_UPEN 0x20 +#define MXC_PLL_DP_CTL_RST 0x10 +#define MXC_PLL_DP_CTL_RCP 0x8 +#define MXC_PLL_DP_CTL_PLM 0x4 +#define MXC_PLL_DP_CTL_BRM0 0x2 +#define MXC_PLL_DP_CTL_LRF 0x1 + +#define MXC_PLL_DP_CONFIG_BIST 0x8 +#define MXC_PLL_DP_CONFIG_SJC_CE 0x4 +#define MXC_PLL_DP_CONFIG_AREN 0x2 +#define MXC_PLL_DP_CONFIG_LDREQ 0x1 + +#define MXC_PLL_DP_OP_MFI_OFFSET 4 +#define MXC_PLL_DP_OP_MFI_MASK (0xF << 4) +#define MXC_PLL_DP_OP_PDF_OFFSET 0 +#define MXC_PLL_DP_OP_PDF_MASK 0xF + +#define MXC_PLL_DP_MFD_OFFSET 0 +#define MXC_PLL_DP_MFD_MASK 0x07FFFFFF + +#define MXC_PLL_DP_MFN_OFFSET 0x0 +#define MXC_PLL_DP_MFN_MASK 0x07FFFFFF + +#define MXC_PLL_DP_MFN_TOGC_TOG_DIS (1 << 17) +#define MXC_PLL_DP_MFN_TOGC_TOG_EN (1 << 16) +#define MXC_PLL_DP_MFN_TOGC_CNT_OFFSET 0x0 +#define MXC_PLL_DP_MFN_TOGC_CNT_MASK 0xFFFF + +#define MXC_PLL_DP_DESTAT_TOG_SEL (1 << 31) +#define MXC_PLL_DP_DESTAT_MFN 0x07FFFFFF + +#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */ + +struct clk_pllv2 { + struct clk clk; + void __iomem *reg; + const char *parent; +}; + +static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate, + u32 dp_ctl, u32 dp_op, u32 dp_mfd, u32 dp_mfn) +{ + long mfi, mfn, mfd, pdf, ref_clk, mfn_abs; + unsigned long dbl; + uint64_t temp; + + dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN; + + pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK; + mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET; + mfi = (mfi <= 5) ? 5 : mfi; + mfd = dp_mfd & MXC_PLL_DP_MFD_MASK; + mfn = mfn_abs = dp_mfn & MXC_PLL_DP_MFN_MASK; + /* Sign extend to 32-bits */ + if (mfn >= 0x04000000) { + mfn |= 0xFC000000; + mfn_abs = -mfn; + } + + ref_clk = 2 * parent_rate; + if (dbl != 0) + ref_clk *= 2; + + ref_clk /= (pdf + 1); + temp = (u64) ref_clk * mfn_abs; + do_div(temp, mfd + 1); + if (mfn < 0) + temp = (ref_clk * mfi) - temp; + else + temp = (ref_clk * mfi) + temp; + + return temp; +} + +static unsigned long clk_pllv2_recalc_rate(struct clk *clk, + unsigned long parent_rate) +{ + u32 dp_op, dp_mfd, dp_mfn, dp_ctl; + void __iomem *pllbase; + struct clk_pllv2 *pll = container_of(clk, struct clk_pllv2, clk); + + pllbase = pll->reg; + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP); + dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD); + dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN); + + return __clk_pllv2_recalc_rate(parent_rate, dp_ctl, dp_op, dp_mfd, dp_mfn); +} + +static int __clk_pllv2_set_rate(unsigned long rate, unsigned long parent_rate, + u32 *dp_op, u32 *dp_mfd, u32 *dp_mfn) +{ + u32 reg; + long mfi, pdf, mfn, mfd = 999999; + u64 temp64; + unsigned long quad_parent_rate; + + quad_parent_rate = 4 * parent_rate; + pdf = mfi = -1; + while (++pdf < 16 && mfi < 5) + mfi = rate * (pdf+1) / quad_parent_rate; + if (mfi > 15) + return -EINVAL; + pdf--; + + temp64 = rate * (pdf + 1) - quad_parent_rate * mfi; + do_div(temp64, quad_parent_rate / 1000000); + mfn = (long)temp64; + + reg = mfi << 4 | pdf; + + *dp_op = reg; + *dp_mfd = mfd; + *dp_mfn = mfn; + + return 0; +} + +static int clk_pllv2_set_rate(struct clk *clk, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv2 *pll = container_of(clk, struct clk_pllv2, clk); + void __iomem *pllbase; + u32 dp_ctl, dp_op, dp_mfd, dp_mfn; + int ret; + + pllbase = pll->reg; + + ret = __clk_pllv2_set_rate(rate, parent_rate, &dp_op, &dp_mfd, &dp_mfn); + if (ret) + return ret; + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + /* use dpdck0_2 */ + __raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL); + + __raw_writel(dp_op, pllbase + MXC_PLL_DP_OP); + __raw_writel(dp_mfd, pllbase + MXC_PLL_DP_MFD); + __raw_writel(dp_mfn, pllbase + MXC_PLL_DP_MFN); + + return 0; +} + +static long clk_pllv2_round_rate(struct clk *clk, unsigned long rate, + unsigned long *prate) +{ + u32 dp_op, dp_mfd, dp_mfn; + + __clk_pllv2_set_rate(rate, *prate, &dp_op, &dp_mfd, &dp_mfn); + return __clk_pllv2_recalc_rate(*prate, MXC_PLL_DP_CTL_DPDCK0_2_EN, + dp_op, dp_mfd, dp_mfn); +} + +struct clk_ops clk_pllv2_ops = { + .recalc_rate = clk_pllv2_recalc_rate, + .round_rate = clk_pllv2_round_rate, + .set_rate = clk_pllv2_set_rate, +}; + +struct clk *imx_clk_pllv2(const char *name, const char *parent, + void __iomem *base) +{ + struct clk_pllv2 *pll = xzalloc(sizeof(*pll)); + int ret; + + pll->parent = parent; + pll->reg = base; + pll->clk.ops = &clk_pllv2_ops; + pll->clk.name = name; + pll->clk.parent_names = &pll->parent; + pll->clk.num_parents = 1; + + ret = clk_register(&pll->clk); + if (ret) { + free(pll); + return ERR_PTR(ret); + } + + return &pll->clk; +} diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c new file mode 100644 index 0000000000..e38dcdfdaa --- /dev/null +++ b/drivers/clk/imx/clk-pllv3.c @@ -0,0 +1,326 @@ +/* + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define PLL_NUM_OFFSET 0x10 +#define PLL_DENOM_OFFSET 0x20 + +#define BM_PLL_POWER (0x1 << 12) +#define BM_PLL_ENABLE (0x1 << 13) +#define BM_PLL_BYPASS (0x1 << 16) +#define BM_PLL_LOCK (0x1 << 31) + +struct clk_pllv3 { + struct clk clk; + void __iomem *base; + bool powerup_set; + u32 div_mask; + const char *parent; +}; + +#define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk) + +static int clk_pllv3_enable(struct clk *clk) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + u32 val; + int timeout = 10000; + + val = readl(pll->base); + val &= ~BM_PLL_BYPASS; + if (pll->powerup_set) + val |= BM_PLL_POWER; + else + val &= ~BM_PLL_POWER; + writel(val, pll->base); + + /* Wait for PLL to lock */ + while (timeout--) { + if (readl(pll->base) & BM_PLL_LOCK) + break; + } + + if (!timeout) + return -ETIMEDOUT; + + val = readl(pll->base); + val |= BM_PLL_ENABLE; + writel(val, pll->base); + + return 0; +} + +static void clk_pllv3_disable(struct clk *clk) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + u32 val; + + val = readl(pll->base); + val &= ~BM_PLL_ENABLE; + writel(val, pll->base); + + val |= BM_PLL_BYPASS; + if (pll->powerup_set) + val &= ~BM_PLL_POWER; + else + val |= BM_PLL_POWER; + writel(val, pll->base); +} + +static unsigned long clk_pllv3_recalc_rate(struct clk *clk, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + u32 div = readl(pll->base) & pll->div_mask; + + return (div == 1) ? parent_rate * 22 : parent_rate * 20; +} + +static long clk_pllv3_round_rate(struct clk *clk, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + + return (rate >= parent_rate * 22) ? parent_rate * 22 : + parent_rate * 20; +} + +static int clk_pllv3_set_rate(struct clk *clk, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + u32 val, div; + + if (rate == parent_rate * 22) + div = 1; + else if (rate == parent_rate * 20) + div = 0; + else + return -EINVAL; + + val = readl(pll->base); + val &= ~pll->div_mask; + val |= div; + writel(val, pll->base); + + return 0; +} + +static const struct clk_ops clk_pllv3_ops = { + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + .recalc_rate = clk_pllv3_recalc_rate, + .round_rate = clk_pllv3_round_rate, + .set_rate = clk_pllv3_set_rate, +}; + +static unsigned long clk_pllv3_sys_recalc_rate(struct clk *clk, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + u32 div = readl(pll->base) & pll->div_mask; + + return parent_rate * div / 2; +} + +static long clk_pllv3_sys_round_rate(struct clk *clk, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + unsigned long min_rate = parent_rate * 54 / 2; + unsigned long max_rate = parent_rate * 108 / 2; + u32 div; + + if (rate > max_rate) + rate = max_rate; + else if (rate < min_rate) + rate = min_rate; + div = rate * 2 / parent_rate; + + return parent_rate * div / 2; +} + +static int clk_pllv3_sys_set_rate(struct clk *clk, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + unsigned long min_rate = parent_rate * 54 / 2; + unsigned long max_rate = parent_rate * 108 / 2; + u32 val, div; + + if (rate < min_rate || rate > max_rate) + return -EINVAL; + + div = rate * 2 / parent_rate; + val = readl(pll->base); + val &= ~pll->div_mask; + val |= div; + writel(val, pll->base); + + return 0; +} + +static const struct clk_ops clk_pllv3_sys_ops = { + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + .recalc_rate = clk_pllv3_sys_recalc_rate, + .round_rate = clk_pllv3_sys_round_rate, + .set_rate = clk_pllv3_sys_set_rate, +}; + +static unsigned long clk_pllv3_av_recalc_rate(struct clk *clk, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + u32 mfn = readl(pll->base + PLL_NUM_OFFSET); + u32 mfd = readl(pll->base + PLL_DENOM_OFFSET); + u32 div = readl(pll->base) & pll->div_mask; + + return (parent_rate * div) + ((parent_rate / mfd) * mfn); +} + +static long clk_pllv3_av_round_rate(struct clk *clk, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + unsigned long min_rate = parent_rate * 27; + unsigned long max_rate = parent_rate * 54; + u32 div; + u32 mfn, mfd = 1000000; + u64 temp64; + + if (rate > max_rate) + rate = max_rate; + else if (rate < min_rate) + rate = min_rate; + + div = rate / parent_rate; + temp64 = (u64) (rate - div * parent_rate); + temp64 *= mfd; + do_div(temp64, parent_rate); + mfn = temp64; + + return parent_rate * div + parent_rate / mfd * mfn; +} + +static int clk_pllv3_av_set_rate(struct clk *clk, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + unsigned long min_rate = parent_rate * 27; + unsigned long max_rate = parent_rate * 54; + u32 val, div; + u32 mfn, mfd = 1000000; + u64 temp64; + + if (rate < min_rate || rate > max_rate) + return -EINVAL; + + div = rate / parent_rate; + temp64 = (u64) (rate - div * parent_rate); + temp64 *= mfd; + do_div(temp64, parent_rate); + mfn = temp64; + + val = readl(pll->base); + val &= ~pll->div_mask; + val |= div; + writel(val, pll->base); + writel(mfn, pll->base + PLL_NUM_OFFSET); + writel(mfd, pll->base + PLL_DENOM_OFFSET); + + return 0; +} + +static const struct clk_ops clk_pllv3_av_ops = { + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + .recalc_rate = clk_pllv3_av_recalc_rate, + .round_rate = clk_pllv3_av_round_rate, + .set_rate = clk_pllv3_av_set_rate, +}; + +static unsigned long clk_pllv3_enet_recalc_rate(struct clk *clk, + unsigned long parent_rate) +{ + return 500000000; +} + +static const struct clk_ops clk_pllv3_enet_ops = { + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + .recalc_rate = clk_pllv3_enet_recalc_rate, +}; + +static const struct clk_ops clk_pllv3_mlb_ops = { + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, +}; + +struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, + const char *parent, void __iomem *base, + u32 div_mask) +{ + struct clk_pllv3 *pll; + const struct clk_ops *ops; + int ret; + + pll = xzalloc(sizeof(*pll)); + + switch (type) { + case IMX_PLLV3_SYS: + ops = &clk_pllv3_sys_ops; + break; + case IMX_PLLV3_USB: + ops = &clk_pllv3_ops; + pll->powerup_set = true; + break; + case IMX_PLLV3_AV: + ops = &clk_pllv3_av_ops; + break; + case IMX_PLLV3_ENET: + ops = &clk_pllv3_enet_ops; + break; + case IMX_PLLV3_MLB: + ops = &clk_pllv3_mlb_ops; + break; + default: + ops = &clk_pllv3_ops; + } + pll->base = base; + pll->div_mask = div_mask; + pll->parent = parent; + pll->clk.ops = ops; + pll->clk.name = name; + pll->clk.parent_names = &pll->parent; + pll->clk.num_parents = 1; + + ret = clk_register(&pll->clk); + if (ret) { + free(pll); + return ERR_PTR(ret); + } + + return &pll->clk; +} diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h new file mode 100644 index 0000000000..c5913e1879 --- /dev/null +++ b/drivers/clk/imx/clk.h @@ -0,0 +1,104 @@ +#ifndef __IMX_CLK_H +#define __IMX_CLK_H + +struct clk *clk_gate2(const char *name, const char *parent, void __iomem *reg, + u8 shift); + +static inline struct clk *imx_clk_divider(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width) +{ + return clk_divider(name, parent, reg, shift, width, CLK_SET_RATE_PARENT); +} + +static inline struct clk *imx_clk_divider_np(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width) +{ + return clk_divider(name, parent, reg, shift, width, 0); +} + +static inline struct clk *imx_clk_divider_table(const char *name, + const char *parent, void __iomem *reg, u8 shift, u8 width, + const struct clk_div_table *table) +{ + return clk_divider_table(name, parent, reg, shift, width, table, + CLK_SET_RATE_PARENT); +} + +static inline struct clk *imx_clk_fixed_factor(const char *name, + const char *parent, unsigned int mult, unsigned int div) +{ + return clk_fixed_factor(name, parent, mult, div, CLK_SET_RATE_PARENT); +} + +static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, + u8 shift, u8 width, const char **parents, u8 num_parents) +{ + return clk_mux(name, reg, shift, width, parents, num_parents, 0); +} + +static inline struct clk *imx_clk_mux_p(const char *name, void __iomem *reg, + u8 shift, u8 width, const char **parents, u8 num_parents) +{ + return clk_mux(name, reg, shift, width, parents, num_parents, CLK_SET_RATE_PARENT); +} + +static inline struct clk *imx_clk_gate(const char *name, const char *parent, + void __iomem *reg, u8 shift) +{ + return clk_gate(name, parent, reg, shift, CLK_SET_RATE_PARENT, 0); +} + +static inline struct clk *imx_clk_gate2(const char *name, const char *parent, + void __iomem *reg, u8 shift) +{ + return clk_gate2(name, parent, reg, shift); +} + +struct clk *imx_clk_pllv1(const char *name, const char *parent, + void __iomem *base); + +struct clk *imx_clk_pllv2(const char *name, const char *parent, + void __iomem *base); + +enum imx_pllv3_type { + IMX_PLLV3_GENERIC, + IMX_PLLV3_SYS, + IMX_PLLV3_USB, + IMX_PLLV3_AV, + IMX_PLLV3_ENET, + IMX_PLLV3_MLB, +}; + +struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, + const char *parent, void __iomem *base, + u32 div_mask); + +struct clk *imx_clk_pfd(const char *name, const char *parent, + void __iomem *reg, u8 idx); + +static inline struct clk *imx_clk_busy_divider(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width, + void __iomem *busy_reg, u8 busy_shift) +{ + /* + * For now we do not support rate setting, so just fall back to + * regular divider. + */ + return imx_clk_divider(name, parent, reg, shift, width); +} + +static inline struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, + u8 width, void __iomem *busy_reg, u8 busy_shift, + const char **parents, int num_parents) +{ + /* + * For now we do not support mux switching, so just fall back to + * regular mux. + */ + return imx_clk_mux(name, reg, shift, width, parents, num_parents); +} + +struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, + void __iomem *reg, u8 shift, u32 exclusive_mask); + +#endif /* __IMX_CLK_H */ -- cgit v1.2.3 From 3ae4754b51da47d612a72a843ac1131b755a5a0e Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:13:59 -0800 Subject: i.MX: clk: Port imx_clk_gate2_cgr() Update clk-gate2 code to be able to accept arbitrary 'cgr' value and introduce imx_clk_gate2_cgr() (Used by Vybrid clock tree) Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/clk/imx/clk-gate2.c | 12 +++++++----- drivers/clk/imx/clk.h | 11 +++++++++-- 2 files changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index faed6313fb..f952f3e3f6 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -26,6 +26,7 @@ struct clk_gate2 { struct clk clk; void __iomem *reg; int shift; + u8 cgr_val; const char *parent; #define CLK_GATE_INVERTED (1 << 0) unsigned flags; @@ -43,7 +44,7 @@ static int clk_gate2_enable(struct clk *clk) if (g->flags & CLK_GATE_INVERTED) val &= ~(3 << g->shift); else - val |= 3 << g->shift; + val |= g->cgr_val << g->shift; writel(val, g->reg); @@ -87,12 +88,13 @@ static struct clk_ops clk_gate2_ops = { }; struct clk *clk_gate2_alloc(const char *name, const char *parent, - void __iomem *reg, u8 shift) + void __iomem *reg, u8 shift, u8 cgr_val) { struct clk_gate2 *g = xzalloc(sizeof(*g)); g->parent = parent; g->reg = reg; + g->cgr_val = cgr_val; g->shift = shift; g->clk.ops = &clk_gate2_ops; g->clk.name = name; @@ -111,12 +113,12 @@ void clk_gate2_free(struct clk *clk) } struct clk *clk_gate2(const char *name, const char *parent, void __iomem *reg, - u8 shift) + u8 shift, u8 cgr_val) { struct clk *g; int ret; - g = clk_gate2_alloc(name , parent, reg, shift); + g = clk_gate2_alloc(name , parent, reg, shift, cgr_val); ret = clk_register(g); if (ret) { @@ -133,7 +135,7 @@ struct clk *clk_gate2_inverted(const char *name, const char *parent, struct clk *clk; struct clk_gate2 *g; - clk = clk_gate2(name, parent, reg, shift); + clk = clk_gate2(name, parent, reg, shift, 0x3); if (IS_ERR(clk)) return clk; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index c5913e1879..2aeb35631d 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -2,7 +2,7 @@ #define __IMX_CLK_H struct clk *clk_gate2(const char *name, const char *parent, void __iomem *reg, - u8 shift); + u8 shift, u8 cgr_val); static inline struct clk *imx_clk_divider(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width) @@ -51,9 +51,16 @@ static inline struct clk *imx_clk_gate(const char *name, const char *parent, static inline struct clk *imx_clk_gate2(const char *name, const char *parent, void __iomem *reg, u8 shift) { - return clk_gate2(name, parent, reg, shift); + return clk_gate2(name, parent, reg, shift, 0x3); } +static inline struct clk *imx_clk_gate2_cgr(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 cgr_val) +{ + return clk_gate2(name, parent, reg, shift, cgr_val); +} + + struct clk *imx_clk_pllv1(const char *name, const char *parent, void __iomem *base); -- cgit v1.2.3 From 385bfcc86f3b531e3713ccb75a2f8ef25750f186 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:14:00 -0800 Subject: i.MX: clk: Add IMX_PLLV3_USB_VF610 support Add IMX_PLLV3_USB_VF610 PLLv3 types support clk-pllv3.c Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/clk/imx/clk-pllv3.c | 9 ++++++--- drivers/clk/imx/clk.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index e38dcdfdaa..29c0f1c700 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -36,6 +36,7 @@ struct clk_pllv3 { void __iomem *base; bool powerup_set; u32 div_mask; + u32 div_shift; const char *parent; }; @@ -92,7 +93,7 @@ static unsigned long clk_pllv3_recalc_rate(struct clk *clk, unsigned long parent_rate) { struct clk_pllv3 *pll = to_clk_pllv3(clk); - u32 div = readl(pll->base) & pll->div_mask; + u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask; return (div == 1) ? parent_rate * 22 : parent_rate * 20; } @@ -120,8 +121,8 @@ static int clk_pllv3_set_rate(struct clk *clk, unsigned long rate, return -EINVAL; val = readl(pll->base); - val &= ~pll->div_mask; - val |= div; + val &= ~(pll->div_mask << pll->div_shift); + val |= div << pll->div_shift; writel(val, pll->base); return 0; @@ -292,6 +293,8 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, case IMX_PLLV3_SYS: ops = &clk_pllv3_sys_ops; break; + case IMX_PLLV3_USB_VF610: + pll->div_shift = 1; case IMX_PLLV3_USB: ops = &clk_pllv3_ops; pll->powerup_set = true; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 2aeb35631d..35e480f291 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -71,6 +71,7 @@ enum imx_pllv3_type { IMX_PLLV3_GENERIC, IMX_PLLV3_SYS, IMX_PLLV3_USB, + IMX_PLLV3_USB_VF610, IMX_PLLV3_AV, IMX_PLLV3_ENET, IMX_PLLV3_MLB, -- cgit v1.2.3 From c30a463d644b49edb4af9a6dec2065c824a9d32b Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:14:01 -0800 Subject: i.MX: clk: Port imx_check_clocks() Port imx_check_clocks() from Linux kernel. Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/clk/imx/Makefile | 3 ++- drivers/clk/imx/clk.c | 21 +++++++++++++++++++++ drivers/clk/imx/clk.h | 3 +++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk.c (limited to 'drivers') diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 99dbe7d17c..7806bb2849 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -4,7 +4,8 @@ obj-$(CONFIG_COMMON_CLK) += \ clk-pllv3.o \ clk-pfd.o \ clk-gate2.o \ - clk-gate-exclusive.o + clk-gate-exclusive.o \ + clk.o obj-$(CONFIG_ARCH_IMX1) += clk-imx1.o obj-$(CONFIG_ARCH_IMX25) += clk-imx25.o diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c new file mode 100644 index 0000000000..7488dfcdc8 --- /dev/null +++ b/drivers/clk/imx/clk.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +void __init imx_check_clocks(struct clk *clks[], unsigned int count) +{ + unsigned i; + + for (i = 0; i < count; i++) + if (IS_ERR(clks[i])) + pr_err("i.MX clk %u: register failed with %ld\n", + i, PTR_ERR(clks[i])); +} + diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 35e480f291..fd43fc2622 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -109,4 +109,7 @@ static inline struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, void __iomem *reg, u8 shift, u32 exclusive_mask); +void imx_check_clocks(struct clk *clks[], unsigned int count); + + #endif /* __IMX_CLK_H */ -- cgit v1.2.3 From 674015bf83c1009a3bfcd81df9207e578cf8288f Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:14:02 -0800 Subject: i.MX: clk: Port imx_clk_mux_flags from Linux Port imx_clk_mux_flags from Linux, to simplify clock code porting. Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/clk/imx/clk.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index fd43fc2622..970f65c7d1 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -30,6 +30,14 @@ static inline struct clk *imx_clk_fixed_factor(const char *name, return clk_fixed_factor(name, parent, mult, div, CLK_SET_RATE_PARENT); } +static inline struct clk *imx_clk_mux_flags(const char *name, void __iomem *reg, + u8 shift, u8 width, + const char **parents, u8 num_parents, + unsigned long flags) +{ + return clk_mux(name, reg, shift, width, parents, num_parents, flags); +} + static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, u8 shift, u8 width, const char **parents, u8 num_parents) { -- cgit v1.2.3 From 12a5342b02f6c754d21379040b779b7f32c55ef4 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:14:03 -0800 Subject: i.MX: Add VF610 clock tree initialization code Based on analogous code from Linux kernel Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-vf610.c | 446 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 447 insertions(+) create mode 100644 drivers/clk/imx/clk-vf610.c (limited to 'drivers') diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 7806bb2849..65d7859ed3 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_ARCH_IMX53) += clk-imx5.o obj-$(CONFIG_ARCH_IMX6) += clk-imx6.o obj-$(CONFIG_ARCH_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_ARCH_IMX6UL) += clk-imx6ul.o +obj-$(CONFIG_ARCH_VF610) += clk-vf610.o diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c new file mode 100644 index 0000000000..9b9ac6cb0a --- /dev/null +++ b/drivers/clk/imx/clk-vf610.c @@ -0,0 +1,446 @@ +/* + * Copyright 2012-2013 Freescale Semiconductor, Inc. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define CCM_CCR (ccm_base + 0x00) +#define CCM_CSR (ccm_base + 0x04) +#define CCM_CCSR (ccm_base + 0x08) +#define CCSR_PLL1_PFDn_EN(n) BIT((n) + 7) +#define CCSR_PLL2_PFDn_EN(n) BIT((n) + 11) +#define CCSR_PLL3_PFDn_EN(n) BIT((n) + 27) +#define CCM_CACRR (ccm_base + 0x0c) +#define CCM_CSCMR1 (ccm_base + 0x10) +#define CCM_CSCDR1 (ccm_base + 0x14) +#define CCM_CSCDR2 (ccm_base + 0x18) +#define CCM_CSCDR3 (ccm_base + 0x1c) +#define CCM_CSCMR2 (ccm_base + 0x20) +#define CCM_CSCDR4 (ccm_base + 0x24) +#define CCM_CLPCR (ccm_base + 0x2c) +#define CCM_CISR (ccm_base + 0x30) +#define CCM_CIMR (ccm_base + 0x34) +#define CCM_CGPR (ccm_base + 0x3c) +#define CCM_CCGR0 (ccm_base + 0x40) +#define CCM_CCGR1 (ccm_base + 0x44) +#define CCM_CCGR2 (ccm_base + 0x48) +#define CCM_CCGR3 (ccm_base + 0x4c) +#define CCM_CCGR4 (ccm_base + 0x50) +#define CCM_CCGR5 (ccm_base + 0x54) +#define CCM_CCGR6 (ccm_base + 0x58) +#define CCM_CCGR7 (ccm_base + 0x5c) +#define CCM_CCGR8 (ccm_base + 0x60) +#define CCM_CCGR9 (ccm_base + 0x64) +#define CCM_CCGR10 (ccm_base + 0x68) +#define CCM_CCGR11 (ccm_base + 0x6c) +#define CCM_CCGRx(x) (CCM_CCGR0 + (x) * 4) +#define CCM_CMEOR0 (ccm_base + 0x70) +#define CCM_CMEOR1 (ccm_base + 0x74) +#define CCM_CMEOR2 (ccm_base + 0x78) +#define CCM_CMEOR3 (ccm_base + 0x7c) +#define CCM_CMEOR4 (ccm_base + 0x80) +#define CCM_CMEOR5 (ccm_base + 0x84) +#define CCM_CPPDSR (ccm_base + 0x88) +#define CCM_CCOWR (ccm_base + 0x8c) +#define CCM_CCPGR0 (ccm_base + 0x90) +#define CCM_CCPGR1 (ccm_base + 0x94) +#define CCM_CCPGR2 (ccm_base + 0x98) +#define CCM_CCPGR3 (ccm_base + 0x9c) + +#define CCM_CCGRx_CGn(n) ((n) * 2) + +#define PFD_PLL1_BASE (anatop_base + 0x2b0) +#define PFD_PLL2_BASE (anatop_base + 0x100) +#define PFD_PLL3_BASE (anatop_base + 0xf0) +#define PLL1_CTRL (anatop_base + 0x270) +#define PLL2_CTRL (anatop_base + 0x30) +#define PLL3_CTRL (anatop_base + 0x10) +#define PLL4_CTRL (anatop_base + 0x70) +#define PLL5_CTRL (anatop_base + 0xe0) +#define PLL6_CTRL (anatop_base + 0xa0) +#define PLL7_CTRL (anatop_base + 0x20) +#define ANA_MISC1 (anatop_base + 0x160) + +static void __iomem *anatop_base; +static void __iomem *ccm_base; + +/* sources for multiplexer clocks, this is used multiple times */ +static const char *fast_sels[] = { "firc", "fxosc", }; +static const char *slow_sels[] = { "sirc_32k", "sxosc", }; +static const char *pll1_sels[] = { "pll1_sys", "pll1_pfd1", "pll1_pfd2", "pll1_pfd3", "pll1_pfd4", }; +static const char *pll2_sels[] = { "pll2_bus", "pll2_pfd1", "pll2_pfd2", "pll2_pfd3", "pll2_pfd4", }; +static const char *pll_bypass_src_sels[] = { "fast_clk_sel", "lvds1_in", }; +static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", }; +static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", }; +static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", }; +static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", }; +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 const char *sys_sels[] = { "fast_clk_sel", "slow_clk_sel", "pll2_pfd_sel", "pll2_bus", "pll1_pfd_sel", "pll3_usb_otg", }; +static const char *ddr_sels[] = { "pll2_pfd2", "sys_sel", }; +static const char *rmii_sels[] = { "enet_ext", "audio_ext", "enet_50m", "enet_25m", }; +static const char *enet_ts_sels[] = { "enet_ext", "fxosc", "audio_ext", "usb", "enet_ts", "enet_25m", "enet_50m", }; +static const char *esai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_audio_div", }; +static const char *sai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_audio_div", }; +static const char *nfc_sels[] = { "platform_bus", "pll1_pfd1", "pll3_pfd1", "pll3_pfd3", }; +static const char *qspi_sels[] = { "pll3_usb_otg", "pll3_pfd4", "pll2_pfd4", "pll1_pfd4", }; +static const char *esdhc_sels[] = { "pll3_usb_otg", "pll3_pfd3", "pll1_pfd3", "platform_bus", }; +static const char *dcu_sels[] = { "pll1_pfd2", "pll3_usb_otg", }; +static const char *gpu_sels[] = { "pll2_pfd2", "pll3_pfd2", }; +static const char *vadc_sels[] = { "pll6_video_div", "pll3_usb_otg_div", "pll3_usb_otg", }; +/* FTM counter clock source, not module clock */ +static const char *ftm_ext_sels[] = {"sirc_128k", "sxosc", "fxosc_half", "audio_ext", }; +static const char *ftm_fix_sels[] = { "sxosc", "ipg_bus", }; + + +static struct clk_div_table pll4_audio_div_table[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 6 }, + { .val = 3, .div = 8 }, + { .val = 4, .div = 10 }, + { .val = 5, .div = 12 }, + { .val = 6, .div = 14 }, + { .val = 7, .div = 16 }, + { } +}; + +static struct clk *clk[VF610_CLK_END]; +static struct clk_onecell_data clk_data; + +static unsigned int const clks_init_on[] __initconst = { + VF610_CLK_SYS_BUS, + VF610_CLK_DDR_SEL, + VF610_CLK_DAP, + VF610_CLK_DDRMC, + VF610_CLK_WKPU, +}; + +static void __init vf610_clocks_init(struct device_node *ccm_node) +{ + u32 ccsr; + struct device_node *np; + int i; + + clk[VF610_CLK_DUMMY] = clk_fixed("dummy", 0); + clk[VF610_CLK_SIRC_128K] = clk_fixed("sirc_128k", 128000); + clk[VF610_CLK_SIRC_32K] = clk_fixed("sirc_32k", 32000); + clk[VF610_CLK_FIRC] = clk_fixed("firc", 24000000); + + clk[VF610_CLK_SXOSC] = of_clk_get_by_name(ccm_node, "sxosc"); + clk[VF610_CLK_FXOSC] = of_clk_get_by_name(ccm_node, "fxosc"); + clk[VF610_CLK_AUDIO_EXT] = of_clk_get_by_name(ccm_node, "audio_ext"); + clk[VF610_CLK_ENET_EXT] = of_clk_get_by_name(ccm_node, "enet_ext"); + + /* Clock source from external clock via LVDs PAD */ + clk[VF610_CLK_ANACLK1] = of_clk_get_by_name(ccm_node, "anaclk1"); + + clk[VF610_CLK_FXOSC_HALF] = imx_clk_fixed_factor("fxosc_half", "fxosc", 1, 2); + + np = of_find_compatible_node(NULL, NULL, "fsl,vf610-anatop"); + anatop_base = of_iomap(np, 0); + BUG_ON(!anatop_base); + + np = ccm_node; + ccm_base = of_iomap(np, 0); + BUG_ON(!ccm_base); + + ccsr = readl(CCM_CCSR); + ccsr |= CCSR_PLL3_PFDn_EN(1) | + CCSR_PLL3_PFDn_EN(2) | + CCSR_PLL3_PFDn_EN(3) | + CCSR_PLL3_PFDn_EN(4) | + CCSR_PLL2_PFDn_EN(1) | + CCSR_PLL2_PFDn_EN(2) | + CCSR_PLL2_PFDn_EN(3) | + CCSR_PLL2_PFDn_EN(4) | + CCSR_PLL1_PFDn_EN(1) | + CCSR_PLL1_PFDn_EN(2) | + CCSR_PLL1_PFDn_EN(3) | + CCSR_PLL1_PFDn_EN(4); + writel(ccsr, CCM_CCSR); + + clk[VF610_CLK_SLOW_CLK_SEL] = imx_clk_mux("slow_clk_sel", CCM_CCSR, 4, 1, slow_sels, ARRAY_SIZE(slow_sels)); + clk[VF610_CLK_FASK_CLK_SEL] = imx_clk_mux("fast_clk_sel", CCM_CCSR, 5, 1, fast_sels, ARRAY_SIZE(fast_sels)); + + clk[VF610_CLK_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", PLL1_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clk[VF610_CLK_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", PLL2_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clk[VF610_CLK_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", PLL3_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clk[VF610_CLK_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", PLL4_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clk[VF610_CLK_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", PLL5_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clk[VF610_CLK_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", PLL6_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clk[VF610_CLK_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", PLL7_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + + clk[VF610_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll1", "pll1_bypass_src", PLL1_CTRL, 0x1); + clk[VF610_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", PLL2_CTRL, 0x1); + clk[VF610_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB_VF610, "pll3", "pll3_bypass_src", PLL3_CTRL, 0x2); + clk[VF610_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", PLL4_CTRL, 0x7f); + clk[VF610_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll5", "pll5_bypass_src", PLL5_CTRL, 0x3); + clk[VF610_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_AV, "pll6", "pll6_bypass_src", PLL6_CTRL, 0x7f); + clk[VF610_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB_VF610, "pll7", "pll7_bypass_src", PLL7_CTRL, 0x2); + + clk[VF610_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", PLL1_CTRL, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT); + clk[VF610_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", PLL2_CTRL, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT); + clk[VF610_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", PLL3_CTRL, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT); + clk[VF610_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", PLL4_CTRL, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT); + clk[VF610_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", PLL5_CTRL, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT); + clk[VF610_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", PLL6_CTRL, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT); + clk[VF610_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", PLL7_CTRL, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT); + + /* Do not bypass PLLs initially */ + clk_set_parent(clk[VF610_PLL1_BYPASS], clk[VF610_CLK_PLL1]); + clk_set_parent(clk[VF610_PLL2_BYPASS], clk[VF610_CLK_PLL2]); + clk_set_parent(clk[VF610_PLL3_BYPASS], clk[VF610_CLK_PLL3]); + clk_set_parent(clk[VF610_PLL4_BYPASS], clk[VF610_CLK_PLL4]); + clk_set_parent(clk[VF610_PLL5_BYPASS], clk[VF610_CLK_PLL5]); + clk_set_parent(clk[VF610_PLL6_BYPASS], clk[VF610_CLK_PLL6]); + clk_set_parent(clk[VF610_PLL7_BYPASS], clk[VF610_CLK_PLL7]); + + clk[VF610_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", PLL1_CTRL, 13); + clk[VF610_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", PLL2_CTRL, 13); + clk[VF610_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", PLL3_CTRL, 13); + clk[VF610_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", PLL4_CTRL, 13); + clk[VF610_CLK_PLL5_ENET] = imx_clk_gate("pll5_enet", "pll5_bypass", PLL5_CTRL, 13); + clk[VF610_CLK_PLL6_VIDEO] = imx_clk_gate("pll6_video", "pll6_bypass", PLL6_CTRL, 13); + clk[VF610_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", PLL7_CTRL, 13); + + clk[VF610_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", ANA_MISC1, 12, BIT(10)); + + clk[VF610_CLK_PLL1_PFD1] = imx_clk_pfd("pll1_pfd1", "pll1_sys", PFD_PLL1_BASE, 0); + clk[VF610_CLK_PLL1_PFD2] = imx_clk_pfd("pll1_pfd2", "pll1_sys", PFD_PLL1_BASE, 1); + clk[VF610_CLK_PLL1_PFD3] = imx_clk_pfd("pll1_pfd3", "pll1_sys", PFD_PLL1_BASE, 2); + clk[VF610_CLK_PLL1_PFD4] = imx_clk_pfd("pll1_pfd4", "pll1_sys", PFD_PLL1_BASE, 3); + + clk[VF610_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1", "pll2_bus", PFD_PLL2_BASE, 0); + clk[VF610_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2", "pll2_bus", PFD_PLL2_BASE, 1); + clk[VF610_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3", "pll2_bus", PFD_PLL2_BASE, 2); + clk[VF610_CLK_PLL2_PFD4] = imx_clk_pfd("pll2_pfd4", "pll2_bus", PFD_PLL2_BASE, 3); + + clk[VF610_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1", "pll3_usb_otg", PFD_PLL3_BASE, 0); + clk[VF610_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2", "pll3_usb_otg", PFD_PLL3_BASE, 1); + clk[VF610_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3", "pll3_usb_otg", PFD_PLL3_BASE, 2); + clk[VF610_CLK_PLL3_PFD4] = imx_clk_pfd("pll3_pfd4", "pll3_usb_otg", PFD_PLL3_BASE, 3); + + clk[VF610_CLK_PLL1_PFD_SEL] = imx_clk_mux("pll1_pfd_sel", CCM_CCSR, 16, 3, pll1_sels, 5); + clk[VF610_CLK_PLL2_PFD_SEL] = imx_clk_mux("pll2_pfd_sel", CCM_CCSR, 19, 3, pll2_sels, 5); + clk[VF610_CLK_SYS_SEL] = imx_clk_mux("sys_sel", CCM_CCSR, 0, 3, sys_sels, ARRAY_SIZE(sys_sels)); + clk[VF610_CLK_DDR_SEL] = imx_clk_mux("ddr_sel", CCM_CCSR, 6, 1, ddr_sels, ARRAY_SIZE(ddr_sels)); + clk[VF610_CLK_SYS_BUS] = imx_clk_divider("sys_bus", "sys_sel", CCM_CACRR, 0, 3); + clk[VF610_CLK_PLATFORM_BUS] = imx_clk_divider("platform_bus", "sys_bus", CCM_CACRR, 3, 3); + clk[VF610_CLK_IPG_BUS] = imx_clk_divider("ipg_bus", "platform_bus", CCM_CACRR, 11, 2); + + clk[VF610_CLK_PLL3_MAIN_DIV] = imx_clk_divider("pll3_usb_otg_div", "pll3_usb_otg", CCM_CACRR, 20, 1); + clk[VF610_CLK_PLL4_MAIN_DIV] = clk_divider_table("pll4_audio_div", "pll4_audio", CCM_CACRR, 6, 3, pll4_audio_div_table, 0); + clk[VF610_CLK_PLL6_MAIN_DIV] = imx_clk_divider("pll6_video_div", "pll6_video", CCM_CACRR, 21, 1); + + clk[VF610_CLK_DDRMC] = imx_clk_gate2_cgr("ddrmc", "ddr_sel", CCM_CCGR6, CCM_CCGRx_CGn(14), 0x2); + clk[VF610_CLK_WKPU] = imx_clk_gate2_cgr("wkpu", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(10), 0x2); + + clk[VF610_CLK_USBPHY0] = imx_clk_gate("usbphy0", "pll3_usb_otg", PLL3_CTRL, 6); + clk[VF610_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll7_usb_host", PLL7_CTRL, 6); + + clk[VF610_CLK_USBC0] = imx_clk_gate2("usbc0", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(4)); + clk[VF610_CLK_USBC1] = imx_clk_gate2("usbc1", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(4)); + + clk[VF610_CLK_QSPI0_SEL] = imx_clk_mux("qspi0_sel", CCM_CSCMR1, 22, 2, qspi_sels, 4); + clk[VF610_CLK_QSPI0_EN] = imx_clk_gate("qspi0_en", "qspi0_sel", CCM_CSCDR3, 4); + clk[VF610_CLK_QSPI0_X4_DIV] = imx_clk_divider("qspi0_x4", "qspi0_en", CCM_CSCDR3, 0, 2); + clk[VF610_CLK_QSPI0_X2_DIV] = imx_clk_divider("qspi0_x2", "qspi0_x4", CCM_CSCDR3, 2, 1); + clk[VF610_CLK_QSPI0_X1_DIV] = imx_clk_divider("qspi0_x1", "qspi0_x2", CCM_CSCDR3, 3, 1); + clk[VF610_CLK_QSPI0] = imx_clk_gate2("qspi0", "qspi0_x1", CCM_CCGR2, CCM_CCGRx_CGn(4)); + + clk[VF610_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", CCM_CSCMR1, 24, 2, qspi_sels, 4); + clk[VF610_CLK_QSPI1_EN] = imx_clk_gate("qspi1_en", "qspi1_sel", CCM_CSCDR3, 12); + clk[VF610_CLK_QSPI1_X4_DIV] = imx_clk_divider("qspi1_x4", "qspi1_en", CCM_CSCDR3, 8, 2); + clk[VF610_CLK_QSPI1_X2_DIV] = imx_clk_divider("qspi1_x2", "qspi1_x4", CCM_CSCDR3, 10, 1); + clk[VF610_CLK_QSPI1_X1_DIV] = imx_clk_divider("qspi1_x1", "qspi1_x2", CCM_CSCDR3, 11, 1); + clk[VF610_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_x1", CCM_CCGR8, CCM_CCGRx_CGn(4)); + + clk[VF610_CLK_ENET_50M] = imx_clk_fixed_factor("enet_50m", "pll5_enet", 1, 10); + clk[VF610_CLK_ENET_25M] = imx_clk_fixed_factor("enet_25m", "pll5_enet", 1, 20); + clk[VF610_CLK_ENET_SEL] = imx_clk_mux("enet_sel", CCM_CSCMR2, 4, 2, rmii_sels, 4); + clk[VF610_CLK_ENET_TS_SEL] = imx_clk_mux("enet_ts_sel", CCM_CSCMR2, 0, 3, enet_ts_sels, 7); + clk[VF610_CLK_ENET] = imx_clk_gate("enet", "enet_sel", CCM_CSCDR1, 24); + clk[VF610_CLK_ENET_TS] = imx_clk_gate("enet_ts", "enet_ts_sel", CCM_CSCDR1, 23); + clk[VF610_CLK_ENET0] = imx_clk_gate2("enet0", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(0)); + clk[VF610_CLK_ENET1] = imx_clk_gate2("enet1", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(1)); + + clk[VF610_CLK_PIT] = imx_clk_gate2("pit", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(7)); + + clk[VF610_CLK_UART0] = imx_clk_gate2_cgr("uart0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(7), 0x2); + clk[VF610_CLK_UART1] = imx_clk_gate2_cgr("uart1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(8), 0x2); + clk[VF610_CLK_UART2] = imx_clk_gate2_cgr("uart2", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(9), 0x2); + clk[VF610_CLK_UART3] = imx_clk_gate2_cgr("uart3", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(10), 0x2); + clk[VF610_CLK_UART4] = imx_clk_gate2_cgr("uart4", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(9), 0x2); + clk[VF610_CLK_UART5] = imx_clk_gate2_cgr("uart5", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(10), 0x2); + + clk[VF610_CLK_I2C0] = imx_clk_gate2("i2c0", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(6)); + clk[VF610_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(7)); + clk[VF610_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_bus", CCM_CCGR10, CCM_CCGRx_CGn(6)); + clk[VF610_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_bus", CCM_CCGR10, CCM_CCGRx_CGn(7)); + + clk[VF610_CLK_DSPI0] = imx_clk_gate2("dspi0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(12)); + clk[VF610_CLK_DSPI1] = imx_clk_gate2("dspi1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(13)); + clk[VF610_CLK_DSPI2] = imx_clk_gate2("dspi2", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(12)); + clk[VF610_CLK_DSPI3] = imx_clk_gate2("dspi3", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(13)); + + clk[VF610_CLK_WDT] = imx_clk_gate2("wdt", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(14)); + + clk[VF610_CLK_ESDHC0_SEL] = imx_clk_mux("esdhc0_sel", CCM_CSCMR1, 16, 2, esdhc_sels, 4); + clk[VF610_CLK_ESDHC0_EN] = imx_clk_gate("esdhc0_en", "esdhc0_sel", CCM_CSCDR2, 28); + clk[VF610_CLK_ESDHC0_DIV] = imx_clk_divider("esdhc0_div", "esdhc0_en", CCM_CSCDR2, 16, 4); + clk[VF610_CLK_ESDHC0] = imx_clk_gate2("eshc0", "esdhc0_div", CCM_CCGR7, CCM_CCGRx_CGn(1)); + + clk[VF610_CLK_ESDHC1_SEL] = imx_clk_mux("esdhc1_sel", CCM_CSCMR1, 18, 2, esdhc_sels, 4); + clk[VF610_CLK_ESDHC1_EN] = imx_clk_gate("esdhc1_en", "esdhc1_sel", CCM_CSCDR2, 29); + clk[VF610_CLK_ESDHC1_DIV] = imx_clk_divider("esdhc1_div", "esdhc1_en", CCM_CSCDR2, 20, 4); + clk[VF610_CLK_ESDHC1] = imx_clk_gate2("eshc1", "esdhc1_div", CCM_CCGR7, CCM_CCGRx_CGn(2)); + + /* + * ftm_ext_clk and ftm_fix_clk are FTM timer counter's + * selectable clock sources, both use a common enable bit + * in CCM_CSCDR1, selecting "dummy" clock as parent of + * "ftm0_ext_fix" make it serve only for enable/disable. + */ + clk[VF610_CLK_FTM0_EXT_SEL] = imx_clk_mux("ftm0_ext_sel", CCM_CSCMR2, 6, 2, ftm_ext_sels, 4); + clk[VF610_CLK_FTM0_FIX_SEL] = imx_clk_mux("ftm0_fix_sel", CCM_CSCMR2, 14, 1, ftm_fix_sels, 2); + clk[VF610_CLK_FTM0_EXT_FIX_EN] = imx_clk_gate("ftm0_ext_fix_en", "dummy", CCM_CSCDR1, 25); + clk[VF610_CLK_FTM1_EXT_SEL] = imx_clk_mux("ftm1_ext_sel", CCM_CSCMR2, 8, 2, ftm_ext_sels, 4); + clk[VF610_CLK_FTM1_FIX_SEL] = imx_clk_mux("ftm1_fix_sel", CCM_CSCMR2, 15, 1, ftm_fix_sels, 2); + clk[VF610_CLK_FTM1_EXT_FIX_EN] = imx_clk_gate("ftm1_ext_fix_en", "dummy", CCM_CSCDR1, 26); + clk[VF610_CLK_FTM2_EXT_SEL] = imx_clk_mux("ftm2_ext_sel", CCM_CSCMR2, 10, 2, ftm_ext_sels, 4); + clk[VF610_CLK_FTM2_FIX_SEL] = imx_clk_mux("ftm2_fix_sel", CCM_CSCMR2, 16, 1, ftm_fix_sels, 2); + clk[VF610_CLK_FTM2_EXT_FIX_EN] = imx_clk_gate("ftm2_ext_fix_en", "dummy", CCM_CSCDR1, 27); + clk[VF610_CLK_FTM3_EXT_SEL] = imx_clk_mux("ftm3_ext_sel", CCM_CSCMR2, 12, 2, ftm_ext_sels, 4); + clk[VF610_CLK_FTM3_FIX_SEL] = imx_clk_mux("ftm3_fix_sel", CCM_CSCMR2, 17, 1, ftm_fix_sels, 2); + clk[VF610_CLK_FTM3_EXT_FIX_EN] = imx_clk_gate("ftm3_ext_fix_en", "dummy", CCM_CSCDR1, 28); + + /* ftm(n)_clk are FTM module operation clock */ + clk[VF610_CLK_FTM0] = imx_clk_gate2("ftm0", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(8)); + clk[VF610_CLK_FTM1] = imx_clk_gate2("ftm1", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(9)); + clk[VF610_CLK_FTM2] = imx_clk_gate2("ftm2", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(8)); + clk[VF610_CLK_FTM3] = imx_clk_gate2("ftm3", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(9)); + + clk[VF610_CLK_DCU0_SEL] = imx_clk_mux("dcu0_sel", CCM_CSCMR1, 28, 1, dcu_sels, 2); + clk[VF610_CLK_DCU0_EN] = imx_clk_gate("dcu0_en", "dcu0_sel", CCM_CSCDR3, 19); + clk[VF610_CLK_DCU0_DIV] = imx_clk_divider("dcu0_div", "dcu0_en", CCM_CSCDR3, 16, 3); + clk[VF610_CLK_DCU0] = imx_clk_gate2("dcu0", "ipg_bus", CCM_CCGR3, CCM_CCGRx_CGn(8)); + clk[VF610_CLK_DCU1_SEL] = imx_clk_mux("dcu1_sel", CCM_CSCMR1, 29, 1, dcu_sels, 2); + clk[VF610_CLK_DCU1_EN] = imx_clk_gate("dcu1_en", "dcu1_sel", CCM_CSCDR3, 23); + clk[VF610_CLK_DCU1_DIV] = imx_clk_divider("dcu1_div", "dcu1_en", CCM_CSCDR3, 20, 3); + clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(8)); + + clk[VF610_CLK_TCON0] = imx_clk_gate2("tcon0", "platform_bus", CCM_CCGR1, CCM_CCGRx_CGn(13)); + clk[VF610_CLK_TCON1] = imx_clk_gate2("tcon1", "platform_bus", CCM_CCGR7, CCM_CCGRx_CGn(13)); + + clk[VF610_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", CCM_CSCMR1, 20, 2, esai_sels, 4); + clk[VF610_CLK_ESAI_EN] = imx_clk_gate("esai_en", "esai_sel", CCM_CSCDR2, 30); + clk[VF610_CLK_ESAI_DIV] = imx_clk_divider("esai_div", "esai_en", CCM_CSCDR2, 24, 4); + clk[VF610_CLK_ESAI] = imx_clk_gate2("esai", "esai_div", CCM_CCGR4, CCM_CCGRx_CGn(2)); + + clk[VF610_CLK_SAI0_SEL] = imx_clk_mux("sai0_sel", CCM_CSCMR1, 0, 2, sai_sels, 4); + clk[VF610_CLK_SAI0_EN] = imx_clk_gate("sai0_en", "sai0_sel", CCM_CSCDR1, 16); + clk[VF610_CLK_SAI0_DIV] = imx_clk_divider("sai0_div", "sai0_en", CCM_CSCDR1, 0, 4); + clk[VF610_CLK_SAI0] = imx_clk_gate2("sai0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(15)); + + clk[VF610_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", CCM_CSCMR1, 2, 2, sai_sels, 4); + clk[VF610_CLK_SAI1_EN] = imx_clk_gate("sai1_en", "sai1_sel", CCM_CSCDR1, 17); + clk[VF610_CLK_SAI1_DIV] = imx_clk_divider("sai1_div", "sai1_en", CCM_CSCDR1, 4, 4); + clk[VF610_CLK_SAI1] = imx_clk_gate2("sai1", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(0)); + + clk[VF610_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", CCM_CSCMR1, 4, 2, sai_sels, 4); + clk[VF610_CLK_SAI2_EN] = imx_clk_gate("sai2_en", "sai2_sel", CCM_CSCDR1, 18); + clk[VF610_CLK_SAI2_DIV] = imx_clk_divider("sai2_div", "sai2_en", CCM_CSCDR1, 8, 4); + clk[VF610_CLK_SAI2] = imx_clk_gate2("sai2", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(1)); + + clk[VF610_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", CCM_CSCMR1, 6, 2, sai_sels, 4); + clk[VF610_CLK_SAI3_EN] = imx_clk_gate("sai3_en", "sai3_sel", CCM_CSCDR1, 19); + clk[VF610_CLK_SAI3_DIV] = imx_clk_divider("sai3_div", "sai3_en", CCM_CSCDR1, 12, 4); + clk[VF610_CLK_SAI3] = imx_clk_gate2("sai3", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(2)); + + clk[VF610_CLK_NFC_SEL] = imx_clk_mux("nfc_sel", CCM_CSCMR1, 12, 2, nfc_sels, 4); + clk[VF610_CLK_NFC_EN] = imx_clk_gate("nfc_en", "nfc_sel", CCM_CSCDR2, 9); + clk[VF610_CLK_NFC_PRE_DIV] = imx_clk_divider("nfc_pre_div", "nfc_en", CCM_CSCDR3, 13, 3); + clk[VF610_CLK_NFC_FRAC_DIV] = imx_clk_divider("nfc_frac_div", "nfc_pre_div", CCM_CSCDR2, 4, 4); + clk[VF610_CLK_NFC] = imx_clk_gate2("nfc", "nfc_frac_div", CCM_CCGR10, CCM_CCGRx_CGn(0)); + + clk[VF610_CLK_GPU_SEL] = imx_clk_mux("gpu_sel", CCM_CSCMR1, 14, 1, gpu_sels, 2); + clk[VF610_CLK_GPU_EN] = imx_clk_gate("gpu_en", "gpu_sel", CCM_CSCDR2, 10); + clk[VF610_CLK_GPU2D] = imx_clk_gate2("gpu", "gpu_en", CCM_CCGR8, CCM_CCGRx_CGn(15)); + + clk[VF610_CLK_VADC_SEL] = imx_clk_mux("vadc_sel", CCM_CSCMR1, 8, 2, vadc_sels, 3); + clk[VF610_CLK_VADC_EN] = imx_clk_gate("vadc_en", "vadc_sel", CCM_CSCDR1, 22); + clk[VF610_CLK_VADC_DIV] = imx_clk_divider("vadc_div", "vadc_en", CCM_CSCDR1, 20, 2); + clk[VF610_CLK_VADC_DIV_HALF] = imx_clk_fixed_factor("vadc_div_half", "vadc_div", 1, 2); + clk[VF610_CLK_VADC] = imx_clk_gate2("vadc", "vadc_div", CCM_CCGR8, CCM_CCGRx_CGn(7)); + + clk[VF610_CLK_ADC0] = imx_clk_gate2("adc0", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(11)); + clk[VF610_CLK_ADC1] = imx_clk_gate2("adc1", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(11)); + clk[VF610_CLK_DAC0] = imx_clk_gate2("dac0", "ipg_bus", CCM_CCGR8, CCM_CCGRx_CGn(12)); + clk[VF610_CLK_DAC1] = imx_clk_gate2("dac1", "ipg_bus", CCM_CCGR8, CCM_CCGRx_CGn(13)); + + clk[VF610_CLK_ASRC] = imx_clk_gate2("asrc", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(1)); + + clk[VF610_CLK_FLEXCAN0_EN] = imx_clk_gate("flexcan0_en", "ipg_bus", CCM_CSCDR2, 11); + clk[VF610_CLK_FLEXCAN0] = imx_clk_gate2("flexcan0", "flexcan0_en", CCM_CCGR0, CCM_CCGRx_CGn(0)); + clk[VF610_CLK_FLEXCAN1_EN] = imx_clk_gate("flexcan1_en", "ipg_bus", CCM_CSCDR2, 12); + clk[VF610_CLK_FLEXCAN1] = imx_clk_gate2("flexcan1", "flexcan1_en", CCM_CCGR9, CCM_CCGRx_CGn(4)); + + clk[VF610_CLK_DMAMUX0] = imx_clk_gate2("dmamux0", "platform_bus", CCM_CCGR0, CCM_CCGRx_CGn(4)); + clk[VF610_CLK_DMAMUX1] = imx_clk_gate2("dmamux1", "platform_bus", CCM_CCGR0, CCM_CCGRx_CGn(5)); + clk[VF610_CLK_DMAMUX2] = imx_clk_gate2("dmamux2", "platform_bus", CCM_CCGR6, CCM_CCGRx_CGn(1)); + clk[VF610_CLK_DMAMUX3] = imx_clk_gate2("dmamux3", "platform_bus", CCM_CCGR6, CCM_CCGRx_CGn(2)); + + clk[VF610_CLK_SNVS] = imx_clk_gate2("snvs-rtc", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(7)); + clk[VF610_CLK_DAP] = imx_clk_gate("dap", "platform_bus", CCM_CCSR, 24); + clk[VF610_CLK_OCOTP] = imx_clk_gate("ocotp", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(5)); + + imx_check_clocks(clk, ARRAY_SIZE(clk)); + + clk_set_parent(clk[VF610_CLK_QSPI0_SEL], clk[VF610_CLK_PLL1_PFD4]); + clk_set_rate(clk[VF610_CLK_QSPI0_X4_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_SEL]) / 2); + clk_set_rate(clk[VF610_CLK_QSPI0_X2_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_X4_DIV]) / 2); + clk_set_rate(clk[VF610_CLK_QSPI0_X1_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_X2_DIV]) / 2); + + clk_set_parent(clk[VF610_CLK_QSPI1_SEL], clk[VF610_CLK_PLL1_PFD4]); + clk_set_rate(clk[VF610_CLK_QSPI1_X4_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_SEL]) / 2); + clk_set_rate(clk[VF610_CLK_QSPI1_X2_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_X4_DIV]) / 2); + clk_set_rate(clk[VF610_CLK_QSPI1_X1_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_X2_DIV]) / 2); + + clk_set_parent(clk[VF610_CLK_ESDHC1_SEL], clk[VF610_CLK_PLL1_PFD3]); + clk_set_rate(clk[VF610_CLK_ESDHC1_DIV], clk_get_rate(clk[VF610_CLK_PLL1_PFD3]) / 9); + + clk_set_parent(clk[VF610_CLK_ESDHC0_SEL], clk[VF610_CLK_PLL1_PFD3]); + clk_set_rate(clk[VF610_CLK_ESDHC0_DIV], clk_get_rate(clk[VF610_CLK_PLL1_PFD3]) / 9); + + clk_set_parent(clk[VF610_CLK_SAI0_SEL], clk[VF610_CLK_AUDIO_EXT]); + clk_set_parent(clk[VF610_CLK_SAI1_SEL], clk[VF610_CLK_AUDIO_EXT]); + clk_set_parent(clk[VF610_CLK_SAI2_SEL], clk[VF610_CLK_AUDIO_EXT]); + clk_set_parent(clk[VF610_CLK_SAI3_SEL], clk[VF610_CLK_AUDIO_EXT]); + + for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) + clk_enable(clk[clks_init_on[i]]); + + /* Add the clocks to provider list */ + clk_data.clks = clk; + clk_data.clk_num = ARRAY_SIZE(clk); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); +} +CLK_OF_DECLARE(vf610, "fsl,vf610-ccm", vf610_clocks_init); -- cgit v1.2.3 From 9d0b248bc4c89c841e6aa284d41221035680b854 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:14:05 -0800 Subject: i.MX: Add 'lpuart' serial driver Add 'lpuart' serial driver, based on analogous driver from U-Boot Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/serial/Kconfig | 5 + drivers/serial/Makefile | 1 + drivers/serial/serial_lpuart.c | 217 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 drivers/serial/serial_lpuart.c (limited to 'drivers') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index b112d7ee04..4eab437ea5 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -137,4 +137,9 @@ config DRIVER_SERIAL_DIGIC bool "Canon DIGIC serial driver" depends on ARCH_DIGIC +config DRIVER_SERIAL_LPUART + depends on ARCH_VF610 + default y + bool "LPUART serial driver" + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 189e777777..7d1bae195f 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_DRIVER_SERIAL_AUART) += serial_auart.o obj-$(CONFIG_DRIVER_SERIAL_CADENCE) += serial_cadence.o obj-$(CONFIG_DRIVER_SERIAL_EFI_STDIO) += efi-stdio.o obj-$(CONFIG_DRIVER_SERIAL_DIGIC) += serial_digic.o +obj-$(CONFIG_DRIVER_SERIAL_LPUART) += serial_lpuart.o diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c new file mode 100644 index 0000000000..52fb6d39c0 --- /dev/null +++ b/drivers/serial/serial_lpuart.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2016 Zodiac Inflight Innovation + * Author: Andrey Smirnov + * + * Based on analogous driver from U-Boot + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct lpuart { + struct console_device cdev; + int baudrate; + int dte_mode; + struct notifier_block notify; + struct resource *io; + void __iomem *base; + struct clk *clk; +}; + +static struct lpuart *cdev_to_lpuart(struct console_device *cdev) +{ + return container_of(cdev, struct lpuart, cdev); +} + +static struct lpuart *nb_to_lpuart(struct notifier_block *nb) +{ + return container_of(nb, struct lpuart, notify); +} + +static void lpuart_enable(struct lpuart *lpuart, bool on) +{ + u8 ctrl; + + ctrl = readb(lpuart->base + UARTCR2); + if (on) + ctrl |= UARTCR2_TE | UARTCR2_RE; + else + ctrl &= ~(UARTCR2_TE | UARTCR2_RE); + writeb(ctrl, lpuart->base + UARTCR2); +} + +static int lpuart_serial_setbaudrate(struct console_device *cdev, + int baudrate) +{ + struct lpuart *lpuart = cdev_to_lpuart(cdev); + + lpuart_enable(lpuart, false); + + lpuart_setbrg(lpuart->base, + clk_get_rate(lpuart->clk), + baudrate); + + lpuart_enable(lpuart, true); + + lpuart->baudrate = baudrate; + + return 0; +} + +static int lpuart_serial_getc(struct console_device *cdev) +{ + bool ready; + struct lpuart *lpuart = cdev_to_lpuart(cdev); + + do { + const u8 sr1 = readb(lpuart->base + UARTSR1); + ready = !!(sr1 & (UARTSR1_OR | UARTSR1_RDRF)); + } while (!ready); + + return readb(lpuart->base + UARTDR); +} + +static void lpuart_serial_putc(struct console_device *cdev, char c) +{ + lpuart_putc(cdev_to_lpuart(cdev)->base, c); +} + +/* Test whether a character is in the RX buffer */ +static int lpuart_serial_tstc(struct console_device *cdev) +{ + return !!readb(cdev_to_lpuart(cdev)->base + UARTRCFIFO); +} + +static void lpuart_serial_flush(struct console_device *cdev) +{ + bool tx_empty; + struct lpuart *lpuart = cdev_to_lpuart(cdev); + + do { + const u8 sr1 = readb(lpuart->base + UARTSR1); + tx_empty = !!(sr1 & UARTSR1_TDRE); + } while (!tx_empty); +} + +static int lpuart_clocksource_clock_change(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct lpuart *lpuart = nb_to_lpuart(nb); + + return lpuart_serial_setbaudrate(&lpuart->cdev, lpuart->baudrate); +} + +static int lpuart_serial_probe(struct device_d *dev) +{ + int ret; + struct console_device *cdev; + struct lpuart *lpuart; + const char *devname; + + lpuart = xzalloc(sizeof(*lpuart)); + cdev = &lpuart->cdev; + dev->priv = lpuart; + + lpuart->io = dev_request_mem_resource(dev, 0); + if (IS_ERR(lpuart->io)) { + ret = PTR_ERR(lpuart->io); + goto err_free; + } + lpuart->base = IOMEM(lpuart->io->start); + + lpuart->clk = clk_get(dev, NULL); + if (IS_ERR(lpuart->clk)) { + ret = PTR_ERR(lpuart->clk); + dev_err(dev, "Failed to get UART clock %d\n", ret); + goto io_release; + } + + ret = clk_enable(lpuart->clk); + if (ret) { + dev_err(dev, "Failed to enable UART clock %d\n", ret); + goto io_release; + } + + cdev->dev = dev; + cdev->tstc = lpuart_serial_tstc; + cdev->putc = lpuart_serial_putc; + cdev->getc = lpuart_serial_getc; + cdev->flush = lpuart_serial_flush; + cdev->setbrg = lpuart_serial_setbaudrate; + + if (dev->device_node) { + devname = of_alias_get(dev->device_node); + if (devname) { + cdev->devname = xstrdup(devname); + cdev->devid = DEVICE_ID_SINGLE; + } + } + + cdev->linux_console_name = "ttyLP"; + + lpuart_setup_with_fifo(lpuart->base, + clk_get_rate(lpuart->clk), + 15); + + ret = console_register(cdev); + if (!ret) { + lpuart->notify.notifier_call = lpuart_clocksource_clock_change; + clock_register_client(&lpuart->notify); + + return 0; + } + + clk_put(lpuart->clk); +io_release: + release_region(lpuart->io); +err_free: + free(lpuart); + + return ret; +} + +static void lpuart_serial_remove(struct device_d *dev) +{ + struct lpuart *lpuart = dev->priv; + + lpuart_serial_flush(&lpuart->cdev); + console_unregister(&lpuart->cdev); + release_region(lpuart->io); + clk_put(lpuart->clk); + + free(lpuart); +} + +static struct of_device_id lpuart_serial_dt_ids[] = { + { .compatible = "fsl,vf610-lpuart" }, + {} +}; + +static struct driver_d lpuart_serial_driver = { + .name = "lpuart-serial", + .probe = lpuart_serial_probe, + .remove = lpuart_serial_remove, + .of_compatible = DRV_OF_COMPAT(lpuart_serial_dt_ids), +}; +console_platform_driver(lpuart_serial_driver); -- cgit v1.2.3 From a6cf6b3ff0be58aaf63526c26b02c1ea936ba031 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:14:06 -0800 Subject: i.MX: i2c: Use read/write adapter functions Use read/write adapter functions instead of directly calling to readb/writeb. This is needed to prepare driver code to support Vybrid SoC's variant of this block. Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/i2c/busses/i2c-imx.c | 88 +++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index e407896394..f859d8ff3a 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -115,14 +115,27 @@ struct fsl_i2c_struct { }; #define to_fsl_i2c_struct(a) container_of(a, struct fsl_i2c_struct, adapter) +static inline void fsl_i2c_write_reg(unsigned int val, + struct fsl_i2c_struct *i2c_fsl, + unsigned int reg) +{ + writeb(val, i2c_fsl->base + reg); +} + +static inline unsigned char fsl_i2c_read_reg(struct fsl_i2c_struct *i2c_fsl, + unsigned int reg) +{ + return readb(i2c_fsl->base + reg); +} + #ifdef CONFIG_I2C_DEBUG static void i2c_fsl_dump_reg(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); u32 reg_cr, reg_sr; - reg_cr = readb(i2c_fsl->base + FSL_I2C_I2CR); - reg_sr = readb(i2c_fsl->base + FSL_I2C_I2SR); + reg_cr = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); + reg_sr = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2SR); dev_dbg(adapter->dev, "CONTROL:\t" "IEN =%d, IIEN=%d, MSTA=%d, MTX =%d, TXAK=%d, RSTA=%d\n", @@ -144,16 +157,16 @@ static inline void i2c_fsl_dump_reg(struct i2c_adapter *adapter) } #endif + static int i2c_fsl_bus_busy(struct i2c_adapter *adapter, int for_busy) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); - void __iomem *base = i2c_fsl->base; uint64_t start; unsigned int temp; start = get_time_ns(); while (1) { - temp = readb(base + FSL_I2C_I2SR); + temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2SR); if (for_busy && (temp & I2SR_IBB)) break; if (!for_busy && !(temp & I2SR_IBB)) @@ -172,12 +185,11 @@ static int i2c_fsl_bus_busy(struct i2c_adapter *adapter, int for_busy) static int i2c_fsl_trx_complete(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); - void __iomem *base = i2c_fsl->base; uint64_t start; start = get_time_ns(); while (1) { - unsigned int reg = readb(base + FSL_I2C_I2SR); + unsigned int reg = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2SR); if (reg & I2SR_IIF) break; @@ -186,7 +198,7 @@ static int i2c_fsl_trx_complete(struct i2c_adapter *adapter) return -EIO; } } - writeb(0, base + FSL_I2C_I2SR); + fsl_i2c_write_reg(0, i2c_fsl, FSL_I2C_I2SR); return 0; } @@ -194,12 +206,11 @@ static int i2c_fsl_trx_complete(struct i2c_adapter *adapter) static int i2c_fsl_acked(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); - void __iomem *base = i2c_fsl->base; uint64_t start; start = get_time_ns(); while (1) { - unsigned int reg = readb(base + FSL_I2C_I2SR); + unsigned int reg = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2SR); if (!(reg & I2SR_RXAK)) break; @@ -215,25 +226,24 @@ static int i2c_fsl_acked(struct i2c_adapter *adapter) static int i2c_fsl_start(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); - void __iomem *base = i2c_fsl->base; unsigned int temp = 0; int result; - writeb(i2c_fsl->ifdr, base + FSL_I2C_IFDR); + fsl_i2c_write_reg(i2c_fsl->ifdr, i2c_fsl, FSL_I2C_IFDR); if (i2c_fsl->dfsrr != -1) - writeb(i2c_fsl->dfsrr, base + FSL_I2C_DFSRR); + fsl_i2c_write_reg(i2c_fsl->dfsrr, i2c_fsl, FSL_I2C_DFSRR); /* Enable I2C controller */ - writeb(0, base + FSL_I2C_I2SR); - writeb(I2CR_IEN, base + FSL_I2C_I2CR); + fsl_i2c_write_reg(0, i2c_fsl, FSL_I2C_I2SR); + fsl_i2c_write_reg(I2CR_IEN, i2c_fsl, FSL_I2C_I2CR); /* Wait controller to be stable */ udelay(100); /* Start I2C transaction */ - temp = readb(base + FSL_I2C_I2CR); + temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); temp |= I2CR_MSTA; - writeb(temp, base + FSL_I2C_I2CR); + fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); result = i2c_fsl_bus_busy(adapter, 1); if (result) { @@ -246,7 +256,7 @@ static int i2c_fsl_start(struct i2c_adapter *adapter) i2c_fsl->stopped = 0; temp |= I2CR_MTX | I2CR_TXAK; - writeb(temp, base + FSL_I2C_I2CR); + fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); return result; } @@ -254,14 +264,13 @@ static int i2c_fsl_start(struct i2c_adapter *adapter) static void i2c_fsl_stop(struct i2c_adapter *adapter) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); - void __iomem *base = i2c_fsl->base; unsigned int temp = 0; if (!i2c_fsl->stopped) { /* Stop I2C transaction */ - temp = readb(base + FSL_I2C_I2CR); + temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); temp &= ~(I2CR_MSTA | I2CR_MTX); - writeb(temp, base + FSL_I2C_I2CR); + fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); /* wait for the stop condition to be send, otherwise the i2c * controller is disabled before the STOP is sent completely */ i2c_fsl->stopped = i2c_fsl_bus_busy(adapter, 0) ? 0 : 1; @@ -273,14 +282,13 @@ static void i2c_fsl_stop(struct i2c_adapter *adapter) } /* Disable I2C controller, and force our state to stopped */ - writeb(0, base + FSL_I2C_I2CR); + fsl_i2c_write_reg(0, i2c_fsl, FSL_I2C_I2CR); } #ifdef CONFIG_PPC static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl, unsigned int rate) { - void __iomem *base; unsigned int i2c_clk; unsigned short divider; /* @@ -295,7 +303,6 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl, unsigned long c_div, est_div; fdr = 0x31; /* Default if no FDR found */ - base = i2c_fsl->base; i2c_clk = fsl_get_i2c_freq(); divider = min((unsigned short)(i2c_clk / rate), (unsigned short) -1); @@ -387,7 +394,6 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl, static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); - void __iomem *base = i2c_fsl->base; int i, result; if ( !(msgs->flags & I2C_M_DATA_ONLY) ) { @@ -396,7 +402,7 @@ static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs) __func__, msgs->addr << 1); /* write slave address */ - writeb(msgs->addr << 1, base + FSL_I2C_I2DR); + fsl_i2c_write_reg(msgs->addr << 1, i2c_fsl, FSL_I2C_I2DR); result = i2c_fsl_trx_complete(adapter); if (result) @@ -411,7 +417,7 @@ static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs) dev_dbg(&adapter->dev, "<%s> write byte: B%d=0x%02X\n", __func__, i, msgs->buf[i]); - writeb(msgs->buf[i], base + FSL_I2C_I2DR); + fsl_i2c_write_reg(msgs->buf[i], i2c_fsl, FSL_I2C_I2DR); result = i2c_fsl_trx_complete(adapter); if (result) @@ -426,12 +432,11 @@ static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs) static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); - void __iomem *base = i2c_fsl->base; int i, result; unsigned int temp; /* clear IIF */ - writeb(0x0, base + FSL_I2C_I2SR); + fsl_i2c_write_reg(0x0, i2c_fsl, FSL_I2C_I2SR); if ( !(msgs->flags & I2C_M_DATA_ONLY) ) { dev_dbg(&adapter->dev, @@ -439,7 +444,7 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs) __func__, (msgs->addr << 1) | 0x01); /* write slave address */ - writeb((msgs->addr << 1) | 0x01, base + FSL_I2C_I2DR); + fsl_i2c_write_reg((msgs->addr << 1) | 0x01, i2c_fsl, FSL_I2C_I2DR); result = i2c_fsl_trx_complete(adapter); if (result) @@ -450,13 +455,13 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs) } /* setup bus to read data */ - temp = readb(base + FSL_I2C_I2CR); + temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); temp &= ~I2CR_MTX; if (msgs->len - 1) temp &= ~I2CR_TXAK; - writeb(temp, base + FSL_I2C_I2CR); + fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); - readb(base + FSL_I2C_I2DR); /* dummy read */ + fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2DR); /* dummy read */ /* read data */ for (i = 0; i < msgs->len; i++) { @@ -469,9 +474,9 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs) * It must generate STOP before read I2DR to prevent * controller from generating another clock cycle */ - temp = readb(base + FSL_I2C_I2CR); + temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); temp &= ~(I2CR_MSTA | I2CR_MTX); - writeb(temp, base + FSL_I2C_I2CR); + fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); /* * adding this delay helps on low bitrates @@ -481,11 +486,11 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs) i2c_fsl_bus_busy(adapter, 0); i2c_fsl->stopped = 1; } else if (i == (msgs->len - 2)) { - temp = readb(base + FSL_I2C_I2CR); + temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); temp |= I2CR_TXAK; - writeb(temp, base + FSL_I2C_I2CR); + fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); } - msgs->buf[i] = readb(base + FSL_I2C_I2DR); + msgs->buf[i] = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2DR); dev_dbg(&adapter->dev, "<%s> read byte: B%d=0x%02X\n", __func__, i, msgs->buf[i]); @@ -497,7 +502,6 @@ static int i2c_fsl_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) { struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter); - void __iomem *base = i2c_fsl->base; unsigned int i, temp; int result; @@ -514,9 +518,9 @@ static int i2c_fsl_xfer(struct i2c_adapter *adapter, /* read/write data */ for (i = 0; i < num; i++) { if (i && !(msgs[i].flags & I2C_M_DATA_ONLY)) { - temp = readb(base + FSL_I2C_I2CR); + temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR); temp |= I2CR_RSTA; - writeb(temp, base + FSL_I2C_I2CR); + fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); result = i2c_fsl_bus_busy(adapter, 1); if (result) @@ -623,8 +627,8 @@ static int __init i2c_fsl_probe(struct device_d *pdev) i2c_fsl_set_clk(i2c_fsl, FSL_I2C_BIT_RATE); /* Set up chip registers to defaults */ - writeb(0, i2c_fsl->base + FSL_I2C_I2CR); - writeb(0, i2c_fsl->base + FSL_I2C_I2SR); + fsl_i2c_write_reg(0, i2c_fsl, FSL_I2C_I2CR); + fsl_i2c_write_reg(0, i2c_fsl, FSL_I2C_I2SR); /* Add I2C adapter */ ret = i2c_add_numbered_adapter(&i2c_fsl->adapter); -- cgit v1.2.3 From 4ed5b778a56bcd6204086efde7039e64936d8f96 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:14:07 -0800 Subject: i.MX: i2c: Add Vybrid support Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/i2c/busses/i2c-imx.c | 150 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 122 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index f859d8ff3a..74f046d00c 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -54,14 +55,25 @@ /* Default value */ #define FSL_I2C_BIT_RATE 100000 /* 100kHz */ -/* FSL I2C registers */ +/* IMX I2C registers: + * the I2C register offset is different between SoCs, + * to provid support for all these chips, split the + * register offset into a fixed base address and a + * variable shift value, then the full register offset + * will be calculated by + * reg_off = ( reg_base_addr << reg_shift) + */ #define FSL_I2C_IADR 0x00 /* i2c slave address */ -#define FSL_I2C_IFDR 0x04 /* i2c frequency divider */ -#define FSL_I2C_I2CR 0x08 /* i2c control */ -#define FSL_I2C_I2SR 0x0C /* i2c status */ -#define FSL_I2C_I2DR 0x10 /* i2c transfer data */ +#define FSL_I2C_IFDR 0x01 /* i2c frequency divider */ +#define FSL_I2C_I2CR 0x02 /* i2c control */ +#define FSL_I2C_I2SR 0x03 /* i2c status */ +#define FSL_I2C_I2DR 0x04 /* i2c transfer data */ #define FSL_I2C_DFSRR 0x14 /* i2c digital filter sampling rate */ +#define IMX_I2C_REGSHIFT 2 +#define VF610_I2C_REGSHIFT 0 + + /* Bits of FSL I2C registers */ #define I2SR_RXAK 0x01 #define I2SR_IIF 0x02 @@ -77,6 +89,22 @@ #define I2CR_IIEN 0x40 #define I2CR_IEN 0x80 +/* register bits different operating codes definition: + * 1) I2SR: Interrupt flags clear operation differ between SoCs: + * - write zero to clear(w0c) INT flag on i.MX, + * - but write one to clear(w1c) INT flag on Vybrid. + * 2) I2CR: I2C module enable operation also differ between SoCs: + * - set I2CR_IEN bit enable the module on i.MX, + * - but clear I2CR_IEN bit enable the module on Vybrid. + */ +#define I2SR_CLR_OPCODE_W0C 0x0 +#define I2SR_CLR_OPCODE_W1C (I2SR_IAL | I2SR_IIF) +#define I2CR_IEN_OPCODE_0 0x0 +#define I2CR_IEN_OPCODE_1 I2CR_IEN + +#define I2C_PM_TIMEOUT 10 /* ms */ + + /* * sorted list of clock divider, register value pairs * taken from table 26-5, p.26-9, Freescale i.MX @@ -85,8 +113,12 @@ * * Duplicated divider values removed from list */ -#ifndef CONFIG_PPC -static u16 i2c_clk_div[50][2] = { +struct fsl_i2c_clk_pair { + u16 div; + u16 val; +}; + +static struct fsl_i2c_clk_pair imx_i2c_clk_div[] = { { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 }, @@ -101,7 +133,33 @@ static u16 i2c_clk_div[50][2] = { { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D }, { 3072, 0x1E }, { 3840, 0x1F } }; -#endif + +/* Vybrid VF610 clock divider, register value pairs */ +static struct fsl_i2c_clk_pair vf610_i2c_clk_div[] = { + { 20, 0x00 }, { 22, 0x01 }, { 24, 0x02 }, { 26, 0x03 }, + { 28, 0x04 }, { 30, 0x05 }, { 32, 0x09 }, { 34, 0x06 }, + { 36, 0x0A }, { 40, 0x07 }, { 44, 0x0C }, { 48, 0x0D }, + { 52, 0x43 }, { 56, 0x0E }, { 60, 0x45 }, { 64, 0x12 }, + { 68, 0x0F }, { 72, 0x13 }, { 80, 0x14 }, { 88, 0x15 }, + { 96, 0x19 }, { 104, 0x16 }, { 112, 0x1A }, { 128, 0x17 }, + { 136, 0x4F }, { 144, 0x1C }, { 160, 0x1D }, { 176, 0x55 }, + { 192, 0x1E }, { 208, 0x56 }, { 224, 0x22 }, { 228, 0x24 }, + { 240, 0x1F }, { 256, 0x23 }, { 288, 0x5C }, { 320, 0x25 }, + { 384, 0x26 }, { 448, 0x2A }, { 480, 0x27 }, { 512, 0x2B }, + { 576, 0x2C }, { 640, 0x2D }, { 768, 0x31 }, { 896, 0x32 }, + { 960, 0x2F }, { 1024, 0x33 }, { 1152, 0x34 }, { 1280, 0x35 }, + { 1536, 0x36 }, { 1792, 0x3A }, { 1920, 0x37 }, { 2048, 0x3B }, + { 2304, 0x3C }, { 2560, 0x3D }, { 3072, 0x3E }, { 3584, 0x7A }, + { 3840, 0x3F }, { 4096, 0x7B }, { 5120, 0x7D }, { 6144, 0x7E }, +}; + +struct fsl_i2c_hwdata { + unsigned regshift; + struct fsl_i2c_clk_pair *clk_div; + unsigned ndivs; + unsigned i2sr_clr_opcode; + unsigned i2cr_ien_opcode; +}; struct fsl_i2c_struct { void __iomem *base; @@ -112,6 +170,7 @@ struct fsl_i2c_struct { unsigned int ifdr; /* FSL_I2C_IFDR */ unsigned int dfsrr; /* FSL_I2C_DFSRR */ struct i2c_bus_recovery_info rinfo; + const struct fsl_i2c_hwdata *hwdata; }; #define to_fsl_i2c_struct(a) container_of(a, struct fsl_i2c_struct, adapter) @@ -119,12 +178,14 @@ static inline void fsl_i2c_write_reg(unsigned int val, struct fsl_i2c_struct *i2c_fsl, unsigned int reg) { + reg <<= i2c_fsl->hwdata->regshift; writeb(val, i2c_fsl->base + reg); } static inline unsigned char fsl_i2c_read_reg(struct fsl_i2c_struct *i2c_fsl, unsigned int reg) { + reg <<= i2c_fsl->hwdata->regshift; return readb(i2c_fsl->base + reg); } @@ -198,7 +259,9 @@ static int i2c_fsl_trx_complete(struct i2c_adapter *adapter) return -EIO; } } - fsl_i2c_write_reg(0, i2c_fsl, FSL_I2C_I2SR); + + fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode, + i2c_fsl, FSL_I2C_I2SR); return 0; } @@ -230,12 +293,16 @@ static int i2c_fsl_start(struct i2c_adapter *adapter) int result; fsl_i2c_write_reg(i2c_fsl->ifdr, i2c_fsl, FSL_I2C_IFDR); +#ifdef CONFIG_PPC if (i2c_fsl->dfsrr != -1) fsl_i2c_write_reg(i2c_fsl->dfsrr, i2c_fsl, FSL_I2C_DFSRR); +#endif /* Enable I2C controller */ - fsl_i2c_write_reg(0, i2c_fsl, FSL_I2C_I2SR); - fsl_i2c_write_reg(I2CR_IEN, i2c_fsl, FSL_I2C_I2CR); + fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode, + i2c_fsl, FSL_I2C_I2SR); + fsl_i2c_write_reg(i2c_fsl->hwdata->i2cr_ien_opcode, + i2c_fsl, FSL_I2C_I2CR); /* Wait controller to be stable */ udelay(100); @@ -282,7 +349,8 @@ static void i2c_fsl_stop(struct i2c_adapter *adapter) } /* Disable I2C controller, and force our state to stopped */ - fsl_i2c_write_reg(0, i2c_fsl, FSL_I2C_I2CR); + temp = i2c_fsl->hwdata->i2cr_ien_opcode ^ I2CR_IEN, + fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); } #ifdef CONFIG_PPC @@ -356,6 +424,7 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl, static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl, unsigned int rate) { + struct fsl_i2c_clk_pair *i2c_clk_div = i2c_fsl->hwdata->clk_div; unsigned int i2c_clk_rate; unsigned int div; int i; @@ -363,16 +432,16 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl, /* Divider value calculation */ i2c_clk_rate = clk_get_rate(i2c_fsl->clk); div = (i2c_clk_rate + rate - 1) / rate; - if (div < i2c_clk_div[0][0]) + if (div < i2c_clk_div[0].div) i = 0; - else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0]) - i = ARRAY_SIZE(i2c_clk_div) - 1; + else if (div > i2c_clk_div[i2c_fsl->hwdata->ndivs - 1].div) + i = i2c_clk_div[i2c_fsl->hwdata->ndivs - 1].div - 1; else - for (i = 0; i2c_clk_div[i][0] < div; i++) + for (i = 0; i2c_clk_div[i].div < div; i++) ; /* Store divider value */ - i2c_fsl->ifdr = i2c_clk_div[i][1]; + i2c_fsl->ifdr = i2c_clk_div[i].val; /* * There dummy delay is calculated. @@ -381,13 +450,13 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl, * to fix chip hardware bug. */ i2c_fsl->disable_delay = - (500000U * i2c_clk_div[i][0] + (i2c_clk_rate / 2) - 1) / + (500000U * i2c_clk_div[i].div + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2); dev_dbg(&i2c_fsl->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n", __func__, i2c_clk_rate, div); dev_dbg(&i2c_fsl->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n", - __func__, i2c_clk_div[i][1], i2c_clk_div[i][0]); + __func__, i2c_clk_div[i].val, i2c_clk_div[i].div); } #endif @@ -436,7 +505,8 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs) unsigned int temp; /* clear IIF */ - fsl_i2c_write_reg(0x0, i2c_fsl, FSL_I2C_I2SR); + fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode, + i2c_fsl, FSL_I2C_I2SR); if ( !(msgs->flags & I2C_M_DATA_ONLY) ) { dev_dbg(&adapter->dev, @@ -461,7 +531,7 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs) temp &= ~I2CR_TXAK; fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR); - fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2DR); /* dummy read */ + fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2DR); /* dummy read */ /* read data */ for (i = 0; i < msgs->len; i++) { @@ -604,6 +674,13 @@ static int __init i2c_fsl_probe(struct device_d *pdev) goto fail; } #endif + + i2c_fsl->hwdata = of_device_get_match_data(pdev); + if (!i2c_fsl->hwdata) { + ret = -EINVAL; + goto fail; + } + /* Setup i2c_fsl driver structure */ i2c_fsl->adapter.master_xfer = i2c_fsl_xfer; i2c_fsl->adapter.nr = pdev->id; @@ -627,8 +704,9 @@ static int __init i2c_fsl_probe(struct device_d *pdev) i2c_fsl_set_clk(i2c_fsl, FSL_I2C_BIT_RATE); /* Set up chip registers to defaults */ - fsl_i2c_write_reg(0, i2c_fsl, FSL_I2C_I2CR); - fsl_i2c_write_reg(0, i2c_fsl, FSL_I2C_I2SR); + fsl_i2c_write_reg(i2c_fsl->hwdata->i2cr_ien_opcode ^ I2CR_IEN, + i2c_fsl, FSL_I2C_I2CR); + fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode, i2c_fsl, FSL_I2C_I2SR); /* Add I2C adapter */ ret = i2c_add_numbered_adapter(&i2c_fsl->adapter); @@ -644,17 +722,33 @@ fail: return ret; } +static const struct fsl_i2c_hwdata imx21_i2c_hwdata = { + .regshift = IMX_I2C_REGSHIFT, + .clk_div = imx_i2c_clk_div, + .ndivs = ARRAY_SIZE(imx_i2c_clk_div), + .i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C, + .i2cr_ien_opcode = I2CR_IEN_OPCODE_1, +}; + +static const struct fsl_i2c_hwdata vf610_i2c_hwdata = { + .regshift = VF610_I2C_REGSHIFT, + .clk_div = vf610_i2c_clk_div, + .ndivs = ARRAY_SIZE(vf610_i2c_clk_div), + .i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C, + .i2cr_ien_opcode = I2CR_IEN_OPCODE_0, +}; + static __maybe_unused struct of_device_id imx_i2c_dt_ids[] = { - { - .compatible = "fsl,imx21-i2c", - }, { - /* sentinel */ - } + { .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, }, + { .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, }, + { /* sentinel */ } }; static struct driver_d i2c_fsl_driver = { .probe = i2c_fsl_probe, .name = DRIVER_NAME, +#ifndef CONFIG_PPC .of_compatible = DRV_OF_COMPAT(imx_i2c_dt_ids), +#endif }; coredevice_platform_driver(i2c_fsl_driver); -- cgit v1.2.3 From 39f7a7ee8b68299e50bbfd4a68f392379b2e98df Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:14:08 -0800 Subject: i.MX: esdhc: Do not rely on CPU type for quirks CPU type is not a reliable indicator of the underlying type of IP core used, since there's no 1:1 mapping between the two. As example of one such violation consider Vybrid SoC which contains IP block from i.MX53. Instead port feature flags from corresponding Linux kernel driver and use the ones that are relevant. Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/mci/imx-esdhc.c | 121 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 100 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c index 262a904ace..764a106453 100644 --- a/drivers/mci/imx-esdhc.c +++ b/drivers/mci/imx-esdhc.c @@ -35,28 +35,81 @@ #include #include #include +#include #include "sdhci.h" #include "imx-esdhc.h" +/* + * The CMDTYPE of the CMD register (offset 0xE) should be set to + * "11" when the STOP CMD12 is issued on imx53 to abort one + * open ended multi-blk IO. Otherwise the TC INT wouldn't + * be generated. + * In exact block transfer, the controller doesn't complete the + * operations automatically as required at the end of the + * transfer and remains on hold if the abort command is not sent. + * As a result, the TC flag is not asserted and SW received timeout + * exeception. Bit1 of Vendor Spec registor is used to fix it. + */ +#define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1) +/* + * The flag enables the workaround for ESDHC errata ENGcm07207 which + * affects i.MX25 and i.MX35. + */ +#define ESDHC_FLAG_ENGCM07207 BIT(2) +/* + * The flag tells that the ESDHC controller is an USDHC block that is + * integrated on the i.MX6 series. + */ +#define ESDHC_FLAG_USDHC BIT(3) +/* The IP supports manual tuning process */ +#define ESDHC_FLAG_MAN_TUNING BIT(4) +/* The IP supports standard tuning process */ +#define ESDHC_FLAG_STD_TUNING BIT(5) +/* The IP has SDHCI_CAPABILITIES_1 register */ +#define ESDHC_FLAG_HAVE_CAP1 BIT(6) +/* + * The IP has errata ERR004536 + * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow, + * when reading data from the card + */ +#define ESDHC_FLAG_ERR004536 BIT(7) +/* The IP supports HS200 mode */ +#define ESDHC_FLAG_HS200 BIT(8) +/* The IP supports HS400 mode */ +#define ESDHC_FLAG_HS400 BIT(9) + + #define IMX_SDHCI_WML 0x44 #define IMX_SDHCI_MIXCTRL 0x48 #define IMX_SDHCI_DLL_CTRL 0x60 #define IMX_SDHCI_MIX_CTRL_FBCLK_SEL (BIT(25)) +struct esdhc_soc_data { + u32 flags; +}; + struct fsl_esdhc_host { struct mci_host mci; void __iomem *regs; struct device_d *dev; struct clk *clk; + const struct esdhc_soc_data *socdata; }; #define to_fsl_esdhc(mci) container_of(mci, struct fsl_esdhc_host, mci) #define SDHCI_CMD_ABORTCMD (0xC0 << 16) +static inline int esdhc_is_usdhc(struct fsl_esdhc_host *data) +{ + return !!(data->socdata->flags & ESDHC_FLAG_USDHC); +} + + /* Return the XFERTYP flags for a given command and data packet */ -static u32 esdhc_xfertyp(struct mci_cmd *cmd, struct mci_data *data) +static u32 esdhc_xfertyp(struct fsl_esdhc_host *host, + struct mci_cmd *cmd, struct mci_data *data) { u32 xfertyp = 0; @@ -85,8 +138,8 @@ static u32 esdhc_xfertyp(struct mci_cmd *cmd, struct mci_data *data) xfertyp |= COMMAND_RSPTYP_48_BUSY; else if (cmd->resp_type & MMC_RSP_PRESENT) xfertyp |= COMMAND_RSPTYP_48; - if ((cpu_is_mx50() || cpu_is_mx51() || cpu_is_mx53()) && - cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) + if ((host->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) && + (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)) xfertyp |= SDHCI_CMD_ABORTCMD; return COMMAND_CMD(cmd->cmdidx) | xfertyp; @@ -273,12 +326,12 @@ esdhc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data) } /* Figure out the transfer arguments */ - xfertyp = esdhc_xfertyp(cmd, data); + xfertyp = esdhc_xfertyp(host, cmd, data); /* Send the command */ esdhc_write32(regs + SDHCI_ARGUMENT, cmd->cmdarg); - if (cpu_is_mx6()) { + if (esdhc_is_usdhc(host)) { /* write lower-half of xfertyp to mixctrl */ mixctrl = xfertyp & 0xFFFF; /* Keep the bits 22-25 of the register as is */ @@ -525,7 +578,7 @@ static int esdhc_reset(struct fsl_esdhc_host *host) SYSCTL_RSTA); /* extra register reset for i.MX6 Solo/DualLite */ - if (cpu_is_mx6()) { + if (esdhc_is_usdhc(host)) { /* reset bit FBCLK_SEL */ val = esdhc_read32(regs + IMX_SDHCI_MIXCTRL); val &= ~IMX_SDHCI_MIX_CTRL_FBCLK_SEL; @@ -570,6 +623,10 @@ static int fsl_esdhc_probe(struct device_d *dev) host = xzalloc(sizeof(*host)); mci = &host->mci; + host->socdata = of_device_get_match_data(dev); + if (!host->socdata) + return -EINVAL; + host->clk = clk_get(dev, NULL); if (IS_ERR(host->clk)) return PTR_ERR(host->clk); @@ -634,22 +691,44 @@ static int fsl_esdhc_probe(struct device_d *dev) return mci_register(&host->mci); } +static struct esdhc_soc_data esdhc_imx25_data = { + .flags = ESDHC_FLAG_ENGCM07207, +}; + +static struct esdhc_soc_data esdhc_imx50_data = { + .flags = ESDHC_FLAG_MULTIBLK_NO_INT, + /* .flags = 0, */ +}; + +static struct esdhc_soc_data esdhc_imx51_data = { + .flags = ESDHC_FLAG_MULTIBLK_NO_INT, + /* .flags = 0, */ +}; + +static struct esdhc_soc_data esdhc_imx53_data = { + .flags = ESDHC_FLAG_MULTIBLK_NO_INT, +}; + +static struct esdhc_soc_data usdhc_imx6q_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING, +}; + +static struct esdhc_soc_data usdhc_imx6sl_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536 + | ESDHC_FLAG_HS200, +}; + + static __maybe_unused struct of_device_id fsl_esdhc_compatible[] = { - { - .compatible = "fsl,imx25-esdhc", - }, { - .compatible = "fsl,imx50-esdhc", - }, { - .compatible = "fsl,imx51-esdhc", - }, { - .compatible = "fsl,imx53-esdhc", - }, { - .compatible = "fsl,imx6q-usdhc", - }, { - .compatible = "fsl,imx6sl-usdhc", - }, { - /* sentinel */ - } + + { .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data }, + { .compatible = "fsl,imx50-esdhc", .data = &esdhc_imx50_data }, + { .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data }, + { .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data }, + { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data }, + { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data }, + { /* sentinel */ } }; static struct driver_d fsl_esdhc_driver = { -- cgit v1.2.3 From 05f625a9e1ecab34a6e7a8eb96f10ff8be2c4856 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:14:09 -0800 Subject: i.MX: esdhc: Request "per" clock explicitly Calling clk_get() with NULL as the second argument will give us "ipg" clock as a result. The actual clock feeding into the peripheral is "per" and, depending on the SoC, "ipg" and "per" may be separated by a clock divider, so querying "ipg"'s rate may not result in rate that does not represent the actual peripheral clock rate. Change the code to request "per" as our peripheral clock to avoid aforementioned problem. Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/mci/imx-esdhc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c index 764a106453..d72e3f8c80 100644 --- a/drivers/mci/imx-esdhc.c +++ b/drivers/mci/imx-esdhc.c @@ -627,7 +627,7 @@ static int fsl_esdhc_probe(struct device_d *dev) if (!host->socdata) return -EINVAL; - host->clk = clk_get(dev, NULL); + host->clk = clk_get(dev, "per"); if (IS_ERR(host->clk)) return PTR_ERR(host->clk); -- cgit v1.2.3 From 2de277264c27a5baceff014678823c8469edd4aa Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:14:14 -0800 Subject: i.MX: fec: Enable all clocks specified for FEC For some i.MX variants more than just "ipg" clock need to be enabled for Ethernet to function, so change the code to enable all of the clock defined for FEC node (this is what analogous Linux driver does as well). Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/net/fec_imx.c | 71 +++++++++++++++++++++++++++++++++++++++++++-------- drivers/net/fec_imx.h | 10 +++++++- 2 files changed, 70 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fec_imx.c b/drivers/net/fec_imx.c index 8bc7c2993a..1be5b9de2d 100644 --- a/drivers/net/fec_imx.c +++ b/drivers/net/fec_imx.c @@ -51,7 +51,7 @@ static int fec_miibus_read(struct mii_bus *bus, int phyAddr, int regAddr) uint32_t phy; /* convenient holder for the PHY */ uint64_t start; - writel(((clk_get_rate(fec->clk) >> 20) / 5) << 1, + writel(((clk_get_rate(fec->clk[FEC_CLK_IPG]) >> 20) / 5) << 1, fec->regs + FEC_MII_SPEED); /* * reading from any PHY's register is done by properly @@ -94,7 +94,7 @@ static int fec_miibus_write(struct mii_bus *bus, int phyAddr, uint32_t phy; /* convenient holder for the PHY */ uint64_t start; - writel(((clk_get_rate(fec->clk) >> 20) / 5) << 1, + writel(((clk_get_rate(fec->clk[FEC_CLK_IPG]) >> 20) / 5) << 1, fec->regs + FEC_MII_SPEED); reg = regAddr << FEC_MII_DATA_RA_SHIFT; @@ -287,7 +287,7 @@ static int fec_init(struct eth_device *dev) * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock * and do not drop the Preamble. */ - writel(((clk_get_rate(fec->clk) >> 20) / 5) << 1, + writel(((clk_get_rate(fec->clk[FEC_CLK_IPG]) >> 20) / 5) << 1, fec->regs + FEC_MII_SPEED); if (fec->interface == PHY_INTERFACE_MODE_RMII) { @@ -651,6 +651,59 @@ static int fec_probe_dt(struct device_d *dev, struct fec_priv *fec) return -ENODEV; } #endif + +static int fec_clk_enable(struct fec_priv *fec) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fec->clk); i++) { + const int err = clk_enable(fec->clk[i]); + if (err < 0) + return err; + } + + return 0; +} + +static void fec_clk_disable(struct fec_priv *fec) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fec->clk); i++) { + if (!IS_ERR_OR_NULL(fec->clk[i])) + clk_disable(fec->clk[i]); + } +} + +static void fec_clk_put(struct fec_priv *fec) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fec->clk); i++) { + if (!IS_ERR_OR_NULL(fec->clk[i])) + clk_put(fec->clk[i]); + } +} + +static int fec_clk_get(struct fec_priv *fec) +{ + int i, err = 0; + static const char *clk_names[ARRAY_SIZE(fec->clk)] = { + "ipg", "ahb", "ptp" + }; + + for (i = 0; i < ARRAY_SIZE(fec->clk); i++) { + fec->clk[i] = clk_get(fec->edev.parent, clk_names[i]); + if (IS_ERR(fec->clk[i])) { + err = PTR_ERR(fec->clk[i]); + fec_clk_put(fec); + break; + } + } + + return err; +} + static int fec_probe(struct device_d *dev) { struct resource *iores; @@ -681,13 +734,11 @@ static int fec_probe(struct device_d *dev) edev->set_ethaddr = fec_set_hwaddr; edev->parent = dev; - fec->clk = clk_get(dev, NULL); - if (IS_ERR(fec->clk)) { - ret = PTR_ERR(fec->clk); + ret = fec_clk_get(fec); + if (ret < 0) goto err_free; - } - ret = clk_enable(fec->clk); + ret = fec_clk_enable(fec); if (ret < 0) goto put_clk; @@ -787,9 +838,9 @@ free_gpio: release_res: release_region(iores); disable_clk: - clk_disable(fec->clk); + fec_clk_disable(fec); put_clk: - clk_put(fec->clk); + fec_clk_put(fec); err_free: free(fec); return ret; diff --git a/drivers/net/fec_imx.h b/drivers/net/fec_imx.h index 1947e60f69..85d51bad60 100644 --- a/drivers/net/fec_imx.h +++ b/drivers/net/fec_imx.h @@ -129,6 +129,14 @@ enum fec_type { FEC_TYPE_IMX6, }; +enum fec_clock { + FEC_CLK_IPG, + FEC_CLK_AHB, + FEC_CLK_PTP, + + FEC_CLK_NUM +}; + /** * @brief i.MX27-FEC private structure */ @@ -144,7 +152,7 @@ struct fec_priv { u32 phy_flags; struct mii_bus miibus; void (*phy_init)(struct phy_device *dev); - struct clk *clk; + struct clk *clk[FEC_CLK_NUM]; enum fec_type type; }; -- cgit v1.2.3 From 882703195fb43630d4004bd371a3f4a9d1eed2da Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:14:15 -0800 Subject: i.MX: fec: Add support for Vybrid variant Add support for Vybrid variant of this IP block Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/net/fec_imx.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/fec_imx.c b/drivers/net/fec_imx.c index 1be5b9de2d..e2b25fe375 100644 --- a/drivers/net/fec_imx.c +++ b/drivers/net/fec_imx.c @@ -869,6 +869,9 @@ static __maybe_unused struct of_device_id imx_fec_dt_ids[] = { }, { .compatible = "fsl,imx6sx-fec", .data = (void *)FEC_TYPE_IMX6, + }, { + .compatible = "fsl,mvf600-fec", + .data = (void *)FEC_TYPE_IMX6, }, { /* sentinel */ } -- cgit v1.2.3 From 1b2cc689fc2db0db56c617e789906a684b22097a Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:14:16 -0800 Subject: gpio: Add GPIO driver for Vybrid Add GPIO driver for VF610 Family of SoCs (based on analogous driver from Linux kernel) Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/gpio/Kconfig | 3 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-vf610.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 drivers/gpio/gpio-vf610.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ab919c95f5..fe62778b3c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -49,6 +49,9 @@ config GPIO_GENERIC_PLATFORM config GPIO_IMX def_bool ARCH_IMX +config GPIO_VF610 + def_bool ARCH_VF610 + config GPIO_MXS def_bool ARCH_MXS diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 8767eed1e8..248100f0fe 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o obj-$(CONFIG_GPIO_DESIGNWARE) += gpio-dw.o +obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c new file mode 100644 index 0000000000..7c8d1e4c98 --- /dev/null +++ b/drivers/gpio/gpio-vf610.c @@ -0,0 +1,166 @@ +/* + * vf610 GPIO support through PORT and GPIO module + * + * Copyright (c) 2014 Toradex AG. + * + * Author: Stefan Agner . + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define VF610_GPIO_PER_PORT 32 +#define PINCTRL_BASE 2 +#define COUNT 3 + +struct vf610_gpio_port { + struct gpio_chip chip; + void __iomem *gpio_base; + unsigned int pinctrl_base; +}; + +#define GPIO_PDOR 0x00 +#define GPIO_PSOR 0x04 +#define GPIO_PCOR 0x08 +#define GPIO_PTOR 0x0c +#define GPIO_PDIR 0x10 + +static const struct of_device_id vf610_gpio_dt_ids[] = { + { .compatible = "fsl,vf610-gpio" }, + { /* sentinel */ } +}; + + +static int vf610_gpio_get_value(struct gpio_chip *chip, unsigned int gpio) +{ + struct vf610_gpio_port *port = + container_of(chip, struct vf610_gpio_port, chip); + + return !!(readl(port->gpio_base + GPIO_PDIR) & BIT(gpio)); +} + +static void vf610_gpio_set_value(struct gpio_chip *chip, + unsigned int gpio, int val) +{ + struct vf610_gpio_port *port = + container_of(chip, struct vf610_gpio_port, chip); + unsigned long mask = BIT(gpio); + + writel(mask, port->gpio_base + ((val) ? GPIO_PSOR : GPIO_PCOR)); +} + +static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + struct vf610_gpio_port *port = + container_of(chip, struct vf610_gpio_port, chip); + + return pinctrl_gpio_direction_input(port->pinctrl_base + gpio); +} + +static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, + int value) +{ + struct vf610_gpio_port *port = + container_of(chip, struct vf610_gpio_port, chip); + + vf610_gpio_set_value(chip, gpio, value); + + return pinctrl_gpio_direction_output(port->pinctrl_base + gpio); +} + +static int vf610_gpio_get_direction(struct gpio_chip *chip, unsigned gpio) +{ + struct vf610_gpio_port *port = + container_of(chip, struct vf610_gpio_port, chip); + + return pinctrl_gpio_get_direction(port->pinctrl_base + gpio); +} + +static struct gpio_ops vf610_gpio_ops = { + .direction_input = vf610_gpio_direction_input, + .direction_output = vf610_gpio_direction_output, + .get = vf610_gpio_get_value, + .set = vf610_gpio_set_value, + .get_direction = vf610_gpio_get_direction, +}; + +static int vf610_gpio_probe(struct device_d *dev) +{ + int ret, size; + struct resource *iores; + struct vf610_gpio_port *port; + const __be32 *gpio_ranges; + + port = xzalloc(sizeof(*port)); + if (!port) + return -ENOMEM; + + gpio_ranges = of_get_property(dev->device_node, "gpio-ranges", &size); + if (!gpio_ranges) { + dev_err(dev, "Couldn't read 'gpio-ranges' propery of %s\n", + dev->device_node->full_name); + ret = -EINVAL; + goto free_port; + } + + port->pinctrl_base = be32_to_cpu(gpio_ranges[PINCTRL_BASE]); + port->chip.ngpio = be32_to_cpu(gpio_ranges[COUNT]); + + iores = dev_request_mem_resource(dev, 1); + if (IS_ERR(iores)) { + ret = PTR_ERR(iores); + dev_dbg(dev, "Failed to request memory resource\n"); + goto free_port; + } + + port->gpio_base = IOMEM(iores->start); + + port->chip.ops = &vf610_gpio_ops; + if (dev->id < 0) { + port->chip.base = of_alias_get_id(dev->device_node, "gpio"); + if (port->chip.base < 0) { + ret = port->chip.base; + dev_dbg(dev, "Failed to get GPIO alias\n"); + goto free_port; + } + } else { + port->chip.base = dev->id; + } + + + port->chip.base *= VF610_GPIO_PER_PORT; + port->chip.dev = dev; + gpiochip_add(&port->chip); + + return 0; + +free_port: + free(port); + return ret; +} + +static struct driver_d vf610_gpio_driver = { + .name = "gpio-vf610", + .probe = vf610_gpio_probe, + .of_compatible = DRV_OF_COMPAT(vf610_gpio_dt_ids), +}; + +static int __init gpio_vf610_init(void) +{ + return platform_driver_register(&vf610_gpio_driver); +} +core_initcall(gpio_vf610_init); -- cgit v1.2.3