Implement routines to estimate GPU busy time and fetching the
current frequency for the polling interval. This is required by
the devfreq framework which recommends a frequency change if needed.
The driver code then tries to set this new frequency on the GPU by
sending an Out Of Band(OOB) request to the GMU.

Signed-off-by: Sharat Masetty <smase...@codeaurora.org>
---
 drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 39 +++++++++++++++++++++++++++++++----
 drivers/gpu/drm/msm/adreno/a6xx_gmu.h |  2 ++
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 27 ++++++++++++++++++++++++
 drivers/gpu/drm/msm/adreno/a6xx_gpu.h |  2 ++
 4 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c 
b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index f6634c0..3a7b899 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -67,7 +67,7 @@ static bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu)
                A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF));
 }
 
-static int a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index)
+static int __a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index)
 {
        gmu_write(gmu, REG_A6XX_GMU_DCVS_ACK_OPTION, 0);
 
@@ -84,7 +84,38 @@ static int a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index)
        a6xx_gmu_set_oob(gmu, GMU_OOB_DCVS_SET);
        a6xx_gmu_clear_oob(gmu, GMU_OOB_DCVS_SET);
 
-       return gmu_read(gmu, REG_A6XX_GMU_DCVS_RETURN);
+       if (gmu_read(gmu, REG_A6XX_GMU_DCVS_RETURN) != 0)
+               return -EINVAL;
+
+       gmu->freq = gmu->gpu_freqs[index];
+
+       return 0;
+}
+
+int a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+       struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
+       u32 perf_index = 0;
+
+       if (freq == gmu->freq)
+               return 0;
+
+       for (perf_index = 0; perf_index < gmu->nr_gpu_freqs - 1; perf_index++)
+               if (freq == gmu->gpu_freqs[perf_index])
+                       break;
+
+       return  __a6xx_gmu_set_freq(gmu, perf_index);
+}
+
+unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+       struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
+
+       return  gmu->freq;
 }
 
 static bool a6xx_gmu_check_idle_level(struct a6xx_gmu *gmu)
@@ -630,7 +661,7 @@ int a6xx_gmu_reset(struct a6xx_gpu *a6xx_gpu)
                ret = a6xx_hfi_start(gmu, GMU_COLD_BOOT);
 
        /* Set the GPU back to the highest power frequency */
-       a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1);
+       __a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1);
 
 out:
        if (ret)
@@ -671,7 +702,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
        ret = a6xx_hfi_start(gmu, status);
 
        /* Set the GPU to the highest power frequency */
-       a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1);
+       __a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1);
 
 out:
        /* Make sure to turn off the boot OOB request on error */
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h 
b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
index 09fd3a7..13b064f 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
@@ -77,6 +77,8 @@ struct a6xx_gmu {
        unsigned long gmu_freqs[4];
        u32 cx_arc_votes[4];
 
+       unsigned long freq;
+
        struct a6xx_hfi_queue queues[2];
 
        struct tasklet_struct hfi_tasklet;
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c 
b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 3429d33a..af90706 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -7,6 +7,8 @@
 #include "a6xx_gpu.h"
 #include "a6xx_gmu.xml.h"
 
+#include <linux/devfreq.h>
+
 static inline bool _a6xx_check_idle(struct msm_gpu *gpu)
 {
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@@ -682,6 +684,8 @@ static int a6xx_pm_resume(struct msm_gpu *gpu)
 
        gpu->needs_hw_init = true;
 
+       msm_gpu_resume_devfreq(gpu);
+
        return ret;
 }
 
@@ -690,6 +694,8 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu)
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
        struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
 
+       devfreq_suspend_device(gpu->devfreq.devfreq);
+
        /*
         * Make sure the GMU is idle before continuing (because some transitions
         * may use VBIF
@@ -753,6 +759,24 @@ static void a6xx_destroy(struct msm_gpu *gpu)
        kfree(a6xx_gpu);
 }
 
+static unsigned long a6xx_gpu_busy(struct msm_gpu *gpu)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+       u64 busy_cycles;
+       unsigned long busy_time;
+
+       busy_cycles = gmu_read64(&a6xx_gpu->gmu,
+                       REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L,
+                       REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H);
+
+       busy_time = ((busy_cycles - gpu->devfreq.busy_cycles) * 10) / 192;
+
+       gpu->devfreq.busy_cycles = busy_cycles;
+
+       return busy_time;
+}
+
 static const struct adreno_gpu_funcs funcs = {
        .base = {
                .get_param = adreno_get_param,
@@ -768,6 +792,9 @@ static void a6xx_destroy(struct msm_gpu *gpu)
 #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
                .show = a6xx_show,
 #endif
+               .gpu_busy = a6xx_gpu_busy,
+               .gpu_get_freq = a6xx_gmu_get_freq,
+               .gpu_set_freq = a6xx_gmu_set_freq,
        },
        .get_timestamp = a6xx_get_timestamp,
 };
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h 
b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
index 32c2501..f236767 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
@@ -56,5 +56,7 @@ struct a6xx_gpu {
 
 int a6xx_gmu_probe(struct a6xx_gpu *a6xx_gpu, struct device_node *node, struct 
platform_device *gpu_pdev);
 void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu);
+int a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq);
+unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu);
 
 #endif /* __A6XX_GPU_H__ */
-- 
1.9.1

_______________________________________________
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno

Reply via email to