| 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: ANDROID: 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. |
| |
| [CPNOTE: 06/07/21] Lee: Requested status from the bug |
| |
| Bug: 141621388 |
| Change-Id: I4f8cf9df6fc256d065599de86a34cf99eae4d853 |
| Signed-off-by: David Dai <daidavid1@codeaurora.org> |
| Signed-off-by: Lee Jones <joneslee@google.com> |
| --- |
| 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 |
| --- a/drivers/clk/clk.c |
| +++ b/drivers/clk/clk.c |
| @@ -2198,6 +2198,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) |
| @@ -2292,6 +2299,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 |
| --- a/include/linux/clk-provider.h |
| +++ b/include/linux/clk-provider.h |
| @@ -217,6 +217,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 |
| @@ -264,6 +271,12 @@ struct clk_ops { |
| int (*init)(struct clk_hw *hw); |
| void (*terminate)(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); |
| }; |
| |
| /** |