diff options
| author | Tom Rini <[email protected]> | 2026-06-27 14:09:17 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2026-06-27 14:09:17 -0600 |
| commit | a3f393c02cf10f44310c6ddf3dedf354c2e877a0 (patch) | |
| tree | 9b033e9e2e2433d212a3d8a18e054c2ca93078e4 | |
| parent | 6902fb4c17faa375003124c451c2550deab5463d (diff) | |
| parent | 9b41032699cf8f7c25c883f7c12edba350fed1d8 (diff) | |
Merge tag 'u-boot-imx-master-20260627' of https://gitlab.denx.de/u-boot/custodians/u-boot-imxHEADmaster
CI: https://source.denx.de/u-boot/custodians/u-boot-imx/-/pipelines/30543
- Fix MAC address representation on i.MX9
- Fix iMX8MQ PLL
- Fix SPL trampoline buffer for 1GB DDR on i.MX9
| -rw-r--r-- | arch/arm/mach-imx/imx9/scmi/soc.c | 75 | ||||
| -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-imx8mq.c | 55 | ||||
| -rw-r--r-- | drivers/clk/imx/clk.h | 3 |
5 files changed, 292 insertions, 42 deletions
diff --git a/arch/arm/mach-imx/imx9/scmi/soc.c b/arch/arm/mach-imx/imx9/scmi/soc.c index fbee435786c..e73f8c29d57 100644 --- a/arch/arm/mach-imx/imx9/scmi/soc.c +++ b/arch/arm/mach-imx/imx9/scmi/soc.c @@ -507,6 +507,35 @@ phys_size_t get_effective_memsize(void) } } +static inline u64 ether_addr_to_u64(const u8 *addr) +{ + u64 u = 0; + int i; + + for (i = 0; i < 6; i++) + u = u << 8 | addr[i]; + + return u; +} + +static inline void u64_to_ether_addr(u64 u, u8 *addr) +{ + int i; + + for (i = 6 - 1; i >= 0; i--) { + addr[i] = u & 0xff; + u = u >> 8; + } +} + +static inline void eth_addr_add(u8 *addr, long offset) +{ + u64 u = ether_addr_to_u64(addr); + + u += offset; + u64_to_ether_addr(u, addr); +} + void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) { u32 val[2] = {}; @@ -551,16 +580,16 @@ void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) * | 10 | netc switch | swp2 | */ if (dev_id == 0) - mac[5] = mac[5] + 2; /* enetc3 mac/swp0 */ + eth_addr_add(mac, 2); /* enetc3 mac/swp0 */ if (dev_id == 1) - mac[5] = mac[5] + 8; /* enetc1 */ + eth_addr_add(mac, 8); /* enetc1 */ if (dev_id == 2) - mac[5] = mac[5] + 9; /* enetc2 */ + eth_addr_add(mac, 9); /* enetc2 */ } else { if (dev_id == 1) - mac[5] = mac[5] + 3; + eth_addr_add(mac, 3); if (dev_id == 2) - mac[5] = mac[5] + 6; + eth_addr_add(mac, 6); } debug("%s: MAC%d: %pM\n", __func__, dev_id, mac); @@ -665,11 +694,11 @@ int get_reset_reason(bool sys, bool lm) } if (out.shutdownflags & MISC_SHUTDOWN_FLAG_VLD) { printf("SYS shutdown reason: %s, origin: %ld, errid: %ld\n", - rst[out.bootflags & MISC_SHUTDOWN_FLAG_REASON], - out.bootflags & MISC_SHUTDOWN_FLAG_ORG_VLD ? - FIELD_GET(MISC_SHUTDOWN_FLAG_ORIGIN, out.bootflags) : -1, - out.bootflags & MISC_SHUTDOWN_FLAG_ERR_VLD ? - FIELD_GET(MISC_SHUTDOWN_FLAG_ERR_ID, out.bootflags) : -1 + rst[out.shutdownflags & MISC_SHUTDOWN_FLAG_REASON], + out.shutdownflags & MISC_SHUTDOWN_FLAG_ORG_VLD ? + FIELD_GET(MISC_SHUTDOWN_FLAG_ORIGIN, out.shutdownflags) : -1, + out.shutdownflags & MISC_SHUTDOWN_FLAG_ERR_VLD ? + FIELD_GET(MISC_SHUTDOWN_FLAG_ERR_ID, out.shutdownflags) : -1 ); } } @@ -696,11 +725,11 @@ int get_reset_reason(bool sys, bool lm) if (out.shutdownflags & MISC_SHUTDOWN_FLAG_VLD) { printf("LM shutdown reason: %s, origin: %ld, errid: %ld\n", - rst[out.bootflags & MISC_SHUTDOWN_FLAG_REASON], - out.bootflags & MISC_SHUTDOWN_FLAG_ORG_VLD ? - FIELD_GET(MISC_SHUTDOWN_FLAG_ORIGIN, out.bootflags) : -1, - out.bootflags & MISC_SHUTDOWN_FLAG_ERR_VLD ? - FIELD_GET(MISC_SHUTDOWN_FLAG_ERR_ID, out.bootflags) : -1 + rst[out.shutdownflags & MISC_SHUTDOWN_FLAG_REASON], + out.shutdownflags & MISC_SHUTDOWN_FLAG_ORG_VLD ? + FIELD_GET(MISC_SHUTDOWN_FLAG_ORIGIN, out.shutdownflags) : -1, + out.shutdownflags & MISC_SHUTDOWN_FLAG_ERR_VLD ? + FIELD_GET(MISC_SHUTDOWN_FLAG_ERR_ID, out.shutdownflags) : -1 ); } } @@ -985,10 +1014,11 @@ enum boot_device get_boot_device(void) bool arch_check_dst_in_secure(void *start, ulong size) { - ulong ns_end = CFG_SYS_SDRAM_BASE + PHYS_SDRAM_SIZE; -#ifdef PHYS_SDRAM_2_SIZE - ns_end += PHYS_SDRAM_2_SIZE; -#endif + ulong ns_end; + phys_size_t dram_size; + + board_phys_sdram_size(&dram_size); + ns_end = CFG_SYS_SDRAM_BASE + dram_size; if ((ulong)start < CFG_SYS_SDRAM_BASE || (ulong)start + size > ns_end) return true; @@ -998,5 +1028,10 @@ bool arch_check_dst_in_secure(void *start, ulong size) void *arch_get_container_trampoline(void) { - return (void *)((ulong)CFG_SYS_SDRAM_BASE + PHYS_SDRAM_SIZE - SZ_16M); + phys_size_t size; + + board_phys_sdram_size(&size); + size = (size > PHYS_SDRAM_SIZE) ? PHYS_SDRAM_SIZE : size; + + return (void *)((ulong)CFG_SYS_SDRAM_BASE + size - SZ_16M); } 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-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, |
