aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2015-01-20 19:16:24 -0500
committerDave Airlie <airlied@redhat.com>2015-01-20 19:16:24 -0500
commitb2eb0489809cf0b824357b6fa85aab1aabe3f063 (patch)
treed6b4bf3f4bd2f63f00bbcb9afdf2c39f396504b5
parent4f4d89af78682f2ed1cf6745794804817f867bba (diff)
parent906eff7fcada4186cde54eb89572fb774ab294a0 (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.txt4
-rw-r--r--drivers/gpu/drm/i2c/adv7511.c3
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c95
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.h1
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c6
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_encoder.c34
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_group.c21
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c18
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.c15
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.c20
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_regs.h5
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_vgacon.c1
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
30Required nodes: 34Required 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
87error_group:
88 clk_disable_unprepare(rcrtc->extclock);
89error_clock:
90 clk_disable_unprepare(rcrtc->clock);
81 return ret; 91 return ret;
82} 92}
83 93
84static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc) 94static 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
90static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) 102static 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)
217static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) 259static 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
58static const struct rcar_du_device_info rcar_du_r8a7790_info = { 58static 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
85static const struct rcar_du_device_info rcar_du_r8a7791_info = { 86static 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;
27struct rcar_du_lvdsenc; 27struct 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
226done:
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
25struct rcar_du_hdmienc { 26struct 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);