Skip to content

Commit fa5aec9

Browse files
Andre-ARMvireshk
authored andcommitted
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 <[email protected]> Reviewed-by: Jernej Skrabec <[email protected]> Signed-off-by: Viresh Kumar <[email protected]>
1 parent 6cc4bcc commit fa5aec9

File tree

1 file changed

+54
-8
lines changed

1 file changed

+54
-8
lines changed

drivers/cpufreq/sun50i-cpufreq-nvmem.c

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,41 @@ static const struct of_device_id cpu_opp_match_list[] = {
5757
{}
5858
};
5959

60+
/**
61+
* dt_has_supported_hw() - Check if any OPPs use opp-supported-hw
62+
*
63+
* If we ask the cpufreq framework to use the opp-supported-hw feature, it
64+
* will ignore every OPP node without that DT property. If none of the OPPs
65+
* have it, the driver will fail probing, due to the lack of OPPs.
66+
*
67+
* Returns true if we have at least one OPP with the opp-supported-hw property.
68+
*/
69+
static bool dt_has_supported_hw(void)
70+
{
71+
bool has_opp_supported_hw = false;
72+
struct device_node *np, *opp;
73+
struct device *cpu_dev;
74+
75+
cpu_dev = get_cpu_device(0);
76+
if (!cpu_dev)
77+
return -ENODEV;
78+
79+
np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
80+
if (!np)
81+
return -ENOENT;
82+
83+
for_each_child_of_node(np, opp) {
84+
if (of_find_property(opp, "opp-supported-hw", NULL)) {
85+
has_opp_supported_hw = true;
86+
break;
87+
}
88+
}
89+
90+
of_node_put(np);
91+
92+
return has_opp_supported_hw;
93+
}
94+
6095
/**
6196
* sun50i_cpufreq_get_efuse() - Determine speed grade from efuse value
6297
*
@@ -110,7 +145,8 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
110145
{
111146
int *opp_tokens;
112147
char name[MAX_NAME_LEN];
113-
unsigned int cpu;
148+
unsigned int cpu, supported_hw;
149+
struct dev_pm_opp_config config = {};
114150
int speed;
115151
int ret;
116152

@@ -125,7 +161,18 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
125161
return speed;
126162
}
127163

164+
/*
165+
* We need at least one OPP with the "opp-supported-hw" property,
166+
* or else the upper layers will ignore every OPP and will bail out.
167+
*/
168+
if (dt_has_supported_hw()) {
169+
supported_hw = 1U << speed;
170+
config.supported_hw = &supported_hw;
171+
config.supported_hw_count = 1;
172+
}
173+
128174
snprintf(name, MAX_NAME_LEN, "speed%d", speed);
175+
config.prop_name = name;
129176

130177
for_each_possible_cpu(cpu) {
131178
struct device *cpu_dev = get_cpu_device(cpu);
@@ -135,12 +182,11 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
135182
goto free_opp;
136183
}
137184

138-
opp_tokens[cpu] = dev_pm_opp_set_prop_name(cpu_dev, name);
139-
if (opp_tokens[cpu] < 0) {
140-
ret = opp_tokens[cpu];
141-
pr_err("Failed to set prop name\n");
185+
ret = dev_pm_opp_set_config(cpu_dev, &config);
186+
if (ret < 0)
142187
goto free_opp;
143-
}
188+
189+
opp_tokens[cpu] = ret;
144190
}
145191

146192
cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
@@ -155,7 +201,7 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
155201

156202
free_opp:
157203
for_each_possible_cpu(cpu)
158-
dev_pm_opp_put_prop_name(opp_tokens[cpu]);
204+
dev_pm_opp_clear_config(opp_tokens[cpu]);
159205
kfree(opp_tokens);
160206

161207
return ret;
@@ -169,7 +215,7 @@ static void sun50i_cpufreq_nvmem_remove(struct platform_device *pdev)
169215
platform_device_unregister(cpufreq_dt_pdev);
170216

171217
for_each_possible_cpu(cpu)
172-
dev_pm_opp_put_prop_name(opp_tokens[cpu]);
218+
dev_pm_opp_clear_config(opp_tokens[cpu]);
173219

174220
kfree(opp_tokens);
175221
}

0 commit comments

Comments
 (0)