Index: sys/dev/cpufreq/cpufreq_dt.c =================================================================== --- sys/dev/cpufreq/cpufreq_dt.c +++ sys/dev/cpufreq/cpufreq_dt.c @@ -81,6 +81,9 @@ struct cpufreq_dt_opp *opp; ssize_t nopp; + /* if true, need a regulator and voltage table entries */ + bool require_regulator; + int cpu; cpuset_t cpus; }; @@ -181,23 +184,31 @@ 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); + + /* + * Only do the regulator work if it's required. + */ + if (sc->require_regulator) { + /* 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; } - uvolt = copp->uvolt_target; + } else { + uvolt = 0; } opp = cpufreq_dt_find_opp(sc->dev, set->freq * 1000000); @@ -209,7 +220,7 @@ DPRINTF(sc->dev, "Target freq %ju, , uvolt: %d\n", opp->freq, opp->uvolt_target); - if (uvolt < opp->uvolt_target) { + if ((sc->require_regulator) && (uvolt < opp->uvolt_target)) { DPRINTF(dev, "Changing regulator from %u to %u\n", uvolt, opp->uvolt_target); error = regulator_set_voltage(sc->reg, @@ -226,13 +237,14 @@ if (error != 0) { DPRINTF(dev, "Failed, backout\n"); /* Restore previous voltage (best effort) */ - error = regulator_set_voltage(sc->reg, - copp->uvolt_min, - copp->uvolt_max); + if (sc->require_regulator) + error = regulator_set_voltage(sc->reg, + copp->uvolt_min, + copp->uvolt_max); return (ENXIO); } - if (uvolt > opp->uvolt_target) { + if ((sc->require_regulator) && (uvolt > opp->uvolt_target)) { DPRINTF(dev, "Changing regulator from %u to %u\n", uvolt, opp->uvolt_target); error = regulator_set_voltage(sc->reg, @@ -297,9 +309,7 @@ node = ofw_bus_get_node(parent); /* The cpu@0 node must have the following properties */ - if (!OF_hasprop(node, "clocks") || - (!OF_hasprop(node, "cpu-supply") && - !OF_hasprop(node, "cpu0-supply"))) + if (!OF_hasprop(node, "clocks")) return; if (!OF_hasprop(node, "operating-points") && @@ -321,10 +331,11 @@ node = ofw_bus_get_node(device_get_parent(dev)); - if (!OF_hasprop(node, "clocks") || - (!OF_hasprop(node, "cpu-supply") && - !OF_hasprop(node, "cpu0-supply"))) - + /* + * Note - supply isn't required here for probe; we'll check + * it out in more detail during attach. + */ + if (!OF_hasprop(node, "clocks")) return (ENXIO); if (!OF_hasprop(node, "operating-points") && @@ -377,6 +388,10 @@ uint32_t *volts, lat; int nvolt, i; + /* + * operating-points-v2 does not require the voltage entries + * and a regulator. So, it's OK if they're not there. + */ if (OF_getencprop(node, "operating-points-v2", &opp_xref, sizeof(opp_xref)) == -1) { device_printf(sc->dev, "Cannot get xref to oppv2 table\n"); @@ -419,24 +434,31 @@ if (OF_hasprop(opp_table, "opp-suspend")) sc->opp[i].opp_suspend = true; - nvolt = OF_getencprop_alloc_multi(opp_table, "opp-microvolt", - sizeof(*volts), (void **)&volts); - if (nvolt == 1) { - sc->opp[i].uvolt_target = volts[0]; - sc->opp[i].uvolt_min = volts[0]; - sc->opp[i].uvolt_max = volts[0]; - } else if (nvolt == 3) { - sc->opp[i].uvolt_target = volts[0]; - sc->opp[i].uvolt_min = volts[1]; - sc->opp[i].uvolt_max = volts[2]; - } else { - device_printf(sc->dev, - "Wrong count of opp-microvolt property\n"); + if (sc->require_regulator) { + nvolt = OF_getencprop_alloc_multi(opp_table, + "opp-microvolt", sizeof(*volts), (void **)&volts); + if (nvolt == 1) { + sc->opp[i].uvolt_target = volts[0]; + sc->opp[i].uvolt_min = volts[0]; + sc->opp[i].uvolt_max = volts[0]; + } else if (nvolt == 3) { + sc->opp[i].uvolt_target = volts[0]; + sc->opp[i].uvolt_min = volts[1]; + sc->opp[i].uvolt_max = volts[2]; + } else { + device_printf(sc->dev, + "Wrong count of opp-microvolt property\n"); + OF_prop_free(volts); + free(sc->opp, M_DEVBUF); + return (ENXIO); + } OF_prop_free(volts); - free(sc->opp, M_DEVBUF); - return (ENXIO); + } else { + /* No regulator required; don't add anything */ + sc->opp[i].uvolt_target = 0; + sc->opp[i].uvolt_min = 0; + sc->opp[i].uvolt_max = 0; } - OF_prop_free(volts); if (bootverbose) device_printf(sc->dev, "%ju.%03ju Mhz (%u uV)\n", @@ -458,6 +480,7 @@ int rv = 0; char device_type[16]; enum opp_version version; + bool found_regulator = false; sc = device_get_softc(dev); sc->dev = dev; @@ -470,20 +493,55 @@ return (ENXIO); } - if (regulator_get_by_ofw_property(dev, node, - "cpu-supply", &sc->reg) != 0) { - 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); - } + /* + * Cache if we have the regulator supply but don't error out + * quite yet. If it's operating-points-v2 then regulator + * and voltage entries are optional. + */ + if (regulator_get_by_ofw_property(dev, node, "cpu-supply", + &sc->reg) == 0) + found_regulator = true; + else if (regulator_get_by_ofw_property(dev, node, "cpu0-supply", + &sc->reg) == 0) + found_regulator = true; + else + found_regulator = false; + + /* + * Determine which operating mode we're in. Error out if we expect + * a regulator but we're not getting it. + */ + if (OF_hasprop(node, "operating-points")) { + version = OPP_V1; + } else if (OF_hasprop(node, "operating-points-v2")) { + version = OPP_V2; + } else { + device_printf(dev, "didn't find a valid operating-points or v2 node\n"); + if (found_regulator) + regulator_release(sc->reg); + return (ENXIO); } + /* + * Now, we only enforce needing a regulator for v1. + */ + if ((version == OPP_V1) && (found_regulator == false)) { + device_printf(dev, "no regulator for %s\n", + ofw_bus_get_name(device_get_parent(dev))); + return (ENXIO); + } + + /* + * Set whether we need voltage table entries based on whether + * we found a regulator or not. + */ + sc->require_regulator = found_regulator; + if (clk_get_by_ofw_index(dev, node, 0, &sc->clk) != 0) { device_printf(dev, "no clock for %s\n", ofw_bus_get_name(device_get_parent(dev))); - regulator_release(sc->reg); + if (found_regulator) + regulator_release(sc->reg); return (ENXIO); }