mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
firmware: arm_scmi: Introduce all_rates_get clock operation
Add a clock operation to get the whole set of rates available to a specific clock: when needed this request could transparently trigger a full rate discovery enumeration if this specific clock-rates were previously only lazily enumerated. Reviewed-by: Peng Fan <peng.fan@nxp.com> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com> Link: https://patch.msgid.link/20260508153300.2224715-16-cristian.marussi@arm.com Signed-off-by: Sudeep Holla <sudeep.holla@kernel.org>
This commit is contained in:
parent
4a07036d61
commit
d2488ff1a2
|
|
@ -159,10 +159,8 @@ struct scmi_clock_rate_notify_payld {
|
|||
|
||||
struct scmi_clock_desc {
|
||||
u32 id;
|
||||
bool rate_discrete;
|
||||
unsigned int tot_rates;
|
||||
unsigned int num_rates;
|
||||
u64 *rates;
|
||||
struct scmi_clock_rates r;
|
||||
#define RATE_MIN 0
|
||||
#define RATE_MAX 1
|
||||
#define RATE_STEP 2
|
||||
|
|
@ -469,10 +467,10 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
|
|||
flags = le32_to_cpu(r->num_rates_flags);
|
||||
st->num_remaining = NUM_REMAINING(flags);
|
||||
st->num_returned = NUM_RETURNED(flags);
|
||||
p->clkd->rate_discrete = RATE_DISCRETE(flags);
|
||||
p->clkd->r.rate_discrete = RATE_DISCRETE(flags);
|
||||
|
||||
/* Warn about out of spec replies ... */
|
||||
if (!p->clkd->rate_discrete &&
|
||||
if (!p->clkd->r.rate_discrete &&
|
||||
(st->num_returned != 3 || st->num_remaining != 0)) {
|
||||
dev_warn(p->dev,
|
||||
"Out-of-spec CLOCK_DESCRIBE_RATES reply for %s - returned:%d remaining:%d rx_len:%zd\n",
|
||||
|
|
@ -486,9 +484,9 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
|
|||
if (!st->max_resources) {
|
||||
unsigned int tot_rates = st->num_returned + st->num_remaining;
|
||||
|
||||
p->clkd->rates = devm_kcalloc(p->dev, tot_rates,
|
||||
sizeof(*p->clkd->rates), GFP_KERNEL);
|
||||
if (!p->clkd->rates)
|
||||
p->clkd->r.rates = devm_kcalloc(p->dev, tot_rates,
|
||||
sizeof(*p->clkd->r.rates), GFP_KERNEL);
|
||||
if (!p->clkd->r.rates)
|
||||
return -ENOMEM;
|
||||
|
||||
/* max_resources is used by the iterators to control bounds */
|
||||
|
|
@ -507,10 +505,10 @@ iter_clk_describe_process_response(const struct scmi_protocol_handle *ph,
|
|||
struct scmi_clk_ipriv *p = priv;
|
||||
const struct scmi_msg_resp_clock_describe_rates *r = response;
|
||||
|
||||
p->clkd->rates[p->clkd->num_rates] = RATE_TO_U64(r->rate[st->loop_idx]);
|
||||
p->clkd->r.rates[p->clkd->r.num_rates] = RATE_TO_U64(r->rate[st->loop_idx]);
|
||||
|
||||
/* Count only effectively discovered rates */
|
||||
p->clkd->num_rates++;
|
||||
p->clkd->r.num_rates++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -531,7 +529,13 @@ scmi_clock_describe_rates_get_full(const struct scmi_protocol_handle *ph,
|
|||
.dev = ph->dev,
|
||||
};
|
||||
|
||||
iter = ph->hops->iter_response_init(ph, &ops, 0, CLOCK_DESCRIBE_RATES,
|
||||
/*
|
||||
* Using tot_rates as max_resources parameter here so as to trigger
|
||||
* the dynamic allocation only when strictly needed: when trying a
|
||||
* full enumeration after a lazy one tot_rates will be non-zero.
|
||||
*/
|
||||
iter = ph->hops->iter_response_init(ph, &ops, clkd->tot_rates,
|
||||
CLOCK_DESCRIBE_RATES,
|
||||
sizeof(struct scmi_msg_clock_describe_rates),
|
||||
&cpriv);
|
||||
if (IS_ERR(iter))
|
||||
|
|
@ -542,12 +546,12 @@ scmi_clock_describe_rates_get_full(const struct scmi_protocol_handle *ph,
|
|||
return ret;
|
||||
|
||||
/* empty set ? */
|
||||
if (!clkd->num_rates)
|
||||
if (!clkd->r.num_rates)
|
||||
return 0;
|
||||
|
||||
if (clkd->rate_discrete)
|
||||
sort(clkd->rates, clkd->num_rates,
|
||||
sizeof(clkd->rates[0]), rate_cmp_func, NULL);
|
||||
if (clkd->r.rate_discrete && PROTOCOL_REV_MAJOR(ph->version) == 0x1)
|
||||
sort(clkd->r.rates, clkd->r.num_rates,
|
||||
sizeof(clkd->r.rates[0]), rate_cmp_func, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -586,7 +590,7 @@ scmi_clock_describe_rates_get_lazy(const struct scmi_protocol_handle *ph,
|
|||
* If discrete and we don't already have it, grab the last value, which
|
||||
* should be the max
|
||||
*/
|
||||
if (clkd->rate_discrete && clkd->tot_rates > clkd->num_rates) {
|
||||
if (clkd->r.rate_discrete && clkd->tot_rates > clkd->r.num_rates) {
|
||||
first = clkd->tot_rates - 1;
|
||||
last = clkd->tot_rates - 1;
|
||||
ret = ph->hops->iter_response_run_bound(iter, &first, &last);
|
||||
|
|
@ -618,14 +622,14 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
clkd->info.min_rate = clkd->rates[RATE_MIN];
|
||||
if (!clkd->rate_discrete) {
|
||||
clkd->info.max_rate = clkd->rates[RATE_MAX];
|
||||
clkd->info.min_rate = clkd->r.rates[RATE_MIN];
|
||||
if (!clkd->r.rate_discrete) {
|
||||
clkd->info.max_rate = clkd->r.rates[RATE_MAX];
|
||||
dev_dbg(ph->dev, "Min %llu Max %llu Step %llu Hz\n",
|
||||
clkd->rates[RATE_MIN], clkd->rates[RATE_MAX],
|
||||
clkd->rates[RATE_STEP]);
|
||||
clkd->r.rates[RATE_MIN], clkd->r.rates[RATE_MAX],
|
||||
clkd->r.rates[RATE_STEP]);
|
||||
} else {
|
||||
clkd->info.max_rate = clkd->rates[clkd->num_rates - 1];
|
||||
clkd->info.max_rate = clkd->r.rates[clkd->r.num_rates - 1];
|
||||
dev_dbg(ph->dev, "Clock:%s Num_Rates:%u -> Min %llu Max %llu\n",
|
||||
clkd->info.name, clkd->tot_rates,
|
||||
clkd->info.min_rate, clkd->info.max_rate);
|
||||
|
|
@ -732,7 +736,7 @@ static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph,
|
|||
* If we can't figure out what rate it will be, so just return the
|
||||
* rate back to the caller.
|
||||
*/
|
||||
if (clkd->rate_discrete)
|
||||
if (clkd->r.rate_discrete)
|
||||
return 0;
|
||||
|
||||
fmin = clk->min_rate;
|
||||
|
|
@ -746,14 +750,40 @@ static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph,
|
|||
}
|
||||
|
||||
ftmp = *rate - fmin;
|
||||
ftmp += clkd->rates[RATE_STEP] - 1; /* to round up */
|
||||
ftmp = div64_ul(ftmp, clkd->rates[RATE_STEP]);
|
||||
ftmp += clkd->r.rates[RATE_STEP] - 1; /* to round up */
|
||||
ftmp = div64_ul(ftmp, clkd->r.rates[RATE_STEP]);
|
||||
|
||||
*rate = ftmp * clkd->rates[RATE_STEP] + fmin;
|
||||
*rate = ftmp * clkd->r.rates[RATE_STEP] + fmin;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct scmi_clock_rates *
|
||||
scmi_clock_all_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id)
|
||||
{
|
||||
struct clock_info *ci = ph->get_priv(ph);
|
||||
struct scmi_clock_desc *clkd;
|
||||
struct scmi_clock_info *clk;
|
||||
|
||||
clk = scmi_clock_domain_lookup(ci, clk_id);
|
||||
if (IS_ERR(clk) || !clk->name[0])
|
||||
return NULL;
|
||||
|
||||
clkd = to_desc(clk);
|
||||
/* Needs full enumeration ? */
|
||||
if (clkd->r.rate_discrete && clkd->tot_rates != clkd->r.num_rates) {
|
||||
int ret;
|
||||
|
||||
/* rates[] is already allocated BUT we need to re-enumerate */
|
||||
clkd->r.num_rates = 0;
|
||||
ret = scmi_clock_describe_rates_get_full(ph, clkd);
|
||||
if (ret)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &clkd->r;
|
||||
}
|
||||
|
||||
static int
|
||||
scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id,
|
||||
enum clk_state state,
|
||||
|
|
@ -1067,6 +1097,7 @@ static const struct scmi_clk_proto_ops clk_proto_ops = {
|
|||
.rate_get = scmi_clock_rate_get,
|
||||
.rate_set = scmi_clock_rate_set,
|
||||
.determine_rate = scmi_clock_determine_rate,
|
||||
.all_rates_get = scmi_clock_all_rates_get,
|
||||
.enable = scmi_clock_enable,
|
||||
.disable = scmi_clock_disable,
|
||||
.state_get = scmi_clock_state_get,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,12 @@ struct scmi_base_info {
|
|||
char sub_vendor_id[SCMI_SHORT_NAME_MAX_SIZE];
|
||||
};
|
||||
|
||||
struct scmi_clock_rates {
|
||||
bool rate_discrete;
|
||||
unsigned int num_rates;
|
||||
u64 *rates;
|
||||
};
|
||||
|
||||
struct scmi_clock_info {
|
||||
char name[SCMI_MAX_STR_SIZE];
|
||||
unsigned int enable_latency;
|
||||
|
|
@ -84,6 +90,7 @@ enum scmi_clock_oem_config {
|
|||
* 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
|
||||
* @all_rates_get: get the list of all available rates for the specified clock.
|
||||
* @enable: enables the specified clock
|
||||
* @disable: disables the specified clock
|
||||
* @state_get: get the status of the specified clock
|
||||
|
|
@ -103,6 +110,8 @@ struct scmi_clk_proto_ops {
|
|||
u64 rate);
|
||||
int (*determine_rate)(const struct scmi_protocol_handle *ph, u32 clk_id,
|
||||
unsigned long *rate);
|
||||
const struct scmi_clock_rates __must_check *(*all_rates_get)
|
||||
(const struct scmi_protocol_handle *ph, u32 clk_id);
|
||||
int (*enable)(const struct scmi_protocol_handle *ph, u32 clk_id,
|
||||
bool atomic);
|
||||
int (*disable)(const struct scmi_protocol_handle *ph, u32 clk_id,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user