aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2016-09-28 20:30:25 -0400
committerEric Anholt <eric@anholt.net>2016-10-06 14:58:27 -0400
commit682e62c45406ccf81216481be59c2f7ca5a883d4 (patch)
treef8a37357784f3008869cfbff0ac84ea980fd696d
parent2b29bf16611a1aabb310406dd171dce6e6d51322 (diff)
drm/vc4: Fix support for interlaced modes on HDMI.
We really do need to be using the halved V fields. I had been confused by the code I was using as a reference because it stored halved vsync fields but not halved vdisplay, so it looked like I only needed to divide vdisplay by 2. This reverts part of Mario's timestamping fixes that prevented CRTC_HALVE_V from applying, and instead adjusts the timestamping code to not use the crtc field in that case. Fixes locking of 1920x1080x60i on my Dell 2408WFP. There are black bars on the top and bottom, but I suspect that might be an under/overscan flags problem as opposed to video timings. Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c49
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c45
-rw-r--r--drivers/gpu/drm/vc4/vc4_regs.h3
3 files changed, 41 insertions, 56 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 2682f07d8f1e..83cafea03eff 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -229,7 +229,7 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
229 * and need to make things up in a approximative but consistent way. 229 * and need to make things up in a approximative but consistent way.
230 */ 230 */
231 ret |= DRM_SCANOUTPOS_IN_VBLANK; 231 ret |= DRM_SCANOUTPOS_IN_VBLANK;
232 vblank_lines = mode->crtc_vtotal - mode->crtc_vdisplay; 232 vblank_lines = mode->vtotal - mode->vdisplay;
233 233
234 if (flags & DRM_CALLED_FROM_VBLIRQ) { 234 if (flags & DRM_CALLED_FROM_VBLIRQ) {
235 /* 235 /*
@@ -378,7 +378,6 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
378 struct drm_crtc_state *state = crtc->state; 378 struct drm_crtc_state *state = crtc->state;
379 struct drm_display_mode *mode = &state->adjusted_mode; 379 struct drm_display_mode *mode = &state->adjusted_mode;
380 bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; 380 bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
381 u32 vactive = (mode->vdisplay >> (interlace ? 1 : 0));
382 u32 format = PV_CONTROL_FORMAT_24; 381 u32 format = PV_CONTROL_FORMAT_24;
383 bool debug_dump_regs = false; 382 bool debug_dump_regs = false;
384 int clock_select = vc4_get_clock_select(crtc); 383 int clock_select = vc4_get_clock_select(crtc);
@@ -404,32 +403,46 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
404 VC4_SET_FIELD(mode->hdisplay, PV_HORZB_HACTIVE)); 403 VC4_SET_FIELD(mode->hdisplay, PV_HORZB_HACTIVE));
405 404
406 CRTC_WRITE(PV_VERTA, 405 CRTC_WRITE(PV_VERTA,
407 VC4_SET_FIELD(mode->vtotal - mode->vsync_end, 406 VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
408 PV_VERTA_VBP) | 407 PV_VERTA_VBP) |
409 VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, 408 VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
410 PV_VERTA_VSYNC)); 409 PV_VERTA_VSYNC));
411 CRTC_WRITE(PV_VERTB, 410 CRTC_WRITE(PV_VERTB,
412 VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, 411 VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
413 PV_VERTB_VFP) | 412 PV_VERTB_VFP) |
414 VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE)); 413 VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
415 414
416 if (interlace) { 415 if (interlace) {
417 CRTC_WRITE(PV_VERTA_EVEN, 416 CRTC_WRITE(PV_VERTA_EVEN,
418 VC4_SET_FIELD(mode->vtotal - mode->vsync_end - 1, 417 VC4_SET_FIELD(mode->crtc_vtotal -
418 mode->crtc_vsync_end - 1,
419 PV_VERTA_VBP) | 419 PV_VERTA_VBP) |
420 VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, 420 VC4_SET_FIELD(mode->crtc_vsync_end -
421 mode->crtc_vsync_start,
421 PV_VERTA_VSYNC)); 422 PV_VERTA_VSYNC));
422 CRTC_WRITE(PV_VERTB_EVEN, 423 CRTC_WRITE(PV_VERTB_EVEN,
423 VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, 424 VC4_SET_FIELD(mode->crtc_vsync_start -
425 mode->crtc_vdisplay,
424 PV_VERTB_VFP) | 426 PV_VERTB_VFP) |
425 VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE)); 427 VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
428
429 /* We set up first field even mode for HDMI. VEC's
430 * NTSC mode would want first field odd instead, once
431 * we support it (to do so, set ODD_FIRST and put the
432 * delay in VSYNCD_EVEN instead).
433 */
434 CRTC_WRITE(PV_V_CONTROL,
435 PV_VCONTROL_CONTINUOUS |
436 PV_VCONTROL_INTERLACE |
437 VC4_SET_FIELD(mode->htotal / 2,
438 PV_VCONTROL_ODD_DELAY));
439 CRTC_WRITE(PV_VSYNCD_EVEN, 0);
440 } else {
441 CRTC_WRITE(PV_V_CONTROL, PV_VCONTROL_CONTINUOUS);
426 } 442 }
427 443
428 CRTC_WRITE(PV_HACT_ACT, mode->hdisplay); 444 CRTC_WRITE(PV_HACT_ACT, mode->hdisplay);
429 445
430 CRTC_WRITE(PV_V_CONTROL,
431 PV_VCONTROL_CONTINUOUS |
432 (interlace ? PV_VCONTROL_INTERLACE : 0));
433 446
434 CRTC_WRITE(PV_CONTROL, 447 CRTC_WRITE(PV_CONTROL,
435 VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | 448 VC4_SET_FIELD(format, PV_CONTROL_FORMAT) |
@@ -544,16 +557,6 @@ static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc,
544 return false; 557 return false;
545 } 558 }
546 559
547 /*
548 * Interlaced video modes got CRTC_INTERLACE_HALVE_V applied when
549 * coming from user space. We don't want this, as it screws up
550 * vblank timestamping, so fix it up.
551 */
552 drm_mode_set_crtcinfo(adjusted_mode, 0);
553
554 DRM_DEBUG_KMS("[CRTC:%d] adjusted_mode :\n", crtc->base.id);
555 drm_mode_debug_printmodeline(adjusted_mode);
556
557 return true; 560 return true;
558} 561}
559 562
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index fe1c4e35e681..d94108ca961d 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -211,35 +211,10 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
211 return ret; 211 return ret;
212} 212}
213 213
214/*
215 * drm_helper_probe_single_connector_modes() applies drm_mode_set_crtcinfo to
216 * all modes with flag CRTC_INTERLACE_HALVE_V. We don't want this, as it
217 * screws up vblank timestamping for interlaced modes, so fix it up.
218 */
219static int vc4_hdmi_connector_probe_modes(struct drm_connector *connector,
220 uint32_t maxX, uint32_t maxY)
221{
222 struct drm_display_mode *mode;
223 int count;
224
225 count = drm_helper_probe_single_connector_modes(connector, maxX, maxY);
226 if (count == 0)
227 return 0;
228
229 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed adapted modes :\n",
230 connector->base.id, connector->name);
231 list_for_each_entry(mode, &connector->modes, head) {
232 drm_mode_set_crtcinfo(mode, 0);
233 drm_mode_debug_printmodeline(mode);
234 }
235
236 return count;
237}
238
239static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { 214static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
240 .dpms = drm_atomic_helper_connector_dpms, 215 .dpms = drm_atomic_helper_connector_dpms,
241 .detect = vc4_hdmi_connector_detect, 216 .detect = vc4_hdmi_connector_detect,
242 .fill_modes = vc4_hdmi_connector_probe_modes, 217 .fill_modes = drm_helper_probe_single_connector_modes,
243 .destroy = vc4_hdmi_connector_destroy, 218 .destroy = vc4_hdmi_connector_destroy,
244 .reset = drm_atomic_helper_connector_reset, 219 .reset = drm_atomic_helper_connector_reset,
245 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 220 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -307,16 +282,20 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
307 bool debug_dump_regs = false; 282 bool debug_dump_regs = false;
308 bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; 283 bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
309 bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; 284 bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
310 u32 vactive = (mode->vdisplay >> 285 bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
311 ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0)); 286 u32 verta = (VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
312 u32 verta = (VC4_SET_FIELD(mode->vsync_end - mode->vsync_start,
313 VC4_HDMI_VERTA_VSP) | 287 VC4_HDMI_VERTA_VSP) |
314 VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, 288 VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
315 VC4_HDMI_VERTA_VFP) | 289 VC4_HDMI_VERTA_VFP) |
316 VC4_SET_FIELD(vactive, VC4_HDMI_VERTA_VAL)); 290 VC4_SET_FIELD(mode->crtc_vdisplay, VC4_HDMI_VERTA_VAL));
317 u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) | 291 u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
318 VC4_SET_FIELD(mode->vtotal - mode->vsync_end, 292 VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
319 VC4_HDMI_VERTB_VBP)); 293 VC4_HDMI_VERTB_VBP));
294 u32 vertb_even = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
295 VC4_SET_FIELD(mode->crtc_vtotal -
296 mode->crtc_vsync_end -
297 interlaced,
298 VC4_HDMI_VERTB_VBP));
320 u32 csc_ctl; 299 u32 csc_ctl;
321 300
322 if (debug_dump_regs) { 301 if (debug_dump_regs) {
@@ -349,7 +328,7 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
349 HDMI_WRITE(VC4_HDMI_VERTA0, verta); 328 HDMI_WRITE(VC4_HDMI_VERTA0, verta);
350 HDMI_WRITE(VC4_HDMI_VERTA1, verta); 329 HDMI_WRITE(VC4_HDMI_VERTA1, verta);
351 330
352 HDMI_WRITE(VC4_HDMI_VERTB0, vertb); 331 HDMI_WRITE(VC4_HDMI_VERTB0, vertb_even);
353 HDMI_WRITE(VC4_HDMI_VERTB1, vertb); 332 HDMI_WRITE(VC4_HDMI_VERTB1, vertb);
354 333
355 HD_WRITE(VC4_HD_VID_CTL, 334 HD_WRITE(VC4_HD_VID_CTL,
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index 9ecd6ff3d493..c5a423ead86f 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -183,6 +183,9 @@
183# define PV_CONTROL_EN BIT(0) 183# define PV_CONTROL_EN BIT(0)
184 184
185#define PV_V_CONTROL 0x04 185#define PV_V_CONTROL 0x04
186# define PV_VCONTROL_ODD_DELAY_MASK VC4_MASK(22, 6)
187# define PV_VCONTROL_ODD_DELAY_SHIFT 6
188# define PV_VCONTROL_ODD_FIRST BIT(5)
186# define PV_VCONTROL_INTERLACE BIT(4) 189# define PV_VCONTROL_INTERLACE BIT(4)
187# define PV_VCONTROL_CONTINUOUS BIT(1) 190# define PV_VCONTROL_CONTINUOUS BIT(1)
188# define PV_VCONTROL_VIDEN BIT(0) 191# define PV_VCONTROL_VIDEN BIT(0)