Author: mmel
Date: Tue Mar 19 14:34:53 2019
New Revision: 345297
URL: https://svnweb.freebsd.org/changeset/base/345297

Log:
  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

Modified:
  head/sys/dev/cpufreq/cpufreq_dt.c

Modified: head/sys/dev/cpufreq/cpufreq_dt.c
==============================================================================
--- head/sys/dev/cpufreq/cpufreq_dt.c   Tue Mar 19 14:32:54 2019        
(r345296)
+++ head/sys/dev/cpufreq/cpufreq_dt.c   Tue Mar 19 14:34:53 2019        
(r345297)
@@ -166,7 +166,7 @@ cpufreq_dt_set(device_t dev, const struct cf_setting *
        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 *
                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 *
        }
 
        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 *
                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 *
                        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) {
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to