linux/drivers/gpu/drm/mediatek/mtk_drm_drv.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2015 MediaTek Inc.
   4 * Author: YT SHEN <yt.shen@mediatek.com>
   5 */
   6
   7#include <linux/component.h>
   8#include <linux/iommu.h>
   9#include <linux/module.h>
  10#include <linux/of_address.h>
  11#include <linux/of_platform.h>
  12#include <linux/pm_runtime.h>
  13#include <linux/soc/mediatek/mtk-mmsys.h>
  14#include <linux/dma-mapping.h>
  15
  16#include <drm/drm_atomic.h>
  17#include <drm/drm_atomic_helper.h>
  18#include <drm/drm_drv.h>
  19#include <drm/drm_fb_helper.h>
  20#include <drm/drm_fourcc.h>
  21#include <drm/drm_gem.h>
  22#include <drm/drm_gem_cma_helper.h>
  23#include <drm/drm_gem_framebuffer_helper.h>
  24#include <drm/drm_of.h>
  25#include <drm/drm_probe_helper.h>
  26#include <drm/drm_vblank.h>
  27
  28#include "mtk_drm_crtc.h"
  29#include "mtk_drm_ddp.h"
  30#include "mtk_drm_ddp_comp.h"
  31#include "mtk_drm_drv.h"
  32#include "mtk_drm_gem.h"
  33
  34#define DRIVER_NAME "mediatek"
  35#define DRIVER_DESC "Mediatek SoC DRM"
  36#define DRIVER_DATE "20150513"
  37#define DRIVER_MAJOR 1
  38#define DRIVER_MINOR 0
  39
  40static const struct drm_mode_config_helper_funcs mtk_drm_mode_config_helpers = {
  41        .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
  42};
  43
  44static struct drm_framebuffer *
  45mtk_drm_mode_fb_create(struct drm_device *dev,
  46                       struct drm_file *file,
  47                       const struct drm_mode_fb_cmd2 *cmd)
  48{
  49        const struct drm_format_info *info = drm_get_format_info(dev, cmd);
  50
  51        if (info->num_planes != 1)
  52                return ERR_PTR(-EINVAL);
  53
  54        return drm_gem_fb_create(dev, file, cmd);
  55}
  56
  57static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = {
  58        .fb_create = mtk_drm_mode_fb_create,
  59        .atomic_check = drm_atomic_helper_check,
  60        .atomic_commit = drm_atomic_helper_commit,
  61};
  62
  63static const enum mtk_ddp_comp_id mt2701_mtk_ddp_main[] = {
  64        DDP_COMPONENT_OVL0,
  65        DDP_COMPONENT_RDMA0,
  66        DDP_COMPONENT_COLOR0,
  67        DDP_COMPONENT_BLS,
  68        DDP_COMPONENT_DSI0,
  69};
  70
  71static const enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = {
  72        DDP_COMPONENT_RDMA1,
  73        DDP_COMPONENT_DPI0,
  74};
  75
  76static const enum mtk_ddp_comp_id mt7623_mtk_ddp_main[] = {
  77        DDP_COMPONENT_OVL0,
  78        DDP_COMPONENT_RDMA0,
  79        DDP_COMPONENT_COLOR0,
  80        DDP_COMPONENT_BLS,
  81        DDP_COMPONENT_DPI0,
  82};
  83
  84static const enum mtk_ddp_comp_id mt7623_mtk_ddp_ext[] = {
  85        DDP_COMPONENT_RDMA1,
  86        DDP_COMPONENT_DSI0,
  87};
  88
  89static const enum mtk_ddp_comp_id mt2712_mtk_ddp_main[] = {
  90        DDP_COMPONENT_OVL0,
  91        DDP_COMPONENT_COLOR0,
  92        DDP_COMPONENT_AAL0,
  93        DDP_COMPONENT_OD0,
  94        DDP_COMPONENT_RDMA0,
  95        DDP_COMPONENT_DPI0,
  96        DDP_COMPONENT_PWM0,
  97};
  98
  99static const enum mtk_ddp_comp_id mt2712_mtk_ddp_ext[] = {
 100        DDP_COMPONENT_OVL1,
 101        DDP_COMPONENT_COLOR1,
 102        DDP_COMPONENT_AAL1,
 103        DDP_COMPONENT_OD1,
 104        DDP_COMPONENT_RDMA1,
 105        DDP_COMPONENT_DPI1,
 106        DDP_COMPONENT_PWM1,
 107};
 108
 109static const enum mtk_ddp_comp_id mt2712_mtk_ddp_third[] = {
 110        DDP_COMPONENT_RDMA2,
 111        DDP_COMPONENT_DSI3,
 112        DDP_COMPONENT_PWM2,
 113};
 114
 115static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = {
 116        DDP_COMPONENT_OVL0,
 117        DDP_COMPONENT_COLOR0,
 118        DDP_COMPONENT_AAL0,
 119        DDP_COMPONENT_OD0,
 120        DDP_COMPONENT_RDMA0,
 121        DDP_COMPONENT_UFOE,
 122        DDP_COMPONENT_DSI0,
 123        DDP_COMPONENT_PWM0,
 124};
 125
 126static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
 127        DDP_COMPONENT_OVL1,
 128        DDP_COMPONENT_COLOR1,
 129        DDP_COMPONENT_GAMMA,
 130        DDP_COMPONENT_RDMA1,
 131        DDP_COMPONENT_DPI0,
 132};
 133
 134static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
 135        .main_path = mt2701_mtk_ddp_main,
 136        .main_len = ARRAY_SIZE(mt2701_mtk_ddp_main),
 137        .ext_path = mt2701_mtk_ddp_ext,
 138        .ext_len = ARRAY_SIZE(mt2701_mtk_ddp_ext),
 139        .shadow_register = true,
 140};
 141
 142static const struct mtk_mmsys_driver_data mt7623_mmsys_driver_data = {
 143        .main_path = mt7623_mtk_ddp_main,
 144        .main_len = ARRAY_SIZE(mt7623_mtk_ddp_main),
 145        .ext_path = mt7623_mtk_ddp_ext,
 146        .ext_len = ARRAY_SIZE(mt7623_mtk_ddp_ext),
 147        .shadow_register = true,
 148};
 149
 150static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = {
 151        .main_path = mt2712_mtk_ddp_main,
 152        .main_len = ARRAY_SIZE(mt2712_mtk_ddp_main),
 153        .ext_path = mt2712_mtk_ddp_ext,
 154        .ext_len = ARRAY_SIZE(mt2712_mtk_ddp_ext),
 155        .third_path = mt2712_mtk_ddp_third,
 156        .third_len = ARRAY_SIZE(mt2712_mtk_ddp_third),
 157};
 158
 159static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
 160        .main_path = mt8173_mtk_ddp_main,
 161        .main_len = ARRAY_SIZE(mt8173_mtk_ddp_main),
 162        .ext_path = mt8173_mtk_ddp_ext,
 163        .ext_len = ARRAY_SIZE(mt8173_mtk_ddp_ext),
 164};
 165
 166static int mtk_drm_kms_init(struct drm_device *drm)
 167{
 168        struct mtk_drm_private *private = drm->dev_private;
 169        struct platform_device *pdev;
 170        struct device_node *np;
 171        struct device *dma_dev;
 172        int ret;
 173
 174        if (!iommu_present(&platform_bus_type))
 175                return -EPROBE_DEFER;
 176
 177        pdev = of_find_device_by_node(private->mutex_node);
 178        if (!pdev) {
 179                dev_err(drm->dev, "Waiting for disp-mutex device %pOF\n",
 180                        private->mutex_node);
 181                of_node_put(private->mutex_node);
 182                return -EPROBE_DEFER;
 183        }
 184        private->mutex_dev = &pdev->dev;
 185
 186        ret = drmm_mode_config_init(drm);
 187        if (ret)
 188                goto put_mutex_dev;
 189
 190        drm->mode_config.min_width = 64;
 191        drm->mode_config.min_height = 64;
 192
 193        /*
 194         * set max width and height as default value(4096x4096).
 195         * this value would be used to check framebuffer size limitation
 196         * at drm_mode_addfb().
 197         */
 198        drm->mode_config.max_width = 4096;
 199        drm->mode_config.max_height = 4096;
 200        drm->mode_config.funcs = &mtk_drm_mode_config_funcs;
 201        drm->mode_config.helper_private = &mtk_drm_mode_config_helpers;
 202
 203        ret = component_bind_all(drm->dev, drm);
 204        if (ret)
 205                goto put_mutex_dev;
 206
 207        /*
 208         * We currently support two fixed data streams, each optional,
 209         * and each statically assigned to a crtc:
 210         * OVL0 -> COLOR0 -> AAL -> OD -> RDMA0 -> UFOE -> DSI0 ...
 211         */
 212        ret = mtk_drm_crtc_create(drm, private->data->main_path,
 213                                  private->data->main_len);
 214        if (ret < 0)
 215                goto err_component_unbind;
 216        /* ... and OVL1 -> COLOR1 -> GAMMA -> RDMA1 -> DPI0. */
 217        ret = mtk_drm_crtc_create(drm, private->data->ext_path,
 218                                  private->data->ext_len);
 219        if (ret < 0)
 220                goto err_component_unbind;
 221
 222        ret = mtk_drm_crtc_create(drm, private->data->third_path,
 223                                  private->data->third_len);
 224        if (ret < 0)
 225                goto err_component_unbind;
 226
 227        /* Use OVL device for all DMA memory allocations */
 228        np = private->comp_node[private->data->main_path[0]] ?:
 229             private->comp_node[private->data->ext_path[0]];
 230        pdev = of_find_device_by_node(np);
 231        if (!pdev) {
 232                ret = -ENODEV;
 233                dev_err(drm->dev, "Need at least one OVL device\n");
 234                goto err_component_unbind;
 235        }
 236
 237        dma_dev = &pdev->dev;
 238        private->dma_dev = dma_dev;
 239
 240        /*
 241         * Configure the DMA segment size to make sure we get contiguous IOVA
 242         * when importing PRIME buffers.
 243         */
 244        if (!dma_dev->dma_parms) {
 245                private->dma_parms_allocated = true;
 246                dma_dev->dma_parms =
 247                        devm_kzalloc(drm->dev, sizeof(*dma_dev->dma_parms),
 248                                     GFP_KERNEL);
 249        }
 250        if (!dma_dev->dma_parms) {
 251                ret = -ENOMEM;
 252                goto put_dma_dev;
 253        }
 254
 255        ret = dma_set_max_seg_size(dma_dev, (unsigned int)DMA_BIT_MASK(32));
 256        if (ret) {
 257                dev_err(dma_dev, "Failed to set DMA segment size\n");
 258                goto err_unset_dma_parms;
 259        }
 260
 261        /*
 262         * We don't use the drm_irq_install() helpers provided by the DRM
 263         * core, so we need to set this manually in order to allow the
 264         * DRM_IOCTL_WAIT_VBLANK to operate correctly.
 265         */
 266        drm->irq_enabled = true;
 267        ret = drm_vblank_init(drm, MAX_CRTC);
 268        if (ret < 0)
 269                goto err_unset_dma_parms;
 270
 271        drm_kms_helper_poll_init(drm);
 272        drm_mode_config_reset(drm);
 273
 274        return 0;
 275
 276err_unset_dma_parms:
 277        if (private->dma_parms_allocated)
 278                dma_dev->dma_parms = NULL;
 279put_dma_dev:
 280        put_device(private->dma_dev);
 281err_component_unbind:
 282        component_unbind_all(drm->dev, drm);
 283put_mutex_dev:
 284        put_device(private->mutex_dev);
 285        return ret;
 286}
 287
 288static void mtk_drm_kms_deinit(struct drm_device *drm)
 289{
 290        struct mtk_drm_private *private = drm->dev_private;
 291
 292        drm_kms_helper_poll_fini(drm);
 293        drm_atomic_helper_shutdown(drm);
 294
 295        if (private->dma_parms_allocated)
 296                private->dma_dev->dma_parms = NULL;
 297
 298        component_unbind_all(drm->dev, drm);
 299}
 300
 301static const struct file_operations mtk_drm_fops = {
 302        .owner = THIS_MODULE,
 303        .open = drm_open,
 304        .release = drm_release,
 305        .unlocked_ioctl = drm_ioctl,
 306        .mmap = mtk_drm_gem_mmap,
 307        .poll = drm_poll,
 308        .read = drm_read,
 309        .compat_ioctl = drm_compat_ioctl,
 310};
 311
 312/*
 313 * We need to override this because the device used to import the memory is
 314 * not dev->dev, as drm_gem_prime_import() expects.
 315 */
 316struct drm_gem_object *mtk_drm_gem_prime_import(struct drm_device *dev,
 317                                                struct dma_buf *dma_buf)
 318{
 319        struct mtk_drm_private *private = dev->dev_private;
 320
 321        return drm_gem_prime_import_dev(dev, dma_buf, private->dma_dev);
 322}
 323
 324static struct drm_driver mtk_drm_driver = {
 325        .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
 326
 327        .gem_free_object_unlocked = mtk_drm_gem_free_object,
 328        .gem_vm_ops = &drm_gem_cma_vm_ops,
 329        .dumb_create = mtk_drm_gem_dumb_create,
 330
 331        .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
 332        .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
 333        .gem_prime_import = mtk_drm_gem_prime_import,
 334        .gem_prime_get_sg_table = mtk_gem_prime_get_sg_table,
 335        .gem_prime_import_sg_table = mtk_gem_prime_import_sg_table,
 336        .gem_prime_mmap = mtk_drm_gem_mmap_buf,
 337        .gem_prime_vmap = mtk_drm_gem_prime_vmap,
 338        .gem_prime_vunmap = mtk_drm_gem_prime_vunmap,
 339        .fops = &mtk_drm_fops,
 340
 341        .name = DRIVER_NAME,
 342        .desc = DRIVER_DESC,
 343        .date = DRIVER_DATE,
 344        .major = DRIVER_MAJOR,
 345        .minor = DRIVER_MINOR,
 346};
 347
 348static int compare_of(struct device *dev, void *data)
 349{
 350        return dev->of_node == data;
 351}
 352
 353static int mtk_drm_bind(struct device *dev)
 354{
 355        struct mtk_drm_private *private = dev_get_drvdata(dev);
 356        struct drm_device *drm;
 357        int ret;
 358
 359        drm = drm_dev_alloc(&mtk_drm_driver, dev);
 360        if (IS_ERR(drm))
 361                return PTR_ERR(drm);
 362
 363        drm->dev_private = private;
 364        private->drm = drm;
 365
 366        ret = mtk_drm_kms_init(drm);
 367        if (ret < 0)
 368                goto err_free;
 369
 370        ret = drm_dev_register(drm, 0);
 371        if (ret < 0)
 372                goto err_deinit;
 373
 374        drm_fbdev_generic_setup(drm, 32);
 375
 376        return 0;
 377
 378err_deinit:
 379        mtk_drm_kms_deinit(drm);
 380err_free:
 381        drm_dev_put(drm);
 382        return ret;
 383}
 384
 385static void mtk_drm_unbind(struct device *dev)
 386{
 387        struct mtk_drm_private *private = dev_get_drvdata(dev);
 388
 389        drm_dev_unregister(private->drm);
 390        mtk_drm_kms_deinit(private->drm);
 391        drm_dev_put(private->drm);
 392        private->num_pipes = 0;
 393        private->drm = NULL;
 394}
 395
 396static const struct component_master_ops mtk_drm_ops = {
 397        .bind           = mtk_drm_bind,
 398        .unbind         = mtk_drm_unbind,
 399};
 400
 401static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
 402        { .compatible = "mediatek,mt2701-disp-ovl",
 403          .data = (void *)MTK_DISP_OVL },
 404        { .compatible = "mediatek,mt8173-disp-ovl",
 405          .data = (void *)MTK_DISP_OVL },
 406        { .compatible = "mediatek,mt2701-disp-rdma",
 407          .data = (void *)MTK_DISP_RDMA },
 408        { .compatible = "mediatek,mt8173-disp-rdma",
 409          .data = (void *)MTK_DISP_RDMA },
 410        { .compatible = "mediatek,mt8173-disp-wdma",
 411          .data = (void *)MTK_DISP_WDMA },
 412        { .compatible = "mediatek,mt2701-disp-color",
 413          .data = (void *)MTK_DISP_COLOR },
 414        { .compatible = "mediatek,mt8173-disp-color",
 415          .data = (void *)MTK_DISP_COLOR },
 416        { .compatible = "mediatek,mt8173-disp-aal",
 417          .data = (void *)MTK_DISP_AAL},
 418        { .compatible = "mediatek,mt8173-disp-gamma",
 419          .data = (void *)MTK_DISP_GAMMA, },
 420        { .compatible = "mediatek,mt8173-disp-ufoe",
 421          .data = (void *)MTK_DISP_UFOE },
 422        { .compatible = "mediatek,mt2701-dsi",
 423          .data = (void *)MTK_DSI },
 424        { .compatible = "mediatek,mt8173-dsi",
 425          .data = (void *)MTK_DSI },
 426        { .compatible = "mediatek,mt2701-dpi",
 427          .data = (void *)MTK_DPI },
 428        { .compatible = "mediatek,mt8173-dpi",
 429          .data = (void *)MTK_DPI },
 430        { .compatible = "mediatek,mt2701-disp-mutex",
 431          .data = (void *)MTK_DISP_MUTEX },
 432        { .compatible = "mediatek,mt2712-disp-mutex",
 433          .data = (void *)MTK_DISP_MUTEX },
 434        { .compatible = "mediatek,mt8173-disp-mutex",
 435          .data = (void *)MTK_DISP_MUTEX },
 436        { .compatible = "mediatek,mt2701-disp-pwm",
 437          .data = (void *)MTK_DISP_BLS },
 438        { .compatible = "mediatek,mt8173-disp-pwm",
 439          .data = (void *)MTK_DISP_PWM },
 440        { .compatible = "mediatek,mt8173-disp-od",
 441          .data = (void *)MTK_DISP_OD },
 442        { }
 443};
 444
 445static const struct of_device_id mtk_drm_of_ids[] = {
 446        { .compatible = "mediatek,mt2701-mmsys",
 447          .data = &mt2701_mmsys_driver_data},
 448        { .compatible = "mediatek,mt7623-mmsys",
 449          .data = &mt7623_mmsys_driver_data},
 450        { .compatible = "mediatek,mt2712-mmsys",
 451          .data = &mt2712_mmsys_driver_data},
 452        { .compatible = "mediatek,mt8173-mmsys",
 453          .data = &mt8173_mmsys_driver_data},
 454        { }
 455};
 456
 457static int mtk_drm_probe(struct platform_device *pdev)
 458{
 459        struct device *dev = &pdev->dev;
 460        struct device_node *phandle = dev->parent->of_node;
 461        const struct of_device_id *of_id;
 462        struct mtk_drm_private *private;
 463        struct device_node *node;
 464        struct component_match *match = NULL;
 465        int ret;
 466        int i;
 467
 468        private = devm_kzalloc(dev, sizeof(*private), GFP_KERNEL);
 469        if (!private)
 470                return -ENOMEM;
 471
 472        private->mmsys_dev = dev->parent;
 473        if (!private->mmsys_dev) {
 474                dev_err(dev, "Failed to get MMSYS device\n");
 475                return -ENODEV;
 476        }
 477
 478        of_id = of_match_node(mtk_drm_of_ids, phandle);
 479        if (!of_id)
 480                return -ENODEV;
 481
 482        private->data = of_id->data;
 483
 484        /* Iterate over sibling DISP function blocks */
 485        for_each_child_of_node(phandle->parent, node) {
 486                const struct of_device_id *of_id;
 487                enum mtk_ddp_comp_type comp_type;
 488                int comp_id;
 489
 490                of_id = of_match_node(mtk_ddp_comp_dt_ids, node);
 491                if (!of_id)
 492                        continue;
 493
 494                if (!of_device_is_available(node)) {
 495                        dev_dbg(dev, "Skipping disabled component %pOF\n",
 496                                node);
 497                        continue;
 498                }
 499
 500                comp_type = (enum mtk_ddp_comp_type)of_id->data;
 501
 502                if (comp_type == MTK_DISP_MUTEX) {
 503                        private->mutex_node = of_node_get(node);
 504                        continue;
 505                }
 506
 507                comp_id = mtk_ddp_comp_get_id(node, comp_type);
 508                if (comp_id < 0) {
 509                        dev_warn(dev, "Skipping unknown component %pOF\n",
 510                                 node);
 511                        continue;
 512                }
 513
 514                private->comp_node[comp_id] = of_node_get(node);
 515
 516                /*
 517                 * Currently only the COLOR, OVL, RDMA, DSI, and DPI blocks have
 518                 * separate component platform drivers and initialize their own
 519                 * DDP component structure. The others are initialized here.
 520                 */
 521                if (comp_type == MTK_DISP_COLOR ||
 522                    comp_type == MTK_DISP_OVL ||
 523                    comp_type == MTK_DISP_OVL_2L ||
 524                    comp_type == MTK_DISP_RDMA ||
 525                    comp_type == MTK_DSI ||
 526                    comp_type == MTK_DPI) {
 527                        dev_info(dev, "Adding component match for %pOF\n",
 528                                 node);
 529                        drm_of_component_match_add(dev, &match, compare_of,
 530                                                   node);
 531                } else {
 532                        struct mtk_ddp_comp *comp;
 533
 534                        comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
 535                        if (!comp) {
 536                                ret = -ENOMEM;
 537                                of_node_put(node);
 538                                goto err_node;
 539                        }
 540
 541                        ret = mtk_ddp_comp_init(dev->parent, node, comp,
 542                                                comp_id, NULL);
 543                        if (ret) {
 544                                of_node_put(node);
 545                                goto err_node;
 546                        }
 547
 548                        private->ddp_comp[comp_id] = comp;
 549                }
 550        }
 551
 552        if (!private->mutex_node) {
 553                dev_err(dev, "Failed to find disp-mutex node\n");
 554                ret = -ENODEV;
 555                goto err_node;
 556        }
 557
 558        pm_runtime_enable(dev);
 559
 560        platform_set_drvdata(pdev, private);
 561
 562        ret = component_master_add_with_match(dev, &mtk_drm_ops, match);
 563        if (ret)
 564                goto err_pm;
 565
 566        return 0;
 567
 568err_pm:
 569        pm_runtime_disable(dev);
 570err_node:
 571        of_node_put(private->mutex_node);
 572        for (i = 0; i < DDP_COMPONENT_ID_MAX; i++) {
 573                of_node_put(private->comp_node[i]);
 574                if (private->ddp_comp[i]) {
 575                        put_device(private->ddp_comp[i]->larb_dev);
 576                        private->ddp_comp[i] = NULL;
 577                }
 578        }
 579        return ret;
 580}
 581
 582static int mtk_drm_remove(struct platform_device *pdev)
 583{
 584        struct mtk_drm_private *private = platform_get_drvdata(pdev);
 585        int i;
 586
 587        component_master_del(&pdev->dev, &mtk_drm_ops);
 588        pm_runtime_disable(&pdev->dev);
 589        of_node_put(private->mutex_node);
 590        for (i = 0; i < DDP_COMPONENT_ID_MAX; i++)
 591                of_node_put(private->comp_node[i]);
 592
 593        return 0;
 594}
 595
 596#ifdef CONFIG_PM_SLEEP
 597static int mtk_drm_sys_suspend(struct device *dev)
 598{
 599        struct mtk_drm_private *private = dev_get_drvdata(dev);
 600        struct drm_device *drm = private->drm;
 601        int ret;
 602
 603        ret = drm_mode_config_helper_suspend(drm);
 604
 605        return ret;
 606}
 607
 608static int mtk_drm_sys_resume(struct device *dev)
 609{
 610        struct mtk_drm_private *private = dev_get_drvdata(dev);
 611        struct drm_device *drm = private->drm;
 612        int ret;
 613
 614        ret = drm_mode_config_helper_resume(drm);
 615
 616        return ret;
 617}
 618#endif
 619
 620static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend,
 621                         mtk_drm_sys_resume);
 622
 623static struct platform_driver mtk_drm_platform_driver = {
 624        .probe  = mtk_drm_probe,
 625        .remove = mtk_drm_remove,
 626        .driver = {
 627                .name   = "mediatek-drm",
 628                .pm     = &mtk_drm_pm_ops,
 629        },
 630};
 631
 632static struct platform_driver * const mtk_drm_drivers[] = {
 633        &mtk_ddp_driver,
 634        &mtk_disp_color_driver,
 635        &mtk_disp_ovl_driver,
 636        &mtk_disp_rdma_driver,
 637        &mtk_dpi_driver,
 638        &mtk_drm_platform_driver,
 639        &mtk_mipi_tx_driver,
 640        &mtk_dsi_driver,
 641};
 642
 643static int __init mtk_drm_init(void)
 644{
 645        return platform_register_drivers(mtk_drm_drivers,
 646                                         ARRAY_SIZE(mtk_drm_drivers));
 647}
 648
 649static void __exit mtk_drm_exit(void)
 650{
 651        platform_unregister_drivers(mtk_drm_drivers,
 652                                    ARRAY_SIZE(mtk_drm_drivers));
 653}
 654
 655module_init(mtk_drm_init);
 656module_exit(mtk_drm_exit);
 657
 658MODULE_AUTHOR("YT SHEN <yt.shen@mediatek.com>");
 659MODULE_DESCRIPTION("Mediatek SoC DRM driver");
 660MODULE_LICENSE("GPL v2");
 661