]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
Merge branch '2019-08-23-master-imports'
authorTom Rini <trini@konsulko.com>
Sat, 24 Aug 2019 12:32:22 +0000 (08:32 -0400)
committerTom Rini <trini@konsulko.com>
Sat, 24 Aug 2019 12:32:22 +0000 (08:32 -0400)
- Migrate CONFIG_MX_CYCLIC, CONFIG_FSL_USDHC and CONFIG_MXS_GPIO to
  Kconfig
- Fix some SPL/TPL and ARM64 dependencies

15 files changed:
cmd/clk.c
drivers/clk/Kconfig
drivers/clk/clk-uclass.c
drivers/clk/clk.c
drivers/clk/clk_fixed_rate.c
drivers/clk/clk_sandbox_ccf.c
drivers/clk/imx/Kconfig
drivers/clk/imx/Makefile
drivers/clk/imx/clk-composite-8m.c [new file with mode: 0644]
drivers/clk/imx/clk-imx8mm.c [new file with mode: 0644]
drivers/clk/imx/clk-pll14xx.c [new file with mode: 0644]
drivers/clk/imx/clk.h
include/clk.h
include/sandbox-clk.h
test/dm/clk_ccf.c

index 5402c87de7295ca8bd5f374a788b360dcc1e5a7e..74ad8685002461bb431c13dc32e41ef61c976b77 100644 (file)
--- a/cmd/clk.c
+++ b/cmd/clk.c
@@ -7,51 +7,70 @@
 #include <clk.h>
 #if defined(CONFIG_DM) && defined(CONFIG_CLK)
 #include <dm.h>
+#include <dm/device.h>
+#include <dm/root.h>
 #include <dm/device-internal.h>
+#include <linux/clk-provider.h>
 #endif
 
-int __weak soc_clk_dump(void)
-{
 #if defined(CONFIG_DM) && defined(CONFIG_CLK)
-       struct udevice *dev;
-       struct uclass *uc;
-       struct clk clk;
-       int ret;
-       ulong rate;
-
-       /* Device addresses start at 1 */
-       ret = uclass_get(UCLASS_CLK, &uc);
-       if (ret)
-               return ret;
-
-       uclass_foreach_dev(dev, uc) {
-               memset(&clk, 0, sizeof(clk));
-               ret = device_probe(dev);
-               if (ret)
-                       goto noclk;
+static void show_clks(struct udevice *dev, int depth, int last_flag)
+{
+       int i, is_last;
+       struct udevice *child;
+       struct clk *clkp;
+       u32 rate;
+
+       clkp = dev_get_clk_ptr(dev);
+       if (device_get_uclass_id(dev) == UCLASS_CLK && clkp) {
+               rate = clk_get_rate(clkp);
+
+       printf(" %-12u  %8d        ", rate, clkp->enable_count);
+
+       for (i = depth; i >= 0; i--) {
+               is_last = (last_flag >> i) & 1;
+               if (i) {
+                       if (is_last)
+                               printf("    ");
+                       else
+                               printf("|   ");
+               } else {
+                       if (is_last)
+                               printf("`-- ");
+                       else
+                               printf("|-- ");
+               }
+       }
 
-               ret = clk_request(dev, &clk);
-               if (ret)
-                       goto noclk;
+       printf("%s\n", dev->name);
+       }
 
-               rate = clk_get_rate(&clk);
-               clk_free(&clk);
+       list_for_each_entry(child, &dev->child_head, sibling_node) {
+               is_last = list_is_last(&child->sibling_node, &dev->child_head);
+               show_clks(child, depth + 1, (last_flag << 1) | is_last);
+       }
+}
 
-               if (rate == -ENODEV)
-                       goto noclk;
+int __weak soc_clk_dump(void)
+{
+       struct udevice *root;
 
-               printf("%-30.30s : %lu Hz\n", dev->name, rate);
-               continue;
-       noclk:
-               printf("%-30.30s : ? Hz\n", dev->name);
+       root = dm_root();
+       if (root) {
+               printf(" Rate               Usecnt      Name\n");
+               printf("------------------------------------------\n");
+               show_clks(root, -1, 0);
        }
 
        return 0;
+}
 #else
+int __weak soc_clk_dump(void)
+{
        puts("Not implemented\n");
        return 1;
-#endif
 }
+#endif
 
 static int do_clk_dump(cmd_tbl_t *cmdtp, int flag, int argc,
                       char *const argv[])
index a3f0171b45fb5ec60361f25711ded00a12191418..82cd8f623c45f5f45a3c53460c5a1eb07854c18d 100644 (file)
@@ -48,7 +48,6 @@ config CLK_BOSTON
 
 config SPL_CLK_CCF
        bool "SPL Common Clock Framework [CCF] support "
-       depends on SPL_CLK_IMX6Q
        help
          Enable this option if you want to (re-)use the Linux kernel's Common
          Clock Framework [CCF] code in U-Boot's SPL.
@@ -62,7 +61,6 @@ config SPL_CLK_COMPOSITE_CCF
 
 config CLK_CCF
        bool "Common Clock Framework [CCF] support "
-       depends on CLK_IMX6Q || SANDBOX_CLK_CCF
        help
          Enable this option if you want to (re-)use the Linux kernel's Common
          Clock Framework [CCF] code in U-Boot's clock driver.
index c66b6f3c4ebb4417ce73ab1964d4487af3358dc2..64c181f4ad3009e30cf6bbff3ce7714d3201c33f 100644 (file)
@@ -449,13 +449,45 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
 int clk_enable(struct clk *clk)
 {
        const struct clk_ops *ops = clk_dev_ops(clk->dev);
+       struct clk *clkp = NULL;
+       int ret;
 
        debug("%s(clk=%p)\n", __func__, clk);
 
-       if (!ops->enable)
-               return -ENOSYS;
+       if (CONFIG_IS_ENABLED(CLK_CCF)) {
+               /* Take id 0 as a non-valid clk, such as dummy */
+               if (clk->id && !clk_get_by_id(clk->id, &clkp)) {
+                       if (clkp->enable_count) {
+                               clkp->enable_count++;
+                               return 0;
+                       }
+                       if (clkp->dev->parent &&
+                           device_get_uclass_id(clkp->dev) == UCLASS_CLK) {
+                               ret = clk_enable(dev_get_clk_ptr(clkp->dev->parent));
+                               if (ret) {
+                                       printf("Enable %s failed\n",
+                                              clkp->dev->parent->name);
+                                       return ret;
+                               }
+                       }
+               }
 
-       return ops->enable(clk);
+               if (ops->enable) {
+                       ret = ops->enable(clk);
+                       if (ret) {
+                               printf("Enable %s failed\n", clk->dev->name);
+                               return ret;
+                       }
+               }
+               if (clkp)
+                       clkp->enable_count++;
+       } else {
+               if (!ops->enable)
+                       return -ENOSYS;
+               return ops->enable(clk);
+       }
+
+       return 0;
 }
 
 int clk_enable_bulk(struct clk_bulk *bulk)
@@ -474,13 +506,46 @@ int clk_enable_bulk(struct clk_bulk *bulk)
 int clk_disable(struct clk *clk)
 {
        const struct clk_ops *ops = clk_dev_ops(clk->dev);
+       struct clk *clkp = NULL;
+       int ret;
 
        debug("%s(clk=%p)\n", __func__, clk);
 
-       if (!ops->disable)
-               return -ENOSYS;
+       if (CONFIG_IS_ENABLED(CLK_CCF)) {
+               if (clk->id && !clk_get_by_id(clk->id, &clkp)) {
+                       if (clkp->enable_count == 0) {
+                               printf("clk %s already disabled\n",
+                                      clkp->dev->name);
+                               return 0;
+                       }
 
-       return ops->disable(clk);
+                       if (--clkp->enable_count > 0)
+                               return 0;
+               }
+
+               if (ops->disable) {
+                       ret = ops->disable(clk);
+                       if (ret)
+                               return ret;
+               }
+
+               if (clkp && clkp->dev->parent &&
+                   device_get_uclass_id(clkp->dev) == UCLASS_CLK) {
+                       ret = clk_disable(dev_get_clk_ptr(clkp->dev->parent));
+                       if (ret) {
+                               printf("Disable %s failed\n",
+                                      clkp->dev->parent->name);
+                               return ret;
+                       }
+               }
+       } else {
+               if (!ops->disable)
+                       return -ENOSYS;
+
+               return ops->disable(clk);
+       }
+
+       return 0;
 }
 
 int clk_disable_bulk(struct clk_bulk *bulk)
index 39b3087067a63b097b4c6b5d03e378c66f7b1fb6..1cf9987f6cbb8d87ca69d08ee1c361c62f8ee78f 100644 (file)
@@ -40,6 +40,7 @@ int clk_register(struct clk *clk, const char *drv_name,
                return ret;
        }
 
+       clk->enable_count = 0;
        /* Store back pointer to clk from udevice */
        clk->dev->uclass_priv = clk;
 
index 08cce0d79b71033a7d387d4e6ffe045c04958b8a..f51126793eaed285756b4af8d5cb157e8ef11934 100644 (file)
@@ -27,6 +27,7 @@ static int clk_fixed_rate_ofdata_to_platdata(struct udevice *dev)
        /* Make fixed rate clock accessible from higher level struct clk */
        dev->uclass_priv = clk;
        clk->dev = dev;
+       clk->enable_count = 0;
 
        return 0;
 }
index e126f18d8e96256f90914e0d0aaa548e849767db..9fa27229e18668305e41d65d7e6a8e1390f4d657 100644 (file)
@@ -25,6 +25,18 @@ struct clk_pllv3 {
        u32             div_shift;
 };
 
+int sandbox_clk_enable_count(struct clk *clk)
+{
+       struct clk *clkp = NULL;
+       int ret;
+
+       ret = clk_get_by_id(clk->id, &clkp);
+       if (ret)
+               return 0;
+
+       return clkp->enable_count;
+}
+
 static ulong clk_pllv3_get_rate(struct clk *clk)
 {
        unsigned long parent_rate = clk_get_parent_rate(clk);
@@ -254,6 +266,9 @@ static int sandbox_clk_ccf_probe(struct udevice *dev)
               sandbox_clk_composite("i2c", i2c_sels, ARRAY_SIZE(i2c_sels),
                                     &reg, 0));
 
+       clk_dm(SANDBOX_CLK_I2C_ROOT,
+              sandbox_clk_gate2("i2c_root", "i2c", base + 0x7c, 0));
+
        return 0;
 }
 
index 3e6a980c8c3933d4aa0905bb1afea072b18eaeb2..aae69cf9b08abb31f430030552e8110b9dd3fa8b 100644 (file)
@@ -20,3 +20,19 @@ config CLK_IMX8
        select CLK
        help
          This enables support clock driver for i.MX8 platforms.
+
+config SPL_CLK_IMX8MM
+       bool "SPL clock support for i.MX8MM"
+       depends on ARCH_IMX8M && SPL
+       select SPL_CLK
+       select SPL_CLK_CCF
+       help
+         This enables SPL DM/DTS support for clock driver in i.MX8MM
+
+config CLK_IMX8MM
+       bool "Clock support for i.MX8MM"
+       depends on ARCH_IMX8M
+       select CLK
+       select CLK_CCF
+       help
+         This enables support clock driver for i.MX8MM platforms.
index 105a58ca907eddb8c5b869a7f905a13b5034fa51..5ad7967fe982855af35828d249f79a3b755f4592 100644 (file)
@@ -10,3 +10,5 @@ ifdef CONFIG_CLK_IMX8
 obj-$(CONFIG_IMX8QXP) += clk-imx8qxp.o
 obj-$(CONFIG_IMX8QM) += clk-imx8qm.o
 endif
+obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MM) += clk-imx8mm.o clk-pll14xx.o \
+                               clk-composite-8m.o
diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c
new file mode 100644 (file)
index 0000000..95120d6
--- /dev/null
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <linux/clk-provider.h>
+#include <clk.h>
+#include "clk.h"
+
+#define UBOOT_DM_CLK_IMX_COMPOSITE "imx_clk_composite"
+
+#define PCG_PREDIV_SHIFT       16
+#define PCG_PREDIV_WIDTH       3
+#define PCG_PREDIV_MAX         8
+
+#define PCG_DIV_SHIFT          0
+#define PCG_DIV_WIDTH          6
+#define PCG_DIV_MAX            64
+
+#define PCG_PCS_SHIFT          24
+#define PCG_PCS_MASK           0x7
+
+#define PCG_CGC_SHIFT          28
+
+static unsigned long imx8m_clk_composite_divider_recalc_rate(struct clk *clk)
+{
+       struct clk_divider *divider = (struct clk_divider *)to_clk_divider(clk);
+       struct clk_composite *composite = (struct clk_composite *)clk->data;
+       ulong parent_rate = clk_get_parent_rate(&composite->clk);
+       unsigned long prediv_rate;
+       unsigned int prediv_value;
+       unsigned int div_value;
+
+       debug("%s: name %s prate: %lu reg: %p\n", __func__,
+             (&composite->clk)->dev->name, parent_rate, divider->reg);
+       prediv_value = readl(divider->reg) >> divider->shift;
+       prediv_value &= clk_div_mask(divider->width);
+
+       prediv_rate = divider_recalc_rate(clk, parent_rate, prediv_value,
+                                         NULL, divider->flags,
+                                         divider->width);
+
+       div_value = readl(divider->reg) >> PCG_DIV_SHIFT;
+       div_value &= clk_div_mask(PCG_DIV_WIDTH);
+
+       return divider_recalc_rate(clk, prediv_rate, div_value, NULL,
+                                  divider->flags, PCG_DIV_WIDTH);
+}
+
+static int imx8m_clk_composite_compute_dividers(unsigned long rate,
+                                               unsigned long parent_rate,
+                                               int *prediv, int *postdiv)
+{
+       int div1, div2;
+       int error = INT_MAX;
+       int ret = -EINVAL;
+
+       *prediv = 1;
+       *postdiv = 1;
+
+       for (div1 = 1; div1 <= PCG_PREDIV_MAX; div1++) {
+               for (div2 = 1; div2 <= PCG_DIV_MAX; div2++) {
+                       int new_error = ((parent_rate / div1) / div2) - rate;
+
+                       if (abs(new_error) < abs(error)) {
+                               *prediv = div1;
+                               *postdiv = div2;
+                               error = new_error;
+                               ret = 0;
+                       }
+               }
+       }
+       return ret;
+}
+
+/*
+ * The clk are bound to a dev, because it is part of composite clk
+ * use composite clk to get dev
+ */
+static ulong imx8m_clk_composite_divider_set_rate(struct clk *clk,
+                                                 unsigned long rate)
+{
+       struct clk_divider *divider = (struct clk_divider *)to_clk_divider(clk);
+       struct clk_composite *composite = (struct clk_composite *)clk->data;
+       ulong parent_rate = clk_get_parent_rate(&composite->clk);
+       int prediv_value;
+       int div_value;
+       int ret;
+       u32 val;
+
+       ret = imx8m_clk_composite_compute_dividers(rate, parent_rate,
+                                                  &prediv_value, &div_value);
+       if (ret)
+               return ret;
+
+       val = readl(divider->reg);
+       val &= ~((clk_div_mask(divider->width) << divider->shift) |
+                       (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT));
+
+       val |= (u32)(prediv_value  - 1) << divider->shift;
+       val |= (u32)(div_value - 1) << PCG_DIV_SHIFT;
+       writel(val, divider->reg);
+
+       return clk_get_rate(&composite->clk);
+}
+
+static const struct clk_ops imx8m_clk_composite_divider_ops = {
+       .get_rate = imx8m_clk_composite_divider_recalc_rate,
+       .set_rate = imx8m_clk_composite_divider_set_rate,
+};
+
+struct clk *imx8m_clk_composite_flags(const char *name,
+                                     const char * const *parent_names,
+                                     int num_parents, void __iomem *reg,
+                                     unsigned long flags)
+{
+       struct clk *clk = ERR_PTR(-ENOMEM);
+       struct clk_divider *div = NULL;
+       struct clk_gate *gate = NULL;
+       struct clk_mux *mux = NULL;
+
+       mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+       if (!mux)
+               goto fail;
+
+       mux->reg = reg;
+       mux->shift = PCG_PCS_SHIFT;
+       mux->mask = PCG_PCS_MASK;
+       mux->num_parents = num_parents;
+       mux->flags = flags;
+       mux->parent_names = parent_names;
+
+       div = kzalloc(sizeof(*div), GFP_KERNEL);
+       if (!div)
+               goto fail;
+
+       div->reg = reg;
+       div->shift = PCG_PREDIV_SHIFT;
+       div->width = PCG_PREDIV_WIDTH;
+       div->flags = CLK_DIVIDER_ROUND_CLOSEST | flags;
+
+       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+       if (!gate)
+               goto fail;
+
+       gate->reg = reg;
+       gate->bit_idx = PCG_CGC_SHIFT;
+       gate->flags = flags;
+
+       clk = clk_register_composite(NULL, name,
+                                    parent_names, num_parents,
+                                    &mux->clk, &clk_mux_ops, &div->clk,
+                                    &imx8m_clk_composite_divider_ops,
+                                    &gate->clk, &clk_gate_ops, flags);
+       if (IS_ERR(clk))
+               goto fail;
+
+       return clk;
+
+fail:
+       kfree(gate);
+       kfree(div);
+       kfree(mux);
+       return ERR_CAST(clk);
+}
diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c
new file mode 100644 (file)
index 0000000..f4913e7
--- /dev/null
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <dt-bindings/clock/imx8mm-clock.h>
+
+#include "clk.h"
+
+#define PLL_1416X_RATE(_rate, _m, _p, _s)              \
+       {                                               \
+               .rate   =       (_rate),                \
+               .mdiv   =       (_m),                   \
+               .pdiv   =       (_p),                   \
+               .sdiv   =       (_s),                   \
+       }
+
+#define PLL_1443X_RATE(_rate, _m, _p, _s, _k)          \
+       {                                               \
+               .rate   =       (_rate),                \
+               .mdiv   =       (_m),                   \
+               .pdiv   =       (_p),                   \
+               .sdiv   =       (_s),                   \
+               .kdiv   =       (_k),                   \
+       }
+
+static const struct imx_pll14xx_rate_table imx8mm_pll1416x_tbl[] = {
+       PLL_1416X_RATE(1800000000U, 225, 3, 0),
+       PLL_1416X_RATE(1600000000U, 200, 3, 0),
+       PLL_1416X_RATE(1200000000U, 300, 3, 1),
+       PLL_1416X_RATE(1000000000U, 250, 3, 1),
+       PLL_1416X_RATE(800000000U,  200, 3, 1),
+       PLL_1416X_RATE(750000000U,  250, 2, 2),
+       PLL_1416X_RATE(700000000U,  350, 3, 2),
+       PLL_1416X_RATE(600000000U,  300, 3, 2),
+};
+
+static const struct imx_pll14xx_rate_table imx8mm_drampll_tbl[] = {
+       PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
+};
+
+static struct imx_pll14xx_clk imx8mm_dram_pll __initdata = {
+               .type = PLL_1443X,
+               .rate_table = imx8mm_drampll_tbl,
+               .rate_count = ARRAY_SIZE(imx8mm_drampll_tbl),
+};
+
+static struct imx_pll14xx_clk imx8mm_arm_pll __initdata = {
+               .type = PLL_1416X,
+               .rate_table = imx8mm_pll1416x_tbl,
+               .rate_count = ARRAY_SIZE(imx8mm_pll1416x_tbl),
+};
+
+static struct imx_pll14xx_clk imx8mm_sys_pll __initdata = {
+               .type = PLL_1416X,
+               .rate_table = imx8mm_pll1416x_tbl,
+               .rate_count = ARRAY_SIZE(imx8mm_pll1416x_tbl),
+};
+
+static const char *pll_ref_sels[] = { "clock-osc-24m", "dummy", "dummy", "dummy", };
+static const char *dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", };
+static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
+static const char *sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", };
+static const char *sys_pll2_bypass_sels[] = {"sys_pll2", "sys_pll2_ref_sel", };
+static const char *sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", };
+
+static const char *imx8mm_a53_sels[] = {"clock-osc-24m", "arm_pll_out", "sys_pll2_500m", "sys_pll2_1000m",
+                                       "sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "sys_pll3_out", };
+
+static const char *imx8mm_ahb_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_800m", "sys_pll1_400m",
+                                       "sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", "video_pll1_out", };
+
+static const char *imx8mm_enet_axi_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_250m",
+                                            "sys_pll2_200m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", };
+
+static const char *imx8mm_nand_usdhc_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_200m",
+                                              "sys_pll1_133m", "sys_pll3_out", "sys_pll2_250m", "audio_pll1_out", };
+
+static const char *imx8mm_usdhc1_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m",
+                                          "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", };
+
+static const char *imx8mm_usdhc2_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m",
+                                          "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", };
+
+static const char *imx8mm_i2c1_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out",
+                                        "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", };
+
+static const char *imx8mm_i2c2_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out",
+                                        "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", };
+
+static const char *imx8mm_i2c3_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out",
+                                        "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", };
+
+static const char *imx8mm_i2c4_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out",
+                                        "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", };
+
+static const char *imx8mm_wdog_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_160m", "vpu_pll_out",
+                                        "sys_pll2_125m", "sys_pll3_out", "sys_pll1_80m", "sys_pll2_166m", };
+
+static const char *imx8mm_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m",
+                                          "sys_pll3_out", "sys_pll1_266m", "audio_pll2_clk", "sys_pll1_100m", };
+
+static ulong imx8mm_clk_get_rate(struct clk *clk)
+{
+       struct clk *c;
+       int ret;
+
+       debug("%s(#%lu)\n", __func__, clk->id);
+
+       ret = clk_get_by_id(clk->id, &c);
+       if (ret)
+               return ret;
+
+       return clk_get_rate(c);
+}
+
+static ulong imx8mm_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       struct clk *c;
+       int ret;
+
+       debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
+
+       ret = clk_get_by_id(clk->id, &c);
+       if (ret)
+               return ret;
+
+       return clk_set_rate(c, rate);
+}
+
+static int __imx8mm_clk_enable(struct clk *clk, bool enable)
+{
+       struct clk *c;
+       int ret;
+
+       debug("%s(#%lu) en: %d\n", __func__, clk->id, enable);
+
+       ret = clk_get_by_id(clk->id, &c);
+       if (ret)
+               return ret;
+
+       if (enable)
+               ret = clk_enable(c);
+       else
+               ret = clk_disable(c);
+
+       return ret;
+}
+
+static int imx8mm_clk_disable(struct clk *clk)
+{
+       return __imx8mm_clk_enable(clk, 0);
+}
+
+static int imx8mm_clk_enable(struct clk *clk)
+{
+       return __imx8mm_clk_enable(clk, 1);
+}
+
+static struct clk_ops imx8mm_clk_ops = {
+       .set_rate = imx8mm_clk_set_rate,
+       .get_rate = imx8mm_clk_get_rate,
+       .enable = imx8mm_clk_enable,
+       .disable = imx8mm_clk_disable,
+};
+
+static int imx8mm_clk_probe(struct udevice *dev)
+{
+       void __iomem *base;
+
+       base = (void *)ANATOP_BASE_ADDR;
+
+       clk_dm(IMX8MM_DRAM_PLL_REF_SEL,
+              imx_clk_mux("dram_pll_ref_sel", base + 0x50, 0, 2,
+                          pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
+       clk_dm(IMX8MM_ARM_PLL_REF_SEL,
+              imx_clk_mux("arm_pll_ref_sel", base + 0x84, 0, 2,
+                          pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
+       clk_dm(IMX8MM_SYS_PLL1_REF_SEL,
+              imx_clk_mux("sys_pll1_ref_sel", base + 0x94, 0, 2,
+                          pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
+       clk_dm(IMX8MM_SYS_PLL2_REF_SEL,
+              imx_clk_mux("sys_pll2_ref_sel", base + 0x104, 0, 2,
+                          pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
+       clk_dm(IMX8MM_SYS_PLL3_REF_SEL,
+              imx_clk_mux("sys_pll3_ref_sel", base + 0x114, 0, 2,
+                          pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
+
+       clk_dm(IMX8MM_DRAM_PLL,
+              imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel",
+                              base + 0x50, &imx8mm_dram_pll));
+       clk_dm(IMX8MM_ARM_PLL,
+              imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel",
+                              base + 0x84, &imx8mm_arm_pll));
+       clk_dm(IMX8MM_SYS_PLL1,
+              imx_clk_pll14xx("sys_pll1", "sys_pll1_ref_sel",
+                              base + 0x94, &imx8mm_sys_pll));
+       clk_dm(IMX8MM_SYS_PLL2,
+              imx_clk_pll14xx("sys_pll2", "sys_pll2_ref_sel",
+                              base + 0x104, &imx8mm_sys_pll));
+       clk_dm(IMX8MM_SYS_PLL3,
+              imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel",
+                              base + 0x114, &imx8mm_sys_pll));
+
+       /* PLL bypass out */
+       clk_dm(IMX8MM_DRAM_PLL_BYPASS,
+              imx_clk_mux_flags("dram_pll_bypass", base + 0x50, 4, 1,
+                                dram_pll_bypass_sels,
+                                ARRAY_SIZE(dram_pll_bypass_sels),
+                                CLK_SET_RATE_PARENT));
+       clk_dm(IMX8MM_ARM_PLL_BYPASS,
+              imx_clk_mux_flags("arm_pll_bypass", base + 0x84, 4, 1,
+                                arm_pll_bypass_sels,
+                                ARRAY_SIZE(arm_pll_bypass_sels),
+                                CLK_SET_RATE_PARENT));
+       clk_dm(IMX8MM_SYS_PLL1_BYPASS,
+              imx_clk_mux_flags("sys_pll1_bypass", base + 0x94, 4, 1,
+                                sys_pll1_bypass_sels,
+                                ARRAY_SIZE(sys_pll1_bypass_sels),
+                                CLK_SET_RATE_PARENT));
+       clk_dm(IMX8MM_SYS_PLL2_BYPASS,
+              imx_clk_mux_flags("sys_pll2_bypass", base + 0x104, 4, 1,
+                                sys_pll2_bypass_sels,
+                                ARRAY_SIZE(sys_pll2_bypass_sels),
+                                CLK_SET_RATE_PARENT));
+       clk_dm(IMX8MM_SYS_PLL3_BYPASS,
+              imx_clk_mux_flags("sys_pll3_bypass", base + 0x114, 4, 1,
+                                sys_pll3_bypass_sels,
+                                ARRAY_SIZE(sys_pll3_bypass_sels),
+                                CLK_SET_RATE_PARENT));
+
+       /* PLL out gate */
+       clk_dm(IMX8MM_DRAM_PLL_OUT,
+              imx_clk_gate("dram_pll_out", "dram_pll_bypass",
+                           base + 0x50, 13));
+       clk_dm(IMX8MM_ARM_PLL_OUT,
+              imx_clk_gate("arm_pll_out", "arm_pll_bypass",
+                           base + 0x84, 11));
+       clk_dm(IMX8MM_SYS_PLL1_OUT,
+              imx_clk_gate("sys_pll1_out", "sys_pll1_bypass",
+                           base + 0x94, 11));
+       clk_dm(IMX8MM_SYS_PLL2_OUT,
+              imx_clk_gate("sys_pll2_out", "sys_pll2_bypass",
+                           base + 0x104, 11));
+       clk_dm(IMX8MM_SYS_PLL3_OUT,
+              imx_clk_gate("sys_pll3_out", "sys_pll3_bypass",
+                           base + 0x114, 11));
+
+       /* SYS PLL fixed output */
+       clk_dm(IMX8MM_SYS_PLL1_40M,
+              imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20));
+       clk_dm(IMX8MM_SYS_PLL1_80M,
+              imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10));
+       clk_dm(IMX8MM_SYS_PLL1_100M,
+              imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8));
+       clk_dm(IMX8MM_SYS_PLL1_133M,
+              imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6));
+       clk_dm(IMX8MM_SYS_PLL1_160M,
+              imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5));
+       clk_dm(IMX8MM_SYS_PLL1_200M,
+              imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4));
+       clk_dm(IMX8MM_SYS_PLL1_266M,
+              imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3));
+       clk_dm(IMX8MM_SYS_PLL1_400M,
+              imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2));
+       clk_dm(IMX8MM_SYS_PLL1_800M,
+              imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1));
+
+       clk_dm(IMX8MM_SYS_PLL2_50M,
+              imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20));
+       clk_dm(IMX8MM_SYS_PLL2_100M,
+              imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10));
+       clk_dm(IMX8MM_SYS_PLL2_125M,
+              imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8));
+       clk_dm(IMX8MM_SYS_PLL2_166M,
+              imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6));
+       clk_dm(IMX8MM_SYS_PLL2_200M,
+              imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5));
+       clk_dm(IMX8MM_SYS_PLL2_250M,
+              imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4));
+       clk_dm(IMX8MM_SYS_PLL2_333M,
+              imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3));
+       clk_dm(IMX8MM_SYS_PLL2_500M,
+              imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2));
+       clk_dm(IMX8MM_SYS_PLL2_1000M,
+              imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1));
+
+       base = dev_read_addr_ptr(dev);
+       if (base == (void *)FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       clk_dm(IMX8MM_CLK_A53_SRC,
+              imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3,
+                           imx8mm_a53_sels, ARRAY_SIZE(imx8mm_a53_sels)));
+       clk_dm(IMX8MM_CLK_A53_CG,
+              imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28));
+       clk_dm(IMX8MM_CLK_A53_DIV,
+              imx_clk_divider2("arm_a53_div", "arm_a53_cg",
+                               base + 0x8000, 0, 3));
+
+       clk_dm(IMX8MM_CLK_AHB,
+              imx8m_clk_composite_critical("ahb", imx8mm_ahb_sels,
+                                           base + 0x9000));
+       clk_dm(IMX8MM_CLK_IPG_ROOT,
+              imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1));
+
+       clk_dm(IMX8MM_CLK_ENET_AXI,
+              imx8m_clk_composite("enet_axi", imx8mm_enet_axi_sels,
+                                  base + 0x8880));
+       clk_dm(IMX8MM_CLK_NAND_USDHC_BUS,
+              imx8m_clk_composite_critical("nand_usdhc_bus",
+                                           imx8mm_nand_usdhc_sels,
+                                           base + 0x8900));
+
+       /* IP */
+       clk_dm(IMX8MM_CLK_USDHC1,
+              imx8m_clk_composite("usdhc1", imx8mm_usdhc1_sels,
+                                  base + 0xac00));
+       clk_dm(IMX8MM_CLK_USDHC2,
+              imx8m_clk_composite("usdhc2", imx8mm_usdhc2_sels,
+                                  base + 0xac80));
+       clk_dm(IMX8MM_CLK_I2C1,
+              imx8m_clk_composite("i2c1", imx8mm_i2c1_sels, base + 0xad00));
+       clk_dm(IMX8MM_CLK_I2C2,
+              imx8m_clk_composite("i2c2", imx8mm_i2c2_sels, base + 0xad80));
+       clk_dm(IMX8MM_CLK_I2C3,
+              imx8m_clk_composite("i2c3", imx8mm_i2c3_sels, base + 0xae00));
+       clk_dm(IMX8MM_CLK_I2C4,
+              imx8m_clk_composite("i2c4", imx8mm_i2c4_sels, base + 0xae80));
+       clk_dm(IMX8MM_CLK_WDOG,
+              imx8m_clk_composite("wdog", imx8mm_wdog_sels, base + 0xb900));
+       clk_dm(IMX8MM_CLK_USDHC3,
+              imx8m_clk_composite("usdhc3", imx8mm_usdhc3_sels,
+                                  base + 0xbc80));
+
+       clk_dm(IMX8MM_CLK_I2C1_ROOT,
+              imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0));
+       clk_dm(IMX8MM_CLK_I2C2_ROOT,
+              imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0));
+       clk_dm(IMX8MM_CLK_I2C3_ROOT,
+              imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0));
+       clk_dm(IMX8MM_CLK_I2C4_ROOT,
+              imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0));
+       clk_dm(IMX8MM_CLK_OCOTP_ROOT,
+              imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0));
+       clk_dm(IMX8MM_CLK_USDHC1_ROOT,
+              imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0));
+       clk_dm(IMX8MM_CLK_USDHC2_ROOT,
+              imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0));
+       clk_dm(IMX8MM_CLK_WDOG1_ROOT,
+              imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0));
+       clk_dm(IMX8MM_CLK_WDOG2_ROOT,
+              imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0));
+       clk_dm(IMX8MM_CLK_WDOG3_ROOT,
+              imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0));
+       clk_dm(IMX8MM_CLK_USDHC3_ROOT,
+              imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0));
+
+#ifdef CONFIG_SPL_BUILD
+       struct clk *clkp, *clkp1;
+
+       clk_get_by_id(IMX8MM_CLK_WDOG1_ROOT, &clkp);
+       clk_enable(clkp);
+       clk_get_by_id(IMX8MM_CLK_WDOG2_ROOT, &clkp);
+       clk_enable(clkp);
+       clk_get_by_id(IMX8MM_CLK_WDOG3_ROOT, &clkp);
+       clk_enable(clkp);
+
+       /* Configure SYS_PLL3 to 750MHz */
+       clk_get_by_id(IMX8MM_SYS_PLL3, &clkp);
+       clk_set_rate(clkp, 750000000UL);
+       clk_enable(clkp);
+
+       /* Configure ARM to sys_pll2_500m */
+       clk_get_by_id(IMX8MM_CLK_A53_SRC, &clkp);
+       clk_get_by_id(IMX8MM_SYS_PLL2_OUT, &clkp1);
+       clk_enable(clkp1);
+       clk_get_by_id(IMX8MM_SYS_PLL2_500M, &clkp1);
+       clk_set_parent(clkp, clkp1);
+
+       /* Configure ARM PLL to 1.2GHz */
+       clk_get_by_id(IMX8MM_ARM_PLL, &clkp1);
+       clk_set_rate(clkp1, 1200000000UL);
+       clk_get_by_id(IMX8MM_ARM_PLL_OUT, &clkp1);
+       clk_enable(clkp1);
+       clk_set_parent(clkp, clkp1);
+
+       /* Configure DIV to 1.2GHz */
+       clk_get_by_id(IMX8MM_CLK_A53_DIV, &clkp1);
+       clk_set_rate(clkp1, 1200000000UL);
+#endif
+
+       return 0;
+}
+
+static const struct udevice_id imx8mm_clk_ids[] = {
+       { .compatible = "fsl,imx8mm-ccm" },
+       { },
+};
+
+U_BOOT_DRIVER(imx8mm_clk) = {
+       .name = "clk_imx8mm",
+       .id = UCLASS_CLK,
+       .of_match = imx8mm_clk_ids,
+       .ops = &imx8mm_clk_ops,
+       .probe = imx8mm_clk_probe,
+       .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c
new file mode 100644 (file)
index 0000000..2246beb
--- /dev/null
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2017-2019 NXP.
+ *
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <linux/clk-provider.h>
+#include <linux/iopoll.h>
+#include <clk.h>
+#include <div64.h>
+
+#include "clk.h"
+
+#define UBOOT_DM_CLK_IMX_PLL1443X "imx_clk_pll1443x"
+#define UBOOT_DM_CLK_IMX_PLL1416X "imx_clk_pll1416x"
+
+#define GNRL_CTL       0x0
+#define DIV_CTL                0x4
+#define LOCK_STATUS    BIT(31)
+#define LOCK_SEL_MASK  BIT(29)
+#define CLKE_MASK      BIT(11)
+#define RST_MASK       BIT(9)
+#define BYPASS_MASK    BIT(4)
+#define MDIV_SHIFT     12
+#define MDIV_MASK      GENMASK(21, 12)
+#define PDIV_SHIFT     4
+#define PDIV_MASK      GENMASK(9, 4)
+#define SDIV_SHIFT     0
+#define SDIV_MASK      GENMASK(2, 0)
+#define KDIV_SHIFT     0
+#define KDIV_MASK      GENMASK(15, 0)
+
+#define LOCK_TIMEOUT_US                10000
+
+struct clk_pll14xx {
+       struct clk                      clk;
+       void __iomem                    *base;
+       enum imx_pll14xx_type           type;
+       const struct imx_pll14xx_rate_table *rate_table;
+       int rate_count;
+};
+
+#define to_clk_pll14xx(_clk) container_of(_clk, struct clk_pll14xx, clk)
+
+static const struct imx_pll14xx_rate_table *imx_get_pll_settings(
+               struct clk_pll14xx *pll, unsigned long rate)
+{
+       const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
+       int i;
+
+       for (i = 0; i < pll->rate_count; i++)
+               if (rate == rate_table[i].rate)
+                       return &rate_table[i];
+
+       return NULL;
+}
+
+static unsigned long clk_pll1416x_recalc_rate(struct clk *clk)
+{
+       struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev));
+       u64 fvco = clk_get_parent_rate(clk);
+       u32 mdiv, pdiv, sdiv, pll_div;
+
+       pll_div = readl(pll->base + 4);
+       mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
+       pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
+       sdiv = (pll_div & SDIV_MASK) >> SDIV_SHIFT;
+
+       fvco *= mdiv;
+       do_div(fvco, pdiv << sdiv);
+
+       return fvco;
+}
+
+static unsigned long clk_pll1443x_recalc_rate(struct clk *clk)
+{
+       struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev));
+       u64 fvco = clk_get_parent_rate(clk);
+       u32 mdiv, pdiv, sdiv, pll_div_ctl0, pll_div_ctl1;
+       short int kdiv;
+
+       pll_div_ctl0 = readl(pll->base + 4);
+       pll_div_ctl1 = readl(pll->base + 8);
+       mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT;
+       pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT;
+       sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT;
+       kdiv = pll_div_ctl1 & KDIV_MASK;
+
+       /* fvco = (m * 65536 + k) * Fin / (p * 65536) */
+       fvco *= (mdiv * 65536 + kdiv);
+       pdiv *= 65536;
+
+       do_div(fvco, pdiv << sdiv);
+
+       return fvco;
+}
+
+static inline bool clk_pll1416x_mp_change(const struct imx_pll14xx_rate_table *rate,
+                                         u32 pll_div)
+{
+       u32 old_mdiv, old_pdiv;
+
+       old_mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
+       old_pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
+
+       return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv;
+}
+
+static inline bool clk_pll1443x_mpk_change(const struct imx_pll14xx_rate_table *rate,
+                                          u32 pll_div_ctl0, u32 pll_div_ctl1)
+{
+       u32 old_mdiv, old_pdiv, old_kdiv;
+
+       old_mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT;
+       old_pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT;
+       old_kdiv = (pll_div_ctl1 & KDIV_MASK) >> KDIV_SHIFT;
+
+       return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
+               rate->kdiv != old_kdiv;
+}
+
+static inline bool clk_pll1443x_mp_change(const struct imx_pll14xx_rate_table *rate,
+                                         u32 pll_div_ctl0, u32 pll_div_ctl1)
+{
+       u32 old_mdiv, old_pdiv, old_kdiv;
+
+       old_mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT;
+       old_pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT;
+       old_kdiv = (pll_div_ctl1 & KDIV_MASK) >> KDIV_SHIFT;
+
+       return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
+               rate->kdiv != old_kdiv;
+}
+
+static int clk_pll14xx_wait_lock(struct clk_pll14xx *pll)
+{
+       u32 val;
+
+       return readl_poll_timeout(pll->base, val, val & LOCK_TIMEOUT_US,
+                       LOCK_TIMEOUT_US);
+}
+
+static ulong clk_pll1416x_set_rate(struct clk *clk, unsigned long drate)
+{
+       struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev));
+       const struct imx_pll14xx_rate_table *rate;
+       u32 tmp, div_val;
+       int ret;
+
+       rate = imx_get_pll_settings(pll, drate);
+       if (!rate) {
+               pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+                      drate, "xxxx");
+               return -EINVAL;
+       }
+
+       tmp = readl(pll->base + 4);
+
+       if (!clk_pll1416x_mp_change(rate, tmp)) {
+               tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
+               tmp |= rate->sdiv << SDIV_SHIFT;
+               writel(tmp, pll->base + 4);
+
+               return clk_pll1416x_recalc_rate(clk);
+       }
+
+       /* Bypass clock and set lock to pll output lock */
+       tmp = readl(pll->base);
+       tmp |= LOCK_SEL_MASK;
+       writel(tmp, pll->base);
+
+       /* Enable RST */
+       tmp &= ~RST_MASK;
+       writel(tmp, pll->base);
+
+       /* Enable BYPASS */
+       tmp |= BYPASS_MASK;
+       writel(tmp, pll->base);
+
+
+       div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
+               (rate->sdiv << SDIV_SHIFT);
+       writel(div_val, pll->base + 0x4);
+
+       /*
+        * According to SPEC, t3 - t2 need to be greater than
+        * 1us and 1/FREF, respectively.
+        * FREF is FIN / Prediv, the prediv is [1, 63], so choose
+        * 3us.
+        */
+       udelay(3);
+
+       /* Disable RST */
+       tmp |= RST_MASK;
+       writel(tmp, pll->base);
+
+       /* Wait Lock */
+       ret = clk_pll14xx_wait_lock(pll);
+       if (ret)
+               return ret;
+
+       /* Bypass */
+       tmp &= ~BYPASS_MASK;
+       writel(tmp, pll->base);
+
+       return clk_pll1416x_recalc_rate(clk);
+}
+
+static ulong clk_pll1443x_set_rate(struct clk *clk, unsigned long drate)
+{
+       struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev));
+       const struct imx_pll14xx_rate_table *rate;
+       u32 tmp, div_val;
+       int ret;
+
+       rate = imx_get_pll_settings(pll, drate);
+       if (!rate) {
+               pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+                      drate, "===");
+               return -EINVAL;
+       }
+
+       tmp = readl(pll->base + 4);
+       div_val = readl(pll->base + 8);
+
+       if (!clk_pll1443x_mpk_change(rate, tmp, div_val)) {
+               tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
+               tmp |= rate->sdiv << SDIV_SHIFT;
+               writel(tmp, pll->base + 4);
+
+               return clk_pll1443x_recalc_rate(clk);
+       }
+
+       tmp = readl(pll->base);
+
+       /* Enable RST */
+       tmp &= ~RST_MASK;
+       writel(tmp, pll->base);
+
+       /* Enable BYPASS */
+       tmp |= BYPASS_MASK;
+       writel(tmp, pll->base);
+
+       div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
+               (rate->sdiv << SDIV_SHIFT);
+       writel(div_val, pll->base + 0x4);
+       writel(rate->kdiv << KDIV_SHIFT, pll->base + 0x8);
+
+       /*
+        * According to SPEC, t3 - t2 need to be greater than
+        * 1us and 1/FREF, respectively.
+        * FREF is FIN / Prediv, the prediv is [1, 63], so choose
+        * 3us.
+        */
+       udelay(3);
+
+       /* Disable RST */
+       tmp |= RST_MASK;
+       writel(tmp, pll->base);
+
+       /* Wait Lock*/
+       ret = clk_pll14xx_wait_lock(pll);
+       if (ret)
+               return ret;
+
+       /* Bypass */
+       tmp &= ~BYPASS_MASK;
+       writel(tmp, pll->base);
+
+       return clk_pll1443x_recalc_rate(clk);
+}
+
+static int clk_pll14xx_prepare(struct clk *clk)
+{
+       struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev));
+       u32 val;
+
+       /*
+        * RESETB = 1 from 0, PLL starts its normal
+        * operation after lock time
+        */
+       val = readl(pll->base + GNRL_CTL);
+       val |= RST_MASK;
+       writel(val, pll->base + GNRL_CTL);
+
+       return clk_pll14xx_wait_lock(pll);
+}
+
+static int clk_pll14xx_unprepare(struct clk *clk)
+{
+       struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev));
+       u32 val;
+
+       /*
+        * Set RST to 0, power down mode is enabled and
+        * every digital block is reset
+        */
+       val = readl(pll->base + GNRL_CTL);
+       val &= ~RST_MASK;
+       writel(val, pll->base + GNRL_CTL);
+
+       return 0;
+}
+
+static const struct clk_ops clk_pll1416x_ops = {
+       .enable         = clk_pll14xx_prepare,
+       .disable        = clk_pll14xx_unprepare,
+       .set_rate       = clk_pll1416x_set_rate,
+       .get_rate       = clk_pll1416x_recalc_rate,
+};
+
+static const struct clk_ops clk_pll1443x_ops = {
+       .enable         = clk_pll14xx_prepare,
+       .disable        = clk_pll14xx_unprepare,
+       .set_rate       = clk_pll1443x_set_rate,
+       .get_rate       = clk_pll1443x_recalc_rate,
+};
+
+struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
+                           void __iomem *base,
+                           const struct imx_pll14xx_clk *pll_clk)
+{
+       struct clk_pll14xx *pll;
+       struct clk *clk;
+       char *type_name;
+       int ret;
+
+       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+       if (!pll)
+               return ERR_PTR(-ENOMEM);
+
+       switch (pll_clk->type) {
+       case PLL_1416X:
+               type_name = UBOOT_DM_CLK_IMX_PLL1416X;
+               break;
+       case PLL_1443X:
+               type_name = UBOOT_DM_CLK_IMX_PLL1443X;
+               break;
+       default:
+               pr_err("%s: Unknown pll type for pll clk %s\n",
+                      __func__, name);
+               return ERR_PTR(-EINVAL);
+       };
+
+       pll->base = base;
+       pll->type = pll_clk->type;
+       pll->rate_table = pll_clk->rate_table;
+       pll->rate_count = pll_clk->rate_count;
+
+       clk = &pll->clk;
+
+       ret = clk_register(clk, type_name, name, parent_name);
+       if (ret) {
+               pr_err("%s: failed to register pll %s %d\n",
+                      __func__, name, ret);
+               kfree(pll);
+               return ERR_PTR(ret);
+       }
+
+       return clk;
+}
+
+U_BOOT_DRIVER(clk_pll1443x) = {
+       .name   = UBOOT_DM_CLK_IMX_PLL1443X,
+       .id     = UCLASS_CLK,
+       .ops    = &clk_pll1443x_ops,
+       .flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(clk_pll1416x) = {
+       .name   = UBOOT_DM_CLK_IMX_PLL1416X,
+       .id     = UCLASS_CLK,
+       .ops    = &clk_pll1416x_ops,
+       .flags = DM_FLAG_PRE_RELOC,
+};
index 1d480d8722b623ef760349e6b9ab4b1958e68b09..4956e04a9253076175ed6c7c564fd19e80384382 100644 (file)
@@ -20,6 +20,31 @@ enum imx_pllv3_type {
        IMX_PLLV3_DDR_IMX7,
 };
 
+enum imx_pll14xx_type {
+       PLL_1416X,
+       PLL_1443X,
+};
+
+/* NOTE: Rate table should be kept sorted in descending order. */
+struct imx_pll14xx_rate_table {
+       unsigned int rate;
+       unsigned int pdiv;
+       unsigned int mdiv;
+       unsigned int sdiv;
+       unsigned int kdiv;
+};
+
+struct imx_pll14xx_clk {
+       enum imx_pll14xx_type type;
+       const struct imx_pll14xx_rate_table *rate_table;
+       int rate_count;
+       int flags;
+};
+
+struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
+                           void __iomem *base,
+                           const struct imx_pll14xx_clk *pll_clk);
+
 struct clk *clk_register_gate2(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx, u8 cgr_val,
index 3ca2796b5774990dae8560bb7f4e12fd3f135d8b..18b2e3ca54c53ab37d2ac743d9327b7c71424dc0 100644 (file)
@@ -61,6 +61,7 @@ struct clk {
        struct udevice *dev;
        long long rate; /* in HZ */
        u32 flags;
+       int enable_count;
        /*
         * Written by of_xlate. In the future, we might add more fields here.
         */
index f449de13649d2ff55a1078507e08fcf66d62a7c7..296cddfbb0ef7575a386e185c61e7af87df496a4 100644 (file)
@@ -20,6 +20,7 @@ enum {
        SANDBOX_CLK_USDHC1_SEL,
        SANDBOX_CLK_USDHC2_SEL,
        SANDBOX_CLK_I2C,
+       SANDBOX_CLK_I2C_ROOT,
 };
 
 enum sandbox_pllv3_type {
@@ -74,4 +75,6 @@ static inline struct clk *sandbox_clk_mux(const char *name, void __iomem *reg,
                                width, 0);
 }
 
+int sandbox_clk_enable_count(struct clk *clk);
+
 #endif /* __SANDBOX_CLK_H__ */
index bbc4b500e83d7985daf7cce4ea911e9d6fb759ad..ae3a4d8a76a429caee686eb5b0edc526dae660dc 100644 (file)
@@ -64,6 +64,34 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
        rate = clk_get_rate(clk);
        ut_asserteq(rate, 60000000);
 
+#if CONFIG_IS_ENABLED(CLK_CCF)
+       /* Test clk tree enable/disable */
+       ret = clk_get_by_id(SANDBOX_CLK_I2C_ROOT, &clk);
+       ut_assertok(ret);
+       ut_asserteq_str("i2c_root", clk->dev->name);
+
+       ret = clk_enable(clk);
+       ut_assertok(ret);
+
+       ret = sandbox_clk_enable_count(clk);
+       ut_asserteq(ret, 1);
+
+       ret = clk_get_by_id(SANDBOX_CLK_I2C, &pclk);
+       ut_assertok(ret);
+
+       ret = sandbox_clk_enable_count(pclk);
+       ut_asserteq(ret, 1);
+
+       ret = clk_disable(clk);
+       ut_assertok(ret);
+
+       ret = sandbox_clk_enable_count(clk);
+       ut_asserteq(ret, 0);
+
+       ret = sandbox_clk_enable_count(pclk);
+       ut_asserteq(ret, 0);
+#endif
+
        return 1;
 }