1 // SPDX-License-Identifier: GPL-2.0+
3 * rcar_du_drv.c -- R-Car Display Unit DRM driver
5 * Copyright (C) 2013-2015 Renesas Electronics Corporation
10 #include <linux/clk.h>
13 #include <linux/module.h>
14 #include <linux/of_device.h>
15 #include <linux/platform_device.h>
17 #include <linux/slab.h>
18 #include <linux/wait.h>
20 #include <drm/drm_atomic_helper.h>
21 #include <drm/drm_drv.h>
22 #include <drm/drm_fb_cma_helper.h>
23 #include <drm/drm_fb_helper.h>
24 #include <drm/drm_gem_cma_helper.h>
25 #include <drm/drm_managed.h>
26 #include <drm/drm_probe_helper.h>
28 #include "rcar_du_drv.h"
29 #include "rcar_du_kms.h"
30 #include "rcar_du_of.h"
31 #include "rcar_du_regs.h"
33 /* -----------------------------------------------------------------------------
37 static const struct rcar_du_device_info rzg1_du_r8a7743_info = {
39 .features = RCAR_DU_FEATURE_CRTC_IRQ_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),
59 static const struct rcar_du_device_info rzg1_du_r8a7745_info = {
61 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
62 | RCAR_DU_FEATURE_INTERLACED
63 | RCAR_DU_FEATURE_TVM_SYNC,
64 .channels_mask = BIT(1) | BIT(0),
67 * R8A7745 has two RGB outputs
69 [RCAR_DU_OUTPUT_DPAD0] = {
70 .possible_crtcs = BIT(0),
73 [RCAR_DU_OUTPUT_DPAD1] = {
74 .possible_crtcs = BIT(1),
80 static const struct rcar_du_device_info rzg1_du_r8a77470_info = {
82 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
83 | RCAR_DU_FEATURE_INTERLACED
84 | RCAR_DU_FEATURE_TVM_SYNC,
85 .channels_mask = BIT(1) | BIT(0),
88 * R8A77470 has two RGB outputs, one LVDS output, and
89 * one (currently unsupported) analog video output
91 [RCAR_DU_OUTPUT_DPAD0] = {
92 .possible_crtcs = BIT(0),
95 [RCAR_DU_OUTPUT_DPAD1] = {
96 .possible_crtcs = BIT(1),
99 [RCAR_DU_OUTPUT_LVDS0] = {
100 .possible_crtcs = BIT(0) | BIT(1),
106 static const struct rcar_du_device_info rcar_du_r8a774a1_info = {
108 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
109 | RCAR_DU_FEATURE_VSP1_SOURCE
110 | RCAR_DU_FEATURE_INTERLACED
111 | RCAR_DU_FEATURE_TVM_SYNC,
112 .channels_mask = BIT(2) | BIT(1) | BIT(0),
115 * R8A774A1 has one RGB output, one LVDS output and one HDMI
118 [RCAR_DU_OUTPUT_DPAD0] = {
119 .possible_crtcs = BIT(2),
122 [RCAR_DU_OUTPUT_HDMI0] = {
123 .possible_crtcs = BIT(1),
126 [RCAR_DU_OUTPUT_LVDS0] = {
127 .possible_crtcs = BIT(0),
135 static const struct rcar_du_device_info rcar_du_r8a774b1_info = {
137 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
138 | RCAR_DU_FEATURE_VSP1_SOURCE
139 | RCAR_DU_FEATURE_INTERLACED
140 | RCAR_DU_FEATURE_TVM_SYNC,
141 .channels_mask = BIT(3) | BIT(1) | BIT(0),
144 * R8A774B1 has one RGB output, one LVDS output and one HDMI
147 [RCAR_DU_OUTPUT_DPAD0] = {
148 .possible_crtcs = BIT(2),
151 [RCAR_DU_OUTPUT_HDMI0] = {
152 .possible_crtcs = BIT(1),
155 [RCAR_DU_OUTPUT_LVDS0] = {
156 .possible_crtcs = BIT(0),
164 static const struct rcar_du_device_info rcar_du_r8a774c0_info = {
166 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
167 | RCAR_DU_FEATURE_VSP1_SOURCE,
168 .channels_mask = BIT(1) | BIT(0),
171 * R8A774C0 has one RGB output and two LVDS outputs
173 [RCAR_DU_OUTPUT_DPAD0] = {
174 .possible_crtcs = BIT(0) | BIT(1),
177 [RCAR_DU_OUTPUT_LVDS0] = {
178 .possible_crtcs = BIT(0),
181 [RCAR_DU_OUTPUT_LVDS1] = {
182 .possible_crtcs = BIT(1),
187 .lvds_clk_mask = BIT(1) | BIT(0),
190 static const struct rcar_du_device_info rcar_du_r8a774e1_info = {
192 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
193 | RCAR_DU_FEATURE_VSP1_SOURCE
194 | RCAR_DU_FEATURE_INTERLACED
195 | RCAR_DU_FEATURE_TVM_SYNC,
196 .channels_mask = BIT(3) | BIT(1) | BIT(0),
199 * R8A774E1 has one RGB output, one LVDS output and one HDMI
202 [RCAR_DU_OUTPUT_DPAD0] = {
203 .possible_crtcs = BIT(2),
206 [RCAR_DU_OUTPUT_HDMI0] = {
207 .possible_crtcs = BIT(1),
210 [RCAR_DU_OUTPUT_LVDS0] = {
211 .possible_crtcs = BIT(0),
219 static const struct rcar_du_device_info rcar_du_r8a7779_info = {
221 .features = RCAR_DU_FEATURE_INTERLACED
222 | RCAR_DU_FEATURE_TVM_SYNC,
223 .channels_mask = BIT(1) | BIT(0),
226 * R8A7779 has two RGB outputs and one (currently unsupported)
229 [RCAR_DU_OUTPUT_DPAD0] = {
230 .possible_crtcs = BIT(0),
233 [RCAR_DU_OUTPUT_DPAD1] = {
234 .possible_crtcs = BIT(1) | BIT(0),
240 static const struct rcar_du_device_info rcar_du_r8a7790_info = {
242 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
243 | RCAR_DU_FEATURE_INTERLACED
244 | RCAR_DU_FEATURE_TVM_SYNC,
245 .quirks = RCAR_DU_QUIRK_ALIGN_128B,
246 .channels_mask = BIT(2) | BIT(1) | BIT(0),
249 * R8A7742 and R8A7790 each have one RGB output and two LVDS
250 * outputs. Additionally R8A7790 supports one TCON output
251 * (currently unsupported by the driver).
253 [RCAR_DU_OUTPUT_DPAD0] = {
254 .possible_crtcs = BIT(2) | BIT(1) | BIT(0),
257 [RCAR_DU_OUTPUT_LVDS0] = {
258 .possible_crtcs = BIT(0),
261 [RCAR_DU_OUTPUT_LVDS1] = {
262 .possible_crtcs = BIT(2) | BIT(1),
269 /* M2-W (r8a7791) and M2-N (r8a7793) are identical */
270 static const struct rcar_du_device_info rcar_du_r8a7791_info = {
272 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
273 | RCAR_DU_FEATURE_INTERLACED
274 | RCAR_DU_FEATURE_TVM_SYNC,
275 .channels_mask = BIT(1) | BIT(0),
278 * R8A779[13] has one RGB output, one LVDS output and one
279 * (currently unsupported) TCON output.
281 [RCAR_DU_OUTPUT_DPAD0] = {
282 .possible_crtcs = BIT(1) | BIT(0),
285 [RCAR_DU_OUTPUT_LVDS0] = {
286 .possible_crtcs = BIT(0),
293 static const struct rcar_du_device_info rcar_du_r8a7792_info = {
295 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
296 | RCAR_DU_FEATURE_INTERLACED
297 | RCAR_DU_FEATURE_TVM_SYNC,
298 .channels_mask = BIT(1) | BIT(0),
300 /* R8A7792 has two RGB outputs. */
301 [RCAR_DU_OUTPUT_DPAD0] = {
302 .possible_crtcs = BIT(0),
305 [RCAR_DU_OUTPUT_DPAD1] = {
306 .possible_crtcs = BIT(1),
312 static const struct rcar_du_device_info rcar_du_r8a7794_info = {
314 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
315 | RCAR_DU_FEATURE_INTERLACED
316 | RCAR_DU_FEATURE_TVM_SYNC,
317 .channels_mask = BIT(1) | BIT(0),
320 * R8A7794 has two RGB outputs and one (currently unsupported)
323 [RCAR_DU_OUTPUT_DPAD0] = {
324 .possible_crtcs = BIT(0),
327 [RCAR_DU_OUTPUT_DPAD1] = {
328 .possible_crtcs = BIT(1),
334 static const struct rcar_du_device_info rcar_du_r8a7795_info = {
336 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
337 | RCAR_DU_FEATURE_VSP1_SOURCE
338 | RCAR_DU_FEATURE_INTERLACED
339 | RCAR_DU_FEATURE_TVM_SYNC,
340 .channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
343 * R8A7795 has one RGB output, two HDMI outputs and one
346 [RCAR_DU_OUTPUT_DPAD0] = {
347 .possible_crtcs = BIT(3),
350 [RCAR_DU_OUTPUT_HDMI0] = {
351 .possible_crtcs = BIT(1),
354 [RCAR_DU_OUTPUT_HDMI1] = {
355 .possible_crtcs = BIT(2),
358 [RCAR_DU_OUTPUT_LVDS0] = {
359 .possible_crtcs = BIT(0),
364 .dpll_mask = BIT(2) | BIT(1),
367 static const struct rcar_du_device_info rcar_du_r8a7796_info = {
369 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
370 | RCAR_DU_FEATURE_VSP1_SOURCE
371 | RCAR_DU_FEATURE_INTERLACED
372 | RCAR_DU_FEATURE_TVM_SYNC,
373 .channels_mask = BIT(2) | BIT(1) | BIT(0),
376 * R8A7796 has one RGB output, one LVDS output and one HDMI
379 [RCAR_DU_OUTPUT_DPAD0] = {
380 .possible_crtcs = BIT(2),
383 [RCAR_DU_OUTPUT_HDMI0] = {
384 .possible_crtcs = BIT(1),
387 [RCAR_DU_OUTPUT_LVDS0] = {
388 .possible_crtcs = BIT(0),
396 static const struct rcar_du_device_info rcar_du_r8a77965_info = {
398 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
399 | RCAR_DU_FEATURE_VSP1_SOURCE
400 | RCAR_DU_FEATURE_INTERLACED
401 | RCAR_DU_FEATURE_TVM_SYNC,
402 .channels_mask = BIT(3) | BIT(1) | BIT(0),
405 * R8A77965 has one RGB output, one LVDS output and one HDMI
408 [RCAR_DU_OUTPUT_DPAD0] = {
409 .possible_crtcs = BIT(2),
412 [RCAR_DU_OUTPUT_HDMI0] = {
413 .possible_crtcs = BIT(1),
416 [RCAR_DU_OUTPUT_LVDS0] = {
417 .possible_crtcs = BIT(0),
425 static const struct rcar_du_device_info rcar_du_r8a77970_info = {
427 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
428 | RCAR_DU_FEATURE_VSP1_SOURCE
429 | RCAR_DU_FEATURE_INTERLACED
430 | RCAR_DU_FEATURE_TVM_SYNC,
431 .channels_mask = BIT(0),
434 * R8A77970 and R8A77980 have one RGB output and one LVDS
437 [RCAR_DU_OUTPUT_DPAD0] = {
438 .possible_crtcs = BIT(0),
441 [RCAR_DU_OUTPUT_LVDS0] = {
442 .possible_crtcs = BIT(0),
449 static const struct rcar_du_device_info rcar_du_r8a7799x_info = {
451 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
452 | RCAR_DU_FEATURE_VSP1_SOURCE,
453 .channels_mask = BIT(1) | BIT(0),
456 * R8A77990 and R8A77995 have one RGB output and two LVDS
459 [RCAR_DU_OUTPUT_DPAD0] = {
460 .possible_crtcs = BIT(0) | BIT(1),
463 [RCAR_DU_OUTPUT_LVDS0] = {
464 .possible_crtcs = BIT(0),
467 [RCAR_DU_OUTPUT_LVDS1] = {
468 .possible_crtcs = BIT(1),
473 .lvds_clk_mask = BIT(1) | BIT(0),
476 static const struct of_device_id rcar_du_of_table[] = {
477 { .compatible = "renesas,du-r8a7742", .data = &rcar_du_r8a7790_info },
478 { .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
479 { .compatible = "renesas,du-r8a7744", .data = &rzg1_du_r8a7743_info },
480 { .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info },
481 { .compatible = "renesas,du-r8a77470", .data = &rzg1_du_r8a77470_info },
482 { .compatible = "renesas,du-r8a774a1", .data = &rcar_du_r8a774a1_info },
483 { .compatible = "renesas,du-r8a774b1", .data = &rcar_du_r8a774b1_info },
484 { .compatible = "renesas,du-r8a774c0", .data = &rcar_du_r8a774c0_info },
485 { .compatible = "renesas,du-r8a774e1", .data = &rcar_du_r8a774e1_info },
486 { .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info },
487 { .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info },
488 { .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info },
489 { .compatible = "renesas,du-r8a7792", .data = &rcar_du_r8a7792_info },
490 { .compatible = "renesas,du-r8a7793", .data = &rcar_du_r8a7791_info },
491 { .compatible = "renesas,du-r8a7794", .data = &rcar_du_r8a7794_info },
492 { .compatible = "renesas,du-r8a7795", .data = &rcar_du_r8a7795_info },
493 { .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info },
494 { .compatible = "renesas,du-r8a77961", .data = &rcar_du_r8a7796_info },
495 { .compatible = "renesas,du-r8a77965", .data = &rcar_du_r8a77965_info },
496 { .compatible = "renesas,du-r8a77970", .data = &rcar_du_r8a77970_info },
497 { .compatible = "renesas,du-r8a77980", .data = &rcar_du_r8a77970_info },
498 { .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info },
499 { .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info },
503 MODULE_DEVICE_TABLE(of, rcar_du_of_table);
505 /* -----------------------------------------------------------------------------
509 DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops);
511 static const struct drm_driver rcar_du_driver = {
512 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
513 DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(rcar_du_dumb_create),
514 .fops = &rcar_du_fops,
516 .desc = "Renesas R-Car Display Unit",
522 /* -----------------------------------------------------------------------------
526 #ifdef CONFIG_PM_SLEEP
527 static int rcar_du_pm_suspend(struct device *dev)
529 struct rcar_du_device *rcdu = dev_get_drvdata(dev);
531 return drm_mode_config_helper_suspend(&rcdu->ddev);
534 static int rcar_du_pm_resume(struct device *dev)
536 struct rcar_du_device *rcdu = dev_get_drvdata(dev);
538 return drm_mode_config_helper_resume(&rcdu->ddev);
542 static const struct dev_pm_ops rcar_du_pm_ops = {
543 SET_SYSTEM_SLEEP_PM_OPS(rcar_du_pm_suspend, rcar_du_pm_resume)
546 /* -----------------------------------------------------------------------------
550 static int rcar_du_remove(struct platform_device *pdev)
552 struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
553 struct drm_device *ddev = &rcdu->ddev;
555 drm_dev_unregister(ddev);
557 drm_kms_helper_poll_fini(ddev);
564 static int rcar_du_probe(struct platform_device *pdev)
566 struct rcar_du_device *rcdu;
567 struct resource *mem;
570 /* Allocate and initialize the R-Car device structure. */
571 rcdu = devm_drm_dev_alloc(&pdev->dev, &rcar_du_driver,
572 struct rcar_du_device, ddev);
574 return PTR_ERR(rcdu);
576 rcdu->dev = &pdev->dev;
577 rcdu->info = of_device_get_match_data(rcdu->dev);
579 platform_set_drvdata(pdev, rcdu);
582 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
583 rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
584 if (IS_ERR(rcdu->mmio))
585 return PTR_ERR(rcdu->mmio);
587 /* DRM/KMS objects */
588 ret = rcar_du_modeset_init(rcdu);
590 if (ret != -EPROBE_DEFER)
592 "failed to initialize DRM/KMS (%d)\n", ret);
596 rcdu->ddev.irq_enabled = 1;
599 * Register the DRM device with the core and the connectors with
602 ret = drm_dev_register(&rcdu->ddev, 0);
606 DRM_INFO("Device %s probed\n", dev_name(&pdev->dev));
608 drm_fbdev_generic_setup(&rcdu->ddev, 32);
613 drm_kms_helper_poll_fini(&rcdu->ddev);
617 static struct platform_driver rcar_du_platform_driver = {
618 .probe = rcar_du_probe,
619 .remove = rcar_du_remove,
622 .pm = &rcar_du_pm_ops,
623 .of_match_table = rcar_du_of_table,
627 static int __init rcar_du_init(void)
629 rcar_du_of_init(rcar_du_of_table);
631 return platform_driver_register(&rcar_du_platform_driver);
633 module_init(rcar_du_init);
635 static void __exit rcar_du_exit(void)
637 platform_driver_unregister(&rcar_du_platform_driver);
639 module_exit(rcar_du_exit);
642 MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver");
643 MODULE_LICENSE("GPL");