18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */ 38c2ecf20Sopenharmony_ci/* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */ 48c2ecf20Sopenharmony_ci/* Copyright 2019 Collabora ltd. */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 88c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 98c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 108c2ecf20Sopenharmony_ci#include <drm/panfrost_drm.h> 118c2ecf20Sopenharmony_ci#include <drm/drm_drv.h> 128c2ecf20Sopenharmony_ci#include <drm/drm_ioctl.h> 138c2ecf20Sopenharmony_ci#include <drm/drm_syncobj.h> 148c2ecf20Sopenharmony_ci#include <drm/drm_utils.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "panfrost_device.h" 178c2ecf20Sopenharmony_ci#include "panfrost_gem.h" 188c2ecf20Sopenharmony_ci#include "panfrost_mmu.h" 198c2ecf20Sopenharmony_ci#include "panfrost_job.h" 208c2ecf20Sopenharmony_ci#include "panfrost_gpu.h" 218c2ecf20Sopenharmony_ci#include "panfrost_perfcnt.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic bool unstable_ioctls; 248c2ecf20Sopenharmony_cimodule_param_unsafe(unstable_ioctls, bool, 0600); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int panfrost_ioctl_get_param(struct drm_device *ddev, void *data, struct drm_file *file) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct drm_panfrost_get_param *param = data; 298c2ecf20Sopenharmony_ci struct panfrost_device *pfdev = ddev->dev_private; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (param->pad != 0) 328c2ecf20Sopenharmony_ci return -EINVAL; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define PANFROST_FEATURE(name, member) \ 358c2ecf20Sopenharmony_ci case DRM_PANFROST_PARAM_ ## name: \ 368c2ecf20Sopenharmony_ci param->value = pfdev->features.member; \ 378c2ecf20Sopenharmony_ci break 388c2ecf20Sopenharmony_ci#define PANFROST_FEATURE_ARRAY(name, member, max) \ 398c2ecf20Sopenharmony_ci case DRM_PANFROST_PARAM_ ## name ## 0 ... \ 408c2ecf20Sopenharmony_ci DRM_PANFROST_PARAM_ ## name ## max: \ 418c2ecf20Sopenharmony_ci param->value = pfdev->features.member[param->param - \ 428c2ecf20Sopenharmony_ci DRM_PANFROST_PARAM_ ## name ## 0]; \ 438c2ecf20Sopenharmony_ci break 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci switch (param->param) { 468c2ecf20Sopenharmony_ci PANFROST_FEATURE(GPU_PROD_ID, id); 478c2ecf20Sopenharmony_ci PANFROST_FEATURE(GPU_REVISION, revision); 488c2ecf20Sopenharmony_ci PANFROST_FEATURE(SHADER_PRESENT, shader_present); 498c2ecf20Sopenharmony_ci PANFROST_FEATURE(TILER_PRESENT, tiler_present); 508c2ecf20Sopenharmony_ci PANFROST_FEATURE(L2_PRESENT, l2_present); 518c2ecf20Sopenharmony_ci PANFROST_FEATURE(STACK_PRESENT, stack_present); 528c2ecf20Sopenharmony_ci PANFROST_FEATURE(AS_PRESENT, as_present); 538c2ecf20Sopenharmony_ci PANFROST_FEATURE(JS_PRESENT, js_present); 548c2ecf20Sopenharmony_ci PANFROST_FEATURE(L2_FEATURES, l2_features); 558c2ecf20Sopenharmony_ci PANFROST_FEATURE(CORE_FEATURES, core_features); 568c2ecf20Sopenharmony_ci PANFROST_FEATURE(TILER_FEATURES, tiler_features); 578c2ecf20Sopenharmony_ci PANFROST_FEATURE(MEM_FEATURES, mem_features); 588c2ecf20Sopenharmony_ci PANFROST_FEATURE(MMU_FEATURES, mmu_features); 598c2ecf20Sopenharmony_ci PANFROST_FEATURE(THREAD_FEATURES, thread_features); 608c2ecf20Sopenharmony_ci PANFROST_FEATURE(MAX_THREADS, max_threads); 618c2ecf20Sopenharmony_ci PANFROST_FEATURE(THREAD_MAX_WORKGROUP_SZ, 628c2ecf20Sopenharmony_ci thread_max_workgroup_sz); 638c2ecf20Sopenharmony_ci PANFROST_FEATURE(THREAD_MAX_BARRIER_SZ, 648c2ecf20Sopenharmony_ci thread_max_barrier_sz); 658c2ecf20Sopenharmony_ci PANFROST_FEATURE(COHERENCY_FEATURES, coherency_features); 668c2ecf20Sopenharmony_ci PANFROST_FEATURE_ARRAY(TEXTURE_FEATURES, texture_features, 3); 678c2ecf20Sopenharmony_ci PANFROST_FEATURE_ARRAY(JS_FEATURES, js_features, 15); 688c2ecf20Sopenharmony_ci PANFROST_FEATURE(NR_CORE_GROUPS, nr_core_groups); 698c2ecf20Sopenharmony_ci PANFROST_FEATURE(THREAD_TLS_ALLOC, thread_tls_alloc); 708c2ecf20Sopenharmony_ci default: 718c2ecf20Sopenharmony_ci return -EINVAL; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int panfrost_ioctl_create_bo(struct drm_device *dev, void *data, 788c2ecf20Sopenharmony_ci struct drm_file *file) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct panfrost_file_priv *priv = file->driver_priv; 818c2ecf20Sopenharmony_ci struct panfrost_gem_object *bo; 828c2ecf20Sopenharmony_ci struct drm_panfrost_create_bo *args = data; 838c2ecf20Sopenharmony_ci struct panfrost_gem_mapping *mapping; 848c2ecf20Sopenharmony_ci int ret; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (!args->size || args->pad || 878c2ecf20Sopenharmony_ci (args->flags & ~(PANFROST_BO_NOEXEC | PANFROST_BO_HEAP))) 888c2ecf20Sopenharmony_ci return -EINVAL; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* Heaps should never be executable */ 918c2ecf20Sopenharmony_ci if ((args->flags & PANFROST_BO_HEAP) && 928c2ecf20Sopenharmony_ci !(args->flags & PANFROST_BO_NOEXEC)) 938c2ecf20Sopenharmony_ci return -EINVAL; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci bo = panfrost_gem_create(dev, args->size, args->flags); 968c2ecf20Sopenharmony_ci if (IS_ERR(bo)) 978c2ecf20Sopenharmony_ci return PTR_ERR(bo); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci ret = drm_gem_handle_create(file, &bo->base.base, &args->handle); 1008c2ecf20Sopenharmony_ci if (ret) 1018c2ecf20Sopenharmony_ci goto out; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci mapping = panfrost_gem_mapping_get(bo, priv); 1048c2ecf20Sopenharmony_ci if (mapping) { 1058c2ecf20Sopenharmony_ci args->offset = mapping->mmnode.start << PAGE_SHIFT; 1068c2ecf20Sopenharmony_ci panfrost_gem_mapping_put(mapping); 1078c2ecf20Sopenharmony_ci } else { 1088c2ecf20Sopenharmony_ci /* This can only happen if the handle from 1098c2ecf20Sopenharmony_ci * drm_gem_handle_create() has already been guessed and freed 1108c2ecf20Sopenharmony_ci * by user space 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci ret = -EINVAL; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciout: 1168c2ecf20Sopenharmony_ci drm_gem_object_put(&bo->base.base); 1178c2ecf20Sopenharmony_ci return ret; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/** 1218c2ecf20Sopenharmony_ci * panfrost_lookup_bos() - Sets up job->bo[] with the GEM objects 1228c2ecf20Sopenharmony_ci * referenced by the job. 1238c2ecf20Sopenharmony_ci * @dev: DRM device 1248c2ecf20Sopenharmony_ci * @file_priv: DRM file for this fd 1258c2ecf20Sopenharmony_ci * @args: IOCTL args 1268c2ecf20Sopenharmony_ci * @job: job being set up 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * Resolve handles from userspace to BOs and attach them to job. 1298c2ecf20Sopenharmony_ci * 1308c2ecf20Sopenharmony_ci * Note that this function doesn't need to unreference the BOs on 1318c2ecf20Sopenharmony_ci * failure, because that will happen at panfrost_job_cleanup() time. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_cistatic int 1348c2ecf20Sopenharmony_cipanfrost_lookup_bos(struct drm_device *dev, 1358c2ecf20Sopenharmony_ci struct drm_file *file_priv, 1368c2ecf20Sopenharmony_ci struct drm_panfrost_submit *args, 1378c2ecf20Sopenharmony_ci struct panfrost_job *job) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct panfrost_file_priv *priv = file_priv->driver_priv; 1408c2ecf20Sopenharmony_ci struct panfrost_gem_object *bo; 1418c2ecf20Sopenharmony_ci unsigned int i; 1428c2ecf20Sopenharmony_ci int ret; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci job->bo_count = args->bo_handle_count; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (!job->bo_count) 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci job->implicit_fences = kvmalloc_array(job->bo_count, 1508c2ecf20Sopenharmony_ci sizeof(struct dma_fence *), 1518c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 1528c2ecf20Sopenharmony_ci if (!job->implicit_fences) 1538c2ecf20Sopenharmony_ci return -ENOMEM; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci ret = drm_gem_objects_lookup(file_priv, 1568c2ecf20Sopenharmony_ci (void __user *)(uintptr_t)args->bo_handles, 1578c2ecf20Sopenharmony_ci job->bo_count, &job->bos); 1588c2ecf20Sopenharmony_ci if (ret) 1598c2ecf20Sopenharmony_ci return ret; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci job->mappings = kvmalloc_array(job->bo_count, 1628c2ecf20Sopenharmony_ci sizeof(struct panfrost_gem_mapping *), 1638c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 1648c2ecf20Sopenharmony_ci if (!job->mappings) 1658c2ecf20Sopenharmony_ci return -ENOMEM; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci for (i = 0; i < job->bo_count; i++) { 1688c2ecf20Sopenharmony_ci struct panfrost_gem_mapping *mapping; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci bo = to_panfrost_bo(job->bos[i]); 1718c2ecf20Sopenharmony_ci mapping = panfrost_gem_mapping_get(bo, priv); 1728c2ecf20Sopenharmony_ci if (!mapping) { 1738c2ecf20Sopenharmony_ci ret = -EINVAL; 1748c2ecf20Sopenharmony_ci break; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci atomic_inc(&bo->gpu_usecount); 1788c2ecf20Sopenharmony_ci job->mappings[i] = mapping; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return ret; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/** 1858c2ecf20Sopenharmony_ci * panfrost_copy_in_sync() - Sets up job->in_fences[] with the sync objects 1868c2ecf20Sopenharmony_ci * referenced by the job. 1878c2ecf20Sopenharmony_ci * @dev: DRM device 1888c2ecf20Sopenharmony_ci * @file_priv: DRM file for this fd 1898c2ecf20Sopenharmony_ci * @args: IOCTL args 1908c2ecf20Sopenharmony_ci * @job: job being set up 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * Resolve syncobjs from userspace to fences and attach them to job. 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * Note that this function doesn't need to unreference the fences on 1958c2ecf20Sopenharmony_ci * failure, because that will happen at panfrost_job_cleanup() time. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cistatic int 1988c2ecf20Sopenharmony_cipanfrost_copy_in_sync(struct drm_device *dev, 1998c2ecf20Sopenharmony_ci struct drm_file *file_priv, 2008c2ecf20Sopenharmony_ci struct drm_panfrost_submit *args, 2018c2ecf20Sopenharmony_ci struct panfrost_job *job) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci u32 *handles; 2048c2ecf20Sopenharmony_ci int ret = 0; 2058c2ecf20Sopenharmony_ci int i; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci job->in_fence_count = args->in_sync_count; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (!job->in_fence_count) 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci job->in_fences = kvmalloc_array(job->in_fence_count, 2138c2ecf20Sopenharmony_ci sizeof(struct dma_fence *), 2148c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 2158c2ecf20Sopenharmony_ci if (!job->in_fences) { 2168c2ecf20Sopenharmony_ci DRM_DEBUG("Failed to allocate job in fences\n"); 2178c2ecf20Sopenharmony_ci return -ENOMEM; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci handles = kvmalloc_array(job->in_fence_count, sizeof(u32), GFP_KERNEL); 2218c2ecf20Sopenharmony_ci if (!handles) { 2228c2ecf20Sopenharmony_ci ret = -ENOMEM; 2238c2ecf20Sopenharmony_ci DRM_DEBUG("Failed to allocate incoming syncobj handles\n"); 2248c2ecf20Sopenharmony_ci goto fail; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (copy_from_user(handles, 2288c2ecf20Sopenharmony_ci (void __user *)(uintptr_t)args->in_syncs, 2298c2ecf20Sopenharmony_ci job->in_fence_count * sizeof(u32))) { 2308c2ecf20Sopenharmony_ci ret = -EFAULT; 2318c2ecf20Sopenharmony_ci DRM_DEBUG("Failed to copy in syncobj handles\n"); 2328c2ecf20Sopenharmony_ci goto fail; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci for (i = 0; i < job->in_fence_count; i++) { 2368c2ecf20Sopenharmony_ci ret = drm_syncobj_find_fence(file_priv, handles[i], 0, 0, 2378c2ecf20Sopenharmony_ci &job->in_fences[i]); 2388c2ecf20Sopenharmony_ci if (ret == -EINVAL) 2398c2ecf20Sopenharmony_ci goto fail; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cifail: 2438c2ecf20Sopenharmony_ci kvfree(handles); 2448c2ecf20Sopenharmony_ci return ret; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int panfrost_ioctl_submit(struct drm_device *dev, void *data, 2488c2ecf20Sopenharmony_ci struct drm_file *file) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct panfrost_device *pfdev = dev->dev_private; 2518c2ecf20Sopenharmony_ci struct drm_panfrost_submit *args = data; 2528c2ecf20Sopenharmony_ci struct drm_syncobj *sync_out = NULL; 2538c2ecf20Sopenharmony_ci struct panfrost_job *job; 2548c2ecf20Sopenharmony_ci int ret = 0; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (!args->jc) 2578c2ecf20Sopenharmony_ci return -EINVAL; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (args->requirements && args->requirements != PANFROST_JD_REQ_FS) 2608c2ecf20Sopenharmony_ci return -EINVAL; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (args->out_sync > 0) { 2638c2ecf20Sopenharmony_ci sync_out = drm_syncobj_find(file, args->out_sync); 2648c2ecf20Sopenharmony_ci if (!sync_out) 2658c2ecf20Sopenharmony_ci return -ENODEV; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci job = kzalloc(sizeof(*job), GFP_KERNEL); 2698c2ecf20Sopenharmony_ci if (!job) { 2708c2ecf20Sopenharmony_ci ret = -ENOMEM; 2718c2ecf20Sopenharmony_ci goto fail_out_sync; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci kref_init(&job->refcount); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci job->pfdev = pfdev; 2778c2ecf20Sopenharmony_ci job->jc = args->jc; 2788c2ecf20Sopenharmony_ci job->requirements = args->requirements; 2798c2ecf20Sopenharmony_ci job->flush_id = panfrost_gpu_get_latest_flush_id(pfdev); 2808c2ecf20Sopenharmony_ci job->file_priv = file->driver_priv; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci ret = panfrost_copy_in_sync(dev, file, args, job); 2838c2ecf20Sopenharmony_ci if (ret) 2848c2ecf20Sopenharmony_ci goto fail_job; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci ret = panfrost_lookup_bos(dev, file, args, job); 2878c2ecf20Sopenharmony_ci if (ret) 2888c2ecf20Sopenharmony_ci goto fail_job; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci ret = panfrost_job_push(job); 2918c2ecf20Sopenharmony_ci if (ret) 2928c2ecf20Sopenharmony_ci goto fail_job; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* Update the return sync object for the job */ 2958c2ecf20Sopenharmony_ci if (sync_out) 2968c2ecf20Sopenharmony_ci drm_syncobj_replace_fence(sync_out, job->render_done_fence); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cifail_job: 2998c2ecf20Sopenharmony_ci panfrost_job_put(job); 3008c2ecf20Sopenharmony_cifail_out_sync: 3018c2ecf20Sopenharmony_ci if (sync_out) 3028c2ecf20Sopenharmony_ci drm_syncobj_put(sync_out); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return ret; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int 3088c2ecf20Sopenharmony_cipanfrost_ioctl_wait_bo(struct drm_device *dev, void *data, 3098c2ecf20Sopenharmony_ci struct drm_file *file_priv) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci long ret; 3128c2ecf20Sopenharmony_ci struct drm_panfrost_wait_bo *args = data; 3138c2ecf20Sopenharmony_ci struct drm_gem_object *gem_obj; 3148c2ecf20Sopenharmony_ci unsigned long timeout = drm_timeout_abs_to_jiffies(args->timeout_ns); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (args->pad) 3178c2ecf20Sopenharmony_ci return -EINVAL; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci gem_obj = drm_gem_object_lookup(file_priv, args->handle); 3208c2ecf20Sopenharmony_ci if (!gem_obj) 3218c2ecf20Sopenharmony_ci return -ENOENT; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci ret = dma_resv_wait_timeout_rcu(gem_obj->resv, true, 3248c2ecf20Sopenharmony_ci true, timeout); 3258c2ecf20Sopenharmony_ci if (!ret) 3268c2ecf20Sopenharmony_ci ret = timeout ? -ETIMEDOUT : -EBUSY; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci drm_gem_object_put(gem_obj); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int panfrost_ioctl_mmap_bo(struct drm_device *dev, void *data, 3348c2ecf20Sopenharmony_ci struct drm_file *file_priv) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct drm_panfrost_mmap_bo *args = data; 3378c2ecf20Sopenharmony_ci struct drm_gem_object *gem_obj; 3388c2ecf20Sopenharmony_ci int ret; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (args->flags != 0) { 3418c2ecf20Sopenharmony_ci DRM_INFO("unknown mmap_bo flags: %d\n", args->flags); 3428c2ecf20Sopenharmony_ci return -EINVAL; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci gem_obj = drm_gem_object_lookup(file_priv, args->handle); 3468c2ecf20Sopenharmony_ci if (!gem_obj) { 3478c2ecf20Sopenharmony_ci DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle); 3488c2ecf20Sopenharmony_ci return -ENOENT; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* Don't allow mmapping of heap objects as pages are not pinned. */ 3528c2ecf20Sopenharmony_ci if (to_panfrost_bo(gem_obj)->is_heap) { 3538c2ecf20Sopenharmony_ci ret = -EINVAL; 3548c2ecf20Sopenharmony_ci goto out; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci ret = drm_gem_create_mmap_offset(gem_obj); 3588c2ecf20Sopenharmony_ci if (ret == 0) 3598c2ecf20Sopenharmony_ci args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ciout: 3628c2ecf20Sopenharmony_ci drm_gem_object_put(gem_obj); 3638c2ecf20Sopenharmony_ci return ret; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int panfrost_ioctl_get_bo_offset(struct drm_device *dev, void *data, 3678c2ecf20Sopenharmony_ci struct drm_file *file_priv) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct panfrost_file_priv *priv = file_priv->driver_priv; 3708c2ecf20Sopenharmony_ci struct drm_panfrost_get_bo_offset *args = data; 3718c2ecf20Sopenharmony_ci struct panfrost_gem_mapping *mapping; 3728c2ecf20Sopenharmony_ci struct drm_gem_object *gem_obj; 3738c2ecf20Sopenharmony_ci struct panfrost_gem_object *bo; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci gem_obj = drm_gem_object_lookup(file_priv, args->handle); 3768c2ecf20Sopenharmony_ci if (!gem_obj) { 3778c2ecf20Sopenharmony_ci DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle); 3788c2ecf20Sopenharmony_ci return -ENOENT; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci bo = to_panfrost_bo(gem_obj); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci mapping = panfrost_gem_mapping_get(bo, priv); 3838c2ecf20Sopenharmony_ci drm_gem_object_put(gem_obj); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (!mapping) 3868c2ecf20Sopenharmony_ci return -EINVAL; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci args->offset = mapping->mmnode.start << PAGE_SHIFT; 3898c2ecf20Sopenharmony_ci panfrost_gem_mapping_put(mapping); 3908c2ecf20Sopenharmony_ci return 0; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic int panfrost_ioctl_madvise(struct drm_device *dev, void *data, 3948c2ecf20Sopenharmony_ci struct drm_file *file_priv) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci struct panfrost_file_priv *priv = file_priv->driver_priv; 3978c2ecf20Sopenharmony_ci struct drm_panfrost_madvise *args = data; 3988c2ecf20Sopenharmony_ci struct panfrost_device *pfdev = dev->dev_private; 3998c2ecf20Sopenharmony_ci struct drm_gem_object *gem_obj; 4008c2ecf20Sopenharmony_ci struct panfrost_gem_object *bo; 4018c2ecf20Sopenharmony_ci int ret = 0; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci gem_obj = drm_gem_object_lookup(file_priv, args->handle); 4048c2ecf20Sopenharmony_ci if (!gem_obj) { 4058c2ecf20Sopenharmony_ci DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle); 4068c2ecf20Sopenharmony_ci return -ENOENT; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci bo = to_panfrost_bo(gem_obj); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci mutex_lock(&pfdev->shrinker_lock); 4128c2ecf20Sopenharmony_ci mutex_lock(&bo->mappings.lock); 4138c2ecf20Sopenharmony_ci if (args->madv == PANFROST_MADV_DONTNEED) { 4148c2ecf20Sopenharmony_ci struct panfrost_gem_mapping *first; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci first = list_first_entry(&bo->mappings.list, 4178c2ecf20Sopenharmony_ci struct panfrost_gem_mapping, 4188c2ecf20Sopenharmony_ci node); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* 4218c2ecf20Sopenharmony_ci * If we want to mark the BO purgeable, there must be only one 4228c2ecf20Sopenharmony_ci * user: the caller FD. 4238c2ecf20Sopenharmony_ci * We could do something smarter and mark the BO purgeable only 4248c2ecf20Sopenharmony_ci * when all its users have marked it purgeable, but globally 4258c2ecf20Sopenharmony_ci * visible/shared BOs are likely to never be marked purgeable 4268c2ecf20Sopenharmony_ci * anyway, so let's not bother. 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_ci if (!list_is_singular(&bo->mappings.list) || 4298c2ecf20Sopenharmony_ci WARN_ON_ONCE(first->mmu != priv->mmu)) { 4308c2ecf20Sopenharmony_ci ret = -EINVAL; 4318c2ecf20Sopenharmony_ci goto out_unlock_mappings; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci args->retained = drm_gem_shmem_madvise(gem_obj, args->madv); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (args->retained) { 4388c2ecf20Sopenharmony_ci if (args->madv == PANFROST_MADV_DONTNEED) 4398c2ecf20Sopenharmony_ci list_move_tail(&bo->base.madv_list, 4408c2ecf20Sopenharmony_ci &pfdev->shrinker_list); 4418c2ecf20Sopenharmony_ci else if (args->madv == PANFROST_MADV_WILLNEED) 4428c2ecf20Sopenharmony_ci list_del_init(&bo->base.madv_list); 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ciout_unlock_mappings: 4468c2ecf20Sopenharmony_ci mutex_unlock(&bo->mappings.lock); 4478c2ecf20Sopenharmony_ci mutex_unlock(&pfdev->shrinker_lock); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci drm_gem_object_put(gem_obj); 4508c2ecf20Sopenharmony_ci return ret; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ciint panfrost_unstable_ioctl_check(void) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci if (!unstable_ioctls) 4568c2ecf20Sopenharmony_ci return -ENOSYS; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return 0; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int 4628c2ecf20Sopenharmony_cipanfrost_open(struct drm_device *dev, struct drm_file *file) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci int ret; 4658c2ecf20Sopenharmony_ci struct panfrost_device *pfdev = dev->dev_private; 4668c2ecf20Sopenharmony_ci struct panfrost_file_priv *panfrost_priv; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci panfrost_priv = kzalloc(sizeof(*panfrost_priv), GFP_KERNEL); 4698c2ecf20Sopenharmony_ci if (!panfrost_priv) 4708c2ecf20Sopenharmony_ci return -ENOMEM; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci panfrost_priv->pfdev = pfdev; 4738c2ecf20Sopenharmony_ci file->driver_priv = panfrost_priv; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci panfrost_priv->mmu = panfrost_mmu_ctx_create(pfdev); 4768c2ecf20Sopenharmony_ci if (IS_ERR(panfrost_priv->mmu)) { 4778c2ecf20Sopenharmony_ci ret = PTR_ERR(panfrost_priv->mmu); 4788c2ecf20Sopenharmony_ci goto err_free; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci ret = panfrost_job_open(panfrost_priv); 4828c2ecf20Sopenharmony_ci if (ret) 4838c2ecf20Sopenharmony_ci goto err_job; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return 0; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cierr_job: 4888c2ecf20Sopenharmony_ci panfrost_mmu_ctx_put(panfrost_priv->mmu); 4898c2ecf20Sopenharmony_cierr_free: 4908c2ecf20Sopenharmony_ci kfree(panfrost_priv); 4918c2ecf20Sopenharmony_ci return ret; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic void 4958c2ecf20Sopenharmony_cipanfrost_postclose(struct drm_device *dev, struct drm_file *file) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci struct panfrost_file_priv *panfrost_priv = file->driver_priv; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci panfrost_perfcnt_close(file); 5008c2ecf20Sopenharmony_ci panfrost_job_close(panfrost_priv); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci panfrost_mmu_ctx_put(panfrost_priv->mmu); 5038c2ecf20Sopenharmony_ci kfree(panfrost_priv); 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = { 5078c2ecf20Sopenharmony_ci#define PANFROST_IOCTL(n, func, flags) \ 5088c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(PANFROST_##n, panfrost_ioctl_##func, flags) 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci PANFROST_IOCTL(SUBMIT, submit, DRM_RENDER_ALLOW), 5118c2ecf20Sopenharmony_ci PANFROST_IOCTL(WAIT_BO, wait_bo, DRM_RENDER_ALLOW), 5128c2ecf20Sopenharmony_ci PANFROST_IOCTL(CREATE_BO, create_bo, DRM_RENDER_ALLOW), 5138c2ecf20Sopenharmony_ci PANFROST_IOCTL(MMAP_BO, mmap_bo, DRM_RENDER_ALLOW), 5148c2ecf20Sopenharmony_ci PANFROST_IOCTL(GET_PARAM, get_param, DRM_RENDER_ALLOW), 5158c2ecf20Sopenharmony_ci PANFROST_IOCTL(GET_BO_OFFSET, get_bo_offset, DRM_RENDER_ALLOW), 5168c2ecf20Sopenharmony_ci PANFROST_IOCTL(PERFCNT_ENABLE, perfcnt_enable, DRM_RENDER_ALLOW), 5178c2ecf20Sopenharmony_ci PANFROST_IOCTL(PERFCNT_DUMP, perfcnt_dump, DRM_RENDER_ALLOW), 5188c2ecf20Sopenharmony_ci PANFROST_IOCTL(MADVISE, madvise, DRM_RENDER_ALLOW), 5198c2ecf20Sopenharmony_ci}; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ciDEFINE_DRM_GEM_FOPS(panfrost_drm_driver_fops); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci/* 5248c2ecf20Sopenharmony_ci * Panfrost driver version: 5258c2ecf20Sopenharmony_ci * - 1.0 - initial interface 5268c2ecf20Sopenharmony_ci * - 1.1 - adds HEAP and NOEXEC flags for CREATE_BO 5278c2ecf20Sopenharmony_ci */ 5288c2ecf20Sopenharmony_cistatic struct drm_driver panfrost_drm_driver = { 5298c2ecf20Sopenharmony_ci .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ, 5308c2ecf20Sopenharmony_ci .open = panfrost_open, 5318c2ecf20Sopenharmony_ci .postclose = panfrost_postclose, 5328c2ecf20Sopenharmony_ci .ioctls = panfrost_drm_driver_ioctls, 5338c2ecf20Sopenharmony_ci .num_ioctls = ARRAY_SIZE(panfrost_drm_driver_ioctls), 5348c2ecf20Sopenharmony_ci .fops = &panfrost_drm_driver_fops, 5358c2ecf20Sopenharmony_ci .name = "panfrost", 5368c2ecf20Sopenharmony_ci .desc = "panfrost DRM", 5378c2ecf20Sopenharmony_ci .date = "20180908", 5388c2ecf20Sopenharmony_ci .major = 1, 5398c2ecf20Sopenharmony_ci .minor = 1, 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci .gem_create_object = panfrost_gem_create_object, 5428c2ecf20Sopenharmony_ci .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 5438c2ecf20Sopenharmony_ci .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 5448c2ecf20Sopenharmony_ci .gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table, 5458c2ecf20Sopenharmony_ci .gem_prime_mmap = drm_gem_prime_mmap, 5468c2ecf20Sopenharmony_ci}; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic int panfrost_probe(struct platform_device *pdev) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct panfrost_device *pfdev; 5518c2ecf20Sopenharmony_ci struct drm_device *ddev; 5528c2ecf20Sopenharmony_ci int err; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci pfdev = devm_kzalloc(&pdev->dev, sizeof(*pfdev), GFP_KERNEL); 5558c2ecf20Sopenharmony_ci if (!pfdev) 5568c2ecf20Sopenharmony_ci return -ENOMEM; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci pfdev->pdev = pdev; 5598c2ecf20Sopenharmony_ci pfdev->dev = &pdev->dev; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pfdev); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci pfdev->comp = of_device_get_match_data(&pdev->dev); 5648c2ecf20Sopenharmony_ci if (!pfdev->comp) 5658c2ecf20Sopenharmony_ci return -ENODEV; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci pfdev->coherent = device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci /* Allocate and initialze the DRM device. */ 5708c2ecf20Sopenharmony_ci ddev = drm_dev_alloc(&panfrost_drm_driver, &pdev->dev); 5718c2ecf20Sopenharmony_ci if (IS_ERR(ddev)) 5728c2ecf20Sopenharmony_ci return PTR_ERR(ddev); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci ddev->dev_private = pfdev; 5758c2ecf20Sopenharmony_ci pfdev->ddev = ddev; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci mutex_init(&pfdev->shrinker_lock); 5788c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pfdev->shrinker_list); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci err = panfrost_device_init(pfdev); 5818c2ecf20Sopenharmony_ci if (err) { 5828c2ecf20Sopenharmony_ci if (err != -EPROBE_DEFER) 5838c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Fatal error during GPU init\n"); 5848c2ecf20Sopenharmony_ci goto err_out0; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci pm_runtime_set_active(pfdev->dev); 5888c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(pfdev->dev); 5898c2ecf20Sopenharmony_ci pm_runtime_enable(pfdev->dev); 5908c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(pfdev->dev, 50); /* ~3 frames */ 5918c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(pfdev->dev); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* 5948c2ecf20Sopenharmony_ci * Register the DRM device with the core and the connectors with 5958c2ecf20Sopenharmony_ci * sysfs 5968c2ecf20Sopenharmony_ci */ 5978c2ecf20Sopenharmony_ci err = drm_dev_register(ddev, 0); 5988c2ecf20Sopenharmony_ci if (err < 0) 5998c2ecf20Sopenharmony_ci goto err_out1; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci panfrost_gem_shrinker_init(ddev); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci return 0; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cierr_out1: 6068c2ecf20Sopenharmony_ci pm_runtime_disable(pfdev->dev); 6078c2ecf20Sopenharmony_ci panfrost_device_fini(pfdev); 6088c2ecf20Sopenharmony_ci pm_runtime_set_suspended(pfdev->dev); 6098c2ecf20Sopenharmony_cierr_out0: 6108c2ecf20Sopenharmony_ci drm_dev_put(ddev); 6118c2ecf20Sopenharmony_ci return err; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic int panfrost_remove(struct platform_device *pdev) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct panfrost_device *pfdev = platform_get_drvdata(pdev); 6178c2ecf20Sopenharmony_ci struct drm_device *ddev = pfdev->ddev; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci drm_dev_unregister(ddev); 6208c2ecf20Sopenharmony_ci panfrost_gem_shrinker_cleanup(ddev); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci pm_runtime_get_sync(pfdev->dev); 6238c2ecf20Sopenharmony_ci pm_runtime_disable(pfdev->dev); 6248c2ecf20Sopenharmony_ci panfrost_device_fini(pfdev); 6258c2ecf20Sopenharmony_ci pm_runtime_set_suspended(pfdev->dev); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci drm_dev_put(ddev); 6288c2ecf20Sopenharmony_ci return 0; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic const char * const default_supplies[] = { "mali" }; 6328c2ecf20Sopenharmony_cistatic const struct panfrost_compatible default_data = { 6338c2ecf20Sopenharmony_ci .num_supplies = ARRAY_SIZE(default_supplies), 6348c2ecf20Sopenharmony_ci .supply_names = default_supplies, 6358c2ecf20Sopenharmony_ci .num_pm_domains = 1, /* optional */ 6368c2ecf20Sopenharmony_ci .pm_domain_names = NULL, 6378c2ecf20Sopenharmony_ci}; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic const struct panfrost_compatible amlogic_data = { 6408c2ecf20Sopenharmony_ci .num_supplies = ARRAY_SIZE(default_supplies), 6418c2ecf20Sopenharmony_ci .supply_names = default_supplies, 6428c2ecf20Sopenharmony_ci .vendor_quirk = panfrost_gpu_amlogic_quirk, 6438c2ecf20Sopenharmony_ci}; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic const struct of_device_id dt_match[] = { 6468c2ecf20Sopenharmony_ci /* Set first to probe before the generic compatibles */ 6478c2ecf20Sopenharmony_ci { .compatible = "amlogic,meson-gxm-mali", 6488c2ecf20Sopenharmony_ci .data = &amlogic_data, }, 6498c2ecf20Sopenharmony_ci { .compatible = "amlogic,meson-g12a-mali", 6508c2ecf20Sopenharmony_ci .data = &amlogic_data, }, 6518c2ecf20Sopenharmony_ci { .compatible = "arm,mali-t604", .data = &default_data, }, 6528c2ecf20Sopenharmony_ci { .compatible = "arm,mali-t624", .data = &default_data, }, 6538c2ecf20Sopenharmony_ci { .compatible = "arm,mali-t628", .data = &default_data, }, 6548c2ecf20Sopenharmony_ci { .compatible = "arm,mali-t720", .data = &default_data, }, 6558c2ecf20Sopenharmony_ci { .compatible = "arm,mali-t760", .data = &default_data, }, 6568c2ecf20Sopenharmony_ci { .compatible = "arm,mali-t820", .data = &default_data, }, 6578c2ecf20Sopenharmony_ci { .compatible = "arm,mali-t830", .data = &default_data, }, 6588c2ecf20Sopenharmony_ci { .compatible = "arm,mali-t860", .data = &default_data, }, 6598c2ecf20Sopenharmony_ci { .compatible = "arm,mali-t880", .data = &default_data, }, 6608c2ecf20Sopenharmony_ci { .compatible = "arm,mali-bifrost", .data = &default_data, }, 6618c2ecf20Sopenharmony_ci {} 6628c2ecf20Sopenharmony_ci}; 6638c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, dt_match); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic const struct dev_pm_ops panfrost_pm_ops = { 6668c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) 6678c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(panfrost_device_suspend, panfrost_device_resume, NULL) 6688c2ecf20Sopenharmony_ci}; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic struct platform_driver panfrost_driver = { 6718c2ecf20Sopenharmony_ci .probe = panfrost_probe, 6728c2ecf20Sopenharmony_ci .remove = panfrost_remove, 6738c2ecf20Sopenharmony_ci .driver = { 6748c2ecf20Sopenharmony_ci .name = "panfrost", 6758c2ecf20Sopenharmony_ci .pm = &panfrost_pm_ops, 6768c2ecf20Sopenharmony_ci .of_match_table = dt_match, 6778c2ecf20Sopenharmony_ci }, 6788c2ecf20Sopenharmony_ci}; 6798c2ecf20Sopenharmony_cimodule_platform_driver(panfrost_driver); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ciMODULE_AUTHOR("Panfrost Project Developers"); 6828c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Panfrost DRM Driver"); 6838c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 684