mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
cpufreq: sun50i: Add support for opp_supported_hw
The opp_supported_hw DT property allows the DT to specify a mask of chip revisions that a certain OPP is eligible for. This allows for easy limiting of maximum frequencies, for instance. Add support for that in the sun50i-cpufreq-nvmem driver. We support both the existing opp-microvolt suffix properties as well as the opp-supported-hw property, the generic code figures out which is needed automatically. However if none of the DT OPP nodes contain an opp-supported-hw property, the core code will ignore all OPPs and the driver will fail probing. So check the DT's eligibility first before using that feature. Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
This commit is contained in:
parent
6cc4bcceff
commit
fa5aec9561
@ -57,6 +57,41 @@ static const struct of_device_id cpu_opp_match_list[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* dt_has_supported_hw() - Check if any OPPs use opp-supported-hw
|
||||
*
|
||||
* If we ask the cpufreq framework to use the opp-supported-hw feature, it
|
||||
* will ignore every OPP node without that DT property. If none of the OPPs
|
||||
* have it, the driver will fail probing, due to the lack of OPPs.
|
||||
*
|
||||
* Returns true if we have at least one OPP with the opp-supported-hw property.
|
||||
*/
|
||||
static bool dt_has_supported_hw(void)
|
||||
{
|
||||
bool has_opp_supported_hw = false;
|
||||
struct device_node *np, *opp;
|
||||
struct device *cpu_dev;
|
||||
|
||||
cpu_dev = get_cpu_device(0);
|
||||
if (!cpu_dev)
|
||||
return -ENODEV;
|
||||
|
||||
np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
|
||||
if (!np)
|
||||
return -ENOENT;
|
||||
|
||||
for_each_child_of_node(np, opp) {
|
||||
if (of_find_property(opp, "opp-supported-hw", NULL)) {
|
||||
has_opp_supported_hw = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
of_node_put(np);
|
||||
|
||||
return has_opp_supported_hw;
|
||||
}
|
||||
|
||||
/**
|
||||
* sun50i_cpufreq_get_efuse() - Determine speed grade from efuse value
|
||||
*
|
||||
@ -110,7 +145,8 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
|
||||
{
|
||||
int *opp_tokens;
|
||||
char name[MAX_NAME_LEN];
|
||||
unsigned int cpu;
|
||||
unsigned int cpu, supported_hw;
|
||||
struct dev_pm_opp_config config = {};
|
||||
int speed;
|
||||
int ret;
|
||||
|
||||
@ -125,7 +161,18 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
|
||||
return speed;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need at least one OPP with the "opp-supported-hw" property,
|
||||
* or else the upper layers will ignore every OPP and will bail out.
|
||||
*/
|
||||
if (dt_has_supported_hw()) {
|
||||
supported_hw = 1U << speed;
|
||||
config.supported_hw = &supported_hw;
|
||||
config.supported_hw_count = 1;
|
||||
}
|
||||
|
||||
snprintf(name, MAX_NAME_LEN, "speed%d", speed);
|
||||
config.prop_name = name;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct device *cpu_dev = get_cpu_device(cpu);
|
||||
@ -135,12 +182,11 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
|
||||
goto free_opp;
|
||||
}
|
||||
|
||||
opp_tokens[cpu] = dev_pm_opp_set_prop_name(cpu_dev, name);
|
||||
if (opp_tokens[cpu] < 0) {
|
||||
ret = opp_tokens[cpu];
|
||||
pr_err("Failed to set prop name\n");
|
||||
ret = dev_pm_opp_set_config(cpu_dev, &config);
|
||||
if (ret < 0)
|
||||
goto free_opp;
|
||||
}
|
||||
|
||||
opp_tokens[cpu] = ret;
|
||||
}
|
||||
|
||||
cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
|
||||
@ -155,7 +201,7 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
|
||||
|
||||
free_opp:
|
||||
for_each_possible_cpu(cpu)
|
||||
dev_pm_opp_put_prop_name(opp_tokens[cpu]);
|
||||
dev_pm_opp_clear_config(opp_tokens[cpu]);
|
||||
kfree(opp_tokens);
|
||||
|
||||
return ret;
|
||||
@ -169,7 +215,7 @@ static void sun50i_cpufreq_nvmem_remove(struct platform_device *pdev)
|
||||
platform_device_unregister(cpufreq_dt_pdev);
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
dev_pm_opp_put_prop_name(opp_tokens[cpu]);
|
||||
dev_pm_opp_clear_config(opp_tokens[cpu]);
|
||||
|
||||
kfree(opp_tokens);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user