Messages in this thread Patch in this message | | | From | Cristian Marussi <> | Subject | [PATCH 6/7] clk: scmi: Allocate CLK operations dynamically | Date | Wed, 14 Feb 2024 18:30:05 +0000 |
| |
SCMI Clocks descriptors expose and increasing number of properties that in turn lead to a different set of supported CLK operations to be associated dynamically with a clock.
Providing statically pre-defined CLK operations structs for all the possible combinations of allowed properties is cumbersome and error-prone.
Allocate per-clock operations descriptor dynamically and populate it with the strictly needed set of operations depending on the advertised clock properties.
CC: Michael Turquette <mturquette@baylibre.com> CC: Stephen Boyd <sboyd@kernel.org> CC: linux-clk@vger.kernel.org Signed-off-by: Cristian Marussi <cristian.marussi@arm.com> --- drivers/clk/clk-scmi.c | 129 ++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 59 deletions(-)
diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c index 5747b6d651f0..b91a0dbd2fe0 100644 --- a/drivers/clk/clk-scmi.c +++ b/drivers/clk/clk-scmi.c @@ -158,51 +158,6 @@ static int scmi_clk_atomic_is_enabled(struct clk_hw *hw) return !!enabled; } -/* - * We can provide enable/disable/is_enabled atomic callbacks only if the - * underlying SCMI transport for an SCMI instance is configured to handle - * SCMI commands in an atomic manner. - * - * When no SCMI atomic transport support is available we instead provide only - * the prepare/unprepare API, as allowed by the clock framework when atomic - * calls are not available. - * - * Two distinct sets of clk_ops are provided since we could have multiple SCMI - * instances with different underlying transport quality, so they cannot be - * shared. - */ -static const struct clk_ops scmi_clk_ops = { - .recalc_rate = scmi_clk_recalc_rate, - .round_rate = scmi_clk_round_rate, - .set_rate = scmi_clk_set_rate, - .prepare = scmi_clk_enable, - .unprepare = scmi_clk_disable, - .set_parent = scmi_clk_set_parent, - .get_parent = scmi_clk_get_parent, - .determine_rate = scmi_clk_determine_rate, -}; - -static const struct clk_ops scmi_atomic_clk_ops = { - .recalc_rate = scmi_clk_recalc_rate, - .round_rate = scmi_clk_round_rate, - .set_rate = scmi_clk_set_rate, - .enable = scmi_clk_atomic_enable, - .disable = scmi_clk_atomic_disable, - .is_enabled = scmi_clk_atomic_is_enabled, - .set_parent = scmi_clk_set_parent, - .get_parent = scmi_clk_get_parent, - .determine_rate = scmi_clk_determine_rate, -}; - -static const struct clk_ops scmi_no_state_ctrl_clk_ops = { - .recalc_rate = scmi_clk_recalc_rate, - .round_rate = scmi_clk_round_rate, - .set_rate = scmi_clk_set_rate, - .set_parent = scmi_clk_set_parent, - .get_parent = scmi_clk_get_parent, - .determine_rate = scmi_clk_determine_rate, -}; - static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk, const struct clk_ops *scmi_ops) { @@ -239,6 +194,71 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk, return ret; } +/** + * scmi_clk_ops_alloc() - Alloc and configure CLK ops + * @sclk: A reference to an SCMI clock descriptor + * @atomic_capable: A flag to indicate if atomic mode is supported by the + * transport + * @atomic_threshold: Platform atomic threshold value + * + * Allocate and configure a proper set of CLK operations depending on the + * specific SCMI clock characteristics and platform atomic operation capability. + * + * We can provide enable/disable/is_enabled atomic callbacks only if the + * underlying SCMI transport for an SCMI instance is configured to handle + * SCMI commands in an atomic manner. + * + * When no SCMI atomic transport support is available we instead provide only + * the prepare/unprepare API, as allowed by the clock framework when atomic + * calls are not available. + * + * Return: A pointer to the allocated and configured clk_ops on Success, + * NULL otherwise. + */ +static const struct clk_ops * +scmi_clk_ops_alloc(struct scmi_clk *sclk, bool atomic_capable, + unsigned int atomic_threshold) +{ + const struct scmi_clock_info *ci = sclk->info; + struct clk_ops *ops; + + ops = devm_kzalloc(sclk->dev, sizeof(*ops), GFP_KERNEL); + if (!ops) + return NULL; + + /* + * Note that when transport is atomic but SCMI protocol did not + * specify (or support) an enable_latency associated with a + * clock, we default to use atomic operations mode. + */ + if (!ci->state_ctrl_forbidden) { + if (atomic_capable && ci->enable_latency <= atomic_threshold) { + ops->enable = scmi_clk_atomic_enable; + ops->disable = scmi_clk_atomic_disable; + } else { + ops->prepare = scmi_clk_enable; + ops->unprepare = scmi_clk_disable; + } + } + + if (atomic_capable) + ops->is_enabled = scmi_clk_atomic_is_enabled; + + /* Rate ops */ + ops->recalc_rate = scmi_clk_recalc_rate; + ops->round_rate = scmi_clk_round_rate; + ops->determine_rate = scmi_clk_determine_rate; + if (!ci->rate_ctrl_forbidden) + ops->set_rate = scmi_clk_set_rate; + + /* Parent ops */ + ops->get_parent = scmi_clk_get_parent; + if (!ci->parent_ctrl_forbidden) + ops->set_parent = scmi_clk_set_parent; + + return ops; +} + static int scmi_clocks_probe(struct scmi_device *sdev) { int idx, count, err; @@ -294,18 +314,9 @@ static int scmi_clocks_probe(struct scmi_device *sdev) sclk->ph = ph; sclk->dev = dev; - /* - * Note that when transport is atomic but SCMI protocol did not - * specify (or support) an enable_latency associated with a - * clock, we default to use atomic operations mode. - */ - if (sclk->info->state_ctrl_forbidden) - scmi_ops = &scmi_no_state_ctrl_clk_ops; - else if (is_atomic && - sclk->info->enable_latency <= atomic_threshold) - scmi_ops = &scmi_atomic_clk_ops; - else - scmi_ops = &scmi_clk_ops; + scmi_ops = scmi_clk_ops_alloc(sclk, is_atomic, atomic_threshold); + if (!scmi_ops) + return -ENOMEM; /* Initialize clock parent data. */ if (sclk->info->num_parents > 0) { @@ -324,13 +335,13 @@ static int scmi_clocks_probe(struct scmi_device *sdev) if (err) { dev_err(dev, "failed to register clock %d\n", idx); devm_kfree(dev, sclk->parent_data); + devm_kfree(dev, scmi_ops); devm_kfree(dev, sclk); hws[idx] = NULL; } else { dev_dbg(dev, "Registered clock:%s%s\n", sclk->info->name, - scmi_ops == &scmi_atomic_clk_ops ? - " (atomic ops)" : ""); + scmi_ops->enable ? " (atomic ops)" : ""); hws[idx] = &sclk->hw; } } -- 2.43.0
| |