
up to 1caeb408f5
("UPSTREAM: base: soc: Handle custom soc information sysfs entries")
Change-Id: I070748e45a9ffbdd0fdba43fe56b99db90a10b08
Signed-off-by: Matthias Maennich <maennich@google.com>
88 lines
3.5 KiB
Diff
88 lines
3.5 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: David Dai <daidavid1@codeaurora.org>
|
|
Date: Mon, 19 Aug 2019 16:35:44 -0700
|
|
Subject: clk: add pre and post change rate callbacks
|
|
|
|
There are scenarios where a rate change could result in a configuration
|
|
change for both the targeted clock and its parent.
|
|
|
|
For example, setting the rate for a clock could require both slewing its parent
|
|
PLL as well as adjusting the clock's divider values. Due to the fact that
|
|
rate change propagation always occurs from parent to child, we could exceed
|
|
the allowed operating frequencies for the clock as the parent slews to a higher
|
|
frequency before increasing the downstream divider.
|
|
|
|
Add a pre change call back which allows the clock to adjust its divider
|
|
appropriately before any rate change has occurred from its parents to ensure
|
|
that the clock's requirements are always within safe frequencies during parent
|
|
rate changes. The symmetrical post change call back handles the scenario where
|
|
the divider adjusts to a lower value and can only be safely adjusted after the
|
|
parent rate changes.
|
|
|
|
Change-Id: I4f8cf9df6fc256d065599de86a34cf99eae4d853
|
|
Signed-off-by: David Dai <daidavid1@codeaurora.org>
|
|
---
|
|
drivers/clk/clk.c | 10 ++++++++++
|
|
include/linux/clk-provider.h | 13 +++++++++++++
|
|
2 files changed, 23 insertions(+)
|
|
|
|
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
|
|
index 1c677d7f7f53..020fdb8105cc 100644
|
|
--- a/drivers/clk/clk.c
|
|
+++ b/drivers/clk/clk.c
|
|
@@ -1980,6 +1980,13 @@ static struct clk_core *clk_propagate_rate_change(struct clk_core *core,
|
|
fail_clk = core;
|
|
}
|
|
|
|
+ if (core->ops->pre_rate_change) {
|
|
+ ret = core->ops->pre_rate_change(core->hw, core->rate,
|
|
+ core->new_rate);
|
|
+ if (ret)
|
|
+ fail_clk = core;
|
|
+ }
|
|
+
|
|
hlist_for_each_entry(child, &core->children, child_node) {
|
|
/* Skip children who will be reparented to another clock */
|
|
if (child->new_parent && child->new_parent != core)
|
|
@@ -2082,6 +2089,9 @@ static void clk_change_rate(struct clk_core *core)
|
|
if (core->flags & CLK_RECALC_NEW_RATES)
|
|
(void)clk_calc_new_rates(core, core->new_rate);
|
|
|
|
+ if (core->ops->post_rate_change)
|
|
+ core->ops->post_rate_change(core->hw, old_rate, core->rate);
|
|
+
|
|
/*
|
|
* Use safe iteration, as change_rate can actually swap parents
|
|
* for certain clock types.
|
|
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
|
|
index 2fdfe8061363..73e4369e8408 100644
|
|
--- a/include/linux/clk-provider.h
|
|
+++ b/include/linux/clk-provider.h
|
|
@@ -199,6 +199,13 @@ struct clk_duty {
|
|
* directory is provided as an argument. Called with
|
|
* prepare_lock held. Returns 0 on success, -EERROR otherwise.
|
|
*
|
|
+ * @pre_rate_change: Optional callback for a clock to fulfill its rate
|
|
+ * change requirements before any rate change has occurred in
|
|
+ * its clock tree. Returns 0 on success, -EERROR otherwise.
|
|
+ *
|
|
+ * @post_rate_change: Optional callback for a clock to clean up any
|
|
+ * requirements that were needed while the clock and its tree
|
|
+ * was changing states. Returns 0 on success, -EERROR otherwise.
|
|
*
|
|
* The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
|
|
* implementations to split any work between atomic (enable) and sleepable
|
|
@@ -245,6 +252,12 @@ struct clk_ops {
|
|
struct clk_duty *duty);
|
|
void (*init)(struct clk_hw *hw);
|
|
void (*debug_init)(struct clk_hw *hw, struct dentry *dentry);
|
|
+ int (*pre_rate_change)(struct clk_hw *hw,
|
|
+ unsigned long rate,
|
|
+ unsigned long new_rate);
|
|
+ int (*post_rate_change)(struct clk_hw *hw,
|
|
+ unsigned long old_rate,
|
|
+ unsigned long rate);
|
|
};
|
|
|
|
/**
|