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