diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index b2628afcb327..af0fcb41e420 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -316,7 +316,9 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode struct drm_crtc_state *crtc_state = crtc->state; struct drm_display_mode *mode = &crtc_state->adjusted_mode; bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; - u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1; + bool is_hdmi = vc4_encoder->type == VC4_ENCODER_TYPE_HDMI0 || + vc4_encoder->type == VC4_ENCODER_TYPE_HDMI1; + u32 pixel_rep = ((mode->flags & DRM_MODE_FLAG_DBLCLK) && !is_hdmi) ? 2 : 1; bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 || vc4_encoder->type == VC4_ENCODER_TYPE_DSI1); bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index ad7fcfa5a068..23ff6aa5e8f6 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -79,6 +79,8 @@ #define VC5_HDMI_VERTB_VSPO_SHIFT 16 #define VC5_HDMI_VERTB_VSPO_MASK VC4_MASK(29, 16) +#define VC4_HDMI_MISC_CONTROL_PIXEL_REP_SHIFT 0 +#define VC4_HDMI_MISC_CONTROL_PIXEL_REP_MASK VC4_MASK(3, 0) #define VC5_HDMI_MISC_CONTROL_PIXEL_REP_SHIFT 0 #define VC5_HDMI_MISC_CONTROL_PIXEL_REP_MASK VC4_MASK(3, 0) @@ -996,6 +998,7 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, mode->crtc_vsync_end, VC4_HDMI_VERTB_VBP)); unsigned long flags; + u32 reg; spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); @@ -1022,6 +1025,11 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, HDMI_WRITE(HDMI_VERTB0, vertb_even); HDMI_WRITE(HDMI_VERTB1, vertb); + reg = HDMI_READ(HDMI_MISC_CONTROL); + reg &= ~VC4_HDMI_MISC_CONTROL_PIXEL_REP_MASK; + reg |= VC4_SET_FIELD(pixel_rep - 1, VC4_HDMI_MISC_CONTROL_PIXEL_REP); + HDMI_WRITE(HDMI_MISC_CONTROL, reg); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } @@ -1122,7 +1130,7 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, reg = HDMI_READ(HDMI_MISC_CONTROL); reg &= ~VC5_HDMI_MISC_CONTROL_PIXEL_REP_MASK; - reg |= VC4_SET_FIELD(0, VC5_HDMI_MISC_CONTROL_PIXEL_REP); + reg |= VC4_SET_FIELD(pixel_rep - 1, VC5_HDMI_MISC_CONTROL_PIXEL_REP); HDMI_WRITE(HDMI_MISC_CONTROL, reg); HDMI_WRITE(HDMI_CLOCK_STOP, 0); @@ -1632,11 +1640,25 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, unsigned long long tmds_bit_rate; int ret; - if (vc4_hdmi->variant->unsupported_odd_h_timings && - !(mode->flags & DRM_MODE_FLAG_DBLCLK) && - ((mode->hdisplay % 2) || (mode->hsync_start % 2) || - (mode->hsync_end % 2) || (mode->htotal % 2))) - return -EINVAL; + if (vc4_hdmi->variant->unsupported_odd_h_timings) { + if (mode->flags & DRM_MODE_FLAG_DBLCLK) { + /* Only try to fixup DBLCLK modes to get 480i and 576i + * working. + * A generic solution for all modes with odd horizontal + * timing values seems impossible based on trying to + * solve it for 1366x768 monitors. + */ + if ((mode->hsync_start - mode->hdisplay) & 1) + mode->hsync_start--; + if ((mode->hsync_end - mode->hsync_start) & 1) + mode->hsync_end--; + } + + /* Now check whether we still have odd values remaining */ + if ((mode->hdisplay % 2) || (mode->hsync_start % 2) || + (mode->hsync_end % 2) || (mode->htotal % 2)) + return -EINVAL; + } /* * The 1440p@60 pixel rate is in the same range than the first