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