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: Fix gpu init from secure world

A7XX_GEN2 and newer GPUs requires initialization of few configurations
related to features/power from secure world. The SCM call to do this
should be triggered after GDSC and clocks are enabled. So, keep this
sequence to a6xx_gmu_resume instead of the probe.

Also, simplify the error handling in a6xx_gmu_resume() using 'goto'
labels.

Fixes: 14b27d5df3ea ("drm/msm/a7xx: Initialize a750 "software fuse"")
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
Patchwork: https://patchwork.freedesktop.org/patch/714664/
Message-ID: <20260327-a8xx-gpu-batch2-v2-6-2b53c38d2101@oss.qualcomm.com>
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>

authored by

Akhil P Oommen and committed by
Rob Clark
bb9b1d6e ae25e6e9

+80 -74
+78 -15
drivers/gpu/drm/msm/adreno/a6xx_gmu.c
··· 3 3 4 4 #include <linux/bitfield.h> 5 5 #include <linux/clk.h> 6 + #include <linux/firmware/qcom/qcom_scm.h> 6 7 #include <linux/interconnect.h> 7 8 #include <linux/of_platform.h> 8 9 #include <linux/platform_device.h> ··· 1192 1191 dev_pm_opp_put(gpu_opp); 1193 1192 } 1194 1193 1194 + static int a6xx_gmu_secure_init(struct a6xx_gpu *a6xx_gpu) 1195 + { 1196 + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; 1197 + struct msm_gpu *gpu = &adreno_gpu->base; 1198 + struct a6xx_gmu *gmu = &a6xx_gpu->gmu; 1199 + u32 fuse_val; 1200 + int ret; 1201 + 1202 + if (test_bit(GMU_STATUS_SECURE_INIT, &gmu->status)) 1203 + return 0; 1204 + 1205 + if (adreno_is_a750(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) { 1206 + /* 1207 + * Assume that if qcom scm isn't available, that whatever 1208 + * replacement allows writing the fuse register ourselves. 1209 + * Users of alternative firmware need to make sure this 1210 + * register is writeable or indicate that it's not somehow. 1211 + * Print a warning because if you mess this up you're about to 1212 + * crash horribly. 1213 + */ 1214 + if (!qcom_scm_is_available()) { 1215 + dev_warn_once(gpu->dev->dev, 1216 + "SCM is not available, poking fuse register\n"); 1217 + a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_SW_FUSE_VALUE, 1218 + A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING | 1219 + A7XX_CX_MISC_SW_FUSE_VALUE_FASTBLEND | 1220 + A7XX_CX_MISC_SW_FUSE_VALUE_LPAC); 1221 + adreno_gpu->has_ray_tracing = true; 1222 + goto done; 1223 + } 1224 + 1225 + ret = qcom_scm_gpu_init_regs(QCOM_SCM_GPU_ALWAYS_EN_REQ | 1226 + QCOM_SCM_GPU_TSENSE_EN_REQ); 1227 + if (ret) { 1228 + dev_warn_once(gpu->dev->dev, 1229 + "SCM call failed\n"); 1230 + return ret; 1231 + } 1232 + 1233 + /* 1234 + * On A7XX_GEN3 and newer, raytracing may be disabled by the 1235 + * firmware, find out whether that's the case. The scm call 1236 + * above sets the fuse register. 1237 + */ 1238 + fuse_val = a6xx_llc_read(a6xx_gpu, 1239 + REG_A7XX_CX_MISC_SW_FUSE_VALUE); 1240 + adreno_gpu->has_ray_tracing = 1241 + !!(fuse_val & A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING); 1242 + } else if (adreno_is_a740(adreno_gpu)) { 1243 + /* Raytracing is always enabled on a740 */ 1244 + adreno_gpu->has_ray_tracing = true; 1245 + } 1246 + 1247 + done: 1248 + set_bit(GMU_STATUS_SECURE_INIT, &gmu->status); 1249 + return 0; 1250 + } 1251 + 1252 + 1195 1253 int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) 1196 1254 { 1197 1255 struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; ··· 1279 1219 clk_set_rate(gmu->hub_clk, adreno_is_a740_family(adreno_gpu) ? 1280 1220 200000000 : 150000000); 1281 1221 ret = clk_bulk_prepare_enable(gmu->nr_clocks, gmu->clocks); 1282 - if (ret) { 1283 - pm_runtime_put(gmu->gxpd); 1284 - pm_runtime_put(gmu->dev); 1285 - return ret; 1286 - } 1222 + if (ret) 1223 + goto rpm_put; 1224 + 1225 + ret = a6xx_gmu_secure_init(a6xx_gpu); 1226 + if (ret) 1227 + goto disable_clk; 1287 1228 1288 1229 /* Read the slice info on A8x GPUs */ 1289 1230 a8xx_gpu_get_slice_info(gpu); ··· 1314 1253 1315 1254 ret = a6xx_gmu_fw_start(gmu, status); 1316 1255 if (ret) 1317 - goto out; 1256 + goto disable_irq; 1318 1257 1319 1258 ret = a6xx_hfi_start(gmu, status); 1320 1259 if (ret) 1321 - goto out; 1260 + goto disable_irq; 1322 1261 1323 1262 /* 1324 1263 * Turn on the GMU firmware fault interrupt after we know the boot ··· 1331 1270 /* Set the GPU to the current freq */ 1332 1271 a6xx_gmu_set_initial_freq(gpu, gmu); 1333 1272 1334 - out: 1335 - /* On failure, shut down the GMU to leave it in a good state */ 1336 - if (ret) { 1337 - disable_irq(gmu->gmu_irq); 1338 - a6xx_rpmh_stop(gmu); 1339 - pm_runtime_put(gmu->gxpd); 1340 - pm_runtime_put(gmu->dev); 1341 - } 1273 + return 0; 1274 + 1275 + disable_irq: 1276 + disable_irq(gmu->gmu_irq); 1277 + a6xx_rpmh_stop(gmu); 1278 + disable_clk: 1279 + clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks); 1280 + rpm_put: 1281 + pm_runtime_put(gmu->gxpd); 1282 + pm_runtime_put(gmu->dev); 1342 1283 1343 1284 return ret; 1344 1285 }
+2
drivers/gpu/drm/msm/adreno/a6xx_gmu.h
··· 130 130 #define GMU_STATUS_PDC_SLEEP 1 131 131 /* To track Perfcounter OOB set status */ 132 132 #define GMU_STATUS_OOB_PERF_SET 2 133 + /* To track whether secure world init was done */ 134 + #define GMU_STATUS_SECURE_INIT 3 133 135 unsigned long status; 134 136 }; 135 137
-59
drivers/gpu/drm/msm/adreno/a6xx_gpu.c
··· 10 10 11 11 #include <linux/bitfield.h> 12 12 #include <linux/devfreq.h> 13 - #include <linux/firmware/qcom/qcom_scm.h> 14 13 #include <linux/pm_domain.h> 15 14 #include <linux/soc/qcom/llcc-qcom.h> 16 15 ··· 2159 2160 a6xx_gpu->llc_mmio = ERR_PTR(-EINVAL); 2160 2161 } 2161 2162 2162 - static int a7xx_cx_mem_init(struct a6xx_gpu *a6xx_gpu) 2163 - { 2164 - struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; 2165 - struct msm_gpu *gpu = &adreno_gpu->base; 2166 - u32 fuse_val; 2167 - int ret; 2168 - 2169 - if (adreno_is_a750(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) { 2170 - /* 2171 - * Assume that if qcom scm isn't available, that whatever 2172 - * replacement allows writing the fuse register ourselves. 2173 - * Users of alternative firmware need to make sure this 2174 - * register is writeable or indicate that it's not somehow. 2175 - * Print a warning because if you mess this up you're about to 2176 - * crash horribly. 2177 - */ 2178 - if (!qcom_scm_is_available()) { 2179 - dev_warn_once(gpu->dev->dev, 2180 - "SCM is not available, poking fuse register\n"); 2181 - a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_SW_FUSE_VALUE, 2182 - A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING | 2183 - A7XX_CX_MISC_SW_FUSE_VALUE_FASTBLEND | 2184 - A7XX_CX_MISC_SW_FUSE_VALUE_LPAC); 2185 - adreno_gpu->has_ray_tracing = true; 2186 - return 0; 2187 - } 2188 - 2189 - ret = qcom_scm_gpu_init_regs(QCOM_SCM_GPU_ALWAYS_EN_REQ | 2190 - QCOM_SCM_GPU_TSENSE_EN_REQ); 2191 - if (ret) 2192 - return ret; 2193 - 2194 - /* 2195 - * On A7XX_GEN3 and newer, raytracing may be disabled by the 2196 - * firmware, find out whether that's the case. The scm call 2197 - * above sets the fuse register. 2198 - */ 2199 - fuse_val = a6xx_llc_read(a6xx_gpu, 2200 - REG_A7XX_CX_MISC_SW_FUSE_VALUE); 2201 - adreno_gpu->has_ray_tracing = 2202 - !!(fuse_val & A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING); 2203 - } else if (adreno_is_a740(adreno_gpu)) { 2204 - /* Raytracing is always enabled on a740 */ 2205 - adreno_gpu->has_ray_tracing = true; 2206 - } 2207 - 2208 - return 0; 2209 - } 2210 - 2211 - 2212 2163 #define GBIF_CLIENT_HALT_MASK BIT(0) 2213 2164 #define GBIF_ARB_HALT_MASK BIT(1) 2214 2165 #define VBIF_XIN_HALT_CTRL0_MASK GENMASK(3, 0) ··· 2653 2704 if (ret) { 2654 2705 a6xx_destroy(&(a6xx_gpu->base.base)); 2655 2706 return ERR_PTR(ret); 2656 - } 2657 - 2658 - if (adreno_is_a7xx(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) { 2659 - ret = a7xx_cx_mem_init(a6xx_gpu); 2660 - if (ret) { 2661 - a6xx_destroy(&(a6xx_gpu->base.base)); 2662 - return ERR_PTR(ret); 2663 - } 2664 2707 } 2665 2708 2666 2709 adreno_gpu->uche_trap_base = 0x1fffffffff000ull;