1 // SPDX-License-Identifier: GPL-2.0+
3 * R-Car Display Unit DRM driver
5 * Copyright (C) 2013-2015 Renesas Electronics Corporation
7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
10 #include <linux/clk.h>
11 #include <linux/dma-mapping.h>
14 #include <linux/module.h>
16 #include <linux/platform_device.h>
18 #include <linux/slab.h>
19 #include <linux/wait.h>
21 #include <drm/drm_atomic_helper.h>
22 #include <drm/drm_client_setup.h>
23 #include <drm/drm_drv.h>
24 #include <drm/drm_fbdev_dma.h>
25 #include <drm/drm_gem_dma_helper.h>
26 #include <drm/drm_managed.h>
27 #include <drm/drm_probe_helper.h>
29 #include "rcar_du_drv.h"
30 #include "rcar_du_kms.h"
32 /* -----------------------------------------------------------------------------
36 static const struct rcar_du_device_info rzg1_du_r8a7743_info
= {
38 .features
= RCAR_DU_FEATURE_CRTC_IRQ
39 | RCAR_DU_FEATURE_CRTC_CLOCK
40 | RCAR_DU_FEATURE_INTERLACED
41 | RCAR_DU_FEATURE_TVM_SYNC
,
42 .channels_mask
= BIT(1) | BIT(0),
45 * R8A774[34] has one RGB output and one LVDS output
47 [RCAR_DU_OUTPUT_DPAD0
] = {
48 .possible_crtcs
= BIT(1) | BIT(0),
51 [RCAR_DU_OUTPUT_LVDS0
] = {
52 .possible_crtcs
= BIT(0),
60 static const struct rcar_du_device_info rzg1_du_r8a7745_info
= {
62 .features
= RCAR_DU_FEATURE_CRTC_IRQ
63 | RCAR_DU_FEATURE_CRTC_CLOCK
64 | RCAR_DU_FEATURE_INTERLACED
65 | RCAR_DU_FEATURE_TVM_SYNC
,
66 .channels_mask
= BIT(1) | BIT(0),
69 * R8A7745 has two RGB outputs
71 [RCAR_DU_OUTPUT_DPAD0
] = {
72 .possible_crtcs
= BIT(0),
75 [RCAR_DU_OUTPUT_DPAD1
] = {
76 .possible_crtcs
= BIT(1),
83 static const struct rcar_du_device_info rzg1_du_r8a77470_info
= {
85 .features
= RCAR_DU_FEATURE_CRTC_IRQ
86 | RCAR_DU_FEATURE_CRTC_CLOCK
87 | RCAR_DU_FEATURE_INTERLACED
88 | RCAR_DU_FEATURE_TVM_SYNC
,
89 .channels_mask
= BIT(1) | BIT(0),
92 * R8A77470 has two RGB outputs, one LVDS output, and
93 * one (currently unsupported) analog video output
95 [RCAR_DU_OUTPUT_DPAD0
] = {
96 .possible_crtcs
= BIT(0),
99 [RCAR_DU_OUTPUT_DPAD1
] = {
100 .possible_crtcs
= BIT(1),
103 [RCAR_DU_OUTPUT_LVDS0
] = {
104 .possible_crtcs
= BIT(0) | BIT(1),
111 static const struct rcar_du_device_info rcar_du_r8a774a1_info
= {
113 .features
= RCAR_DU_FEATURE_CRTC_IRQ
114 | RCAR_DU_FEATURE_CRTC_CLOCK
115 | RCAR_DU_FEATURE_VSP1_SOURCE
116 | RCAR_DU_FEATURE_INTERLACED
117 | RCAR_DU_FEATURE_TVM_SYNC
,
118 .channels_mask
= BIT(2) | BIT(1) | BIT(0),
121 * R8A774A1 has one RGB output, one LVDS output and one HDMI
124 [RCAR_DU_OUTPUT_DPAD0
] = {
125 .possible_crtcs
= BIT(2),
128 [RCAR_DU_OUTPUT_HDMI0
] = {
129 .possible_crtcs
= BIT(1),
132 [RCAR_DU_OUTPUT_LVDS0
] = {
133 .possible_crtcs
= BIT(0),
142 static const struct rcar_du_device_info rcar_du_r8a774b1_info
= {
144 .features
= RCAR_DU_FEATURE_CRTC_IRQ
145 | RCAR_DU_FEATURE_CRTC_CLOCK
146 | RCAR_DU_FEATURE_VSP1_SOURCE
147 | RCAR_DU_FEATURE_INTERLACED
148 | RCAR_DU_FEATURE_TVM_SYNC
,
149 .channels_mask
= BIT(3) | BIT(1) | BIT(0),
152 * R8A774B1 has one RGB output, one LVDS output and one HDMI
155 [RCAR_DU_OUTPUT_DPAD0
] = {
156 .possible_crtcs
= BIT(2),
159 [RCAR_DU_OUTPUT_HDMI0
] = {
160 .possible_crtcs
= BIT(1),
163 [RCAR_DU_OUTPUT_LVDS0
] = {
164 .possible_crtcs
= BIT(0),
173 static const struct rcar_du_device_info rcar_du_r8a774c0_info
= {
175 .features
= RCAR_DU_FEATURE_CRTC_IRQ
176 | RCAR_DU_FEATURE_CRTC_CLOCK
177 | RCAR_DU_FEATURE_VSP1_SOURCE
,
178 .channels_mask
= BIT(1) | BIT(0),
181 * R8A774C0 has one RGB output and two LVDS outputs
183 [RCAR_DU_OUTPUT_DPAD0
] = {
184 .possible_crtcs
= BIT(0) | BIT(1),
187 [RCAR_DU_OUTPUT_LVDS0
] = {
188 .possible_crtcs
= BIT(0),
191 [RCAR_DU_OUTPUT_LVDS1
] = {
192 .possible_crtcs
= BIT(1),
198 .lvds_clk_mask
= BIT(1) | BIT(0),
201 static const struct rcar_du_device_info rcar_du_r8a774e1_info
= {
203 .features
= RCAR_DU_FEATURE_CRTC_IRQ
204 | RCAR_DU_FEATURE_CRTC_CLOCK
205 | RCAR_DU_FEATURE_VSP1_SOURCE
206 | RCAR_DU_FEATURE_INTERLACED
207 | RCAR_DU_FEATURE_TVM_SYNC
,
208 .channels_mask
= BIT(3) | BIT(1) | BIT(0),
211 * R8A774E1 has one RGB output, one LVDS output and one HDMI
214 [RCAR_DU_OUTPUT_DPAD0
] = {
215 .possible_crtcs
= BIT(2),
218 [RCAR_DU_OUTPUT_HDMI0
] = {
219 .possible_crtcs
= BIT(1),
222 [RCAR_DU_OUTPUT_LVDS0
] = {
223 .possible_crtcs
= BIT(0),
232 static const struct rcar_du_device_info rcar_du_r8a7779_info
= {
234 .features
= RCAR_DU_FEATURE_INTERLACED
235 | RCAR_DU_FEATURE_TVM_SYNC
,
236 .channels_mask
= BIT(1) | BIT(0),
239 * R8A7779 has two RGB outputs and one (currently unsupported)
242 [RCAR_DU_OUTPUT_DPAD0
] = {
243 .possible_crtcs
= BIT(0),
246 [RCAR_DU_OUTPUT_DPAD1
] = {
247 .possible_crtcs
= BIT(1) | BIT(0),
253 static const struct rcar_du_device_info rcar_du_r8a7790_info
= {
255 .features
= RCAR_DU_FEATURE_CRTC_IRQ
256 | RCAR_DU_FEATURE_CRTC_CLOCK
257 | RCAR_DU_FEATURE_INTERLACED
258 | RCAR_DU_FEATURE_TVM_SYNC
,
259 .quirks
= RCAR_DU_QUIRK_ALIGN_128B
,
260 .channels_mask
= BIT(2) | BIT(1) | BIT(0),
263 * R8A7742 and R8A7790 each have one RGB output and two LVDS
264 * outputs. Additionally R8A7790 supports one TCON output
265 * (currently unsupported by the driver).
267 [RCAR_DU_OUTPUT_DPAD0
] = {
268 .possible_crtcs
= BIT(2) | BIT(1) | BIT(0),
271 [RCAR_DU_OUTPUT_LVDS0
] = {
272 .possible_crtcs
= BIT(0),
275 [RCAR_DU_OUTPUT_LVDS1
] = {
276 .possible_crtcs
= BIT(2) | BIT(1),
284 /* M2-W (r8a7791) and M2-N (r8a7793) are identical */
285 static const struct rcar_du_device_info rcar_du_r8a7791_info
= {
287 .features
= RCAR_DU_FEATURE_CRTC_IRQ
288 | RCAR_DU_FEATURE_CRTC_CLOCK
289 | RCAR_DU_FEATURE_INTERLACED
290 | RCAR_DU_FEATURE_TVM_SYNC
,
291 .channels_mask
= BIT(1) | BIT(0),
294 * R8A779[13] has one RGB output, one LVDS output and one
295 * (currently unsupported) TCON output.
297 [RCAR_DU_OUTPUT_DPAD0
] = {
298 .possible_crtcs
= BIT(1) | BIT(0),
301 [RCAR_DU_OUTPUT_LVDS0
] = {
302 .possible_crtcs
= BIT(0),
310 static const struct rcar_du_device_info rcar_du_r8a7792_info
= {
312 .features
= RCAR_DU_FEATURE_CRTC_IRQ
313 | RCAR_DU_FEATURE_CRTC_CLOCK
314 | RCAR_DU_FEATURE_INTERLACED
315 | RCAR_DU_FEATURE_TVM_SYNC
,
316 .channels_mask
= BIT(1) | BIT(0),
318 /* R8A7792 has two RGB outputs. */
319 [RCAR_DU_OUTPUT_DPAD0
] = {
320 .possible_crtcs
= BIT(0),
323 [RCAR_DU_OUTPUT_DPAD1
] = {
324 .possible_crtcs
= BIT(1),
331 static const struct rcar_du_device_info rcar_du_r8a7794_info
= {
333 .features
= RCAR_DU_FEATURE_CRTC_IRQ
334 | RCAR_DU_FEATURE_CRTC_CLOCK
335 | RCAR_DU_FEATURE_INTERLACED
336 | RCAR_DU_FEATURE_TVM_SYNC
,
337 .channels_mask
= BIT(1) | BIT(0),
340 * R8A7794 has two RGB outputs and one (currently unsupported)
343 [RCAR_DU_OUTPUT_DPAD0
] = {
344 .possible_crtcs
= BIT(0),
347 [RCAR_DU_OUTPUT_DPAD1
] = {
348 .possible_crtcs
= BIT(1),
355 static const struct rcar_du_device_info rcar_du_r8a7795_info
= {
357 .features
= RCAR_DU_FEATURE_CRTC_IRQ
358 | RCAR_DU_FEATURE_CRTC_CLOCK
359 | RCAR_DU_FEATURE_VSP1_SOURCE
360 | RCAR_DU_FEATURE_INTERLACED
361 | RCAR_DU_FEATURE_TVM_SYNC
,
362 .channels_mask
= BIT(3) | BIT(2) | BIT(1) | BIT(0),
365 * R8A7795 has one RGB output, two HDMI outputs and one
368 [RCAR_DU_OUTPUT_DPAD0
] = {
369 .possible_crtcs
= BIT(3),
372 [RCAR_DU_OUTPUT_HDMI0
] = {
373 .possible_crtcs
= BIT(1),
376 [RCAR_DU_OUTPUT_HDMI1
] = {
377 .possible_crtcs
= BIT(2),
380 [RCAR_DU_OUTPUT_LVDS0
] = {
381 .possible_crtcs
= BIT(0),
387 .dpll_mask
= BIT(2) | BIT(1),
390 static const struct rcar_du_device_info rcar_du_r8a7796_info
= {
392 .features
= RCAR_DU_FEATURE_CRTC_IRQ
393 | RCAR_DU_FEATURE_CRTC_CLOCK
394 | RCAR_DU_FEATURE_VSP1_SOURCE
395 | RCAR_DU_FEATURE_INTERLACED
396 | RCAR_DU_FEATURE_TVM_SYNC
,
397 .channels_mask
= BIT(2) | BIT(1) | BIT(0),
400 * R8A7796 has one RGB output, one LVDS output and one HDMI
403 [RCAR_DU_OUTPUT_DPAD0
] = {
404 .possible_crtcs
= BIT(2),
407 [RCAR_DU_OUTPUT_HDMI0
] = {
408 .possible_crtcs
= BIT(1),
411 [RCAR_DU_OUTPUT_LVDS0
] = {
412 .possible_crtcs
= BIT(0),
421 static const struct rcar_du_device_info rcar_du_r8a77965_info
= {
423 .features
= RCAR_DU_FEATURE_CRTC_IRQ
424 | RCAR_DU_FEATURE_CRTC_CLOCK
425 | RCAR_DU_FEATURE_VSP1_SOURCE
426 | RCAR_DU_FEATURE_INTERLACED
427 | RCAR_DU_FEATURE_TVM_SYNC
,
428 .channels_mask
= BIT(3) | BIT(1) | BIT(0),
431 * R8A77965 has one RGB output, one LVDS output and one HDMI
434 [RCAR_DU_OUTPUT_DPAD0
] = {
435 .possible_crtcs
= BIT(2),
438 [RCAR_DU_OUTPUT_HDMI0
] = {
439 .possible_crtcs
= BIT(1),
442 [RCAR_DU_OUTPUT_LVDS0
] = {
443 .possible_crtcs
= BIT(0),
452 static const struct rcar_du_device_info rcar_du_r8a77970_info
= {
454 .features
= RCAR_DU_FEATURE_CRTC_IRQ
455 | RCAR_DU_FEATURE_CRTC_CLOCK
456 | RCAR_DU_FEATURE_VSP1_SOURCE
457 | RCAR_DU_FEATURE_INTERLACED
458 | RCAR_DU_FEATURE_TVM_SYNC
,
459 .channels_mask
= BIT(0),
462 * R8A77970 and R8A77980 have one RGB output and one LVDS
465 [RCAR_DU_OUTPUT_DPAD0
] = {
466 .possible_crtcs
= BIT(0),
469 [RCAR_DU_OUTPUT_LVDS0
] = {
470 .possible_crtcs
= BIT(0),
478 static const struct rcar_du_device_info rcar_du_r8a7799x_info
= {
480 .features
= RCAR_DU_FEATURE_CRTC_IRQ
481 | RCAR_DU_FEATURE_CRTC_CLOCK
482 | RCAR_DU_FEATURE_VSP1_SOURCE
,
483 .channels_mask
= BIT(1) | BIT(0),
486 * R8A77990 and R8A77995 have one RGB output and two LVDS
489 [RCAR_DU_OUTPUT_DPAD0
] = {
490 .possible_crtcs
= BIT(0) | BIT(1),
493 [RCAR_DU_OUTPUT_LVDS0
] = {
494 .possible_crtcs
= BIT(0),
497 [RCAR_DU_OUTPUT_LVDS1
] = {
498 .possible_crtcs
= BIT(1),
504 .lvds_clk_mask
= BIT(1) | BIT(0),
507 static const struct rcar_du_device_info rcar_du_r8a779a0_info
= {
509 .features
= RCAR_DU_FEATURE_CRTC_IRQ
510 | RCAR_DU_FEATURE_VSP1_SOURCE
511 | RCAR_DU_FEATURE_NO_BLENDING
,
512 .channels_mask
= BIT(1) | BIT(0),
514 /* R8A779A0 has two MIPI DSI outputs. */
515 [RCAR_DU_OUTPUT_DSI0
] = {
516 .possible_crtcs
= BIT(0),
519 [RCAR_DU_OUTPUT_DSI1
] = {
520 .possible_crtcs
= BIT(1),
525 .dsi_clk_mask
= BIT(1) | BIT(0),
528 static const struct rcar_du_device_info rcar_du_r8a779g0_info
= {
530 .features
= RCAR_DU_FEATURE_CRTC_IRQ
531 | RCAR_DU_FEATURE_VSP1_SOURCE
532 | RCAR_DU_FEATURE_NO_BLENDING
,
533 .channels_mask
= BIT(1) | BIT(0),
535 /* R8A779G0 has two MIPI DSI outputs. */
536 [RCAR_DU_OUTPUT_DSI0
] = {
537 .possible_crtcs
= BIT(0),
540 [RCAR_DU_OUTPUT_DSI1
] = {
541 .possible_crtcs
= BIT(1),
546 .dsi_clk_mask
= BIT(1) | BIT(0),
549 static const struct of_device_id rcar_du_of_table
[] = {
550 { .compatible
= "renesas,du-r8a7742", .data
= &rcar_du_r8a7790_info
},
551 { .compatible
= "renesas,du-r8a7743", .data
= &rzg1_du_r8a7743_info
},
552 { .compatible
= "renesas,du-r8a7744", .data
= &rzg1_du_r8a7743_info
},
553 { .compatible
= "renesas,du-r8a7745", .data
= &rzg1_du_r8a7745_info
},
554 { .compatible
= "renesas,du-r8a77470", .data
= &rzg1_du_r8a77470_info
},
555 { .compatible
= "renesas,du-r8a774a1", .data
= &rcar_du_r8a774a1_info
},
556 { .compatible
= "renesas,du-r8a774b1", .data
= &rcar_du_r8a774b1_info
},
557 { .compatible
= "renesas,du-r8a774c0", .data
= &rcar_du_r8a774c0_info
},
558 { .compatible
= "renesas,du-r8a774e1", .data
= &rcar_du_r8a774e1_info
},
559 { .compatible
= "renesas,du-r8a7779", .data
= &rcar_du_r8a7779_info
},
560 { .compatible
= "renesas,du-r8a7790", .data
= &rcar_du_r8a7790_info
},
561 { .compatible
= "renesas,du-r8a7791", .data
= &rcar_du_r8a7791_info
},
562 { .compatible
= "renesas,du-r8a7792", .data
= &rcar_du_r8a7792_info
},
563 { .compatible
= "renesas,du-r8a7793", .data
= &rcar_du_r8a7791_info
},
564 { .compatible
= "renesas,du-r8a7794", .data
= &rcar_du_r8a7794_info
},
565 { .compatible
= "renesas,du-r8a7795", .data
= &rcar_du_r8a7795_info
},
566 { .compatible
= "renesas,du-r8a7796", .data
= &rcar_du_r8a7796_info
},
567 { .compatible
= "renesas,du-r8a77961", .data
= &rcar_du_r8a7796_info
},
568 { .compatible
= "renesas,du-r8a77965", .data
= &rcar_du_r8a77965_info
},
569 { .compatible
= "renesas,du-r8a77970", .data
= &rcar_du_r8a77970_info
},
570 { .compatible
= "renesas,du-r8a77980", .data
= &rcar_du_r8a77970_info
},
571 { .compatible
= "renesas,du-r8a77990", .data
= &rcar_du_r8a7799x_info
},
572 { .compatible
= "renesas,du-r8a77995", .data
= &rcar_du_r8a7799x_info
},
573 { .compatible
= "renesas,du-r8a779a0", .data
= &rcar_du_r8a779a0_info
},
574 { .compatible
= "renesas,du-r8a779g0", .data
= &rcar_du_r8a779g0_info
},
578 MODULE_DEVICE_TABLE(of
, rcar_du_of_table
);
580 const char *rcar_du_output_name(enum rcar_du_output output
)
582 static const char * const names
[] = {
583 [RCAR_DU_OUTPUT_DPAD0
] = "DPAD0",
584 [RCAR_DU_OUTPUT_DPAD1
] = "DPAD1",
585 [RCAR_DU_OUTPUT_DSI0
] = "DSI0",
586 [RCAR_DU_OUTPUT_DSI1
] = "DSI1",
587 [RCAR_DU_OUTPUT_HDMI0
] = "HDMI0",
588 [RCAR_DU_OUTPUT_HDMI1
] = "HDMI1",
589 [RCAR_DU_OUTPUT_LVDS0
] = "LVDS0",
590 [RCAR_DU_OUTPUT_LVDS1
] = "LVDS1",
591 [RCAR_DU_OUTPUT_TCON
] = "TCON",
594 if (output
>= ARRAY_SIZE(names
) || !names
[output
])
597 return names
[output
];
600 /* -----------------------------------------------------------------------------
604 DEFINE_DRM_GEM_DMA_FOPS(rcar_du_fops
);
606 static const struct drm_driver rcar_du_driver
= {
607 .driver_features
= DRIVER_GEM
| DRIVER_MODESET
| DRIVER_ATOMIC
,
608 .dumb_create
= rcar_du_dumb_create
,
609 .gem_prime_import_sg_table
= rcar_du_gem_prime_import_sg_table
,
610 DRM_FBDEV_DMA_DRIVER_OPS
,
611 .fops
= &rcar_du_fops
,
613 .desc
= "Renesas R-Car Display Unit",
619 /* -----------------------------------------------------------------------------
623 static int rcar_du_pm_suspend(struct device
*dev
)
625 struct rcar_du_device
*rcdu
= dev_get_drvdata(dev
);
627 return drm_mode_config_helper_suspend(&rcdu
->ddev
);
630 static int rcar_du_pm_resume(struct device
*dev
)
632 struct rcar_du_device
*rcdu
= dev_get_drvdata(dev
);
634 return drm_mode_config_helper_resume(&rcdu
->ddev
);
637 static DEFINE_SIMPLE_DEV_PM_OPS(rcar_du_pm_ops
,
638 rcar_du_pm_suspend
, rcar_du_pm_resume
);
640 /* -----------------------------------------------------------------------------
644 static void rcar_du_remove(struct platform_device
*pdev
)
646 struct rcar_du_device
*rcdu
= platform_get_drvdata(pdev
);
647 struct drm_device
*ddev
= &rcdu
->ddev
;
649 drm_dev_unregister(ddev
);
650 drm_atomic_helper_shutdown(ddev
);
652 drm_kms_helper_poll_fini(ddev
);
655 static void rcar_du_shutdown(struct platform_device
*pdev
)
657 struct rcar_du_device
*rcdu
= platform_get_drvdata(pdev
);
659 drm_atomic_helper_shutdown(&rcdu
->ddev
);
662 static int rcar_du_probe(struct platform_device
*pdev
)
664 struct rcar_du_device
*rcdu
;
668 if (drm_firmware_drivers_only())
671 /* Allocate and initialize the R-Car device structure. */
672 rcdu
= devm_drm_dev_alloc(&pdev
->dev
, &rcar_du_driver
,
673 struct rcar_du_device
, ddev
);
675 return PTR_ERR(rcdu
);
677 rcdu
->dev
= &pdev
->dev
;
679 rcdu
->info
= of_device_get_match_data(rcdu
->dev
);
681 platform_set_drvdata(pdev
, rcdu
);
684 rcdu
->mmio
= devm_platform_ioremap_resource(pdev
, 0);
685 if (IS_ERR(rcdu
->mmio
))
686 return PTR_ERR(rcdu
->mmio
);
689 * Set the DMA coherent mask to reflect the DU 32-bit DMA address space
690 * limitations. When sourcing frames from a VSP the DU doesn't perform
691 * any memory access so set the mask to 40 bits to accept all buffers.
693 mask
= rcar_du_has(rcdu
, RCAR_DU_FEATURE_VSP1_SOURCE
) ? 40 : 32;
694 ret
= dma_coerce_mask_and_coherent(&pdev
->dev
, DMA_BIT_MASK(mask
));
698 /* DRM/KMS objects */
699 ret
= rcar_du_modeset_init(rcdu
);
702 * Don't use dev_err_probe(), as it would overwrite the probe
703 * deferral reason recorded in rcar_du_modeset_init().
705 if (ret
!= -EPROBE_DEFER
)
707 "failed to initialize DRM/KMS (%d)\n", ret
);
712 * Register the DRM device with the core and the connectors with
715 ret
= drm_dev_register(&rcdu
->ddev
, 0);
719 drm_info(&rcdu
->ddev
, "Device %s probed\n", dev_name(&pdev
->dev
));
721 drm_client_setup(&rcdu
->ddev
, NULL
);
726 drm_kms_helper_poll_fini(&rcdu
->ddev
);
730 static struct platform_driver rcar_du_platform_driver
= {
731 .probe
= rcar_du_probe
,
732 .remove
= rcar_du_remove
,
733 .shutdown
= rcar_du_shutdown
,
736 .pm
= pm_sleep_ptr(&rcar_du_pm_ops
),
737 .of_match_table
= rcar_du_of_table
,
741 module_platform_driver(rcar_du_platform_driver
);
743 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
744 MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver");
745 MODULE_LICENSE("GPL");