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
This commit is contained in:
Tom Rini
2026-06-27 14:09:17 -06:00
5 changed files with 292 additions and 42 deletions
+55 -20
View File
@@ -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);
}
+1 -1
View File
@@ -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
+199
View File
@@ -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,
};
+34 -21
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 NXP
* Copyright 2019, 2026 NXP
* Copyright 2022 Purism
* Peng Fan <peng.fan@nxp.com>
*/
@@ -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,
+3
View File
@@ -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,