[PATCH 4/5] clk: Add flag to prevent frequency changes when walking subtrees
Miquel Raynal
miquel.raynal at bootlin.com
Thu Nov 21 09:41:14 PST 2024
There are mainly two ways to change a clock frequency. The active way
requires calling ->set_rate() in order to ask "on purpose" for a
frequency change. Otherwise, a clock can passively see its frequency
being updated depending on upstream clock frequency changes. In most
cases it is fine to just accept the new upstream frequency - which by
definition will have an impact on downstream frequencies if we do not
recalculate internal divisors. But there are cases where, upon an
upstream frequency change, we would like to maintain a specific rate.
As an example, on iMX8MP the video pipeline clocks are looking like this:
video_pll1
video_pll1_bypass
video_pll1_out
media_ldb
media_ldb_root_clk
media_disp2_pix
media_disp2_pix_root_clk
media_disp1_pix
media_disp1_pix_root_clk
media_ldb, media_disp2_pix and media_disp1_pix are simple divisors from
which we might require 2 or 3 different rates, whereas video_pll1 is a
very configurable PLL which can achieve almost any frequency. There are
however relationships between them, typically the ldb clock must be 3.5
or 7 times higher than the media_disp* clocks.
Currently, if eg. media_disp2_pix is set to 71900000Hz, when media_ldb
is (later) set to 503300000Hz, media_disp2_pix is updated to 503300000Hz
as well, which clearly does not make sense. We want it to stay at
71900000Hz during the subtree walk.
Achieving this is the purpose of the new clock flag:
CLK_NO_RATE_CHANGE_DURING_PROPAGATION
Please note, if the kernel was setting the ldb clock before a pixel
clock, the result would be different, and this is also what this patch
is trying to solve.
Signed-off-by: Miquel Raynal <miquel.raynal at bootlin.com>
---
In all cases, the LDB must be aware of the device configuration, and ask
for a clever frequency, we will never cope with slightly aware drivers
when addressing this kind of subtle situation.
---
drivers/clk/clk.c | 9 +++++++--
include/linux/clk-provider.h | 2 ++
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index adfc5bfb93b5a65b6f58c52ca2c432d651f7dd7d..94d93470479e77769e63e97462b176261103b552 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1927,7 +1927,6 @@ long clk_get_accuracy(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_get_accuracy);
-__maybe_unused
static unsigned long clk_determine(struct clk_core *core, unsigned long rate)
{
struct clk_rate_request req = {};
@@ -2272,7 +2271,13 @@ static void clk_calc_subtree(struct clk_core *core)
{
struct clk_core *child;
- core->new_rate = clk_recalc(core, core->parent->new_rate);
+ if (core->flags & CLK_NO_RATE_CHANGE_DURING_PROPAGATION) {
+ core->new_rate = clk_determine(core, core->rate);
+ if (!core->new_rate)
+ core->new_rate = clk_recalc(core, core->parent->new_rate);
+ } else {
+ core->new_rate = clk_recalc(core, core->parent->new_rate);
+ }
hlist_for_each_entry(child, &core->children, child_node)
clk_calc_subtree(child);
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 200135e0f6d00d48b10e843259333b9733c97f38..baef0b442ac1d36ee935cbcaaaa4e2d95fe7654c 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -38,6 +38,8 @@
#define CLK_OPS_PARENT_ENABLE BIT(12)
/* duty cycle call may be forwarded to the parent clock */
#define CLK_DUTY_CYCLE_PARENT BIT(13)
+/* do not passively change this clock rate during subtree rate propagation */
+#define CLK_NO_RATE_CHANGE_DURING_PROPAGATION BIT(14)
struct clk;
struct clk_hw;
--
2.47.0
More information about the linux-arm-kernel
mailing list