* [PATCH v2 2/7] clk: imx6q: add missing pll bypasses
2026-04-28 8:51 [PATCH v2 1/7] clk: imx6q: cosmetic: keep pll definitions together Brian Ruley
@ 2026-04-28 8:51 ` Brian Ruley
2026-04-28 8:51 ` [PATCH v2 3/7] imx6: clock: allow different clock sources for ldb Brian Ruley
` (4 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: Brian Ruley @ 2026-04-28 8:51 UTC (permalink / raw)
To: festevam, Lukasz Majewski, Tom Rini; +Cc: brian.ruley, u-boot
After reset, all PLLs are bypassed by default so unbypass them so that
dependent clocks can function correctly.
Signed-off-by: Brian Ruley <brian.ruley@gehealthcare.com>
---
Changes for v2:
- Fix unused variable warning
- Fix checkpatch findings (const identifier, spacing)
---
drivers/clk/imx/clk-imx6q.c | 90 ++++++++++++++++++++++++++++++++-----
1 file changed, 80 insertions(+), 10 deletions(-)
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index cd06d211e8d..6dadfd9b59c 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -111,6 +111,33 @@ static const char *ipu2_di1_sels_2[] = {
"ipu2_di1_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf",
};
+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 unsigned int share_count_mipi_core_cfg;
static int imx6q_clk_probe(struct udevice *dev)
@@ -120,27 +147,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_CLK_PLL3_USB_OTG,
- imx_clk_pllv3(dev, IMX_PLLV3_USB, "pll3_usb_otg", "osc",
- base + 0x10, 0x3));
+ 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_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_VIDEO,
- imx_clk_gate(dev, "pll5_video", "pll5", base + 0xa0, 13));
- 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));
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 3/7] imx6: clock: allow different clock sources for ldb
2026-04-28 8:51 [PATCH v2 1/7] clk: imx6q: cosmetic: keep pll definitions together Brian Ruley
2026-04-28 8:51 ` [PATCH v2 2/7] clk: imx6q: add missing pll bypasses Brian Ruley
@ 2026-04-28 8:51 ` Brian Ruley
2026-04-29 2:20 ` Peng Fan
2026-05-15 2:18 ` Fabio Estevam
2026-04-28 8:51 ` [PATCH v2 4/7] clk: imx6q: configure ldb clock selectors Brian Ruley
` (3 subsequent siblings)
5 siblings, 2 replies; 11+ messages in thread
From: Brian Ruley @ 2026-04-28 8:51 UTC (permalink / raw)
To: festevam, Stefano Babic, NXP i.MX U-Boot Team, Tom Rini,
Heiko Schocher, Huan 'Kitty' Wang, Ian Ray, Martyn Welch
Cc: brian.ruley, lukma, u-boot
The LDB clock sources don't have to be the same, so allow DI1 clock to
be configured separately.
Unlikely to be significant, but the reason will become apparent in the
following commit.
Signed-off-by: Brian Ruley <brian.ruley@gehealthcare.com>
---
arch/arm/include/asm/arch-mx6/clock.h | 2 +-
arch/arm/mach-imx/mx6/clock.c | 6 +++---
board/aristainetos/aristainetos.c | 2 +-
board/ge/b1x5v2/b1x5v2.c | 2 +-
board/ge/bx50v3/bx50v3.c | 2 +-
5 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/arch/arm/include/asm/arch-mx6/clock.h b/arch/arm/include/asm/arch-mx6/clock.h
index 81af89c631f..9c5f3090bd8 100644
--- a/arch/arm/include/asm/arch-mx6/clock.h
+++ b/arch/arm/include/asm/arch-mx6/clock.h
@@ -82,7 +82,7 @@ int enable_lcdif_clock(u32 base_addr, bool enable);
void enable_qspi_clk(int qspi_num);
void enable_thermal_clk(void);
void mxs_set_lcdclk(u32 base_addr, u32 freq);
-void select_ldb_di_clock_source(enum ldb_di_clock clk);
+void select_ldb_di_clock_source(enum ldb_di_clock clk0, enum ldb_di_clock clk1);
void enable_eim_clk(unsigned char enable);
int do_mx6_showclocks(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]);
diff --git a/arch/arm/mach-imx/mx6/clock.c b/arch/arm/mach-imx/mx6/clock.c
index b5aa606b8d0..828a101ba05 100644
--- a/arch/arm/mach-imx/mx6/clock.c
+++ b/arch/arm/mach-imx/mx6/clock.c
@@ -1452,7 +1452,7 @@ static void enable_ldb_di_clock_sources(void)
* Try call this function as early in the boot process as possible since the
* function temporarily disables PLL2 PFD's, PLL3 PFD's and PLL5.
*/
-void select_ldb_di_clock_source(enum ldb_di_clock clk)
+void select_ldb_di_clock_source(enum ldb_di_clock clk0, enum ldb_di_clock clk1)
{
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
int reg;
@@ -1525,8 +1525,8 @@ void select_ldb_di_clock_source(enum ldb_di_clock clk)
reg = readl(&mxc_ccm->cs2cdr);
reg &= ~(MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK
| MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK);
- reg |= ((clk << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET)
- | (clk << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET));
+ reg |= ((clk0 << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET)
+ | (clk1 << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET));
writel(reg, &mxc_ccm->cs2cdr);
/* Unbypass pll3_sw_clk */
diff --git a/board/aristainetos/aristainetos.c b/board/aristainetos/aristainetos.c
index 8cfac9fbb34..4a2349e165b 100644
--- a/board/aristainetos/aristainetos.c
+++ b/board/aristainetos/aristainetos.c
@@ -218,7 +218,7 @@ static void set_gpr_register(void)
int board_early_init_f(void)
{
- select_ldb_di_clock_source(MXC_PLL5_CLK);
+ select_ldb_di_clock_source(MXC_PLL5_CLK, MXC_PLL5_CLK);
set_gpr_register();
/*
diff --git a/board/ge/b1x5v2/b1x5v2.c b/board/ge/b1x5v2/b1x5v2.c
index ddb7304d493..f7751fd6fb1 100644
--- a/board/ge/b1x5v2/b1x5v2.c
+++ b/board/ge/b1x5v2/b1x5v2.c
@@ -320,7 +320,7 @@ int overwrite_console(void)
int board_early_init_f(void)
{
- select_ldb_di_clock_source(MXC_PLL5_CLK);
+ select_ldb_di_clock_source(MXC_PLL5_CLK, MXC_PLL5_CLK);
return 0;
}
diff --git a/board/ge/bx50v3/bx50v3.c b/board/ge/bx50v3/bx50v3.c
index e1d08475e94..9fc5f604a49 100644
--- a/board/ge/bx50v3/bx50v3.c
+++ b/board/ge/bx50v3/bx50v3.c
@@ -383,7 +383,7 @@ int board_early_init_f(void)
#if defined(CONFIG_VIDEO_IPUV3)
/* Set LDB clock to Video PLL */
- select_ldb_di_clock_source(MXC_PLL5_CLK);
+ select_ldb_di_clock_source(MXC_PLL5_CLK, MXC_PLL5_CLK);
#endif
return 0;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH v2 3/7] imx6: clock: allow different clock sources for ldb
2026-04-28 8:51 ` [PATCH v2 3/7] imx6: clock: allow different clock sources for ldb Brian Ruley
@ 2026-04-29 2:20 ` Peng Fan
2026-04-29 11:22 ` Brian Ruley
2026-05-15 2:18 ` Fabio Estevam
1 sibling, 1 reply; 11+ messages in thread
From: Peng Fan @ 2026-04-29 2:20 UTC (permalink / raw)
To: Brian Ruley
Cc: festevam, Stefano Babic, NXP i.MX U-Boot Team, Tom Rini,
Heiko Schocher, Huan 'Kitty' Wang, Ian Ray, Martyn Welch,
lukma, u-boot
On Tue, Apr 28, 2026 at 11:51:08AM +0300, Brian Ruley wrote:
>The LDB clock sources don't have to be the same, so allow DI1 clock to
>be configured separately.
>
>Unlikely to be significant, but the reason will become apparent in the
>following commit.
>
>Signed-off-by: Brian Ruley <brian.ruley@gehealthcare.com>
I not see other patches in this thread. Have they been sent out to list?
Regards
Peng
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 3/7] imx6: clock: allow different clock sources for ldb
2026-04-29 2:20 ` Peng Fan
@ 2026-04-29 11:22 ` Brian Ruley
0 siblings, 0 replies; 11+ messages in thread
From: Brian Ruley @ 2026-04-29 11:22 UTC (permalink / raw)
To: Peng Fan
Cc: festevam, Stefano Babic, NXP i.MX U-Boot Team, Tom Rini,
Heiko Schocher, Huan 'Kitty' Wang, Ian Ray, Martyn Welch,
lukma, u-boot
On Apr 29, Peng Fan wrote:
> CAUTION: This email originated from outside of GE HealthCare. Only open links or attachments if you trust the sender. Report suspicious emails using Outlook’s “Report” button.
>
> On Tue, Apr 28, 2026 at 11:51:08AM +0300, Brian Ruley wrote:
> >The LDB clock sources don't have to be the same, so allow DI1 clock to
> >be configured separately.
> >
> >Unlikely to be significant, but the reason will become apparent in the
> >following commit.
> >
> >Signed-off-by: Brian Ruley <brian.ruley@gehealthcare.com>
>
> I not see other patches in this thread. Have they been sent out to list?
>
> Regards
> Peng
Hi Peng,
Did you find it on the list?
If not:
https://lore.kernel.org/u-boot/20260428085117.402523-1-brian.ruley@gehealthcare.com/T/#t
BR,
Brian
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 3/7] imx6: clock: allow different clock sources for ldb
2026-04-28 8:51 ` [PATCH v2 3/7] imx6: clock: allow different clock sources for ldb Brian Ruley
2026-04-29 2:20 ` Peng Fan
@ 2026-05-15 2:18 ` Fabio Estevam
2026-05-15 6:05 ` Brian Ruley
1 sibling, 1 reply; 11+ messages in thread
From: Fabio Estevam @ 2026-05-15 2:18 UTC (permalink / raw)
To: Brian Ruley
Cc: Stefano Babic, NXP i.MX U-Boot Team, Tom Rini, Heiko Schocher,
Huan 'Kitty' Wang, Ian Ray, Martyn Welch, lukma, u-boot
On Tue, Apr 28, 2026 at 5:51 AM Brian Ruley
<brian.ruley@gehealthcare.com> wrote:
>
> The LDB clock sources don't have to be the same, so allow DI1 clock to
> be configured separately.
>
> Unlikely to be significant, but the reason will become apparent in the
> following commit.
>
> Signed-off-by: Brian Ruley <brian.ruley@gehealthcare.com>
Once again, this series does not pass CI:
https://source.denx.de/u-boot/custodians/u-boot-imx/-/jobs/1450024
arm: + kp_imx6q_tpc
+arm-linux-gnueabi-ld: u-boot-spl section `__u_boot_list' will not fit
in region `.sram'
+arm-linux-gnueabi-ld: region `.sram' overflowed by 200 bytes
+arm-linux-gnueabi-ld: drivers/clk/imx/clk-imx6q.o: in function
`imx6q_init_ldb_clks':
+drivers/clk/imx/clk-imx6q.c:271:(.text.imx6q_clk_probe+0x1458):
undefined reference to `select_ldb_di_clock_source'
+make[2]: *** [scripts/Makefile.xpl:546: spl/u-boot-spl] Error 1
+make[1]: *** [Makefile:2440: spl/u-boot-spl] Error 2
+make: *** [Makefile:189: __sub-make] Error 2
For v3, please share a URL with a green CI pass; otherwise, I'll need
to ignore it.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 3/7] imx6: clock: allow different clock sources for ldb
2026-05-15 2:18 ` Fabio Estevam
@ 2026-05-15 6:05 ` Brian Ruley
0 siblings, 0 replies; 11+ messages in thread
From: Brian Ruley @ 2026-05-15 6:05 UTC (permalink / raw)
To: Fabio Estevam
Cc: Stefano Babic, NXP i.MX U-Boot Team, Tom Rini, Heiko Schocher,
Huan 'Kitty' Wang, Ian Ray, Martyn Welch, lukma, u-boot
On May 14, Fabio Estevam wrote:
> CAUTION: This email originated from outside of GE HealthCare. Only open links or attachments if you trust the sender. Report suspicious emails using Outlook’s “Report” button.
>
> On Tue, Apr 28, 2026 at 5:51 AM Brian Ruley
> <brian.ruley@gehealthcare.com> wrote:
> >
> > The LDB clock sources don't have to be the same, so allow DI1 clock to
> > be configured separately.
> >
> > Unlikely to be significant, but the reason will become apparent in the
> > following commit.
> >
> > Signed-off-by: Brian Ruley <brian.ruley@gehealthcare.com>
>
> Once again, this series does not pass CI:
>
> https://source.denx.de/u-boot/custodians/u-boot-imx/-/jobs/1450024
>
> arm: + kp_imx6q_tpc
> +arm-linux-gnueabi-ld: u-boot-spl section `__u_boot_list' will not fit
> in region `.sram'
> +arm-linux-gnueabi-ld: region `.sram' overflowed by 200 bytes
> +arm-linux-gnueabi-ld: drivers/clk/imx/clk-imx6q.o: in function
> `imx6q_init_ldb_clks':
> +drivers/clk/imx/clk-imx6q.c:271:(.text.imx6q_clk_probe+0x1458):
> undefined reference to `select_ldb_di_clock_source'
> +make[2]: *** [scripts/Makefile.xpl:546: spl/u-boot-spl] Error 1
> +make[1]: *** [Makefile:2440: spl/u-boot-spl] Error 2
> +make: *** [Makefile:189: __sub-make] Error 2
>
> For v3, please share a URL with a green CI pass; otherwise, I'll need
> to ignore it.
Apologies!
I honestly did not believe there to be any issues anymore, and at the
time I did not have access to the GitLab CI, so I ran some additional
tests locally.
This was an error of judgement on my part, V3 will have a link to
passed CI.
Best regards,
Brian
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 4/7] clk: imx6q: configure ldb clock selectors
2026-04-28 8:51 [PATCH v2 1/7] clk: imx6q: cosmetic: keep pll definitions together Brian Ruley
2026-04-28 8:51 ` [PATCH v2 2/7] clk: imx6q: add missing pll bypasses Brian Ruley
2026-04-28 8:51 ` [PATCH v2 3/7] imx6: clock: allow different clock sources for ldb Brian Ruley
@ 2026-04-28 8:51 ` Brian Ruley
2026-04-28 8:51 ` [PATCH v2 5/7] video: imx: ipuv3: enable ipu clk before writing registers in CCF Brian Ruley
` (2 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: Brian Ruley @ 2026-04-28 8:51 UTC (permalink / raw)
To: festevam, Lukasz Majewski, Tom Rini; +Cc: brian.ruley, u-boot
A hardware bug prevents LDB clock selectors from being configured later
on non-plus i.MX6QD variants, so let's set the desired configuration in
the probe before we register them.
Signed-off-by: Brian Ruley <brian.ruley@gehealthcare.com>
---
drivers/clk/imx/clk-imx6q.c | 121 +++++++++++++++++++++++++++++++++++-
1 file changed, 119 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index 6dadfd9b59c..ba039e56227 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"
@@ -140,6 +141,121 @@ static const char *const pll6_bypass_sels[] = {
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]);
+}
+
static int imx6q_clk_probe(struct udevice *dev)
{
void *base;
@@ -350,9 +466,10 @@ 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 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),
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 5/7] video: imx: ipuv3: enable ipu clk before writing registers in CCF
2026-04-28 8:51 [PATCH v2 1/7] clk: imx6q: cosmetic: keep pll definitions together Brian Ruley
` (2 preceding siblings ...)
2026-04-28 8:51 ` [PATCH v2 4/7] clk: imx6q: configure ldb clock selectors Brian Ruley
@ 2026-04-28 8:51 ` Brian Ruley
2026-04-28 8:51 ` [PATCH v2 6/7] clk: clk-divider: add clk_register_divider_table() Brian Ruley
2026-04-28 8:51 ` [PATCH v2 7/7] clk: imx6q: use clk_divider_table instead of fixed factor for pll5 divs Brian Ruley
5 siblings, 0 replies; 11+ messages in thread
From: Brian Ruley @ 2026-04-28 8:51 UTC (permalink / raw)
To: festevam, Anatolij Gustschin, Tom Rini; +Cc: brian.ruley, lukma, u-boot
Obviously, the clock has to be enabled if writing to it's registers.
This was missed because the board I tested on had enabled the clocks in
early init.
Also, remove the completely useless "ipu_clk_enabled" struct member and
use the accurate usecount / enabled_count instead.
Signed-off-by: Brian Ruley <brian.ruley@gehealthcare.com>
---
drivers/video/imx/ipu.h | 1 -
drivers/video/imx/ipu_common.c | 13 +++++++------
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/video/imx/ipu.h b/drivers/video/imx/ipu.h
index ae40e20bc28..aecb6adffce 100644
--- a/drivers/video/imx/ipu.h
+++ b/drivers/video/imx/ipu.h
@@ -136,7 +136,6 @@ struct ipu_ctx {
struct clk *ipu_clk;
struct clk *ldb_clk;
- unsigned char ipu_clk_enabled;
struct clk *di_clk[2];
struct clk *pixel_clk[2];
diff --git a/drivers/video/imx/ipu_common.c b/drivers/video/imx/ipu_common.c
index 8630374a055..d3b52605731 100644
--- a/drivers/video/imx/ipu_common.c
+++ b/drivers/video/imx/ipu_common.c
@@ -299,9 +299,9 @@ struct ipu_ctx *ipu_probe(struct udevice *dev)
#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
clk_set_parent(ctx->pixel_clk[0], ctx->ipu_clk);
clk_set_parent(ctx->pixel_clk[1], ctx->ipu_clk);
+#endif
clk_enable(ctx->ipu_clk);
-#endif
for (int i = 0; i <= 1; i++) {
ret = ipu_di_clk_init(ctx, i);
@@ -384,10 +384,8 @@ int32_t ipu_init_channel(struct ipu_ctx *ctx, ipu_channel_t channel,
debug("init channel = %d\n", IPU_CHAN_ID(channel));
- if (ctx->ipu_clk_enabled == 0) {
- ctx->ipu_clk_enabled = 1;
+ if (!ipu_clk_enabled(ctx))
clk_enable(ipu_clk);
- }
if (*channel_init_mask & (1L << IPU_CHAN_ID(channel))) {
printf("Warning: channel already initialized %d\n",
@@ -543,7 +541,6 @@ void ipu_uninit_channel(struct ipu_ctx *ctx, ipu_channel_t channel)
if (ipu_conf == 0) {
clk_disable(ctx->ipu_clk);
- ctx->ipu_clk_enabled = 0;
}
}
@@ -1045,5 +1042,9 @@ ipu_color_space_t format_to_colorspace(u32 fmt)
bool ipu_clk_enabled(struct ipu_ctx *ctx)
{
- return ctx->ipu_clk_enabled;
+#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
+ return clk_get_usecount(ctx->ipu_clk);
+#else
+ return ctx->ipu_clk->enable_count;
+#endif
}
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 6/7] clk: clk-divider: add clk_register_divider_table()
2026-04-28 8:51 [PATCH v2 1/7] clk: imx6q: cosmetic: keep pll definitions together Brian Ruley
` (3 preceding siblings ...)
2026-04-28 8:51 ` [PATCH v2 5/7] video: imx: ipuv3: enable ipu clk before writing registers in CCF Brian Ruley
@ 2026-04-28 8:51 ` Brian Ruley
2026-04-28 8:51 ` [PATCH v2 7/7] clk: imx6q: use clk_divider_table instead of fixed factor for pll5 divs Brian Ruley
5 siblings, 0 replies; 11+ messages in thread
From: Brian Ruley @ 2026-04-28 8:51 UTC (permalink / raw)
To: festevam, Lukasz Majewski, Tom Rini; +Cc: brian.ruley, u-boot
The existing clk_register_divider() only supports linear or
power-of-two divider mappings. Some hardware (e.g. i.MX6 PLL5
post_div and video_div) uses non-linear register-value-to-divisor
mappings that require a lookup table.
Add clk_register_divider_table() which accepts a clk_div_table,
and reimplement clk_register_divider() as a wrapper passing
table=NULL.
Signed-off-by: Brian Ruley <brian.ruley@gehealthcare.com>
---
Changes for v2:
- New
---
drivers/clk/clk-divider.c | 16 +++++++++++++---
include/linux/clk-provider.h | 5 +++++
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index e692b9c2167..d30786a9e6c 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -228,20 +228,30 @@ static struct clk *_register_divider(struct udevice *dev, const char *name,
return clk;
}
-struct clk *clk_register_divider(struct udevice *dev, const char *name,
+struct clk *clk_register_divider_table(struct udevice *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
- u8 clk_divider_flags)
+ u8 clk_divider_flags, const struct clk_div_table *table)
{
struct clk *clk;
clk = _register_divider(dev, name, parent_name, flags, reg, shift,
- width, clk_divider_flags, NULL);
+ width, clk_divider_flags, table);
if (IS_ERR(clk))
return ERR_CAST(clk);
return clk;
}
+struct clk *clk_register_divider(struct udevice *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_divider_flags)
+{
+ return clk_register_divider_table(dev, name, parent_name, flags, reg,
+ shift, width, clk_divider_flags,
+ NULL);
+}
+
U_BOOT_DRIVER(ccf_clk_divider) = {
.name = UBOOT_DM_CLK_CCF_DIVIDER,
.id = UCLASS_CLK,
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 2d754fa4287..366f2d968a3 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -246,6 +246,11 @@ struct clk *clk_register_fixed_factor(struct udevice *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div);
+struct clk *clk_register_divider_table(struct udevice *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_divider_flags, const struct clk_div_table *table);
+
struct clk *clk_register_divider(struct udevice *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 7/7] clk: imx6q: use clk_divider_table instead of fixed factor for pll5 divs
2026-04-28 8:51 [PATCH v2 1/7] clk: imx6q: cosmetic: keep pll definitions together Brian Ruley
` (4 preceding siblings ...)
2026-04-28 8:51 ` [PATCH v2 6/7] clk: clk-divider: add clk_register_divider_table() Brian Ruley
@ 2026-04-28 8:51 ` Brian Ruley
5 siblings, 0 replies; 11+ messages in thread
From: Brian Ruley @ 2026-04-28 8:51 UTC (permalink / raw)
To: festevam, Lukasz Majewski, Tom Rini; +Cc: brian.ruley, u-boot
Now that non-linear clk divider tables are supported, replace the fixed
factor implementation with the proper divider, which allows more fine
control over clock rates.
Signed-off-by: Brian Ruley <brian.ruley@gehealthcare.com>
---
Changes for v2:
- New
---
drivers/clk/imx/clk-imx6q.c | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index ba039e56227..a4649a1a9d9 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -139,6 +139,21 @@ static const char *const pll6_bypass_sels[] = {
"pll6_bypass_src",
};
+static struct clk_div_table post_div_table[] = {
+ { .val = 2, .div = 1, },
+ { .val = 1, .div = 2, },
+ { .val = 0, .div = 4, },
+ { /* sentinel */ }
+};
+
+static struct clk_div_table video_div_table[] = {
+ { .val = 0, .div = 1, },
+ { .val = 1, .div = 2, },
+ { .val = 2, .div = 1, },
+ { .val = 3, .div = 4, },
+ { /* sentinel */ }
+};
+
static unsigned int share_count_mipi_core_cfg;
static void of_assigned_ldb_sels(struct udevice *dev, int *ldb_di0_sel,
@@ -338,10 +353,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));
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread