diff options
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_crtc.c | 49 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_hdmi.c | 45 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_regs.h | 3 |
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 | */ | ||
219 | static 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 | |||
239 | static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { | 214 | static 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) |