in cpufreq-dt.c [191:302]
static int dt_cpufreq_early_init(struct device *dev, int cpu)
{
struct private_data *priv;
struct device *cpu_dev;
bool fallback = false;
const char *reg_name;
int ret;
/* Check if this CPU is already covered by some other policy */
if (cpufreq_dt_find_data(cpu))
return 0;
cpu_dev = get_cpu_device(cpu);
if (!cpu_dev)
return -EPROBE_DEFER;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
if (!alloc_cpumask_var(&priv->cpus, GFP_KERNEL))
return -ENOMEM;
cpumask_set_cpu(cpu, priv->cpus);
priv->cpu_dev = cpu_dev;
/*
* OPP layer will be taking care of regulators now, but it needs to know
* the name of the regulator first.
*/
reg_name = find_supply_name(cpu_dev);
if (reg_name) {
priv->opp_table = dev_pm_opp_set_regulators(cpu_dev, ®_name,
1);
if (IS_ERR(priv->opp_table)) {
ret = PTR_ERR(priv->opp_table);
if (ret != -EPROBE_DEFER)
dev_err(cpu_dev, "failed to set regulators: %d\n",
ret);
goto free_cpumask;
}
}
/* Get OPP-sharing information from "operating-points-v2" bindings */
ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, priv->cpus);
if (ret) {
if (ret != -ENOENT)
goto out;
/*
* operating-points-v2 not supported, fallback to all CPUs share
* OPP for backward compatibility if the platform hasn't set
* sharing CPUs.
*/
if (dev_pm_opp_get_sharing_cpus(cpu_dev, priv->cpus))
fallback = true;
}
/*
* Initialize OPP tables for all priv->cpus. They will be shared by
* all CPUs which have marked their CPUs shared with OPP bindings.
*
* For platforms not using operating-points-v2 bindings, we do this
* before updating priv->cpus. Otherwise, we will end up creating
* duplicate OPPs for the CPUs.
*
* OPPs might be populated at runtime, don't fail for error here unless
* it is -EPROBE_DEFER.
*/
ret = dev_pm_opp_of_cpumask_add_table(priv->cpus);
if (!ret) {
priv->have_static_opps = true;
} else if (ret == -EPROBE_DEFER) {
goto out;
}
/*
* The OPP table must be initialized, statically or dynamically, by this
* point.
*/
ret = dev_pm_opp_get_opp_count(cpu_dev);
if (ret <= 0) {
dev_err(cpu_dev, "OPP table can't be empty\n");
ret = -ENODEV;
goto out;
}
if (fallback) {
cpumask_setall(priv->cpus);
ret = dev_pm_opp_set_sharing_cpus(cpu_dev, priv->cpus);
if (ret)
dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
__func__, ret);
}
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &priv->freq_table);
if (ret) {
dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
goto out;
}
list_add(&priv->node, &priv_list);
return 0;
out:
if (priv->have_static_opps)
dev_pm_opp_of_cpumask_remove_table(priv->cpus);
dev_pm_opp_put_regulators(priv->opp_table);
free_cpumask:
free_cpumask_var(priv->cpus);
return ret;
}