drm/panfrost: Simplify devfreq utilisation tracking
[linux-2.6-microblaze.git] / drivers / gpu / drm / panfrost / panfrost_devfreq.c
index 12ff77d..4c4e8a3 100644 (file)
 #include "panfrost_gpu.h"
 #include "panfrost_regs.h"
 
-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev, int slot);
+static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev);
 
 static int panfrost_devfreq_target(struct device *dev, unsigned long *freq,
                                   u32 flags)
 {
-       struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev));
-       struct dev_pm_opp *opp;
-       unsigned long old_clk_rate = pfdev->devfreq.cur_freq;
-       unsigned long target_volt, target_rate;
+       struct panfrost_device *pfdev = dev_get_drvdata(dev);
        int err;
 
-       opp = devfreq_recommended_opp(dev, freq, flags);
-       if (IS_ERR(opp))
-               return PTR_ERR(opp);
-
-       target_rate = dev_pm_opp_get_freq(opp);
-       target_volt = dev_pm_opp_get_voltage(opp);
-       dev_pm_opp_put(opp);
-
-       if (old_clk_rate == target_rate)
-               return 0;
-
-       /*
-        * If frequency scaling from low to high, adjust voltage first.
-        * If frequency scaling from high to low, adjust frequency first.
-        */
-       if (old_clk_rate < target_rate) {
-               err = regulator_set_voltage(pfdev->regulator, target_volt,
-                                           target_volt);
-               if (err) {
-                       dev_err(dev, "Cannot set voltage %lu uV\n",
-                               target_volt);
-                       return err;
-               }
-       }
-
-       err = clk_set_rate(pfdev->clock, target_rate);
-       if (err) {
-               dev_err(dev, "Cannot set frequency %lu (%d)\n", target_rate,
-                       err);
-               regulator_set_voltage(pfdev->regulator, pfdev->devfreq.cur_volt,
-                                     pfdev->devfreq.cur_volt);
+       err = dev_pm_opp_set_rate(dev, *freq);
+       if (err)
                return err;
-       }
 
-       if (old_clk_rate > target_rate) {
-               err = regulator_set_voltage(pfdev->regulator, target_volt,
-                                           target_volt);
-               if (err)
-                       dev_err(dev, "Cannot set voltage %lu uV\n", target_volt);
-       }
-
-       pfdev->devfreq.cur_freq = target_rate;
-       pfdev->devfreq.cur_volt = target_volt;
+       *freq = clk_get_rate(pfdev->clock);
 
        return 0;
 }
 
 static void panfrost_devfreq_reset(struct panfrost_device *pfdev)
 {
-       ktime_t now = ktime_get();
-       int i;
-
-       for (i = 0; i < NUM_JOB_SLOTS; i++) {
-               pfdev->devfreq.slot[i].busy_time = 0;
-               pfdev->devfreq.slot[i].idle_time = 0;
-               pfdev->devfreq.slot[i].time_last_update = now;
-       }
+       pfdev->devfreq.busy_time = 0;
+       pfdev->devfreq.idle_time = 0;
+       pfdev->devfreq.time_last_update = ktime_get();
 }
 
 static int panfrost_devfreq_get_dev_status(struct device *dev,
                                           struct devfreq_dev_status *status)
 {
-       struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev));
-       int i;
+       struct panfrost_device *pfdev = dev_get_drvdata(dev);
 
-       for (i = 0; i < NUM_JOB_SLOTS; i++) {
-               panfrost_devfreq_update_utilization(pfdev, i);
-       }
+       panfrost_devfreq_update_utilization(pfdev);
 
        status->current_frequency = clk_get_rate(pfdev->clock);
-       status->total_time = ktime_to_ns(ktime_add(pfdev->devfreq.slot[0].busy_time,
-                                                  pfdev->devfreq.slot[0].idle_time));
+       status->total_time = ktime_to_ns(ktime_add(pfdev->devfreq.busy_time,
+                                                  pfdev->devfreq.idle_time));
 
-       status->busy_time = 0;
-       for (i = 0; i < NUM_JOB_SLOTS; i++) {
-               status->busy_time += ktime_to_ns(pfdev->devfreq.slot[i].busy_time);
-       }
-
-       /* We're scheduling only to one core atm, so don't divide for now */
-       /* status->busy_time /= NUM_JOB_SLOTS; */
+       status->busy_time = ktime_to_ns(pfdev->devfreq.busy_time);
 
        panfrost_devfreq_reset(pfdev);
 
@@ -119,7 +64,7 @@ static int panfrost_devfreq_get_cur_freq(struct device *dev, unsigned long *freq
 {
        struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev));
 
-       *freq = pfdev->devfreq.cur_freq;
+       *freq = clk_get_rate(pfdev->clock);
 
        return 0;
 }
@@ -135,6 +80,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
 {
        int ret;
        struct dev_pm_opp *opp;
+       unsigned long cur_freq;
 
        ret = dev_pm_opp_of_add_table(&pfdev->pdev->dev);
        if (ret == -ENODEV) /* Optional, continue without devfreq */
@@ -144,13 +90,13 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
 
        panfrost_devfreq_reset(pfdev);
 
-       pfdev->devfreq.cur_freq = clk_get_rate(pfdev->clock);
+       cur_freq = clk_get_rate(pfdev->clock);
 
-       opp = devfreq_recommended_opp(&pfdev->pdev->dev, &pfdev->devfreq.cur_freq, 0);
+       opp = devfreq_recommended_opp(&pfdev->pdev->dev, &cur_freq, 0);
        if (IS_ERR(opp))
                return PTR_ERR(opp);
 
-       panfrost_devfreq_profile.initial_freq = pfdev->devfreq.cur_freq;
+       panfrost_devfreq_profile.initial_freq = cur_freq;
        dev_pm_opp_put(opp);
 
        pfdev->devfreq.devfreq = devm_devfreq_add_device(&pfdev->pdev->dev,
@@ -174,14 +120,10 @@ void panfrost_devfreq_fini(struct panfrost_device *pfdev)
 
 void panfrost_devfreq_resume(struct panfrost_device *pfdev)
 {
-       int i;
-
        if (!pfdev->devfreq.devfreq)
                return;
 
        panfrost_devfreq_reset(pfdev);
-       for (i = 0; i < NUM_JOB_SLOTS; i++)
-               pfdev->devfreq.slot[i].busy = false;
 
        devfreq_resume_device(pfdev->devfreq.devfreq);
 }
@@ -194,9 +136,8 @@ void panfrost_devfreq_suspend(struct panfrost_device *pfdev)
        devfreq_suspend_device(pfdev->devfreq.devfreq);
 }
 
-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev, int slot)
+static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev)
 {
-       struct panfrost_devfreq_slot *devfreq_slot = &pfdev->devfreq.slot[slot];
        ktime_t now;
        ktime_t last;
 
@@ -204,22 +145,27 @@ static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev, i
                return;
 
        now = ktime_get();
-       last = pfdev->devfreq.slot[slot].time_last_update;
+       last = pfdev->devfreq.time_last_update;
 
-       /* If we last recorded a transition to busy, we have been idle since */
-       if (devfreq_slot->busy)
-               pfdev->devfreq.slot[slot].busy_time += ktime_sub(now, last);
+       if (atomic_read(&pfdev->devfreq.busy_count) > 0)
+               pfdev->devfreq.busy_time += ktime_sub(now, last);
        else
-               pfdev->devfreq.slot[slot].idle_time += ktime_sub(now, last);
+               pfdev->devfreq.idle_time += ktime_sub(now, last);
 
-       pfdev->devfreq.slot[slot].time_last_update = now;
+       pfdev->devfreq.time_last_update = now;
+}
+
+void panfrost_devfreq_record_busy(struct panfrost_device *pfdev)
+{
+       panfrost_devfreq_update_utilization(pfdev);
+       atomic_inc(&pfdev->devfreq.busy_count);
 }
 
-/* The job scheduler is expected to call this at every transition busy <-> idle */
-void panfrost_devfreq_record_transition(struct panfrost_device *pfdev, int slot)
+void panfrost_devfreq_record_idle(struct panfrost_device *pfdev)
 {
-       struct panfrost_devfreq_slot *devfreq_slot = &pfdev->devfreq.slot[slot];
+       int count;
 
-       panfrost_devfreq_update_utilization(pfdev, slot);
-       devfreq_slot->busy = !devfreq_slot->busy;
+       panfrost_devfreq_update_utilization(pfdev);
+       count = atomic_dec_if_positive(&pfdev->devfreq.busy_count);
+       WARN_ON(count < 0);
 }