.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2013 Red Hat |
---|
3 | 4 | * Author: Rob Clark <robdclark@gmail.com> |
---|
4 | 5 | * |
---|
5 | 6 | * Copyright (c) 2014 The Linux Foundation. All rights reserved. |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify it |
---|
8 | | - * under the terms of the GNU General Public License version 2 as published by |
---|
9 | | - * the Free Software Foundation. |
---|
10 | | - * |
---|
11 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
---|
12 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
13 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
14 | | - * more details. |
---|
15 | | - * |
---|
16 | | - * You should have received a copy of the GNU General Public License along with |
---|
17 | | - * this program. If not, see <http://www.gnu.org/licenses/>. |
---|
18 | 7 | */ |
---|
19 | 8 | |
---|
20 | 9 | #include <linux/ascii85.h> |
---|
| 10 | +#include <linux/interconnect.h> |
---|
| 11 | +#include <linux/qcom_scm.h> |
---|
21 | 12 | #include <linux/kernel.h> |
---|
| 13 | +#include <linux/of_address.h> |
---|
22 | 14 | #include <linux/pm_opp.h> |
---|
23 | 15 | #include <linux/slab.h> |
---|
| 16 | +#include <linux/soc/qcom/mdt_loader.h> |
---|
| 17 | +#include <soc/qcom/ocmem.h> |
---|
24 | 18 | #include "adreno_gpu.h" |
---|
25 | 19 | #include "msm_gem.h" |
---|
26 | 20 | #include "msm_mmu.h" |
---|
| 21 | + |
---|
| 22 | +static bool zap_available = true; |
---|
| 23 | + |
---|
| 24 | +static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname, |
---|
| 25 | + u32 pasid) |
---|
| 26 | +{ |
---|
| 27 | + struct device *dev = &gpu->pdev->dev; |
---|
| 28 | + const struct firmware *fw; |
---|
| 29 | + const char *signed_fwname = NULL; |
---|
| 30 | + struct device_node *np, *mem_np; |
---|
| 31 | + struct resource r; |
---|
| 32 | + phys_addr_t mem_phys; |
---|
| 33 | + ssize_t mem_size; |
---|
| 34 | + void *mem_region = NULL; |
---|
| 35 | + int ret; |
---|
| 36 | + |
---|
| 37 | + if (!IS_ENABLED(CONFIG_ARCH_QCOM)) { |
---|
| 38 | + zap_available = false; |
---|
| 39 | + return -EINVAL; |
---|
| 40 | + } |
---|
| 41 | + |
---|
| 42 | + np = of_get_child_by_name(dev->of_node, "zap-shader"); |
---|
| 43 | + if (!np) { |
---|
| 44 | + zap_available = false; |
---|
| 45 | + return -ENODEV; |
---|
| 46 | + } |
---|
| 47 | + |
---|
| 48 | + mem_np = of_parse_phandle(np, "memory-region", 0); |
---|
| 49 | + of_node_put(np); |
---|
| 50 | + if (!mem_np) { |
---|
| 51 | + zap_available = false; |
---|
| 52 | + return -EINVAL; |
---|
| 53 | + } |
---|
| 54 | + |
---|
| 55 | + ret = of_address_to_resource(mem_np, 0, &r); |
---|
| 56 | + of_node_put(mem_np); |
---|
| 57 | + if (ret) |
---|
| 58 | + return ret; |
---|
| 59 | + |
---|
| 60 | + mem_phys = r.start; |
---|
| 61 | + |
---|
| 62 | + /* |
---|
| 63 | + * Check for a firmware-name property. This is the new scheme |
---|
| 64 | + * to handle firmware that may be signed with device specific |
---|
| 65 | + * keys, allowing us to have a different zap fw path for different |
---|
| 66 | + * devices. |
---|
| 67 | + * |
---|
| 68 | + * If the firmware-name property is found, we bypass the |
---|
| 69 | + * adreno_request_fw() mechanism, because we don't need to handle |
---|
| 70 | + * the /lib/firmware/qcom/... vs /lib/firmware/... case. |
---|
| 71 | + * |
---|
| 72 | + * If the firmware-name property is not found, for backwards |
---|
| 73 | + * compatibility we fall back to the fwname from the gpulist |
---|
| 74 | + * table. |
---|
| 75 | + */ |
---|
| 76 | + of_property_read_string_index(np, "firmware-name", 0, &signed_fwname); |
---|
| 77 | + if (signed_fwname) { |
---|
| 78 | + fwname = signed_fwname; |
---|
| 79 | + ret = request_firmware_direct(&fw, fwname, gpu->dev->dev); |
---|
| 80 | + if (ret) |
---|
| 81 | + fw = ERR_PTR(ret); |
---|
| 82 | + } else if (fwname) { |
---|
| 83 | + /* Request the MDT file from the default location: */ |
---|
| 84 | + fw = adreno_request_fw(to_adreno_gpu(gpu), fwname); |
---|
| 85 | + } else { |
---|
| 86 | + /* |
---|
| 87 | + * For new targets, we require the firmware-name property, |
---|
| 88 | + * if a zap-shader is required, rather than falling back |
---|
| 89 | + * to a firmware name specified in gpulist. |
---|
| 90 | + * |
---|
| 91 | + * Because the firmware is signed with a (potentially) |
---|
| 92 | + * device specific key, having the name come from gpulist |
---|
| 93 | + * was a bad idea, and is only provided for backwards |
---|
| 94 | + * compatibility for older targets. |
---|
| 95 | + */ |
---|
| 96 | + return -ENODEV; |
---|
| 97 | + } |
---|
| 98 | + |
---|
| 99 | + if (IS_ERR(fw)) { |
---|
| 100 | + DRM_DEV_ERROR(dev, "Unable to load %s\n", fwname); |
---|
| 101 | + return PTR_ERR(fw); |
---|
| 102 | + } |
---|
| 103 | + |
---|
| 104 | + /* Figure out how much memory we need */ |
---|
| 105 | + mem_size = qcom_mdt_get_size(fw); |
---|
| 106 | + if (mem_size < 0) { |
---|
| 107 | + ret = mem_size; |
---|
| 108 | + goto out; |
---|
| 109 | + } |
---|
| 110 | + |
---|
| 111 | + if (mem_size > resource_size(&r)) { |
---|
| 112 | + DRM_DEV_ERROR(dev, |
---|
| 113 | + "memory region is too small to load the MDT\n"); |
---|
| 114 | + ret = -E2BIG; |
---|
| 115 | + goto out; |
---|
| 116 | + } |
---|
| 117 | + |
---|
| 118 | + /* Allocate memory for the firmware image */ |
---|
| 119 | + mem_region = memremap(mem_phys, mem_size, MEMREMAP_WC); |
---|
| 120 | + if (!mem_region) { |
---|
| 121 | + ret = -ENOMEM; |
---|
| 122 | + goto out; |
---|
| 123 | + } |
---|
| 124 | + |
---|
| 125 | + /* |
---|
| 126 | + * Load the rest of the MDT |
---|
| 127 | + * |
---|
| 128 | + * Note that we could be dealing with two different paths, since |
---|
| 129 | + * with upstream linux-firmware it would be in a qcom/ subdir.. |
---|
| 130 | + * adreno_request_fw() handles this, but qcom_mdt_load() does |
---|
| 131 | + * not. But since we've already gotten through adreno_request_fw() |
---|
| 132 | + * we know which of the two cases it is: |
---|
| 133 | + */ |
---|
| 134 | + if (signed_fwname || (to_adreno_gpu(gpu)->fwloc == FW_LOCATION_LEGACY)) { |
---|
| 135 | + ret = qcom_mdt_load(dev, fw, fwname, pasid, |
---|
| 136 | + mem_region, mem_phys, mem_size, NULL); |
---|
| 137 | + } else { |
---|
| 138 | + char *newname; |
---|
| 139 | + |
---|
| 140 | + newname = kasprintf(GFP_KERNEL, "qcom/%s", fwname); |
---|
| 141 | + |
---|
| 142 | + ret = qcom_mdt_load(dev, fw, newname, pasid, |
---|
| 143 | + mem_region, mem_phys, mem_size, NULL); |
---|
| 144 | + kfree(newname); |
---|
| 145 | + } |
---|
| 146 | + if (ret) |
---|
| 147 | + goto out; |
---|
| 148 | + |
---|
| 149 | + /* Send the image to the secure world */ |
---|
| 150 | + ret = qcom_scm_pas_auth_and_reset(pasid); |
---|
| 151 | + |
---|
| 152 | + /* |
---|
| 153 | + * If the scm call returns -EOPNOTSUPP we assume that this target |
---|
| 154 | + * doesn't need/support the zap shader so quietly fail |
---|
| 155 | + */ |
---|
| 156 | + if (ret == -EOPNOTSUPP) |
---|
| 157 | + zap_available = false; |
---|
| 158 | + else if (ret) |
---|
| 159 | + DRM_DEV_ERROR(dev, "Unable to authorize the image\n"); |
---|
| 160 | + |
---|
| 161 | +out: |
---|
| 162 | + if (mem_region) |
---|
| 163 | + memunmap(mem_region); |
---|
| 164 | + |
---|
| 165 | + release_firmware(fw); |
---|
| 166 | + |
---|
| 167 | + return ret; |
---|
| 168 | +} |
---|
| 169 | + |
---|
| 170 | +int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid) |
---|
| 171 | +{ |
---|
| 172 | + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); |
---|
| 173 | + struct platform_device *pdev = gpu->pdev; |
---|
| 174 | + |
---|
| 175 | + /* Short cut if we determine the zap shader isn't available/needed */ |
---|
| 176 | + if (!zap_available) |
---|
| 177 | + return -ENODEV; |
---|
| 178 | + |
---|
| 179 | + /* We need SCM to be able to load the firmware */ |
---|
| 180 | + if (!qcom_scm_is_available()) { |
---|
| 181 | + DRM_DEV_ERROR(&pdev->dev, "SCM is not available\n"); |
---|
| 182 | + return -EPROBE_DEFER; |
---|
| 183 | + } |
---|
| 184 | + |
---|
| 185 | + return zap_shader_load_mdt(gpu, adreno_gpu->info->zapfw, pasid); |
---|
| 186 | +} |
---|
| 187 | + |
---|
| 188 | +struct msm_gem_address_space * |
---|
| 189 | +adreno_iommu_create_address_space(struct msm_gpu *gpu, |
---|
| 190 | + struct platform_device *pdev) |
---|
| 191 | +{ |
---|
| 192 | + struct iommu_domain *iommu; |
---|
| 193 | + struct msm_mmu *mmu; |
---|
| 194 | + struct msm_gem_address_space *aspace; |
---|
| 195 | + u64 start, size; |
---|
| 196 | + |
---|
| 197 | + iommu = iommu_domain_alloc(&platform_bus_type); |
---|
| 198 | + if (!iommu) |
---|
| 199 | + return NULL; |
---|
| 200 | + |
---|
| 201 | + mmu = msm_iommu_new(&pdev->dev, iommu); |
---|
| 202 | + |
---|
| 203 | + /* |
---|
| 204 | + * Use the aperture start or SZ_16M, whichever is greater. This will |
---|
| 205 | + * ensure that we align with the allocated pagetable range while still |
---|
| 206 | + * allowing room in the lower 32 bits for GMEM and whatnot |
---|
| 207 | + */ |
---|
| 208 | + start = max_t(u64, SZ_16M, iommu->geometry.aperture_start); |
---|
| 209 | + size = iommu->geometry.aperture_end - start + 1; |
---|
| 210 | + |
---|
| 211 | + aspace = msm_gem_address_space_create(mmu, "gpu", |
---|
| 212 | + start & GENMASK_ULL(48, 0), size); |
---|
| 213 | + |
---|
| 214 | + if (IS_ERR(aspace) && !IS_ERR(mmu)) |
---|
| 215 | + mmu->funcs->destroy(mmu); |
---|
| 216 | + |
---|
| 217 | + return aspace; |
---|
| 218 | +} |
---|
27 | 219 | |
---|
28 | 220 | int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) |
---|
29 | 221 | { |
---|
.. | .. |
---|
37 | 229 | *value = adreno_gpu->gmem; |
---|
38 | 230 | return 0; |
---|
39 | 231 | case MSM_PARAM_GMEM_BASE: |
---|
40 | | - *value = 0x100000; |
---|
| 232 | + *value = !adreno_is_a650(adreno_gpu) ? 0x100000 : 0; |
---|
41 | 233 | return 0; |
---|
42 | 234 | case MSM_PARAM_CHIP_ID: |
---|
43 | 235 | *value = adreno_gpu->rev.patchid | |
---|
.. | .. |
---|
61 | 253 | return -EINVAL; |
---|
62 | 254 | case MSM_PARAM_NR_RINGS: |
---|
63 | 255 | *value = gpu->nr_rings; |
---|
| 256 | + return 0; |
---|
| 257 | + case MSM_PARAM_PP_PGTABLE: |
---|
| 258 | + *value = 0; |
---|
| 259 | + return 0; |
---|
| 260 | + case MSM_PARAM_FAULTS: |
---|
| 261 | + *value = gpu->global_faults; |
---|
64 | 262 | return 0; |
---|
65 | 263 | default: |
---|
66 | 264 | DBG("%s: invalid param: %u", gpu->name, param); |
---|
.. | .. |
---|
89 | 287 | |
---|
90 | 288 | ret = request_firmware_direct(&fw, newname, drm->dev); |
---|
91 | 289 | if (!ret) { |
---|
92 | | - dev_info(drm->dev, "loaded %s from new location\n", |
---|
| 290 | + DRM_DEV_INFO(drm->dev, "loaded %s from new location\n", |
---|
93 | 291 | newname); |
---|
94 | 292 | adreno_gpu->fwloc = FW_LOCATION_NEW; |
---|
95 | 293 | goto out; |
---|
96 | 294 | } else if (adreno_gpu->fwloc != FW_LOCATION_UNKNOWN) { |
---|
97 | | - dev_err(drm->dev, "failed to load %s: %d\n", |
---|
| 295 | + DRM_DEV_ERROR(drm->dev, "failed to load %s: %d\n", |
---|
98 | 296 | newname, ret); |
---|
99 | 297 | fw = ERR_PTR(ret); |
---|
100 | 298 | goto out; |
---|
.. | .. |
---|
109 | 307 | |
---|
110 | 308 | ret = request_firmware_direct(&fw, fwname, drm->dev); |
---|
111 | 309 | if (!ret) { |
---|
112 | | - dev_info(drm->dev, "loaded %s from legacy location\n", |
---|
| 310 | + DRM_DEV_INFO(drm->dev, "loaded %s from legacy location\n", |
---|
113 | 311 | newname); |
---|
114 | 312 | adreno_gpu->fwloc = FW_LOCATION_LEGACY; |
---|
115 | 313 | goto out; |
---|
116 | 314 | } else if (adreno_gpu->fwloc != FW_LOCATION_UNKNOWN) { |
---|
117 | | - dev_err(drm->dev, "failed to load %s: %d\n", |
---|
| 315 | + DRM_DEV_ERROR(drm->dev, "failed to load %s: %d\n", |
---|
118 | 316 | fwname, ret); |
---|
119 | 317 | fw = ERR_PTR(ret); |
---|
120 | 318 | goto out; |
---|
.. | .. |
---|
130 | 328 | |
---|
131 | 329 | ret = request_firmware(&fw, newname, drm->dev); |
---|
132 | 330 | if (!ret) { |
---|
133 | | - dev_info(drm->dev, "loaded %s with helper\n", |
---|
| 331 | + DRM_DEV_INFO(drm->dev, "loaded %s with helper\n", |
---|
134 | 332 | newname); |
---|
135 | 333 | adreno_gpu->fwloc = FW_LOCATION_HELPER; |
---|
136 | 334 | goto out; |
---|
137 | 335 | } else if (adreno_gpu->fwloc != FW_LOCATION_UNKNOWN) { |
---|
138 | | - dev_err(drm->dev, "failed to load %s: %d\n", |
---|
| 336 | + DRM_DEV_ERROR(drm->dev, "failed to load %s: %d\n", |
---|
139 | 337 | newname, ret); |
---|
140 | 338 | fw = ERR_PTR(ret); |
---|
141 | 339 | goto out; |
---|
142 | 340 | } |
---|
143 | 341 | } |
---|
144 | 342 | |
---|
145 | | - dev_err(drm->dev, "failed to load %s\n", fwname); |
---|
| 343 | + DRM_DEV_ERROR(drm->dev, "failed to load %s\n", fwname); |
---|
146 | 344 | fw = ERR_PTR(-ENOENT); |
---|
147 | 345 | out: |
---|
148 | 346 | kfree(newname); |
---|
.. | .. |
---|
209 | 407 | if (!ring) |
---|
210 | 408 | continue; |
---|
211 | 409 | |
---|
212 | | - ret = msm_gem_get_iova(ring->bo, gpu->aspace, &ring->iova); |
---|
213 | | - if (ret) { |
---|
214 | | - ring->iova = 0; |
---|
215 | | - dev_err(gpu->dev->dev, |
---|
216 | | - "could not map ringbuffer %d: %d\n", i, ret); |
---|
217 | | - return ret; |
---|
218 | | - } |
---|
219 | | - |
---|
220 | 410 | ring->cur = ring->start; |
---|
221 | 411 | ring->next = ring->start; |
---|
222 | 412 | |
---|
223 | 413 | /* reset completed fence seqno: */ |
---|
224 | 414 | ring->memptrs->fence = ring->fctx->completed_fence; |
---|
225 | 415 | ring->memptrs->rptr = 0; |
---|
226 | | - } |
---|
227 | | - |
---|
228 | | - /* |
---|
229 | | - * Setup REG_CP_RB_CNTL. The same value is used across targets (with |
---|
230 | | - * the excpetion of A430 that disables the RPTR shadow) - the cacluation |
---|
231 | | - * for the ringbuffer size and block size is moved to msm_gpu.h for the |
---|
232 | | - * pre-processor to deal with and the A430 variant is ORed in here |
---|
233 | | - */ |
---|
234 | | - adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_CNTL, |
---|
235 | | - MSM_GPU_RB_CNTL_DEFAULT | |
---|
236 | | - (adreno_is_a430(adreno_gpu) ? AXXX_CP_RB_CNTL_NO_UPDATE : 0)); |
---|
237 | | - |
---|
238 | | - /* Setup ringbuffer address - use ringbuffer[0] for GPU init */ |
---|
239 | | - adreno_gpu_write64(adreno_gpu, REG_ADRENO_CP_RB_BASE, |
---|
240 | | - REG_ADRENO_CP_RB_BASE_HI, gpu->rb[0]->iova); |
---|
241 | | - |
---|
242 | | - if (!adreno_is_a430(adreno_gpu)) { |
---|
243 | | - adreno_gpu_write64(adreno_gpu, REG_ADRENO_CP_RB_RPTR_ADDR, |
---|
244 | | - REG_ADRENO_CP_RB_RPTR_ADDR_HI, |
---|
245 | | - rbmemptr(gpu->rb[0], rptr)); |
---|
246 | 416 | } |
---|
247 | 417 | |
---|
248 | 418 | return 0; |
---|
.. | .. |
---|
252 | 422 | static uint32_t get_rptr(struct adreno_gpu *adreno_gpu, |
---|
253 | 423 | struct msm_ringbuffer *ring) |
---|
254 | 424 | { |
---|
255 | | - if (adreno_is_a430(adreno_gpu)) |
---|
256 | | - return ring->memptrs->rptr = adreno_gpu_read( |
---|
257 | | - adreno_gpu, REG_ADRENO_CP_RB_RPTR); |
---|
258 | | - else |
---|
259 | | - return ring->memptrs->rptr; |
---|
| 425 | + struct msm_gpu *gpu = &adreno_gpu->base; |
---|
| 426 | + |
---|
| 427 | + return gpu->funcs->get_rptr(gpu, ring); |
---|
260 | 428 | } |
---|
261 | 429 | |
---|
262 | 430 | struct msm_ringbuffer *adreno_active_ring(struct msm_gpu *gpu) |
---|
.. | .. |
---|
277 | 445 | |
---|
278 | 446 | ret = msm_gpu_hw_init(gpu); |
---|
279 | 447 | if (ret) { |
---|
280 | | - dev_err(dev->dev, "gpu hw init failed: %d\n", ret); |
---|
| 448 | + DRM_DEV_ERROR(dev->dev, "gpu hw init failed: %d\n", ret); |
---|
281 | 449 | /* hmm, oh well? */ |
---|
282 | 450 | } |
---|
283 | 451 | } |
---|
284 | 452 | |
---|
285 | | -void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, |
---|
286 | | - struct msm_file_private *ctx) |
---|
| 453 | +void adreno_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring, u32 reg) |
---|
287 | 454 | { |
---|
288 | | - struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); |
---|
289 | | - struct msm_drm_private *priv = gpu->dev->dev_private; |
---|
290 | | - struct msm_ringbuffer *ring = submit->ring; |
---|
291 | | - unsigned i; |
---|
292 | | - |
---|
293 | | - for (i = 0; i < submit->nr_cmds; i++) { |
---|
294 | | - switch (submit->cmd[i].type) { |
---|
295 | | - case MSM_SUBMIT_CMD_IB_TARGET_BUF: |
---|
296 | | - /* ignore IB-targets */ |
---|
297 | | - break; |
---|
298 | | - case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: |
---|
299 | | - /* ignore if there has not been a ctx switch: */ |
---|
300 | | - if (priv->lastctx == ctx) |
---|
301 | | - break; |
---|
302 | | - case MSM_SUBMIT_CMD_BUF: |
---|
303 | | - OUT_PKT3(ring, adreno_is_a430(adreno_gpu) ? |
---|
304 | | - CP_INDIRECT_BUFFER_PFE : CP_INDIRECT_BUFFER_PFD, 2); |
---|
305 | | - OUT_RING(ring, lower_32_bits(submit->cmd[i].iova)); |
---|
306 | | - OUT_RING(ring, submit->cmd[i].size); |
---|
307 | | - OUT_PKT2(ring); |
---|
308 | | - break; |
---|
309 | | - } |
---|
310 | | - } |
---|
311 | | - |
---|
312 | | - OUT_PKT0(ring, REG_AXXX_CP_SCRATCH_REG2, 1); |
---|
313 | | - OUT_RING(ring, submit->seqno); |
---|
314 | | - |
---|
315 | | - if (adreno_is_a3xx(adreno_gpu) || adreno_is_a4xx(adreno_gpu)) { |
---|
316 | | - /* Flush HLSQ lazy updates to make sure there is nothing |
---|
317 | | - * pending for indirect loads after the timestamp has |
---|
318 | | - * passed: |
---|
319 | | - */ |
---|
320 | | - OUT_PKT3(ring, CP_EVENT_WRITE, 1); |
---|
321 | | - OUT_RING(ring, HLSQ_FLUSH); |
---|
322 | | - |
---|
323 | | - OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1); |
---|
324 | | - OUT_RING(ring, 0x00000000); |
---|
325 | | - } |
---|
326 | | - |
---|
327 | | - /* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */ |
---|
328 | | - OUT_PKT3(ring, CP_EVENT_WRITE, 3); |
---|
329 | | - OUT_RING(ring, CACHE_FLUSH_TS | BIT(31)); |
---|
330 | | - OUT_RING(ring, rbmemptr(ring, fence)); |
---|
331 | | - OUT_RING(ring, submit->seqno); |
---|
332 | | - |
---|
333 | | -#if 0 |
---|
334 | | - if (adreno_is_a3xx(adreno_gpu)) { |
---|
335 | | - /* Dummy set-constant to trigger context rollover */ |
---|
336 | | - OUT_PKT3(ring, CP_SET_CONSTANT, 2); |
---|
337 | | - OUT_RING(ring, CP_REG(REG_A3XX_HLSQ_CL_KERNEL_GROUP_X_REG)); |
---|
338 | | - OUT_RING(ring, 0x00000000); |
---|
339 | | - } |
---|
340 | | -#endif |
---|
341 | | - |
---|
342 | | - gpu->funcs->flush(gpu, ring); |
---|
343 | | -} |
---|
344 | | - |
---|
345 | | -void adreno_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring) |
---|
346 | | -{ |
---|
347 | | - struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); |
---|
348 | 455 | uint32_t wptr; |
---|
349 | 456 | |
---|
350 | 457 | /* Copy the shadow to the actual register */ |
---|
.. | .. |
---|
360 | 467 | /* ensure writes to ringbuffer have hit system memory: */ |
---|
361 | 468 | mb(); |
---|
362 | 469 | |
---|
363 | | - adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_WPTR, wptr); |
---|
| 470 | + gpu_write(gpu, reg, wptr); |
---|
364 | 471 | } |
---|
365 | 472 | |
---|
366 | 473 | bool adreno_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring) |
---|
.. | .. |
---|
406 | 513 | size = j + 1; |
---|
407 | 514 | |
---|
408 | 515 | if (size) { |
---|
409 | | - state->ring[i].data = kmalloc(size << 2, GFP_KERNEL); |
---|
| 516 | + state->ring[i].data = kvmalloc(size << 2, GFP_KERNEL); |
---|
410 | 517 | if (state->ring[i].data) { |
---|
411 | 518 | memcpy(state->ring[i].data, gpu->rb[i]->start, size << 2); |
---|
412 | 519 | state->ring[i].data_size = size << 2; |
---|
413 | 520 | } |
---|
414 | 521 | } |
---|
415 | 522 | } |
---|
| 523 | + |
---|
| 524 | + /* Some targets prefer to collect their own registers */ |
---|
| 525 | + if (!adreno_gpu->registers) |
---|
| 526 | + return 0; |
---|
416 | 527 | |
---|
417 | 528 | /* Count the number of registers */ |
---|
418 | 529 | for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) |
---|
.. | .. |
---|
445 | 556 | int i; |
---|
446 | 557 | |
---|
447 | 558 | for (i = 0; i < ARRAY_SIZE(state->ring); i++) |
---|
448 | | - kfree(state->ring[i].data); |
---|
| 559 | + kvfree(state->ring[i].data); |
---|
449 | 560 | |
---|
450 | 561 | for (i = 0; state->bos && i < state->nr_bos; i++) |
---|
451 | 562 | kvfree(state->bos[i].data); |
---|
.. | .. |
---|
475 | 586 | |
---|
476 | 587 | #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) |
---|
477 | 588 | |
---|
478 | | -static void adreno_show_object(struct drm_printer *p, u32 *ptr, int len) |
---|
| 589 | +static char *adreno_gpu_ascii85_encode(u32 *src, size_t len) |
---|
479 | 590 | { |
---|
| 591 | + void *buf; |
---|
| 592 | + size_t buf_itr = 0, buffer_size; |
---|
480 | 593 | char out[ASCII85_BUFSZ]; |
---|
481 | | - long l, datalen, i; |
---|
| 594 | + long l; |
---|
| 595 | + int i; |
---|
482 | 596 | |
---|
483 | | - if (!ptr || !len) |
---|
484 | | - return; |
---|
| 597 | + if (!src || !len) |
---|
| 598 | + return NULL; |
---|
| 599 | + |
---|
| 600 | + l = ascii85_encode_len(len); |
---|
485 | 601 | |
---|
486 | 602 | /* |
---|
487 | | - * Only dump the non-zero part of the buffer - rarely will any data |
---|
488 | | - * completely fill the entire allocated size of the buffer |
---|
| 603 | + * Ascii85 outputs either a 5 byte string or a 1 byte string. So we |
---|
| 604 | + * account for the worst case of 5 bytes per dword plus the 1 for '\0' |
---|
489 | 605 | */ |
---|
490 | | - for (datalen = 0, i = 0; i < len >> 2; i++) { |
---|
491 | | - if (ptr[i]) |
---|
492 | | - datalen = (i << 2) + 1; |
---|
493 | | - } |
---|
| 606 | + buffer_size = (l * 5) + 1; |
---|
494 | 607 | |
---|
495 | | - /* Skip printing the object if it is empty */ |
---|
496 | | - if (datalen == 0) |
---|
| 608 | + buf = kvmalloc(buffer_size, GFP_KERNEL); |
---|
| 609 | + if (!buf) |
---|
| 610 | + return NULL; |
---|
| 611 | + |
---|
| 612 | + for (i = 0; i < l; i++) |
---|
| 613 | + buf_itr += scnprintf(buf + buf_itr, buffer_size - buf_itr, "%s", |
---|
| 614 | + ascii85_encode(src[i], out)); |
---|
| 615 | + |
---|
| 616 | + return buf; |
---|
| 617 | +} |
---|
| 618 | + |
---|
| 619 | +/* len is expected to be in bytes */ |
---|
| 620 | +static void adreno_show_object(struct drm_printer *p, void **ptr, int len, |
---|
| 621 | + bool *encoded) |
---|
| 622 | +{ |
---|
| 623 | + if (!*ptr || !len) |
---|
497 | 624 | return; |
---|
498 | 625 | |
---|
499 | | - l = ascii85_encode_len(datalen); |
---|
| 626 | + if (!*encoded) { |
---|
| 627 | + long datalen, i; |
---|
| 628 | + u32 *buf = *ptr; |
---|
| 629 | + |
---|
| 630 | + /* |
---|
| 631 | + * Only dump the non-zero part of the buffer - rarely will |
---|
| 632 | + * any data completely fill the entire allocated size of |
---|
| 633 | + * the buffer. |
---|
| 634 | + */ |
---|
| 635 | + for (datalen = 0, i = 0; i < len >> 2; i++) |
---|
| 636 | + if (buf[i]) |
---|
| 637 | + datalen = ((i + 1) << 2); |
---|
| 638 | + |
---|
| 639 | + /* |
---|
| 640 | + * If we reach here, then the originally captured binary buffer |
---|
| 641 | + * will be replaced with the ascii85 encoded string |
---|
| 642 | + */ |
---|
| 643 | + *ptr = adreno_gpu_ascii85_encode(buf, datalen); |
---|
| 644 | + |
---|
| 645 | + kvfree(buf); |
---|
| 646 | + |
---|
| 647 | + *encoded = true; |
---|
| 648 | + } |
---|
| 649 | + |
---|
| 650 | + if (!*ptr) |
---|
| 651 | + return; |
---|
500 | 652 | |
---|
501 | 653 | drm_puts(p, " data: !!ascii85 |\n"); |
---|
502 | 654 | drm_puts(p, " "); |
---|
503 | 655 | |
---|
504 | | - for (i = 0; i < l; i++) |
---|
505 | | - drm_puts(p, ascii85_encode(ptr[i], out)); |
---|
| 656 | + drm_puts(p, *ptr); |
---|
506 | 657 | |
---|
507 | 658 | drm_puts(p, "\n"); |
---|
508 | 659 | } |
---|
.. | .. |
---|
534 | 685 | drm_printf(p, " wptr: %d\n", state->ring[i].wptr); |
---|
535 | 686 | drm_printf(p, " size: %d\n", MSM_GPU_RINGBUFFER_SZ); |
---|
536 | 687 | |
---|
537 | | - adreno_show_object(p, state->ring[i].data, |
---|
538 | | - state->ring[i].data_size); |
---|
| 688 | + adreno_show_object(p, &state->ring[i].data, |
---|
| 689 | + state->ring[i].data_size, &state->ring[i].encoded); |
---|
539 | 690 | } |
---|
540 | 691 | |
---|
541 | 692 | if (state->bos) { |
---|
.. | .. |
---|
546 | 697 | state->bos[i].iova); |
---|
547 | 698 | drm_printf(p, " size: %zd\n", state->bos[i].size); |
---|
548 | 699 | |
---|
549 | | - adreno_show_object(p, state->bos[i].data, |
---|
550 | | - state->bos[i].size); |
---|
| 700 | + adreno_show_object(p, &state->bos[i].data, |
---|
| 701 | + state->bos[i].size, &state->bos[i].encoded); |
---|
551 | 702 | } |
---|
552 | 703 | } |
---|
553 | 704 | |
---|
554 | | - drm_puts(p, "registers:\n"); |
---|
| 705 | + if (state->nr_registers) { |
---|
| 706 | + drm_puts(p, "registers:\n"); |
---|
555 | 707 | |
---|
556 | | - for (i = 0; i < state->nr_registers; i++) { |
---|
557 | | - drm_printf(p, " - { offset: 0x%04x, value: 0x%08x }\n", |
---|
558 | | - state->registers[i * 2] << 2, |
---|
559 | | - state->registers[(i * 2) + 1]); |
---|
| 708 | + for (i = 0; i < state->nr_registers; i++) { |
---|
| 709 | + drm_printf(p, " - { offset: 0x%04x, value: 0x%08x }\n", |
---|
| 710 | + state->registers[i * 2] << 2, |
---|
| 711 | + state->registers[(i * 2) + 1]); |
---|
| 712 | + } |
---|
560 | 713 | } |
---|
561 | 714 | } |
---|
562 | 715 | #endif |
---|
.. | .. |
---|
594 | 747 | { |
---|
595 | 748 | struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); |
---|
596 | 749 | int i; |
---|
| 750 | + |
---|
| 751 | + if (!adreno_gpu->registers) |
---|
| 752 | + return; |
---|
597 | 753 | |
---|
598 | 754 | /* dump these out in a form that can be parsed by demsm: */ |
---|
599 | 755 | printk("IO:region %s 00000000 00020000\n", gpu->name); |
---|
.. | .. |
---|
635 | 791 | |
---|
636 | 792 | node = of_get_compatible_child(dev->of_node, "qcom,gpu-pwrlevels"); |
---|
637 | 793 | if (!node) { |
---|
638 | | - dev_err(dev, "Could not find the GPU powerlevels\n"); |
---|
| 794 | + DRM_DEV_DEBUG(dev, "Could not find the GPU powerlevels\n"); |
---|
639 | 795 | return -ENXIO; |
---|
640 | 796 | } |
---|
641 | 797 | |
---|
.. | .. |
---|
659 | 815 | return 0; |
---|
660 | 816 | } |
---|
661 | 817 | |
---|
662 | | -static int adreno_get_pwrlevels(struct device *dev, |
---|
| 818 | +static void adreno_get_pwrlevels(struct device *dev, |
---|
663 | 819 | struct msm_gpu *gpu) |
---|
664 | 820 | { |
---|
665 | 821 | unsigned long freq = ULONG_MAX; |
---|
.. | .. |
---|
674 | 830 | else { |
---|
675 | 831 | ret = dev_pm_opp_of_add_table(dev); |
---|
676 | 832 | if (ret) |
---|
677 | | - dev_err(dev, "Unable to set the OPP table\n"); |
---|
| 833 | + DRM_DEV_ERROR(dev, "Unable to set the OPP table\n"); |
---|
678 | 834 | } |
---|
679 | 835 | |
---|
680 | 836 | if (!ret) { |
---|
.. | .. |
---|
694 | 850 | } |
---|
695 | 851 | |
---|
696 | 852 | DBG("fast_rate=%u, slow_rate=27000000", gpu->fast_rate); |
---|
| 853 | +} |
---|
| 854 | + |
---|
| 855 | +int adreno_gpu_ocmem_init(struct device *dev, struct adreno_gpu *adreno_gpu, |
---|
| 856 | + struct adreno_ocmem *adreno_ocmem) |
---|
| 857 | +{ |
---|
| 858 | + struct ocmem_buf *ocmem_hdl; |
---|
| 859 | + struct ocmem *ocmem; |
---|
| 860 | + |
---|
| 861 | + ocmem = of_get_ocmem(dev); |
---|
| 862 | + if (IS_ERR(ocmem)) { |
---|
| 863 | + if (PTR_ERR(ocmem) == -ENODEV) { |
---|
| 864 | + /* |
---|
| 865 | + * Return success since either the ocmem property was |
---|
| 866 | + * not specified in device tree, or ocmem support is |
---|
| 867 | + * not compiled into the kernel. |
---|
| 868 | + */ |
---|
| 869 | + return 0; |
---|
| 870 | + } |
---|
| 871 | + |
---|
| 872 | + return PTR_ERR(ocmem); |
---|
| 873 | + } |
---|
| 874 | + |
---|
| 875 | + ocmem_hdl = ocmem_allocate(ocmem, OCMEM_GRAPHICS, adreno_gpu->gmem); |
---|
| 876 | + if (IS_ERR(ocmem_hdl)) |
---|
| 877 | + return PTR_ERR(ocmem_hdl); |
---|
| 878 | + |
---|
| 879 | + adreno_ocmem->ocmem = ocmem; |
---|
| 880 | + adreno_ocmem->base = ocmem_hdl->addr; |
---|
| 881 | + adreno_ocmem->hdl = ocmem_hdl; |
---|
| 882 | + adreno_gpu->gmem = ocmem_hdl->len; |
---|
697 | 883 | |
---|
698 | 884 | return 0; |
---|
| 885 | +} |
---|
| 886 | + |
---|
| 887 | +void adreno_gpu_ocmem_cleanup(struct adreno_ocmem *adreno_ocmem) |
---|
| 888 | +{ |
---|
| 889 | + if (adreno_ocmem && adreno_ocmem->base) |
---|
| 890 | + ocmem_free(adreno_ocmem->ocmem, OCMEM_GRAPHICS, |
---|
| 891 | + adreno_ocmem->hdl); |
---|
699 | 892 | } |
---|
700 | 893 | |
---|
701 | 894 | int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, |
---|
702 | 895 | struct adreno_gpu *adreno_gpu, |
---|
703 | 896 | const struct adreno_gpu_funcs *funcs, int nr_rings) |
---|
704 | 897 | { |
---|
705 | | - struct adreno_platform_config *config = pdev->dev.platform_data; |
---|
| 898 | + struct device *dev = &pdev->dev; |
---|
| 899 | + struct adreno_platform_config *config = dev->platform_data; |
---|
706 | 900 | struct msm_gpu_config adreno_gpu_config = { 0 }; |
---|
707 | 901 | struct msm_gpu *gpu = &adreno_gpu->base; |
---|
| 902 | + int ret; |
---|
708 | 903 | |
---|
709 | 904 | adreno_gpu->funcs = funcs; |
---|
710 | 905 | adreno_gpu->info = adreno_info(config->rev); |
---|
.. | .. |
---|
713 | 908 | adreno_gpu->rev = config->rev; |
---|
714 | 909 | |
---|
715 | 910 | adreno_gpu_config.ioname = "kgsl_3d0_reg_memory"; |
---|
716 | | - adreno_gpu_config.irqname = "kgsl_3d0_irq"; |
---|
717 | | - |
---|
718 | | - adreno_gpu_config.va_start = SZ_16M; |
---|
719 | | - adreno_gpu_config.va_end = 0xffffffff; |
---|
720 | 911 | |
---|
721 | 912 | adreno_gpu_config.nr_rings = nr_rings; |
---|
722 | 913 | |
---|
723 | | - adreno_get_pwrlevels(&pdev->dev, gpu); |
---|
| 914 | + adreno_get_pwrlevels(dev, gpu); |
---|
724 | 915 | |
---|
725 | | - pm_runtime_set_autosuspend_delay(&pdev->dev, |
---|
| 916 | + pm_runtime_set_autosuspend_delay(dev, |
---|
726 | 917 | adreno_gpu->info->inactive_period); |
---|
727 | | - pm_runtime_use_autosuspend(&pdev->dev); |
---|
728 | | - pm_runtime_enable(&pdev->dev); |
---|
| 918 | + pm_runtime_use_autosuspend(dev); |
---|
729 | 919 | |
---|
730 | | - return msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base, |
---|
| 920 | + ret = msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base, |
---|
731 | 921 | adreno_gpu->info->name, &adreno_gpu_config); |
---|
| 922 | + if (ret) |
---|
| 923 | + return ret; |
---|
| 924 | + |
---|
| 925 | + /* |
---|
| 926 | + * The legacy case, before "interconnect-names", only has a |
---|
| 927 | + * single interconnect path which is equivalent to "gfx-mem" |
---|
| 928 | + */ |
---|
| 929 | + if (!of_find_property(dev->of_node, "interconnect-names", NULL)) { |
---|
| 930 | + gpu->icc_path = of_icc_get(dev, NULL); |
---|
| 931 | + } else { |
---|
| 932 | + gpu->icc_path = of_icc_get(dev, "gfx-mem"); |
---|
| 933 | + gpu->ocmem_icc_path = of_icc_get(dev, "ocmem"); |
---|
| 934 | + } |
---|
| 935 | + |
---|
| 936 | + if (IS_ERR(gpu->icc_path)) { |
---|
| 937 | + ret = PTR_ERR(gpu->icc_path); |
---|
| 938 | + gpu->icc_path = NULL; |
---|
| 939 | + return ret; |
---|
| 940 | + } |
---|
| 941 | + |
---|
| 942 | + if (IS_ERR(gpu->ocmem_icc_path)) { |
---|
| 943 | + ret = PTR_ERR(gpu->ocmem_icc_path); |
---|
| 944 | + gpu->ocmem_icc_path = NULL; |
---|
| 945 | + /* allow -ENODATA, ocmem icc is optional */ |
---|
| 946 | + if (ret != -ENODATA) |
---|
| 947 | + return ret; |
---|
| 948 | + } |
---|
| 949 | + |
---|
| 950 | + return 0; |
---|
732 | 951 | } |
---|
733 | 952 | |
---|
734 | 953 | void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu) |
---|
735 | 954 | { |
---|
| 955 | + struct msm_gpu *gpu = &adreno_gpu->base; |
---|
| 956 | + struct msm_drm_private *priv = gpu->dev ? gpu->dev->dev_private : NULL; |
---|
736 | 957 | unsigned int i; |
---|
737 | 958 | |
---|
738 | 959 | for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++) |
---|
739 | 960 | release_firmware(adreno_gpu->fw[i]); |
---|
740 | 961 | |
---|
| 962 | + if (priv && pm_runtime_enabled(&priv->gpu_pdev->dev)) |
---|
| 963 | + pm_runtime_disable(&priv->gpu_pdev->dev); |
---|
| 964 | + |
---|
741 | 965 | msm_gpu_cleanup(&adreno_gpu->base); |
---|
| 966 | + |
---|
| 967 | + icc_put(gpu->icc_path); |
---|
| 968 | + icc_put(gpu->ocmem_icc_path); |
---|
742 | 969 | } |
---|