Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/cpufreq/cpufreq_dt.c
Show First 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
#include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
#include <dev/extres/clk/clk.h> | #include <dev/extres/clk/clk.h> | ||||
#include <dev/extres/regulator/regulator.h> | #include <dev/extres/regulator/regulator.h> | ||||
#include "cpufreq_if.h" | #include "cpufreq_if.h" | ||||
#if 0 | #if 0 | ||||
#define DEBUG(dev, msg...) device_printf(dev, "cpufreq_dt: " msg); | #define DPRINTF(dev, msg...) device_printf(dev, "cpufreq_dt: " msg); | ||||
#else | #else | ||||
#define DEBUG(dev, msg...) | #define DPRINTF(dev, msg...) | ||||
#endif | #endif | ||||
enum opp_version { | enum opp_version { | ||||
OPP_V1 = 1, | OPP_V1 = 1, | ||||
OPP_V2, | OPP_V2, | ||||
}; | }; | ||||
struct cpufreq_dt_opp { | struct cpufreq_dt_opp { | ||||
Show All 39 Lines | |||||
static const struct cpufreq_dt_opp * | static const struct cpufreq_dt_opp * | ||||
cpufreq_dt_find_opp(device_t dev, uint64_t freq) | cpufreq_dt_find_opp(device_t dev, uint64_t freq) | ||||
{ | { | ||||
struct cpufreq_dt_softc *sc; | struct cpufreq_dt_softc *sc; | ||||
ssize_t n; | ssize_t n; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
DEBUG(dev, "Looking for freq %ju\n", freq); | DPRINTF(dev, "Looking for freq %ju\n", freq); | ||||
for (n = 0; n < sc->nopp; n++) | for (n = 0; n < sc->nopp; n++) | ||||
if (CPUFREQ_CMP(sc->opp[n].freq, freq)) | if (CPUFREQ_CMP(sc->opp[n].freq, freq)) | ||||
return (&sc->opp[n]); | return (&sc->opp[n]); | ||||
DEBUG(dev, "Couldn't find one\n"); | DPRINTF(dev, "Couldn't find one\n"); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
static void | static void | ||||
cpufreq_dt_opp_to_setting(device_t dev, const struct cpufreq_dt_opp *opp, | cpufreq_dt_opp_to_setting(device_t dev, const struct cpufreq_dt_opp *opp, | ||||
struct cf_setting *set) | struct cf_setting *set) | ||||
{ | { | ||||
struct cpufreq_dt_softc *sc; | struct cpufreq_dt_softc *sc; | ||||
Show All 12 Lines | |||||
cpufreq_dt_get(device_t dev, struct cf_setting *set) | cpufreq_dt_get(device_t dev, struct cf_setting *set) | ||||
{ | { | ||||
struct cpufreq_dt_softc *sc; | struct cpufreq_dt_softc *sc; | ||||
const struct cpufreq_dt_opp *opp; | const struct cpufreq_dt_opp *opp; | ||||
uint64_t freq; | uint64_t freq; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
DEBUG(dev, "cpufreq_dt_get\n"); | DPRINTF(dev, "cpufreq_dt_get\n"); | ||||
if (clk_get_freq(sc->clk, &freq) != 0) | if (clk_get_freq(sc->clk, &freq) != 0) | ||||
return (ENXIO); | return (ENXIO); | ||||
opp = cpufreq_dt_find_opp(dev, freq); | opp = cpufreq_dt_find_opp(dev, freq); | ||||
if (opp == NULL) { | if (opp == NULL) { | ||||
device_printf(dev, "Can't find the current freq in opp\n"); | device_printf(dev, "Can't find the current freq in opp\n"); | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
cpufreq_dt_opp_to_setting(dev, opp, set); | cpufreq_dt_opp_to_setting(dev, opp, set); | ||||
DEBUG(dev, "Current freq %dMhz\n", set->freq); | DPRINTF(dev, "Current freq %dMhz\n", set->freq); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
cpufreq_dt_set(device_t dev, const struct cf_setting *set) | cpufreq_dt_set(device_t dev, const struct cf_setting *set) | ||||
{ | { | ||||
struct cpufreq_dt_softc *sc; | struct cpufreq_dt_softc *sc; | ||||
const struct cpufreq_dt_opp *opp, *copp; | const struct cpufreq_dt_opp *opp, *copp; | ||||
uint64_t freq; | uint64_t freq; | ||||
int uvolt, error; | int uvolt, error; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
DEBUG(dev, "Working on cpu %d\n", sc->cpu); | DPRINTF(dev, "Working on cpu %d\n", sc->cpu); | ||||
DEBUG(dev, "We have %d cpu on this dev\n", CPU_COUNT(&sc->cpus)); | DPRINTF(dev, "We have %d cpu on this dev\n", CPU_COUNT(&sc->cpus)); | ||||
if (!CPU_ISSET(sc->cpu, &sc->cpus)) { | if (!CPU_ISSET(sc->cpu, &sc->cpus)) { | ||||
DEBUG(dev, "Not for this CPU\n"); | DPRINTF(dev, "Not for this CPU\n"); | ||||
return (0); | return (0); | ||||
} | } | ||||
if (clk_get_freq(sc->clk, &freq) != 0) { | if (clk_get_freq(sc->clk, &freq) != 0) { | ||||
device_printf(dev, "Can't get current clk freq\n"); | device_printf(dev, "Can't get current clk freq\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
/* Try to get current valtage by using regulator first. */ | /* Try to get current valtage by using regulator first. */ | ||||
Show All 15 Lines | if (error != 0) { | ||||
uvolt = copp->uvolt_target; | uvolt = copp->uvolt_target; | ||||
} | } | ||||
opp = cpufreq_dt_find_opp(sc->dev, set->freq * 1000000); | opp = cpufreq_dt_find_opp(sc->dev, set->freq * 1000000); | ||||
if (opp == NULL) { | if (opp == NULL) { | ||||
device_printf(dev, "Couldn't find an opp for this freq\n"); | device_printf(dev, "Couldn't find an opp for this freq\n"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
DEBUG(sc->dev, "Current freq %ju, uvolt: %d\n", freq, uvolt); | DPRINTF(sc->dev, "Current freq %ju, uvolt: %d\n", freq, uvolt); | ||||
DEBUG(sc->dev, "Target freq %ju, , uvolt: %d\n", | DPRINTF(sc->dev, "Target freq %ju, , uvolt: %d\n", | ||||
opp->freq, opp->uvolt_target); | opp->freq, opp->uvolt_target); | ||||
if (uvolt < opp->uvolt_target) { | if (uvolt < opp->uvolt_target) { | ||||
DEBUG(dev, "Changing regulator from %u to %u\n", | DPRINTF(dev, "Changing regulator from %u to %u\n", | ||||
uvolt, opp->uvolt_target); | uvolt, opp->uvolt_target); | ||||
error = regulator_set_voltage(sc->reg, | error = regulator_set_voltage(sc->reg, | ||||
opp->uvolt_min, | opp->uvolt_min, | ||||
opp->uvolt_max); | opp->uvolt_max); | ||||
if (error != 0) { | if (error != 0) { | ||||
DEBUG(dev, "Failed, backout\n"); | DPRINTF(dev, "Failed, backout\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
} | } | ||||
DEBUG(dev, "Setting clk to %ju\n", opp->freq); | DPRINTF(dev, "Setting clk to %ju\n", opp->freq); | ||||
error = clk_set_freq(sc->clk, opp->freq, CLK_SET_ROUND_DOWN); | error = clk_set_freq(sc->clk, opp->freq, CLK_SET_ROUND_DOWN); | ||||
if (error != 0) { | if (error != 0) { | ||||
DEBUG(dev, "Failed, backout\n"); | DPRINTF(dev, "Failed, backout\n"); | ||||
/* Restore previous voltage (best effort) */ | /* Restore previous voltage (best effort) */ | ||||
error = regulator_set_voltage(sc->reg, | error = regulator_set_voltage(sc->reg, | ||||
copp->uvolt_min, | copp->uvolt_min, | ||||
copp->uvolt_max); | copp->uvolt_max); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
if (uvolt > opp->uvolt_target) { | if (uvolt > opp->uvolt_target) { | ||||
DEBUG(dev, "Changing regulator from %u to %u\n", | DPRINTF(dev, "Changing regulator from %u to %u\n", | ||||
uvolt, opp->uvolt_target); | uvolt, opp->uvolt_target); | ||||
error = regulator_set_voltage(sc->reg, | error = regulator_set_voltage(sc->reg, | ||||
opp->uvolt_min, | opp->uvolt_min, | ||||
opp->uvolt_max); | opp->uvolt_max); | ||||
if (error != 0) { | if (error != 0) { | ||||
DEBUG(dev, "Failed to switch regulator to %d\n", | DPRINTF(dev, "Failed to switch regulator to %d\n", | ||||
opp->uvolt_target); | opp->uvolt_target); | ||||
/* Restore previous CPU frequency (best effort) */ | /* 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); | return (ENXIO); | ||||
} | } | ||||
} | } | ||||
if (clk_get_freq(sc->clk, &freq) == 0) | if (clk_get_freq(sc->clk, &freq) == 0) | ||||
Show All 14 Lines | |||||
} | } | ||||
static int | static int | ||||
cpufreq_dt_settings(device_t dev, struct cf_setting *sets, int *count) | cpufreq_dt_settings(device_t dev, struct cf_setting *sets, int *count) | ||||
{ | { | ||||
struct cpufreq_dt_softc *sc; | struct cpufreq_dt_softc *sc; | ||||
ssize_t n; | ssize_t n; | ||||
DEBUG(dev, "cpufreq_dt_settings\n"); | DPRINTF(dev, "cpufreq_dt_settings\n"); | ||||
if (sets == NULL || count == NULL) | if (sets == NULL || count == NULL) | ||||
return (EINVAL); | return (EINVAL); | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
if (*count < sc->nopp) { | if (*count < sc->nopp) { | ||||
*count = (int)sc->nopp; | *count = (int)sc->nopp; | ||||
return (E2BIG); | return (E2BIG); | ||||
▲ Show 20 Lines • Show All 177 Lines • ▼ Show 20 Lines | cpufreq_dt_attach(device_t dev) | ||||
char device_type[16]; | char device_type[16]; | ||||
enum opp_version version; | enum opp_version version; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sc->dev = dev; | sc->dev = dev; | ||||
node = ofw_bus_get_node(device_get_parent(dev)); | node = ofw_bus_get_node(device_get_parent(dev)); | ||||
sc->cpu = device_get_unit(device_get_parent(dev)); | sc->cpu = device_get_unit(device_get_parent(dev)); | ||||
DEBUG(dev, "cpu=%d\n", sc->cpu); | DPRINTF(dev, "cpu=%d\n", sc->cpu); | ||||
if (sc->cpu >= mp_ncpus) { | if (sc->cpu >= mp_ncpus) { | ||||
device_printf(dev, "Not attaching as cpu is not present\n"); | device_printf(dev, "Not attaching as cpu is not present\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
if (regulator_get_by_ofw_property(dev, node, | if (regulator_get_by_ofw_property(dev, node, | ||||
"cpu-supply", &sc->reg) != 0) { | "cpu-supply", &sc->reg) != 0) { | ||||
if (regulator_get_by_ofw_property(dev, node, | if (regulator_get_by_ofw_property(dev, node, | ||||
Show All 37 Lines | cpufreq_dt_attach(device_t dev) | ||||
CPU_ZERO(&sc->cpus); | CPU_ZERO(&sc->cpus); | ||||
cnode = OF_parent(node); | cnode = OF_parent(node); | ||||
for (cpu = 0, cnode = OF_child(cnode); cnode > 0; cnode = OF_peer(cnode)) { | for (cpu = 0, cnode = OF_child(cnode); cnode > 0; cnode = OF_peer(cnode)) { | ||||
if (OF_getprop(cnode, "device_type", device_type, sizeof(device_type)) <= 0) | if (OF_getprop(cnode, "device_type", device_type, sizeof(device_type)) <= 0) | ||||
continue; | continue; | ||||
if (strcmp(device_type, "cpu") != 0) | if (strcmp(device_type, "cpu") != 0) | ||||
continue; | continue; | ||||
if (cpu == sc->cpu) { | if (cpu == sc->cpu) { | ||||
DEBUG(dev, "Skipping our cpu\n"); | DPRINTF(dev, "Skipping our cpu\n"); | ||||
CPU_SET(cpu, &sc->cpus); | CPU_SET(cpu, &sc->cpus); | ||||
cpu++; | cpu++; | ||||
continue; | continue; | ||||
} | } | ||||
DEBUG(dev, "Testing CPU %d\n", cpu); | DPRINTF(dev, "Testing CPU %d\n", cpu); | ||||
copp = -1; | copp = -1; | ||||
if (version == OPP_V1) | if (version == OPP_V1) | ||||
OF_getencprop(cnode, "operating-points", &copp, | OF_getencprop(cnode, "operating-points", &copp, | ||||
sizeof(copp)); | sizeof(copp)); | ||||
else if (version == OPP_V2) | else if (version == OPP_V2) | ||||
OF_getencprop(cnode, "operating-points-v2", | OF_getencprop(cnode, "operating-points-v2", | ||||
&copp, sizeof(copp)); | &copp, sizeof(copp)); | ||||
if (opp == copp) { | if (opp == copp) { | ||||
DEBUG(dev, "CPU %d is using the same opp as this one (%d)\n", cpu, sc->cpu); | DPRINTF(dev, "CPU %d is using the same opp as this one (%d)\n", | ||||
cpu, sc->cpu); | |||||
CPU_SET(cpu, &sc->cpus); | CPU_SET(cpu, &sc->cpus); | ||||
} | } | ||||
cpu++; | cpu++; | ||||
} | } | ||||
if (clk_get_freq(sc->clk, &freq) == 0) | if (clk_get_freq(sc->clk, &freq) == 0) | ||||
cpufreq_dt_notify(dev, freq); | cpufreq_dt_notify(dev, freq); | ||||
Show All 31 Lines |