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
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",
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 */
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;
}
.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))
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;
}
* 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);
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);
* 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;
}
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,
.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,