Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/msm/a6xx: Share dependency vote table with GMU

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 <akhilpo@oss.qualcomm.com>
Patchwork: https://patchwork.freedesktop.org/patch/689016/
Message-ID: <20251118-kaana-gpu-support-v4-13-86eeb8e93fb6@oss.qualcomm.com>
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>

authored by

Akhil P Oommen and committed by
Rob Clark
06cfbca0 ca04ce7a

+125
+54
drivers/gpu/drm/msm/adreno/a6xx_gmu.c
··· 1616 1616 return 0; 1617 1617 } 1618 1618 1619 + static int a6xx_gmu_rpmh_dep_votes_init(struct device *dev, u32 *votes, 1620 + unsigned long *freqs, int freqs_count) 1621 + { 1622 + const u16 *mx; 1623 + size_t count; 1624 + 1625 + mx = cmd_db_read_aux_data("mx.lvl", &count); 1626 + if (IS_ERR(mx)) 1627 + return PTR_ERR(mx); 1628 + /* 1629 + * The data comes back as an array of unsigned shorts so adjust the 1630 + * count accordingly 1631 + */ 1632 + count >>= 1; 1633 + if (!count) 1634 + return -EINVAL; 1635 + 1636 + /* Fix the vote for zero frequency */ 1637 + votes[0] = 0xffffffff; 1638 + 1639 + /* Construct a vote for rest of the corners */ 1640 + for (int i = 1; i < freqs_count; i++) { 1641 + unsigned int level = a6xx_gmu_get_arc_level(dev, freqs[i]); 1642 + u8 j, index = 0; 1643 + 1644 + /* Get the primary index that matches the arc level */ 1645 + for (j = 0; j < count; j++) { 1646 + if (mx[j] >= level) { 1647 + index = j; 1648 + break; 1649 + } 1650 + } 1651 + 1652 + if (j == count) { 1653 + DRM_DEV_ERROR(dev, 1654 + "Mx Level %u not found in the RPMh list\n", 1655 + level); 1656 + DRM_DEV_ERROR(dev, "Available levels:\n"); 1657 + for (j = 0; j < count; j++) 1658 + DRM_DEV_ERROR(dev, " %u\n", mx[j]); 1659 + 1660 + return -EINVAL; 1661 + } 1662 + 1663 + /* Construct the vote */ 1664 + votes[i] = (0x3fff << 14) | (index << 8) | (0xff); 1665 + } 1666 + 1667 + return 0; 1668 + } 1669 + 1619 1670 /* 1620 1671 * The GMU votes with the RPMh for itself and on behalf of the GPU but we need 1621 1672 * to construct the list of votes on the CPU and send it over. Query the RPMh ··· 1699 1648 /* Build the CX votes */ 1700 1649 ret |= a6xx_gmu_rpmh_arc_votes_init(gmu->dev, gmu->cx_arc_votes, 1701 1650 gmu->gmu_freqs, gmu->nr_gmu_freqs, "cx.lvl", "mx.lvl"); 1651 + 1652 + ret |= a6xx_gmu_rpmh_dep_votes_init(gmu->dev, gmu->dep_arc_votes, 1653 + gmu->gpu_freqs, gmu->nr_gpu_freqs); 1702 1654 1703 1655 /* Build the interconnect votes */ 1704 1656 if (info->bcms && gmu->nr_gpu_bws > 1)
+1
drivers/gpu/drm/msm/adreno/a6xx_gmu.h
··· 97 97 int nr_gpu_freqs; 98 98 unsigned long gpu_freqs[GMU_MAX_GX_FREQS]; 99 99 u32 gx_arc_votes[GMU_MAX_GX_FREQS]; 100 + u32 dep_arc_votes[GMU_MAX_GX_FREQS]; 100 101 struct a6xx_hfi_acd_table acd_table; 101 102 102 103 int nr_gpu_bws;
+53
drivers/gpu/drm/msm/adreno/a6xx_hfi.c
··· 23 23 HFI_MSG_ID(HFI_H2F_MSG_START), 24 24 HFI_MSG_ID(HFI_H2F_FEATURE_CTRL), 25 25 HFI_MSG_ID(HFI_H2F_MSG_CORE_FW_START), 26 + HFI_MSG_ID(HFI_H2F_MSG_TABLE), 26 27 HFI_MSG_ID(HFI_H2F_MSG_GX_BW_PERF_VOTE), 27 28 HFI_MSG_ID(HFI_H2F_MSG_PREPARE_SLUMBER), 28 29 }; ··· 271 270 NULL, 0); 272 271 } 273 272 273 + static int a8xx_hfi_send_perf_table(struct a6xx_gmu *gmu) 274 + { 275 + unsigned int num_gx_votes = 3, num_cx_votes = 2; 276 + struct a6xx_hfi_table_entry *entry; 277 + struct a6xx_hfi_table *tbl; 278 + int ret, i; 279 + u32 size; 280 + 281 + size = sizeof(*tbl) + (2 * sizeof(tbl->entry[0])) + 282 + (gmu->nr_gpu_freqs * num_gx_votes * sizeof(gmu->gx_arc_votes[0])) + 283 + (gmu->nr_gmu_freqs * num_cx_votes * sizeof(gmu->cx_arc_votes[0])); 284 + tbl = kzalloc(size, GFP_KERNEL); 285 + tbl->type = HFI_TABLE_GPU_PERF; 286 + 287 + /* First fill GX votes */ 288 + entry = &tbl->entry[0]; 289 + entry->count = gmu->nr_gpu_freqs; 290 + entry->stride = num_gx_votes; 291 + 292 + for (i = 0; i < gmu->nr_gpu_freqs; i++) { 293 + unsigned int base = i * entry->stride; 294 + 295 + entry->data[base+0] = gmu->gx_arc_votes[i]; 296 + entry->data[base+1] = gmu->dep_arc_votes[i]; 297 + entry->data[base+2] = gmu->gpu_freqs[i] / 1000; 298 + } 299 + 300 + /* Then fill CX votes */ 301 + entry = (struct a6xx_hfi_table_entry *) 302 + &tbl->entry[0].data[gmu->nr_gpu_freqs * num_gx_votes]; 303 + 304 + entry->count = gmu->nr_gmu_freqs; 305 + entry->stride = num_cx_votes; 306 + 307 + for (i = 0; i < gmu->nr_gmu_freqs; i++) { 308 + unsigned int base = i * entry->stride; 309 + 310 + entry->data[base] = gmu->cx_arc_votes[i]; 311 + entry->data[base+1] = gmu->gmu_freqs[i] / 1000; 312 + } 313 + 314 + ret = a6xx_hfi_send_msg(gmu, HFI_H2F_MSG_TABLE, tbl, size, NULL, 0); 315 + 316 + kfree(tbl); 317 + return ret; 318 + } 319 + 274 320 static int a6xx_hfi_send_perf_table(struct a6xx_gmu *gmu) 275 321 { 322 + struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); 323 + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; 276 324 struct a6xx_hfi_msg_perf_table msg = { 0 }; 277 325 int i; 326 + 327 + if (adreno_is_a8xx(adreno_gpu)) 328 + return a8xx_hfi_send_perf_table(gmu); 278 329 279 330 msg.num_gpu_levels = gmu->nr_gpu_freqs; 280 331 msg.num_gmu_levels = gmu->nr_gmu_freqs;
+17
drivers/gpu/drm/msm/adreno/a6xx_hfi.h
··· 185 185 u32 handle; 186 186 }; 187 187 188 + #define HFI_H2F_MSG_TABLE 15 189 + 190 + struct a6xx_hfi_table_entry { 191 + u32 count; 192 + u32 stride; 193 + u32 data[]; 194 + }; 195 + 196 + struct a6xx_hfi_table { 197 + u32 header; 198 + u32 version; 199 + u32 type; 200 + #define HFI_TABLE_BW_VOTE 0 201 + #define HFI_TABLE_GPU_PERF 1 202 + struct a6xx_hfi_table_entry entry[]; 203 + }; 204 + 188 205 #define HFI_H2F_MSG_GX_BW_PERF_VOTE 30 189 206 190 207 struct a6xx_hfi_gx_bw_perf_vote_cmd {