linux/drivers/gpu/drm/panfrost/panfrost_drv.c
<<
>>
Prefs
   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
   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"
  17#include "panfrost_gem.h"
  18#include "panfrost_mmu.h"
  19#include "panfrost_job.h"
  20#include "panfrost_gpu.h"
  21#include "panfrost_perfcnt.h"
  22
  23static bool unstable_ioctls;
  24module_param_unsafe(unstable_ioctls, bool, 0600);
  25
  26static 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
  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
  45        switch (param->param) {
  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);
  66                PANFROST_FEATURE(AFBC_FEATURES, afbc_features);
  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);
  71        default:
  72                return -EINVAL;
  73        }
  74
  75        return 0;
  76}
  77
  78static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data,
  79                struct drm_file *file)
  80{
  81        struct panfrost_file_priv *priv = file->driver_priv;
  82        struct panfrost_gem_object *bo;
  83        struct drm_panfrost_create_bo *args = data;
  84        struct panfrost_gem_mapping *mapping;
  85
  86        if (!args->size || args->pad ||
  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))
  93                return -EINVAL;
  94
  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);
  99
 100        mapping = panfrost_gem_mapping_get(bo, priv);
 101        if (!mapping) {
 102                drm_gem_object_put(&bo->base.base);
 103                return -EINVAL;
 104        }
 105
 106        args->offset = mapping->mmnode.start << PAGE_SHIFT;
 107        panfrost_gem_mapping_put(mapping);
 108
 109        return 0;
 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 */
 125static int
 126panfrost_lookup_bos(struct drm_device *dev,
 127                  struct drm_file *file_priv,
 128                  struct drm_panfrost_submit *args,
 129                  struct panfrost_job *job)
 130{
 131        struct panfrost_file_priv *priv = file_priv->driver_priv;
 132        struct panfrost_gem_object *bo;
 133        unsigned int i;
 134        int ret;
 135
 136        job->bo_count = args->bo_handle_count;
 137
 138        if (!job->bo_count)
 139                return 0;
 140
 141        ret = drm_gem_objects_lookup(file_priv,
 142                                     (void __user *)(uintptr_t)args->bo_handles,
 143                                     job->bo_count, &job->bos);
 144        if (ret)
 145                return ret;
 146
 147        job->mappings = kvmalloc_array(job->bo_count,
 148                                       sizeof(struct panfrost_gem_mapping *),
 149                                       GFP_KERNEL | __GFP_ZERO);
 150        if (!job->mappings)
 151                return -ENOMEM;
 152
 153        for (i = 0; i < job->bo_count; i++) {
 154                struct panfrost_gem_mapping *mapping;
 155
 156                bo = to_panfrost_bo(job->bos[i]);
 157                mapping = panfrost_gem_mapping_get(bo, priv);
 158                if (!mapping) {
 159                        ret = -EINVAL;
 160                        break;
 161                }
 162
 163                atomic_inc(&bo->gpu_usecount);
 164                job->mappings[i] = mapping;
 165        }
 166
 167        return ret;
 168}
 169
 170/**
 171 * panfrost_copy_in_sync() - Sets up job->deps with the sync objects
 172 * referenced by the job.
 173 * @dev: DRM device
 174 * @file_priv: DRM file for this fd
 175 * @args: IOCTL args
 176 * @job: job being set up
 177 *
 178 * Resolve syncobjs from userspace to fences and attach them to job.
 179 *
 180 * Note that this function doesn't need to unreference the fences on
 181 * failure, because that will happen at panfrost_job_cleanup() time.
 182 */
 183static int
 184panfrost_copy_in_sync(struct drm_device *dev,
 185                  struct drm_file *file_priv,
 186                  struct drm_panfrost_submit *args,
 187                  struct panfrost_job *job)
 188{
 189        u32 *handles;
 190        int ret = 0;
 191        int i, in_fence_count;
 192
 193        in_fence_count = args->in_sync_count;
 194
 195        if (!in_fence_count)
 196                return 0;
 197
 198        handles = kvmalloc_array(in_fence_count, sizeof(u32), GFP_KERNEL);
 199        if (!handles) {
 200                ret = -ENOMEM;
 201                DRM_DEBUG("Failed to allocate incoming syncobj handles\n");
 202                goto fail;
 203        }
 204
 205        if (copy_from_user(handles,
 206                           (void __user *)(uintptr_t)args->in_syncs,
 207                           in_fence_count * sizeof(u32))) {
 208                ret = -EFAULT;
 209                DRM_DEBUG("Failed to copy in syncobj handles\n");
 210                goto fail;
 211        }
 212
 213        for (i = 0; i < in_fence_count; i++) {
 214                struct dma_fence *fence;
 215
 216                ret = drm_syncobj_find_fence(file_priv, handles[i], 0, 0,
 217                                             &fence);
 218                if (ret)
 219                        goto fail;
 220
 221                ret = drm_gem_fence_array_add(&job->deps, fence);
 222
 223                if (ret)
 224                        goto fail;
 225        }
 226
 227fail:
 228        kvfree(handles);
 229        return ret;
 230}
 231
 232static int panfrost_ioctl_submit(struct drm_device *dev, void *data,
 233                struct drm_file *file)
 234{
 235        struct panfrost_device *pfdev = dev->dev_private;
 236        struct drm_panfrost_submit *args = data;
 237        struct drm_syncobj *sync_out = NULL;
 238        struct panfrost_job *job;
 239        int ret = 0;
 240
 241        if (!args->jc)
 242                return -EINVAL;
 243
 244        if (args->requirements && args->requirements != PANFROST_JD_REQ_FS)
 245                return -EINVAL;
 246
 247        if (args->out_sync > 0) {
 248                sync_out = drm_syncobj_find(file, args->out_sync);
 249                if (!sync_out)
 250                        return -ENODEV;
 251        }
 252
 253        job = kzalloc(sizeof(*job), GFP_KERNEL);
 254        if (!job) {
 255                ret = -ENOMEM;
 256                goto fail_out_sync;
 257        }
 258
 259        kref_init(&job->refcount);
 260
 261        xa_init_flags(&job->deps, XA_FLAGS_ALLOC);
 262
 263        job->pfdev = pfdev;
 264        job->jc = args->jc;
 265        job->requirements = args->requirements;
 266        job->flush_id = panfrost_gpu_get_latest_flush_id(pfdev);
 267        job->file_priv = file->driver_priv;
 268
 269        ret = panfrost_copy_in_sync(dev, file, args, job);
 270        if (ret)
 271                goto fail_job;
 272
 273        ret = panfrost_lookup_bos(dev, file, args, job);
 274        if (ret)
 275                goto fail_job;
 276
 277        ret = panfrost_job_push(job);
 278        if (ret)
 279                goto fail_job;
 280
 281        /* Update the return sync object for the job */
 282        if (sync_out)
 283                drm_syncobj_replace_fence(sync_out, job->render_done_fence);
 284
 285fail_job:
 286        panfrost_job_put(job);
 287fail_out_sync:
 288        if (sync_out)
 289                drm_syncobj_put(sync_out);
 290
 291        return ret;
 292}
 293
 294static int
 295panfrost_ioctl_wait_bo(struct drm_device *dev, void *data,
 296                       struct drm_file *file_priv)
 297{
 298        long ret;
 299        struct drm_panfrost_wait_bo *args = data;
 300        struct drm_gem_object *gem_obj;
 301        unsigned long timeout = drm_timeout_abs_to_jiffies(args->timeout_ns);
 302
 303        if (args->pad)
 304                return -EINVAL;
 305
 306        gem_obj = drm_gem_object_lookup(file_priv, args->handle);
 307        if (!gem_obj)
 308                return -ENOENT;
 309
 310        ret = dma_resv_wait_timeout(gem_obj->resv, true, true, timeout);
 311        if (!ret)
 312                ret = timeout ? -ETIMEDOUT : -EBUSY;
 313
 314        drm_gem_object_put(gem_obj);
 315
 316        return ret;
 317}
 318
 319static int panfrost_ioctl_mmap_bo(struct drm_device *dev, void *data,
 320                      struct drm_file *file_priv)
 321{
 322        struct drm_panfrost_mmap_bo *args = data;
 323        struct drm_gem_object *gem_obj;
 324        int ret;
 325
 326        if (args->flags != 0) {
 327                DRM_INFO("unknown mmap_bo flags: %d\n", args->flags);
 328                return -EINVAL;
 329        }
 330
 331        gem_obj = drm_gem_object_lookup(file_priv, args->handle);
 332        if (!gem_obj) {
 333                DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
 334                return -ENOENT;
 335        }
 336
 337        /* Don't allow mmapping of heap objects as pages are not pinned. */
 338        if (to_panfrost_bo(gem_obj)->is_heap) {
 339                ret = -EINVAL;
 340                goto out;
 341        }
 342
 343        ret = drm_gem_create_mmap_offset(gem_obj);
 344        if (ret == 0)
 345                args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
 346
 347out:
 348        drm_gem_object_put(gem_obj);
 349        return ret;
 350}
 351
 352static int panfrost_ioctl_get_bo_offset(struct drm_device *dev, void *data,
 353                            struct drm_file *file_priv)
 354{
 355        struct panfrost_file_priv *priv = file_priv->driver_priv;
 356        struct drm_panfrost_get_bo_offset *args = data;
 357        struct panfrost_gem_mapping *mapping;
 358        struct drm_gem_object *gem_obj;
 359        struct panfrost_gem_object *bo;
 360
 361        gem_obj = drm_gem_object_lookup(file_priv, args->handle);
 362        if (!gem_obj) {
 363                DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
 364                return -ENOENT;
 365        }
 366        bo = to_panfrost_bo(gem_obj);
 367
 368        mapping = panfrost_gem_mapping_get(bo, priv);
 369        drm_gem_object_put(gem_obj);
 370
 371        if (!mapping)
 372                return -EINVAL;
 373
 374        args->offset = mapping->mmnode.start << PAGE_SHIFT;
 375        panfrost_gem_mapping_put(mapping);
 376        return 0;
 377}
 378
 379static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
 380                                  struct drm_file *file_priv)
 381{
 382        struct panfrost_file_priv *priv = file_priv->driver_priv;
 383        struct drm_panfrost_madvise *args = data;
 384        struct panfrost_device *pfdev = dev->dev_private;
 385        struct drm_gem_object *gem_obj;
 386        struct panfrost_gem_object *bo;
 387        int ret = 0;
 388
 389        gem_obj = drm_gem_object_lookup(file_priv, args->handle);
 390        if (!gem_obj) {
 391                DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
 392                return -ENOENT;
 393        }
 394
 395        bo = to_panfrost_bo(gem_obj);
 396
 397        mutex_lock(&pfdev->shrinker_lock);
 398        mutex_lock(&bo->mappings.lock);
 399        if (args->madv == PANFROST_MADV_DONTNEED) {
 400                struct panfrost_gem_mapping *first;
 401
 402                first = list_first_entry(&bo->mappings.list,
 403                                         struct panfrost_gem_mapping,
 404                                         node);
 405
 406                /*
 407                 * If we want to mark the BO purgeable, there must be only one
 408                 * user: the caller FD.
 409                 * We could do something smarter and mark the BO purgeable only
 410                 * when all its users have marked it purgeable, but globally
 411                 * visible/shared BOs are likely to never be marked purgeable
 412                 * anyway, so let's not bother.
 413                 */
 414                if (!list_is_singular(&bo->mappings.list) ||
 415                    WARN_ON_ONCE(first->mmu != priv->mmu)) {
 416                        ret = -EINVAL;
 417                        goto out_unlock_mappings;
 418                }
 419        }
 420
 421        args->retained = drm_gem_shmem_madvise(gem_obj, args->madv);
 422
 423        if (args->retained) {
 424                if (args->madv == PANFROST_MADV_DONTNEED)
 425                        list_add_tail(&bo->base.madv_list,
 426                                      &pfdev->shrinker_list);
 427                else if (args->madv == PANFROST_MADV_WILLNEED)
 428                        list_del_init(&bo->base.madv_list);
 429        }
 430
 431out_unlock_mappings:
 432        mutex_unlock(&bo->mappings.lock);
 433        mutex_unlock(&pfdev->shrinker_lock);
 434
 435        drm_gem_object_put(gem_obj);
 436        return ret;
 437}
 438
 439int panfrost_unstable_ioctl_check(void)
 440{
 441        if (!unstable_ioctls)
 442                return -ENOSYS;
 443
 444        return 0;
 445}
 446
 447static int
 448panfrost_open(struct drm_device *dev, struct drm_file *file)
 449{
 450        int ret;
 451        struct panfrost_device *pfdev = dev->dev_private;
 452        struct panfrost_file_priv *panfrost_priv;
 453
 454        panfrost_priv = kzalloc(sizeof(*panfrost_priv), GFP_KERNEL);
 455        if (!panfrost_priv)
 456                return -ENOMEM;
 457
 458        panfrost_priv->pfdev = pfdev;
 459        file->driver_priv = panfrost_priv;
 460
 461        panfrost_priv->mmu = panfrost_mmu_ctx_create(pfdev);
 462        if (IS_ERR(panfrost_priv->mmu)) {
 463                ret = PTR_ERR(panfrost_priv->mmu);
 464                goto err_free;
 465        }
 466
 467        ret = panfrost_job_open(panfrost_priv);
 468        if (ret)
 469                goto err_job;
 470
 471        return 0;
 472
 473err_job:
 474        panfrost_mmu_ctx_put(panfrost_priv->mmu);
 475err_free:
 476        kfree(panfrost_priv);
 477        return ret;
 478}
 479
 480static void
 481panfrost_postclose(struct drm_device *dev, struct drm_file *file)
 482{
 483        struct panfrost_file_priv *panfrost_priv = file->driver_priv;
 484
 485        panfrost_perfcnt_close(file);
 486        panfrost_job_close(panfrost_priv);
 487
 488        panfrost_mmu_ctx_put(panfrost_priv->mmu);
 489        kfree(panfrost_priv);
 490}
 491
 492static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = {
 493#define PANFROST_IOCTL(n, func, flags) \
 494        DRM_IOCTL_DEF_DRV(PANFROST_##n, panfrost_ioctl_##func, flags)
 495
 496        PANFROST_IOCTL(SUBMIT,          submit,         DRM_RENDER_ALLOW),
 497        PANFROST_IOCTL(WAIT_BO,         wait_bo,        DRM_RENDER_ALLOW),
 498        PANFROST_IOCTL(CREATE_BO,       create_bo,      DRM_RENDER_ALLOW),
 499        PANFROST_IOCTL(MMAP_BO,         mmap_bo,        DRM_RENDER_ALLOW),
 500        PANFROST_IOCTL(GET_PARAM,       get_param,      DRM_RENDER_ALLOW),
 501        PANFROST_IOCTL(GET_BO_OFFSET,   get_bo_offset,  DRM_RENDER_ALLOW),
 502        PANFROST_IOCTL(PERFCNT_ENABLE,  perfcnt_enable, DRM_RENDER_ALLOW),
 503        PANFROST_IOCTL(PERFCNT_DUMP,    perfcnt_dump,   DRM_RENDER_ALLOW),
 504        PANFROST_IOCTL(MADVISE,         madvise,        DRM_RENDER_ALLOW),
 505};
 506
 507DEFINE_DRM_GEM_FOPS(panfrost_drm_driver_fops);
 508
 509/*
 510 * Panfrost driver version:
 511 * - 1.0 - initial interface
 512 * - 1.1 - adds HEAP and NOEXEC flags for CREATE_BO
 513 * - 1.2 - adds AFBC_FEATURES query
 514 */
 515static const struct drm_driver panfrost_drm_driver = {
 516        .driver_features        = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ,
 517        .open                   = panfrost_open,
 518        .postclose              = panfrost_postclose,
 519        .ioctls                 = panfrost_drm_driver_ioctls,
 520        .num_ioctls             = ARRAY_SIZE(panfrost_drm_driver_ioctls),
 521        .fops                   = &panfrost_drm_driver_fops,
 522        .name                   = "panfrost",
 523        .desc                   = "panfrost DRM",
 524        .date                   = "20180908",
 525        .major                  = 1,
 526        .minor                  = 2,
 527
 528        .gem_create_object      = panfrost_gem_create_object,
 529        .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
 530        .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
 531        .gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table,
 532        .gem_prime_mmap         = drm_gem_prime_mmap,
 533};
 534
 535static int panfrost_probe(struct platform_device *pdev)
 536{
 537        struct panfrost_device *pfdev;
 538        struct drm_device *ddev;
 539        int err;
 540
 541        pfdev = devm_kzalloc(&pdev->dev, sizeof(*pfdev), GFP_KERNEL);
 542        if (!pfdev)
 543                return -ENOMEM;
 544
 545        pfdev->pdev = pdev;
 546        pfdev->dev = &pdev->dev;
 547
 548        platform_set_drvdata(pdev, pfdev);
 549
 550        pfdev->comp = of_device_get_match_data(&pdev->dev);
 551        if (!pfdev->comp)
 552                return -ENODEV;
 553
 554        pfdev->coherent = device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT;
 555
 556        /* Allocate and initialze the DRM device. */
 557        ddev = drm_dev_alloc(&panfrost_drm_driver, &pdev->dev);
 558        if (IS_ERR(ddev))
 559                return PTR_ERR(ddev);
 560
 561        ddev->dev_private = pfdev;
 562        pfdev->ddev = ddev;
 563
 564        mutex_init(&pfdev->shrinker_lock);
 565        INIT_LIST_HEAD(&pfdev->shrinker_list);
 566
 567        err = panfrost_device_init(pfdev);
 568        if (err) {
 569                if (err != -EPROBE_DEFER)
 570                        dev_err(&pdev->dev, "Fatal error during GPU init\n");
 571                goto err_out0;
 572        }
 573
 574        pm_runtime_set_active(pfdev->dev);
 575        pm_runtime_mark_last_busy(pfdev->dev);
 576        pm_runtime_enable(pfdev->dev);
 577        pm_runtime_set_autosuspend_delay(pfdev->dev, 50); /* ~3 frames */
 578        pm_runtime_use_autosuspend(pfdev->dev);
 579
 580        /*
 581         * Register the DRM device with the core and the connectors with
 582         * sysfs
 583         */
 584        err = drm_dev_register(ddev, 0);
 585        if (err < 0)
 586                goto err_out1;
 587
 588        panfrost_gem_shrinker_init(ddev);
 589
 590        return 0;
 591
 592err_out1:
 593        pm_runtime_disable(pfdev->dev);
 594        panfrost_device_fini(pfdev);
 595        pm_runtime_set_suspended(pfdev->dev);
 596err_out0:
 597        drm_dev_put(ddev);
 598        return err;
 599}
 600
 601static int panfrost_remove(struct platform_device *pdev)
 602{
 603        struct panfrost_device *pfdev = platform_get_drvdata(pdev);
 604        struct drm_device *ddev = pfdev->ddev;
 605
 606        drm_dev_unregister(ddev);
 607        panfrost_gem_shrinker_cleanup(ddev);
 608
 609        pm_runtime_get_sync(pfdev->dev);
 610        pm_runtime_disable(pfdev->dev);
 611        panfrost_device_fini(pfdev);
 612        pm_runtime_set_suspended(pfdev->dev);
 613
 614        drm_dev_put(ddev);
 615        return 0;
 616}
 617
 618static const char * const default_supplies[] = { "mali" };
 619static const struct panfrost_compatible default_data = {
 620        .num_supplies = ARRAY_SIZE(default_supplies),
 621        .supply_names = default_supplies,
 622        .num_pm_domains = 1, /* optional */
 623        .pm_domain_names = NULL,
 624};
 625
 626static const struct panfrost_compatible amlogic_data = {
 627        .num_supplies = ARRAY_SIZE(default_supplies),
 628        .supply_names = default_supplies,
 629        .vendor_quirk = panfrost_gpu_amlogic_quirk,
 630};
 631
 632const char * const mediatek_mt8183_supplies[] = { "mali", "sram" };
 633const char * const mediatek_mt8183_pm_domains[] = { "core0", "core1", "core2" };
 634static const struct panfrost_compatible mediatek_mt8183_data = {
 635        .num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies),
 636        .supply_names = mediatek_mt8183_supplies,
 637        .num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains),
 638        .pm_domain_names = mediatek_mt8183_pm_domains,
 639};
 640
 641static const struct of_device_id dt_match[] = {
 642        /* Set first to probe before the generic compatibles */
 643        { .compatible = "amlogic,meson-gxm-mali",
 644          .data = &amlogic_data, },
 645        { .compatible = "amlogic,meson-g12a-mali",
 646          .data = &amlogic_data, },
 647        { .compatible = "arm,mali-t604", .data = &default_data, },
 648        { .compatible = "arm,mali-t624", .data = &default_data, },
 649        { .compatible = "arm,mali-t628", .data = &default_data, },
 650        { .compatible = "arm,mali-t720", .data = &default_data, },
 651        { .compatible = "arm,mali-t760", .data = &default_data, },
 652        { .compatible = "arm,mali-t820", .data = &default_data, },
 653        { .compatible = "arm,mali-t830", .data = &default_data, },
 654        { .compatible = "arm,mali-t860", .data = &default_data, },
 655        { .compatible = "arm,mali-t880", .data = &default_data, },
 656        { .compatible = "arm,mali-bifrost", .data = &default_data, },
 657        { .compatible = "mediatek,mt8183-mali", .data = &mediatek_mt8183_data },
 658        {}
 659};
 660MODULE_DEVICE_TABLE(of, dt_match);
 661
 662static const struct dev_pm_ops panfrost_pm_ops = {
 663        SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
 664        SET_RUNTIME_PM_OPS(panfrost_device_suspend, panfrost_device_resume, NULL)
 665};
 666
 667static struct platform_driver panfrost_driver = {
 668        .probe          = panfrost_probe,
 669        .remove         = panfrost_remove,
 670        .driver         = {
 671                .name   = "panfrost",
 672                .pm     = &panfrost_pm_ops,
 673                .of_match_table = dt_match,
 674        },
 675};
 676module_platform_driver(panfrost_driver);
 677
 678MODULE_AUTHOR("Panfrost Project Developers");
 679MODULE_DESCRIPTION("Panfrost DRM Driver");
 680MODULE_LICENSE("GPL v2");
 681