diff options
author | Dave Airlie <airlied@redhat.com> | 2015-01-20 19:16:24 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2015-01-20 19:16:24 -0500 |
commit | b2eb0489809cf0b824357b6fa85aab1aabe3f063 (patch) | |
tree | d6b4bf3f4bd2f63f00bbcb9afdf2c39f396504b5 | |
parent | 4f4d89af78682f2ed1cf6745794804817f867bba (diff) | |
parent | 906eff7fcada4186cde54eb89572fb774ab294a0 (diff) |
Merge branch 'drm/next/du' of git://linuxtv.org/pinchartl/fbdev into drm-next
* 'drm/next/du' of git://linuxtv.org/pinchartl/fbdev:
drm: rcar-du: Implement support for interlaced modes
drm: rcar-du: Clamp DPMS states to on and off
drm: rcar-du: Enable hotplug detection on HDMI connector
drm: rcar-du: Output HSYNC instead of CSYNC
drm: rcar-du: Add support for external pixel clock
drm: rcar-du: Refactor DEFR8 feature
drm: rcar-du: Remove LVDS and HDMI encoders chaining restriction
drm: rcar-du: Configure pitch for chroma plane of multiplanar formats
drm: rcar-du: Don't fail probe in case of partial encoder init error
drm: adv7511: Remove interlaced mode check
-rw-r--r-- | Documentation/devicetree/bindings/video/renesas,du.txt | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i2c/adv7511.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 95 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_drv.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_encoder.c | 34 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_group.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_kms.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_plane.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_regs.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_vgacon.c | 1 |
14 files changed, 180 insertions, 47 deletions
diff --git a/Documentation/devicetree/bindings/video/renesas,du.txt b/Documentation/devicetree/bindings/video/renesas,du.txt index 5102830f2760..c902323928f7 100644 --- a/Documentation/devicetree/bindings/video/renesas,du.txt +++ b/Documentation/devicetree/bindings/video/renesas,du.txt | |||
@@ -26,6 +26,10 @@ Required Properties: | |||
26 | per LVDS encoder. The functional clocks must be named "du.x" with "x" | 26 | per LVDS encoder. The functional clocks must be named "du.x" with "x" |
27 | being the channel numerical index. The LVDS clocks must be named | 27 | being the channel numerical index. The LVDS clocks must be named |
28 | "lvds.x" with "x" being the LVDS encoder numerical index. | 28 | "lvds.x" with "x" being the LVDS encoder numerical index. |
29 | - In addition to the functional and encoder clocks, all DU versions also | ||
30 | support externally supplied pixel clocks. Those clocks are optional. | ||
31 | When supplied they must be named "dclkin.x" with "x" being the input | ||
32 | clock numerical index. | ||
29 | 33 | ||
30 | Required nodes: | 34 | Required nodes: |
31 | 35 | ||
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c index faf1c0c5ab2e..fa140e04d5fa 100644 --- a/drivers/gpu/drm/i2c/adv7511.c +++ b/drivers/gpu/drm/i2c/adv7511.c | |||
@@ -644,9 +644,6 @@ static int adv7511_encoder_mode_valid(struct drm_encoder *encoder, | |||
644 | if (mode->clock > 165000) | 644 | if (mode->clock > 165000) |
645 | return MODE_CLOCK_HIGH; | 645 | return MODE_CLOCK_HIGH; |
646 | 646 | ||
647 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | ||
648 | return MODE_NO_INTERLACE; | ||
649 | |||
650 | return MODE_OK; | 647 | return MODE_OK; |
651 | } | 648 | } |
652 | 649 | ||
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 23cc910951f4..25c7a998fc2c 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c | |||
@@ -74,39 +74,77 @@ static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc) | |||
74 | if (ret < 0) | 74 | if (ret < 0) |
75 | return ret; | 75 | return ret; |
76 | 76 | ||
77 | ret = clk_prepare_enable(rcrtc->extclock); | ||
78 | if (ret < 0) | ||
79 | goto error_clock; | ||
80 | |||
77 | ret = rcar_du_group_get(rcrtc->group); | 81 | ret = rcar_du_group_get(rcrtc->group); |
78 | if (ret < 0) | 82 | if (ret < 0) |
79 | clk_disable_unprepare(rcrtc->clock); | 83 | goto error_group; |
84 | |||
85 | return 0; | ||
80 | 86 | ||
87 | error_group: | ||
88 | clk_disable_unprepare(rcrtc->extclock); | ||
89 | error_clock: | ||
90 | clk_disable_unprepare(rcrtc->clock); | ||
81 | return ret; | 91 | return ret; |
82 | } | 92 | } |
83 | 93 | ||
84 | static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc) | 94 | static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc) |
85 | { | 95 | { |
86 | rcar_du_group_put(rcrtc->group); | 96 | rcar_du_group_put(rcrtc->group); |
97 | |||
98 | clk_disable_unprepare(rcrtc->extclock); | ||
87 | clk_disable_unprepare(rcrtc->clock); | 99 | clk_disable_unprepare(rcrtc->clock); |
88 | } | 100 | } |
89 | 101 | ||
90 | static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) | 102 | static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) |
91 | { | 103 | { |
92 | const struct drm_display_mode *mode = &rcrtc->crtc.mode; | 104 | const struct drm_display_mode *mode = &rcrtc->crtc.mode; |
105 | unsigned long mode_clock = mode->clock * 1000; | ||
93 | unsigned long clk; | 106 | unsigned long clk; |
94 | u32 value; | 107 | u32 value; |
108 | u32 escr; | ||
95 | u32 div; | 109 | u32 div; |
96 | 110 | ||
97 | /* Dot clock */ | 111 | /* Compute the clock divisor and select the internal or external dot |
112 | * clock based on the requested frequency. | ||
113 | */ | ||
98 | clk = clk_get_rate(rcrtc->clock); | 114 | clk = clk_get_rate(rcrtc->clock); |
99 | div = DIV_ROUND_CLOSEST(clk, mode->clock * 1000); | 115 | div = DIV_ROUND_CLOSEST(clk, mode_clock); |
100 | div = clamp(div, 1U, 64U) - 1; | 116 | div = clamp(div, 1U, 64U) - 1; |
117 | escr = div | ESCR_DCLKSEL_CLKS; | ||
118 | |||
119 | if (rcrtc->extclock) { | ||
120 | unsigned long extclk; | ||
121 | unsigned long extrate; | ||
122 | unsigned long rate; | ||
123 | u32 extdiv; | ||
124 | |||
125 | extclk = clk_get_rate(rcrtc->extclock); | ||
126 | extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock); | ||
127 | extdiv = clamp(extdiv, 1U, 64U) - 1; | ||
128 | |||
129 | rate = clk / (div + 1); | ||
130 | extrate = extclk / (extdiv + 1); | ||
131 | |||
132 | if (abs((long)extrate - (long)mode_clock) < | ||
133 | abs((long)rate - (long)mode_clock)) { | ||
134 | dev_dbg(rcrtc->group->dev->dev, | ||
135 | "crtc%u: using external clock\n", rcrtc->index); | ||
136 | escr = extdiv | ESCR_DCLKSEL_DCLKIN; | ||
137 | } | ||
138 | } | ||
101 | 139 | ||
102 | rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR, | 140 | rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR, |
103 | ESCR_DCLKSEL_CLKS | div); | 141 | escr); |
104 | rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0); | 142 | rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0); |
105 | 143 | ||
106 | /* Signal polarities */ | 144 | /* Signal polarities */ |
107 | value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL) | 145 | value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL) |
108 | | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL) | 146 | | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL) |
109 | | DSMR_DIPM_DE; | 147 | | DSMR_DIPM_DE | DSMR_CSPM; |
110 | rcar_du_crtc_write(rcrtc, DSMR, value); | 148 | rcar_du_crtc_write(rcrtc, DSMR, value); |
111 | 149 | ||
112 | /* Display timings */ | 150 | /* Display timings */ |
@@ -117,12 +155,15 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) | |||
117 | mode->hsync_start - 1); | 155 | mode->hsync_start - 1); |
118 | rcar_du_crtc_write(rcrtc, HCR, mode->htotal - 1); | 156 | rcar_du_crtc_write(rcrtc, HCR, mode->htotal - 1); |
119 | 157 | ||
120 | rcar_du_crtc_write(rcrtc, VDSR, mode->vtotal - mode->vsync_end - 2); | 158 | rcar_du_crtc_write(rcrtc, VDSR, mode->crtc_vtotal - |
121 | rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end + | 159 | mode->crtc_vsync_end - 2); |
122 | mode->vdisplay - 2); | 160 | rcar_du_crtc_write(rcrtc, VDER, mode->crtc_vtotal - |
123 | rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end + | 161 | mode->crtc_vsync_end + |
124 | mode->vsync_start - 1); | 162 | mode->crtc_vdisplay - 2); |
125 | rcar_du_crtc_write(rcrtc, VCR, mode->vtotal - 1); | 163 | rcar_du_crtc_write(rcrtc, VSPR, mode->crtc_vtotal - |
164 | mode->crtc_vsync_end + | ||
165 | mode->crtc_vsync_start - 1); | ||
166 | rcar_du_crtc_write(rcrtc, VCR, mode->crtc_vtotal - 1); | ||
126 | 167 | ||
127 | rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start); | 168 | rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start); |
128 | rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay); | 169 | rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay); |
@@ -139,9 +180,10 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc, | |||
139 | */ | 180 | */ |
140 | rcrtc->outputs |= BIT(output); | 181 | rcrtc->outputs |= BIT(output); |
141 | 182 | ||
142 | /* Store RGB routing to DPAD0 for R8A7790. */ | 183 | /* Store RGB routing to DPAD0, the hardware will be configured when |
143 | if (rcar_du_has(rcdu, RCAR_DU_FEATURE_DEFR8) && | 184 | * starting the CRTC. |
144 | output == RCAR_DU_OUTPUT_DPAD0) | 185 | */ |
186 | if (output == RCAR_DU_OUTPUT_DPAD0) | ||
145 | rcdu->dpad0_source = rcrtc->index; | 187 | rcdu->dpad0_source = rcrtc->index; |
146 | } | 188 | } |
147 | 189 | ||
@@ -217,6 +259,7 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc) | |||
217 | static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) | 259 | static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) |
218 | { | 260 | { |
219 | struct drm_crtc *crtc = &rcrtc->crtc; | 261 | struct drm_crtc *crtc = &rcrtc->crtc; |
262 | bool interlaced; | ||
220 | unsigned int i; | 263 | unsigned int i; |
221 | 264 | ||
222 | if (rcrtc->started) | 265 | if (rcrtc->started) |
@@ -252,7 +295,10 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) | |||
252 | * sync mode (with the HSYNC and VSYNC signals configured as outputs and | 295 | * sync mode (with the HSYNC and VSYNC signals configured as outputs and |
253 | * actively driven). | 296 | * actively driven). |
254 | */ | 297 | */ |
255 | rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_MASTER); | 298 | interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE; |
299 | rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_SCM_MASK, | ||
300 | (interlaced ? DSYSR_SCM_INT_VIDEO : 0) | | ||
301 | DSYSR_TVM_MASTER); | ||
256 | 302 | ||
257 | rcar_du_group_start_stop(rcrtc->group, true); | 303 | rcar_du_group_start_stop(rcrtc->group, true); |
258 | 304 | ||
@@ -308,6 +354,9 @@ static void rcar_du_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
308 | { | 354 | { |
309 | struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); | 355 | struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); |
310 | 356 | ||
357 | if (mode != DRM_MODE_DPMS_ON) | ||
358 | mode = DRM_MODE_DPMS_OFF; | ||
359 | |||
311 | if (rcrtc->dpms == mode) | 360 | if (rcrtc->dpms == mode) |
312 | return; | 361 | return; |
313 | 362 | ||
@@ -486,7 +535,7 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg) | |||
486 | status = rcar_du_crtc_read(rcrtc, DSSR); | 535 | status = rcar_du_crtc_read(rcrtc, DSSR); |
487 | rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK); | 536 | rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK); |
488 | 537 | ||
489 | if (status & DSSR_VBK) { | 538 | if (status & DSSR_FRM) { |
490 | drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index); | 539 | drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index); |
491 | rcar_du_crtc_finish_page_flip(rcrtc); | 540 | rcar_du_crtc_finish_page_flip(rcrtc); |
492 | ret = IRQ_HANDLED; | 541 | ret = IRQ_HANDLED; |
@@ -542,12 +591,13 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) | |||
542 | struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index]; | 591 | struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index]; |
543 | struct drm_crtc *crtc = &rcrtc->crtc; | 592 | struct drm_crtc *crtc = &rcrtc->crtc; |
544 | unsigned int irqflags; | 593 | unsigned int irqflags; |
545 | char clk_name[5]; | 594 | struct clk *clk; |
595 | char clk_name[9]; | ||
546 | char *name; | 596 | char *name; |
547 | int irq; | 597 | int irq; |
548 | int ret; | 598 | int ret; |
549 | 599 | ||
550 | /* Get the CRTC clock. */ | 600 | /* Get the CRTC clock and the optional external clock. */ |
551 | if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ_CLOCK)) { | 601 | if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ_CLOCK)) { |
552 | sprintf(clk_name, "du.%u", index); | 602 | sprintf(clk_name, "du.%u", index); |
553 | name = clk_name; | 603 | name = clk_name; |
@@ -561,6 +611,15 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) | |||
561 | return PTR_ERR(rcrtc->clock); | 611 | return PTR_ERR(rcrtc->clock); |
562 | } | 612 | } |
563 | 613 | ||
614 | sprintf(clk_name, "dclkin.%u", index); | ||
615 | clk = devm_clk_get(rcdu->dev, clk_name); | ||
616 | if (!IS_ERR(clk)) { | ||
617 | rcrtc->extclock = clk; | ||
618 | } else if (PTR_ERR(rcrtc->clock) == -EPROBE_DEFER) { | ||
619 | dev_info(rcdu->dev, "can't get external clock %u\n", index); | ||
620 | return -EPROBE_DEFER; | ||
621 | } | ||
622 | |||
564 | rcrtc->group = rgrp; | 623 | rcrtc->group = rgrp; |
565 | rcrtc->mmio_offset = mmio_offsets[index]; | 624 | rcrtc->mmio_offset = mmio_offsets[index]; |
566 | rcrtc->index = index; | 625 | rcrtc->index = index; |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 984e6083699f..d2f89f7d2e5e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h | |||
@@ -26,6 +26,7 @@ struct rcar_du_crtc { | |||
26 | struct drm_crtc crtc; | 26 | struct drm_crtc crtc; |
27 | 27 | ||
28 | struct clk *clock; | 28 | struct clk *clock; |
29 | struct clk *extclock; | ||
29 | unsigned int mmio_offset; | 30 | unsigned int mmio_offset; |
30 | unsigned int index; | 31 | unsigned int index; |
31 | bool started; | 32 | bool started; |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 7bfa09cf18d5..e0d74f821416 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c | |||
@@ -56,7 +56,8 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = { | |||
56 | }; | 56 | }; |
57 | 57 | ||
58 | static const struct rcar_du_device_info rcar_du_r8a7790_info = { | 58 | static const struct rcar_du_device_info rcar_du_r8a7790_info = { |
59 | .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8, | 59 | .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK |
60 | | RCAR_DU_FEATURE_EXT_CTRL_REGS, | ||
60 | .quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES, | 61 | .quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES, |
61 | .num_crtcs = 3, | 62 | .num_crtcs = 3, |
62 | .routes = { | 63 | .routes = { |
@@ -83,7 +84,8 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = { | |||
83 | }; | 84 | }; |
84 | 85 | ||
85 | static const struct rcar_du_device_info rcar_du_r8a7791_info = { | 86 | static const struct rcar_du_device_info rcar_du_r8a7791_info = { |
86 | .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8, | 87 | .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK |
88 | | RCAR_DU_FEATURE_EXT_CTRL_REGS, | ||
87 | .num_crtcs = 2, | 89 | .num_crtcs = 2, |
88 | .routes = { | 90 | .routes = { |
89 | /* R8A7791 has one RGB output, one LVDS output and one | 91 | /* R8A7791 has one RGB output, one LVDS output and one |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 0a724669f02d..c5b9ea6a7eaa 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h | |||
@@ -27,7 +27,7 @@ struct rcar_du_device; | |||
27 | struct rcar_du_lvdsenc; | 27 | struct rcar_du_lvdsenc; |
28 | 28 | ||
29 | #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */ | 29 | #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */ |
30 | #define RCAR_DU_FEATURE_DEFR8 (1 << 1) /* Has DEFR8 register */ | 30 | #define RCAR_DU_FEATURE_EXT_CTRL_REGS (1 << 1) /* Has extended control registers */ |
31 | 31 | ||
32 | #define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes */ | 32 | #define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes */ |
33 | #define RCAR_DU_QUIRK_LVDS_LANES (1 << 1) /* LVDS lanes 1 and 3 inverted */ | 33 | #define RCAR_DU_QUIRK_LVDS_LANES (1 << 1) /* LVDS lanes 1 and 3 inverted */ |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c index 34a122a39664..279167f783f6 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c | |||
@@ -46,6 +46,9 @@ static void rcar_du_encoder_dpms(struct drm_encoder *encoder, int mode) | |||
46 | { | 46 | { |
47 | struct rcar_du_encoder *renc = to_rcar_encoder(encoder); | 47 | struct rcar_du_encoder *renc = to_rcar_encoder(encoder); |
48 | 48 | ||
49 | if (mode != DRM_MODE_DPMS_ON) | ||
50 | mode = DRM_MODE_DPMS_OFF; | ||
51 | |||
49 | if (renc->lvds) | 52 | if (renc->lvds) |
50 | rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, mode); | 53 | rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, mode); |
51 | } | 54 | } |
@@ -190,35 +193,42 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, | |||
190 | } | 193 | } |
191 | 194 | ||
192 | if (type == RCAR_DU_ENCODER_HDMI) { | 195 | if (type == RCAR_DU_ENCODER_HDMI) { |
193 | if (renc->lvds) { | ||
194 | dev_err(rcdu->dev, | ||
195 | "Chaining LVDS and HDMI encoders not supported\n"); | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | |||
199 | ret = rcar_du_hdmienc_init(rcdu, renc, enc_node); | 196 | ret = rcar_du_hdmienc_init(rcdu, renc, enc_node); |
200 | if (ret < 0) | 197 | if (ret < 0) |
201 | return ret; | 198 | goto done; |
202 | } else { | 199 | } else { |
203 | ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs, | 200 | ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs, |
204 | encoder_type); | 201 | encoder_type); |
205 | if (ret < 0) | 202 | if (ret < 0) |
206 | return ret; | 203 | goto done; |
207 | 204 | ||
208 | drm_encoder_helper_add(encoder, &encoder_helper_funcs); | 205 | drm_encoder_helper_add(encoder, &encoder_helper_funcs); |
209 | } | 206 | } |
210 | 207 | ||
211 | switch (encoder_type) { | 208 | switch (encoder_type) { |
212 | case DRM_MODE_ENCODER_LVDS: | 209 | case DRM_MODE_ENCODER_LVDS: |
213 | return rcar_du_lvds_connector_init(rcdu, renc, con_node); | 210 | ret = rcar_du_lvds_connector_init(rcdu, renc, con_node); |
211 | break; | ||
214 | 212 | ||
215 | case DRM_MODE_ENCODER_DAC: | 213 | case DRM_MODE_ENCODER_DAC: |
216 | return rcar_du_vga_connector_init(rcdu, renc); | 214 | ret = rcar_du_vga_connector_init(rcdu, renc); |
215 | break; | ||
217 | 216 | ||
218 | case DRM_MODE_ENCODER_TMDS: | 217 | case DRM_MODE_ENCODER_TMDS: |
219 | return rcar_du_hdmi_connector_init(rcdu, renc); | 218 | ret = rcar_du_hdmi_connector_init(rcdu, renc); |
219 | break; | ||
220 | 220 | ||
221 | default: | 221 | default: |
222 | return -EINVAL; | 222 | ret = -EINVAL; |
223 | break; | ||
223 | } | 224 | } |
225 | |||
226 | done: | ||
227 | if (ret < 0) { | ||
228 | if (encoder->name) | ||
229 | encoder->funcs->destroy(encoder); | ||
230 | devm_kfree(rcdu->dev, renc); | ||
231 | } | ||
232 | |||
233 | return ret; | ||
224 | } | 234 | } |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index 4e7614b145db..1bdc0ee0c248 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c | |||
@@ -48,9 +48,6 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp) | |||
48 | { | 48 | { |
49 | u32 defr8 = DEFR8_CODE | DEFR8_DEFE8; | 49 | u32 defr8 = DEFR8_CODE | DEFR8_DEFE8; |
50 | 50 | ||
51 | if (!rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_DEFR8)) | ||
52 | return; | ||
53 | |||
54 | /* The DEFR8 register for the first group also controls RGB output | 51 | /* The DEFR8 register for the first group also controls RGB output |
55 | * routing to DPAD0 | 52 | * routing to DPAD0 |
56 | */ | 53 | */ |
@@ -69,7 +66,20 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp) | |||
69 | rcar_du_group_write(rgrp, DEFR4, DEFR4_CODE); | 66 | rcar_du_group_write(rgrp, DEFR4, DEFR4_CODE); |
70 | rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5); | 67 | rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5); |
71 | 68 | ||
72 | rcar_du_group_setup_defr8(rgrp); | 69 | if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) { |
70 | rcar_du_group_setup_defr8(rgrp); | ||
71 | |||
72 | /* Configure input dot clock routing. We currently hardcode the | ||
73 | * configuration to routing DOTCLKINn to DUn. | ||
74 | */ | ||
75 | rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE | | ||
76 | DIDSR_LCDS_DCLKIN(2) | | ||
77 | DIDSR_LCDS_DCLKIN(1) | | ||
78 | DIDSR_LCDS_DCLKIN(0) | | ||
79 | DIDSR_PDCS_CLK(2, 0) | | ||
80 | DIDSR_PDCS_CLK(1, 0) | | ||
81 | DIDSR_PDCS_CLK(0, 0)); | ||
82 | } | ||
73 | 83 | ||
74 | /* Use DS1PR and DS2PR to configure planes priorities and connects the | 84 | /* Use DS1PR and DS2PR to configure planes priorities and connects the |
75 | * superposition 0 to DU0 pins. DU1 pins will be configured dynamically. | 85 | * superposition 0 to DU0 pins. DU1 pins will be configured dynamically. |
@@ -149,6 +159,9 @@ static int rcar_du_set_dpad0_routing(struct rcar_du_device *rcdu) | |||
149 | { | 159 | { |
150 | int ret; | 160 | int ret; |
151 | 161 | ||
162 | if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_EXT_CTRL_REGS)) | ||
163 | return 0; | ||
164 | |||
152 | /* RGB output routing to DPAD0 is configured in the DEFR8 register of | 165 | /* RGB output routing to DPAD0 is configured in the DEFR8 register of |
153 | * the first group. As this function can be called with the DU0 and DU1 | 166 | * the first group. As this function can be called with the DU0 and DU1 |
154 | * CRTCs disabled, we need to enable the first group clock before | 167 | * CRTCs disabled, we need to enable the first group clock before |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c index 4d7d4dd46d26..ca94b029ac80 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c | |||
@@ -95,6 +95,8 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu, | |||
95 | connector = &rcon->connector; | 95 | connector = &rcon->connector; |
96 | connector->display_info.width_mm = 0; | 96 | connector->display_info.width_mm = 0; |
97 | connector->display_info.height_mm = 0; | 97 | connector->display_info.height_mm = 0; |
98 | connector->interlace_allowed = true; | ||
99 | connector->polled = DRM_CONNECTOR_POLL_HPD; | ||
98 | 100 | ||
99 | ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, | 101 | ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, |
100 | DRM_MODE_CONNECTOR_HDMIA); | 102 | DRM_MODE_CONNECTOR_HDMIA); |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c index 359bc999a9c8..221f0a17fd6a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include "rcar_du_drv.h" | 21 | #include "rcar_du_drv.h" |
22 | #include "rcar_du_encoder.h" | 22 | #include "rcar_du_encoder.h" |
23 | #include "rcar_du_hdmienc.h" | 23 | #include "rcar_du_hdmienc.h" |
24 | #include "rcar_du_lvdsenc.h" | ||
24 | 25 | ||
25 | struct rcar_du_hdmienc { | 26 | struct rcar_du_hdmienc { |
26 | struct rcar_du_encoder *renc; | 27 | struct rcar_du_encoder *renc; |
@@ -36,12 +37,21 @@ static void rcar_du_hdmienc_dpms(struct drm_encoder *encoder, int mode) | |||
36 | struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); | 37 | struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); |
37 | struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); | 38 | struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); |
38 | 39 | ||
40 | if (mode != DRM_MODE_DPMS_ON) | ||
41 | mode = DRM_MODE_DPMS_OFF; | ||
42 | |||
39 | if (hdmienc->dpms == mode) | 43 | if (hdmienc->dpms == mode) |
40 | return; | 44 | return; |
41 | 45 | ||
46 | if (mode == DRM_MODE_DPMS_ON && hdmienc->renc->lvds) | ||
47 | rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode); | ||
48 | |||
42 | if (sfuncs->dpms) | 49 | if (sfuncs->dpms) |
43 | sfuncs->dpms(encoder, mode); | 50 | sfuncs->dpms(encoder, mode); |
44 | 51 | ||
52 | if (mode != DRM_MODE_DPMS_ON && hdmienc->renc->lvds) | ||
53 | rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode); | ||
54 | |||
45 | hdmienc->dpms = mode; | 55 | hdmienc->dpms = mode; |
46 | } | 56 | } |
47 | 57 | ||
@@ -49,8 +59,16 @@ static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder *encoder, | |||
49 | const struct drm_display_mode *mode, | 59 | const struct drm_display_mode *mode, |
50 | struct drm_display_mode *adjusted_mode) | 60 | struct drm_display_mode *adjusted_mode) |
51 | { | 61 | { |
62 | struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); | ||
52 | struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); | 63 | struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); |
53 | 64 | ||
65 | /* The internal LVDS encoder has a clock frequency operating range of | ||
66 | * 30MHz to 150MHz. Clamp the clock accordingly. | ||
67 | */ | ||
68 | if (hdmienc->renc->lvds) | ||
69 | adjusted_mode->clock = clamp(adjusted_mode->clock, | ||
70 | 30000, 150000); | ||
71 | |||
54 | if (sfuncs->mode_fixup == NULL) | 72 | if (sfuncs->mode_fixup == NULL) |
55 | return true; | 73 | return true; |
56 | 74 | ||
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 0c5ee616b5a3..cc9136e8ee9c 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c | |||
@@ -346,8 +346,14 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu) | |||
346 | /* Process the output pipeline. */ | 346 | /* Process the output pipeline. */ |
347 | ret = rcar_du_encoders_init_one(rcdu, output, &ep); | 347 | ret = rcar_du_encoders_init_one(rcdu, output, &ep); |
348 | if (ret < 0) { | 348 | if (ret < 0) { |
349 | of_node_put(ep_node); | 349 | if (ret == -EPROBE_DEFER) { |
350 | return ret; | 350 | of_node_put(ep_node); |
351 | return ret; | ||
352 | } | ||
353 | |||
354 | dev_info(rcdu->dev, | ||
355 | "encoder initialization failed, skipping\n"); | ||
356 | continue; | ||
351 | } | 357 | } |
352 | 358 | ||
353 | num_encoders += ret; | 359 | num_encoders += ret; |
@@ -413,6 +419,11 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) | |||
413 | if (ret < 0) | 419 | if (ret < 0) |
414 | return ret; | 420 | return ret; |
415 | 421 | ||
422 | if (ret == 0) { | ||
423 | dev_err(rcdu->dev, "error: no encoder could be initialized\n"); | ||
424 | return -EINVAL; | ||
425 | } | ||
426 | |||
416 | num_encoders = ret; | 427 | num_encoders = ret; |
417 | 428 | ||
418 | /* Set the possible CRTCs and possible clones. There's always at least | 429 | /* Set the possible CRTCs and possible clones. There's always at least |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 72a7cb47bd9f..50f2f2b20d39 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c | |||
@@ -104,14 +104,22 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane) | |||
104 | { | 104 | { |
105 | struct rcar_du_group *rgrp = plane->group; | 105 | struct rcar_du_group *rgrp = plane->group; |
106 | unsigned int index = plane->hwindex; | 106 | unsigned int index = plane->hwindex; |
107 | bool interlaced; | ||
107 | u32 mwr; | 108 | u32 mwr; |
108 | 109 | ||
109 | /* Memory pitch (expressed in pixels) */ | 110 | interlaced = plane->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE; |
111 | |||
112 | /* Memory pitch (expressed in pixels). Must be doubled for interlaced | ||
113 | * operation with 32bpp formats. | ||
114 | */ | ||
110 | if (plane->format->planes == 2) | 115 | if (plane->format->planes == 2) |
111 | mwr = plane->pitch; | 116 | mwr = plane->pitch; |
112 | else | 117 | else |
113 | mwr = plane->pitch * 8 / plane->format->bpp; | 118 | mwr = plane->pitch * 8 / plane->format->bpp; |
114 | 119 | ||
120 | if (interlaced && plane->format->bpp == 32) | ||
121 | mwr *= 2; | ||
122 | |||
115 | rcar_du_plane_write(rgrp, index, PnMWR, mwr); | 123 | rcar_du_plane_write(rgrp, index, PnMWR, mwr); |
116 | 124 | ||
117 | /* The Y position is expressed in raster line units and must be doubled | 125 | /* The Y position is expressed in raster line units and must be doubled |
@@ -119,17 +127,23 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane) | |||
119 | * doubling the Y position is found in the R8A7779 datasheet, but the | 127 | * doubling the Y position is found in the R8A7779 datasheet, but the |
120 | * rule seems to apply there as well. | 128 | * rule seems to apply there as well. |
121 | * | 129 | * |
130 | * Despite not being documented, doubling seem not to be needed when | ||
131 | * operating in interlaced mode. | ||
132 | * | ||
122 | * Similarly, for the second plane, NV12 and NV21 formats seem to | 133 | * Similarly, for the second plane, NV12 and NV21 formats seem to |
123 | * require a halved Y position value. | 134 | * require a halved Y position value, in both progressive and interlaced |
135 | * modes. | ||
124 | */ | 136 | */ |
125 | rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x); | 137 | rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x); |
126 | rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y * | 138 | rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y * |
127 | (plane->format->bpp == 32 ? 2 : 1)); | 139 | (!interlaced && plane->format->bpp == 32 ? 2 : 1)); |
128 | rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[0]); | 140 | rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[0]); |
129 | 141 | ||
130 | if (plane->format->planes == 2) { | 142 | if (plane->format->planes == 2) { |
131 | index = (index + 1) % 8; | 143 | index = (index + 1) % 8; |
132 | 144 | ||
145 | rcar_du_plane_write(rgrp, index, PnMWR, plane->pitch); | ||
146 | |||
133 | rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x); | 147 | rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x); |
134 | rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y * | 148 | rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y * |
135 | (plane->format->bpp == 16 ? 2 : 1) / 2); | 149 | (plane->format->bpp == 16 ? 2 : 1) / 2); |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h index 73f7347f740b..70fcbc471ebd 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h | |||
@@ -34,6 +34,7 @@ | |||
34 | #define DSYSR_SCM_INT_NONE (0 << 4) | 34 | #define DSYSR_SCM_INT_NONE (0 << 4) |
35 | #define DSYSR_SCM_INT_SYNC (2 << 4) | 35 | #define DSYSR_SCM_INT_SYNC (2 << 4) |
36 | #define DSYSR_SCM_INT_VIDEO (3 << 4) | 36 | #define DSYSR_SCM_INT_VIDEO (3 << 4) |
37 | #define DSYSR_SCM_MASK (3 << 4) | ||
37 | 38 | ||
38 | #define DSMR 0x00004 | 39 | #define DSMR 0x00004 |
39 | #define DSMR_VSPM (1 << 28) | 40 | #define DSMR_VSPM (1 << 28) |
@@ -256,8 +257,8 @@ | |||
256 | #define DIDSR_LCDS_LVDS0(n) (2 << (8 + (n) * 2)) | 257 | #define DIDSR_LCDS_LVDS0(n) (2 << (8 + (n) * 2)) |
257 | #define DIDSR_LCDS_LVDS1(n) (3 << (8 + (n) * 2)) | 258 | #define DIDSR_LCDS_LVDS1(n) (3 << (8 + (n) * 2)) |
258 | #define DIDSR_LCDS_MASK(n) (3 << (8 + (n) * 2)) | 259 | #define DIDSR_LCDS_MASK(n) (3 << (8 + (n) * 2)) |
259 | #define DIDSR_PCDS_CLK(n, clk) (clk << ((n) * 2)) | 260 | #define DIDSR_PDCS_CLK(n, clk) (clk << ((n) * 2)) |
260 | #define DIDSR_PCDS_MASK(n) (3 << ((n) * 2)) | 261 | #define DIDSR_PDCS_MASK(n) (3 << ((n) * 2)) |
261 | 262 | ||
262 | /* ----------------------------------------------------------------------------- | 263 | /* ----------------------------------------------------------------------------- |
263 | * Display Timing Generation Registers | 264 | * Display Timing Generation Registers |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c index 752747a5e920..9d4879921cc7 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c | |||
@@ -64,6 +64,7 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu, | |||
64 | connector = &rcon->connector; | 64 | connector = &rcon->connector; |
65 | connector->display_info.width_mm = 0; | 65 | connector->display_info.width_mm = 0; |
66 | connector->display_info.height_mm = 0; | 66 | connector->display_info.height_mm = 0; |
67 | connector->interlace_allowed = true; | ||
67 | 68 | ||
68 | ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, | 69 | ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, |
69 | DRM_MODE_CONNECTOR_VGA); | 70 | DRM_MODE_CONNECTOR_VGA); |