[U-Boot] [PATCH 0/4] Prepare i.MX8MM clk

This is to support i.MX8MM clk driver. i.MX8MM use similar clock design as i.MX7D, but it has use different PLL, so we need to add pll14xx driver. And to simplify the clock usage, import the composite clk driver from Linux Kernel, then we could have simple clk tree.
This is to split the previous patchset https://github.com/MrVan/u-boot/commits/imx8mmn-ccf for i.MX8MM/N support
There are some checkpatch warnings that not addressed, because import from Linux Kernel.
Peng Fan (4): clk: imx: add Kconfig entry for i.MX8MM clk: imx: add pll14xx driver clk: imx: add i.MX8M composite clk support clk: imx: add i.MX8MM clk driver
drivers/clk/Kconfig | 4 +- drivers/clk/imx/Kconfig | 16 ++ drivers/clk/imx/Makefile | 2 + drivers/clk/imx/clk-composite-8m.c | 170 +++++++++++++++ drivers/clk/imx/clk-imx8mm.c | 414 +++++++++++++++++++++++++++++++++++++ drivers/clk/imx/clk-pll14xx.c | 371 +++++++++++++++++++++++++++++++++ drivers/clk/imx/clk.h | 25 +++ 7 files changed, 1000 insertions(+), 2 deletions(-) create mode 100644 drivers/clk/imx/clk-composite-8m.c create mode 100644 drivers/clk/imx/clk-imx8mm.c create mode 100644 drivers/clk/imx/clk-pll14xx.c

Add Kconfig entry for i.MX8MM
Signed-off-by: Peng Fan peng.fan@nxp.com --- drivers/clk/Kconfig | 4 ++-- drivers/clk/imx/Kconfig | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index a3f0171b45..fce595b4b3 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -48,7 +48,7 @@ config CLK_BOSTON
config SPL_CLK_CCF bool "SPL Common Clock Framework [CCF] support " - depends on SPL_CLK_IMX6Q + depends on SPL_CLK_IMX6Q || ARCH_IMX8M 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 +62,7 @@ config SPL_CLK_COMPOSITE_CCF
config CLK_CCF bool "Common Clock Framework [CCF] support " - depends on CLK_IMX6Q || SANDBOX_CLK_CCF + depends on CLK_IMX6Q || ARCH_IMX8M || 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. diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index 3e6a980c8c..aae69cf9b0 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -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.

Add pll14xx driver
Signed-off-by: Peng Fan peng.fan@nxp.com --- drivers/clk/imx/clk-pll14xx.c | 371 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/imx/clk.h | 25 +++ 2 files changed, 396 insertions(+) create mode 100644 drivers/clk/imx/clk-pll14xx.c
diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c new file mode 100644 index 0000000000..21c258a380 --- /dev/null +++ b/drivers/clk/imx/clk-pll14xx.c @@ -0,0 +1,371 @@ +// 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_SHIFT) & MDIV_MASK; + old_pdiv = (pll_div >> PDIV_SHIFT) & PDIV_MASK; + + 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_SHIFT) & MDIV_MASK; + old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK; + old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK; + + 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_SHIFT) & MDIV_MASK; + old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK; + old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK; + + 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); + + 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); + } + + /* Enable RST */ + tmp = readl(pll->base); + tmp &= ~RST_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, +}; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 1d480d8722..4956e04a92 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -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,

Import i.MX8M composite clk from Linux Kernel 5.3.0-rc2
Signed-off-by: Peng Fan peng.fan@nxp.com --- drivers/clk/imx/clk-composite-8m.c | 170 +++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 drivers/clk/imx/clk-composite-8m.c
diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c new file mode 100644 index 0000000000..57ebbc3bb0 --- /dev/null +++ b/drivers/clk/imx/clk-composite-8m.c @@ -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 not binded 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 -EINVAL; + + 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); +}

Hi Peng,
Import i.MX8M composite clk from Linux Kernel 5.3.0-rc2
Signed-off-by: Peng Fan peng.fan@nxp.com
drivers/clk/imx/clk-composite-8m.c | 170 +++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 drivers/clk/imx/clk-composite-8m.c
diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c new file mode 100644 index 0000000000..57ebbc3bb0 --- /dev/null +++ b/drivers/clk/imx/clk-composite-8m.c @@ -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 not binded 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 -EINVAL;
- 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);
+}
Reviewed-by: Lukasz Majewski lukma@denx.de
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de

Add i.MX8MM clk driver support.
Signed-off-by: Peng Fan peng.fan@nxp.com --- drivers/clk/imx/Makefile | 2 + drivers/clk/imx/clk-imx8mm.c | 414 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 416 insertions(+) create mode 100644 drivers/clk/imx/clk-imx8mm.c
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 105a58ca90..5ad7967fe9 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -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-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c new file mode 100644 index 0000000000..9459d8ab8e --- /dev/null +++ b/drivers/clk/imx/clk-imx8mm.c @@ -0,0 +1,414 @@ +// 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 = 0; + + 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 = 0; + + 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, 13)); + clk_dm(IMX8MM_SYS_PLL1_OUT, + imx_clk_gate("sys_pll1_out", "sys_pll1_bypass", + base + 0x94, 13)); + clk_dm(IMX8MM_SYS_PLL2_OUT, + imx_clk_gate("sys_pll2_out", "sys_pll2_bypass", + base + 0x104, 13)); + clk_dm(IMX8MM_SYS_PLL3_OUT, + imx_clk_gate("sys_pll3_out", "sys_pll3_bypass", + base + 0x114, 13)); + + /* 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; + struct udevice *devp; + + 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); + + /* Configure ARM to osc24M */ + clk_get_by_id(IMX8MM_CLK_A53_SRC, &clkp); + uclass_get_device_by_name(UCLASS_CLK, "clock-osc-24m", &devp); + clkp1 = &to_clk_fixed_rate(devp)->clk; + 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, +};

On Tue, 6 Aug 2019 10:03:11 +0000 Peng Fan peng.fan@nxp.com wrote:
Add i.MX8MM clk driver support.
Signed-off-by: Peng Fan peng.fan@nxp.com
drivers/clk/imx/Makefile | 2 + drivers/clk/imx/clk-imx8mm.c | 414 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 416 insertions(+) create mode 100644 drivers/clk/imx/clk-imx8mm.c
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 105a58ca90..5ad7967fe9 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -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-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c new file mode 100644 index 0000000000..9459d8ab8e --- /dev/null +++ b/drivers/clk/imx/clk-imx8mm.c @@ -0,0 +1,414 @@ +// 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 = 0;
- 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 = 0;
- 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, 13));
- clk_dm(IMX8MM_SYS_PLL1_OUT,
imx_clk_gate("sys_pll1_out", "sys_pll1_bypass",
base + 0x94, 13));
- clk_dm(IMX8MM_SYS_PLL2_OUT,
imx_clk_gate("sys_pll2_out", "sys_pll2_bypass",
base + 0x104, 13));
- clk_dm(IMX8MM_SYS_PLL3_OUT,
imx_clk_gate("sys_pll3_out", "sys_pll3_bypass",
base + 0x114, 13));
- /* 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;
- struct udevice *devp;
- 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);
- /* Configure ARM to osc24M */
- clk_get_by_id(IMX8MM_CLK_A53_SRC, &clkp);
- uclass_get_device_by_name(UCLASS_CLK, "clock-osc-24m",
&devp);
- clkp1 = &to_clk_fixed_rate(devp)->clk;
- 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,
+};
Reviewed-by: Lukasz Majewski lukma@denx.de Acked-by: Lukasz Majewski lukma@denx.de
As this and previous (3/4) patch is part of some other series - I do have a question: shall I take 3/4 and 4/4 to u-boot-clk or shall the whole series be taken by Stefano to u-boot-imx tree ?
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de

Hi Lukasz,
Subject: Re: [PATCH 4/4] clk: imx: add i.MX8MM clk driver
On Tue, 6 Aug 2019 10:03:11 +0000 Peng Fan peng.fan@nxp.com wrote:
Add i.MX8MM clk driver support.
Signed-off-by: Peng Fan peng.fan@nxp.com
drivers/clk/imx/Makefile | 2 + drivers/clk/imx/clk-imx8mm.c | 414 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 416 insertions(+) create mode 100644 drivers/clk/imx/clk-imx8mm.c
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 105a58ca90..5ad7967fe9 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -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-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c new file mode 100644 index 0000000000..9459d8ab8e --- /dev/null +++ b/drivers/clk/imx/clk-imx8mm.c @@ -0,0 +1,414 @@ +// 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 = 0;
- 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 = 0;
- 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, 13));
- clk_dm(IMX8MM_SYS_PLL1_OUT,
imx_clk_gate("sys_pll1_out", "sys_pll1_bypass",
base + 0x94, 13));
- clk_dm(IMX8MM_SYS_PLL2_OUT,
imx_clk_gate("sys_pll2_out", "sys_pll2_bypass",
base + 0x104, 13));
- clk_dm(IMX8MM_SYS_PLL3_OUT,
imx_clk_gate("sys_pll3_out", "sys_pll3_bypass",
base + 0x114, 13));
- /* 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;
- struct udevice *devp;
- 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);
- /* Configure ARM to osc24M */
- clk_get_by_id(IMX8MM_CLK_A53_SRC, &clkp);
- uclass_get_device_by_name(UCLASS_CLK, "clock-osc-24m",
&devp);
- clkp1 = &to_clk_fixed_rate(devp)->clk;
- 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,
+};
Reviewed-by: Lukasz Majewski lukma@denx.de Acked-by: Lukasz Majewski lukma@denx.de
As this and previous (3/4) patch is part of some other series - I do have a question: shall I take 3/4 and 4/4 to u-boot-clk or shall the whole series be taken by Stefano to u-boot-imx tree ?
There are also 1/4 and 2/4, would you please also take that two patches?
Thanks, Peng.
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
participants (2)
-
Lukasz Majewski
-
Peng Fan