diff options
Diffstat (limited to 'drivers/clk/imx')
| -rw-r--r-- | drivers/clk/imx/Makefile | 2 | ||||
| -rw-r--r-- | drivers/clk/imx/clk-frac-pll.c | 199 | ||||
| -rw-r--r-- | drivers/clk/imx/clk-imx6q.c | 255 | ||||
| -rw-r--r-- | drivers/clk/imx/clk-imx8mq.c | 55 | ||||
| -rw-r--r-- | drivers/clk/imx/clk.h | 3 |
5 files changed, 473 insertions, 41 deletions
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index f2fd6ff8ca0..a825ed9988f 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -17,7 +17,7 @@ obj-$(CONFIG_$(PHASE_)CLK_IMX8MN) += clk-imx8mn.o clk-pll14xx.o \ clk-composite-8m.o obj-$(CONFIG_$(PHASE_)CLK_IMX8MP) += clk-imx8mp.o clk-pll14xx.o \ clk-composite-8m.o -obj-$(CONFIG_$(PHASE_)CLK_IMX8MQ) += clk-imx8mq.o clk-pll14xx.o \ +obj-$(CONFIG_$(PHASE_)CLK_IMX8MQ) += clk-imx8mq.o clk-frac-pll.o \ clk-composite-8m.o obj-$(CONFIG_$(PHASE_)CLK_IMX93) += clk-imx93.o clk-fracn-gppll.o \ clk-gate-93.o clk-composite-93.o diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c new file mode 100644 index 00000000000..057389d3069 --- /dev/null +++ b/drivers/clk/imx/clk-frac-pll.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2026 NXP + * + */ + +#include <asm/io.h> +#include <malloc.h> +#include <clk-uclass.h> +#include <dm/device.h> +#include <dm/devres.h> +#include <linux/bitops.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <clk.h> +#include <div64.h> +#include <linux/printk.h> +#include <linux/bitfield.h> + +#include "clk.h" + +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 + +#define PLL_LOCK_STATUS BIT(31) +#define PLL_PD_MASK BIT(19) +#define PLL_BYPASS_MASK BIT(14) +#define PLL_NEWDIV_VAL BIT(12) +#define PLL_NEWDIV_ACK BIT(11) +#define PLL_FRAC_DIV_MASK GENMASK(30, 7) +#define PLL_INT_DIV_MASK GENMASK(6, 0) +#define PLL_OUTPUT_DIV_MASK GENMASK(4, 0) +#define PLL_FRAC_DENOM 0x1000000 + +#define PLL_FRAC_LOCK_TIMEOUT 10000 +#define PLL_FRAC_ACK_TIMEOUT 500000 + +struct clk_frac_pll { + struct clk clk; + void __iomem *base; +}; + +#define to_clk_frac_pll(_clk) container_of(_clk, struct clk_frac_pll, clk) + +static int clk_wait_lock(struct clk_frac_pll *pll) +{ + u32 val; + + return readl_poll_timeout(pll->base, val, val & PLL_LOCK_STATUS, + PLL_FRAC_LOCK_TIMEOUT); +} + +static int clk_wait_ack(struct clk_frac_pll *pll) +{ + u32 val; + + /* return directly if the pll is in powerdown or in bypass */ + if (readl_relaxed(pll->base) & (PLL_PD_MASK | PLL_BYPASS_MASK)) + return 0; + + /* Wait for the pll's divfi and divff to be reloaded */ + return readl_poll_timeout(pll->base, val, val & PLL_NEWDIV_ACK, + PLL_FRAC_ACK_TIMEOUT); +} + +static int clk_pll_prepare(struct clk *clk) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(clk); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return clk_wait_lock(pll); +} + +static int clk_pll_unprepare(struct clk *clk) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(clk); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return 0; +} + +static unsigned long clk_pll_recalc_rate(struct clk *clk) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(clk); + u32 val, divff, divfi, divq; + ulong parent_rate = clk_get_parent_rate(clk); + u64 temp64 = parent_rate; + u64 rate; + + val = readl_relaxed(pll->base + PLL_CFG0); + divq = (FIELD_GET(PLL_OUTPUT_DIV_MASK, val) + 1) * 2; + val = readl_relaxed(pll->base + PLL_CFG1); + divff = FIELD_GET(PLL_FRAC_DIV_MASK, val); + divfi = FIELD_GET(PLL_INT_DIV_MASK, val); + + temp64 *= 8; + temp64 *= divff; + do_div(temp64, PLL_FRAC_DENOM); + do_div(temp64, divq); + + rate = parent_rate * 8 * (divfi + 1); + do_div(rate, divq); + rate += temp64; + + return rate; +} + +static ulong clk_pll_set_rate(struct clk *clk, unsigned long rate) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(clk); + ulong parent_rate = clk_get_parent_rate(clk); + u32 val, divfi, divff; + u64 temp64; + int ret; + + parent_rate *= 8; + rate *= 2; + divfi = rate / parent_rate; + temp64 = parent_rate * divfi; + temp64 = rate - temp64; + temp64 *= PLL_FRAC_DENOM; + do_div(temp64, parent_rate); + divff = temp64; + + val = readl_relaxed(pll->base + PLL_CFG1); + val &= ~(PLL_FRAC_DIV_MASK | PLL_INT_DIV_MASK); + val |= (divff << 7) | (divfi - 1); + writel_relaxed(val, pll->base + PLL_CFG1); + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~0x1f; + writel_relaxed(val, pll->base + PLL_CFG0); + + /* Set the NEV_DIV_VAL to reload the DIVFI and DIVFF */ + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_NEWDIV_VAL; + writel_relaxed(val, pll->base + PLL_CFG0); + + ret = clk_wait_ack(pll); + + /* clear the NEV_DIV_VAL */ + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_NEWDIV_VAL; + writel_relaxed(val, pll->base + PLL_CFG0); + + if (ret) + return ret; + + return clk_pll_recalc_rate(clk); +} + +static const struct clk_ops clk_frac_pll_ops = { + .enable = clk_pll_prepare, + .disable = clk_pll_unprepare, + .set_rate = clk_pll_set_rate, + .get_rate = clk_pll_recalc_rate, +}; + +struct clk *imx_clk_frac_pll(const char *name, const char *parent_name, + void __iomem *base) +{ + struct clk_frac_pll *pll; + struct clk *clk; + int ret; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + pll->base = base; + clk = &pll->clk; + + ret = clk_register(clk, "imx_clk_frac_pll", 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_frac_pll) = { + .name = "imx_clk_frac_pll", + .id = UCLASS_CLK, + .ops = &clk_frac_pll_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index f57ac79f8ca..846b8011f5c 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -9,6 +9,7 @@ #include <log.h> #include <asm/arch/clock.h> #include <asm/arch/imx-regs.h> +#include <dm/of_access.h> #include <dt-bindings/clock/imx6qdl-clock.h> #include "clk.h" @@ -46,6 +47,33 @@ static struct clk_ops imx6q_clk_ops = { .disable = ccf_clk_disable, }; +static const char *const pll_bypass_src_sels[] = { + "osc", + "lvds1_in", + "lvds2_in", + "dummy", +}; + +static const char *const pll2_bypass_sels[] = { + "pll2", + "pll2_bypass_src", +}; + +static const char *const pll3_bypass_sels[] = { + "pll3", + "pll3_bypass_src", +}; + +static const char *const pll5_bypass_sels[] = { + "pll5", + "pll5_bypass_src", +}; + +static const char *const pll6_bypass_sels[] = { + "pll6", + "pll6_bypass_src", +}; + static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", @@ -72,6 +100,23 @@ static const char *const ecspi_sels[] = { "pll3_60m", "osc", }; + +static const struct clk_div_table post_div_table[] = { + { .val = 2, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 0, .div = 4, }, + { /* sentinel */ } +}; + +static const struct clk_div_table video_div_table[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 2, .div = 1, }, + { .val = 3, .div = 4, }, + { /* sentinel */ } +}; + +#if CONFIG_IS_ENABLED(VIDEO) static const char *const ipu_sels[] = { "mmdc_ch0_axi", "pll2_pfd2_396m", @@ -113,6 +158,122 @@ static const char *ipu2_di1_sels_2[] = { static unsigned int share_count_mipi_core_cfg; +static void of_assigned_ldb_sels(struct udevice *dev, int *ldb_di0_sel, + int *ldb_di1_sel) +{ + struct ofnode_phandle_args clk_args, parent_args; + ofnode node = dev_ofnode(dev); + int count, err; + + count = dev_count_phandle_with_args(dev, "assigned-clocks", + "#clock-cells", 0); + if (count <= 0) { + if (count == 0) + debug("%s: no assigned_clocks found\n", dev->name); + else + pr_err("%s: failed to get phandle count (%d)\n", + dev->name, count); + return; + } + + for (int i = 0; i < count; i++) { + err = dev_read_phandle_with_args(dev, "assigned-clocks", + "#clock-cells", 0, i, + &clk_args); + if (err == -ENOENT) + /* Skip empty handles */ + continue; + else if (err < 0) + return; + + if (!ofnode_equal(clk_args.node, node) || + clk_args.args[0] >= IMX6QDL_CLK_END) { + pr_err("%s: clock %d not in ccm\n", dev->name, i); + return; + } + + err = dev_read_phandle_with_args(dev, "assigned-clock-parents", + "#clock-cells", 0, i, + &parent_args); + if (err < 0) + return; + + if (!ofnode_equal(parent_args.node, node) || + parent_args.args[0] >= IMX6QDL_CLK_END) { + pr_err("%s: parent clock %d not in ccm\n", dev->name, + i); + return; + } + + if (clk_args.args[0] == IMX6QDL_CLK_LDB_DI0_SEL) + *ldb_di0_sel = parent_args.args[0]; + else if (clk_args.args[0] == IMX6QDL_CLK_LDB_DI1_SEL) + *ldb_di1_sel = parent_args.args[0]; + } +} + +static void imx6q_init_ldb_clks(struct udevice *dev) +{ + int ldb_di_sel[] = { IMX6QDL_CLK_END, IMX6QDL_CLK_END }; + enum ldb_di_clock ldb_di_clk[] = { MXC_MMDC_CH1_CLK, MXC_MMDC_CH1_CLK }; + + of_assigned_ldb_sels(dev, &ldb_di_sel[0], &ldb_di_sel[1]); + for (int i = 0; i < 2; i++) { + switch (ldb_di_sel[i]) { + case IMX6QDL_CLK_PLL5_VIDEO_DIV: + ldb_di_clk[i] = MXC_PLL5_CLK; + break; + case IMX6QDL_CLK_PLL2_PFD0_352M: + ldb_di_clk[i] = MXC_PLL2_PFD0_CLK; + break; + case IMX6QDL_CLK_PLL2_PFD2_396M: { + struct clk *clk, *parent; + + int err = clk_get_by_id(IMX6QDL_CLK_PERIPH_PRE, &clk); + + if (err) { + pr_err("%s: failed to get periph_pre clock " + "(%d)\n", + dev->name, err); + return; + } + + err = clk_get_by_id(IMX6QDL_CLK_PLL2_PFD2_396M, + &parent); + if (err) { + pr_err("%s: failed to get pll2_pfd2_396m clock" + " (%d)\n", + dev->name, err); + return; + } + + if (parent == clk) { + pr_err("%s: ldb_di%d_sel: couldn't disable " + "pll2_pfd2_396m clock\n", + dev->name, i); + return; + } + + ldb_di_clk[i] = MXC_PLL2_PFD2_CLK; + break; + } + case IMX6QDL_CLK_MMDC_CH1_AXI: + case IMX6QDL_CLK_END: + /* use the default clock */ + break; + case IMX6QDL_CLK_PLL3_USB_OTG: + ldb_di_clk[i] = MXC_PLL3_SW_CLK; + break; + default: + pr_err("%s: invalid LDB clock parent\n", dev->name); + return; + } + } + + select_ldb_di_clock_source(ldb_di_clk[0], ldb_di_clk[1]); +} +#endif /* CONFIG_IS_ENABLED(VIDEO) */ + static int imx6q_clk_probe(struct udevice *dev) { void *base; @@ -120,26 +281,70 @@ static int imx6q_clk_probe(struct udevice *dev) /* Anatop clocks */ base = (void *)ANATOP_BASE_ADDR; - clk_dm(IMX6QDL_CLK_PLL2, - imx_clk_pllv3(dev, IMX_PLLV3_GENERIC, "pll2_bus", "osc", - base + 0x30, 0x1)); + clk_dm(IMX6QDL_PLL2_BYPASS_SRC, + imx_clk_mux(dev, "pll2_bypass_src", base + 0x30, 14, 2, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + clk_dm(IMX6QDL_PLL3_BYPASS_SRC, + imx_clk_mux(dev, "pll3_bypass_src", base + 0x10, 14, 2, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + clk_dm(IMX6QDL_PLL5_BYPASS_SRC, + imx_clk_mux(dev, "pll5_bypass_src", base + 0xa0, 14, 2, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + clk_dm(IMX6QDL_PLL6_BYPASS_SRC, + imx_clk_mux(dev, "pll6_bypass_src", base + 0xe0, 14, 2, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + + clk_dm(IMX6QDL_CLK_PLL2, imx_clk_pllv3(dev, IMX_PLLV3_GENERIC, "pll2", + "osc", base + 0x30, 0x1)); + clk_dm(IMX6QDL_CLK_PLL3, imx_clk_pllv3(dev, IMX_PLLV3_USB, "pll3", + "osc", base + 0x10, 0x3)); + clk_dm(IMX6QDL_CLK_PLL5, imx_clk_pllv3(dev, IMX_PLLV3_AV, "pll5", "osc", + base + 0xa0, 0x7f)); + clk_dm(IMX6QDL_CLK_PLL6, imx_clk_pllv3(dev, IMX_PLLV3_ENET, "pll6", + "osc", base + 0xe0, 0x3)); + + clk_dm(IMX6QDL_PLL2_BYPASS, + imx_clk_mux_flags(dev, "pll2_bypass", base + 0x30, 16, 1, + pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX6QDL_PLL3_BYPASS, + imx_clk_mux_flags(dev, "pll3_bypass", base + 0x10, 16, 1, + pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX6QDL_PLL5_BYPASS, + imx_clk_mux_flags(dev, "pll5_bypass", base + 0xa0, 16, 1, + pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX6QDL_PLL6_BYPASS, + imx_clk_mux_flags(dev, "pll6_bypass", base + 0xe0, 16, 1, + pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), + CLK_SET_RATE_PARENT)); + + SET_CLK_PARENT(IMX6QDL_PLL2_BYPASS, IMX6QDL_CLK_PLL2); + SET_CLK_PARENT(IMX6QDL_PLL3_BYPASS, IMX6QDL_CLK_PLL3); + SET_CLK_PARENT(IMX6QDL_PLL5_BYPASS, IMX6QDL_CLK_PLL5); + SET_CLK_PARENT(IMX6QDL_PLL6_BYPASS, IMX6QDL_CLK_PLL6); + + clk_dm(IMX6QDL_CLK_PLL2_BUS, + imx_clk_gate(dev, "pll2_bus", "pll2_bypass", base + 0x30, 13)); clk_dm(IMX6QDL_CLK_PLL3_USB_OTG, - imx_clk_pllv3(dev, IMX_PLLV3_USB, "pll3_usb_otg", "osc", - base + 0x10, 0x3)); + imx_clk_gate(dev, "pll3_usb_otg", "pll3_bypass", base + 0x10, + 13)); + clk_dm(IMX6QDL_CLK_PLL5_VIDEO, + imx_clk_gate(dev, "pll5_video", "pll5_bypass", base + 0xa0, 13)); + clk_dm(IMX6QDL_CLK_PLL6_ENET, + imx_clk_gate(dev, "pll6_enet", "pll6_bypass", base + 0xe0, 13)); + clk_dm(IMX6QDL_CLK_PLL3_60M, imx_clk_fixed_factor(dev, "pll3_60m", "pll3_usb_otg", 1, 8)); clk_dm(IMX6QDL_CLK_PLL3_80M, imx_clk_fixed_factor(dev, "pll3_80m", "pll3_usb_otg", 1, 6)); clk_dm(IMX6QDL_CLK_PLL3_120M, imx_clk_fixed_factor(dev, "pll3_120m", "pll3_usb_otg", 1, 4)); - clk_dm(IMX6QDL_CLK_PLL5, imx_clk_pllv3(dev, IMX_PLLV3_AV, "pll5", "osc", - base + 0xa0, 0x7f)); - clk_dm(IMX6QDL_CLK_PLL5_VIDEO, - imx_clk_gate(dev, "pll5_video", "pll5", base + 0xa0, 13)); - clk_dm(IMX6QDL_CLK_PLL6, imx_clk_pllv3(dev, IMX_PLLV3_ENET, "pll6", - "osc", base + 0xe0, 0x3)); - clk_dm(IMX6QDL_CLK_PLL6_ENET, - imx_clk_gate(dev, "pll6_enet", "pll6", base + 0xe0, 13)); clk_dm(IMX6QDL_CLK_PLL2_PFD0_352M, imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0)); @@ -151,10 +356,14 @@ static int imx6q_clk_probe(struct udevice *dev) clk_dm(IMX6QDL_CLK_PLL2_198M, imx_clk_fixed_factor(dev, "pll2_198m", "pll2_pfd2_396m", 1, 2)); clk_dm(IMX6QDL_CLK_PLL5_POST_DIV, - imx_clk_fixed_factor(dev, "pll5_post_div", "pll5_video", 1, 1)); + clk_register_divider_table(dev, "pll5_post_div", "pll5_video", + CLK_SET_RATE_PARENT, base + 0xa0, 19, + 2, 0, post_div_table)); clk_dm(IMX6QDL_CLK_PLL5_VIDEO_DIV, - imx_clk_fixed_factor(dev, "pll5_video_div", "pll5_post_div", 1, - 1)); + clk_register_divider_table(dev, "pll5_video_div", + "pll5_post_div", CLK_SET_RATE_PARENT, + base + 0x170, 30, 2, 0, + video_div_table)); clk_dm(IMX6QDL_CLK_VIDEO_27M, imx_clk_fixed_factor(dev, "video_27m", "pll3_pfd1_540m", 1, 20)); @@ -263,6 +472,7 @@ static int imx6q_clk_probe(struct udevice *dev) imx_clk_gate2(dev, "mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22)); +#if CONFIG_IS_ENABLED(VIDEO) clk_dm(IMX6QDL_CLK_IPU1_SEL, imx_clk_mux(dev, "ipu1_sel", base + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels))); @@ -279,9 +489,12 @@ static int imx6q_clk_probe(struct udevice *dev) ldb_di_sels, ARRAY_SIZE(ldb_di_sels))); } else { /* - * Need to set these as read-only due to a hardware bug. - * Keeping default mux values. Fixed on the i.MX6 QuadPlus - */ + * Need to set these as read-only due to a hardware bug. + * Keeping default mux values. Fixed on the i.MX6 QuadPlus + * Need to set the clocks now and make them read-only due to a + * hardware bug. Fixed on the i.MX6 QuadPlus + */ + imx6q_init_ldb_clks(dev); clk_dm(IMX6QDL_CLK_LDB_DI0_SEL, imx_clk_mux_flags(dev, "ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), @@ -413,6 +626,7 @@ static int imx6q_clk_probe(struct udevice *dev) ARRAY_SIZE(ipu2_di1_sels), CLK_SET_RATE_PARENT)); } +#endif /* CONFIG_IS_ENABLED(VIDEO) */ clk_dm(IMX6QDL_CLK_ECSPI1, imx_clk_gate2(dev, "ecspi1", "ecspi_root", base + 0x6c, 0)); @@ -453,6 +667,8 @@ static int imx6q_clk_probe(struct udevice *dev) imx_clk_gate2(dev, "enet", "ipg", base + 0x6c, 10)); clk_dm(IMX6QDL_CLK_ENET_REF, imx_clk_fixed_factor(dev, "enet_ref", "pll6_enet", 1, 1)); + +#if CONFIG_IS_ENABLED(VIDEO) clk_dm(IMX6QDL_CLK_MIPI_CORE_CFG, imx_clk_gate2_shared(dev, "mipi_core_cfg", "video_27m", base + 0x74, 16, @@ -480,6 +696,7 @@ static int imx6q_clk_probe(struct udevice *dev) SET_CLK_PARENT(IMX6QDL_CLK_IPU1_SEL, IMX6QDL_CLK_PLL3_PFD1_540M); } +#endif /* CONFIG_IS_ENABLED(VIDEO) */ return 0; } diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index fe6cba19758..78156003ad9 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2019 NXP + * Copyright 2019, 2026 NXP * Copyright 2022 Purism * Peng Fan <[email protected]> */ @@ -155,39 +155,52 @@ static int imx8mq_clk_probe(struct udevice *dev) imx_clk_mux(dev, "dram_pll_ref_sel", base + 0x60, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_ARM_PLL_REF_SEL, - imx_clk_mux(dev, "arm_pll_ref_sel", base + 0x28, 0, 2, + imx_clk_mux(dev, "arm_pll_ref_sel", base + 0x28, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_GPU_PLL_REF_SEL, - imx_clk_mux(dev, "gpu_pll_ref_sel", base + 0x18, 0, 2, + imx_clk_mux(dev, "gpu_pll_ref_sel", base + 0x18, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_VPU_PLL_REF_SEL, - imx_clk_mux(dev, "vpu_pll_ref_sel", base + 0x20, 0, 2, + imx_clk_mux(dev, "vpu_pll_ref_sel", base + 0x20, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_SYS3_PLL1_REF_SEL, imx_clk_mux(dev, "sys3_pll_ref_sel", base + 0x48, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_AUDIO_PLL1_REF_SEL, - imx_clk_mux(dev, "audio_pll1_ref_sel", base + 0x0, 0, 2, + imx_clk_mux(dev, "audio_pll1_ref_sel", base + 0x0, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_AUDIO_PLL2_REF_SEL, - imx_clk_mux(dev, "audio_pll2_ref_sel", base + 0x8, 0, 2, + imx_clk_mux(dev, "audio_pll2_ref_sel", base + 0x8, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_VIDEO_PLL1_REF_SEL, - imx_clk_mux(dev, "video_pll1_ref_sel", base + 0x10, 0, 2, + imx_clk_mux(dev, "video_pll1_ref_sel", base + 0x10, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_VIDEO2_PLL1_REF_SEL, imx_clk_mux(dev, "video_pll2_ref_sel", base + 0x54, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MQ_ARM_PLL_REF_DIV, + imx_clk_divider(dev, "arm_pll_ref_div", "arm_pll_ref_sel", base + 0x28, 5, 6)); + clk_dm(IMX8MQ_GPU_PLL_REF_DIV, + imx_clk_divider(dev, "gpu_pll_ref_div", "gpu_pll_ref_sel", base + 0x18, 5, 6)); + clk_dm(IMX8MQ_VPU_PLL_REF_DIV, + imx_clk_divider(dev, "vpu_pll_ref_div", "vpu_pll_ref_sel", base + 0x20, 5, 6)); + clk_dm(IMX8MQ_AUDIO_PLL1_REF_DIV, + imx_clk_divider(dev, "audio_pll1_ref_div", "audio_pll1_ref_sel", base + 0x0, 5, 6)); + clk_dm(IMX8MQ_AUDIO_PLL2_REF_DIV, + imx_clk_divider(dev, "audio_pll2_ref_div", "audio_pll2_ref_sel", base + 0x8, 5, 6)); + clk_dm(IMX8MQ_VIDEO_PLL1_REF_DIV, + imx_clk_divider(dev, "video_pll1_ref_div", "video_pll1_ref_sel", base + 0x10, 5, 6)); + clk_dm(IMX8MQ_ARM_PLL, - imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", - base + 0x28, &imx_1416x_pll)); + imx_clk_frac_pll("arm_pll", "arm_pll_ref_div", + base + 0x28)); clk_dm(IMX8MQ_GPU_PLL, - imx_clk_pll14xx("gpu_pll", "gpu_pll_ref_sel", - base + 0x18, &imx_1416x_pll)); + imx_clk_frac_pll("gpu_pll", "gpu_pll_ref_div", + base + 0x18)); clk_dm(IMX8MQ_VPU_PLL, - imx_clk_pll14xx("vpu_pll", "vpu_pll_ref_sel", - base + 0x20, &imx_1416x_pll)); + imx_clk_frac_pll("vpu_pll", "vpu_pll_ref_div", + base + 0x20)); clk_dm(IMX8MQ_SYS1_PLL1, clk_register_fixed_rate(NULL, "sys1_pll", 800000000)); @@ -196,14 +209,14 @@ static int imx8mq_clk_probe(struct udevice *dev) clk_dm(IMX8MQ_SYS2_PLL1, clk_register_fixed_rate(NULL, "sys3_pll", 1000000000)); clk_dm(IMX8MQ_AUDIO_PLL1, - imx_clk_pll14xx("audio_pll1", "audio_pll1_ref_sel", - base + 0x0, &imx_1443x_pll)); + imx_clk_frac_pll("audio_pll1", "audio_pll1_ref_div", + base + 0x0)); clk_dm(IMX8MQ_AUDIO_PLL2, - imx_clk_pll14xx("audio_pll2", "audio_pll2_ref_sel", - base + 0x8, &imx_1443x_pll)); + imx_clk_frac_pll("audio_pll2", "audio_pll2_ref_div", + base + 0x8)); clk_dm(IMX8MQ_VIDEO_PLL1, - imx_clk_pll14xx("video_pll1", "video_pll1_ref_sel", - base + 0x10, &imx_1443x_pll)); + imx_clk_frac_pll("video_pll1", "video_pll1_ref_div", + base + 0x10)); /* PLL bypass out */ clk_dm(IMX8MQ_ARM_PLL_BYPASS, @@ -356,8 +369,8 @@ static int imx8mq_clk_probe(struct udevice *dev) clk_dm(IMX8MQ_CLK_A53_DIV, imx_clk_divider2(dev, "arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3)); - clk_dm(IMX8MQ_CLK_A53_CORE, - imx_clk_mux2(dev, "arm_a53_src", base + 0x9880, 24, 1, + clk_dm(IMX8MQ_CLK_ARM, + imx_clk_mux2(dev, "arm_a53_core", base + 0x9880, 24, 1, imx8mq_a53_core_sels, ARRAY_SIZE(imx8mq_a53_core_sels))); clk_dm(IMX8MQ_CLK_AHB, diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index b53f35df84f..6aef72c0212 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -78,6 +78,9 @@ struct clk *imx_clk_pll14xx(const char *name, const char *parent_name, void __iomem *base, const struct imx_pll14xx_clk *pll_clk); +struct clk *imx_clk_frac_pll(const char *name, const char *parent_name, + void __iomem *base); + struct clk *clk_register_gate2(struct udevice *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, u8 cgr_val, |
