This patch adds support to parse the OPP tables attached the GPU device,
the main opp table and the DDR bandwidth opp table. Additionally, vote
for the GPU->DDR bandwidth when setting the GPU frequency by querying
the linked DDR BW opp to the GPU opp.

Signed-off-by: Sharat Masetty <smase...@codeaurora.org>
---
 drivers/gpu/drm/msm/adreno/a6xx_gmu.c   | 41 ++++++++++++++++++++++++++----
 drivers/gpu/drm/msm/adreno/adreno_gpu.c | 44 +++++++++++++++++++++++++++++----
 drivers/gpu/drm/msm/msm_gpu.h           |  9 +++++++
 3 files changed, 84 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c 
b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 748cd37..489d9b6 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -100,6 +100,40 @@ bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu)
                A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF));
 }

+void a6xx_gmu_set_icc_vote(struct msm_gpu *gpu, unsigned long gpu_freq)
+{
+       struct dev_pm_opp *gpu_opp, *ddr_opp;
+       struct opp_table **tables = gpu->opp_tables;
+       unsigned long peak_bw;
+
+       if (!gpu->opp_tables[GPU_DDR_OPP_TABLE_INDEX])
+               goto done;
+
+       gpu_opp = dev_pm_opp_find_freq_exact(&gpu->pdev->dev, gpu_freq, true);
+       if (IS_ERR_OR_NULL(gpu_opp))
+               goto done;
+
+       ddr_opp = dev_pm_opp_xlate_required_opp(tables[GPU_OPP_TABLE_INDEX],
+                                           tables[GPU_DDR_OPP_TABLE_INDEX],
+                                           gpu_opp);
+       dev_pm_opp_put(gpu_opp);
+
+       if (IS_ERR_OR_NULL(ddr_opp))
+               goto done;
+
+       peak_bw = dev_pm_opp_get_bw(ddr_opp, NULL);
+       dev_pm_opp_put(ddr_opp);
+
+       icc_set_bw(gpu->icc_path, 0, peak_bw);
+       return;
+done:
+       /*
+        * If there is a problem, for now leave it at max so that the
+        * performance is nominal.
+        */
+       icc_set_bw(gpu->icc_path, 0, MBps_to_icc(7216));
+}
+
 static void __a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index)
 {
        struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
@@ -128,11 +162,8 @@ static void __a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int 
index)

        gmu->freq = gmu->gpu_freqs[index];

-       /*
-        * Eventually we will want to scale the path vote with the frequency but
-        * for now leave it at max so that the performance is nominal.
-        */
-       icc_set_bw(gpu->icc_path, 0, MBps_to_icc(7216));
+       if (gpu->icc_path)
+               a6xx_gmu_set_icc_vote(gpu, gmu->freq);
 }

 void a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq)
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c 
b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 2d13694..bbbcc7a 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -882,7 +882,7 @@ static int adreno_get_pwrlevels(struct device *dev,
 {
        unsigned long freq = ULONG_MAX;
        struct dev_pm_opp *opp;
-       int ret;
+       int ret, i;

        gpu->fast_rate = 0;

@@ -890,9 +890,29 @@ static int adreno_get_pwrlevels(struct device *dev,
        if (!of_find_property(dev->of_node, "operating-points-v2", NULL))
                ret = adreno_get_legacy_pwrlevels(dev);
        else {
-               ret = dev_pm_opp_of_add_table(dev);
-               if (ret)
-                       DRM_DEV_ERROR(dev, "Unable to set the OPP table\n");
+               int count = of_count_phandle_with_args(dev->of_node,
+                               "operating-points-v2", NULL);
+
+               count = min(count, GPU_DDR_OPP_TABLE_INDEX + 1);
+               count = max(count, 1);
+
+               for (i = 0; i < count; i++) {
+                       ret = dev_pm_opp_of_add_table_indexed(dev, i);
+                       if (ret) {
+                               DRM_DEV_ERROR(dev, "Add OPP table %d: failed 
%d\n",
+                                               i, ret);
+                               goto err;
+                       }
+
+                       gpu->opp_tables[i] =
+                               dev_pm_opp_get_opp_table_indexed(dev, i);
+                       if (!gpu->opp_tables[i]) {
+                               DRM_DEV_ERROR(dev, "Get OPP table failed index 
%d\n",
+                                               i);
+                               ret = -EINVAL;
+                               goto err;
+                       }
+               }
        }

        if (!ret) {
@@ -919,12 +939,24 @@ static int adreno_get_pwrlevels(struct device *dev,
                gpu->icc_path = NULL;

        return 0;
+err:
+       for (; i >= 0; i--) {
+               if (gpu->opp_tables[i]) {
+                       dev_pm_opp_put_opp_table(gpu->opp_tables[i]);
+                       gpu->opp_tables[i] = NULL;
+               }
+       }
+
+       dev_pm_opp_remove_table(dev);
+       return ret;
 }

 int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
                struct adreno_gpu *adreno_gpu,
                const struct adreno_gpu_funcs *funcs, int nr_rings)
 {
+       int ret = 0;
+
        struct adreno_platform_config *config = pdev->dev.platform_data;
        struct msm_gpu_config adreno_gpu_config  = { 0 };
        struct msm_gpu *gpu = &adreno_gpu->base;
@@ -945,7 +977,9 @@ int adreno_gpu_init(struct drm_device *drm, struct 
platform_device *pdev,

        adreno_gpu_config.nr_rings = nr_rings;

-       adreno_get_pwrlevels(&pdev->dev, gpu);
+       ret = adreno_get_pwrlevels(&pdev->dev, gpu);
+       if (ret)
+               return ret;

        pm_runtime_set_autosuspend_delay(&pdev->dev,
                adreno_gpu->info->inactive_period);
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index ab8f0f9c..5b98b48 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -66,6 +66,12 @@ struct msm_gpu_funcs {
        void (*gpu_set_freq)(struct msm_gpu *gpu, unsigned long freq);
 };

+/* opp table indices */
+enum {
+       GPU_OPP_TABLE_INDEX,
+       GPU_DDR_OPP_TABLE_INDEX,
+};
+
 struct msm_gpu {
        const char *name;
        struct drm_device *dev;
@@ -113,6 +119,9 @@ struct msm_gpu {

        struct icc_path *icc_path;

+       /* gpu/ddr opp tables */
+       struct opp_table *opp_tables[2];
+
        /* Hang and Inactivity Detection:
         */
 #define DRM_MSM_INACTIVE_PERIOD   66 /* in ms (roughly four frames) */
--
2.7.4
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to