From 7ea4fd85f2592f63c774bc0e40904ab0b99e88c9 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Fri, 25 Sep 2026 02:44:32 +0530 Subject: [PATCH 01/13] FROMLIST: dt-bindings: display/msm/gmu: Fix Glymur's compatible The Glymur GMU compatible string was incorrectly documented as qcom,adreno-gmu-x285.1. Fix it to use the correct string qcom,adreno-gmu-x290.1. Fixes: 7bc29d5fb6fa ("dt-bindings: display/msm/gmu: Add Adreno X2-85 GMU") Signed-off-by: Jie Zhang Signed-off-by: Akhil P Oommen Signed-off-by: Kavisha Shah Link: https://lore.kernel.org/lkml/20260925-mahua-gpu-v1-1-0fa0bfd8d315@oss.qualcomm.com/ --- Documentation/devicetree/bindings/display/msm/gmu.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/msm/gmu.yaml b/Documentation/devicetree/bindings/display/msm/gmu.yaml index 9e459f12ce3f5..f22661447e7c7 100644 --- a/Documentation/devicetree/bindings/display/msm/gmu.yaml +++ b/Documentation/devicetree/bindings/display/msm/gmu.yaml @@ -363,7 +363,7 @@ allOf: properties: compatible: contains: - const: qcom,adreno-gmu-x285.1 + const: qcom,adreno-gmu-x290.1 then: properties: reg: From f2e0341c2789161812e37f45bd945248faba1585 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Fri, 25 Sep 2026 02:44:34 +0530 Subject: [PATCH 02/13] FROMLIST: drm/msm/a8xx: Add Mahua GPU support Add support for Mahua's Adreno X2-85 GPU, which shares the same underlying HW IP with Glymur's Adreno X2-90 GPU. Rework adreno_is_x285() as adreno_is_x285_family() since it doesn't uniquely identify a single chip id anymore. Signed-off-by: Jie Zhang Signed-off-by: Akhil P Oommen Signed-off-by: Kavisha Shah Link: https://lore.kernel.org/lkml/20260925-mahua-gpu-v1-3-0fa0bfd8d315@oss.qualcomm.com/ --- drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 42 +++++++++++++++++++++++ drivers/gpu/drm/msm/adreno/a8xx_gpu.c | 2 +- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 7 ++-- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c index 418edde9104ea..1abdebbff9c1a 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c @@ -2857,6 +2857,48 @@ static const struct adreno_info a8xx_gpus[] = { { 242, 1 }, { 221, 2 }, ), + }, { + .chip_ids = ADRENO_CHIP_IDS(0x44060000), + .family = ADRENO_8XX_GEN2, + .fw = { + [ADRENO_FW_SQE] = "gen80100_sqe.fw", + [ADRENO_FW_GMU] = "gen80100_gmu.bin", + [ADRENO_FW_AQE] = "gen80100_aqe.fw", + }, + .gmem = 15 * SZ_1M + SZ_512K + SZ_256K, + .inactive_period = DRM_MSM_INACTIVE_PERIOD, + .quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT | + ADRENO_QUIRK_HAS_HW_APRIV | + ADRENO_QUIRK_PREEMPTION | + ADRENO_QUIRK_SOFTFUSE, + .funcs = &a8xx_gpu_funcs, + .a6xx = &(const struct a6xx_info) { + .protect = &x285_protect, + .nonctxt_reglist = x285_nonctxt_regs, + .pwrup_reglist = &a840_pwrup_reglist, + .dyn_pwrup_reglist = &x285_dyn_pwrup_reglist, + .ifpc_reglist = &a840_ifpc_reglist, + .gbif_cx = a840_gbif, + .max_slices = 3, + .gmu_chipid = 0x80a0000, + .bcms = (const struct a6xx_bcm[]) { + { .name = "SH0", .buswidth = 16 }, + { .name = "MC0", .buswidth = 4 }, + { + .name = "ACV", + .fixed = true, + .perfmode = BIT(2), + .perfmode_bw = 16500000, + }, + { /* sentinel */ }, + }, + }, + .speedbins = ADRENO_SPEEDBINS( + { 0, 0 }, + { 388, 1 }, + { 357, 2 }, + { 284, 3 }, + ), } }; diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c index 62df0569c62be..0a500869b8cff 100644 --- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c @@ -200,7 +200,7 @@ static void a8xx_set_hwcg(struct msm_gpu *gpu, bool state) struct a6xx_gmu *gmu = &a6xx_gpu->gmu; u32 val; - if ((adreno_is_x285(adreno_gpu) || adreno_is_a830(adreno_gpu)) && state) + if ((adreno_is_x285_family(adreno_gpu) || adreno_is_a830(adreno_gpu)) && state) gpu_write(gpu, REG_A8XX_RBBM_CGC_0_PC, 0x00000702); gmu_write(gmu, REG_A6XX_GPU_GMU_AO_GMU_CGC_MODE_CNTL, diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 338e02271fcc2..5292a08151de0 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -597,9 +597,12 @@ static inline int adreno_is_a810(struct adreno_gpu *gpu) return gpu->info->chip_ids[0] == 0x44010000; } -static inline int adreno_is_x285(struct adreno_gpu *gpu) +static inline int adreno_is_x285_family(const struct adreno_gpu *gpu) { - return gpu->info->chip_ids[0] == 0x44070001; + if (WARN_ON_ONCE(!gpu->info)) + return false; + return gpu->info->chip_ids[0] == 0x44060000 || + gpu->info->chip_ids[0] == 0x44070001; } static inline int adreno_is_a830(struct adreno_gpu *gpu) From f886be49cd3472984e375abad4f3c185625ac2e0 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Fri, 25 Sep 2026 02:44:35 +0530 Subject: [PATCH 03/13] FROMLIST: dt-bindings: display/msm: gpu: Document Mahua GPU/GMU Adreno X2-85 GPU found in mahua SoC belongs to the A8x family and is a smaller variant of X2-90 with fewer slices and smaller internal memories. Update the dt bindings documentation to describe this GPU along with it's GMU. Signed-off-by: Jie Zhang Signed-off-by: Akhil P Oommen Signed-off-by: Kavisha Shah Link: https://lore.kernel.org/lkml/20260925-mahua-gpu-v1-4-0fa0bfd8d315@oss.qualcomm.com/ --- Documentation/devicetree/bindings/display/msm/gmu.yaml | 4 +++- Documentation/devicetree/bindings/display/msm/gpu.yaml | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/msm/gmu.yaml b/Documentation/devicetree/bindings/display/msm/gmu.yaml index f22661447e7c7..d10d6147358e9 100644 --- a/Documentation/devicetree/bindings/display/msm/gmu.yaml +++ b/Documentation/devicetree/bindings/display/msm/gmu.yaml @@ -363,7 +363,9 @@ allOf: properties: compatible: contains: - const: qcom,adreno-gmu-x290.1 + enum: + - qcom,adreno-gmu-x285.0 + - qcom,adreno-gmu-x290.1 then: properties: reg: diff --git a/Documentation/devicetree/bindings/display/msm/gpu.yaml b/Documentation/devicetree/bindings/display/msm/gpu.yaml index e5efe2d35ddcc..8a103f998dd87 100644 --- a/Documentation/devicetree/bindings/display/msm/gpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/gpu.yaml @@ -452,6 +452,7 @@ allOf: - qcom,adreno-43051401 - qcom,adreno-44010000 - qcom,adreno-44050a01 + - qcom,adreno-44060000 - qcom,adreno-44070001 then: # Starting with A6xx, the clocks are usually defined in the GMU node From c3dd360621553dca4c58eae97aa2269cdd9e169d Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Wed, 23 Sep 2026 15:55:41 +0530 Subject: [PATCH 04/13] FROMLIST: drm/msm/a6xx: Honor perfmode_bw threshold on A8x Instead of voting ACV for all bw corners for A8x GPU, restrict it to BW votes above the perfmode_bw threshold, similar to the A7x GPUs. Fixes: 288a93200892 ("drm/msm/adreno: Introduce A8x GPU Support") Signed-off-by: Akhil P Oommen Signed-off-by: Kavisha Shah Link: https://lore.kernel.org/lkml/20260923-hawi-gpu-v1-1-0c3c79a1a470@oss.qualcomm.com/ Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 8 ++++++-- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 27cac853975f9..426df5686d0c4 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1656,8 +1656,12 @@ static int a6xx_gmu_rpmh_bw_votes_init(struct adreno_gpu *adreno_gpu, if (bcm->fixed) { u32 perfmode = 0; - /* GMU on A6xx votes perfmode on all valid bandwidth */ - if (!adreno_is_a7xx(adreno_gpu) || + /* + * GMU on A6xx votes perfmode on all valid + * bandwidth. A7xx and A8xx only vote perfmode + * above the perfmode_bw threshold. + */ + if (adreno_is_a6xx(adreno_gpu) || (bcm->perfmode_bw && bw >= bcm->perfmode_bw)) perfmode = bcm->perfmode; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 5292a08151de0..1daf905e371b8 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -580,6 +580,11 @@ static inline int adreno_is_a750_family(struct adreno_gpu *gpu) return gpu->info->family == ADRENO_7XX_GEN3; } +static inline int adreno_is_a6xx(struct adreno_gpu *gpu) +{ + return (gpu->info->family >= ADRENO_6XX_GEN1) && (gpu->info->family < ADRENO_7XX_GEN1); +} + static inline int adreno_is_a7xx(struct adreno_gpu *gpu) { /* Update with non-fake (i.e. non-A702) Gen 7 GPUs */ From fce4fbf0b578c76572e9d53e1ae12683e1550288 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Wed, 23 Sep 2026 15:55:42 +0530 Subject: [PATCH 05/13] FROMLIST: drm/msm/a6xx: Fix secondary rail vote in ARC votes Using the requested level can pick a secondary corner lower than the one required to support the chosen primary corner, under-voting the dependent rail. To fix this, match against the selected primary voltage instead. Fixes: 4b565ca5a2cb ("drm/msm: Add A6XX device support") Reviewed-by: Konrad Dybcio Signed-off-by: Akhil P Oommen Signed-off-by: Kavisha Shah Link: https://lore.kernel.org/lkml/20260923-hawi-gpu-v1-2-0c3c79a1a470@oss.qualcomm.com/ --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 426df5686d0c4..31bbe4d11d7ba 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1765,10 +1765,14 @@ static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, /* * Look for a level in in the secondary list that matches. If * nothing fits, use the maximum non zero vote + * + * The secondary rail depends on the primary rail, so match it + * against the quantized primary voltage (which is >= the + * requested level), not the requested level itself. */ for (j = 0; j < sec_count; j++) { - if (sec[j] >= level) { + if (sec[j] >= pri[pindex]) { sindex = j; break; } else if (sec[j]) { From 64434b23f5ecaaa4679dc18a25ae9955ab7a080e Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Wed, 23 Sep 2026 15:55:43 +0530 Subject: [PATCH 06/13] FROMLIST: drm/msm/a6xx: Fix RPMH dependency votes a6xx_gmu_rpmh_dep_votes_init() iterates the GPU frequency list (gmu->gpu_freqs) but was passed gmu->dev to resolve each frequency to an arc level. This results in generation of incorrect dependency votes table. To fix this, pass gpu->pdev->dev, which owns the GPU OPP table. Also, reorder the dependency vote init to improve clarity. Fixes: 06cfbca0e1c6 ("drm/msm/a6xx: Share dependency vote table with GMU") Reviewed-by: Konrad Dybcio Signed-off-by: Akhil P Oommen Signed-off-by: Kavisha Shah Link: https://lore.kernel.org/lkml/20260923-hawi-gpu-v1-3-0c3c79a1a470@oss.qualcomm.com/ Reviewed-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 31bbe4d11d7ba..a870226a6baed 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1868,13 +1868,13 @@ static int a6xx_gmu_rpmh_votes_init(struct a6xx_gmu *gmu) ret = a6xx_gmu_rpmh_arc_votes_init(&gpu->pdev->dev, gmu->gx_arc_votes, gmu->gpu_freqs, gmu->nr_gpu_freqs, "gfx.lvl", sec_id); + ret |= a6xx_gmu_rpmh_dep_votes_init(&gpu->pdev->dev, gmu->dep_arc_votes, + gmu->gpu_freqs, gmu->nr_gpu_freqs); + /* 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", "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) ret |= a6xx_gmu_rpmh_bw_votes_init(adreno_gpu, info, gmu); From 6485ee5b12047fda5692be742401269c23509935 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Wed, 23 Sep 2026 15:55:44 +0530 Subject: [PATCH 07/13] FROMLIST: drm/msm/a6xx: Factor out RPMh arc-vote helpers The GMU RPMh vote construction repeats two patterns across a6xx_gmu_rpmh_arc_votes_init() and a6xx_gmu_rpmh_dep_votes_init(): reading a cmd-db aux-data resource (with the same "halve the byte count and reject empty" handling), and scanning an arc level array for the first corner that satisfies a target level. Refactor out a6xx_gmu_rpmh_read_arc() and a6xx_gmu_rpmh_arc_index() to reduce code duplication and improve code readability. Assisted-by: LLM Signed-off-by: Akhil P Oommen Signed-off-by: Kavisha Shah Link: https://lore.kernel.org/lkml/20260923-hawi-gpu-v1-4-0c3c79a1a470@oss.qualcomm.com/ --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 138 ++++++++++++-------------- 1 file changed, 63 insertions(+), 75 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index a870226a6baed..bc935c9cccdde 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1711,74 +1711,85 @@ static unsigned int a6xx_gmu_get_arc_level(struct device *dev, return val; } +static const u16 *a6xx_gmu_rpmh_read_arc(const char *id, size_t *count) +{ + const u16 *vals; + + vals = cmd_db_read_aux_data(id, count); + if (IS_ERR(vals)) + return vals; + + *count >>= 1; + /* Exclude the trailing zero paddings if there are any */ + while (*count && !vals[*count - 1]) + (*count)--; + + if (!*count) + return ERR_PTR(-EINVAL); + + return vals; +} + +/* + * Find the first index in an arc level array whose level is greater than or + * equal to the target. If no level is high enough, either clamp to the + * highest available level (@clamp) or fail, dumping the list. + */ +static int a6xx_gmu_rpmh_arc_index(struct device *dev, const u16 *arc, + size_t arc_count, unsigned int level, bool clamp) +{ + int j; + + for (j = 0; j < arc_count; j++) { + if (arc[j] >= level) + return j; + } + + if (clamp) + return arc_count - 1; + + DRM_DEV_ERROR(dev, "Level %u not found in the RPMh list\n", level); + DRM_DEV_ERROR(dev, "Available levels:\n"); + for (j = 0; j < arc_count; j++) + DRM_DEV_ERROR(dev, " %u\n", arc[j]); + + return -EINVAL; +} + static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, unsigned long *freqs, int freqs_count, const char *pri_id, const char *sec_id) { - int i, j; + int i; const u16 *pri, *sec; size_t pri_count, sec_count; - pri = cmd_db_read_aux_data(pri_id, &pri_count); + pri = a6xx_gmu_rpmh_read_arc(pri_id, &pri_count); if (IS_ERR(pri)) return PTR_ERR(pri); - /* - * The data comes back as an array of unsigned shorts so adjust the - * count accordingly - */ - pri_count >>= 1; - if (!pri_count) - return -EINVAL; - sec = cmd_db_read_aux_data(sec_id, &sec_count); + sec = a6xx_gmu_rpmh_read_arc(sec_id, &sec_count); if (IS_ERR(sec)) return PTR_ERR(sec); - sec_count >>= 1; - if (!sec_count) - return -EINVAL; - /* Construct a vote for each frequency */ for (i = 0; i < freqs_count; i++) { - u8 pindex = 0, sindex = 0; unsigned int level = a6xx_gmu_get_arc_level(dev, freqs[i]); + int pindex, sindex; - /* Get the primary index that matches the arc level */ - for (j = 0; j < pri_count; j++) { - if (pri[j] >= level) { - pindex = j; - break; - } - } - - if (j == pri_count) { - DRM_DEV_ERROR(dev, - "Level %u not found in the RPMh list\n", - level); - DRM_DEV_ERROR(dev, "Available levels:\n"); - for (j = 0; j < pri_count; j++) - DRM_DEV_ERROR(dev, " %u\n", pri[j]); - - return -EINVAL; - } + pindex = a6xx_gmu_rpmh_arc_index(dev, pri, pri_count, level, false); + if (pindex < 0) + return pindex; /* - * Look for a level in in the secondary list that matches. If - * nothing fits, use the maximum non zero vote - * - * The secondary rail depends on the primary rail, so match it - * against the quantized primary voltage (which is >= the - * requested level), not the requested level itself. + * Look for a matching level in the secondary list; if nothing + * fits, clamp to the highest available vote. The secondary rail + * depends on the primary rail, so match it against the selected + * primary voltage (which is >= the requested level), not the + * requested level itself. */ - - for (j = 0; j < sec_count; j++) { - if (sec[j] >= pri[pindex]) { - sindex = j; - break; - } else if (sec[j]) { - sindex = j; - } - } + sindex = a6xx_gmu_rpmh_arc_index(dev, sec, sec_count, + pri[pindex], true); /* Construct the vote */ votes[i] = ((pri[pindex] & 0xffff) << 16) | @@ -1794,16 +1805,9 @@ static int a6xx_gmu_rpmh_dep_votes_init(struct device *dev, u32 *votes, const u16 *mx; size_t count; - mx = cmd_db_read_aux_data("mx.lvl", &count); + mx = a6xx_gmu_rpmh_read_arc("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; @@ -1811,26 +1815,10 @@ static int a6xx_gmu_rpmh_dep_votes_init(struct device *dev, u32 *votes, /* Construct a vote for rest of the corners */ for (int i = 1; i < freqs_count; i++) { unsigned int level = a6xx_gmu_get_arc_level(dev, freqs[i]); - u8 j, index = 0; + int index = a6xx_gmu_rpmh_arc_index(dev, mx, count, level, false); - /* 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; - } + if (index < 0) + return index; /* Construct the vote */ votes[i] = (0x3fff << 14) | (index << 8) | (0xff); From 375f5ba615980bf5a86d1002b061eff0eb70e6b4 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Wed, 23 Sep 2026 15:55:45 +0530 Subject: [PATCH 08/13] FROMLIST: drm/msm/a6xx: Add BX rail support to GMU dependency votes Some A8x targets have a third memory rail (BX) in addition to GX and MX. On these targets the GMU dependency vote carries a per-corner BX vote in bits 25:20, which otherwise default to all-ones (no BX constraint). Prepare BX vote field to pass this new voltage recommendation to GMU. Signed-off-by: Akhil P Oommen Signed-off-by: Kavisha Shah Link: https://lore.kernel.org/lkml/20260923-hawi-gpu-v1-5-0c3c79a1a470@oss.qualcomm.com/ --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 37 +++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index bc935c9cccdde..c725830a0053c 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1799,16 +1799,34 @@ static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, return 0; } +#define GMU_BX_MASK GENMASK(25, 20) + 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; + const u16 *mx, *gx = NULL, *gbx; + size_t count, gx_count = 0, gbx_count = 0; mx = a6xx_gmu_rpmh_read_arc("mx.lvl", &count); if (IS_ERR(mx)) return PTR_ERR(mx); + /* + * Targets with a third memory rail (BX), in addition to GX and MX, + * expect a per-corner BX vote packed into the dependency vote. Detect + * such targets by the presence of the "gbx.lvl" RPMh resource. The BX + * corner is matched against the Gx rail level, so the "gfx.lvl" corners + * are needed as well. + */ + gbx = a6xx_gmu_rpmh_read_arc("gbx.lvl", &gbx_count); + if (IS_ERR(gbx)) { + gbx = NULL; + } else { + gx = a6xx_gmu_rpmh_read_arc("gfx.lvl", &gx_count); + if (IS_ERR(gx)) + return PTR_ERR(gx); + } + /* Fix the vote for zero frequency */ votes[0] = 0xffffffff; @@ -1816,12 +1834,27 @@ static int a6xx_gmu_rpmh_dep_votes_init(struct device *dev, u32 *votes, for (int i = 1; i < freqs_count; i++) { unsigned int level = a6xx_gmu_get_arc_level(dev, freqs[i]); int index = a6xx_gmu_rpmh_arc_index(dev, mx, count, level, false); + int bx; if (index < 0) return index; /* Construct the vote */ votes[i] = (0x3fff << 14) | (index << 8) | (0xff); + + if (!gbx) + continue; + + index = a6xx_gmu_rpmh_arc_index(dev, gx, gx_count, level, false); + if (index < 0) + return index; + + /* + * Find the BX corner that satisfies that Gx level, falling + * back to the highest BX corner if none is high enough. + */ + bx = a6xx_gmu_rpmh_arc_index(dev, gbx, gbx_count, gx[index], true); + FIELD_MODIFY(GMU_BX_MASK, &votes[i], bx); } return 0; From e08c126717fdc35689ab568813e454d43254e407 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Wed, 23 Sep 2026 15:55:46 +0530 Subject: [PATCH 09/13] FROMLIST: drm/msm/a6xx: Clamp MX dependency vote In some chipsets like Hawi, the GPU arc level can exceed the highest available MX corner. In that case, use the highest non-zero MX vote instead of failing GMU initialization. Signed-off-by: Akhil P Oommen Signed-off-by: Kavisha Shah Link: https://lore.kernel.org/lkml/20260923-hawi-gpu-v1-6-0c3c79a1a470@oss.qualcomm.com/ Reviewed-by: Konrad Dybcio --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index c725830a0053c..e0e25833e1969 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1833,7 +1833,7 @@ static int a6xx_gmu_rpmh_dep_votes_init(struct device *dev, u32 *votes, /* Construct a vote for rest of the corners */ for (int i = 1; i < freqs_count; i++) { unsigned int level = a6xx_gmu_get_arc_level(dev, freqs[i]); - int index = a6xx_gmu_rpmh_arc_index(dev, mx, count, level, false); + int index = a6xx_gmu_rpmh_arc_index(dev, mx, count, level, true); int bx; if (index < 0) From 8c6c6a4fb832bfaa087fea6643f6d17291a93d18 Mon Sep 17 00:00:00 2001 From: Wangao Wang Date: Wed, 12 Aug 2026 14:29:00 +0800 Subject: [PATCH 10/13] FROMLIST: soc: qcom: ubwc: Add configuration for Hawi Add UBWC configuration data for the Hawi platform, which uses UBWC 7.0 and enables the required flags and highest bank bit settings. This allows drivers to query the correct UBWC capabilities on Hawi. Also add UBWC 7.0 support to the version tag helper so that qcom_ubwc_version_tag() returns the correct tag for UBWC 7.0. Signed-off-by: Wangao Wang Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/lkml/20260812-ubwc_for_hawi_maili-v1-1-c29edecb3bd8@oss.qualcomm.com/ Signed-off-by: Bjorn Andersson Signed-off-by: Kavisha Shah --- drivers/soc/qcom/ubwc_config.c | 8 ++++++++ include/linux/soc/qcom/ubwc.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c index 23901a4c51f73..428a3d1038c8e 100644 --- a/drivers/soc/qcom/ubwc_config.c +++ b/drivers/soc/qcom/ubwc_config.c @@ -105,6 +105,13 @@ static const struct qcom_ubwc_cfg_data milos_data = { .highest_bank_bit = 15, }; +static const struct qcom_ubwc_cfg_data ubwc_7_0_hbb16 = { + .ubwc_enc_version = UBWC_7_0, + .flags = UBWC_SWIZZLE_ENABLE_LVL2 | + UBWC_SWIZZLE_ENABLE_LVL3, + .highest_bank_bit = 16, +}; + static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = { { .compatible = "qcom,apq8016", .data = &no_ubwc_data }, { .compatible = "qcom,apq8026", .data = &no_ubwc_data }, @@ -112,6 +119,7 @@ static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = { { .compatible = "qcom,apq8096", .data = &ubwc_1_0_hbb15 }, { .compatible = "qcom,eliza", .data = &ubwc_5_0_hbb15 }, { .compatible = "qcom,glymur", .data = &glymur_data}, + { .compatible = "qcom,hawi", .data = &ubwc_7_0_hbb16 }, { .compatible = "qcom,kaanapali", .data = &ubwc_6_0_hbb16 }, { .compatible = "qcom,mahua", .data = &glymur_data }, { .compatible = "qcom,milos", .data = &milos_data }, diff --git a/include/linux/soc/qcom/ubwc.h b/include/linux/soc/qcom/ubwc.h index f3a70360b177b..b09ae05cbeae4 100644 --- a/include/linux/soc/qcom/ubwc.h +++ b/include/linux/soc/qcom/ubwc.h @@ -36,6 +36,7 @@ struct qcom_ubwc_cfg_data { #define UBWC_4_3 0x40030000 #define UBWC_5_0 0x50000000 #define UBWC_6_0 0x60000000 +#define UBWC_7_0 0x70000000 #if IS_ENABLED(CONFIG_QCOM_UBWC_CONFIG) const struct qcom_ubwc_cfg_data *qcom_ubwc_config_get_data(void); @@ -108,6 +109,8 @@ static inline u32 qcom_ubwc_swizzle(const struct qcom_ubwc_cfg_data *cfg) static inline u32 qcom_ubwc_version_tag(const struct qcom_ubwc_cfg_data *cfg) { + if (cfg->ubwc_enc_version >= UBWC_7_0) + return 6; if (cfg->ubwc_enc_version >= UBWC_6_0) return 5; if (cfg->ubwc_enc_version >= UBWC_5_0) From edbbc609fd7eb48f0ce310079d1f50dc6da8e22d Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Wed, 23 Sep 2026 15:55:47 +0530 Subject: [PATCH 11/13] FROMLIST: drm/msm/a8xx: Add Adreno 850 support Adreno 850 is the next generation of A8x GPU present in Hawi SoC. It shares the ADRENO_8XX_GEN2 family and slice architecture with A840, but has many architectural improvements. There is a new block Matrix ALU (MALU) which helps to accelerate certain compute workloads. Also, there is a new Bx rail that powers a part of the GPU IP. GMU is now powered by a dedicated GDSC powered by MxG rail. Add a new catalog entry along with the necessary register lists and additional changes to support the aforementioned new features. Hawi SoC support UBWC v7.0, but GPU is unaffected by this upgrade. Assisted-by: LLM Signed-off-by: Akhil P Oommen Signed-off-by: Kavisha Shah Link: https://lore.kernel.org/lkml/20260923-hawi-gpu-v1-7-0c3c79a1a470@oss.qualcomm.com/ --- drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 343 ++++++++++++++++++ drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 50 ++- drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 1 + drivers/gpu/drm/msm/adreno/a8xx_gpu.c | 16 +- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 5 + drivers/gpu/drm/msm/registers/adreno/a6xx.xml | 8 + 6 files changed, 414 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c index 1abdebbff9c1a..fba652b46e7c3 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c @@ -2685,6 +2685,307 @@ static const struct adreno_reglist_pipe a840_dyn_pwrup_reglist_regs[] = { }; DECLARE_ADRENO_REGLIST_PIPE_LIST(a840_dyn_pwrup_reglist); +static const struct adreno_reglist_pipe a850_nonctxt_regs[] = { + { REG_A8XX_CP_SMMU_STREAM_ID_LPAC, 0x00000101, BIT(PIPE_NONE) }, + { REG_A8XX_CP_MULTIDRAW_CNTL, 0x00000001, BIT(PIPE_NONE) }, + { REG_A8XX_GRAS_DBG_ECO_CNTL, 0x01000800, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_GRAS_TSEFE_DBG_ECO_CNTL, 0x00200000, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_VIS_STREAM_CNTL, 0x10010000, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0x00000002, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_1, 0x00000003, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_2, 0x00000200, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_3, 0x00400000, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_4, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_5, BIT(28), BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A7XX_RB_CCU_CNTL, 0x00000068, BIT(PIPE_BR) }, + { REG_A7XX_RB_CCU_DBG_ECO_CNTL, BIT(10) | BIT(9), BIT(PIPE_BR) }, + { REG_A6XX_RB_DBG_ECO_CNTL, BIT(17), BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_RB_GC_GMEM_PROTECT, 0x12000000, BIT(PIPE_BR) }, + { REG_A6XX_RB_RBP_CNTL, BIT(5) | BIT(6), BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0x00000007, BIT(PIPE_BR) }, + { REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0x00004000, BIT(PIPE_BR) }, + { REG_A8XX_RBBM_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) }, + { REG_A8XX_RBBM_SLICE_NC_MODE_CNTL, 0x00000001, BIT(PIPE_NONE) }, + { REG_A8XX_RBBM_SLICE_PERFCTR_CNTL, BIT(0), BIT(PIPE_NONE) }, + { REG_A8XX_RBBM_POWER_UP_RESET_SW_OVERRIDE, 0x70809060, BIT(PIPE_NONE) }, + { REG_A8XX_RBBM_POWER_UP_RESET_SW_BV_OVERRIDE, 0x30000000, BIT(PIPE_NONE) }, + { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL, 0x00000030, BIT(PIPE_NONE) }, + { REG_A8XX_RBBM_WAIT_IDLE_CLOCKS_CNTL2, 0x00000030, BIT(PIPE_NONE) }, + { REG_A8XX_RBBM_GBIF_CLIENT_QOS_CNTL, 0x22122212, BIT(PIPE_NONE) }, + { REG_A8XX_RBBM_CGC_P2S_CNTL, 0x00000040, BIT(PIPE_NONE) }, + { REG_A6XX_SP_CHICKEN_BITS, BIT(24), BIT(PIPE_NONE) }, + { REG_A7XX_SP_CHICKEN_BITS_2, 0x00820800, BIT(PIPE_NONE) }, + { REG_A7XX_SP_CHICKEN_BITS_3, 0x00300000, BIT(PIPE_NONE) }, + { REG_A8XX_SP_CHICKEN_BITS_5, BIT(3), BIT(PIPE_NONE) }, + { REG_A6XX_SP_PERFCTR_SHADER_MASK, 0x0000003f, BIT(PIPE_NONE) }, + { REG_A7XX_SP_HLSQ_DBG_ECO_CNTL, 0x04000000, BIT(PIPE_NONE) }, + { REG_A7XX_SP_HLSQ_DBG_ECO_CNTL_1, BIT(17), BIT(PIPE_NONE) }, + { REG_A8XX_SP_HLSQ_DBG_ECO_CNTL_3, BIT(1), BIT(PIPE_NONE) }, + { REG_A7XX_SP_HLSQ_TIMEOUT_THRESHOLD_DP, 0x00000080, BIT(PIPE_NONE) }, + { REG_A7XX_SP_READ_SEL, 0x0001ff00, BIT(PIPE_NONE) }, + { REG_A8XX_SP_L0_PERF_TUNE, 0x00000024, BIT(PIPE_NONE) }, + { REG_A6XX_TPL1_DBG_ECO_CNTL, 0x10100000, BIT(PIPE_NONE) }, + { REG_A6XX_TPL1_DBG_ECO_CNTL1, 0x00000720, BIT(PIPE_NONE) }, + { REG_A6XX_UCHE_MODE_CNTL, 0x80080000, BIT(PIPE_NONE) }, + { REG_A8XX_UCHE_CCHE_MODE_CNTL, 0x00001000, BIT(PIPE_NONE) }, + { REG_A8XX_UCHE_DBG_ECO_CNTL_0, BIT(31), BIT(PIPE_NONE) }, + { REG_A8XX_UCHE_HW_DBG_CNTL, 0x01410000, BIT(PIPE_NONE) }, + { REG_A8XX_UCHE_CCHE_CACHE_WAYS, 0x00000800, BIT(PIPE_NONE) }, + { REG_A8XX_UCHE_GBIF_GX_CONFIG, 0x010240e0, BIT(PIPE_NONE) }, + { REG_A8XX_UCHE_VARB_IDLE_TIMEOUT, 0x00000020, BIT(PIPE_NONE) }, + { REG_A7XX_VFD_DBG_ECO_CNTL, 0x00008000, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_BV_THRESHOLD, 0x00500050, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_BR_THRESHOLD, 0x00600060, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0x00200020, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_LP_REQ_CNT, 0x00080020, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0x00000001, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VSC_VISIBILITY_FLUSH_CNTL, 0x00080004, BIT(PIPE_NONE) }, + { }, +}; + +static const u32 a850_protect_regs[] = { + A6XX_PROTECT_RDONLY(0x00008, 0x039b), + A6XX_PROTECT_RDONLY(0x003b4, 0x008b), + A6XX_PROTECT_NORDWR(0x00440, 0x001f), + A6XX_PROTECT_RDONLY(0x00580, 0x005f), + A6XX_PROTECT_NORDWR(0x005e0, 0x011f), + A6XX_PROTECT_RDONLY(0x0074a, 0x0005), + A6XX_PROTECT_RDONLY(0x00759, 0x001b), + A6XX_PROTECT_NORDWR(0x00775, 0x000a), + A6XX_PROTECT_RDONLY(0x00789, 0x0000), + A6XX_PROTECT_RDONLY(0x0078c, 0x0013), + A6XX_PROTECT_NORDWR(0x00800, 0x0029), + A6XX_PROTECT_NORDWR(0x00837, 0x00af), + A6XX_PROTECT_RDONLY(0x008e7, 0x00c9), + A6XX_PROTECT_NORDWR(0x008ec, 0x00c3), + A6XX_PROTECT_NORDWR(0x009b1, 0x0250), + A6XX_PROTECT_NORDWR(0x00c07, 0x0008), + A6XX_PROTECT_RDONLY(0x00ce0, 0x0001), + A6XX_PROTECT_RDONLY(0x00df0, 0x0000), + A6XX_PROTECT_NORDWR(0x00df1, 0x0000), + A6XX_PROTECT_NORDWR(0x00df5, 0x0003), + A6XX_PROTECT_RDONLY(0x00df9, 0x0007), + A6XX_PROTECT_NORDWR(0x00e01, 0x0000), + A6XX_PROTECT_NORDWR(0x00e03, 0x1fff), + A6XX_PROTECT_NORDWR(0x03c00, 0x00c5), + A6XX_PROTECT_RDONLY(0x03cc6, 0x0039), + A6XX_PROTECT_NORDWR(0x03d00, 0x1fff), + A6XX_PROTECT_NORDWR(0x08600, 0x01ff), + A6XX_PROTECT_NORDWR(0x08e00, 0x00ff), + A6XX_PROTECT_RDONLY(0x08f00, 0x0000), + A6XX_PROTECT_NORDWR(0x08f01, 0x01be), + A6XX_PROTECT_NORDWR(0x09600, 0x01ff), + A6XX_PROTECT_RDONLY(0x0981a, 0x02e5), + A6XX_PROTECT_NORDWR(0x09e00, 0x01ff), + A6XX_PROTECT_NORDWR(0x0a600, 0x01ff), + A6XX_PROTECT_NORDWR(0x0a82e, 0x0000), + A6XX_PROTECT_NORDWR(0x0ae00, 0x0000), + A6XX_PROTECT_NORDWR(0x0ae02, 0x0004), + A6XX_PROTECT_NORDWR(0x0ae08, 0x0006), + A6XX_PROTECT_NORDWR(0x0ae10, 0x00bf), + A6XX_PROTECT_RDONLY(0x0aed0, 0x002f), + A6XX_PROTECT_NORDWR(0x0af00, 0x027f), + A6XX_PROTECT_NORDWR(0x0b600, 0x1fff), + A6XX_PROTECT_NORDWR(0x0dc00, 0x1fff), + A6XX_PROTECT_RDONLY(0x0fc00, 0x1fff), + A6XX_PROTECT_NORDWR(0x18400, 0x003f), + A6XX_PROTECT_RDONLY(0x18440, 0x013f), + A6XX_PROTECT_NORDWR(0x18580, 0x1fff), + A6XX_PROTECT_NORDWR(0x1ac00, 0x1fff), + A6XX_PROTECT_NORDWR(0x1cc00, 0x1fff), + A6XX_PROTECT_NORDWR(0x1f400, 0x0477), + A6XX_PROTECT_RDONLY(0x1f878, 0x0507), + A6XX_PROTECT_NORDWR(0x1f930, 0x0329), + A6XX_PROTECT_NORDWR(0x1fd80, 0x1fff), + A6XX_PROTECT_NORDWR(0x27800, 0x007f), + A6XX_PROTECT_RDONLY(0x27880, 0x0385), + A6XX_PROTECT_NORDWR(0x27882, 0x0035), + A6XX_PROTECT_NORDWR(0x27c06, 0x0000), +}; +DECLARE_ADRENO_PROTECT(a850_protect, 15); + +static const u32 a850_pwrup_reglist_regs[] = { + REG_A8XX_RB_CMP_NC_MODE_CNTL, + REG_A8XX_SP_HLSQ_GC_GMEM_RANGE_MIN, + REG_A8XX_SP_HLSQ_GC_GMEM_RANGE_MIN + 1, + REG_A7XX_SP_HLSQ_TIMEOUT_THRESHOLD_DP, + REG_A7XX_SP_READ_SEL, + REG_A8XX_CP_MULTIDRAW_CNTL, + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(0), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(1), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(2), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(3), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(4), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(5), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(6), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(7), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(8), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(9), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(10), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(11), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(12), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(13), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(14), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(15), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(16), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(17), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(18), + REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(19), + REG_A6XX_TPL1_DBG_ECO_CNTL, + REG_A6XX_TPL1_DBG_ECO_CNTL1, + REG_A6XX_TPL1_NC_MODE_CNTL, + REG_A6XX_UCHE_MODE_CNTL, + REG_A8XX_UCHE_CCHE_MODE_CNTL, + REG_A8XX_UCHE_HW_DBG_CNTL, + REG_A8XX_UCHE_CCHE_CACHE_WAYS, + REG_A8XX_UCHE_CCHE_GC_GMEM_RANGE_MIN, + REG_A8XX_UCHE_CCHE_GC_GMEM_RANGE_MIN + 1, + REG_A8XX_UCHE_CCHE_LPAC_GMEM_RANGE_MIN, + REG_A8XX_UCHE_CCHE_LPAC_GMEM_RANGE_MIN + 1, + REG_A8XX_UCHE_CCHE_TRAP_BASE, + REG_A8XX_UCHE_CCHE_TRAP_BASE + 1, + REG_A8XX_UCHE_CCHE_WRITE_THRU_BASE, + REG_A8XX_UCHE_CCHE_WRITE_THRU_BASE + 1, + REG_A8XX_UCHE_CLIENT_PF, + REG_A8XX_UCHE_DBG_ECO_CNTL_0, + REG_A8XX_UCHE_GBIF_GX_CONFIG, + REG_A8XX_UCHE_TRAP_BASE, + REG_A8XX_UCHE_TRAP_BASE + 1, + REG_A8XX_UCHE_VARB_IDLE_TIMEOUT, + REG_A8XX_UCHE_WRITE_THRU_BASE, + REG_A8XX_UCHE_WRITE_THRU_BASE + 1, + REG_A8XX_VSC_VISIBILITY_FLUSH_CNTL, +}; +DECLARE_ADRENO_REGLIST_LIST(a850_pwrup_reglist); + +static const u32 a850_ifpc_reglist_regs[] = { + REG_A8XX_CP_INTERRUPT_STATUS_MASK_GLOBAL, + REG_A8XX_RBBM_NC_MODE_CNTL, + REG_A8XX_RBBM_SLICE_INTERFACE_HANG_INT_CNTL, + REG_A8XX_RBBM_SLICE_NC_MODE_CNTL, + REG_A8XX_RBBM_SLICE_PERFCTR_CNTL, + REG_A6XX_SP_CHICKEN_BITS, + REG_A7XX_SP_CHICKEN_BITS_2, + REG_A7XX_SP_CHICKEN_BITS_3, + REG_A8XX_SP_CHICKEN_BITS_5, + REG_A7XX_SP_HLSQ_DBG_ECO_CNTL, + REG_A7XX_SP_HLSQ_DBG_ECO_CNTL_1, + REG_A8XX_SP_HLSQ_DBG_ECO_CNTL_3, + REG_A8XX_SP_HLSQ_LPAC_GMEM_RANGE_MIN, + REG_A8XX_SP_HLSQ_LPAC_GMEM_RANGE_MIN + 1, + REG_A6XX_SP_NC_MODE_CNTL, + REG_A6XX_SP_PERFCTR_SHADER_MASK, + REG_A8XX_SP_L0_PERF_TUNE, + REG_A8XX_CP_PROTECT_GLOBAL(0), + REG_A8XX_CP_PROTECT_GLOBAL(1), + REG_A8XX_CP_PROTECT_GLOBAL(2), + REG_A8XX_CP_PROTECT_GLOBAL(3), + REG_A8XX_CP_PROTECT_GLOBAL(4), + REG_A8XX_CP_PROTECT_GLOBAL(5), + REG_A8XX_CP_PROTECT_GLOBAL(6), + REG_A8XX_CP_PROTECT_GLOBAL(7), + REG_A8XX_CP_PROTECT_GLOBAL(8), + REG_A8XX_CP_PROTECT_GLOBAL(9), + REG_A8XX_CP_PROTECT_GLOBAL(10), + REG_A8XX_CP_PROTECT_GLOBAL(11), + REG_A8XX_CP_PROTECT_GLOBAL(12), + REG_A8XX_CP_PROTECT_GLOBAL(13), + REG_A8XX_CP_PROTECT_GLOBAL(14), + REG_A8XX_CP_PROTECT_GLOBAL(15), + REG_A8XX_CP_PROTECT_GLOBAL(16), + REG_A8XX_CP_PROTECT_GLOBAL(17), + REG_A8XX_CP_PROTECT_GLOBAL(18), + REG_A8XX_CP_PROTECT_GLOBAL(19), + REG_A8XX_CP_PROTECT_GLOBAL(20), + REG_A8XX_CP_PROTECT_GLOBAL(21), + REG_A8XX_CP_PROTECT_GLOBAL(22), + REG_A8XX_CP_PROTECT_GLOBAL(23), + REG_A8XX_CP_PROTECT_GLOBAL(24), + REG_A8XX_CP_PROTECT_GLOBAL(25), + REG_A8XX_CP_PROTECT_GLOBAL(26), + REG_A8XX_CP_PROTECT_GLOBAL(27), + REG_A8XX_CP_PROTECT_GLOBAL(28), + REG_A8XX_CP_PROTECT_GLOBAL(29), + REG_A8XX_CP_PROTECT_GLOBAL(30), + REG_A8XX_CP_PROTECT_GLOBAL(31), + REG_A8XX_CP_PROTECT_GLOBAL(32), + REG_A8XX_CP_PROTECT_GLOBAL(33), + REG_A8XX_CP_PROTECT_GLOBAL(34), + REG_A8XX_CP_PROTECT_GLOBAL(35), + REG_A8XX_CP_PROTECT_GLOBAL(36), + REG_A8XX_CP_PROTECT_GLOBAL(37), + REG_A8XX_CP_PROTECT_GLOBAL(38), + REG_A8XX_CP_PROTECT_GLOBAL(39), + REG_A8XX_CP_PROTECT_GLOBAL(40), + REG_A8XX_CP_PROTECT_GLOBAL(41), + REG_A8XX_CP_PROTECT_GLOBAL(42), + REG_A8XX_CP_PROTECT_GLOBAL(43), + REG_A8XX_CP_PROTECT_GLOBAL(44), + REG_A8XX_CP_PROTECT_GLOBAL(45), + REG_A8XX_CP_PROTECT_GLOBAL(46), + REG_A8XX_CP_PROTECT_GLOBAL(47), + REG_A8XX_CP_PROTECT_GLOBAL(48), + REG_A8XX_CP_PROTECT_GLOBAL(49), + REG_A8XX_CP_PROTECT_GLOBAL(50), + REG_A8XX_CP_PROTECT_GLOBAL(51), + REG_A8XX_CP_PROTECT_GLOBAL(52), + REG_A8XX_CP_PROTECT_GLOBAL(53), + REG_A8XX_CP_PROTECT_GLOBAL(54), + REG_A8XX_CP_PROTECT_GLOBAL(55), + REG_A8XX_CP_PROTECT_GLOBAL(63), +}; +DECLARE_ADRENO_REGLIST_LIST(a850_ifpc_reglist); + +static const struct adreno_reglist a850_gbif[] = { + { REG_A6XX_GBIF_QSB_SIDE0, 0x00071e20 }, + { REG_A6XX_GBIF_QSB_SIDE1, 0x00071e20 }, + { REG_A6XX_GBIF_QSB_SIDE2, 0x00071e20 }, + { REG_A6XX_GBIF_QSB_SIDE3, 0x00071e20 }, + { REG_A6XX_GBIF_CX_CONFIG, 0x20023020 }, + { }, +}; + +static const struct adreno_reglist_pipe a850_dyn_pwrup_reglist_regs[] = { + { REG_A8XX_GRAS_TSEFE_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_GRAS_NC_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_GRAS_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_1, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_2, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_3, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_4, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CHICKEN_BITS_5, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_PC_VIS_STREAM_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A7XX_RB_CCU_CNTL, 0, BIT(PIPE_BR) }, + { REG_A7XX_RB_CCU_DBG_ECO_CNTL, 0, BIT(PIPE_BR)}, + { REG_A8XX_RB_CCU_NC_MODE_CNTL, 0, BIT(PIPE_BR) }, + { REG_A8XX_RB_CMP_NC_MODE_CNTL, 0, BIT(PIPE_BR) }, + { REG_A6XX_RB_RBP_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0, BIT(PIPE_BR) }, + { REG_A6XX_RB_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0, BIT(PIPE_BR) }, + { REG_A7XX_VFD_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_BV_THRESHOLD, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_BR_THRESHOLD, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VFD_CB_LP_REQ_CNT, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, + { REG_A8XX_CP_HW_FAULT_STATUS_MASK_PIPE, 0, BIT(PIPE_BR) | + BIT(PIPE_BV) | BIT(PIPE_LPAC) | BIT(PIPE_AQE0) | + BIT(PIPE_AQE1) | BIT(PIPE_DDE_BR) | BIT(PIPE_DDE_BV) }, + { REG_A8XX_CP_INTERRUPT_STATUS_MASK_PIPE, 0, BIT(PIPE_BR) | + BIT(PIPE_BV) | BIT(PIPE_LPAC) | BIT(PIPE_AQE0) | + BIT(PIPE_AQE1) | BIT(PIPE_DDE_BR) | BIT(PIPE_DDE_BV) }, + { REG_A8XX_CP_PROTECT_CNTL_PIPE, 0, BIT(PIPE_BR) | BIT(PIPE_BV) | BIT(PIPE_LPAC) }, + { REG_A8XX_CP_PROTECT_PIPE(15), 0, BIT(PIPE_BR) | BIT(PIPE_BV) | BIT(PIPE_LPAC) }, + { REG_A8XX_RB_GC_GMEM_PROTECT, 0, BIT(PIPE_BR) }, + { REG_A8XX_RB_LPAC_GMEM_PROTECT, 0, BIT(PIPE_BR) }, + { REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE_ENABLE, 0, BIT(PIPE_BR) }, +}; +DECLARE_ADRENO_REGLIST_PIPE_LIST(a850_dyn_pwrup_reglist); + static const struct adreno_info a8xx_gpus[] = { { .chip_ids = ADRENO_CHIP_IDS(0x44050001), @@ -2899,6 +3200,48 @@ static const struct adreno_info a8xx_gpus[] = { { 357, 2 }, { 284, 3 }, ), + }, { + .chip_ids = ADRENO_CHIP_IDS(0x44051401), + .family = ADRENO_8XX_GEN2, + .fw = { + [ADRENO_FW_SQE] = "gen81100_sqe.fw", + [ADRENO_FW_GMU] = "gen81100_gmu.bin", + [ADRENO_FW_AQE] = "gen81100_aqe.fw", + }, + .gmem = 18 * SZ_1M, + .inactive_period = DRM_MSM_INACTIVE_PERIOD, + .quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT | + ADRENO_QUIRK_HAS_HW_APRIV | + ADRENO_QUIRK_PREEMPTION | + ADRENO_QUIRK_IFPC, + .funcs = &a8xx_gpu_funcs, + .a6xx = &(const struct a6xx_info) { + .protect = &a850_protect, + .nonctxt_reglist = a850_nonctxt_regs, + .pwrup_reglist = &a850_pwrup_reglist, + .dyn_pwrup_reglist = &a850_dyn_pwrup_reglist, + .ifpc_reglist = &a850_ifpc_reglist, + .gbif_cx = a850_gbif, + .max_slices = 3, + .gmu_chipid = 0x80b0100, + .bcms = (const struct a6xx_bcm[]) { + { .name = "SH0", .buswidth = 32 }, + { .name = "MC0", .buswidth = 4 }, + { + .name = "ACV", + .fixed = true, + .perfmode = BIT(2), + .perfmode_bw = 16500000, + }, + { /* sentinel */ }, + }, + }, + .preempt_record_size = 19708 * SZ_1K, + .speedbins = ADRENO_SPEEDBINS( + { 0, 0 }, + { 284, 2 }, + { 216, 3 }, + ), } }; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index e0e25833e1969..17682832c045a 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -145,6 +145,19 @@ bool a8xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu) if (!gmu->initialized) return false; + /* + * Use the CX_MISC_GFX_PWR_CLK_STATUS register instead of the GMUCX + * register to ensure correct GDSC and clock status reporting even + * when the GMU MX domain is powered off + */ + if (adreno_is_a850(adreno_gpu)) { + val = a6xx_cx_misc_read(a6xx_gpu, REG_A8XX_CX_MISC_GFX_PWR_CLK_STATUS); + + return !(val & + (A8XX_CX_MISC_GFX_PWR_CLK_STATUS_GX_GDSC_POWER_OFF | + A8XX_CX_MISC_GFX_PWR_CLK_STATUS_GX_CLK_OFF)); + } + val = gmu_read(gmu, REG_A8XX_GMU_PWR_CLK_STATUS); return !(val & @@ -645,7 +658,7 @@ static void a6xx_rpmh_stop(struct a6xx_gmu *gmu) if (!test_and_clear_bit(GMU_STATUS_FW_START, &gmu->status)) return; - if (adreno_is_a840(adreno_gpu)) + if (adreno_is_a840(adreno_gpu) || adreno_is_a850(adreno_gpu)) bitmask = BIT(30); gmu_write(gmu, REG_A6XX_GMU_RSCC_CONTROL_REQ, 1); @@ -2170,6 +2183,9 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu) dev_pm_domain_detach(gmu->gxpd, false); } + if (!IS_ERR_OR_NULL(gmu->gmu_mxpd)) + dev_pm_domain_detach(gmu->gmu_mxpd, false); + if (!IS_ERR_OR_NULL(gmu->qmp)) qmp_put(gmu->qmp); @@ -2314,7 +2330,8 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; struct msm_gpu *gpu = &adreno_gpu->base; struct a6xx_gmu *gmu = &a6xx_gpu->gmu; - struct device_link *link; + struct device_link *gmu_mx_link = NULL; + struct device_link *cx_link; resource_size_t start; struct resource *res; int ret; @@ -2461,12 +2478,27 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) goto err_mmio; } - link = device_link_add(gmu->dev, gmu->cxpd, DL_FLAG_PM_RUNTIME); - if (!link) { + cx_link = device_link_add(gmu->dev, gmu->cxpd, DL_FLAG_PM_RUNTIME); + if (!cx_link) { ret = -ENODEV; goto detach_cxpd; } + /* Optionally attach the GMU MX power domain */ + gmu->gmu_mxpd = dev_pm_domain_attach_by_name(gmu->dev, "gmu_mx"); + if (IS_ERR(gmu->gmu_mxpd)) { + ret = PTR_ERR(gmu->gmu_mxpd); + goto detach_cxpd_link; + } + + if (gmu->gmu_mxpd) { + gmu_mx_link = device_link_add(gmu->dev, gmu->gmu_mxpd, DL_FLAG_PM_RUNTIME); + if (!gmu_mx_link) { + ret = -ENODEV; + goto detach_gmu_mxpd; + } + } + /* Other errors are handled during GPU ACD probe */ gmu->qmp = qmp_get(gmu->dev); if (PTR_ERR_OR_ZERO(gmu->qmp) == -EPROBE_DEFER) { @@ -2508,7 +2540,15 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) if (!IS_ERR_OR_NULL(gmu->qmp)) qmp_put(gmu->qmp); - device_link_del(link); + if (!IS_ERR_OR_NULL(gmu_mx_link)) + device_link_del(gmu_mx_link); + +detach_gmu_mxpd: + if (gmu->gmu_mxpd) + dev_pm_domain_detach(gmu->gmu_mxpd, false); + +detach_cxpd_link: + device_link_del(cx_link); detach_cxpd: dev_pm_domain_detach(gmu->cxpd, false); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h index 3f96b10b5f61a..d3f6cd8b97413 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h @@ -77,6 +77,7 @@ struct a6xx_gmu { struct device *gxpd; struct device *cxpd; + struct device *gmu_mxpd; int idle_level; diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c index 0a500869b8cff..5fdc6fbafeee9 100644 --- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c @@ -286,10 +286,11 @@ static void a8xx_set_ubwc_config(struct msm_gpu *gpu) u32 hbb, hbb_hi, hbb_lo, mode; u8 uavflagprd_inv = 2; - if (ubwc_version > UBWC_6_0) + if (ubwc_version > UBWC_7_0) dev_err(&gpu->pdev->dev, "Unknown UBWC version: 0x%x\n", ubwc_version); - if (ubwc_version == UBWC_6_0) + if (ubwc_version == UBWC_6_0 || + ubwc_version == UBWC_7_0) yuvnotcomptofc = true; if (ubwc_version < UBWC_5_0 && @@ -726,6 +727,7 @@ static int hw_init(struct msm_gpu *gpu) for (pipe_id = PIPE_BR; pipe_id <= PIPE_DDE_BV; pipe_id++) { u32 apriv_mask = A8XX_APRIV_MASK; + u32 int_mask = A8XX_CP_INTERRUPT_STATUS_MASK_PIPE; unsigned long flags; if (pipe_id == PIPE_LPAC) @@ -734,10 +736,16 @@ static int hw_init(struct msm_gpu *gpu) if (pipe_id == PIPE_BR) apriv_mask = A8XX_BR_APRIV_MASK; + /* + * A850's BV pipe raises a spurious RTWROVF fault interrupt; + * mask it off to avoid false fault recovery. + */ + if (adreno_is_a850(adreno_gpu) && pipe_id == PIPE_BV) + int_mask &= ~A8XX_CP_INTERRUPT_STATUS_MASK_PIPE_RTWROVF; + a8xx_aperture_acquire(gpu, pipe_id, &flags); gpu_write(gpu, REG_A8XX_CP_APRIV_CNTL_PIPE, apriv_mask); - gpu_write(gpu, REG_A8XX_CP_INTERRUPT_STATUS_MASK_PIPE, - A8XX_CP_INTERRUPT_STATUS_MASK_PIPE); + gpu_write(gpu, REG_A8XX_CP_INTERRUPT_STATUS_MASK_PIPE, int_mask); gpu_write(gpu, REG_A8XX_CP_HW_FAULT_STATUS_MASK_PIPE, A8XX_CP_HW_FAULT_STATUS_MASK_PIPE); a8xx_aperture_release(gpu, flags); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 1daf905e371b8..18ea1f433c6ae 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -620,6 +620,11 @@ static inline int adreno_is_a840(struct adreno_gpu *gpu) return gpu->info->chip_ids[0] == 0x44050a01; } +static inline int adreno_is_a850(struct adreno_gpu *gpu) +{ + return gpu->info->chip_ids[0] == 0x44051401; +} + /* 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.xml b/drivers/gpu/drm/msm/registers/adreno/a6xx.xml index 69dd0446f8d2d..e6e56969a9b83 100644 --- a/drivers/gpu/drm/msm/registers/adreno/a6xx.xml +++ b/drivers/gpu/drm/msm/registers/adreno/a6xx.xml @@ -269,6 +269,7 @@ by a particular renderpass/blit. + @@ -1326,6 +1327,7 @@ by a particular renderpass/blit. + @@ -4352,6 +4354,7 @@ by a particular renderpass/blit. +