111696c5eSBiju Das // SPDX-License-Identifier: GPL-2.0+
211696c5eSBiju Das /*
311696c5eSBiju Das * R-Car Display Unit DRM driver
411696c5eSBiju Das *
511696c5eSBiju Das * Copyright (C) 2013-2015 Renesas Electronics Corporation
611696c5eSBiju Das *
711696c5eSBiju Das * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
811696c5eSBiju Das */
911696c5eSBiju Das
1011696c5eSBiju Das #include <linux/clk.h>
1111696c5eSBiju Das #include <linux/dma-mapping.h>
1211696c5eSBiju Das #include <linux/io.h>
1311696c5eSBiju Das #include <linux/mm.h>
1411696c5eSBiju Das #include <linux/module.h>
15722d4f06SRob Herring #include <linux/of.h>
1611696c5eSBiju Das #include <linux/platform_device.h>
1711696c5eSBiju Das #include <linux/pm.h>
1811696c5eSBiju Das #include <linux/slab.h>
1911696c5eSBiju Das #include <linux/wait.h>
2011696c5eSBiju Das
2111696c5eSBiju Das #include <drm/drm_atomic_helper.h>
2211696c5eSBiju Das #include <drm/drm_drv.h>
2311696c5eSBiju Das #include <drm/drm_fbdev_generic.h>
2411696c5eSBiju Das #include <drm/drm_gem_dma_helper.h>
2511696c5eSBiju Das #include <drm/drm_managed.h>
2611696c5eSBiju Das #include <drm/drm_probe_helper.h>
2711696c5eSBiju Das
2811696c5eSBiju Das #include "rcar_du_drv.h"
2911696c5eSBiju Das #include "rcar_du_kms.h"
3011696c5eSBiju Das
3111696c5eSBiju Das /* -----------------------------------------------------------------------------
3211696c5eSBiju Das * Device Information
3311696c5eSBiju Das */
3411696c5eSBiju Das
3511696c5eSBiju Das static const struct rcar_du_device_info rzg1_du_r8a7743_info = {
3611696c5eSBiju Das .gen = 2,
3711696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
3811696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
3911696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
4011696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
4111696c5eSBiju Das .channels_mask = BIT(1) | BIT(0),
4211696c5eSBiju Das .routes = {
4311696c5eSBiju Das /*
4411696c5eSBiju Das * R8A774[34] has one RGB output and one LVDS output
4511696c5eSBiju Das */
4611696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
4711696c5eSBiju Das .possible_crtcs = BIT(1) | BIT(0),
4811696c5eSBiju Das .port = 0,
4911696c5eSBiju Das },
5011696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = {
5111696c5eSBiju Das .possible_crtcs = BIT(0),
5211696c5eSBiju Das .port = 1,
5311696c5eSBiju Das },
5411696c5eSBiju Das },
5511696c5eSBiju Das .num_lvds = 1,
5611696c5eSBiju Das .num_rpf = 4,
5711696c5eSBiju Das };
5811696c5eSBiju Das
5911696c5eSBiju Das static const struct rcar_du_device_info rzg1_du_r8a7745_info = {
6011696c5eSBiju Das .gen = 2,
6111696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
6211696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
6311696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
6411696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
6511696c5eSBiju Das .channels_mask = BIT(1) | BIT(0),
6611696c5eSBiju Das .routes = {
6711696c5eSBiju Das /*
6811696c5eSBiju Das * R8A7745 has two RGB outputs
6911696c5eSBiju Das */
7011696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
7111696c5eSBiju Das .possible_crtcs = BIT(0),
7211696c5eSBiju Das .port = 0,
7311696c5eSBiju Das },
7411696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD1] = {
7511696c5eSBiju Das .possible_crtcs = BIT(1),
7611696c5eSBiju Das .port = 1,
7711696c5eSBiju Das },
7811696c5eSBiju Das },
7911696c5eSBiju Das .num_rpf = 4,
8011696c5eSBiju Das };
8111696c5eSBiju Das
8211696c5eSBiju Das static const struct rcar_du_device_info rzg1_du_r8a77470_info = {
8311696c5eSBiju Das .gen = 2,
8411696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
8511696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
8611696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
8711696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
8811696c5eSBiju Das .channels_mask = BIT(1) | BIT(0),
8911696c5eSBiju Das .routes = {
9011696c5eSBiju Das /*
9111696c5eSBiju Das * R8A77470 has two RGB outputs, one LVDS output, and
9211696c5eSBiju Das * one (currently unsupported) analog video output
9311696c5eSBiju Das */
9411696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
9511696c5eSBiju Das .possible_crtcs = BIT(0),
9611696c5eSBiju Das .port = 0,
9711696c5eSBiju Das },
9811696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD1] = {
9911696c5eSBiju Das .possible_crtcs = BIT(1),
10011696c5eSBiju Das .port = 1,
10111696c5eSBiju Das },
10211696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = {
10311696c5eSBiju Das .possible_crtcs = BIT(0) | BIT(1),
10411696c5eSBiju Das .port = 2,
10511696c5eSBiju Das },
10611696c5eSBiju Das },
10711696c5eSBiju Das .num_rpf = 4,
10811696c5eSBiju Das };
10911696c5eSBiju Das
11011696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a774a1_info = {
11111696c5eSBiju Das .gen = 3,
11211696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
11311696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
11411696c5eSBiju Das | RCAR_DU_FEATURE_VSP1_SOURCE
11511696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
11611696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
11711696c5eSBiju Das .channels_mask = BIT(2) | BIT(1) | BIT(0),
11811696c5eSBiju Das .routes = {
11911696c5eSBiju Das /*
12011696c5eSBiju Das * R8A774A1 has one RGB output, one LVDS output and one HDMI
12111696c5eSBiju Das * output.
12211696c5eSBiju Das */
12311696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
12411696c5eSBiju Das .possible_crtcs = BIT(2),
12511696c5eSBiju Das .port = 0,
12611696c5eSBiju Das },
12711696c5eSBiju Das [RCAR_DU_OUTPUT_HDMI0] = {
12811696c5eSBiju Das .possible_crtcs = BIT(1),
12911696c5eSBiju Das .port = 1,
13011696c5eSBiju Das },
13111696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = {
13211696c5eSBiju Das .possible_crtcs = BIT(0),
13311696c5eSBiju Das .port = 2,
13411696c5eSBiju Das },
13511696c5eSBiju Das },
13611696c5eSBiju Das .num_lvds = 1,
13711696c5eSBiju Das .num_rpf = 5,
13811696c5eSBiju Das .dpll_mask = BIT(1),
13911696c5eSBiju Das };
14011696c5eSBiju Das
14111696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a774b1_info = {
14211696c5eSBiju Das .gen = 3,
14311696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
14411696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
14511696c5eSBiju Das | RCAR_DU_FEATURE_VSP1_SOURCE
14611696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
14711696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
14811696c5eSBiju Das .channels_mask = BIT(3) | BIT(1) | BIT(0),
14911696c5eSBiju Das .routes = {
15011696c5eSBiju Das /*
15111696c5eSBiju Das * R8A774B1 has one RGB output, one LVDS output and one HDMI
15211696c5eSBiju Das * output.
15311696c5eSBiju Das */
15411696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
15511696c5eSBiju Das .possible_crtcs = BIT(2),
15611696c5eSBiju Das .port = 0,
15711696c5eSBiju Das },
15811696c5eSBiju Das [RCAR_DU_OUTPUT_HDMI0] = {
15911696c5eSBiju Das .possible_crtcs = BIT(1),
16011696c5eSBiju Das .port = 1,
16111696c5eSBiju Das },
16211696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = {
16311696c5eSBiju Das .possible_crtcs = BIT(0),
16411696c5eSBiju Das .port = 2,
16511696c5eSBiju Das },
16611696c5eSBiju Das },
16711696c5eSBiju Das .num_lvds = 1,
16811696c5eSBiju Das .num_rpf = 5,
16911696c5eSBiju Das .dpll_mask = BIT(1),
17011696c5eSBiju Das };
17111696c5eSBiju Das
17211696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a774c0_info = {
17311696c5eSBiju Das .gen = 3,
17411696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
17511696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
17611696c5eSBiju Das | RCAR_DU_FEATURE_VSP1_SOURCE,
17711696c5eSBiju Das .channels_mask = BIT(1) | BIT(0),
17811696c5eSBiju Das .routes = {
17911696c5eSBiju Das /*
18011696c5eSBiju Das * R8A774C0 has one RGB output and two LVDS outputs
18111696c5eSBiju Das */
18211696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
18311696c5eSBiju Das .possible_crtcs = BIT(0) | BIT(1),
18411696c5eSBiju Das .port = 0,
18511696c5eSBiju Das },
18611696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = {
18711696c5eSBiju Das .possible_crtcs = BIT(0),
18811696c5eSBiju Das .port = 1,
18911696c5eSBiju Das },
19011696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS1] = {
19111696c5eSBiju Das .possible_crtcs = BIT(1),
19211696c5eSBiju Das .port = 2,
19311696c5eSBiju Das },
19411696c5eSBiju Das },
19511696c5eSBiju Das .num_lvds = 2,
19611696c5eSBiju Das .num_rpf = 4,
19711696c5eSBiju Das .lvds_clk_mask = BIT(1) | BIT(0),
19811696c5eSBiju Das };
19911696c5eSBiju Das
20011696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a774e1_info = {
20111696c5eSBiju Das .gen = 3,
20211696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
20311696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
20411696c5eSBiju Das | RCAR_DU_FEATURE_VSP1_SOURCE
20511696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
20611696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
20711696c5eSBiju Das .channels_mask = BIT(3) | BIT(1) | BIT(0),
20811696c5eSBiju Das .routes = {
20911696c5eSBiju Das /*
21011696c5eSBiju Das * R8A774E1 has one RGB output, one LVDS output and one HDMI
21111696c5eSBiju Das * output.
21211696c5eSBiju Das */
21311696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
21411696c5eSBiju Das .possible_crtcs = BIT(2),
21511696c5eSBiju Das .port = 0,
21611696c5eSBiju Das },
21711696c5eSBiju Das [RCAR_DU_OUTPUT_HDMI0] = {
21811696c5eSBiju Das .possible_crtcs = BIT(1),
21911696c5eSBiju Das .port = 1,
22011696c5eSBiju Das },
22111696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = {
22211696c5eSBiju Das .possible_crtcs = BIT(0),
22311696c5eSBiju Das .port = 2,
22411696c5eSBiju Das },
22511696c5eSBiju Das },
22611696c5eSBiju Das .num_lvds = 1,
22711696c5eSBiju Das .num_rpf = 5,
22811696c5eSBiju Das .dpll_mask = BIT(1),
22911696c5eSBiju Das };
23011696c5eSBiju Das
23111696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a7779_info = {
23211696c5eSBiju Das .gen = 1,
23311696c5eSBiju Das .features = RCAR_DU_FEATURE_INTERLACED
23411696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
23511696c5eSBiju Das .channels_mask = BIT(1) | BIT(0),
23611696c5eSBiju Das .routes = {
23711696c5eSBiju Das /*
23811696c5eSBiju Das * R8A7779 has two RGB outputs and one (currently unsupported)
23911696c5eSBiju Das * TCON output.
24011696c5eSBiju Das */
24111696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
24211696c5eSBiju Das .possible_crtcs = BIT(0),
24311696c5eSBiju Das .port = 0,
24411696c5eSBiju Das },
24511696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD1] = {
24611696c5eSBiju Das .possible_crtcs = BIT(1) | BIT(0),
24711696c5eSBiju Das .port = 1,
24811696c5eSBiju Das },
24911696c5eSBiju Das },
25011696c5eSBiju Das };
25111696c5eSBiju Das
25211696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a7790_info = {
25311696c5eSBiju Das .gen = 2,
25411696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
25511696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
25611696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
25711696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
25811696c5eSBiju Das .quirks = RCAR_DU_QUIRK_ALIGN_128B,
25911696c5eSBiju Das .channels_mask = BIT(2) | BIT(1) | BIT(0),
26011696c5eSBiju Das .routes = {
26111696c5eSBiju Das /*
26211696c5eSBiju Das * R8A7742 and R8A7790 each have one RGB output and two LVDS
26311696c5eSBiju Das * outputs. Additionally R8A7790 supports one TCON output
26411696c5eSBiju Das * (currently unsupported by the driver).
26511696c5eSBiju Das */
26611696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
26711696c5eSBiju Das .possible_crtcs = BIT(2) | BIT(1) | BIT(0),
26811696c5eSBiju Das .port = 0,
26911696c5eSBiju Das },
27011696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = {
27111696c5eSBiju Das .possible_crtcs = BIT(0),
27211696c5eSBiju Das .port = 1,
27311696c5eSBiju Das },
27411696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS1] = {
27511696c5eSBiju Das .possible_crtcs = BIT(2) | BIT(1),
27611696c5eSBiju Das .port = 2,
27711696c5eSBiju Das },
27811696c5eSBiju Das },
27911696c5eSBiju Das .num_lvds = 2,
28011696c5eSBiju Das .num_rpf = 4,
28111696c5eSBiju Das };
28211696c5eSBiju Das
28311696c5eSBiju Das /* M2-W (r8a7791) and M2-N (r8a7793) are identical */
28411696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a7791_info = {
28511696c5eSBiju Das .gen = 2,
28611696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
28711696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
28811696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
28911696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
29011696c5eSBiju Das .channels_mask = BIT(1) | BIT(0),
29111696c5eSBiju Das .routes = {
29211696c5eSBiju Das /*
29311696c5eSBiju Das * R8A779[13] has one RGB output, one LVDS output and one
29411696c5eSBiju Das * (currently unsupported) TCON output.
29511696c5eSBiju Das */
29611696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
29711696c5eSBiju Das .possible_crtcs = BIT(1) | BIT(0),
29811696c5eSBiju Das .port = 0,
29911696c5eSBiju Das },
30011696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = {
30111696c5eSBiju Das .possible_crtcs = BIT(0),
30211696c5eSBiju Das .port = 1,
30311696c5eSBiju Das },
30411696c5eSBiju Das },
30511696c5eSBiju Das .num_lvds = 1,
30611696c5eSBiju Das .num_rpf = 4,
30711696c5eSBiju Das };
30811696c5eSBiju Das
30911696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a7792_info = {
31011696c5eSBiju Das .gen = 2,
31111696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
31211696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
31311696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
31411696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
31511696c5eSBiju Das .channels_mask = BIT(1) | BIT(0),
31611696c5eSBiju Das .routes = {
31711696c5eSBiju Das /* R8A7792 has two RGB outputs. */
31811696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
31911696c5eSBiju Das .possible_crtcs = BIT(0),
32011696c5eSBiju Das .port = 0,
32111696c5eSBiju Das },
32211696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD1] = {
32311696c5eSBiju Das .possible_crtcs = BIT(1),
32411696c5eSBiju Das .port = 1,
32511696c5eSBiju Das },
32611696c5eSBiju Das },
32711696c5eSBiju Das .num_rpf = 4,
32811696c5eSBiju Das };
32911696c5eSBiju Das
33011696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a7794_info = {
33111696c5eSBiju Das .gen = 2,
33211696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
33311696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
33411696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
33511696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
33611696c5eSBiju Das .channels_mask = BIT(1) | BIT(0),
33711696c5eSBiju Das .routes = {
33811696c5eSBiju Das /*
33911696c5eSBiju Das * R8A7794 has two RGB outputs and one (currently unsupported)
34011696c5eSBiju Das * TCON output.
34111696c5eSBiju Das */
34211696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
34311696c5eSBiju Das .possible_crtcs = BIT(0),
34411696c5eSBiju Das .port = 0,
34511696c5eSBiju Das },
34611696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD1] = {
34711696c5eSBiju Das .possible_crtcs = BIT(1),
34811696c5eSBiju Das .port = 1,
34911696c5eSBiju Das },
35011696c5eSBiju Das },
35111696c5eSBiju Das .num_rpf = 4,
35211696c5eSBiju Das };
35311696c5eSBiju Das
35411696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a7795_info = {
35511696c5eSBiju Das .gen = 3,
35611696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
35711696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
35811696c5eSBiju Das | RCAR_DU_FEATURE_VSP1_SOURCE
35911696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
36011696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
36111696c5eSBiju Das .channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
36211696c5eSBiju Das .routes = {
36311696c5eSBiju Das /*
36411696c5eSBiju Das * R8A7795 has one RGB output, two HDMI outputs and one
36511696c5eSBiju Das * LVDS output.
36611696c5eSBiju Das */
36711696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
36811696c5eSBiju Das .possible_crtcs = BIT(3),
36911696c5eSBiju Das .port = 0,
37011696c5eSBiju Das },
37111696c5eSBiju Das [RCAR_DU_OUTPUT_HDMI0] = {
37211696c5eSBiju Das .possible_crtcs = BIT(1),
37311696c5eSBiju Das .port = 1,
37411696c5eSBiju Das },
37511696c5eSBiju Das [RCAR_DU_OUTPUT_HDMI1] = {
37611696c5eSBiju Das .possible_crtcs = BIT(2),
37711696c5eSBiju Das .port = 2,
37811696c5eSBiju Das },
37911696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = {
38011696c5eSBiju Das .possible_crtcs = BIT(0),
38111696c5eSBiju Das .port = 3,
38211696c5eSBiju Das },
38311696c5eSBiju Das },
38411696c5eSBiju Das .num_lvds = 1,
38511696c5eSBiju Das .num_rpf = 5,
38611696c5eSBiju Das .dpll_mask = BIT(2) | BIT(1),
38711696c5eSBiju Das };
38811696c5eSBiju Das
38911696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a7796_info = {
39011696c5eSBiju Das .gen = 3,
39111696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
39211696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
39311696c5eSBiju Das | RCAR_DU_FEATURE_VSP1_SOURCE
39411696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
39511696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
39611696c5eSBiju Das .channels_mask = BIT(2) | BIT(1) | BIT(0),
39711696c5eSBiju Das .routes = {
39811696c5eSBiju Das /*
39911696c5eSBiju Das * R8A7796 has one RGB output, one LVDS output and one HDMI
40011696c5eSBiju Das * output.
40111696c5eSBiju Das */
40211696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
40311696c5eSBiju Das .possible_crtcs = BIT(2),
40411696c5eSBiju Das .port = 0,
40511696c5eSBiju Das },
40611696c5eSBiju Das [RCAR_DU_OUTPUT_HDMI0] = {
40711696c5eSBiju Das .possible_crtcs = BIT(1),
40811696c5eSBiju Das .port = 1,
40911696c5eSBiju Das },
41011696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = {
41111696c5eSBiju Das .possible_crtcs = BIT(0),
41211696c5eSBiju Das .port = 2,
41311696c5eSBiju Das },
41411696c5eSBiju Das },
41511696c5eSBiju Das .num_lvds = 1,
41611696c5eSBiju Das .num_rpf = 5,
41711696c5eSBiju Das .dpll_mask = BIT(1),
41811696c5eSBiju Das };
41911696c5eSBiju Das
42011696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a77965_info = {
42111696c5eSBiju Das .gen = 3,
42211696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
42311696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
42411696c5eSBiju Das | RCAR_DU_FEATURE_VSP1_SOURCE
42511696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
42611696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
42711696c5eSBiju Das .channels_mask = BIT(3) | BIT(1) | BIT(0),
42811696c5eSBiju Das .routes = {
42911696c5eSBiju Das /*
43011696c5eSBiju Das * R8A77965 has one RGB output, one LVDS output and one HDMI
43111696c5eSBiju Das * output.
43211696c5eSBiju Das */
43311696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
43411696c5eSBiju Das .possible_crtcs = BIT(2),
43511696c5eSBiju Das .port = 0,
43611696c5eSBiju Das },
43711696c5eSBiju Das [RCAR_DU_OUTPUT_HDMI0] = {
43811696c5eSBiju Das .possible_crtcs = BIT(1),
43911696c5eSBiju Das .port = 1,
44011696c5eSBiju Das },
44111696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = {
44211696c5eSBiju Das .possible_crtcs = BIT(0),
44311696c5eSBiju Das .port = 2,
44411696c5eSBiju Das },
44511696c5eSBiju Das },
44611696c5eSBiju Das .num_lvds = 1,
44711696c5eSBiju Das .num_rpf = 5,
44811696c5eSBiju Das .dpll_mask = BIT(1),
44911696c5eSBiju Das };
45011696c5eSBiju Das
45111696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a77970_info = {
45211696c5eSBiju Das .gen = 3,
45311696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
45411696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
45511696c5eSBiju Das | RCAR_DU_FEATURE_VSP1_SOURCE
45611696c5eSBiju Das | RCAR_DU_FEATURE_INTERLACED
45711696c5eSBiju Das | RCAR_DU_FEATURE_TVM_SYNC,
45811696c5eSBiju Das .channels_mask = BIT(0),
45911696c5eSBiju Das .routes = {
46011696c5eSBiju Das /*
46111696c5eSBiju Das * R8A77970 and R8A77980 have one RGB output and one LVDS
46211696c5eSBiju Das * output.
46311696c5eSBiju Das */
46411696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
46511696c5eSBiju Das .possible_crtcs = BIT(0),
46611696c5eSBiju Das .port = 0,
46711696c5eSBiju Das },
46811696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = {
46911696c5eSBiju Das .possible_crtcs = BIT(0),
47011696c5eSBiju Das .port = 1,
47111696c5eSBiju Das },
47211696c5eSBiju Das },
47311696c5eSBiju Das .num_lvds = 1,
47411696c5eSBiju Das .num_rpf = 5,
47511696c5eSBiju Das };
47611696c5eSBiju Das
47711696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a7799x_info = {
47811696c5eSBiju Das .gen = 3,
47911696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
48011696c5eSBiju Das | RCAR_DU_FEATURE_CRTC_CLOCK
48111696c5eSBiju Das | RCAR_DU_FEATURE_VSP1_SOURCE,
48211696c5eSBiju Das .channels_mask = BIT(1) | BIT(0),
48311696c5eSBiju Das .routes = {
48411696c5eSBiju Das /*
48511696c5eSBiju Das * R8A77990 and R8A77995 have one RGB output and two LVDS
48611696c5eSBiju Das * outputs.
48711696c5eSBiju Das */
48811696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = {
48911696c5eSBiju Das .possible_crtcs = BIT(0) | BIT(1),
49011696c5eSBiju Das .port = 0,
49111696c5eSBiju Das },
49211696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = {
49311696c5eSBiju Das .possible_crtcs = BIT(0),
49411696c5eSBiju Das .port = 1,
49511696c5eSBiju Das },
49611696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS1] = {
49711696c5eSBiju Das .possible_crtcs = BIT(1),
49811696c5eSBiju Das .port = 2,
49911696c5eSBiju Das },
50011696c5eSBiju Das },
50111696c5eSBiju Das .num_lvds = 2,
50211696c5eSBiju Das .num_rpf = 5,
50311696c5eSBiju Das .lvds_clk_mask = BIT(1) | BIT(0),
50411696c5eSBiju Das };
50511696c5eSBiju Das
50611696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a779a0_info = {
50711696c5eSBiju Das .gen = 4,
50811696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
50911696c5eSBiju Das | RCAR_DU_FEATURE_VSP1_SOURCE
51011696c5eSBiju Das | RCAR_DU_FEATURE_NO_BLENDING,
51111696c5eSBiju Das .channels_mask = BIT(1) | BIT(0),
51211696c5eSBiju Das .routes = {
51311696c5eSBiju Das /* R8A779A0 has two MIPI DSI outputs. */
51411696c5eSBiju Das [RCAR_DU_OUTPUT_DSI0] = {
51511696c5eSBiju Das .possible_crtcs = BIT(0),
51611696c5eSBiju Das .port = 0,
51711696c5eSBiju Das },
51811696c5eSBiju Das [RCAR_DU_OUTPUT_DSI1] = {
51911696c5eSBiju Das .possible_crtcs = BIT(1),
52011696c5eSBiju Das .port = 1,
52111696c5eSBiju Das },
52211696c5eSBiju Das },
52311696c5eSBiju Das .num_rpf = 5,
52411696c5eSBiju Das .dsi_clk_mask = BIT(1) | BIT(0),
52511696c5eSBiju Das };
52611696c5eSBiju Das
52711696c5eSBiju Das static const struct rcar_du_device_info rcar_du_r8a779g0_info = {
52811696c5eSBiju Das .gen = 4,
52911696c5eSBiju Das .features = RCAR_DU_FEATURE_CRTC_IRQ
53011696c5eSBiju Das | RCAR_DU_FEATURE_VSP1_SOURCE
53111696c5eSBiju Das | RCAR_DU_FEATURE_NO_BLENDING,
53211696c5eSBiju Das .channels_mask = BIT(1) | BIT(0),
53311696c5eSBiju Das .routes = {
53411696c5eSBiju Das /* R8A779G0 has two MIPI DSI outputs. */
53511696c5eSBiju Das [RCAR_DU_OUTPUT_DSI0] = {
53611696c5eSBiju Das .possible_crtcs = BIT(0),
53711696c5eSBiju Das .port = 0,
53811696c5eSBiju Das },
53911696c5eSBiju Das [RCAR_DU_OUTPUT_DSI1] = {
54011696c5eSBiju Das .possible_crtcs = BIT(1),
54111696c5eSBiju Das .port = 1,
54211696c5eSBiju Das },
54311696c5eSBiju Das },
54411696c5eSBiju Das .num_rpf = 5,
54511696c5eSBiju Das .dsi_clk_mask = BIT(1) | BIT(0),
54611696c5eSBiju Das };
54711696c5eSBiju Das
54811696c5eSBiju Das static const struct of_device_id rcar_du_of_table[] = {
54911696c5eSBiju Das { .compatible = "renesas,du-r8a7742", .data = &rcar_du_r8a7790_info },
55011696c5eSBiju Das { .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
55111696c5eSBiju Das { .compatible = "renesas,du-r8a7744", .data = &rzg1_du_r8a7743_info },
55211696c5eSBiju Das { .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info },
55311696c5eSBiju Das { .compatible = "renesas,du-r8a77470", .data = &rzg1_du_r8a77470_info },
55411696c5eSBiju Das { .compatible = "renesas,du-r8a774a1", .data = &rcar_du_r8a774a1_info },
55511696c5eSBiju Das { .compatible = "renesas,du-r8a774b1", .data = &rcar_du_r8a774b1_info },
55611696c5eSBiju Das { .compatible = "renesas,du-r8a774c0", .data = &rcar_du_r8a774c0_info },
55711696c5eSBiju Das { .compatible = "renesas,du-r8a774e1", .data = &rcar_du_r8a774e1_info },
55811696c5eSBiju Das { .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info },
55911696c5eSBiju Das { .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info },
56011696c5eSBiju Das { .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info },
56111696c5eSBiju Das { .compatible = "renesas,du-r8a7792", .data = &rcar_du_r8a7792_info },
56211696c5eSBiju Das { .compatible = "renesas,du-r8a7793", .data = &rcar_du_r8a7791_info },
56311696c5eSBiju Das { .compatible = "renesas,du-r8a7794", .data = &rcar_du_r8a7794_info },
56411696c5eSBiju Das { .compatible = "renesas,du-r8a7795", .data = &rcar_du_r8a7795_info },
56511696c5eSBiju Das { .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info },
56611696c5eSBiju Das { .compatible = "renesas,du-r8a77961", .data = &rcar_du_r8a7796_info },
56711696c5eSBiju Das { .compatible = "renesas,du-r8a77965", .data = &rcar_du_r8a77965_info },
56811696c5eSBiju Das { .compatible = "renesas,du-r8a77970", .data = &rcar_du_r8a77970_info },
56911696c5eSBiju Das { .compatible = "renesas,du-r8a77980", .data = &rcar_du_r8a77970_info },
57011696c5eSBiju Das { .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info },
57111696c5eSBiju Das { .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info },
57211696c5eSBiju Das { .compatible = "renesas,du-r8a779a0", .data = &rcar_du_r8a779a0_info },
57311696c5eSBiju Das { .compatible = "renesas,du-r8a779g0", .data = &rcar_du_r8a779g0_info },
57411696c5eSBiju Das { }
57511696c5eSBiju Das };
57611696c5eSBiju Das
57711696c5eSBiju Das MODULE_DEVICE_TABLE(of, rcar_du_of_table);
57811696c5eSBiju Das
rcar_du_output_name(enum rcar_du_output output)57911696c5eSBiju Das const char *rcar_du_output_name(enum rcar_du_output output)
58011696c5eSBiju Das {
58111696c5eSBiju Das static const char * const names[] = {
58211696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD0] = "DPAD0",
58311696c5eSBiju Das [RCAR_DU_OUTPUT_DPAD1] = "DPAD1",
58411696c5eSBiju Das [RCAR_DU_OUTPUT_DSI0] = "DSI0",
58511696c5eSBiju Das [RCAR_DU_OUTPUT_DSI1] = "DSI1",
58611696c5eSBiju Das [RCAR_DU_OUTPUT_HDMI0] = "HDMI0",
58711696c5eSBiju Das [RCAR_DU_OUTPUT_HDMI1] = "HDMI1",
58811696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS0] = "LVDS0",
58911696c5eSBiju Das [RCAR_DU_OUTPUT_LVDS1] = "LVDS1",
59011696c5eSBiju Das [RCAR_DU_OUTPUT_TCON] = "TCON",
59111696c5eSBiju Das };
59211696c5eSBiju Das
59311696c5eSBiju Das if (output >= ARRAY_SIZE(names) || !names[output])
59411696c5eSBiju Das return "UNKNOWN";
59511696c5eSBiju Das
59611696c5eSBiju Das return names[output];
59711696c5eSBiju Das }
59811696c5eSBiju Das
59911696c5eSBiju Das /* -----------------------------------------------------------------------------
60011696c5eSBiju Das * DRM operations
60111696c5eSBiju Das */
60211696c5eSBiju Das
60311696c5eSBiju Das DEFINE_DRM_GEM_DMA_FOPS(rcar_du_fops);
60411696c5eSBiju Das
60511696c5eSBiju Das static const struct drm_driver rcar_du_driver = {
60611696c5eSBiju Das .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
60711696c5eSBiju Das .dumb_create = rcar_du_dumb_create,
60811696c5eSBiju Das .gem_prime_import_sg_table = rcar_du_gem_prime_import_sg_table,
60911696c5eSBiju Das .fops = &rcar_du_fops,
61011696c5eSBiju Das .name = "rcar-du",
61111696c5eSBiju Das .desc = "Renesas R-Car Display Unit",
61211696c5eSBiju Das .date = "20130110",
61311696c5eSBiju Das .major = 1,
61411696c5eSBiju Das .minor = 0,
61511696c5eSBiju Das };
61611696c5eSBiju Das
61711696c5eSBiju Das /* -----------------------------------------------------------------------------
61811696c5eSBiju Das * Power management
61911696c5eSBiju Das */
62011696c5eSBiju Das
rcar_du_pm_suspend(struct device * dev)62111696c5eSBiju Das static int rcar_du_pm_suspend(struct device *dev)
62211696c5eSBiju Das {
62311696c5eSBiju Das struct rcar_du_device *rcdu = dev_get_drvdata(dev);
62411696c5eSBiju Das
62511696c5eSBiju Das return drm_mode_config_helper_suspend(&rcdu->ddev);
62611696c5eSBiju Das }
62711696c5eSBiju Das
rcar_du_pm_resume(struct device * dev)62811696c5eSBiju Das static int rcar_du_pm_resume(struct device *dev)
62911696c5eSBiju Das {
63011696c5eSBiju Das struct rcar_du_device *rcdu = dev_get_drvdata(dev);
63111696c5eSBiju Das
63211696c5eSBiju Das return drm_mode_config_helper_resume(&rcdu->ddev);
63311696c5eSBiju Das }
63411696c5eSBiju Das
63511696c5eSBiju Das static DEFINE_SIMPLE_DEV_PM_OPS(rcar_du_pm_ops,
63611696c5eSBiju Das rcar_du_pm_suspend, rcar_du_pm_resume);
63711696c5eSBiju Das
63811696c5eSBiju Das /* -----------------------------------------------------------------------------
63911696c5eSBiju Das * Platform driver
64011696c5eSBiju Das */
64111696c5eSBiju Das
rcar_du_remove(struct platform_device * pdev)642de8a334fSThomas Zimmermann static void rcar_du_remove(struct platform_device *pdev)
64311696c5eSBiju Das {
64411696c5eSBiju Das struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
64511696c5eSBiju Das struct drm_device *ddev = &rcdu->ddev;
64611696c5eSBiju Das
64711696c5eSBiju Das drm_dev_unregister(ddev);
64811696c5eSBiju Das drm_atomic_helper_shutdown(ddev);
64911696c5eSBiju Das
65011696c5eSBiju Das drm_kms_helper_poll_fini(ddev);
65111696c5eSBiju Das }
65211696c5eSBiju Das
rcar_du_shutdown(struct platform_device * pdev)65311696c5eSBiju Das static void rcar_du_shutdown(struct platform_device *pdev)
65411696c5eSBiju Das {
65511696c5eSBiju Das struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
65611696c5eSBiju Das
65711696c5eSBiju Das drm_atomic_helper_shutdown(&rcdu->ddev);
65811696c5eSBiju Das }
65911696c5eSBiju Das
rcar_du_probe(struct platform_device * pdev)66011696c5eSBiju Das static int rcar_du_probe(struct platform_device *pdev)
66111696c5eSBiju Das {
66211696c5eSBiju Das struct rcar_du_device *rcdu;
66311696c5eSBiju Das unsigned int mask;
66411696c5eSBiju Das int ret;
66511696c5eSBiju Das
66611696c5eSBiju Das if (drm_firmware_drivers_only())
66711696c5eSBiju Das return -ENODEV;
66811696c5eSBiju Das
66911696c5eSBiju Das /* Allocate and initialize the R-Car device structure. */
67011696c5eSBiju Das rcdu = devm_drm_dev_alloc(&pdev->dev, &rcar_du_driver,
67111696c5eSBiju Das struct rcar_du_device, ddev);
67211696c5eSBiju Das if (IS_ERR(rcdu))
67311696c5eSBiju Das return PTR_ERR(rcdu);
67411696c5eSBiju Das
67511696c5eSBiju Das rcdu->dev = &pdev->dev;
67611696c5eSBiju Das
67711696c5eSBiju Das rcdu->info = of_device_get_match_data(rcdu->dev);
67811696c5eSBiju Das
67911696c5eSBiju Das platform_set_drvdata(pdev, rcdu);
68011696c5eSBiju Das
68111696c5eSBiju Das /* I/O resources */
68211696c5eSBiju Das rcdu->mmio = devm_platform_ioremap_resource(pdev, 0);
68311696c5eSBiju Das if (IS_ERR(rcdu->mmio))
68411696c5eSBiju Das return PTR_ERR(rcdu->mmio);
68511696c5eSBiju Das
68611696c5eSBiju Das /*
68711696c5eSBiju Das * Set the DMA coherent mask to reflect the DU 32-bit DMA address space
68811696c5eSBiju Das * limitations. When sourcing frames from a VSP the DU doesn't perform
68911696c5eSBiju Das * any memory access so set the mask to 40 bits to accept all buffers.
69011696c5eSBiju Das */
69111696c5eSBiju Das mask = rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE) ? 40 : 32;
69211696c5eSBiju Das ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(mask));
69311696c5eSBiju Das if (ret)
69411696c5eSBiju Das return ret;
69511696c5eSBiju Das
69611696c5eSBiju Das /* DRM/KMS objects */
69711696c5eSBiju Das ret = rcar_du_modeset_init(rcdu);
69811696c5eSBiju Das if (ret < 0) {
699*f3651bc0SLaurent Pinchart /*
700*f3651bc0SLaurent Pinchart * Don't use dev_err_probe(), as it would overwrite the probe
701*f3651bc0SLaurent Pinchart * deferral reason recorded in rcar_du_modeset_init().
702*f3651bc0SLaurent Pinchart */
70311696c5eSBiju Das if (ret != -EPROBE_DEFER)
70411696c5eSBiju Das dev_err(&pdev->dev,
70511696c5eSBiju Das "failed to initialize DRM/KMS (%d)\n", ret);
70611696c5eSBiju Das goto error;
70711696c5eSBiju Das }
70811696c5eSBiju Das
70911696c5eSBiju Das /*
71011696c5eSBiju Das * Register the DRM device with the core and the connectors with
71111696c5eSBiju Das * sysfs.
71211696c5eSBiju Das */
71311696c5eSBiju Das ret = drm_dev_register(&rcdu->ddev, 0);
71411696c5eSBiju Das if (ret)
71511696c5eSBiju Das goto error;
71611696c5eSBiju Das
717c58dcab0SLaurent Pinchart drm_info(&rcdu->ddev, "Device %s probed\n", dev_name(&pdev->dev));
71811696c5eSBiju Das
71911696c5eSBiju Das drm_fbdev_generic_setup(&rcdu->ddev, 32);
72011696c5eSBiju Das
72111696c5eSBiju Das return 0;
72211696c5eSBiju Das
72311696c5eSBiju Das error:
72411696c5eSBiju Das drm_kms_helper_poll_fini(&rcdu->ddev);
72511696c5eSBiju Das return ret;
72611696c5eSBiju Das }
72711696c5eSBiju Das
72811696c5eSBiju Das static struct platform_driver rcar_du_platform_driver = {
72911696c5eSBiju Das .probe = rcar_du_probe,
730de8a334fSThomas Zimmermann .remove_new = rcar_du_remove,
73111696c5eSBiju Das .shutdown = rcar_du_shutdown,
73211696c5eSBiju Das .driver = {
73311696c5eSBiju Das .name = "rcar-du",
73411696c5eSBiju Das .pm = pm_sleep_ptr(&rcar_du_pm_ops),
73511696c5eSBiju Das .of_match_table = rcar_du_of_table,
73611696c5eSBiju Das },
73711696c5eSBiju Das };
73811696c5eSBiju Das
73911696c5eSBiju Das module_platform_driver(rcar_du_platform_driver);
74011696c5eSBiju Das
74111696c5eSBiju Das MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
74211696c5eSBiju Das MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver");
74311696c5eSBiju Das MODULE_LICENSE("GPL");
744