summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2026-06-27 14:09:17 -0600
committerTom Rini <[email protected]>2026-06-27 14:09:17 -0600
commita3f393c02cf10f44310c6ddf3dedf354c2e877a0 (patch)
tree9b033e9e2e2433d212a3d8a18e054c2ca93078e4
parent6902fb4c17faa375003124c451c2550deab5463d (diff)
parent9b41032699cf8f7c25c883f7c12edba350fed1d8 (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.c75
-rw-r--r--drivers/clk/imx/Makefile2
-rw-r--r--drivers/clk/imx/clk-frac-pll.c199
-rw-r--r--drivers/clk/imx/clk-imx8mq.c55
-rw-r--r--drivers/clk/imx/clk.h3
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,