diff --git a/arch/arm/dts/vf610-twr.dts b/arch/arm/dts/vf610-twr.dts index 54b4435..5947fdb 100644 --- a/arch/arm/dts/vf610-twr.dts +++ b/arch/arm/dts/vf610-twr.dts @@ -12,3 +12,7 @@ &usbdev0 { status = "disabled"; }; + +&enet_ext { + clock-output-names = "enet_ext"; +}; diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index ed5f9d9..9dbe31c 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -668,7 +668,7 @@ config IMX_OCOTP tristate "i.MX6 On Chip OTP controller" - depends on ARCH_IMX6 + depends on ARCH_IMX6 || ARCH_VF610 depends on OFDEVICE help This adds support for the i.MX6 On-Chip OTP controller. Currently the diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index ee839f7..d0fe7ab 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -1,26 +1,23 @@ 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 db88db0..0000000 --- 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 faed631..0000000 --- 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 5f600a9..0000000 --- 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 546461b..0000000 --- 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 864d06e..0000000 --- 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 4b63244..0000000 --- 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 8d135c9..0000000 --- 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 af6c405..0000000 --- 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 c4c47a6..0000000 --- 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 8ac43be..0000000 --- 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 d758957..0000000 --- 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-imx6ul.c b/arch/arm/mach-imx/clk-imx6ul.c deleted file mode 100644 index 72b5fa2..0000000 --- a/arch/arm/mach-imx/clk-imx6ul.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright (C) 2015 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 "clk.h" - -#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16) -#define CCDR 0x4 - -static const char *pll_bypass_src_sels[] = { "osc", "dummy", }; -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 *ca7_secondary_sels[] = { "pll2_pfd2_396m", "pll2_bus", }; -static const char *step_sels[] = { "osc", "ca7_secondary_sel", }; -static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; -static const char *axi_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", }; -static const char *axi_sels[] = {"periph", "axi_alt_sel", }; -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 *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; -static const char *bch_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; -static const char *gpmi_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; -static const char *eim_slow_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd0_720m", }; -static const char *spdif_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll5_video_div", "pll3_usb_otg", }; -static const char *sai_sels[] = { "pll3_pfd2_508m", "pll5_video_div", "pll4_audio_div", }; -static const char *lcdif_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_540m", }; -static const char *sim_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", }; -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_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 *qspi1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", }; -static const char *enfc_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd3_454m", "dummy", "dummy", "dummy", }; -static const char *can_sels[] = { "pll3_60m", "osc", "pll3_80m", "dummy", }; -static const char *ecspi_sels[] = { "pll3_60m", "osc", }; -static const char *uart_sels[] = { "pll3_80m", "osc", }; -static const char *perclk_sels[] = { "ipg", "osc", }; -static const char *lcdif_sels[] = { "lcdif_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; -static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", }; -static const char *sim_sels[] = { "sim_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; - -static struct clk *clks[IMX6UL_CLK_END]; -static struct clk_onecell_data clk_data; - -static int const clks_init_on[] __initconst = { - IMX6UL_CLK_AIPSTZ1, IMX6UL_CLK_AIPSTZ2, IMX6UL_CLK_AIPSTZ3, - IMX6UL_CLK_AXI, IMX6UL_CLK_ARM, IMX6UL_CLK_ROM, - IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG, -}; - -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 int imx6_ccm_probe(struct device_d *dev) -{ - struct resource *iores; - void __iomem *base, *anatop_base, *ccm_base; - int i; - struct device_node *ccm_node = dev->device_node; - - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - ccm_base = IOMEM(iores->start); - - base = anatop_base; - - clks[IMX6UL_CLK_DUMMY] = clk_fixed("dummy", 0); - - base = IOMEM(MX6_ANATOP_BASE_ADDR); - - clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - clks[IMX6UL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - clks[IMX6UL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - clks[IMX6UL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - clks[IMX6UL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - clks[IMX6UL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - clks[IMX6UL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); - - clks[IMX6UL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f); - clks[IMX6UL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1); - clks[IMX6UL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3); - clks[IMX6UL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f); - clks[IMX6UL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f); - clks[IMX6UL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3); - clks[IMX6UL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3); - - clks[IMX6UL_PLL1_BYPASS] = imx_clk_mux_p("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels)); - clks[IMX6UL_PLL2_BYPASS] = imx_clk_mux_p("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels)); - clks[IMX6UL_PLL3_BYPASS] = imx_clk_mux_p("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels)); - clks[IMX6UL_PLL4_BYPASS] = imx_clk_mux_p("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels)); - clks[IMX6UL_PLL5_BYPASS] = imx_clk_mux_p("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels)); - clks[IMX6UL_PLL6_BYPASS] = imx_clk_mux_p("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels)); - clks[IMX6UL_PLL7_BYPASS] = imx_clk_mux_p("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels)); - clks[IMX6UL_CLK_CSI_SEL] = imx_clk_mux_p("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels)); - - /* Do not bypass PLLs initially */ - clk_set_parent(clks[IMX6UL_PLL1_BYPASS], clks[IMX6UL_CLK_PLL1]); - clk_set_parent(clks[IMX6UL_PLL2_BYPASS], clks[IMX6UL_CLK_PLL2]); - clk_set_parent(clks[IMX6UL_PLL3_BYPASS], clks[IMX6UL_CLK_PLL3]); - clk_set_parent(clks[IMX6UL_PLL4_BYPASS], clks[IMX6UL_CLK_PLL4]); - clk_set_parent(clks[IMX6UL_PLL5_BYPASS], clks[IMX6UL_CLK_PLL5]); - clk_set_parent(clks[IMX6UL_PLL6_BYPASS], clks[IMX6UL_CLK_PLL6]); - clk_set_parent(clks[IMX6UL_PLL7_BYPASS], clks[IMX6UL_CLK_PLL7]); - - clks[IMX6UL_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1); - clks[IMX6UL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13); - clks[IMX6UL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13); - clks[IMX6UL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13); - clks[IMX6UL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13); - clks[IMX6UL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13); - clks[IMX6UL_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 many need to enable/disable usbphy's parent - */ - clks[IMX6UL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20); - clks[IMX6UL_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[IMX6UL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6); - clks[IMX6UL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6); - - /* name parent_name reg idx */ - clks[IMX6UL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); - clks[IMX6UL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); - clks[IMX6UL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2); - clks[IMX6UL_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3); - clks[IMX6UL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0); - clks[IMX6UL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1); - clks[IMX6UL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2); - clks[IMX6UL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3); - - clks[IMX6UL_CLK_ENET_REF] = imx_clk_divider_table("enet_ref", "pll6_enet", - base + 0xe0, 0, 2, clk_enet_ref_table); - clks[IMX6UL_CLK_ENET2_REF] = imx_clk_divider_table("enet2_ref", "pll6_enet", - base + 0xe0, 2, 2, clk_enet_ref_table); - - clks[IMX6UL_CLK_ENET2_REF_125M] = imx_clk_gate("enet_ref_125m", "enet2_ref", base + 0xe0, 20); - clks[IMX6UL_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20); - clks[IMX6UL_CLK_ENET_PTP] = imx_clk_gate("enet_ptp", "enet_ptp_ref", base + 0xe0, 21); - - /* name parent_name mult div */ - clks[IMX6UL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2); - clks[IMX6UL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); - clks[IMX6UL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); - clks[IMX6UL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8); - - base = ccm_base; - - clks[IMX6UL_CA7_SECONDARY_SEL] = imx_clk_mux("ca7_secondary_sel", base + 0xc, 3, 1, ca7_secondary_sels, ARRAY_SIZE(ca7_secondary_sels)); - clks[IMX6UL_CLK_STEP] = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels)); - clks[IMX6UL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0x0c, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); - clks[IMX6UL_CLK_AXI_ALT_SEL] = imx_clk_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels)); - clks[IMX6UL_CLK_AXI_SEL] = imx_clk_mux("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels)); - clks[IMX6UL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); - clks[IMX6UL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels)); - clks[IMX6UL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); - clks[IMX6UL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)); - clks[IMX6UL_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels)); - clks[IMX6UL_CLK_GPMI_SEL] = imx_clk_mux("gpmi_sel", base + 0x1c, 19, 1, gpmi_sels, ARRAY_SIZE(gpmi_sels)); - clks[IMX6UL_CLK_BCH_SEL] = imx_clk_mux("bch_sel", base + 0x1c, 18, 1, bch_sels, ARRAY_SIZE(bch_sels)); - clks[IMX6UL_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); - clks[IMX6UL_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); - clks[IMX6UL_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", base + 0x1c, 14, 2, sai_sels, ARRAY_SIZE(sai_sels)); - clks[IMX6UL_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", base + 0x1c, 12, 2, sai_sels, ARRAY_SIZE(sai_sels)); - clks[IMX6UL_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", base + 0x1c, 10, 2, sai_sels, ARRAY_SIZE(sai_sels)); - clks[IMX6UL_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels)); - clks[IMX6UL_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels)); - clks[IMX6UL_CLK_CAN_SEL] = imx_clk_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels)); - clks[IMX6UL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels)); - clks[IMX6UL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels)); - clks[IMX6UL_CLK_LDB_DI0_SEL] = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels)); - clks[IMX6UL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels)); - clks[IMX6UL_CLK_SIM_PRE_SEL] = imx_clk_mux("sim_pre_sel", base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels)); - clks[IMX6UL_CLK_SIM_SEL] = imx_clk_mux("sim_sel", base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels)); - clks[IMX6UL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels)); - clks[IMX6UL_CLK_LCDIF_PRE_SEL] = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels)); - clks[IMX6UL_CLK_LCDIF_SEL] = imx_clk_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels)); - - clks[IMX6UL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels)); - clks[IMX6UL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels)); - - clks[IMX6UL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); - clks[IMX6UL_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7); - clks[IMX6UL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "qspi1_sel", 2, 7); - clks[IMX6UL_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "qspi1_sel", 1, 7); - - clks[IMX6UL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); - clks[IMX6UL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); - - clks[IMX6UL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); - clks[IMX6UL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); - clks[IMX6UL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); - clks[IMX6UL_CLK_LCDIF_PODF] = imx_clk_divider("lcdif_podf", "lcdif_pred", base + 0x18, 23, 3); - clks[IMX6UL_CLK_QSPI1_PDOF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3); - clks[IMX6UL_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3); - clks[IMX6UL_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6); - clks[IMX6UL_CLK_CAN_PODF] = imx_clk_divider("can_podf", "can_sel", base + 0x20, 2, 6); - clks[IMX6UL_CLK_GPMI_PODF] = imx_clk_divider("gpmi_podf", "gpmi_sel", base + 0x24, 22, 3); - clks[IMX6UL_CLK_BCH_PODF] = imx_clk_divider("bch_podf", "bch_sel", base + 0x24, 19, 3); - clks[IMX6UL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); - clks[IMX6UL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); - clks[IMX6UL_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6); - clks[IMX6UL_CLK_SAI3_PRED] = imx_clk_divider("sai3_pred", "sai3_sel", base + 0x28, 22, 3); - clks[IMX6UL_CLK_SAI3_PODF] = imx_clk_divider("sai3_podf", "sai3_pred", base + 0x28, 16, 6); - clks[IMX6UL_CLK_SAI1_PRED] = imx_clk_divider("sai1_pred", "sai1_sel", base + 0x28, 6, 3); - clks[IMX6UL_CLK_SAI1_PODF] = imx_clk_divider("sai1_podf", "sai1_pred", base + 0x28, 0, 6); - clks[IMX6UL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3); - clks[IMX6UL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6); - clks[IMX6UL_CLK_SAI2_PRED] = imx_clk_divider("sai2_pred", "sai2_sel", base + 0x2c, 6, 3); - clks[IMX6UL_CLK_SAI2_PODF] = imx_clk_divider("sai2_podf", "sai2_pred", base + 0x2c, 0, 6); - clks[IMX6UL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3); - clks[IMX6UL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3); - clks[IMX6UL_CLK_SIM_PODF] = imx_clk_divider("sim_podf", "sim_pre_sel", base + 0x34, 12, 3); - clks[IMX6UL_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6); - clks[IMX6UL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3); - clks[IMX6UL_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3); - - clks[IMX6UL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); - clks[IMX6UL_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2); - clks[IMX6UL_CLK_AXI_PODF] = imx_clk_busy_divider("axi_podf", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0); - clks[IMX6UL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); - - /* CCGR0 */ - clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0); - clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2); - clks[IMX6UL_CLK_APBHDMA] = imx_clk_gate2("apbh_dma", "bch_podf", base + 0x68, 4); - clks[IMX6UL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8); - clks[IMX6UL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10); - clks[IMX6UL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12); - clks[IMX6UL_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14); - clks[IMX6UL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_podf", base + 0x68, 16); - clks[IMX6UL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18); - clks[IMX6UL_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_podf", base + 0x68, 20); - clks[IMX6UL_CLK_GPT2_BUS] = imx_clk_gate2("gpt2_bus", "perclk", base + 0x68, 24); - clks[IMX6UL_CLK_GPT2_SERIAL] = imx_clk_gate2("gpt2_serial", "perclk", base + 0x68, 26); - clks[IMX6UL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28); - clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28); - clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30); - - /* CCGR1 */ - clks[IMX6UL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); - clks[IMX6UL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2); - clks[IMX6UL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4); - clks[IMX6UL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6); - clks[IMX6UL_CLK_ADC2] = imx_clk_gate2("adc2", "ipg", base + 0x6c, 8); - clks[IMX6UL_CLK_UART3_IPG] = imx_clk_gate2("uart3_ipg", "ipg", base + 0x6c, 10); - clks[IMX6UL_CLK_UART3_SERIAL] = imx_clk_gate2("uart3_serial", "uart_podf", base + 0x6c, 10); - clks[IMX6UL_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12); - clks[IMX6UL_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14); - clks[IMX6UL_CLK_ADC1] = imx_clk_gate2("adc1", "ipg", base + 0x6c, 16); - clks[IMX6UL_CLK_GPT1_BUS] = imx_clk_gate2("gpt1_bus", "perclk", base + 0x6c, 20); - clks[IMX6UL_CLK_GPT1_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22); - clks[IMX6UL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24); - clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24); - - /* CCGR2 */ - clks[IMX6UL_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2); - clks[IMX6UL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6); - clks[IMX6UL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8); - clks[IMX6UL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); - clks[IMX6UL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); - clks[IMX6UL_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif_podf", base + 0x70, 14); - clks[IMX6UL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28); - clks[IMX6UL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30); - - /* CCGR3 */ - clks[IMX6UL_CLK_UART5_IPG] = imx_clk_gate2("uart5_ipg", "ipg", base + 0x74, 2); - clks[IMX6UL_CLK_UART5_SERIAL] = imx_clk_gate2("uart5_serial", "uart_podf", base + 0x74, 2); - clks[IMX6UL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4); - clks[IMX6UL_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "ahb", base + 0x74, 4); - clks[IMX6UL_CLK_UART6_IPG] = imx_clk_gate2("uart6_ipg", "ipg", base + 0x74, 6); - clks[IMX6UL_CLK_UART6_SERIAL] = imx_clk_gate2("uart6_serial", "uart_podf", base + 0x74, 6); - clks[IMX6UL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10); - clks[IMX6UL_CLK_QSPI] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14); - clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16); - clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20); - clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24); - clks[IMX6UL_CLK_AXI] = imx_clk_gate("axi", "axi_podf", base + 0x74, 28); - - /* CCGR4 */ - clks[IMX6UL_CLK_PER_BCH] = imx_clk_gate2("per_bch", "bch_podf", base + 0x78, 12); - clks[IMX6UL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16); - clks[IMX6UL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18); - clks[IMX6UL_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20); - clks[IMX6UL_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22); - clks[IMX6UL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "bch_podf", base + 0x78, 24); - clks[IMX6UL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "gpmi_podf", base + 0x78, 26); - clks[IMX6UL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc_podf", base + 0x78, 28); - clks[IMX6UL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "bch_podf", base + 0x78, 30); - - /* CCGR5 */ - clks[IMX6UL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); - clks[IMX6UL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); - clks[IMX6UL_CLK_KPP] = imx_clk_gate2("kpp", "ipg", base + 0x7c, 8); - clks[IMX6UL_CLK_WDOG2] = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10); - clks[IMX6UL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); - clks[IMX6UL_CLK_UART1_IPG] = imx_clk_gate2("uart1_ipg", "ipg", base + 0x7c, 24); - clks[IMX6UL_CLK_UART1_SERIAL] = imx_clk_gate2("uart1_serial", "uart_podf", base + 0x7c, 24); - clks[IMX6UL_CLK_UART7_IPG] = imx_clk_gate2("uart7_ipg", "ipg", base + 0x7c, 26); - clks[IMX6UL_CLK_UART7_SERIAL] = imx_clk_gate2("uart7_serial", "uart_podf", base + 0x7c, 26); - - /* CCGR6 */ - clks[IMX6UL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); - clks[IMX6UL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); - clks[IMX6UL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); - clks[IMX6UL_CLK_SIM1] = imx_clk_gate2("sim1", "sim_sel", base + 0x80, 6); - clks[IMX6UL_CLK_SIM2] = imx_clk_gate2("sim2", "sim_sel", base + 0x80, 8); - clks[IMX6UL_CLK_EIM] = imx_clk_gate2("eim", "eim_slow_podf", base + 0x80, 10); - clks[IMX6UL_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16); - clks[IMX6UL_CLK_UART8_IPG] = imx_clk_gate2("uart8_ipg", "ipg", base + 0x80, 14); - clks[IMX6UL_CLK_UART8_SERIAL] = imx_clk_gate2("uart8_serial", "uart_podf", base + 0x80, 14); - clks[IMX6UL_CLK_WDOG3] = imx_clk_gate2("wdog3", "ipg", base + 0x80, 20); - clks[IMX6UL_CLK_I2C4] = imx_clk_gate2("i2c4", "perclk", base + 0x80, 24); - clks[IMX6UL_CLK_PWM5] = imx_clk_gate2("pwm5", "perclk", base + 0x80, 26); - clks[IMX6UL_CLK_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28); - clks[IMX6UL_CLK_PWM7] = imx_clk_gate2("pwm7", "perclk", base + 0x80, 30); - - /* 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); - - /* - * Lower the AHB clock rate before changing the parent clock source, - * as AHB clock rate can NOT be higher than 133MHz, but its parent - * will be switched from 396MHz PFD to 528MHz PLL in order to increase - * AXI clock rate, so we need to lower AHB rate first to make sure at - * any time, AHB rate is <= 133MHz. - */ - clk_set_rate(clks[IMX6UL_CLK_AHB], 99000000); - - /* Change periph_pre clock to pll2_bus to adjust AXI rate to 264MHz */ - clk_set_parent(clks[IMX6UL_CLK_PERIPH_CLK2_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]); - clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_CLK2]); - clk_set_parent(clks[IMX6UL_CLK_PERIPH_PRE], clks[IMX6UL_CLK_PLL2_BUS]); - clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_PRE]); - - /* Make sure AHB rate is 132MHz */ - clk_set_rate(clks[IMX6UL_CLK_AHB], 132000000); - - /* set perclk to from OSC */ - clk_set_parent(clks[IMX6UL_CLK_PERCLK_SEL], clks[IMX6UL_CLK_OSC]); - - clk_set_rate(clks[IMX6UL_CLK_ENET_REF], 50000000); - clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000); - clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000); - - /* keep all the clks on just for bringup */ - for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) - clk_enable(clks[clks_init_on[i]]); - - if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { - clk_enable(clks[IMX6UL_CLK_USBPHY1_GATE]); - clk_enable(clks[IMX6UL_CLK_USBPHY2_GATE]); - } - - clk_set_parent(clks[IMX6UL_CLK_CAN_SEL], clks[IMX6UL_CLK_PLL3_60M]); - clk_set_parent(clks[IMX6UL_CLK_SIM_PRE_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]); - - clk_set_parent(clks[IMX6UL_CLK_ENFC_SEL], clks[IMX6UL_CLK_PLL2_PFD2]); - - return 0; -} - -static __maybe_unused struct of_device_id imx6_ccm_dt_ids[] = { - { - .compatible = "fsl,imx6ul-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-pfd.c b/arch/arm/mach-imx/clk-pfd.c deleted file mode 100644 index 8f6d5ad..0000000 --- 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 f992134..0000000 --- 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 5ba07fa..0000000 --- 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 e38dcdf..0000000 --- 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 c5913e1..0000000 --- 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/arch/arm/mach-imx/ocotp.c b/arch/arm/mach-imx/ocotp.c index e1d0c25..68ff0ce 100644 --- a/arch/arm/mach-imx/ocotp.c +++ b/arch/arm/mach-imx/ocotp.c @@ -67,7 +67,6 @@ #define BF(value, field) (((value) << field) & field##_MASK) /* Other definitions */ -#define FUSE_REGS_COUNT (16 * 8) #define IMX6_OTP_DATA_ERROR_VAL 0xBADABADA #define DEF_RELAX 20 #define MAC_OFFSET (0x22 * 4) @@ -75,6 +74,7 @@ struct imx_ocotp_data { int num_regs; + u32 (*addr_to_offset)(u32 addr); }; struct ocotp_priv { @@ -86,6 +86,7 @@ int sense_enable; char ethaddr[6]; struct regmap_config map_config; + const struct imx_ocotp_data *data; }; static struct ocotp_priv *imx_ocotp; @@ -196,7 +197,8 @@ if (ret) return ret; } else { - *(u32 *)val = readl(priv->base + 0x400 + index * 0x10); + *(u32 *)val = readl(priv->base + + priv->data->addr_to_offset(index)); } return 0; @@ -276,7 +278,8 @@ if (ret < 0) return ret; } else { - writel(val, priv->base + 0x400 + index * 0x10); + writel(val, priv->base + + priv->data->addr_to_offset(index)); } if (priv->permanent_write_enable) @@ -438,7 +441,7 @@ void __iomem *base; struct ocotp_priv *priv; int ret = 0; - struct imx_ocotp_data *data; + const struct imx_ocotp_data *data; ret = dev_get_drvdata(dev, (const void **)&data); if (ret) @@ -453,6 +456,7 @@ priv = xzalloc(sizeof(*priv)); + priv->data = data; priv->base = base; priv->clk = clk_get(dev, NULL); if (IS_ERR(priv->clk)) @@ -491,12 +495,48 @@ return 0; } +static u32 imx6sl_addr_to_offset(u32 addr) +{ + return 0x400 + addr * 0x10; +} + +static u32 imx6q_addr_to_offset(u32 addr) +{ + u32 addendum = 0; + + if (addr > 0x2F) { + /* + * If we are reading past Bank 5, take into account a + * 0x100 bytes wide gap between Bank 5 and Bank 6 + */ + addendum += 0x100; + } + + + return imx6sl_addr_to_offset(addr) + addendum; +} + +static u32 vf610_addr_to_offset(u32 addr) +{ + if (addr == 0x04) + return 0x450; + else + return imx6q_addr_to_offset(addr); +} + static struct imx_ocotp_data imx6q_ocotp_data = { .num_regs = 512, + .addr_to_offset = imx6q_addr_to_offset, }; static struct imx_ocotp_data imx6sl_ocotp_data = { .num_regs = 256, + .addr_to_offset = imx6sl_addr_to_offset, +}; + +static struct imx_ocotp_data vf610_ocotp_data = { + .num_regs = 512, + .addr_to_offset = vf610_addr_to_offset, }; static __maybe_unused struct of_device_id imx_ocotp_dt_ids[] = { @@ -513,6 +553,9 @@ .compatible = "fsl,imx6ul-ocotp", .data = &imx6q_ocotp_data, }, { + .compatible = "fsl,vf610-ocotp", + .data = &vf610_ocotp_data, + }, { /* sentinel */ } }; diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 47ed7b1..a4e4ed0 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/ @@ -9,3 +9,4 @@ 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/clk-conf.c b/drivers/clk/clk-conf.c new file mode 100644 index 0000000..93271b4 --- /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 19377b8..1566bea 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 @@ 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); diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile new file mode 100644 index 0000000..65d7859 --- /dev/null +++ b/drivers/clk/imx/Makefile @@ -0,0 +1,22 @@ +obj-$(CONFIG_COMMON_CLK) += \ + clk-pllv1.o \ + clk-pllv2.o \ + clk-pllv3.o \ + clk-pfd.o \ + clk-gate2.o \ + clk-gate-exclusive.o \ + clk.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 +obj-$(CONFIG_ARCH_VF610) += clk-vf610.o diff --git a/drivers/clk/imx/clk-gate-exclusive.c b/drivers/clk/imx/clk-gate-exclusive.c new file mode 100644 index 0000000..db88db0 --- /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 0000000..f952f3e --- /dev/null +++ b/drivers/clk/imx/clk-gate2.c @@ -0,0 +1,147 @@ +/* + * 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; + u8 cgr_val; + 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 |= g->cgr_val << 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, 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; + 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, u8 cgr_val) +{ + struct clk *g; + int ret; + + g = clk_gate2_alloc(name , parent, reg, shift, cgr_val); + + 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, 0x3); + 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 0000000..5f600a9 --- /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 0000000..546461b --- /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 0000000..864d06e --- /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 0000000..4b63244 --- /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 0000000..8d135c9 --- /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 0000000..af6c405 --- /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 0000000..c4c47a6 --- /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 0000000..8ac43be --- /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 0000000..d758957 --- /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-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c new file mode 100644 index 0000000..72b5fa2 --- /dev/null +++ b/drivers/clk/imx/clk-imx6ul.c @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2015 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 "clk.h" + +#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16) +#define CCDR 0x4 + +static const char *pll_bypass_src_sels[] = { "osc", "dummy", }; +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 *ca7_secondary_sels[] = { "pll2_pfd2_396m", "pll2_bus", }; +static const char *step_sels[] = { "osc", "ca7_secondary_sel", }; +static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; +static const char *axi_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", }; +static const char *axi_sels[] = {"periph", "axi_alt_sel", }; +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 *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *bch_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *gpmi_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *eim_slow_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd0_720m", }; +static const char *spdif_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll5_video_div", "pll3_usb_otg", }; +static const char *sai_sels[] = { "pll3_pfd2_508m", "pll5_video_div", "pll4_audio_div", }; +static const char *lcdif_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_540m", }; +static const char *sim_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", }; +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_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 *qspi1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", }; +static const char *enfc_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd3_454m", "dummy", "dummy", "dummy", }; +static const char *can_sels[] = { "pll3_60m", "osc", "pll3_80m", "dummy", }; +static const char *ecspi_sels[] = { "pll3_60m", "osc", }; +static const char *uart_sels[] = { "pll3_80m", "osc", }; +static const char *perclk_sels[] = { "ipg", "osc", }; +static const char *lcdif_sels[] = { "lcdif_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; +static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", }; +static const char *sim_sels[] = { "sim_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; + +static struct clk *clks[IMX6UL_CLK_END]; +static struct clk_onecell_data clk_data; + +static int const clks_init_on[] __initconst = { + IMX6UL_CLK_AIPSTZ1, IMX6UL_CLK_AIPSTZ2, IMX6UL_CLK_AIPSTZ3, + IMX6UL_CLK_AXI, IMX6UL_CLK_ARM, IMX6UL_CLK_ROM, + IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG, +}; + +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 int imx6_ccm_probe(struct device_d *dev) +{ + struct resource *iores; + void __iomem *base, *anatop_base, *ccm_base; + int i; + struct device_node *ccm_node = dev->device_node; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + ccm_base = IOMEM(iores->start); + + base = anatop_base; + + clks[IMX6UL_CLK_DUMMY] = clk_fixed("dummy", 0); + + base = IOMEM(MX6_ANATOP_BASE_ADDR); + + clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6UL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6UL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6UL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6UL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6UL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6UL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + + clks[IMX6UL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f); + clks[IMX6UL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1); + clks[IMX6UL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3); + clks[IMX6UL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f); + clks[IMX6UL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f); + clks[IMX6UL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3); + clks[IMX6UL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3); + + clks[IMX6UL_PLL1_BYPASS] = imx_clk_mux_p("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels)); + clks[IMX6UL_PLL2_BYPASS] = imx_clk_mux_p("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels)); + clks[IMX6UL_PLL3_BYPASS] = imx_clk_mux_p("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels)); + clks[IMX6UL_PLL4_BYPASS] = imx_clk_mux_p("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels)); + clks[IMX6UL_PLL5_BYPASS] = imx_clk_mux_p("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels)); + clks[IMX6UL_PLL6_BYPASS] = imx_clk_mux_p("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels)); + clks[IMX6UL_PLL7_BYPASS] = imx_clk_mux_p("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels)); + clks[IMX6UL_CLK_CSI_SEL] = imx_clk_mux_p("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels)); + + /* Do not bypass PLLs initially */ + clk_set_parent(clks[IMX6UL_PLL1_BYPASS], clks[IMX6UL_CLK_PLL1]); + clk_set_parent(clks[IMX6UL_PLL2_BYPASS], clks[IMX6UL_CLK_PLL2]); + clk_set_parent(clks[IMX6UL_PLL3_BYPASS], clks[IMX6UL_CLK_PLL3]); + clk_set_parent(clks[IMX6UL_PLL4_BYPASS], clks[IMX6UL_CLK_PLL4]); + clk_set_parent(clks[IMX6UL_PLL5_BYPASS], clks[IMX6UL_CLK_PLL5]); + clk_set_parent(clks[IMX6UL_PLL6_BYPASS], clks[IMX6UL_CLK_PLL6]); + clk_set_parent(clks[IMX6UL_PLL7_BYPASS], clks[IMX6UL_CLK_PLL7]); + + clks[IMX6UL_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1); + clks[IMX6UL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13); + clks[IMX6UL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13); + clks[IMX6UL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13); + clks[IMX6UL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13); + clks[IMX6UL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13); + clks[IMX6UL_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 many need to enable/disable usbphy's parent + */ + clks[IMX6UL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20); + clks[IMX6UL_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[IMX6UL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6); + clks[IMX6UL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6); + + /* name parent_name reg idx */ + clks[IMX6UL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); + clks[IMX6UL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); + clks[IMX6UL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2); + clks[IMX6UL_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3); + clks[IMX6UL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0); + clks[IMX6UL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1); + clks[IMX6UL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2); + clks[IMX6UL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3); + + clks[IMX6UL_CLK_ENET_REF] = imx_clk_divider_table("enet_ref", "pll6_enet", + base + 0xe0, 0, 2, clk_enet_ref_table); + clks[IMX6UL_CLK_ENET2_REF] = imx_clk_divider_table("enet2_ref", "pll6_enet", + base + 0xe0, 2, 2, clk_enet_ref_table); + + clks[IMX6UL_CLK_ENET2_REF_125M] = imx_clk_gate("enet_ref_125m", "enet2_ref", base + 0xe0, 20); + clks[IMX6UL_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20); + clks[IMX6UL_CLK_ENET_PTP] = imx_clk_gate("enet_ptp", "enet_ptp_ref", base + 0xe0, 21); + + /* name parent_name mult div */ + clks[IMX6UL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2); + clks[IMX6UL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); + clks[IMX6UL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); + clks[IMX6UL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8); + + base = ccm_base; + + clks[IMX6UL_CA7_SECONDARY_SEL] = imx_clk_mux("ca7_secondary_sel", base + 0xc, 3, 1, ca7_secondary_sels, ARRAY_SIZE(ca7_secondary_sels)); + clks[IMX6UL_CLK_STEP] = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels)); + clks[IMX6UL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0x0c, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); + clks[IMX6UL_CLK_AXI_ALT_SEL] = imx_clk_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels)); + clks[IMX6UL_CLK_AXI_SEL] = imx_clk_mux("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels)); + clks[IMX6UL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); + clks[IMX6UL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels)); + clks[IMX6UL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); + clks[IMX6UL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)); + clks[IMX6UL_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels)); + clks[IMX6UL_CLK_GPMI_SEL] = imx_clk_mux("gpmi_sel", base + 0x1c, 19, 1, gpmi_sels, ARRAY_SIZE(gpmi_sels)); + clks[IMX6UL_CLK_BCH_SEL] = imx_clk_mux("bch_sel", base + 0x1c, 18, 1, bch_sels, ARRAY_SIZE(bch_sels)); + clks[IMX6UL_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6UL_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6UL_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", base + 0x1c, 14, 2, sai_sels, ARRAY_SIZE(sai_sels)); + clks[IMX6UL_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", base + 0x1c, 12, 2, sai_sels, ARRAY_SIZE(sai_sels)); + clks[IMX6UL_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", base + 0x1c, 10, 2, sai_sels, ARRAY_SIZE(sai_sels)); + clks[IMX6UL_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels)); + clks[IMX6UL_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels)); + clks[IMX6UL_CLK_CAN_SEL] = imx_clk_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels)); + clks[IMX6UL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels)); + clks[IMX6UL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels)); + clks[IMX6UL_CLK_LDB_DI0_SEL] = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels)); + clks[IMX6UL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels)); + clks[IMX6UL_CLK_SIM_PRE_SEL] = imx_clk_mux("sim_pre_sel", base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels)); + clks[IMX6UL_CLK_SIM_SEL] = imx_clk_mux("sim_sel", base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels)); + clks[IMX6UL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels)); + clks[IMX6UL_CLK_LCDIF_PRE_SEL] = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels)); + clks[IMX6UL_CLK_LCDIF_SEL] = imx_clk_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels)); + + clks[IMX6UL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels)); + clks[IMX6UL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels)); + + clks[IMX6UL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); + clks[IMX6UL_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7); + clks[IMX6UL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "qspi1_sel", 2, 7); + clks[IMX6UL_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "qspi1_sel", 1, 7); + + clks[IMX6UL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); + clks[IMX6UL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); + + clks[IMX6UL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); + clks[IMX6UL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); + clks[IMX6UL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); + clks[IMX6UL_CLK_LCDIF_PODF] = imx_clk_divider("lcdif_podf", "lcdif_pred", base + 0x18, 23, 3); + clks[IMX6UL_CLK_QSPI1_PDOF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3); + clks[IMX6UL_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3); + clks[IMX6UL_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6); + clks[IMX6UL_CLK_CAN_PODF] = imx_clk_divider("can_podf", "can_sel", base + 0x20, 2, 6); + clks[IMX6UL_CLK_GPMI_PODF] = imx_clk_divider("gpmi_podf", "gpmi_sel", base + 0x24, 22, 3); + clks[IMX6UL_CLK_BCH_PODF] = imx_clk_divider("bch_podf", "bch_sel", base + 0x24, 19, 3); + clks[IMX6UL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); + clks[IMX6UL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); + clks[IMX6UL_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6); + clks[IMX6UL_CLK_SAI3_PRED] = imx_clk_divider("sai3_pred", "sai3_sel", base + 0x28, 22, 3); + clks[IMX6UL_CLK_SAI3_PODF] = imx_clk_divider("sai3_podf", "sai3_pred", base + 0x28, 16, 6); + clks[IMX6UL_CLK_SAI1_PRED] = imx_clk_divider("sai1_pred", "sai1_sel", base + 0x28, 6, 3); + clks[IMX6UL_CLK_SAI1_PODF] = imx_clk_divider("sai1_podf", "sai1_pred", base + 0x28, 0, 6); + clks[IMX6UL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3); + clks[IMX6UL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6); + clks[IMX6UL_CLK_SAI2_PRED] = imx_clk_divider("sai2_pred", "sai2_sel", base + 0x2c, 6, 3); + clks[IMX6UL_CLK_SAI2_PODF] = imx_clk_divider("sai2_podf", "sai2_pred", base + 0x2c, 0, 6); + clks[IMX6UL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3); + clks[IMX6UL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3); + clks[IMX6UL_CLK_SIM_PODF] = imx_clk_divider("sim_podf", "sim_pre_sel", base + 0x34, 12, 3); + clks[IMX6UL_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6); + clks[IMX6UL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3); + clks[IMX6UL_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3); + + clks[IMX6UL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); + clks[IMX6UL_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2); + clks[IMX6UL_CLK_AXI_PODF] = imx_clk_busy_divider("axi_podf", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0); + clks[IMX6UL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); + + /* CCGR0 */ + clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0); + clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2); + clks[IMX6UL_CLK_APBHDMA] = imx_clk_gate2("apbh_dma", "bch_podf", base + 0x68, 4); + clks[IMX6UL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8); + clks[IMX6UL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10); + clks[IMX6UL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12); + clks[IMX6UL_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14); + clks[IMX6UL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_podf", base + 0x68, 16); + clks[IMX6UL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18); + clks[IMX6UL_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_podf", base + 0x68, 20); + clks[IMX6UL_CLK_GPT2_BUS] = imx_clk_gate2("gpt2_bus", "perclk", base + 0x68, 24); + clks[IMX6UL_CLK_GPT2_SERIAL] = imx_clk_gate2("gpt2_serial", "perclk", base + 0x68, 26); + clks[IMX6UL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28); + clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28); + clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30); + + /* CCGR1 */ + clks[IMX6UL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); + clks[IMX6UL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2); + clks[IMX6UL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4); + clks[IMX6UL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6); + clks[IMX6UL_CLK_ADC2] = imx_clk_gate2("adc2", "ipg", base + 0x6c, 8); + clks[IMX6UL_CLK_UART3_IPG] = imx_clk_gate2("uart3_ipg", "ipg", base + 0x6c, 10); + clks[IMX6UL_CLK_UART3_SERIAL] = imx_clk_gate2("uart3_serial", "uart_podf", base + 0x6c, 10); + clks[IMX6UL_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12); + clks[IMX6UL_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14); + clks[IMX6UL_CLK_ADC1] = imx_clk_gate2("adc1", "ipg", base + 0x6c, 16); + clks[IMX6UL_CLK_GPT1_BUS] = imx_clk_gate2("gpt1_bus", "perclk", base + 0x6c, 20); + clks[IMX6UL_CLK_GPT1_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22); + clks[IMX6UL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24); + clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24); + + /* CCGR2 */ + clks[IMX6UL_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2); + clks[IMX6UL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6); + clks[IMX6UL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8); + clks[IMX6UL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); + clks[IMX6UL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); + clks[IMX6UL_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif_podf", base + 0x70, 14); + clks[IMX6UL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28); + clks[IMX6UL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30); + + /* CCGR3 */ + clks[IMX6UL_CLK_UART5_IPG] = imx_clk_gate2("uart5_ipg", "ipg", base + 0x74, 2); + clks[IMX6UL_CLK_UART5_SERIAL] = imx_clk_gate2("uart5_serial", "uart_podf", base + 0x74, 2); + clks[IMX6UL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4); + clks[IMX6UL_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "ahb", base + 0x74, 4); + clks[IMX6UL_CLK_UART6_IPG] = imx_clk_gate2("uart6_ipg", "ipg", base + 0x74, 6); + clks[IMX6UL_CLK_UART6_SERIAL] = imx_clk_gate2("uart6_serial", "uart_podf", base + 0x74, 6); + clks[IMX6UL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10); + clks[IMX6UL_CLK_QSPI] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14); + clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16); + clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20); + clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24); + clks[IMX6UL_CLK_AXI] = imx_clk_gate("axi", "axi_podf", base + 0x74, 28); + + /* CCGR4 */ + clks[IMX6UL_CLK_PER_BCH] = imx_clk_gate2("per_bch", "bch_podf", base + 0x78, 12); + clks[IMX6UL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16); + clks[IMX6UL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18); + clks[IMX6UL_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20); + clks[IMX6UL_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22); + clks[IMX6UL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "bch_podf", base + 0x78, 24); + clks[IMX6UL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "gpmi_podf", base + 0x78, 26); + clks[IMX6UL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc_podf", base + 0x78, 28); + clks[IMX6UL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "bch_podf", base + 0x78, 30); + + /* CCGR5 */ + clks[IMX6UL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); + clks[IMX6UL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); + clks[IMX6UL_CLK_KPP] = imx_clk_gate2("kpp", "ipg", base + 0x7c, 8); + clks[IMX6UL_CLK_WDOG2] = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10); + clks[IMX6UL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); + clks[IMX6UL_CLK_UART1_IPG] = imx_clk_gate2("uart1_ipg", "ipg", base + 0x7c, 24); + clks[IMX6UL_CLK_UART1_SERIAL] = imx_clk_gate2("uart1_serial", "uart_podf", base + 0x7c, 24); + clks[IMX6UL_CLK_UART7_IPG] = imx_clk_gate2("uart7_ipg", "ipg", base + 0x7c, 26); + clks[IMX6UL_CLK_UART7_SERIAL] = imx_clk_gate2("uart7_serial", "uart_podf", base + 0x7c, 26); + + /* CCGR6 */ + clks[IMX6UL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); + clks[IMX6UL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); + clks[IMX6UL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); + clks[IMX6UL_CLK_SIM1] = imx_clk_gate2("sim1", "sim_sel", base + 0x80, 6); + clks[IMX6UL_CLK_SIM2] = imx_clk_gate2("sim2", "sim_sel", base + 0x80, 8); + clks[IMX6UL_CLK_EIM] = imx_clk_gate2("eim", "eim_slow_podf", base + 0x80, 10); + clks[IMX6UL_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16); + clks[IMX6UL_CLK_UART8_IPG] = imx_clk_gate2("uart8_ipg", "ipg", base + 0x80, 14); + clks[IMX6UL_CLK_UART8_SERIAL] = imx_clk_gate2("uart8_serial", "uart_podf", base + 0x80, 14); + clks[IMX6UL_CLK_WDOG3] = imx_clk_gate2("wdog3", "ipg", base + 0x80, 20); + clks[IMX6UL_CLK_I2C4] = imx_clk_gate2("i2c4", "perclk", base + 0x80, 24); + clks[IMX6UL_CLK_PWM5] = imx_clk_gate2("pwm5", "perclk", base + 0x80, 26); + clks[IMX6UL_CLK_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28); + clks[IMX6UL_CLK_PWM7] = imx_clk_gate2("pwm7", "perclk", base + 0x80, 30); + + /* 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); + + /* + * Lower the AHB clock rate before changing the parent clock source, + * as AHB clock rate can NOT be higher than 133MHz, but its parent + * will be switched from 396MHz PFD to 528MHz PLL in order to increase + * AXI clock rate, so we need to lower AHB rate first to make sure at + * any time, AHB rate is <= 133MHz. + */ + clk_set_rate(clks[IMX6UL_CLK_AHB], 99000000); + + /* Change periph_pre clock to pll2_bus to adjust AXI rate to 264MHz */ + clk_set_parent(clks[IMX6UL_CLK_PERIPH_CLK2_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]); + clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_CLK2]); + clk_set_parent(clks[IMX6UL_CLK_PERIPH_PRE], clks[IMX6UL_CLK_PLL2_BUS]); + clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_PRE]); + + /* Make sure AHB rate is 132MHz */ + clk_set_rate(clks[IMX6UL_CLK_AHB], 132000000); + + /* set perclk to from OSC */ + clk_set_parent(clks[IMX6UL_CLK_PERCLK_SEL], clks[IMX6UL_CLK_OSC]); + + clk_set_rate(clks[IMX6UL_CLK_ENET_REF], 50000000); + clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000); + clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000); + + /* keep all the clks on just for bringup */ + for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) + clk_enable(clks[clks_init_on[i]]); + + if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { + clk_enable(clks[IMX6UL_CLK_USBPHY1_GATE]); + clk_enable(clks[IMX6UL_CLK_USBPHY2_GATE]); + } + + clk_set_parent(clks[IMX6UL_CLK_CAN_SEL], clks[IMX6UL_CLK_PLL3_60M]); + clk_set_parent(clks[IMX6UL_CLK_SIM_PRE_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]); + + clk_set_parent(clks[IMX6UL_CLK_ENFC_SEL], clks[IMX6UL_CLK_PLL2_PFD2]); + + return 0; +} + +static __maybe_unused struct of_device_id imx6_ccm_dt_ids[] = { + { + .compatible = "fsl,imx6ul-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-pfd.c b/drivers/clk/imx/clk-pfd.c new file mode 100644 index 0000000..8f6d5ad --- /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 0000000..f992134 --- /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 0000000..5ba07fa --- /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 0000000..29c0f1c --- /dev/null +++ b/drivers/clk/imx/clk-pllv3.c @@ -0,0 +1,329 @@ +/* + * 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; + u32 div_shift; + 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_shift) & 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 << pll->div_shift); + val |= div << pll->div_shift; + 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_VF610: + pll->div_shift = 1; + 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-vf610.c b/drivers/clk/imx/clk-vf610.c new file mode 100644 index 0000000..9b9ac6c --- /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); diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c new file mode 100644 index 0000000..7488dfc --- /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 new file mode 100644 index 0000000..970f65c --- /dev/null +++ b/drivers/clk/imx/clk.h @@ -0,0 +1,123 @@ +#ifndef __IMX_CLK_H +#define __IMX_CLK_H + +struct clk *clk_gate2(const char *name, const char *parent, void __iomem *reg, + 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) +{ + 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_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) +{ + 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, 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); + +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_USB_VF610, + 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); + +void imx_check_clocks(struct clk *clks[], unsigned int count); + + +#endif /* __IMX_CLK_H */ diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 078deee..434c568 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -49,6 +49,9 @@ 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 2d5142d..f37dd08 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o obj-$(CONFIG_GPIO_DESIGNWARE) += gpio-dw.o obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.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 0000000..7c8d1e4 --- /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); diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index e407896..74f046d 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 @@ { 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,17 +170,33 @@ 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) +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); +} + #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 +218,16 @@ } #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 +246,11 @@ 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 +259,9 @@ return -EIO; } } - writeb(0, base + FSL_I2C_I2SR); + + fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode, + i2c_fsl, FSL_I2C_I2SR); return 0; } @@ -194,12 +269,11 @@ 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 +289,28 @@ 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); +#ifdef CONFIG_PPC 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); +#endif /* Enable I2C controller */ - writeb(0, base + FSL_I2C_I2SR); - writeb(I2CR_IEN, base + 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); /* 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 +323,7 @@ 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 +331,13 @@ 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 +349,14 @@ } /* Disable I2C controller, and force our state to stopped */ - writeb(0, base + 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 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 +371,6 @@ 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); @@ -349,6 +424,7 @@ 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; @@ -356,16 +432,16 @@ /* 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. @@ -374,20 +450,19 @@ * 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 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 +471,7 @@ __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 +486,7 @@ 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 +501,12 @@ 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(i2c_fsl->hwdata->i2sr_clr_opcode, + i2c_fsl, FSL_I2C_I2SR); if ( !(msgs->flags & I2C_M_DATA_ONLY) ) { dev_dbg(&adapter->dev, @@ -439,7 +514,7 @@ __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 +525,13 @@ } /* 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 +544,9 @@ * 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 +556,11 @@ 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 +572,6 @@ 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 +588,9 @@ /* 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) @@ -600,6 +674,13 @@ 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; @@ -623,8 +704,9 @@ 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(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); @@ -640,17 +722,33 @@ 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); diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c index 41f0562..951ac45 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 @@ 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 @@ } /* 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 @@ 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,7 +623,11 @@ host = xzalloc(sizeof(*host)); mci = &host->mci; - host->clk = clk_get(dev, NULL); + host->socdata = of_device_get_match_data(dev); + if (!host->socdata) + return -EINVAL; + + host->clk = clk_get(dev, "per"); if (IS_ERR(host->clk)) return PTR_ERR(host->clk); @@ -634,24 +691,48 @@ 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 struct esdhc_soc_data usdhc_imx6sx_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + | ESDHC_FLAG_HAVE_CAP1 | 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", - }, { - .compatible = "fsl,imx6sx-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 }, + { .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data }, + { /* sentinel */ } }; static struct driver_d fsl_esdhc_driver = { diff --git a/drivers/net/fec_imx.c b/drivers/net/fec_imx.c index 8bc7c29..e2b25fe 100644 --- a/drivers/net/fec_imx.c +++ b/drivers/net/fec_imx.c @@ -51,7 +51,7 @@ 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ 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; @@ -819,6 +870,9 @@ .compatible = "fsl,imx6sx-fec", .data = (void *)FEC_TYPE_IMX6, }, { + .compatible = "fsl,mvf600-fec", + .data = (void *)FEC_TYPE_IMX6, + }, { /* sentinel */ } }; diff --git a/drivers/net/fec_imx.h b/drivers/net/fec_imx.h index 1947e60..85d51ba 100644 --- a/drivers/net/fec_imx.h +++ b/drivers/net/fec_imx.h @@ -129,6 +129,14 @@ 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 @@ 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; }; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index b112d7e..4eab437 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -137,4 +137,9 @@ 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 189e777..7d1bae1 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -20,3 +20,4 @@ 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 0000000..52fb6d3 --- /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); diff --git a/include/linux/clk/clk-conf.h b/include/linux/clk/clk-conf.h new file mode 100644 index 0000000..8f4382e --- /dev/null +++ b/include/linux/clk/clk-conf.h @@ -0,0 +1,17 @@ +/* + * 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. + */ + +#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK_OF_PROVIDER) + +#include + +struct device_node; +int of_clk_set_defaults(struct device_node *node, bool clk_supplier); + +#endif