firmware: arm_scmi: Add clock determine_rate operation

Add a clock operation to help determining the effective rate, closest to
the required one, that a specific clock can support.

Calculation is currently performed kernel side and the logic is taken
directly from the SCMI Clock driver: embedding the determinate rate logic
in the protocol layer enables simplifications in the SCMI Clock protocol
interface and will more easily accommodate further evolutions where such
determine_rate logic into is optionally delegated to the platform SCMI
server.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Tested-by: Florian Fainelli <florian.fainelli@broadcom.com>
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://patch.msgid.link/20260508153300.2224715-3-cristian.marussi@arm.com
Signed-off-by: Sudeep Holla <sudeep.holla@kernel.org>
This commit is contained in:
Cristian Marussi
2026-05-08 16:32:47 +01:00
committed by Sudeep Holla
parent d0c81a38d0
commit ecde921eb4
2 changed files with 48 additions and 0 deletions

View File

@@ -5,6 +5,7 @@
* Copyright (C) 2018-2022 ARM Ltd.
*/
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/limits.h>
#include <linux/sort.h>
@@ -624,6 +625,46 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph,
return ret;
}
static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph,
u32 clk_id, unsigned long *rate)
{
u64 fmin, fmax, ftmp;
struct scmi_clock_info *clk;
struct clock_info *ci = ph->get_priv(ph);
if (!rate)
return -EINVAL;
clk = scmi_clock_domain_lookup(ci, clk_id);
if (IS_ERR(clk))
return PTR_ERR(clk);
/*
* If we can't figure out what rate it will be, so just return the
* rate back to the caller.
*/
if (clk->rate_discrete)
return 0;
fmin = clk->range.min_rate;
fmax = clk->range.max_rate;
if (*rate <= fmin) {
*rate = fmin;
return 0;
} else if (*rate >= fmax) {
*rate = fmax;
return 0;
}
ftmp = *rate - fmin;
ftmp += clk->range.step_size - 1; /* to round up */
ftmp = div64_ul(ftmp, clk->range.step_size);
*rate = ftmp * clk->range.step_size + fmin;
return 0;
}
static int
scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id,
enum clk_state state,
@@ -936,6 +977,7 @@ static const struct scmi_clk_proto_ops clk_proto_ops = {
.info_get = scmi_clock_info_get,
.rate_get = scmi_clock_rate_get,
.rate_set = scmi_clock_rate_set,
.determine_rate = scmi_clock_determine_rate,
.enable = scmi_clock_enable,
.disable = scmi_clock_disable,
.state_get = scmi_clock_state_get,

View File

@@ -91,6 +91,10 @@ enum scmi_clock_oem_config {
* @info_get: get the information of the specified clock
* @rate_get: request the current clock rate of a clock
* @rate_set: set the clock rate of a clock
* @determine_rate: determine the effective rate that can be supported by a
* clock calculating the closest allowed rate.
* Note that @rate is an input/output parameter used both to
* describe the requested rate and report the closest match
* @enable: enables the specified clock
* @disable: disables the specified clock
* @state_get: get the status of the specified clock
@@ -108,6 +112,8 @@ struct scmi_clk_proto_ops {
u64 *rate);
int (*rate_set)(const struct scmi_protocol_handle *ph, u32 clk_id,
u64 rate);
int (*determine_rate)(const struct scmi_protocol_handle *ph, u32 clk_id,
unsigned long *rate);
int (*enable)(const struct scmi_protocol_handle *ph, u32 clk_id,
bool atomic);
int (*disable)(const struct scmi_protocol_handle *ph, u32 clk_id,