Improve cpufreq_dt.

- older DT can use 'cpu0-supply' property for power supply binding.
 - don't expect that actual CPU frequency is contained in CPU
   operational point table, but read current CPU voltage directly from
   reguator. Typically, u-boot can set starting CPU frequency to any
   value.

MFC after:	2 weeks
This commit is contained in:
Michal Meloun 2019-03-19 14:34:53 +00:00
parent 966e7b050d
commit a701764e9c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=345297

View File

@ -166,7 +166,7 @@ cpufreq_dt_set(device_t dev, const struct cf_setting *set)
struct cpufreq_dt_softc *sc;
const struct cpufreq_dt_opp *opp, *copp;
uint64_t freq;
int error = 0;
int uvolt, error;
sc = device_get_softc(dev);
@ -174,23 +174,38 @@ cpufreq_dt_set(device_t dev, const struct cf_setting *set)
device_printf(dev, "Can't get current clk freq\n");
return (ENXIO);
}
/* Try to get current valtage by using regulator first. */
error = regulator_get_voltage(sc->reg, &uvolt);
if (error != 0) {
/*
* Try oppoints table as backup way. However,
* this is insufficient because the actual processor
* frequency may not be in the table. PLL frequency
* granularity can be different that granularity of
* oppoint table.
*/
copp = cpufreq_dt_find_opp(sc->dev, freq);
if (copp == NULL) {
device_printf(dev,
"Can't find the current freq in opp\n");
return (ENOENT);
}
uvolt = copp->uvolt_target;
DEBUG(sc->dev, "Current freq %ju\n", freq);
DEBUG(sc->dev, "Target freq %ju\n", (uint64_t)set->freq * 1000000);
copp = cpufreq_dt_find_opp(sc->dev, freq);
if (copp == NULL) {
device_printf(dev, "Can't find the current freq in opp\n");
return (ENOENT);
}
opp = cpufreq_dt_find_opp(sc->dev, set->freq * 1000000);
if (opp == NULL) {
device_printf(dev, "Couldn't find an opp for this freq\n");
return (EINVAL);
}
DEBUG(sc->dev, "Current freq %ju, uvolt: %d\n", freq, uvolt);
DEBUG(sc->dev, "Target freq %ju, , uvolt: %d\n",
opp->freq, opp->uvolt_target);
if (copp->uvolt_target < opp->uvolt_target) {
if (uvolt < opp->uvolt_target) {
DEBUG(dev, "Changing regulator from %u to %u\n",
copp->uvolt_target, opp->uvolt_target);
uvolt, opp->uvolt_target);
error = regulator_set_voltage(sc->reg,
opp->uvolt_min,
opp->uvolt_max);
@ -201,7 +216,7 @@ cpufreq_dt_set(device_t dev, const struct cf_setting *set)
}
DEBUG(dev, "Setting clk to %ju\n", opp->freq);
error = clk_set_freq(sc->clk, opp->freq, 0);
error = clk_set_freq(sc->clk, opp->freq, CLK_SET_ROUND_DOWN);
if (error != 0) {
DEBUG(dev, "Failed, backout\n");
/* Restore previous voltage (best effort) */
@ -211,7 +226,9 @@ cpufreq_dt_set(device_t dev, const struct cf_setting *set)
return (ENXIO);
}
if (copp->uvolt_target > opp->uvolt_target) {
if (uvolt > opp->uvolt_target) {
DEBUG(dev, "Changing regulator from %u to %u\n",
uvolt, opp->uvolt_target);
error = regulator_set_voltage(sc->reg,
opp->uvolt_min,
opp->uvolt_max);
@ -219,8 +236,7 @@ cpufreq_dt_set(device_t dev, const struct cf_setting *set)
DEBUG(dev, "Failed to switch regulator to %d\n",
opp->uvolt_target);
/* Restore previous CPU frequency (best effort) */
(void)clk_set_freq(sc->clk,
copp->freq, 0);
(void)clk_set_freq(sc->clk, copp->freq, 0);
return (ENXIO);
}
}
@ -277,7 +293,8 @@ cpufreq_dt_identify(driver_t *driver, device_t parent)
/* The cpu@0 node must have the following properties */
if (!OF_hasprop(node, "clocks") ||
!OF_hasprop(node, "cpu-supply"))
(!OF_hasprop(node, "cpu-supply") &&
!OF_hasprop(node, "cpu0-supply")))
return;
if (!OF_hasprop(node, "operating-points") &&
@ -299,7 +316,9 @@ cpufreq_dt_probe(device_t dev)
node = ofw_bus_get_node(device_get_parent(dev));
if (!OF_hasprop(node, "clocks") ||
!OF_hasprop(node, "cpu-supply"))
(!OF_hasprop(node, "cpu-supply") &&
!OF_hasprop(node, "cpu0-supply")))
return (ENXIO);
if (!OF_hasprop(node, "operating-points") &&
@ -439,9 +458,12 @@ cpufreq_dt_attach(device_t dev)
if (regulator_get_by_ofw_property(dev, node,
"cpu-supply", &sc->reg) != 0) {
device_printf(dev, "no regulator for %s\n",
ofw_bus_get_name(device_get_parent(dev)));
return (ENXIO);
if (regulator_get_by_ofw_property(dev, node,
"cpu0-supply", &sc->reg) != 0) {
device_printf(dev, "no regulator for %s\n",
ofw_bus_get_name(device_get_parent(dev)));
return (ENXIO);
}
}
if (clk_get_by_ofw_index(dev, node, 0, &sc->clk) != 0) {