A8x GMU configuration are very similar to A7x. Unfortunately, there are
minor shuffling in the register offsets in the GMU CX register region.
Apart from that, there is a new HFI message support to pass table like
data. This patch adds support for  perf table using this new HFI
message.

Apart from that, there is a minor rework in a6xx_gmu_rpmh_arc_votes_init()
to simplify handling of MxG to MxA fallback along with the additional
calculations for the new dependency vote.

Signed-off-by: Akhil P Oommen <[email protected]>
---
 drivers/gpu/drm/msm/adreno/a6xx_gmu.c             | 161 +++++++++++++++++-----
 drivers/gpu/drm/msm/adreno/a6xx_gmu.h             |   5 +-
 drivers/gpu/drm/msm/adreno/a6xx_hfi.c             |  53 +++++++
 drivers/gpu/drm/msm/adreno/a6xx_hfi.h             |  17 +++
 drivers/gpu/drm/msm/adreno/adreno_gpu.h           |   7 +
 drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml |  48 +++++--
 6 files changed, 242 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c 
b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 
72d64eb10ca931ee90c91f7e004771cf6d7997a4..e687f5cc7ee59c2156d7e1d000106796a9680fd5
 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -224,14 +224,19 @@ unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu)
 
 static bool a6xx_gmu_check_idle_level(struct a6xx_gmu *gmu)
 {
-       u32 val;
+       struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
+       struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
        int local = gmu->idle_level;
+       u32 val;
 
        /* SPTP and IFPC both report as IFPC */
        if (gmu->idle_level == GMU_IDLE_STATE_SPTP)
                local = GMU_IDLE_STATE_IFPC;
 
-       val = gmu_read(gmu, REG_A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE);
+       if (adreno_is_a8xx(adreno_gpu))
+               val = gmu_read(gmu, REG_A8XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE);
+       else
+               val = gmu_read(gmu, REG_A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE);
 
        if (val == local) {
                if (gmu->idle_level != GMU_IDLE_STATE_IFPC ||
@@ -269,7 +274,9 @@ static int a6xx_gmu_start(struct a6xx_gmu *gmu)
        /* Set the log wptr index
         * note: downstream saves the value in poweroff and restores it here
         */
-       if (adreno_is_a7xx(adreno_gpu))
+       if (adreno_is_a8xx(adreno_gpu))
+               gmu_write(gmu, REG_A8XX_GMU_GENERAL_9, 0);
+       else if (adreno_is_a7xx(adreno_gpu))
                gmu_write(gmu, REG_A7XX_GMU_GENERAL_9, 0);
        else
                gmu_write(gmu, REG_A6XX_GPU_GMU_CX_GMU_PWR_COL_CP_RESP, 0);
@@ -485,7 +492,9 @@ static void a6xx_gemnoc_workaround(struct a6xx_gmu *gmu)
         * in the power down sequence not being fully executed. That in turn can
         * prevent CX_GDSC from collapsing. Assert Qactive to avoid this.
         */
-       if (adreno_is_a7xx(adreno_gpu) || (adreno_is_a621(adreno_gpu) ||
+       if (adreno_is_a8xx(adreno_gpu))
+               gmu_write(gmu, REG_A8XX_GPU_GMU_CX_GMU_CX_FALNEXT_INTF, BIT(0));
+       else if (adreno_is_a7xx(adreno_gpu) || (adreno_is_a621(adreno_gpu) ||
                                adreno_is_7c3(adreno_gpu)))
                gmu_write(gmu, REG_A6XX_GPU_GMU_CX_GMU_CX_FALNEXT_INTF, BIT(0));
 }
@@ -493,10 +502,15 @@ static void a6xx_gemnoc_workaround(struct a6xx_gmu *gmu)
 /* Let the GMU know that we are about to go into slumber */
 static int a6xx_gmu_notify_slumber(struct a6xx_gmu *gmu)
 {
+       struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
+       struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
        int ret;
 
        /* Disable the power counter so the GMU isn't busy */
-       gmu_write(gmu, REG_A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0);
+       if (adreno_is_a8xx(adreno_gpu))
+               gmu_write(gmu, REG_A8XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0);
+       else
+               gmu_write(gmu, REG_A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0);
 
        /* Disable SPTP_PC if the CPU is responsible for it */
        if (gmu->idle_level < GMU_IDLE_STATE_SPTP)
@@ -592,12 +606,16 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu)
        struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
        struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
        struct platform_device *pdev = to_platform_device(gmu->dev);
-       void __iomem *pdcptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc", NULL);
        u32 seqmem0_drv0_reg = REG_A6XX_RSCC_SEQ_MEM_0_DRV0;
        void __iomem *seqptr = NULL;
        uint32_t pdc_address_offset;
+       void __iomem *pdcptr;
        bool pdc_in_aop = false;
 
+       if (adreno_is_a8xx(adreno_gpu))
+               return;
+
+       pdcptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc", NULL);
        if (IS_ERR(pdcptr))
                goto err;
 
@@ -732,7 +750,7 @@ static void a6xx_gmu_power_config(struct a6xx_gmu *gmu)
        gmu_write(gmu, REG_A6XX_GMU_DCACHE_CONFIG, 0x1);
 
        /* A7xx knows better by default! */
-       if (adreno_is_a7xx(adreno_gpu))
+       if (adreno_is_a7xx(adreno_gpu) || adreno_is_a8xx(adreno_gpu))
                return;
 
        gmu_write(gmu, REG_A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0x9c40400);
@@ -792,7 +810,8 @@ static int a6xx_gmu_fw_load(struct a6xx_gmu *gmu)
        u32 itcm_base = 0x00000000;
        u32 dtcm_base = 0x00040000;
 
-       if (adreno_is_a650_family(adreno_gpu) || adreno_is_a7xx(adreno_gpu))
+       if (adreno_is_a650_family(adreno_gpu) || adreno_is_a7xx(adreno_gpu) ||
+                       adreno_is_a8xx(adreno_gpu))
                dtcm_base = 0x10004000;
 
        if (gmu->legacy) {
@@ -856,12 +875,15 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, 
unsigned int state)
        if (adreno_is_a650_family(adreno_gpu) || adreno_is_a7xx(adreno_gpu)) {
                gmu_write(gmu, REG_A6XX_GPU_GMU_CX_GMU_CX_FALNEXT_INTF, 1);
                gmu_write(gmu, REG_A6XX_GPU_GMU_CX_GMU_CX_FAL_INTF, 1);
+       } else if (adreno_is_a8xx(adreno_gpu)) {
+               gmu_write(gmu, REG_A8XX_GPU_GMU_CX_GMU_CX_FALNEXT_INTF, 1);
+               gmu_write(gmu, REG_A8XX_GPU_GMU_CX_GMU_CX_FAL_INTF, 1);
        }
 
        /* Turn on TCM (Tightly Coupled Memory) retention */
        if (adreno_is_a7xx(adreno_gpu))
                a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_TCM_RET_CNTL, 1);
-       else
+       else if (!adreno_is_a8xx(adreno_gpu))
                gmu_write(gmu, REG_A6XX_GMU_GENERAL_7, 1);
 
        ret = a6xx_rpmh_start(gmu);
@@ -886,7 +908,10 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, 
unsigned int state)
        gmu_write(gmu, REG_A6XX_GMU_HFI_QTBL_ADDR, gmu->hfi.iova);
        gmu_write(gmu, REG_A6XX_GMU_HFI_QTBL_INFO, 1);
 
-       if (adreno_is_a7xx(adreno_gpu)) {
+       if (adreno_is_a8xx(adreno_gpu)) {
+               fence_range_upper = 0x32;
+               fence_range_lower = 0x8c0;
+       } else if (adreno_is_a7xx(adreno_gpu)) {
                fence_range_upper = 0x32;
                fence_range_lower = 0x8a0;
        } else {
@@ -920,7 +945,12 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, 
unsigned int state)
                chipid |= (adreno_gpu->chip_id << 8) & 0x0f00; /* patchid */
        }
 
-       if (adreno_is_a7xx(adreno_gpu)) {
+       if (adreno_is_a8xx(adreno_gpu)) {
+               gmu_write(gmu, REG_A8XX_GMU_GENERAL_10, chipid);
+               gmu_write(gmu, REG_A8XX_GMU_GENERAL_8,
+                         (gmu->log.iova & GENMASK(31, 12)) |
+                         ((gmu->log.size / SZ_4K - 1) & GENMASK(7, 0)));
+       } else if (adreno_is_a7xx(adreno_gpu)) {
                gmu_write(gmu, REG_A7XX_GMU_GENERAL_10, chipid);
                gmu_write(gmu, REG_A7XX_GMU_GENERAL_8,
                          (gmu->log.iova & GENMASK(31, 12)) |
@@ -983,7 +1013,7 @@ static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu)
        u32 val, seqmem_off = 0;
 
        /* The second spin of A7xx GPUs messed with some register offsets.. */
-       if (adreno_is_a740_family(adreno_gpu))
+       if (adreno_is_a740_family(adreno_gpu) || adreno_is_a8xx(adreno_gpu))
                seqmem_off = 4;
 
        /* Make sure there are no outstanding RPMh votes */
@@ -996,7 +1026,8 @@ static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu)
        gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS3_DRV0_STATUS + seqmem_off,
                val, (val & 1), 100, 1000);
 
-       if (!adreno_is_a740_family(adreno_gpu))
+
+       if (!adreno_is_a740_family(adreno_gpu) && !adreno_is_a8xx(adreno_gpu))
                return;
 
        gmu_poll_timeout_rscc(gmu, REG_A7XX_RSCC_TCS4_DRV0_STATUS + seqmem_off,
@@ -1024,7 +1055,10 @@ static void a6xx_gmu_force_off(struct a6xx_gmu *gmu)
         * Turn off keep alive that might have been enabled by the hang
         * interrupt
         */
-       gmu_write(&a6xx_gpu->gmu, REG_A6XX_GMU_GMU_PWR_COL_KEEPALIVE, 0);
+       if (adreno_is_a8xx(adreno_gpu))
+               gmu_write(&a6xx_gpu->gmu, REG_A8XX_GMU_GMU_PWR_COL_KEEPALIVE, 
0);
+       else
+               gmu_write(&a6xx_gpu->gmu, REG_A6XX_GMU_GMU_PWR_COL_KEEPALIVE, 
0);
 
        /* Flush all the queues */
        a6xx_hfi_stop(gmu);
@@ -1128,7 +1162,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
        enable_irq(gmu->gmu_irq);
 
        /* Check to see if we are doing a cold or warm boot */
-       if (adreno_is_a7xx(adreno_gpu)) {
+       if (adreno_is_a7xx(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) {
                status = a6xx_llc_read(a6xx_gpu, REG_A7XX_CX_MISC_TCM_RET_CNTL) 
== 1 ?
                        GMU_WARM_BOOT : GMU_COLD_BOOT;
        } else if (gmu->legacy) {
@@ -1457,7 +1491,7 @@ static int a6xx_gmu_rpmh_bw_votes_init(struct adreno_gpu 
*adreno_gpu,
                        vote = clamp(peak, 1, BCM_TCS_CMD_VOTE_MASK);
 
                        /* GMUs on A7xx votes on both x & y */
-                       if (adreno_is_a7xx(adreno_gpu))
+                       if (adreno_is_a7xx(adreno_gpu) || 
adreno_is_a8xx(adreno_gpu))
                                data[bcm_index] = BCM_TCS_CMD(commit, true, 
vote, vote);
                        else
                                data[bcm_index] = BCM_TCS_CMD(commit, true, 0, 
vote);
@@ -1489,13 +1523,14 @@ static unsigned int a6xx_gmu_get_arc_level(struct 
device *dev,
 }
 
 static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes,
-               unsigned long *freqs, int freqs_count, const char *id)
+               unsigned long *freqs, int freqs_count,
+               const char *pri_id, const char *sec_id)
 {
        int i, j;
        const u16 *pri, *sec;
        size_t pri_count, sec_count;
 
-       pri = cmd_db_read_aux_data(id, &pri_count);
+       pri = cmd_db_read_aux_data(pri_id, &pri_count);
        if (IS_ERR(pri))
                return PTR_ERR(pri);
        /*
@@ -1506,13 +1541,7 @@ static int a6xx_gmu_rpmh_arc_votes_init(struct device 
*dev, u32 *votes,
        if (!pri_count)
                return -EINVAL;
 
-       /*
-        * Some targets have a separate gfx mxc rail. So try to read that first 
and then fall back
-        * to regular mx rail if it is missing
-        */
-       sec = cmd_db_read_aux_data("gmxc.lvl", &sec_count);
-       if (IS_ERR(sec) && sec != ERR_PTR(-EPROBE_DEFER))
-               sec = cmd_db_read_aux_data("mx.lvl", &sec_count);
+       sec = cmd_db_read_aux_data(sec_id, &sec_count);
        if (IS_ERR(sec))
                return PTR_ERR(sec);
 
@@ -1566,6 +1595,57 @@ static int a6xx_gmu_rpmh_arc_votes_init(struct device 
*dev, u32 *votes,
        return 0;
 }
 
+static int a6xx_gmu_rpmh_dep_votes_init(struct device *dev, u32 *votes,
+               unsigned long *freqs, int freqs_count)
+{
+       const u16 *mx;
+       size_t count;
+
+       mx = cmd_db_read_aux_data("mx.lvl", &count);
+       if (IS_ERR(mx))
+               return PTR_ERR(mx);
+       /*
+        * The data comes back as an array of unsigned shorts so adjust the
+        * count accordingly
+        */
+       count >>= 1;
+       if (!count)
+               return -EINVAL;
+
+       /* Fix the vote for zero frequency */
+       votes[0] = 0xFFFFFFFF;
+
+       /* Construct a vote for rest of the corners */
+       for (int i = 1; i < freqs_count; i++) {
+               u8 j, index = 0;
+               unsigned int level = a6xx_gmu_get_arc_level(dev, freqs[i]);
+
+               /* Get the primary index that matches the arc level */
+               for (j = 0; j < count; j++) {
+                       if (mx[j] >= level) {
+                               index = j;
+                               break;
+                       }
+               }
+
+               if (j == count) {
+                       DRM_DEV_ERROR(dev,
+                                     "Mx Level %u not found in the RPMh 
list\n",
+                                     level);
+                       DRM_DEV_ERROR(dev, "Available levels:\n");
+                       for (j = 0; j < count; j++)
+                               DRM_DEV_ERROR(dev, "  %u\n", mx[j]);
+
+                       return -EINVAL;
+               }
+
+               /* Construct the vote */
+               votes[i] = (0x3fff << 14) | (index << 8) | (0xff);
+       }
+
+       return 0;
+}
+
 /*
  * The GMU votes with the RPMh for itself and on behalf of the GPU but we need
  * to construct the list of votes on the CPU and send it over. Query the RPMh
@@ -1580,15 +1660,27 @@ static int a6xx_gmu_rpmh_votes_init(struct a6xx_gmu 
*gmu)
        struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
        const struct a6xx_info *info = adreno_gpu->info->a6xx;
        struct msm_gpu *gpu = &adreno_gpu->base;
+       const char *sec_id;
+       const u16 *gmxc;
        int ret;
 
+       gmxc = cmd_db_read_aux_data("gmxc.lvl", NULL);
+       if (gmxc == ERR_PTR(-EPROBE_DEFER))
+               return -EPROBE_DEFER;
+
+       /* If GMxC is present, prefer that as secondary rail for GX votes */
+       sec_id = IS_ERR_OR_NULL(gmxc) ? "mx.lvl" : "gmxc.lvl";
+
        /* Build the GX votes */
        ret = a6xx_gmu_rpmh_arc_votes_init(&gpu->pdev->dev, gmu->gx_arc_votes,
-               gmu->gpu_freqs, gmu->nr_gpu_freqs, "gfx.lvl");
+               gmu->gpu_freqs, gmu->nr_gpu_freqs, "gfx.lvl", sec_id);
 
        /* Build the CX votes */
        ret |= a6xx_gmu_rpmh_arc_votes_init(gmu->dev, gmu->cx_arc_votes,
-               gmu->gmu_freqs, gmu->nr_gmu_freqs, "cx.lvl");
+               gmu->gmu_freqs, gmu->nr_gmu_freqs, "cx.lvl", "mx.lvl");
+
+       ret |= a6xx_gmu_rpmh_dep_votes_init(gmu->dev, gmu->dep_arc_votes,
+               gmu->gpu_freqs, gmu->nr_gpu_freqs);
 
        /* Build the interconnect votes */
        if (info->bcms && gmu->nr_gpu_bws > 1)
@@ -2043,14 +2135,14 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct 
device_node *node)
         * are otherwise unused by a660.
         */
        gmu->dummy.size = SZ_4K;
-       if (adreno_is_a660_family(adreno_gpu) ||
-           adreno_is_a7xx(adreno_gpu)) {
+       if (adreno_is_a660_family(adreno_gpu) || adreno_is_a7xx(adreno_gpu) ||
+                       adreno_is_a8xx(adreno_gpu)) {
                ret = a6xx_gmu_memory_alloc(gmu, &gmu->debug, SZ_4K * 7,
                                            0x60400000, "debug");
                if (ret)
                        goto err_memory;
 
-               gmu->dummy.size = SZ_8K;
+               gmu->dummy.size = SZ_16K;
        }
 
        /* Allocate memory for the GMU dummy page */
@@ -2060,8 +2152,8 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct 
device_node *node)
                goto err_memory;
 
        /* Note that a650 family also includes a660 family: */
-       if (adreno_is_a650_family(adreno_gpu) ||
-           adreno_is_a7xx(adreno_gpu)) {
+       if (adreno_is_a650_family(adreno_gpu) || adreno_is_a7xx(adreno_gpu) ||
+                       adreno_is_a8xx(adreno_gpu)) {
                ret = a6xx_gmu_memory_alloc(gmu, &gmu->icache,
                        SZ_16M - SZ_16K, 0x04000, "icache");
                if (ret)
@@ -2118,13 +2210,14 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct 
device_node *node)
        /* Identify gmu base offset from gpu base address */
        gmu->mmio_offset = (u32)(start - res->start);
 
-       if (adreno_is_a650_family(adreno_gpu) ||
-           adreno_is_a7xx(adreno_gpu)) {
+       if (adreno_is_a650_family(adreno_gpu) || adreno_is_a7xx(adreno_gpu)) {
                gmu->rscc = a6xx_gmu_get_mmio(pdev, "rscc", NULL);
                if (IS_ERR(gmu->rscc)) {
                        ret = -ENODEV;
                        goto err_mmio;
                }
+       } else if (adreno_is_a8xx(adreno_gpu)) {
+               gmu->rscc = gmu->mmio + 0x19000;
        } else {
                gmu->rscc = gmu->mmio + 0x23000;
        }
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h 
b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
index 
55b1c78daa8b523147435a86d6eb629dbad18acd..2af074c8e8cfa775a7d35a786834dba30395c8c4
 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
@@ -19,8 +19,8 @@ struct a6xx_gmu_bo {
        u64 iova;
 };
 
-#define GMU_MAX_GX_FREQS       16
-#define GMU_MAX_CX_FREQS       4
+#define GMU_MAX_GX_FREQS       32
+#define GMU_MAX_CX_FREQS       6
 #define GMU_MAX_BCMS           3
 
 struct a6xx_bcm {
@@ -97,6 +97,7 @@ struct a6xx_gmu {
        int nr_gpu_freqs;
        unsigned long gpu_freqs[GMU_MAX_GX_FREQS];
        u32 gx_arc_votes[GMU_MAX_GX_FREQS];
+       u32 dep_arc_votes[GMU_MAX_GX_FREQS];
        struct a6xx_hfi_acd_table acd_table;
 
        int nr_gpu_bws;
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c 
b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
index 
550de6ad68effacaea09751891c2528464bdfcc5..64618fd693051ee7b24406292a86bcfb28f73172
 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
@@ -23,6 +23,7 @@ static const char * const a6xx_hfi_msg_id[] = {
        HFI_MSG_ID(HFI_H2F_MSG_START),
        HFI_MSG_ID(HFI_H2F_FEATURE_CTRL),
        HFI_MSG_ID(HFI_H2F_MSG_CORE_FW_START),
+       HFI_MSG_ID(HFI_H2F_MSG_TABLE),
        HFI_MSG_ID(HFI_H2F_MSG_GX_BW_PERF_VOTE),
        HFI_MSG_ID(HFI_H2F_MSG_PREPARE_SLUMBER),
 };
@@ -255,11 +256,63 @@ static int a6xx_hfi_send_perf_table_v1(struct a6xx_gmu 
*gmu)
                NULL, 0);
 }
 
+static int a8xx_hfi_send_perf_table(struct a6xx_gmu *gmu)
+{
+       unsigned int num_gx_votes = 3, num_cx_votes = 2;
+       struct a6xx_hfi_table_entry *entry;
+       struct a6xx_hfi_table *tbl;
+       int ret, i;
+       u32 size;
+
+       size = sizeof(*tbl) +  (2 * sizeof(tbl->entry[0])) +
+               (gmu->nr_gpu_freqs * num_gx_votes * 
sizeof(gmu->gx_arc_votes[0])) +
+               (gmu->nr_gmu_freqs * num_cx_votes * 
sizeof(gmu->cx_arc_votes[0]));
+       tbl = devm_kzalloc(gmu->dev, size, GFP_KERNEL);
+       tbl->type = HFI_TABLE_GPU_PERF;
+
+       /* First fill GX votes */
+       entry = &tbl->entry[0];
+       entry->count = gmu->nr_gpu_freqs;
+       entry->stride = num_gx_votes;
+
+       for (i = 0; i < gmu->nr_gpu_freqs; i++) {
+               unsigned int base = i * entry->stride;
+
+               entry->data[base+0] = gmu->gx_arc_votes[i];
+               entry->data[base+1] = gmu->dep_arc_votes[i];
+               entry->data[base+2] = gmu->gpu_freqs[i] / 1000;
+       }
+
+       /* Then fill CX votes */
+       entry = (struct a6xx_hfi_table_entry *)
+               &tbl->entry[0].data[gmu->nr_gpu_freqs * num_gx_votes];
+
+       entry->count = gmu->nr_gmu_freqs;
+       entry->stride = num_cx_votes;
+
+       for (i = 0; i < gmu->nr_gmu_freqs; i++) {
+               unsigned int base = i * entry->stride;
+
+               entry->data[base] = gmu->cx_arc_votes[i];
+               entry->data[base+1] = gmu->gmu_freqs[i] / 1000;
+       }
+
+       ret = a6xx_hfi_send_msg(gmu, HFI_H2F_MSG_TABLE, tbl, size, NULL, 0);
+
+       devm_kfree(gmu->dev, tbl);
+       return ret;
+}
+
 static int a6xx_hfi_send_perf_table(struct a6xx_gmu *gmu)
 {
+       struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
+       struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
        struct a6xx_hfi_msg_perf_table msg = { 0 };
        int i;
 
+       if (adreno_is_a8xx(adreno_gpu))
+               return a8xx_hfi_send_perf_table(gmu);
+
        msg.num_gpu_levels = gmu->nr_gpu_freqs;
        msg.num_gmu_levels = gmu->nr_gmu_freqs;
 
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.h 
b/drivers/gpu/drm/msm/adreno/a6xx_hfi.h
index 
653ef720e2da4d2b0793c0b76e994b6f6dc524c7..e12866110cb8ea0c075b3ae5e4cae679405c4bd1
 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.h
@@ -185,6 +185,23 @@ struct a6xx_hfi_msg_core_fw_start {
        u32 handle;
 };
 
+#define HFI_H2F_MSG_TABLE 15
+
+struct a6xx_hfi_table_entry {
+       u32 count;
+       u32 stride;
+       u32 data[];
+};
+
+struct a6xx_hfi_table {
+       u32 header;
+       u32 version;
+#define HFI_TABLE_BW_VOTE 0
+#define HFI_TABLE_GPU_PERF 1
+       u32 type;
+       struct a6xx_hfi_table_entry entry[];
+};
+
 #define HFI_H2F_MSG_GX_BW_PERF_VOTE 30
 
 struct a6xx_hfi_gx_bw_perf_vote_cmd {
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h 
b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 
b27974d97c7512ecae326eb2d22238330d6c52f0..9831401c3bc865b803c2f9759d5e2ffcd79d19f8
 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -50,6 +50,8 @@ enum adreno_family {
        ADRENO_7XX_GEN1,  /* a730 family */
        ADRENO_7XX_GEN2,  /* a740 family */
        ADRENO_7XX_GEN3,  /* a750 family */
+       ADRENO_8XX_GEN1,  /* a830 family */
+       ADRENO_8XX_GEN2,  /* a840 family */
 };
 
 #define ADRENO_QUIRK_TWO_PASS_USE_WFI          BIT(0)
@@ -555,6 +557,11 @@ static inline int adreno_is_a7xx(struct adreno_gpu *gpu)
               adreno_is_a740_family(gpu);
 }
 
+static inline int adreno_is_a8xx(struct adreno_gpu *gpu)
+{
+       return gpu->info->family >= ADRENO_8XX_GEN1;
+}
+
 /* Put vm_start above 32b to catch issues with not setting xyz_BASE_HI */
 #define ADRENO_VM_START 0x100000000ULL
 u64 adreno_private_vm_size(struct msm_gpu *gpu);
diff --git a/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml 
b/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml
index 
09b8a0b9c0de7615f7e7e6364c198405a498121a..5dce7934056dd6472c368309b4894f0ed4a4d960
 100644
--- a/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml
+++ b/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml
@@ -66,10 +66,15 @@ 
xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
        <reg32 offset="0x1f81c" name="GMU_CM3_FW_INIT_RESULT"/>
        <reg32 offset="0x1f82d" name="GMU_CM3_CFG"/>
        <reg32 offset="0x1f840" name="GMU_CX_GMU_POWER_COUNTER_ENABLE"/>
+       <reg32 offset="0x1fc10" name="GMU_CX_GMU_POWER_COUNTER_ENABLE" 
variants="A8XX"/>
        <reg32 offset="0x1f841" name="GMU_CX_GMU_POWER_COUNTER_SELECT_0"/>
        <reg32 offset="0x1f842" name="GMU_CX_GMU_POWER_COUNTER_SELECT_1"/>
+       <reg32 offset="0x1fc40" name="GMU_CX_GMU_POWER_COUNTER_SELECT_XOCLK_0" 
variants="A8XX-"/>
+       <reg32 offset="0x1fc41" name="GMU_CX_GMU_POWER_COUNTER_SELECT_XOCLK_1" 
variants="A8XX-"/>
        <reg32 offset="0x1f844" name="GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L"/>
+       <reg32 offset="0x1fca0" name="GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L" 
variants="A8XX-"/>
        <reg32 offset="0x1f845" name="GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H"/>
+       <reg32 offset="0x1fca1" name="GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H" 
variants="A8XX-"/>
        <reg32 offset="0x1f846" name="GMU_CX_GMU_POWER_COUNTER_XOCLK_1_L"/>
        <reg32 offset="0x1f847" name="GMU_CX_GMU_POWER_COUNTER_XOCLK_1_H"/>
        <reg32 offset="0x1f848" name="GMU_CX_GMU_POWER_COUNTER_XOCLK_2_L"/>
@@ -89,7 +94,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ 
rules-fd.xsd">
        </reg32>
        <reg32 offset="0x1f8c1" name="GMU_PWR_COL_INTER_FRAME_HYST"/>
        <reg32 offset="0x1f8c2" name="GMU_PWR_COL_SPTPRAC_HYST"/>
-       <reg32 offset="0x1f8d0" name="GMU_SPTPRAC_PWR_CLK_STATUS">
+       <reg32 offset="0x1f8d0" name="GMU_SPTPRAC_PWR_CLK_STATUS" 
variants="A6XX">
                <bitfield name="SPTPRAC_GDSC_POWERING_OFF" pos="0" 
type="boolean"/>
                <bitfield name="SPTPRAC_GDSC_POWERING_ON" pos="1" 
type="boolean"/>
                <bitfield name="SPTPRAC_GDSC_POWER_OFF" pos="2" type="boolean"/>
@@ -99,7 +104,11 @@ 
xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
                <bitfield name="GX_HM_GDSC_POWER_OFF" pos="6" type="boolean"/>
                <bitfield name="GX_HM_CLK_OFF" pos="7" type="boolean"/>
        </reg32>
-       <reg32 offset="0x1f8d0" name="GMU_SPTPRAC_PWR_CLK_STATUS" 
variants="A7XX-">
+       <reg32 offset="0x1f8d0" name="GMU_SPTPRAC_PWR_CLK_STATUS" 
variants="A7XX">
+               <bitfield name="GX_HM_GDSC_POWER_OFF" pos="0" type="boolean"/>
+               <bitfield name="GX_HM_CLK_OFF" pos="1" type="boolean"/>
+       </reg32>
+       <reg32 offset="0x1f7e8" name="GMU_PWR_CLK_STATUS" variants="A8XX-">
                <bitfield name="GX_HM_GDSC_POWER_OFF" pos="0" type="boolean"/>
                <bitfield name="GX_HM_CLK_OFF" pos="1" type="boolean"/>
        </reg32>
@@ -120,9 +129,12 @@ 
xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
                <bitfield name="GFX_MIN_VOTE_ENABLE" pos="15" type="boolean"/>
        </reg32>
        <reg32 offset="0x1f8e9" name="GMU_RPMH_HYST_CTRL"/>
-       <reg32 offset="0x1f8ec" name="GPU_GMU_CX_GMU_RPMH_POWER_STATE"/>
-       <reg32 offset="0x1f8f0" name="GPU_GMU_CX_GMU_CX_FAL_INTF"/>
-       <reg32 offset="0x1f8f1" name="GPU_GMU_CX_GMU_CX_FALNEXT_INTF"/>
+       <reg32 offset="0x1f8ec" name="GPU_GMU_CX_GMU_RPMH_POWER_STATE" 
variants="A6XX"/>
+       <reg32 offset="0x1f7e9" name="GPU_GMU_CX_GMU_RPMH_POWER_STATE" 
variants="A8XX-"/>
+       <reg32 offset="0x1f8f0" name="GPU_GMU_CX_GMU_CX_FAL_INTF" 
variants="A6XX"/>
+       <reg32 offset="0x1f7ec" name="GPU_GMU_CX_GMU_CX_FAL_INTF" 
variants="A8XX-"/>
+       <reg32 offset="0x1f8f1" name="GPU_GMU_CX_GMU_CX_FALNEXT_INTF" 
variants="A6XX"/>
+       <reg32 offset="0x1f7ed" name="GPU_GMU_CX_GMU_CX_FALNEXT_INTF" 
variants="A8XX-"/>
        <reg32 offset="0x1f900" name="GPU_GMU_CX_GMU_PWR_COL_CP_MSG"/>
        <reg32 offset="0x1f901" name="GPU_GMU_CX_GMU_PWR_COL_CP_RESP"/>
        <reg32 offset="0x1f9f0" name="GMU_BOOT_KMD_LM_HANDSHAKE"/>
@@ -130,8 +142,10 @@ 
xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
        <reg32 offset="0x1f958" name="GMU_LLM_GLM_SLEEP_STATUS"/>
        <reg32 offset="0x1f888" name="GMU_ALWAYS_ON_COUNTER_L"/>
        <reg32 offset="0x1f889" name="GMU_ALWAYS_ON_COUNTER_H"/>
-       <reg32 offset="0x1f8c3" name="GMU_GMU_PWR_COL_KEEPALIVE"/>
-       <reg32 offset="0x1f8c4" name="GMU_PWR_COL_PREEMPT_KEEPALIVE"/>
+       <reg32 offset="0x1f8c3" name="GMU_GMU_PWR_COL_KEEPALIVE" 
variants="A6XX-A7XX"/>
+       <reg32 offset="0x1f7e4" name="GMU_GMU_PWR_COL_KEEPALIVE" 
variants="A8XX-"/>
+       <reg32 offset="0x1f8c4" name="GMU_PWR_COL_PREEMPT_KEEPALIVE" 
variants="A6XX-A7XX"/>
+       <reg32 offset="0x1f7e5" name="GMU_PWR_COL_PREEMPT_KEEPALIVE" 
variants="A8XX-"/>
        <reg32 offset="0x1f980" name="GMU_HFI_CTRL_STATUS"/>
        <reg32 offset="0x1f981" name="GMU_HFI_VERSION_INFO"/>
        <reg32 offset="0x1f982" name="GMU_HFI_SFR_ADDR"/>
@@ -164,6 +178,14 @@ 
xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
        <reg32 offset="0x1f9cd" name="GMU_GENERAL_8" variants="A7XX"/>
        <reg32 offset="0x1f9ce" name="GMU_GENERAL_9" variants="A7XX"/>
        <reg32 offset="0x1f9cf" name="GMU_GENERAL_10" variants="A7XX"/>
+       <reg32 offset="0x1f9c0" name="GMU_GENERAL_0" variants="A8XX"/>
+       <reg32 offset="0x1f9c1" name="GMU_GENERAL_1" variants="A8XX"/>
+       <reg32 offset="0x1f9c6" name="GMU_GENERAL_6" variants="A8XX"/>
+       <reg32 offset="0x1f9c7" name="GMU_GENERAL_7" variants="A8XX"/>
+       <reg32 offset="0x1f9c8" name="GMU_GENERAL_8" variants="A8XX"/>
+       <reg32 offset="0x1f9c9" name="GMU_GENERAL_9" variants="A8XX"/>
+       <reg32 offset="0x1f9ca" name="GMU_GENERAL_10" variants="A8XX"/>
+       <reg32 offset="0x1f9cb" name="GMU_GENERAL_11" variants="A8XX"/>
        <reg32 offset="0x1f95d" name="GMU_ISENSE_CTRL"/>
        <reg32 offset="0x23120" name="GPU_CS_ENABLE_REG"/>
        <reg32 offset="0x1f95d" name="GPU_GMU_CX_GMU_ISENSE_CTRL"/>
@@ -233,12 +255,12 @@ 
xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
        <reg32 offset="0x03ee" name="RSCC_TCS1_DRV0_STATUS"/>
        <reg32 offset="0x0496" name="RSCC_TCS2_DRV0_STATUS"/>
        <reg32 offset="0x053e" name="RSCC_TCS3_DRV0_STATUS"/>
-       <reg32 offset="0x05e6" name="RSCC_TCS4_DRV0_STATUS" variants="A7XX"/>
-       <reg32 offset="0x068e" name="RSCC_TCS5_DRV0_STATUS" variants="A7XX"/>
-       <reg32 offset="0x0736" name="RSCC_TCS6_DRV0_STATUS" variants="A7XX"/>
-       <reg32 offset="0x07de" name="RSCC_TCS7_DRV0_STATUS" variants="A7XX"/>
-       <reg32 offset="0x0886" name="RSCC_TCS8_DRV0_STATUS" variants="A7XX"/>
-       <reg32 offset="0x092e" name="RSCC_TCS9_DRV0_STATUS" variants="A7XX"/>
+       <reg32 offset="0x05e6" name="RSCC_TCS4_DRV0_STATUS" variants="A7XX-"/>
+       <reg32 offset="0x068e" name="RSCC_TCS5_DRV0_STATUS" variants="A7XX-"/>
+       <reg32 offset="0x0736" name="RSCC_TCS6_DRV0_STATUS" variants="A7XX-"/>
+       <reg32 offset="0x07de" name="RSCC_TCS7_DRV0_STATUS" variants="A7XX-"/>
+       <reg32 offset="0x0886" name="RSCC_TCS8_DRV0_STATUS" variants="A7XX-"/>
+       <reg32 offset="0x092e" name="RSCC_TCS9_DRV0_STATUS" variants="A7XX-"/>
 </domain>
 
 </database>

-- 
2.51.0

Reply via email to