* [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP
@ 2026-10-21 13:09 Miquel Raynal
2026-10-21 13:09 ` [PATCH 1/5] clk: composite: Initialize inner hw clocks during registration Miquel Raynal
` (5 more replies)
0 siblings, 6 replies; 9+ messages in thread
From: Miquel Raynal @ 2026-10-21 13:09 UTC (permalink / raw)
To: Stephen Boyd, Brian Masney, Jerome Brunet, Abel Vesa, Peng Fan,
Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Thomas Petazzoni, Ian Ray, Hervé Codina, Luca Ceresoli,
linux-clk, linux-kernel, imx, linux-arm-kernel, devicetree,
Miquel Raynal
Hello,
Thanks to Brian's series, we can finally solve the problem of rate
calculation faced with the i.MX8MP LDB/PIX clocks. I've tested this
series using a v7.1 mainline kernel with a lot of unrelated DRM
patches. I then re-applied it on top of clk-next after fixing the few
conflicts when applying Brian's series, but that means I cannot (yet)
run a 7.2/7.3 kernel on the platform (and applying this series with b4
will fail due to Brian's series no longer applying on top of clk-next).
The DTS patch is there for reference, I don't mind if it's not picked
up.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
Miquel Raynal (5):
clk: composite: Initialize inner hw clocks during registration
clk: Fix v2 rate negotiation with composite clocks
clk: imx8mp: Allow adjusting the video PLL rates for the LDB clock
clk: imx8mp: Set v2 rate negociation to LDB and pixel clocks
arm64: dts: imx8mp: Drop VIDEO_PLL1 assigned rate
arch/arm64/boot/dts/freescale/imx8mp.dtsi | 6 ++----
drivers/clk/clk-composite.c | 34 ++++++++++++++-----------------
drivers/clk/clk.c | 2 +-
drivers/clk/imx/clk-imx8mp.c | 6 +++---
4 files changed, 21 insertions(+), 27 deletions(-)
---
base-commit: 31c632c62c5b98fd965ef5cff3c3fc1ffff02913
change-id: 20261021-ge-clk-lcm-b0d81fcaaa17
prerequisite-message-id: <20260327-clk-scaling-v8-0-86cd0aba3c5f@redhat.com>
prerequisite-patch-id: 8f4664c519b38f0c34e388104f9a75e0946c27f7
prerequisite-patch-id: 041b5fbc0014b25795f8eda6b89b6b61131d51ca
prerequisite-patch-id: 2b9d8038fb1733a94291248ce9042139275fb4d1
prerequisite-patch-id: dcf50f042320b672cabff74bcb861e5ddf26bf6b
prerequisite-patch-id: 3539877187131dae288e6bcfb204d047e5768f84
prerequisite-patch-id: e55a07d726e3caad4508b8f200a8a8c17327c8aa
prerequisite-patch-id: f09cbe9bc44cc58bf47aae239c3558b4e6f6233e
prerequisite-patch-id: 272e0710fba77dd768e6312aacef5a3e9addebc0
Best regards,
--
Miquel Raynal <miquel.raynal@bootlin.com>
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH 1/5] clk: composite: Initialize inner hw clocks during registration 2026-10-21 13:09 [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP Miquel Raynal @ 2026-10-21 13:09 ` Miquel Raynal 2026-10-21 13:09 ` [PATCH 2/5] clk: Fix v2 rate negotiation with composite clocks Miquel Raynal ` (4 subsequent siblings) 5 siblings, 0 replies; 9+ messages in thread From: Miquel Raynal @ 2026-10-21 13:09 UTC (permalink / raw) To: Stephen Boyd, Brian Masney, Jerome Brunet, Abel Vesa, Peng Fan, Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: Thomas Petazzoni, Ian Ray, Hervé Codina, Luca Ceresoli, linux-clk, linux-kernel, imx, linux-arm-kernel, devicetree, Miquel Raynal The mux, rate and gate clk_hws of a composite are not registered as clocks on their own. Only the ->clk pointer was set to the composite clk, but their ->core remained unassigned. Provider ops may call into clk_hw_* helpers, such as clk_hw_get_flags() or clk_hw_get_rate() for instance. In these cases, hw->core will be dereferenced. The composite callbacks kind of papered with this situation by (almost) always calling __clk_hw_set_clk() before use. clk_composite_determine_rate() never did it, but it probably did not fail because the core likely called callbacks like get_parent() or recalc_rate() before. Add a clk_composite_init() callback that sets up the inner core pointers once for all just after the core clock registration, and before any other callback call from the core. Thanks to this, each per-callback assignement can be dropped. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- drivers/clk/clk-composite.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 11842bce5918..332b38a326fa 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -8,14 +8,26 @@ #include <linux/err.h> #include <linux/slab.h> +static int clk_composite_init(struct clk_hw *hw) +{ + struct clk_composite *composite = to_clk_composite(hw); + + if (composite->mux_hw) + __clk_hw_set_clk(composite->mux_hw, hw); + if (composite->rate_hw) + __clk_hw_set_clk(composite->rate_hw, hw); + if (composite->gate_hw) + __clk_hw_set_clk(composite->gate_hw, hw); + + return 0; +} + static u8 clk_composite_get_parent(struct clk_hw *hw) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *mux_ops = composite->mux_ops; struct clk_hw *mux_hw = composite->mux_hw; - __clk_hw_set_clk(mux_hw, hw); - return mux_ops->get_parent(mux_hw); } @@ -25,8 +37,6 @@ static int clk_composite_set_parent(struct clk_hw *hw, u8 index) const struct clk_ops *mux_ops = composite->mux_ops; struct clk_hw *mux_hw = composite->mux_hw; - __clk_hw_set_clk(mux_hw, hw); - return mux_ops->set_parent(mux_hw, index); } @@ -37,8 +47,6 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, const struct clk_ops *rate_ops = composite->rate_ops; struct clk_hw *rate_hw = composite->rate_hw; - __clk_hw_set_clk(rate_hw, hw); - return rate_ops->recalc_rate(rate_hw, parent_rate); } @@ -126,10 +134,8 @@ static int clk_composite_determine_rate(struct clk_hw *hw, req->rate = best_rate; return 0; } else if (rate_hw && rate_ops && rate_ops->determine_rate) { - __clk_hw_set_clk(rate_hw, hw); return rate_ops->determine_rate(rate_hw, req); } else if (mux_hw && mux_ops && mux_ops->determine_rate) { - __clk_hw_set_clk(mux_hw, hw); return mux_ops->determine_rate(mux_hw, req); } else { pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n"); @@ -144,8 +150,6 @@ static int clk_composite_set_rate(struct clk_hw *hw, unsigned long rate, const struct clk_ops *rate_ops = composite->rate_ops; struct clk_hw *rate_hw = composite->rate_hw; - __clk_hw_set_clk(rate_hw, hw); - return rate_ops->set_rate(rate_hw, rate, parent_rate); } @@ -161,9 +165,6 @@ static int clk_composite_set_rate_and_parent(struct clk_hw *hw, struct clk_hw *mux_hw = composite->mux_hw; unsigned long temp_rate; - __clk_hw_set_clk(rate_hw, hw); - __clk_hw_set_clk(mux_hw, hw); - temp_rate = rate_ops->recalc_rate(rate_hw, parent_rate); if (temp_rate > rate) { rate_ops->set_rate(rate_hw, rate, parent_rate); @@ -182,8 +183,6 @@ static int clk_composite_is_enabled(struct clk_hw *hw) const struct clk_ops *gate_ops = composite->gate_ops; struct clk_hw *gate_hw = composite->gate_hw; - __clk_hw_set_clk(gate_hw, hw); - return gate_ops->is_enabled(gate_hw); } @@ -193,8 +192,6 @@ static int clk_composite_enable(struct clk_hw *hw) const struct clk_ops *gate_ops = composite->gate_ops; struct clk_hw *gate_hw = composite->gate_hw; - __clk_hw_set_clk(gate_hw, hw); - return gate_ops->enable(gate_hw); } @@ -204,8 +201,6 @@ static void clk_composite_disable(struct clk_hw *hw) const struct clk_ops *gate_ops = composite->gate_ops; struct clk_hw *gate_hw = composite->gate_hw; - __clk_hw_set_clk(gate_hw, hw); - gate_ops->disable(gate_hw); } @@ -237,6 +232,7 @@ static struct clk_hw *__clk_hw_register_composite(struct device *dev, hw = &composite->hw; clk_composite_ops = &composite->ops; + clk_composite_ops->init = clk_composite_init; if (mux_hw && mux_ops) { if (!mux_ops->get_parent) { -- 2.56.0 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/5] clk: Fix v2 rate negotiation with composite clocks 2026-10-21 13:09 [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP Miquel Raynal 2026-10-21 13:09 ` [PATCH 1/5] clk: composite: Initialize inner hw clocks during registration Miquel Raynal @ 2026-10-21 13:09 ` Miquel Raynal 2026-10-21 13:09 ` [PATCH 3/5] clk: imx8mp: Allow adjusting the video PLL rates for the LDB clock Miquel Raynal ` (3 subsequent siblings) 5 siblings, 0 replies; 9+ messages in thread From: Miquel Raynal @ 2026-10-21 13:09 UTC (permalink / raw) To: Stephen Boyd, Brian Masney, Jerome Brunet, Abel Vesa, Peng Fan, Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: Thomas Petazzoni, Ian Ray, Hervé Codina, Luca Ceresoli, linux-clk, linux-kernel, imx, linux-arm-kernel, devicetree, Miquel Raynal V2 rate negotiation walks the subtree using the composite hw clocks (the ones that we have acces to while walking the clock tree), but compares it internally with the inner hw clocks (typically the inner divider of a composite clock). Since these may be different pointers in the case of composite clocks, the comparison won't match for them, which fails the whole v2 rate negociation logic. Always use the top level core clock instead. Comparing the top level hw clocks instead of the core clocks would also work, at the cost of an extra pointer dereference. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- Brian, if you agree with this change, you may keep this fix or fold it into your series, at your own preference. --- drivers/clk/clk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 745b13a77c83..349c35ab8a5d 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -917,7 +917,7 @@ unsigned long clk_hw_get_children_lcm(struct clk_hw *hw, struct clk_hw *requesti hlist_for_each_entry(child, &hw->core->children, child_node) { /* Use requesting rate for the requesting child, current rate for others */ - if (child->hw == requesting_hw) { + if (requesting_hw && child == requesting_hw->core) { child_rate = requesting_rate; } else { if (!clk_hw_is_enabled(child->hw)) -- 2.56.0 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/5] clk: imx8mp: Allow adjusting the video PLL rates for the LDB clock 2026-10-21 13:09 [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP Miquel Raynal 2026-10-21 13:09 ` [PATCH 1/5] clk: composite: Initialize inner hw clocks during registration Miquel Raynal 2026-10-21 13:09 ` [PATCH 2/5] clk: Fix v2 rate negotiation with composite clocks Miquel Raynal @ 2026-10-21 13:09 ` Miquel Raynal 2026-10-21 13:10 ` [PATCH 4/5] clk: imx8mp: Set v2 rate negociation to LDB and pixel clocks Miquel Raynal ` (2 subsequent siblings) 5 siblings, 0 replies; 9+ messages in thread From: Miquel Raynal @ 2026-10-21 13:09 UTC (permalink / raw) To: Stephen Boyd, Brian Masney, Jerome Brunet, Abel Vesa, Peng Fan, Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: Thomas Petazzoni, Ian Ray, Hervé Codina, Luca Ceresoli, linux-clk, linux-kernel, imx, linux-arm-kernel, devicetree, Miquel Raynal There must be a x7 or x14 relationship between the LDB clock and the pixel clocks feeding the LCDIF blocks. There must be some negociation happening between the two and that may only happen by using the upper video PLLs. Allow this by setting the CLK_SET_RATE_PARENT flag to the LDB clock. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- drivers/clk/imx/clk-imx8mp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index fe6dac70f1a1..3540992b8940 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -753,7 +753,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_MEDIA_MIPI_PHY1_REF] = imx8m_clk_hw_composite("media_mipi_phy1_ref", imx8mp_media_mipi_phy1_ref_sels, ccm_base + 0xbd80); hws[IMX8MP_CLK_MEDIA_DISP1_PIX] = imx8m_clk_hw_composite_bus_flags("media_disp1_pix", imx8mp_media_disp_pix_sels, ccm_base + 0xbe00, CLK_SET_RATE_PARENT); hws[IMX8MP_CLK_MEDIA_CAM2_PIX] = imx8m_clk_hw_composite("media_cam2_pix", imx8mp_media_cam2_pix_sels, ccm_base + 0xbe80); - hws[IMX8MP_CLK_MEDIA_LDB] = imx8m_clk_hw_composite("media_ldb", imx8mp_media_ldb_sels, ccm_base + 0xbf00); + hws[IMX8MP_CLK_MEDIA_LDB] = imx8m_clk_hw_composite_bus_flags("media_ldb", imx8mp_media_ldb_sels, ccm_base + 0xbf00, CLK_SET_RATE_PARENT); hws[IMX8MP_CLK_MEMREPAIR] = imx8m_clk_hw_composite_critical("mem_repair", imx8mp_memrepair_sels, ccm_base + 0xbf80); hws[IMX8MP_CLK_MEDIA_MIPI_TEST_BYTE] = imx8m_clk_hw_composite("media_mipi_test_byte", imx8mp_media_mipi_test_byte_sels, ccm_base + 0xc100); hws[IMX8MP_CLK_ECSPI3] = imx8m_clk_hw_composite("ecspi3", imx8mp_ecspi3_sels, ccm_base + 0xc180); -- 2.56.0 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/5] clk: imx8mp: Set v2 rate negociation to LDB and pixel clocks 2026-10-21 13:09 [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP Miquel Raynal ` (2 preceding siblings ...) 2026-10-21 13:09 ` [PATCH 3/5] clk: imx8mp: Allow adjusting the video PLL rates for the LDB clock Miquel Raynal @ 2026-10-21 13:10 ` Miquel Raynal 2026-10-21 13:10 ` [PATCH 5/5] arm64: dts: imx8mp: Drop VIDEO_PLL1 assigned rate Miquel Raynal 2026-10-21 14:11 ` [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP Brian Masney 5 siblings, 0 replies; 9+ messages in thread From: Miquel Raynal @ 2026-10-21 13:10 UTC (permalink / raw) To: Stephen Boyd, Brian Masney, Jerome Brunet, Abel Vesa, Peng Fan, Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: Thomas Petazzoni, Ian Ray, Hervé Codina, Luca Ceresoli, linux-clk, linux-kernel, imx, linux-arm-kernel, devicetree, Miquel Raynal Both clocks are fed using the same PLL, but when modifying the PLL to please one of the two, we must not break the other. Because of that, we must enable the new negociation logic that does an LCM calculation and preserves the existing rates while walking the subtree. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- drivers/clk/imx/clk-imx8mp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index 3540992b8940..96dc237c10ea 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -689,7 +689,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_AHB] = imx8m_clk_hw_composite_bus_critical("ahb_root", imx8mp_ahb_sels, ccm_base + 0x9000); hws[IMX8MP_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mp_audio_ahb_sels, ccm_base + 0x9100); hws[IMX8MP_CLK_MIPI_DSI_ESC_RX] = imx8m_clk_hw_composite_bus("mipi_dsi_esc_rx", imx8mp_mipi_dsi_esc_rx_sels, ccm_base + 0x9200); - hws[IMX8MP_CLK_MEDIA_DISP2_PIX] = imx8m_clk_hw_composite_bus_flags("media_disp2_pix", imx8mp_media_disp_pix_sels, ccm_base + 0x9300, CLK_SET_RATE_PARENT); + hws[IMX8MP_CLK_MEDIA_DISP2_PIX] = imx8m_clk_hw_composite_bus_flags("media_disp2_pix", imx8mp_media_disp_pix_sels, ccm_base + 0x9300, CLK_SET_RATE_PARENT | CLK_V2_RATE_NEGOTIATION); hws[IMX8MP_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb_root", ccm_base + 0x9080, 0, 1); @@ -751,9 +751,9 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_USDHC3] = imx8m_clk_hw_composite("usdhc3", imx8mp_usdhc3_sels, ccm_base + 0xbc80); hws[IMX8MP_CLK_MEDIA_CAM1_PIX] = imx8m_clk_hw_composite("media_cam1_pix", imx8mp_media_cam1_pix_sels, ccm_base + 0xbd00); hws[IMX8MP_CLK_MEDIA_MIPI_PHY1_REF] = imx8m_clk_hw_composite("media_mipi_phy1_ref", imx8mp_media_mipi_phy1_ref_sels, ccm_base + 0xbd80); - hws[IMX8MP_CLK_MEDIA_DISP1_PIX] = imx8m_clk_hw_composite_bus_flags("media_disp1_pix", imx8mp_media_disp_pix_sels, ccm_base + 0xbe00, CLK_SET_RATE_PARENT); + hws[IMX8MP_CLK_MEDIA_DISP1_PIX] = imx8m_clk_hw_composite_bus_flags("media_disp1_pix", imx8mp_media_disp_pix_sels, ccm_base + 0xbe00, CLK_SET_RATE_PARENT | CLK_V2_RATE_NEGOTIATION); hws[IMX8MP_CLK_MEDIA_CAM2_PIX] = imx8m_clk_hw_composite("media_cam2_pix", imx8mp_media_cam2_pix_sels, ccm_base + 0xbe80); - hws[IMX8MP_CLK_MEDIA_LDB] = imx8m_clk_hw_composite_bus_flags("media_ldb", imx8mp_media_ldb_sels, ccm_base + 0xbf00, CLK_SET_RATE_PARENT); + hws[IMX8MP_CLK_MEDIA_LDB] = imx8m_clk_hw_composite_bus_flags("media_ldb", imx8mp_media_ldb_sels, ccm_base + 0xbf00, CLK_SET_RATE_PARENT | CLK_V2_RATE_NEGOTIATION); hws[IMX8MP_CLK_MEMREPAIR] = imx8m_clk_hw_composite_critical("mem_repair", imx8mp_memrepair_sels, ccm_base + 0xbf80); hws[IMX8MP_CLK_MEDIA_MIPI_TEST_BYTE] = imx8m_clk_hw_composite("media_mipi_test_byte", imx8mp_media_mipi_test_byte_sels, ccm_base + 0xc100); hws[IMX8MP_CLK_ECSPI3] = imx8m_clk_hw_composite("ecspi3", imx8mp_ecspi3_sels, ccm_base + 0xc180); -- 2.56.0 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 5/5] arm64: dts: imx8mp: Drop VIDEO_PLL1 assigned rate 2026-10-21 13:09 [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP Miquel Raynal ` (3 preceding siblings ...) 2026-10-21 13:10 ` [PATCH 4/5] clk: imx8mp: Set v2 rate negociation to LDB and pixel clocks Miquel Raynal @ 2026-10-21 13:10 ` Miquel Raynal 2026-10-21 14:11 ` [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP Brian Masney 5 siblings, 0 replies; 9+ messages in thread From: Miquel Raynal @ 2026-10-21 13:10 UTC (permalink / raw) To: Stephen Boyd, Brian Masney, Jerome Brunet, Abel Vesa, Peng Fan, Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: Thomas Petazzoni, Ian Ray, Hervé Codina, Luca Ceresoli, linux-clk, linux-kernel, imx, linux-arm-kernel, devicetree, Miquel Raynal This rate has never been assigned for good reasons. It was assigning a frequency only adapted to the panel of some evaluation board, while allowing a rate division by 7 and 14 for the needs of the LDB. Linux now has an LCM-based divisor calculation that allows us from dropping that inappropriate assignment. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- I believe most of the users of this DTS set their own frequency in their downstream DTS, just because the existing assignment won't fit their panels, so while in theory this change could break bootloaders/other OS pulling this file, in practice it is unlikely it will. I don't know if we really want to do that cleanup or not since at most it is an incorrect and useless assignment, but at least one should know that it can (should?) be removed. --- arch/arm64/boot/dts/freescale/imx8mp.dtsi | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index 9cf9f6f08654..7691d917646e 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -1988,16 +1988,14 @@ media_blk_ctrl: blk-ctrl@32ec0000 { <&clk IMX8MP_CLK_MEDIA_APB>, <&clk IMX8MP_CLK_MEDIA_DISP1_PIX>, <&clk IMX8MP_CLK_MEDIA_DISP2_PIX>, - <&clk IMX8MP_CLK_MEDIA_ISP>, - <&clk IMX8MP_VIDEO_PLL1>; + <&clk IMX8MP_CLK_MEDIA_ISP>; assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>, <&clk IMX8MP_SYS_PLL1_800M>, <&clk IMX8MP_VIDEO_PLL1_OUT>, <&clk IMX8MP_VIDEO_PLL1_OUT>, <&clk IMX8MP_SYS_PLL2_500M>; assigned-clock-rates = <500000000>, <200000000>, - <0>, <0>, <500000000>, - <1039500000>; + <0>, <0>, <500000000>; #power-domain-cells = <1>; lvds_bridge: bridge@5c { -- 2.56.0 ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP 2026-10-21 13:09 [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP Miquel Raynal ` (4 preceding siblings ...) 2026-10-21 13:10 ` [PATCH 5/5] arm64: dts: imx8mp: Drop VIDEO_PLL1 assigned rate Miquel Raynal @ 2026-10-21 14:11 ` Brian Masney 2026-10-23 14:10 ` Jerome Brunet 5 siblings, 1 reply; 9+ messages in thread From: Brian Masney @ 2026-10-21 14:11 UTC (permalink / raw) To: Miquel Raynal, Jerome Brunet Cc: Stephen Boyd, Abel Vesa, Peng Fan, Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thomas Petazzoni, Ian Ray, Hervé Codina, Luca Ceresoli, linux-clk, linux-kernel, imx, linux-arm-kernel, devicetree Hi Miquel (and Jerome), On Wed, Oct 21, 2026 at 03:09:56PM +0200, Miquel Raynal wrote: > Hello, > > Thanks to Brian's series, we can finally solve the problem of rate > calculation faced with the i.MX8MP LDB/PIX clocks. I've tested this > series using a v7.1 mainline kernel with a lot of unrelated DRM > patches. I then re-applied it on top of clk-next after fixing the few > conflicts when applying Brian's series, but that means I cannot (yet) > run a 7.2/7.3 kernel on the platform (and applying this series with b4 > will fail due to Brian's series no longer applying on top of clk-next). > > The DTS patch is there for reference, I don't mind if it's not picked > up. > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Thanks for testing and posting this! I know that Jerome would like to see some changes to my rate change series before it can be merged. I'm going to probably poorly describe his concerns here, so apologies in advance if I miscommunicate this Jerome. I'd appreciate it if you could clarify. - Currently the latest version posted (v8) to the list has the LCM helper (clk_hw_get_children_lcm) in drivers/clk/clk.c, and the LCM helper should be in clk-divider.c. I agree that it should be in the divider code, but we'd have to export some additional APIs to allow that. In the future if we went with what's in v8, and wanted to fix the fractional dividers, then it would need a similar type of helper in clk.c, which is not ideal. I initially went with this approach to limit the APIs that are exported from the clk core. - I have a draft v9 series that I haven't posted yet that adds two new helpers: clk_hw_get_num_children() and clk_hw_get_child_by_index() similar to the existing functions for the parents. This allows moving the LCM logic into clk-divider.c where it belongs, however the downside to this approach is that it expands the clk exported APIs so that providers will be able to fully walk the clk tree. The concern is that providers may abuse this in the future and it may limit future changes / cleanups to the clk core. For example, if we wanted to clean up the way locking is done, this may potentially limit the available options. https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git/log/?h=clk-divider-scaling-v9 - He would like to see it where each clk consumer sets the min/max rate that's acceptable, and the clk scaling in the provider takes those ranges into account when rates are negotiated. Anyways, please chime in Jerome if I got this right / wrong, and any additional concerns. Brian ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP 2026-10-21 14:11 ` [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP Brian Masney @ 2026-10-23 14:10 ` Jerome Brunet 2026-10-23 16:32 ` Miquel Raynal 0 siblings, 1 reply; 9+ messages in thread From: Jerome Brunet @ 2026-10-23 14:10 UTC (permalink / raw) To: Brian Masney, Miquel Raynal Cc: Stephen Boyd, Abel Vesa, Peng Fan, Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thomas Petazzoni, Ian Ray, Hervé Codina, Luca Ceresoli, linux-clk, linux-kernel, imx, linux-arm-kernel, devicetree On mer. 21 oct. 2026 at 10:11, Brian Masney <bmasney@redhat.com> wrote: > Hi Miquel (and Jerome), > > On Wed, Oct 21, 2026 at 03:09:56PM +0200, Miquel Raynal wrote: >> Hello, >> >> Thanks to Brian's series, we can finally solve the problem of rate >> calculation faced with the i.MX8MP LDB/PIX clocks. I've tested this >> series using a v7.1 mainline kernel with a lot of unrelated DRM >> patches. I then re-applied it on top of clk-next after fixing the few >> conflicts when applying Brian's series, but that means I cannot (yet) >> run a 7.2/7.3 kernel on the platform (and applying this series with b4 >> will fail due to Brian's series no longer applying on top of clk-next). >> >> The DTS patch is there for reference, I don't mind if it's not picked >> up. >> >> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> > > Thanks for testing and posting this! > > I know that Jerome would like to see some changes to my rate change > series before it can be merged. I'm going to probably poorly describe > his concerns here, so apologies in advance if I miscommunicate this > Jerome. I'd appreciate it if you could clarify. > > - Currently the latest version posted (v8) to the list has the LCM > helper (clk_hw_get_children_lcm) in drivers/clk/clk.c, and the LCM > helper should be in clk-divider.c. I agree that it should be in the > divider code, but we'd have to export some additional APIs to allow > that. In the future if we went with what's in v8, and wanted to fix > the fractional dividers, then it would need a similar type of helper > in clk.c, which is not ideal. I initially went with this approach to > limit the APIs that are exported from the clk core. > > - I have a draft v9 series that I haven't posted yet that adds two new > helpers: clk_hw_get_num_children() and clk_hw_get_child_by_index() > similar to the existing functions for the parents. This allows moving > the LCM logic into clk-divider.c where it belongs, however the > downside to this approach is that it expands the clk exported APIs so > that providers will be able to fully walk the clk tree. The concern is > that providers may abuse this in the future and it may limit future > changes / cleanups to the clk core. For example, if we wanted to clean > up the way locking is done, this may potentially limit the available > options. > https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git/log/?h=clk-divider-scaling-v9 > > - He would like to see it where each clk consumer sets the min/max rate > that's acceptable, and the clk scaling in the provider takes those > ranges into account when rates are negotiated. > > Anyways, please chime in Jerome if I got this right / wrong, and any > additional concerns. > Hi Brian, Miquel, Thanks Brian for the summary, and Miquel for testing and posting this. The i.MX8MP LDB/pixel case is a real problem and I'd like us to solve it. My concerns are about how, more than whether. You got most of it. The main nuance is I want to convey is where it should live IMO: not in a divider helper, and not in providers at all, but in the core. I'll try to explain. So far, CCF has preserved the settings of each element, or more honestly, left them alone: if a divider divides by 4, it keeps doing so whatever happens to its parent. This behavior has been there for years and many devices rely on it, even if unknowingly. Miquel, I understand you would rather make the new behavior the default, but I think this one is here to stay. That said, it would be nice to have a way to say that the rate should be preserved rather than the setting. I'll come back to that. My first concern is about the responsibilities of each component. IMO a provider should only describe the transfer function it implements: "given this parent rate, here is what I can do". It should not walk the tree or care about what its children are doing. Coordinating the providers is the core's job, without assumptions about their transfer functions. Providers already query their parents: a mux asks each candidate parent what it can provide, and a clock with CLK_SET_RATE_PARENT forwards its request upward. That is the request path, and the core stays in charge of it. Reading the state of children or siblings, and deciding on their behalf, is a different thing. Once a provider is allowed to do that, there is no good reason to deny it to the others, and I think that would make the core much harder to maintain. It could also get in the way of other pressing work, like the global lock problem, where tree walking will certainly play a critical role. Miquel's patch 2 is a good illustration: the helper ends up comparing the clk_hw of the tree with the inner clk_hw of a composite, which is not part of the tree. My second concern is that it is tied to the integer divider, since it relies on the LCM. If another element with a different transfer function sits on the path, it does not work, as we discussed. We could extend the principle to other types, but: * I don't see how the different types would reconcile, since each one does its own thing in its own .determine_rate(); * the change is no longer simple and harmless if it has to spread to every provider to work. The behavior is also hard for consumers to predict. For example, the parent rate is only negotiated with the subtree of the divider's direct parent. With a gate between the divider and the PLL, the other branches of the PLL are left out. That could be fixed with more tree walking in the provider, which brings us back to my first point. If such a mechanism is needed, I would much prefer it done entirely in the core, in a generic way, with no assumption about the transfer functions involved. I realize this may go against a direction suggested at a previous LPC, which this series followed, and I think the points above are worth reconsidering it for. I say "if" because I doubt clock trees are designed with runtime rate negotiation in mind. So far, we have mostly dealt with these cases by removing CLK_SET_RATE_PARENT and using assigned-clock-rates on the shared ancestor. I understand that falls short when the PLL has to follow the display mode, as here. For rate negotiation, my suggestion would be to reuse what the framework already has: clock ranges, and re-running .determine_rate() on the children being dragged along, with the common ancestor's rate pinned. When that rate does not suit a sibling's range, other ancestor rates can be tried within the constraints, rather than giving up. clk_set_rate() is a best effort function. It tries to get as close to the request as possible, honoring the ranges of every clock along the path, and it is up to the consumer to decide whether the result is good enough. That decision is lost if the framework recomputes the rates of a sibling branch on its own. Ranges could help it decide: either "I'm fine with the new rate", or -EBUSY. What I'm suggesting is to treat any clock with a range as one that needs updating. Its consumer cared enough to tell us what it can and cannot cope with. That removes the need for a specific flag, and puts the rate policy in the consumer, which is where I'd prefer use case choices to live, rather than in the provider or the core. It would also fix clocks being dragged out of their range during an update. Presumably, a clock without a range does not care enough to give us a decider, so the framework has no basis to act on its behalf and keeps today's behavior. I think this behavior will keep on being good enough for the vast majority clocks out there and it is a lot lighter on the math side (which is already quite severe as it is) I've been checking whether the idea is remotely feasible. It involves multiple planning stages and multiple tops. It is still very rough, but there is the beginning of something: https://github.com/jbrun3t/linux/commits/clk/clk-rate-range-update/ Miquel, if you fancy trying it, please let me know whether it works for you. All you should need is to set a range on the clocks you care about. Sorry for this rather long explanation. Brian, your series is what got this discussion going, I know a lot of efforts have gone into it already. I'd be glad to work on this together. > Brian > -- Jerome ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP 2026-10-23 14:10 ` Jerome Brunet @ 2026-10-23 16:32 ` Miquel Raynal 0 siblings, 0 replies; 9+ messages in thread From: Miquel Raynal @ 2026-10-23 16:32 UTC (permalink / raw) To: Jerome Brunet Cc: Brian Masney, Stephen Boyd, Abel Vesa, Peng Fan, Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thomas Petazzoni, Ian Ray, Hervé Codina, Luca Ceresoli, linux-clk, linux-kernel, imx, linux-arm-kernel, devicetree Hello, On 23/10/2026 at 16:10:34 +02, Jerome Brunet <jbrunet@baylibre.com> wrote: > On mer. 21 oct. 2026 at 10:11, Brian Masney <bmasney@redhat.com> wrote: > >> Hi Miquel (and Jerome), >> >> On Wed, Oct 21, 2026 at 03:09:56PM +0200, Miquel Raynal wrote: >>> Hello, >>> >>> Thanks to Brian's series, we can finally solve the problem of rate >>> calculation faced with the i.MX8MP LDB/PIX clocks. I've tested this >>> series using a v7.1 mainline kernel with a lot of unrelated DRM >>> patches. I then re-applied it on top of clk-next after fixing the few >>> conflicts when applying Brian's series, but that means I cannot (yet) >>> run a 7.2/7.3 kernel on the platform (and applying this series with b4 >>> will fail due to Brian's series no longer applying on top of clk-next). >>> >>> The DTS patch is there for reference, I don't mind if it's not picked >>> up. >>> >>> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> >> >> Thanks for testing and posting this! >> >> I know that Jerome would like to see some changes to my rate change >> series before it can be merged. I'm going to probably poorly describe >> his concerns here, so apologies in advance if I miscommunicate this >> Jerome. I'd appreciate it if you could clarify. >> >> - Currently the latest version posted (v8) to the list has the LCM >> helper (clk_hw_get_children_lcm) in drivers/clk/clk.c, and the LCM >> helper should be in clk-divider.c. I agree that it should be in the >> divider code, but we'd have to export some additional APIs to allow >> that. In the future if we went with what's in v8, and wanted to fix >> the fractional dividers, then it would need a similar type of helper >> in clk.c, which is not ideal. I initially went with this approach to >> limit the APIs that are exported from the clk core. >> >> - I have a draft v9 series that I haven't posted yet that adds two new >> helpers: clk_hw_get_num_children() and clk_hw_get_child_by_index() >> similar to the existing functions for the parents. This allows moving >> the LCM logic into clk-divider.c where it belongs, however the >> downside to this approach is that it expands the clk exported APIs so >> that providers will be able to fully walk the clk tree. The concern is >> that providers may abuse this in the future and it may limit future >> changes / cleanups to the clk core. For example, if we wanted to clean >> up the way locking is done, this may potentially limit the available >> options. >> https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git/log/?h=clk-divider-scaling-v9 >> >> - He would like to see it where each clk consumer sets the min/max rate >> that's acceptable, and the clk scaling in the provider takes those >> ranges into account when rates are negotiated. >> >> Anyways, please chime in Jerome if I got this right / wrong, and any >> additional concerns. >> > > Hi Brian, Miquel, > > Thanks Brian for the summary, and Miquel for testing and posting this. > The i.MX8MP LDB/pixel case is a real problem and I'd like us to solve > it. My concerns are about how, more than whether. > > You got most of it. The main nuance is I want to convey is where it > should live IMO: not in a divider helper, and not in providers at all, > but in the core. I'll try to explain. > > So far, CCF has preserved the settings of each element, or more > honestly, left them alone: if a divider divides by 4, it keeps doing so > whatever happens to its parent. This behavior has been there for years > and many devices rely on it, even if unknowingly. Miquel, I understand > you would rather make the new behavior the default, but I think this one > is here to stay. That said, it would be nice to have a way to say that > the rate should be preserved rather than the setting. I'll come back > to that. > > My first concern is about the responsibilities of each component. IMO a > provider should only describe the transfer function it implements: > "given this parent rate, here is what I can do". It should not walk > the tree or care about what its children are doing. Coordinating the > providers is the core's job, without assumptions about their transfer > functions. > > Providers already query their parents: a mux asks each candidate > parent what it can provide, and a clock with CLK_SET_RATE_PARENT > forwards its request upward. That is the request path, and the core > stays in charge of it. Reading the state of children or siblings, and > deciding on their behalf, is a different thing. Once a provider is > allowed to do that, there is no good reason to deny it to the others, > and I think that would make the core much harder to maintain. It could > also get in the way of other pressing work, like the global lock problem, > where tree walking will certainly play a critical role. Miquel's > patch 2 is a good illustration: the helper ends up comparing the > clk_hw of the tree with the inner clk_hw of a composite, which is not > part of the tree. > > My second concern is that it is tied to the integer divider, since it > relies on the LCM. If another element with a different transfer > function sits on the path, it does not work, as we discussed. We could > extend the principle to other types, but: > * I don't see how the different types would reconcile, since each one > does its own thing in its own .determine_rate(); > * the change is no longer simple and harmless if it has to spread to > every provider to work. > > The behavior is also hard for consumers to predict. For example, the > parent rate is only negotiated with the subtree of the divider's > direct parent. With a gate between the divider and the PLL, the other > branches of the PLL are left out. That could be fixed with more tree > walking in the provider, which brings us back to my first point. > > If such a mechanism is needed, I would much prefer it done entirely in > the core, in a generic way, with no assumption about the transfer > functions involved. I realize this may go against a direction > suggested at a previous LPC, which this series followed, and I think the > points above are worth reconsidering it for. > > I say "if" because I doubt clock trees are designed with runtime rate > negotiation in mind. So far, we have mostly dealt with these cases by > removing CLK_SET_RATE_PARENT and using assigned-clock-rates on the > shared ancestor. I understand that falls short when the PLL has to > follow the display mode, as here. > > For rate negotiation, my suggestion would be to reuse what the > framework already has: clock ranges, and re-running .determine_rate() > on the children being dragged along, with the common ancestor's rate > pinned. When that rate does not suit a sibling's range, other ancestor > rates can be tried within the constraints, rather than giving up. > > clk_set_rate() is a best effort function. It tries to get as close to > the request as possible, honoring the ranges of every clock along the > path, and it is up to the consumer to decide whether the result is > good enough. That decision is lost if the framework recomputes the > rates of a sibling branch on its own. Ranges could help it decide: > either "I'm fine with the new rate", or -EBUSY. I see an upside with this approach: we could keep one single rate negotiation logic. But it still requires modifications to be done on a per user basis to be enabled (but that is needed from your perspective). While I fully understand all the concerns expressed above, there has been one minor point that arose while working on your series: it's very hard to determine the tolerance beyond which the clock rate shall be refused. Expect bikeshedding on a per driver basis. > What I'm suggesting is to treat any clock with a range as one that > needs updating. Its consumer cared enough to tell us what it can and > cannot cope with. That removes the need for a specific flag, and puts > the rate policy in the consumer, which is where I'd prefer use case > choices to live, rather than in the provider or the core. It would > also fix clocks being dragged out of their range during an update. > Presumably, a clock without a range does not care enough to give us a > decider, so the framework has no basis to act on its behalf and keeps > today's behavior. I think this behavior will keep on being good enough > for the vast majority clocks out there and it is a lot lighter > on the math side (which is already quite severe as it is) Well, yeah, I see we share conclusions :-) > I've been checking whether the idea is remotely feasible. It involves > multiple planning stages and multiple tops. It is still very rough, > but there is the beginning of something: > > https://github.com/jbrun3t/linux/commits/clk/clk-rate-range-update/ > > Miquel, if you fancy trying it, please let me know whether it works > for you. All you should need is to set a range on the clocks you care > about. I managed to pull most of the clock patches in your branch and apply them to my 7.2 branch (with a couple of tweaks). I then made the changes to request a tolerance as you hinted (available below) in the two relevant drivers: it worked as expected! While doing so, I realized the whole operation (set rate, set rate range, get rate and verify) needs to be repeated almost identically in every user of the "tolerance composition" logic, which probably indicates that a core helper would be relevant instead. I had in mind something like ~clk_set_rate_and_tolerance() which would do the equivalent of my fsl_ldb_link_rate_set() and lcdif_pixel_rate_set() helpers. > Sorry for this rather long explanation. > > Brian, your series is what got this discussion going, I know a lot of > efforts have gone into it already. I'd be glad to work on this together. In case that is relevant, here is below the code snippet which I used to get my panels working after removing the assigned rates from the DTS on i.MX8MP. Thanks, Miquèl diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c index 1d65c75845a4..db17b26b7f3f 100644 --- a/drivers/gpu/drm/bridge/fsl-ldb.c +++ b/drivers/gpu/drm/bridge/fsl-ldb.c @@ -16,6 +16,13 @@ #include <drm/drm_bridge.h> #include <drm/drm_of.h> +#define FSL_LDB_CLK_TOLERANCE_PERCENT 1 + #define LDB_CTRL_CH0_ENABLE BIT(0) #define LDB_CTRL_CH0_DI_SELECT BIT(1) #define LDB_CTRL_CH1_ENABLE BIT(2) @@ -111,6 +118,44 @@ static unsigned long fsl_ldb_link_frequency(struct fsl_ldb *fsl_ldb, int clock) return clock * 7000; } +static int fsl_ldb_link_rate_set(struct fsl_ldb *fsl_ldb, + const struct drm_display_mode *mode) +{ + unsigned long requested_link_freq, min_link_freq, max_link_freq; + unsigned long configured_link_freq; + int ret; + + requested_link_freq = fsl_ldb_link_frequency(fsl_ldb, mode->clock); + min_link_freq = requested_link_freq - + requested_link_freq * FSL_LDB_CLK_TOLERANCE_PERCENT / 100; + max_link_freq = requested_link_freq + + requested_link_freq * FSL_LDB_CLK_TOLERANCE_PERCENT / 100; + + ret = clk_set_rate(fsl_ldb->clk, requested_link_freq); + if (ret) { + dev_err(fsl_ldb->dev, "Failed to set %pC to %lu Hz: %d\n", + fsl_ldb->clk, requested_link_freq, ret); + return ret; + } + + ret = clk_set_rate_range(fsl_ldb->clk, min_link_freq, max_link_freq); + if (ret) { + dev_err(fsl_ldb->dev, + "Failed to keep %pC in [%lu, %lu] Hz: %d\n", + fsl_ldb->clk, min_link_freq, max_link_freq, ret); + return ret; + } + + configured_link_freq = clk_get_rate(fsl_ldb->clk); + if (configured_link_freq < min_link_freq || + configured_link_freq > max_link_freq) + dev_warn(fsl_ldb->dev, + "Configured %pC clock (%lu Hz) does not match requested LVDS clock: %lu Hz\n", + fsl_ldb->clk, configured_link_freq, requested_link_freq); + + return 0; +} + static int fsl_ldb_attach(struct drm_bridge *bridge, struct drm_encoder *encoder, enum drm_bridge_attach_flags flags) @@ -130,11 +175,10 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge, const struct drm_display_mode *mode; struct drm_connector *connector; struct drm_crtc *crtc; - unsigned long configured_link_freq; - unsigned long requested_link_freq; bool lvds_format_24bpp; bool lvds_format_jeida; u32 reg; + int ret; /* Get the LVDS format from the bridge state. */ bridge_state = drm_atomic_get_new_bridge_state(state, bridge); @@ -175,14 +219,9 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge, crtc_state = drm_atomic_get_new_crtc_state(state, crtc); mode = &crtc_state->adjusted_mode; - requested_link_freq = fsl_ldb_link_frequency(fsl_ldb, mode->clock); - clk_set_rate(fsl_ldb->clk, requested_link_freq); - - configured_link_freq = clk_get_rate(fsl_ldb->clk); - if (configured_link_freq != requested_link_freq) - dev_warn(fsl_ldb->dev, - "Configured %pC clock (%lu Hz) does not match requested LVDS clock: %lu Hz\n", - fsl_ldb->clk, configured_link_freq, requested_link_freq); + ret = fsl_ldb_link_rate_set(fsl_ldb, mode); + if (ret) + return; clk_prepare_enable(fsl_ldb->clk); @@ -241,6 +280,8 @@ static void fsl_ldb_atomic_disable(struct drm_bridge *bridge, regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->ldb_ctrl, 0); clk_disable_unprepare(fsl_ldb->clk); + + clk_drop_range(fsl_ldb->clk); } #define MAX_INPUT_SEL_FORMATS 1 diff --git a/drivers/gpu/drm/mxsfb/lcdif_kms.c b/drivers/gpu/drm/mxsfb/lcdif_kms.c index ade76c3f4e4e..2dddb82e0269 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_kms.c +++ b/drivers/gpu/drm/mxsfb/lcdif_kms.c @@ -32,6 +32,13 @@ #include "lcdif_drv.h" #include "lcdif_regs.h" +#define LCDIF_PIXEL_CLK_TOLERANCE_PERCENT 1 + struct lcdif_crtc_state { struct drm_crtc_state base; /* always be the first member */ u32 bus_format; @@ -527,6 +534,38 @@ static void lcdif_crtc_atomic_flush(struct drm_crtc *crtc, spin_unlock_irq(&crtc->dev->event_lock); } +static int lcdif_pixel_rate_set(struct lcdif_drm_private *lcdif, + const struct drm_display_mode *m) +{ + unsigned long pix_rate = m->clock * 1000; + unsigned long min_rate, max_rate; + int ret; + + /* + * Pin the pixel rate so a change on the PLL made for another branch + * (typically the LDB serializer clock) does not drag it away. + */ + min_rate = pix_rate - pix_rate * LCDIF_PIXEL_CLK_TOLERANCE_PERCENT / 100; + max_rate = pix_rate + pix_rate * LCDIF_PIXEL_CLK_TOLERANCE_PERCENT / 100; + + ret = clk_set_rate(lcdif->clk, pix_rate); + if (ret) { + drm_err(lcdif->drm, "Failed to set pixel clock to %lu Hz: %d\n", + pix_rate, ret); + return ret; + } + + ret = clk_set_rate_range(lcdif->clk, min_rate, max_rate); + if (ret) { + drm_err(lcdif->drm, + "Failed to keep pixel clock in [%lu, %lu] Hz: %d\n", + min_rate, max_rate, ret); + return ret; + } + + return 0; +} + static void lcdif_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_commit *state) { @@ -537,8 +576,11 @@ static void lcdif_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode; struct drm_device *drm = lcdif->drm; dma_addr_t paddr; + int ret; - clk_set_rate(lcdif->clk, m->clock * 1000); + ret = lcdif_pixel_rate_set(lcdif, m); + if (ret) + return; pm_runtime_get_sync(drm->dev); @@ -568,6 +610,8 @@ static void lcdif_crtc_atomic_disable(struct drm_crtc *crtc, lcdif_disable_controller(lcdif); + clk_drop_range(lcdif->clk); + spin_lock_irq(&drm->event_lock); event = crtc->state->event; if (event) { ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-10-23 16:32 UTC | newest] Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-10-21 13:09 [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP Miquel Raynal 2026-10-21 13:09 ` [PATCH 1/5] clk: composite: Initialize inner hw clocks during registration Miquel Raynal 2026-10-21 13:09 ` [PATCH 2/5] clk: Fix v2 rate negotiation with composite clocks Miquel Raynal 2026-10-21 13:09 ` [PATCH 3/5] clk: imx8mp: Allow adjusting the video PLL rates for the LDB clock Miquel Raynal 2026-10-21 13:10 ` [PATCH 4/5] clk: imx8mp: Set v2 rate negociation to LDB and pixel clocks Miquel Raynal 2026-10-21 13:10 ` [PATCH 5/5] arm64: dts: imx8mp: Drop VIDEO_PLL1 assigned rate Miquel Raynal 2026-10-21 14:11 ` [PATCH 0/5] clk: Use v2 rate calculation on i.MX8MP Brian Masney 2026-10-23 14:10 ` Jerome Brunet 2026-10-23 16:32 ` Miquel Raynal
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®