On 11/10/25 5:37 PM, Akhil P Oommen wrote:
> A8x GMU firmwares expect a separate vote table which describes the
> relationship between the Gx rail and MxA rail (and possibly Cx rail).
> Create this new vote table and implement the new HFI message which
> allows passing vote tables to send this data to GMU.
> 
> Signed-off-by: Akhil P Oommen <[email protected]>
> ---

[...]

>  drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 54 
> +++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/msm/adreno/a6xx_gmu.h |  1 +
>  drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 53 ++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/msm/adreno/a6xx_hfi.h | 17 +++++++++++
>  4 files changed, 125 insertions(+)
> 
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c 
> b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> index 8597d7adf2f7..396da035cbe8 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> @@ -1591,6 +1591,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)

Checkpatch should be grumpy about indentation here

[...]

> +     /* 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]);

nit: reverse-Christmas-tree would be nice here

> +
> +             /* 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);

FIELD_PREP() + GENMASK, please

[...]

> +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);

devm_ only adds overhead here, there's not even an error-return path,
go with regular kzalloc/kfree

> +     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;

This is essentially struct perf_gx_level with the ACD field recycled

> +     }
> +
> +     /* 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;

And this is struct perf_level

[...]

> +#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

Such defines usually go below the field definition, not above

Konrad
> +     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 {
> 

Reply via email to