From 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 13 May 2024 10:30:14 +0000 Subject: [PATCH] modify sin led gpio --- kernel/drivers/gpu/drm/msm/adreno/adreno_gpu.c | 539 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 383 insertions(+), 156 deletions(-) diff --git a/kernel/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/kernel/drivers/gpu/drm/msm/adreno/adreno_gpu.c index c9f8316..11a6a41 100644 --- a/kernel/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/kernel/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -1,29 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * * Copyright (c) 2014 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/ascii85.h> +#include <linux/interconnect.h> +#include <linux/qcom_scm.h> #include <linux/kernel.h> +#include <linux/of_address.h> #include <linux/pm_opp.h> #include <linux/slab.h> +#include <linux/soc/qcom/mdt_loader.h> +#include <soc/qcom/ocmem.h> #include "adreno_gpu.h" #include "msm_gem.h" #include "msm_mmu.h" + +static bool zap_available = true; + +static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname, + u32 pasid) +{ + struct device *dev = &gpu->pdev->dev; + const struct firmware *fw; + const char *signed_fwname = NULL; + struct device_node *np, *mem_np; + struct resource r; + phys_addr_t mem_phys; + ssize_t mem_size; + void *mem_region = NULL; + int ret; + + if (!IS_ENABLED(CONFIG_ARCH_QCOM)) { + zap_available = false; + return -EINVAL; + } + + np = of_get_child_by_name(dev->of_node, "zap-shader"); + if (!np) { + zap_available = false; + return -ENODEV; + } + + mem_np = of_parse_phandle(np, "memory-region", 0); + of_node_put(np); + if (!mem_np) { + zap_available = false; + return -EINVAL; + } + + ret = of_address_to_resource(mem_np, 0, &r); + of_node_put(mem_np); + if (ret) + return ret; + + mem_phys = r.start; + + /* + * Check for a firmware-name property. This is the new scheme + * to handle firmware that may be signed with device specific + * keys, allowing us to have a different zap fw path for different + * devices. + * + * If the firmware-name property is found, we bypass the + * adreno_request_fw() mechanism, because we don't need to handle + * the /lib/firmware/qcom/... vs /lib/firmware/... case. + * + * If the firmware-name property is not found, for backwards + * compatibility we fall back to the fwname from the gpulist + * table. + */ + of_property_read_string_index(np, "firmware-name", 0, &signed_fwname); + if (signed_fwname) { + fwname = signed_fwname; + ret = request_firmware_direct(&fw, fwname, gpu->dev->dev); + if (ret) + fw = ERR_PTR(ret); + } else if (fwname) { + /* Request the MDT file from the default location: */ + fw = adreno_request_fw(to_adreno_gpu(gpu), fwname); + } else { + /* + * For new targets, we require the firmware-name property, + * if a zap-shader is required, rather than falling back + * to a firmware name specified in gpulist. + * + * Because the firmware is signed with a (potentially) + * device specific key, having the name come from gpulist + * was a bad idea, and is only provided for backwards + * compatibility for older targets. + */ + return -ENODEV; + } + + if (IS_ERR(fw)) { + DRM_DEV_ERROR(dev, "Unable to load %s\n", fwname); + return PTR_ERR(fw); + } + + /* Figure out how much memory we need */ + mem_size = qcom_mdt_get_size(fw); + if (mem_size < 0) { + ret = mem_size; + goto out; + } + + if (mem_size > resource_size(&r)) { + DRM_DEV_ERROR(dev, + "memory region is too small to load the MDT\n"); + ret = -E2BIG; + goto out; + } + + /* Allocate memory for the firmware image */ + mem_region = memremap(mem_phys, mem_size, MEMREMAP_WC); + if (!mem_region) { + ret = -ENOMEM; + goto out; + } + + /* + * Load the rest of the MDT + * + * Note that we could be dealing with two different paths, since + * with upstream linux-firmware it would be in a qcom/ subdir.. + * adreno_request_fw() handles this, but qcom_mdt_load() does + * not. But since we've already gotten through adreno_request_fw() + * we know which of the two cases it is: + */ + if (signed_fwname || (to_adreno_gpu(gpu)->fwloc == FW_LOCATION_LEGACY)) { + ret = qcom_mdt_load(dev, fw, fwname, pasid, + mem_region, mem_phys, mem_size, NULL); + } else { + char *newname; + + newname = kasprintf(GFP_KERNEL, "qcom/%s", fwname); + + ret = qcom_mdt_load(dev, fw, newname, pasid, + mem_region, mem_phys, mem_size, NULL); + kfree(newname); + } + if (ret) + goto out; + + /* Send the image to the secure world */ + ret = qcom_scm_pas_auth_and_reset(pasid); + + /* + * If the scm call returns -EOPNOTSUPP we assume that this target + * doesn't need/support the zap shader so quietly fail + */ + if (ret == -EOPNOTSUPP) + zap_available = false; + else if (ret) + DRM_DEV_ERROR(dev, "Unable to authorize the image\n"); + +out: + if (mem_region) + memunmap(mem_region); + + release_firmware(fw); + + return ret; +} + +int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct platform_device *pdev = gpu->pdev; + + /* Short cut if we determine the zap shader isn't available/needed */ + if (!zap_available) + return -ENODEV; + + /* We need SCM to be able to load the firmware */ + if (!qcom_scm_is_available()) { + DRM_DEV_ERROR(&pdev->dev, "SCM is not available\n"); + return -EPROBE_DEFER; + } + + return zap_shader_load_mdt(gpu, adreno_gpu->info->zapfw, pasid); +} + +struct msm_gem_address_space * +adreno_iommu_create_address_space(struct msm_gpu *gpu, + struct platform_device *pdev) +{ + struct iommu_domain *iommu; + struct msm_mmu *mmu; + struct msm_gem_address_space *aspace; + u64 start, size; + + iommu = iommu_domain_alloc(&platform_bus_type); + if (!iommu) + return NULL; + + mmu = msm_iommu_new(&pdev->dev, iommu); + + /* + * Use the aperture start or SZ_16M, whichever is greater. This will + * ensure that we align with the allocated pagetable range while still + * allowing room in the lower 32 bits for GMEM and whatnot + */ + start = max_t(u64, SZ_16M, iommu->geometry.aperture_start); + size = iommu->geometry.aperture_end - start + 1; + + aspace = msm_gem_address_space_create(mmu, "gpu", + start & GENMASK_ULL(48, 0), size); + + if (IS_ERR(aspace) && !IS_ERR(mmu)) + mmu->funcs->destroy(mmu); + + return aspace; +} int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) { @@ -37,7 +229,7 @@ *value = adreno_gpu->gmem; return 0; case MSM_PARAM_GMEM_BASE: - *value = 0x100000; + *value = !adreno_is_a650(adreno_gpu) ? 0x100000 : 0; return 0; case MSM_PARAM_CHIP_ID: *value = adreno_gpu->rev.patchid | @@ -61,6 +253,12 @@ return -EINVAL; case MSM_PARAM_NR_RINGS: *value = gpu->nr_rings; + return 0; + case MSM_PARAM_PP_PGTABLE: + *value = 0; + return 0; + case MSM_PARAM_FAULTS: + *value = gpu->global_faults; return 0; default: DBG("%s: invalid param: %u", gpu->name, param); @@ -89,12 +287,12 @@ ret = request_firmware_direct(&fw, newname, drm->dev); if (!ret) { - dev_info(drm->dev, "loaded %s from new location\n", + DRM_DEV_INFO(drm->dev, "loaded %s from new location\n", newname); adreno_gpu->fwloc = FW_LOCATION_NEW; goto out; } else if (adreno_gpu->fwloc != FW_LOCATION_UNKNOWN) { - dev_err(drm->dev, "failed to load %s: %d\n", + DRM_DEV_ERROR(drm->dev, "failed to load %s: %d\n", newname, ret); fw = ERR_PTR(ret); goto out; @@ -109,12 +307,12 @@ ret = request_firmware_direct(&fw, fwname, drm->dev); if (!ret) { - dev_info(drm->dev, "loaded %s from legacy location\n", + DRM_DEV_INFO(drm->dev, "loaded %s from legacy location\n", newname); adreno_gpu->fwloc = FW_LOCATION_LEGACY; goto out; } else if (adreno_gpu->fwloc != FW_LOCATION_UNKNOWN) { - dev_err(drm->dev, "failed to load %s: %d\n", + DRM_DEV_ERROR(drm->dev, "failed to load %s: %d\n", fwname, ret); fw = ERR_PTR(ret); goto out; @@ -130,19 +328,19 @@ ret = request_firmware(&fw, newname, drm->dev); if (!ret) { - dev_info(drm->dev, "loaded %s with helper\n", + DRM_DEV_INFO(drm->dev, "loaded %s with helper\n", newname); adreno_gpu->fwloc = FW_LOCATION_HELPER; goto out; } else if (adreno_gpu->fwloc != FW_LOCATION_UNKNOWN) { - dev_err(drm->dev, "failed to load %s: %d\n", + DRM_DEV_ERROR(drm->dev, "failed to load %s: %d\n", newname, ret); fw = ERR_PTR(ret); goto out; } } - dev_err(drm->dev, "failed to load %s\n", fwname); + DRM_DEV_ERROR(drm->dev, "failed to load %s\n", fwname); fw = ERR_PTR(-ENOENT); out: kfree(newname); @@ -209,40 +407,12 @@ if (!ring) continue; - ret = msm_gem_get_iova(ring->bo, gpu->aspace, &ring->iova); - if (ret) { - ring->iova = 0; - dev_err(gpu->dev->dev, - "could not map ringbuffer %d: %d\n", i, ret); - return ret; - } - ring->cur = ring->start; ring->next = ring->start; /* reset completed fence seqno: */ ring->memptrs->fence = ring->fctx->completed_fence; ring->memptrs->rptr = 0; - } - - /* - * Setup REG_CP_RB_CNTL. The same value is used across targets (with - * the excpetion of A430 that disables the RPTR shadow) - the cacluation - * for the ringbuffer size and block size is moved to msm_gpu.h for the - * pre-processor to deal with and the A430 variant is ORed in here - */ - adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_CNTL, - MSM_GPU_RB_CNTL_DEFAULT | - (adreno_is_a430(adreno_gpu) ? AXXX_CP_RB_CNTL_NO_UPDATE : 0)); - - /* Setup ringbuffer address - use ringbuffer[0] for GPU init */ - adreno_gpu_write64(adreno_gpu, REG_ADRENO_CP_RB_BASE, - REG_ADRENO_CP_RB_BASE_HI, gpu->rb[0]->iova); - - if (!adreno_is_a430(adreno_gpu)) { - adreno_gpu_write64(adreno_gpu, REG_ADRENO_CP_RB_RPTR_ADDR, - REG_ADRENO_CP_RB_RPTR_ADDR_HI, - rbmemptr(gpu->rb[0], rptr)); } return 0; @@ -252,11 +422,9 @@ static uint32_t get_rptr(struct adreno_gpu *adreno_gpu, struct msm_ringbuffer *ring) { - if (adreno_is_a430(adreno_gpu)) - return ring->memptrs->rptr = adreno_gpu_read( - adreno_gpu, REG_ADRENO_CP_RB_RPTR); - else - return ring->memptrs->rptr; + struct msm_gpu *gpu = &adreno_gpu->base; + + return gpu->funcs->get_rptr(gpu, ring); } struct msm_ringbuffer *adreno_active_ring(struct msm_gpu *gpu) @@ -277,74 +445,13 @@ ret = msm_gpu_hw_init(gpu); if (ret) { - dev_err(dev->dev, "gpu hw init failed: %d\n", ret); + DRM_DEV_ERROR(dev->dev, "gpu hw init failed: %d\n", ret); /* hmm, oh well? */ } } -void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, - struct msm_file_private *ctx) +void adreno_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring, u32 reg) { - struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - struct msm_drm_private *priv = gpu->dev->dev_private; - struct msm_ringbuffer *ring = submit->ring; - unsigned i; - - for (i = 0; i < submit->nr_cmds; i++) { - switch (submit->cmd[i].type) { - case MSM_SUBMIT_CMD_IB_TARGET_BUF: - /* ignore IB-targets */ - break; - case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: - /* ignore if there has not been a ctx switch: */ - if (priv->lastctx == ctx) - break; - case MSM_SUBMIT_CMD_BUF: - OUT_PKT3(ring, adreno_is_a430(adreno_gpu) ? - CP_INDIRECT_BUFFER_PFE : CP_INDIRECT_BUFFER_PFD, 2); - OUT_RING(ring, lower_32_bits(submit->cmd[i].iova)); - OUT_RING(ring, submit->cmd[i].size); - OUT_PKT2(ring); - break; - } - } - - OUT_PKT0(ring, REG_AXXX_CP_SCRATCH_REG2, 1); - OUT_RING(ring, submit->seqno); - - if (adreno_is_a3xx(adreno_gpu) || adreno_is_a4xx(adreno_gpu)) { - /* Flush HLSQ lazy updates to make sure there is nothing - * pending for indirect loads after the timestamp has - * passed: - */ - OUT_PKT3(ring, CP_EVENT_WRITE, 1); - OUT_RING(ring, HLSQ_FLUSH); - - OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1); - OUT_RING(ring, 0x00000000); - } - - /* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */ - OUT_PKT3(ring, CP_EVENT_WRITE, 3); - OUT_RING(ring, CACHE_FLUSH_TS | BIT(31)); - OUT_RING(ring, rbmemptr(ring, fence)); - OUT_RING(ring, submit->seqno); - -#if 0 - if (adreno_is_a3xx(adreno_gpu)) { - /* Dummy set-constant to trigger context rollover */ - OUT_PKT3(ring, CP_SET_CONSTANT, 2); - OUT_RING(ring, CP_REG(REG_A3XX_HLSQ_CL_KERNEL_GROUP_X_REG)); - OUT_RING(ring, 0x00000000); - } -#endif - - gpu->funcs->flush(gpu, ring); -} - -void adreno_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring) -{ - struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); uint32_t wptr; /* Copy the shadow to the actual register */ @@ -360,7 +467,7 @@ /* ensure writes to ringbuffer have hit system memory: */ mb(); - adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_WPTR, wptr); + gpu_write(gpu, reg, wptr); } bool adreno_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring) @@ -406,13 +513,17 @@ size = j + 1; if (size) { - state->ring[i].data = kmalloc(size << 2, GFP_KERNEL); + state->ring[i].data = kvmalloc(size << 2, GFP_KERNEL); if (state->ring[i].data) { memcpy(state->ring[i].data, gpu->rb[i]->start, size << 2); state->ring[i].data_size = size << 2; } } } + + /* Some targets prefer to collect their own registers */ + if (!adreno_gpu->registers) + return 0; /* Count the number of registers */ for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) @@ -445,7 +556,7 @@ int i; for (i = 0; i < ARRAY_SIZE(state->ring); i++) - kfree(state->ring[i].data); + kvfree(state->ring[i].data); for (i = 0; state->bos && i < state->nr_bos; i++) kvfree(state->bos[i].data); @@ -475,34 +586,74 @@ #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) -static void adreno_show_object(struct drm_printer *p, u32 *ptr, int len) +static char *adreno_gpu_ascii85_encode(u32 *src, size_t len) { + void *buf; + size_t buf_itr = 0, buffer_size; char out[ASCII85_BUFSZ]; - long l, datalen, i; + long l; + int i; - if (!ptr || !len) - return; + if (!src || !len) + return NULL; + + l = ascii85_encode_len(len); /* - * Only dump the non-zero part of the buffer - rarely will any data - * completely fill the entire allocated size of the buffer + * Ascii85 outputs either a 5 byte string or a 1 byte string. So we + * account for the worst case of 5 bytes per dword plus the 1 for '\0' */ - for (datalen = 0, i = 0; i < len >> 2; i++) { - if (ptr[i]) - datalen = (i << 2) + 1; - } + buffer_size = (l * 5) + 1; - /* Skip printing the object if it is empty */ - if (datalen == 0) + buf = kvmalloc(buffer_size, GFP_KERNEL); + if (!buf) + return NULL; + + for (i = 0; i < l; i++) + buf_itr += scnprintf(buf + buf_itr, buffer_size - buf_itr, "%s", + ascii85_encode(src[i], out)); + + return buf; +} + +/* len is expected to be in bytes */ +static void adreno_show_object(struct drm_printer *p, void **ptr, int len, + bool *encoded) +{ + if (!*ptr || !len) return; - l = ascii85_encode_len(datalen); + if (!*encoded) { + long datalen, i; + u32 *buf = *ptr; + + /* + * Only dump the non-zero part of the buffer - rarely will + * any data completely fill the entire allocated size of + * the buffer. + */ + for (datalen = 0, i = 0; i < len >> 2; i++) + if (buf[i]) + datalen = ((i + 1) << 2); + + /* + * If we reach here, then the originally captured binary buffer + * will be replaced with the ascii85 encoded string + */ + *ptr = adreno_gpu_ascii85_encode(buf, datalen); + + kvfree(buf); + + *encoded = true; + } + + if (!*ptr) + return; drm_puts(p, " data: !!ascii85 |\n"); drm_puts(p, " "); - for (i = 0; i < l; i++) - drm_puts(p, ascii85_encode(ptr[i], out)); + drm_puts(p, *ptr); drm_puts(p, "\n"); } @@ -534,8 +685,8 @@ drm_printf(p, " wptr: %d\n", state->ring[i].wptr); drm_printf(p, " size: %d\n", MSM_GPU_RINGBUFFER_SZ); - adreno_show_object(p, state->ring[i].data, - state->ring[i].data_size); + adreno_show_object(p, &state->ring[i].data, + state->ring[i].data_size, &state->ring[i].encoded); } if (state->bos) { @@ -546,17 +697,19 @@ state->bos[i].iova); drm_printf(p, " size: %zd\n", state->bos[i].size); - adreno_show_object(p, state->bos[i].data, - state->bos[i].size); + adreno_show_object(p, &state->bos[i].data, + state->bos[i].size, &state->bos[i].encoded); } } - drm_puts(p, "registers:\n"); + if (state->nr_registers) { + drm_puts(p, "registers:\n"); - for (i = 0; i < state->nr_registers; i++) { - drm_printf(p, " - { offset: 0x%04x, value: 0x%08x }\n", - state->registers[i * 2] << 2, - state->registers[(i * 2) + 1]); + for (i = 0; i < state->nr_registers; i++) { + drm_printf(p, " - { offset: 0x%04x, value: 0x%08x }\n", + state->registers[i * 2] << 2, + state->registers[(i * 2) + 1]); + } } } #endif @@ -594,6 +747,9 @@ { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); int i; + + if (!adreno_gpu->registers) + return; /* dump these out in a form that can be parsed by demsm: */ printk("IO:region %s 00000000 00020000\n", gpu->name); @@ -635,7 +791,7 @@ node = of_get_compatible_child(dev->of_node, "qcom,gpu-pwrlevels"); if (!node) { - dev_err(dev, "Could not find the GPU powerlevels\n"); + DRM_DEV_DEBUG(dev, "Could not find the GPU powerlevels\n"); return -ENXIO; } @@ -659,7 +815,7 @@ return 0; } -static int adreno_get_pwrlevels(struct device *dev, +static void adreno_get_pwrlevels(struct device *dev, struct msm_gpu *gpu) { unsigned long freq = ULONG_MAX; @@ -674,7 +830,7 @@ else { ret = dev_pm_opp_of_add_table(dev); if (ret) - dev_err(dev, "Unable to set the OPP table\n"); + DRM_DEV_ERROR(dev, "Unable to set the OPP table\n"); } if (!ret) { @@ -694,17 +850,56 @@ } DBG("fast_rate=%u, slow_rate=27000000", gpu->fast_rate); +} + +int adreno_gpu_ocmem_init(struct device *dev, struct adreno_gpu *adreno_gpu, + struct adreno_ocmem *adreno_ocmem) +{ + struct ocmem_buf *ocmem_hdl; + struct ocmem *ocmem; + + ocmem = of_get_ocmem(dev); + if (IS_ERR(ocmem)) { + if (PTR_ERR(ocmem) == -ENODEV) { + /* + * Return success since either the ocmem property was + * not specified in device tree, or ocmem support is + * not compiled into the kernel. + */ + return 0; + } + + return PTR_ERR(ocmem); + } + + ocmem_hdl = ocmem_allocate(ocmem, OCMEM_GRAPHICS, adreno_gpu->gmem); + if (IS_ERR(ocmem_hdl)) + return PTR_ERR(ocmem_hdl); + + adreno_ocmem->ocmem = ocmem; + adreno_ocmem->base = ocmem_hdl->addr; + adreno_ocmem->hdl = ocmem_hdl; + adreno_gpu->gmem = ocmem_hdl->len; return 0; +} + +void adreno_gpu_ocmem_cleanup(struct adreno_ocmem *adreno_ocmem) +{ + if (adreno_ocmem && adreno_ocmem->base) + ocmem_free(adreno_ocmem->ocmem, OCMEM_GRAPHICS, + adreno_ocmem->hdl); } int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, struct adreno_gpu *adreno_gpu, const struct adreno_gpu_funcs *funcs, int nr_rings) { - struct adreno_platform_config *config = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct adreno_platform_config *config = dev->platform_data; struct msm_gpu_config adreno_gpu_config = { 0 }; struct msm_gpu *gpu = &adreno_gpu->base; + int ret; adreno_gpu->funcs = funcs; adreno_gpu->info = adreno_info(config->rev); @@ -713,30 +908,62 @@ adreno_gpu->rev = config->rev; adreno_gpu_config.ioname = "kgsl_3d0_reg_memory"; - adreno_gpu_config.irqname = "kgsl_3d0_irq"; - - adreno_gpu_config.va_start = SZ_16M; - adreno_gpu_config.va_end = 0xffffffff; adreno_gpu_config.nr_rings = nr_rings; - adreno_get_pwrlevels(&pdev->dev, gpu); + adreno_get_pwrlevels(dev, gpu); - pm_runtime_set_autosuspend_delay(&pdev->dev, + pm_runtime_set_autosuspend_delay(dev, adreno_gpu->info->inactive_period); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_enable(&pdev->dev); + pm_runtime_use_autosuspend(dev); - return msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base, + ret = msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base, adreno_gpu->info->name, &adreno_gpu_config); + if (ret) + return ret; + + /* + * The legacy case, before "interconnect-names", only has a + * single interconnect path which is equivalent to "gfx-mem" + */ + if (!of_find_property(dev->of_node, "interconnect-names", NULL)) { + gpu->icc_path = of_icc_get(dev, NULL); + } else { + gpu->icc_path = of_icc_get(dev, "gfx-mem"); + gpu->ocmem_icc_path = of_icc_get(dev, "ocmem"); + } + + if (IS_ERR(gpu->icc_path)) { + ret = PTR_ERR(gpu->icc_path); + gpu->icc_path = NULL; + return ret; + } + + if (IS_ERR(gpu->ocmem_icc_path)) { + ret = PTR_ERR(gpu->ocmem_icc_path); + gpu->ocmem_icc_path = NULL; + /* allow -ENODATA, ocmem icc is optional */ + if (ret != -ENODATA) + return ret; + } + + return 0; } void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu) { + struct msm_gpu *gpu = &adreno_gpu->base; + struct msm_drm_private *priv = gpu->dev ? gpu->dev->dev_private : NULL; unsigned int i; for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++) release_firmware(adreno_gpu->fw[i]); + if (priv && pm_runtime_enabled(&priv->gpu_pdev->dev)) + pm_runtime_disable(&priv->gpu_pdev->dev); + msm_gpu_cleanup(&adreno_gpu->base); + + icc_put(gpu->icc_path); + icc_put(gpu->ocmem_icc_path); } -- Gitblit v1.6.2