aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)