Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */ |
| 3 | /* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */ |
| 4 | /* Copyright 2019 Collabora ltd. */ |
| 5 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 6 | #include <linux/module.h> |
| 7 | #include <linux/of_platform.h> |
| 8 | #include <linux/pagemap.h> |
| 9 | #include <linux/pm_runtime.h> |
| 10 | #include <drm/panfrost_drm.h> |
| 11 | #include <drm/drm_drv.h> |
| 12 | #include <drm/drm_ioctl.h> |
| 13 | #include <drm/drm_syncobj.h> |
| 14 | #include <drm/drm_utils.h> |
| 15 | |
| 16 | #include "panfrost_device.h" |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 17 | #include "panfrost_gem.h" |
| 18 | #include "panfrost_mmu.h" |
| 19 | #include "panfrost_job.h" |
| 20 | #include "panfrost_gpu.h" |
Boris Brezillon | 7786fd1 | 2019-06-18 10:16:48 +0200 | [diff] [blame] | 21 | #include "panfrost_perfcnt.h" |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 22 | |
Boris Brezillon | 92f0ad0 | 2019-06-18 10:16:46 +0200 | [diff] [blame] | 23 | static bool unstable_ioctls; |
| 24 | module_param_unsafe(unstable_ioctls, bool, 0600); |
| 25 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 26 | static int panfrost_ioctl_get_param(struct drm_device *ddev, void *data, struct drm_file *file) |
| 27 | { |
| 28 | struct drm_panfrost_get_param *param = data; |
| 29 | struct panfrost_device *pfdev = ddev->dev_private; |
| 30 | |
| 31 | if (param->pad != 0) |
| 32 | return -EINVAL; |
| 33 | |
Steven Price | 4bced8b | 2019-07-24 11:56:26 +0100 | [diff] [blame] | 34 | #define PANFROST_FEATURE(name, member) \ |
| 35 | case DRM_PANFROST_PARAM_ ## name: \ |
| 36 | param->value = pfdev->features.member; \ |
| 37 | break |
| 38 | #define PANFROST_FEATURE_ARRAY(name, member, max) \ |
| 39 | case DRM_PANFROST_PARAM_ ## name ## 0 ... \ |
| 40 | DRM_PANFROST_PARAM_ ## name ## max: \ |
| 41 | param->value = pfdev->features.member[param->param - \ |
| 42 | DRM_PANFROST_PARAM_ ## name ## 0]; \ |
| 43 | break |
| 44 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 45 | switch (param->param) { |
Steven Price | 4bced8b | 2019-07-24 11:56:26 +0100 | [diff] [blame] | 46 | PANFROST_FEATURE(GPU_PROD_ID, id); |
| 47 | PANFROST_FEATURE(GPU_REVISION, revision); |
| 48 | PANFROST_FEATURE(SHADER_PRESENT, shader_present); |
| 49 | PANFROST_FEATURE(TILER_PRESENT, tiler_present); |
| 50 | PANFROST_FEATURE(L2_PRESENT, l2_present); |
| 51 | PANFROST_FEATURE(STACK_PRESENT, stack_present); |
| 52 | PANFROST_FEATURE(AS_PRESENT, as_present); |
| 53 | PANFROST_FEATURE(JS_PRESENT, js_present); |
| 54 | PANFROST_FEATURE(L2_FEATURES, l2_features); |
| 55 | PANFROST_FEATURE(CORE_FEATURES, core_features); |
| 56 | PANFROST_FEATURE(TILER_FEATURES, tiler_features); |
| 57 | PANFROST_FEATURE(MEM_FEATURES, mem_features); |
| 58 | PANFROST_FEATURE(MMU_FEATURES, mmu_features); |
| 59 | PANFROST_FEATURE(THREAD_FEATURES, thread_features); |
| 60 | PANFROST_FEATURE(MAX_THREADS, max_threads); |
| 61 | PANFROST_FEATURE(THREAD_MAX_WORKGROUP_SZ, |
| 62 | thread_max_workgroup_sz); |
| 63 | PANFROST_FEATURE(THREAD_MAX_BARRIER_SZ, |
| 64 | thread_max_barrier_sz); |
| 65 | PANFROST_FEATURE(COHERENCY_FEATURES, coherency_features); |
Alyssa Rosenzweig | 3e2926f | 2021-06-04 09:00:11 -0400 | [diff] [blame] | 66 | PANFROST_FEATURE(AFBC_FEATURES, afbc_features); |
Steven Price | 4bced8b | 2019-07-24 11:56:26 +0100 | [diff] [blame] | 67 | PANFROST_FEATURE_ARRAY(TEXTURE_FEATURES, texture_features, 3); |
| 68 | PANFROST_FEATURE_ARRAY(JS_FEATURES, js_features, 15); |
| 69 | PANFROST_FEATURE(NR_CORE_GROUPS, nr_core_groups); |
| 70 | PANFROST_FEATURE(THREAD_TLS_ALLOC, thread_tls_alloc); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 71 | default: |
| 72 | return -EINVAL; |
| 73 | } |
| 74 | |
| 75 | return 0; |
| 76 | } |
| 77 | |
| 78 | static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data, |
| 79 | struct drm_file *file) |
| 80 | { |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 81 | struct panfrost_file_priv *priv = file->driver_priv; |
Rob Herring | 203270c | 2019-07-11 15:56:14 -0600 | [diff] [blame] | 82 | struct panfrost_gem_object *bo; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 83 | struct drm_panfrost_create_bo *args = data; |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 84 | struct panfrost_gem_mapping *mapping; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 85 | |
Rob Herring | 203270c | 2019-07-11 15:56:14 -0600 | [diff] [blame] | 86 | if (!args->size || args->pad || |
Rob Herring | 187d292 | 2019-07-26 16:09:43 -0600 | [diff] [blame] | 87 | (args->flags & ~(PANFROST_BO_NOEXEC | PANFROST_BO_HEAP))) |
| 88 | return -EINVAL; |
| 89 | |
| 90 | /* Heaps should never be executable */ |
| 91 | if ((args->flags & PANFROST_BO_HEAP) && |
| 92 | !(args->flags & PANFROST_BO_NOEXEC)) |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 93 | return -EINVAL; |
| 94 | |
Rob Herring | 203270c | 2019-07-11 15:56:14 -0600 | [diff] [blame] | 95 | bo = panfrost_gem_create_with_handle(file, dev, args->size, args->flags, |
| 96 | &args->handle); |
| 97 | if (IS_ERR(bo)) |
| 98 | return PTR_ERR(bo); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 99 | |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 100 | mapping = panfrost_gem_mapping_get(bo, priv); |
| 101 | if (!mapping) { |
Emil Velikov | 496d0cc | 2020-05-15 10:51:07 +0100 | [diff] [blame] | 102 | drm_gem_object_put(&bo->base.base); |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 103 | return -EINVAL; |
| 104 | } |
| 105 | |
| 106 | args->offset = mapping->mmnode.start << PAGE_SHIFT; |
| 107 | panfrost_gem_mapping_put(mapping); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 108 | |
| 109 | return 0; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 110 | } |
| 111 | |
| 112 | /** |
| 113 | * panfrost_lookup_bos() - Sets up job->bo[] with the GEM objects |
| 114 | * referenced by the job. |
| 115 | * @dev: DRM device |
| 116 | * @file_priv: DRM file for this fd |
| 117 | * @args: IOCTL args |
| 118 | * @job: job being set up |
| 119 | * |
| 120 | * Resolve handles from userspace to BOs and attach them to job. |
| 121 | * |
| 122 | * Note that this function doesn't need to unreference the BOs on |
| 123 | * failure, because that will happen at panfrost_job_cleanup() time. |
| 124 | */ |
| 125 | static int |
| 126 | panfrost_lookup_bos(struct drm_device *dev, |
| 127 | struct drm_file *file_priv, |
| 128 | struct drm_panfrost_submit *args, |
| 129 | struct panfrost_job *job) |
| 130 | { |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 131 | struct panfrost_file_priv *priv = file_priv->driver_priv; |
| 132 | struct panfrost_gem_object *bo; |
| 133 | unsigned int i; |
| 134 | int ret; |
| 135 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 136 | job->bo_count = args->bo_handle_count; |
| 137 | |
| 138 | if (!job->bo_count) |
| 139 | return 0; |
| 140 | |
| 141 | job->implicit_fences = kvmalloc_array(job->bo_count, |
| 142 | sizeof(struct dma_fence *), |
| 143 | GFP_KERNEL | __GFP_ZERO); |
| 144 | if (!job->implicit_fences) |
| 145 | return -ENOMEM; |
| 146 | |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 147 | ret = drm_gem_objects_lookup(file_priv, |
| 148 | (void __user *)(uintptr_t)args->bo_handles, |
| 149 | job->bo_count, &job->bos); |
| 150 | if (ret) |
| 151 | return ret; |
| 152 | |
| 153 | job->mappings = kvmalloc_array(job->bo_count, |
| 154 | sizeof(struct panfrost_gem_mapping *), |
| 155 | GFP_KERNEL | __GFP_ZERO); |
| 156 | if (!job->mappings) |
| 157 | return -ENOMEM; |
| 158 | |
| 159 | for (i = 0; i < job->bo_count; i++) { |
| 160 | struct panfrost_gem_mapping *mapping; |
| 161 | |
| 162 | bo = to_panfrost_bo(job->bos[i]); |
| 163 | mapping = panfrost_gem_mapping_get(bo, priv); |
| 164 | if (!mapping) { |
| 165 | ret = -EINVAL; |
| 166 | break; |
| 167 | } |
| 168 | |
Boris Brezillon | 7e0cf7e | 2019-11-29 14:59:08 +0100 | [diff] [blame] | 169 | atomic_inc(&bo->gpu_usecount); |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 170 | job->mappings[i] = mapping; |
| 171 | } |
| 172 | |
| 173 | return ret; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 174 | } |
| 175 | |
| 176 | /** |
| 177 | * panfrost_copy_in_sync() - Sets up job->in_fences[] with the sync objects |
| 178 | * referenced by the job. |
| 179 | * @dev: DRM device |
| 180 | * @file_priv: DRM file for this fd |
| 181 | * @args: IOCTL args |
| 182 | * @job: job being set up |
| 183 | * |
| 184 | * Resolve syncobjs from userspace to fences and attach them to job. |
| 185 | * |
| 186 | * Note that this function doesn't need to unreference the fences on |
| 187 | * failure, because that will happen at panfrost_job_cleanup() time. |
| 188 | */ |
| 189 | static int |
| 190 | panfrost_copy_in_sync(struct drm_device *dev, |
| 191 | struct drm_file *file_priv, |
| 192 | struct drm_panfrost_submit *args, |
| 193 | struct panfrost_job *job) |
| 194 | { |
| 195 | u32 *handles; |
| 196 | int ret = 0; |
| 197 | int i; |
| 198 | |
| 199 | job->in_fence_count = args->in_sync_count; |
| 200 | |
| 201 | if (!job->in_fence_count) |
| 202 | return 0; |
| 203 | |
| 204 | job->in_fences = kvmalloc_array(job->in_fence_count, |
| 205 | sizeof(struct dma_fence *), |
| 206 | GFP_KERNEL | __GFP_ZERO); |
| 207 | if (!job->in_fences) { |
| 208 | DRM_DEBUG("Failed to allocate job in fences\n"); |
| 209 | return -ENOMEM; |
| 210 | } |
| 211 | |
| 212 | handles = kvmalloc_array(job->in_fence_count, sizeof(u32), GFP_KERNEL); |
| 213 | if (!handles) { |
| 214 | ret = -ENOMEM; |
| 215 | DRM_DEBUG("Failed to allocate incoming syncobj handles\n"); |
| 216 | goto fail; |
| 217 | } |
| 218 | |
| 219 | if (copy_from_user(handles, |
| 220 | (void __user *)(uintptr_t)args->in_syncs, |
| 221 | job->in_fence_count * sizeof(u32))) { |
| 222 | ret = -EFAULT; |
| 223 | DRM_DEBUG("Failed to copy in syncobj handles\n"); |
| 224 | goto fail; |
| 225 | } |
| 226 | |
| 227 | for (i = 0; i < job->in_fence_count; i++) { |
| 228 | ret = drm_syncobj_find_fence(file_priv, handles[i], 0, 0, |
| 229 | &job->in_fences[i]); |
| 230 | if (ret == -EINVAL) |
| 231 | goto fail; |
| 232 | } |
| 233 | |
| 234 | fail: |
| 235 | kvfree(handles); |
| 236 | return ret; |
| 237 | } |
| 238 | |
| 239 | static int panfrost_ioctl_submit(struct drm_device *dev, void *data, |
| 240 | struct drm_file *file) |
| 241 | { |
| 242 | struct panfrost_device *pfdev = dev->dev_private; |
| 243 | struct drm_panfrost_submit *args = data; |
Tomeu Vizoso | 6ff408e | 2019-04-24 15:13:53 +0200 | [diff] [blame] | 244 | struct drm_syncobj *sync_out = NULL; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 245 | struct panfrost_job *job; |
| 246 | int ret = 0; |
| 247 | |
Tomeu Vizoso | 6ff408e | 2019-04-24 15:13:53 +0200 | [diff] [blame] | 248 | if (!args->jc) |
| 249 | return -EINVAL; |
| 250 | |
| 251 | if (args->requirements && args->requirements != PANFROST_JD_REQ_FS) |
| 252 | return -EINVAL; |
| 253 | |
| 254 | if (args->out_sync > 0) { |
| 255 | sync_out = drm_syncobj_find(file, args->out_sync); |
| 256 | if (!sync_out) |
| 257 | return -ENODEV; |
| 258 | } |
| 259 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 260 | job = kzalloc(sizeof(*job), GFP_KERNEL); |
Tomeu Vizoso | 6ff408e | 2019-04-24 15:13:53 +0200 | [diff] [blame] | 261 | if (!job) { |
| 262 | ret = -ENOMEM; |
| 263 | goto fail_out_sync; |
| 264 | } |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 265 | |
| 266 | kref_init(&job->refcount); |
| 267 | |
| 268 | job->pfdev = pfdev; |
| 269 | job->jc = args->jc; |
| 270 | job->requirements = args->requirements; |
| 271 | job->flush_id = panfrost_gpu_get_latest_flush_id(pfdev); |
| 272 | job->file_priv = file->driver_priv; |
| 273 | |
| 274 | ret = panfrost_copy_in_sync(dev, file, args, job); |
| 275 | if (ret) |
Tomeu Vizoso | 6ff408e | 2019-04-24 15:13:53 +0200 | [diff] [blame] | 276 | goto fail_job; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 277 | |
| 278 | ret = panfrost_lookup_bos(dev, file, args, job); |
| 279 | if (ret) |
Tomeu Vizoso | 6ff408e | 2019-04-24 15:13:53 +0200 | [diff] [blame] | 280 | goto fail_job; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 281 | |
| 282 | ret = panfrost_job_push(job); |
| 283 | if (ret) |
Tomeu Vizoso | 6ff408e | 2019-04-24 15:13:53 +0200 | [diff] [blame] | 284 | goto fail_job; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 285 | |
| 286 | /* Update the return sync object for the job */ |
Tomeu Vizoso | 6ff408e | 2019-04-24 15:13:53 +0200 | [diff] [blame] | 287 | if (sync_out) |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 288 | drm_syncobj_replace_fence(sync_out, job->render_done_fence); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 289 | |
Tomeu Vizoso | 6ff408e | 2019-04-24 15:13:53 +0200 | [diff] [blame] | 290 | fail_job: |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 291 | panfrost_job_put(job); |
Tomeu Vizoso | 6ff408e | 2019-04-24 15:13:53 +0200 | [diff] [blame] | 292 | fail_out_sync: |
Tomeu Vizoso | cc2e787 | 2019-05-09 10:21:51 +0200 | [diff] [blame] | 293 | if (sync_out) |
| 294 | drm_syncobj_put(sync_out); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 295 | |
| 296 | return ret; |
| 297 | } |
| 298 | |
| 299 | static int |
| 300 | panfrost_ioctl_wait_bo(struct drm_device *dev, void *data, |
| 301 | struct drm_file *file_priv) |
| 302 | { |
| 303 | long ret; |
| 304 | struct drm_panfrost_wait_bo *args = data; |
| 305 | struct drm_gem_object *gem_obj; |
| 306 | unsigned long timeout = drm_timeout_abs_to_jiffies(args->timeout_ns); |
| 307 | |
| 308 | if (args->pad) |
| 309 | return -EINVAL; |
| 310 | |
| 311 | gem_obj = drm_gem_object_lookup(file_priv, args->handle); |
| 312 | if (!gem_obj) |
| 313 | return -ENOENT; |
| 314 | |
Christian König | d3fae3b | 2021-06-02 13:01:15 +0200 | [diff] [blame] | 315 | ret = dma_resv_wait_timeout(gem_obj->resv, true, true, timeout); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 316 | if (!ret) |
| 317 | ret = timeout ? -ETIMEDOUT : -EBUSY; |
| 318 | |
Emil Velikov | 496d0cc | 2020-05-15 10:51:07 +0100 | [diff] [blame] | 319 | drm_gem_object_put(gem_obj); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 320 | |
| 321 | return ret; |
| 322 | } |
| 323 | |
| 324 | static int panfrost_ioctl_mmap_bo(struct drm_device *dev, void *data, |
| 325 | struct drm_file *file_priv) |
| 326 | { |
| 327 | struct drm_panfrost_mmap_bo *args = data; |
Rob Herring | e6be0a9 | 2019-08-07 10:52:48 -0400 | [diff] [blame] | 328 | struct drm_gem_object *gem_obj; |
| 329 | int ret; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 330 | |
| 331 | if (args->flags != 0) { |
| 332 | DRM_INFO("unknown mmap_bo flags: %d\n", args->flags); |
| 333 | return -EINVAL; |
| 334 | } |
| 335 | |
Rob Herring | e6be0a9 | 2019-08-07 10:52:48 -0400 | [diff] [blame] | 336 | gem_obj = drm_gem_object_lookup(file_priv, args->handle); |
| 337 | if (!gem_obj) { |
| 338 | DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle); |
| 339 | return -ENOENT; |
| 340 | } |
| 341 | |
Rob Herring | 187d292 | 2019-07-26 16:09:43 -0600 | [diff] [blame] | 342 | /* Don't allow mmapping of heap objects as pages are not pinned. */ |
Boris Brezillon | 3bb69db | 2019-11-29 14:59:03 +0100 | [diff] [blame] | 343 | if (to_panfrost_bo(gem_obj)->is_heap) { |
| 344 | ret = -EINVAL; |
| 345 | goto out; |
| 346 | } |
Rob Herring | 187d292 | 2019-07-26 16:09:43 -0600 | [diff] [blame] | 347 | |
Rob Herring | e6be0a9 | 2019-08-07 10:52:48 -0400 | [diff] [blame] | 348 | ret = drm_gem_create_mmap_offset(gem_obj); |
| 349 | if (ret == 0) |
| 350 | args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node); |
Rob Herring | e6be0a9 | 2019-08-07 10:52:48 -0400 | [diff] [blame] | 351 | |
Boris Brezillon | 3bb69db | 2019-11-29 14:59:03 +0100 | [diff] [blame] | 352 | out: |
Emil Velikov | 496d0cc | 2020-05-15 10:51:07 +0100 | [diff] [blame] | 353 | drm_gem_object_put(gem_obj); |
Rob Herring | e6be0a9 | 2019-08-07 10:52:48 -0400 | [diff] [blame] | 354 | return ret; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 355 | } |
| 356 | |
| 357 | static int panfrost_ioctl_get_bo_offset(struct drm_device *dev, void *data, |
| 358 | struct drm_file *file_priv) |
| 359 | { |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 360 | struct panfrost_file_priv *priv = file_priv->driver_priv; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 361 | struct drm_panfrost_get_bo_offset *args = data; |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 362 | struct panfrost_gem_mapping *mapping; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 363 | struct drm_gem_object *gem_obj; |
| 364 | struct panfrost_gem_object *bo; |
| 365 | |
| 366 | gem_obj = drm_gem_object_lookup(file_priv, args->handle); |
| 367 | if (!gem_obj) { |
| 368 | DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle); |
| 369 | return -ENOENT; |
| 370 | } |
| 371 | bo = to_panfrost_bo(gem_obj); |
| 372 | |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 373 | mapping = panfrost_gem_mapping_get(bo, priv); |
Emil Velikov | 496d0cc | 2020-05-15 10:51:07 +0100 | [diff] [blame] | 374 | drm_gem_object_put(gem_obj); |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 375 | |
| 376 | if (!mapping) |
| 377 | return -EINVAL; |
| 378 | |
| 379 | args->offset = mapping->mmnode.start << PAGE_SHIFT; |
| 380 | panfrost_gem_mapping_put(mapping); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 381 | return 0; |
| 382 | } |
| 383 | |
Rob Herring | 013b65101 | 2019-08-05 08:33:58 -0600 | [diff] [blame] | 384 | static int panfrost_ioctl_madvise(struct drm_device *dev, void *data, |
| 385 | struct drm_file *file_priv) |
| 386 | { |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 387 | struct panfrost_file_priv *priv = file_priv->driver_priv; |
Rob Herring | 013b65101 | 2019-08-05 08:33:58 -0600 | [diff] [blame] | 388 | struct drm_panfrost_madvise *args = data; |
| 389 | struct panfrost_device *pfdev = dev->dev_private; |
| 390 | struct drm_gem_object *gem_obj; |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 391 | struct panfrost_gem_object *bo; |
| 392 | int ret = 0; |
Rob Herring | 013b65101 | 2019-08-05 08:33:58 -0600 | [diff] [blame] | 393 | |
| 394 | gem_obj = drm_gem_object_lookup(file_priv, args->handle); |
| 395 | if (!gem_obj) { |
| 396 | DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle); |
| 397 | return -ENOENT; |
| 398 | } |
| 399 | |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 400 | bo = to_panfrost_bo(gem_obj); |
| 401 | |
Boris Brezillon | 70cc779 | 2019-11-29 14:59:02 +0100 | [diff] [blame] | 402 | mutex_lock(&pfdev->shrinker_lock); |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 403 | mutex_lock(&bo->mappings.lock); |
| 404 | if (args->madv == PANFROST_MADV_DONTNEED) { |
| 405 | struct panfrost_gem_mapping *first; |
| 406 | |
| 407 | first = list_first_entry(&bo->mappings.list, |
| 408 | struct panfrost_gem_mapping, |
| 409 | node); |
| 410 | |
| 411 | /* |
| 412 | * If we want to mark the BO purgeable, there must be only one |
| 413 | * user: the caller FD. |
| 414 | * We could do something smarter and mark the BO purgeable only |
| 415 | * when all its users have marked it purgeable, but globally |
| 416 | * visible/shared BOs are likely to never be marked purgeable |
| 417 | * anyway, so let's not bother. |
| 418 | */ |
| 419 | if (!list_is_singular(&bo->mappings.list) || |
| 420 | WARN_ON_ONCE(first->mmu != &priv->mmu)) { |
| 421 | ret = -EINVAL; |
| 422 | goto out_unlock_mappings; |
| 423 | } |
| 424 | } |
| 425 | |
Rob Herring | 013b65101 | 2019-08-05 08:33:58 -0600 | [diff] [blame] | 426 | args->retained = drm_gem_shmem_madvise(gem_obj, args->madv); |
| 427 | |
| 428 | if (args->retained) { |
Rob Herring | 013b65101 | 2019-08-05 08:33:58 -0600 | [diff] [blame] | 429 | if (args->madv == PANFROST_MADV_DONTNEED) |
Boris Brezillon | 70cc779 | 2019-11-29 14:59:02 +0100 | [diff] [blame] | 430 | list_add_tail(&bo->base.madv_list, |
| 431 | &pfdev->shrinker_list); |
Rob Herring | 013b65101 | 2019-08-05 08:33:58 -0600 | [diff] [blame] | 432 | else if (args->madv == PANFROST_MADV_WILLNEED) |
| 433 | list_del_init(&bo->base.madv_list); |
Rob Herring | 013b65101 | 2019-08-05 08:33:58 -0600 | [diff] [blame] | 434 | } |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 435 | |
| 436 | out_unlock_mappings: |
| 437 | mutex_unlock(&bo->mappings.lock); |
Boris Brezillon | 70cc779 | 2019-11-29 14:59:02 +0100 | [diff] [blame] | 438 | mutex_unlock(&pfdev->shrinker_lock); |
Rob Herring | 013b65101 | 2019-08-05 08:33:58 -0600 | [diff] [blame] | 439 | |
Emil Velikov | 496d0cc | 2020-05-15 10:51:07 +0100 | [diff] [blame] | 440 | drm_gem_object_put(gem_obj); |
Boris Brezillon | bdefca2 | 2020-01-15 20:15:54 -0600 | [diff] [blame] | 441 | return ret; |
Rob Herring | 013b65101 | 2019-08-05 08:33:58 -0600 | [diff] [blame] | 442 | } |
| 443 | |
Boris Brezillon | 92f0ad0 | 2019-06-18 10:16:46 +0200 | [diff] [blame] | 444 | int panfrost_unstable_ioctl_check(void) |
| 445 | { |
| 446 | if (!unstable_ioctls) |
| 447 | return -ENOSYS; |
| 448 | |
| 449 | return 0; |
| 450 | } |
| 451 | |
Rob Herring | 203270c | 2019-07-11 15:56:14 -0600 | [diff] [blame] | 452 | #define PFN_4G (SZ_4G >> PAGE_SHIFT) |
| 453 | #define PFN_4G_MASK (PFN_4G - 1) |
| 454 | #define PFN_16M (SZ_16M >> PAGE_SHIFT) |
| 455 | |
| 456 | static void panfrost_drm_mm_color_adjust(const struct drm_mm_node *node, |
| 457 | unsigned long color, |
| 458 | u64 *start, u64 *end) |
| 459 | { |
| 460 | /* Executable buffers can't start or end on a 4GB boundary */ |
| 461 | if (!(color & PANFROST_BO_NOEXEC)) { |
| 462 | u64 next_seg; |
| 463 | |
| 464 | if ((*start & PFN_4G_MASK) == 0) |
| 465 | (*start)++; |
| 466 | |
| 467 | if ((*end & PFN_4G_MASK) == 0) |
| 468 | (*end)--; |
| 469 | |
| 470 | next_seg = ALIGN(*start, PFN_4G); |
| 471 | if (next_seg - *start <= PFN_16M) |
| 472 | *start = next_seg + 1; |
| 473 | |
| 474 | *end = min(*end, ALIGN(*start, PFN_4G) - 1); |
| 475 | } |
| 476 | } |
| 477 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 478 | static int |
| 479 | panfrost_open(struct drm_device *dev, struct drm_file *file) |
| 480 | { |
Rob Herring | 7282f76 | 2019-08-13 09:01:15 -0600 | [diff] [blame] | 481 | int ret; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 482 | struct panfrost_device *pfdev = dev->dev_private; |
| 483 | struct panfrost_file_priv *panfrost_priv; |
| 484 | |
| 485 | panfrost_priv = kzalloc(sizeof(*panfrost_priv), GFP_KERNEL); |
| 486 | if (!panfrost_priv) |
| 487 | return -ENOMEM; |
| 488 | |
| 489 | panfrost_priv->pfdev = pfdev; |
| 490 | file->driver_priv = panfrost_priv; |
| 491 | |
Rob Herring | 7282f76 | 2019-08-13 09:01:15 -0600 | [diff] [blame] | 492 | spin_lock_init(&panfrost_priv->mm_lock); |
| 493 | |
| 494 | /* 4G enough for now. can be 48-bit */ |
| 495 | drm_mm_init(&panfrost_priv->mm, SZ_32M >> PAGE_SHIFT, (SZ_4G - SZ_32M) >> PAGE_SHIFT); |
| 496 | panfrost_priv->mm.color_adjust = panfrost_drm_mm_color_adjust; |
| 497 | |
| 498 | ret = panfrost_mmu_pgtable_alloc(panfrost_priv); |
| 499 | if (ret) |
| 500 | goto err_pgtable; |
| 501 | |
| 502 | ret = panfrost_job_open(panfrost_priv); |
| 503 | if (ret) |
| 504 | goto err_job; |
| 505 | |
| 506 | return 0; |
| 507 | |
| 508 | err_job: |
| 509 | panfrost_mmu_pgtable_free(panfrost_priv); |
| 510 | err_pgtable: |
| 511 | drm_mm_takedown(&panfrost_priv->mm); |
| 512 | kfree(panfrost_priv); |
| 513 | return ret; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 514 | } |
| 515 | |
| 516 | static void |
| 517 | panfrost_postclose(struct drm_device *dev, struct drm_file *file) |
| 518 | { |
| 519 | struct panfrost_file_priv *panfrost_priv = file->driver_priv; |
| 520 | |
Boris Brezillon | 0a52399 | 2019-11-29 14:59:05 +0100 | [diff] [blame] | 521 | panfrost_perfcnt_close(file); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 522 | panfrost_job_close(panfrost_priv); |
| 523 | |
Rob Herring | 7282f76 | 2019-08-13 09:01:15 -0600 | [diff] [blame] | 524 | panfrost_mmu_pgtable_free(panfrost_priv); |
| 525 | drm_mm_takedown(&panfrost_priv->mm); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 526 | kfree(panfrost_priv); |
| 527 | } |
| 528 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 529 | static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = { |
| 530 | #define PANFROST_IOCTL(n, func, flags) \ |
| 531 | DRM_IOCTL_DEF_DRV(PANFROST_##n, panfrost_ioctl_##func, flags) |
| 532 | |
Emil Velikov | c1572b75 | 2019-11-01 13:03:12 +0000 | [diff] [blame] | 533 | PANFROST_IOCTL(SUBMIT, submit, DRM_RENDER_ALLOW), |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 534 | PANFROST_IOCTL(WAIT_BO, wait_bo, DRM_RENDER_ALLOW), |
| 535 | PANFROST_IOCTL(CREATE_BO, create_bo, DRM_RENDER_ALLOW), |
| 536 | PANFROST_IOCTL(MMAP_BO, mmap_bo, DRM_RENDER_ALLOW), |
| 537 | PANFROST_IOCTL(GET_PARAM, get_param, DRM_RENDER_ALLOW), |
| 538 | PANFROST_IOCTL(GET_BO_OFFSET, get_bo_offset, DRM_RENDER_ALLOW), |
Boris Brezillon | 7786fd1 | 2019-06-18 10:16:48 +0200 | [diff] [blame] | 539 | PANFROST_IOCTL(PERFCNT_ENABLE, perfcnt_enable, DRM_RENDER_ALLOW), |
| 540 | PANFROST_IOCTL(PERFCNT_DUMP, perfcnt_dump, DRM_RENDER_ALLOW), |
Rob Herring | 013b65101 | 2019-08-05 08:33:58 -0600 | [diff] [blame] | 541 | PANFROST_IOCTL(MADVISE, madvise, DRM_RENDER_ALLOW), |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 542 | }; |
| 543 | |
Gerd Hoffmann | eee9a2e | 2019-10-16 13:51:57 +0200 | [diff] [blame] | 544 | DEFINE_DRM_GEM_FOPS(panfrost_drm_driver_fops); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 545 | |
Rob Herring | 1c2b939 | 2019-07-02 12:49:36 -0600 | [diff] [blame] | 546 | /* |
| 547 | * Panfrost driver version: |
| 548 | * - 1.0 - initial interface |
| 549 | * - 1.1 - adds HEAP and NOEXEC flags for CREATE_BO |
Alyssa Rosenzweig | 3e2926f | 2021-06-04 09:00:11 -0400 | [diff] [blame] | 550 | * - 1.2 - adds AFBC_FEATURES query |
Rob Herring | 1c2b939 | 2019-07-02 12:49:36 -0600 | [diff] [blame] | 551 | */ |
Daniel Vetter | 70a59dd | 2020-11-04 11:04:24 +0100 | [diff] [blame] | 552 | static const struct drm_driver panfrost_drm_driver = { |
Daniel Vetter | 0424fda | 2019-06-17 17:39:24 +0200 | [diff] [blame] | 553 | .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ, |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 554 | .open = panfrost_open, |
| 555 | .postclose = panfrost_postclose, |
| 556 | .ioctls = panfrost_drm_driver_ioctls, |
| 557 | .num_ioctls = ARRAY_SIZE(panfrost_drm_driver_ioctls), |
| 558 | .fops = &panfrost_drm_driver_fops, |
| 559 | .name = "panfrost", |
| 560 | .desc = "panfrost DRM", |
| 561 | .date = "20180908", |
| 562 | .major = 1, |
Alyssa Rosenzweig | 3e2926f | 2021-06-04 09:00:11 -0400 | [diff] [blame] | 563 | .minor = 2, |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 564 | |
| 565 | .gem_create_object = panfrost_gem_create_object, |
| 566 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
| 567 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, |
| 568 | .gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table, |
| 569 | .gem_prime_mmap = drm_gem_prime_mmap, |
| 570 | }; |
| 571 | |
| 572 | static int panfrost_probe(struct platform_device *pdev) |
| 573 | { |
| 574 | struct panfrost_device *pfdev; |
| 575 | struct drm_device *ddev; |
| 576 | int err; |
| 577 | |
| 578 | pfdev = devm_kzalloc(&pdev->dev, sizeof(*pfdev), GFP_KERNEL); |
| 579 | if (!pfdev) |
| 580 | return -ENOMEM; |
| 581 | |
| 582 | pfdev->pdev = pdev; |
| 583 | pfdev->dev = &pdev->dev; |
| 584 | |
| 585 | platform_set_drvdata(pdev, pfdev); |
| 586 | |
Nicolas Boichat | 3e1399b | 2020-02-07 13:26:24 +0800 | [diff] [blame] | 587 | pfdev->comp = of_device_get_match_data(&pdev->dev); |
| 588 | if (!pfdev->comp) |
| 589 | return -ENODEV; |
| 590 | |
Robin Murphy | 268af50 | 2020-09-22 15:16:49 +0100 | [diff] [blame] | 591 | pfdev->coherent = device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT; |
| 592 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 593 | /* Allocate and initialze the DRM device. */ |
| 594 | ddev = drm_dev_alloc(&panfrost_drm_driver, &pdev->dev); |
| 595 | if (IS_ERR(ddev)) |
| 596 | return PTR_ERR(ddev); |
| 597 | |
| 598 | ddev->dev_private = pfdev; |
| 599 | pfdev->ddev = ddev; |
| 600 | |
Rob Herring | 013b65101 | 2019-08-05 08:33:58 -0600 | [diff] [blame] | 601 | mutex_init(&pfdev->shrinker_lock); |
| 602 | INIT_LIST_HEAD(&pfdev->shrinker_list); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 603 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 604 | err = panfrost_device_init(pfdev); |
| 605 | if (err) { |
Robin Murphy | 5450f36 | 2019-05-03 16:31:44 +0100 | [diff] [blame] | 606 | if (err != -EPROBE_DEFER) |
| 607 | dev_err(&pdev->dev, "Fatal error during GPU init\n"); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 608 | goto err_out0; |
| 609 | } |
| 610 | |
Rob Herring | 6354307 | 2019-08-26 17:33:10 -0500 | [diff] [blame] | 611 | pm_runtime_set_active(pfdev->dev); |
| 612 | pm_runtime_mark_last_busy(pfdev->dev); |
| 613 | pm_runtime_enable(pfdev->dev); |
| 614 | pm_runtime_set_autosuspend_delay(pfdev->dev, 50); /* ~3 frames */ |
| 615 | pm_runtime_use_autosuspend(pfdev->dev); |
| 616 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 617 | /* |
| 618 | * Register the DRM device with the core and the connectors with |
| 619 | * sysfs |
| 620 | */ |
| 621 | err = drm_dev_register(ddev, 0); |
| 622 | if (err < 0) |
Clément Péron | 25e247b | 2020-07-10 11:54:03 +0200 | [diff] [blame] | 623 | goto err_out1; |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 624 | |
Rob Herring | 013b65101 | 2019-08-05 08:33:58 -0600 | [diff] [blame] | 625 | panfrost_gem_shrinker_init(ddev); |
| 626 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 627 | return 0; |
| 628 | |
| 629 | err_out1: |
Clément Péron | 25e247b | 2020-07-10 11:54:03 +0200 | [diff] [blame] | 630 | pm_runtime_disable(pfdev->dev); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 631 | panfrost_device_fini(pfdev); |
Steven Price | 876b15d | 2020-10-30 14:58:33 +0000 | [diff] [blame] | 632 | pm_runtime_set_suspended(pfdev->dev); |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 633 | err_out0: |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 634 | drm_dev_put(ddev); |
| 635 | return err; |
| 636 | } |
| 637 | |
| 638 | static int panfrost_remove(struct platform_device *pdev) |
| 639 | { |
| 640 | struct panfrost_device *pfdev = platform_get_drvdata(pdev); |
| 641 | struct drm_device *ddev = pfdev->ddev; |
| 642 | |
| 643 | drm_dev_unregister(ddev); |
Rob Herring | 013b65101 | 2019-08-05 08:33:58 -0600 | [diff] [blame] | 644 | panfrost_gem_shrinker_cleanup(ddev); |
Rob Herring | aebe8c22 | 2019-08-22 21:12:09 -0500 | [diff] [blame] | 645 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 646 | pm_runtime_get_sync(pfdev->dev); |
Rob Herring | aebe8c22 | 2019-08-22 21:12:09 -0500 | [diff] [blame] | 647 | pm_runtime_disable(pfdev->dev); |
Steven Price | 876b15d | 2020-10-30 14:58:33 +0000 | [diff] [blame] | 648 | panfrost_device_fini(pfdev); |
| 649 | pm_runtime_set_suspended(pfdev->dev); |
Rob Herring | aebe8c22 | 2019-08-22 21:12:09 -0500 | [diff] [blame] | 650 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 651 | drm_dev_put(ddev); |
| 652 | return 0; |
| 653 | } |
| 654 | |
kbuild test robot | 987b90d | 2020-02-27 09:41:46 +0800 | [diff] [blame] | 655 | static const char * const default_supplies[] = { "mali" }; |
Nicolas Boichat | 3e1399b | 2020-02-07 13:26:24 +0800 | [diff] [blame] | 656 | static const struct panfrost_compatible default_data = { |
| 657 | .num_supplies = ARRAY_SIZE(default_supplies), |
| 658 | .supply_names = default_supplies, |
Nicolas Boichat | 506629c | 2020-02-07 13:26:25 +0800 | [diff] [blame] | 659 | .num_pm_domains = 1, /* optional */ |
| 660 | .pm_domain_names = NULL, |
Nicolas Boichat | 3e1399b | 2020-02-07 13:26:24 +0800 | [diff] [blame] | 661 | }; |
| 662 | |
Neil Armstrong | afcd0c7 | 2020-09-16 17:01:47 +0200 | [diff] [blame] | 663 | static const struct panfrost_compatible amlogic_data = { |
| 664 | .num_supplies = ARRAY_SIZE(default_supplies), |
| 665 | .supply_names = default_supplies, |
| 666 | .vendor_quirk = panfrost_gpu_amlogic_quirk, |
| 667 | }; |
| 668 | |
Nicolas Boichat | 1275e41 | 2021-04-21 13:28:55 +0800 | [diff] [blame] | 669 | const char * const mediatek_mt8183_supplies[] = { "mali", "sram" }; |
| 670 | const char * const mediatek_mt8183_pm_domains[] = { "core0", "core1", "core2" }; |
| 671 | static const struct panfrost_compatible mediatek_mt8183_data = { |
| 672 | .num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies), |
| 673 | .supply_names = mediatek_mt8183_supplies, |
| 674 | .num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains), |
| 675 | .pm_domain_names = mediatek_mt8183_pm_domains, |
| 676 | }; |
| 677 | |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 678 | static const struct of_device_id dt_match[] = { |
Neil Armstrong | afcd0c7 | 2020-09-16 17:01:47 +0200 | [diff] [blame] | 679 | /* Set first to probe before the generic compatibles */ |
| 680 | { .compatible = "amlogic,meson-gxm-mali", |
| 681 | .data = &amlogic_data, }, |
| 682 | { .compatible = "amlogic,meson-g12a-mali", |
| 683 | .data = &amlogic_data, }, |
Nicolas Boichat | 3e1399b | 2020-02-07 13:26:24 +0800 | [diff] [blame] | 684 | { .compatible = "arm,mali-t604", .data = &default_data, }, |
| 685 | { .compatible = "arm,mali-t624", .data = &default_data, }, |
| 686 | { .compatible = "arm,mali-t628", .data = &default_data, }, |
| 687 | { .compatible = "arm,mali-t720", .data = &default_data, }, |
| 688 | { .compatible = "arm,mali-t760", .data = &default_data, }, |
| 689 | { .compatible = "arm,mali-t820", .data = &default_data, }, |
| 690 | { .compatible = "arm,mali-t830", .data = &default_data, }, |
| 691 | { .compatible = "arm,mali-t860", .data = &default_data, }, |
| 692 | { .compatible = "arm,mali-t880", .data = &default_data, }, |
Tomeu Vizoso | 72ef7fe | 2020-06-11 10:58:44 +0200 | [diff] [blame] | 693 | { .compatible = "arm,mali-bifrost", .data = &default_data, }, |
Nicolas Boichat | 1275e41 | 2021-04-21 13:28:55 +0800 | [diff] [blame] | 694 | { .compatible = "mediatek,mt8183-mali", .data = &mediatek_mt8183_data }, |
Rob Herring | f3ba912 | 2018-09-10 14:27:58 -0500 | [diff] [blame] | 695 | {} |
| 696 | }; |
| 697 | MODULE_DEVICE_TABLE(of, dt_match); |
| 698 | |
| 699 | static const struct dev_pm_ops panfrost_pm_ops = { |
| 700 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) |
| 701 | SET_RUNTIME_PM_OPS(panfrost_device_suspend, panfrost_device_resume, NULL) |
| 702 | }; |
| 703 | |
| 704 | static struct platform_driver panfrost_driver = { |
| 705 | .probe = panfrost_probe, |
| 706 | .remove = panfrost_remove, |
| 707 | .driver = { |
| 708 | .name = "panfrost", |
| 709 | .pm = &panfrost_pm_ops, |
| 710 | .of_match_table = dt_match, |
| 711 | }, |
| 712 | }; |
| 713 | module_platform_driver(panfrost_driver); |
| 714 | |
| 715 | MODULE_AUTHOR("Panfrost Project Developers"); |
| 716 | MODULE_DESCRIPTION("Panfrost DRM Driver"); |
| 717 | MODULE_LICENSE("GPL v2"); |