From ae200c4c1d2d0c9f827e7f73d00f00074e3a7a04 Mon Sep 17 00:00:00 2001 From: Mateusz Kwiatkowski Date: Thu, 15 Jul 2021 01:08:08 +0200 Subject: [PATCH] drm/vc4: Relax VEC modeline requirements and add progressive mode support Make vc4_vec_encoder_atomic_check() accept arbitrary modelines, as long as they result in somewhat sane output from the VEC. The bounds have been determined empirically. Additionally, add support for the progressive 262-line and 312-line modes. Signed-off-by: Mateusz Kwiatkowski --- drivers/gpu/drm/vc4/vc4_crtc.c | 1 + drivers/gpu/drm/vc4/vc4_vec.c | 97 ++++++++++++++++++++++++++++------ 2 files changed, 83 insertions(+), 15 deletions(-) --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -401,6 +401,7 @@ static void vc4_crtc_config_pv(struct dr CRTC_WRITE(PV_V_CONTROL, PV_VCONTROL_CONTINUOUS | (is_dsi ? PV_VCONTROL_DSI : 0)); + CRTC_WRITE(PV_VSYNCD_EVEN, 0); } if (is_dsi) --- a/drivers/gpu/drm/vc4/vc4_vec.c +++ b/drivers/gpu/drm/vc4/vc4_vec.c @@ -423,18 +423,11 @@ static int vc4_vec_connector_atomic_chec struct drm_connector_state *new_state = drm_atomic_get_new_connector_state(state, conn); - const struct vc4_vec_tv_mode *vec_mode = - &vc4_vec_tv_modes[new_state->tv.mode]; - - if (new_state->crtc) { + if (new_state->crtc && old_state->tv.mode != new_state->tv.mode) { struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); - if (!drm_mode_equal(vec_mode->mode, &crtc_state->mode)) - return -EINVAL; - - if (old_state->tv.mode != new_state->tv.mode) - crtc_state->mode_changed = true; + crtc_state->mode_changed = true; } return 0; @@ -559,7 +552,10 @@ static void vc4_vec_encoder_enable(struc VEC_WRITE(VEC_CLMP0_START, 0xac); VEC_WRITE(VEC_CLMP0_END, 0xec); VEC_WRITE(VEC_CONFIG2, - VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS); + VEC_CONFIG2_UV_DIG_DIS | + VEC_CONFIG2_RGB_DIG_DIS | + ((encoder->crtc->state->adjusted_mode.flags & + DRM_MODE_FLAG_INTERLACE) ? 0 : VEC_CONFIG2_PROG_SCAN)); VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD); VEC_WRITE(VEC_DAC_CONFIG, vec->variant->dac_config); @@ -582,17 +578,88 @@ static void vc4_vec_encoder_enable(struc } -static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) { - return true; + const struct drm_display_mode *reference_mode = + vc4_vec_tv_modes[conn_state->tv.mode].mode; + + if (crtc_state->adjusted_mode.crtc_clock != reference_mode->clock || + crtc_state->adjusted_mode.crtc_htotal != reference_mode->htotal || + crtc_state->adjusted_mode.crtc_hdisplay % 4 != 0 || + crtc_state->adjusted_mode.crtc_hsync_end - + crtc_state->adjusted_mode.crtc_hsync_start < 1) + return -EINVAL; + + switch (reference_mode->vtotal) { + case 525: + if (crtc_state->adjusted_mode.crtc_vdisplay < 1 || + crtc_state->adjusted_mode.crtc_vdisplay > 253 || + crtc_state->adjusted_mode.crtc_vsync_start - + crtc_state->adjusted_mode.crtc_vdisplay < 1 || + crtc_state->adjusted_mode.crtc_vsync_end - + crtc_state->adjusted_mode.crtc_vsync_start != 3 || + crtc_state->adjusted_mode.crtc_vtotal - + crtc_state->adjusted_mode.crtc_vsync_end < 4 || + crtc_state->adjusted_mode.crtc_vtotal > 262) + return -EINVAL; + + if ((crtc_state->adjusted_mode.flags & + DRM_MODE_FLAG_INTERLACE) && + (crtc_state->adjusted_mode.vdisplay % 2 != 0 || + crtc_state->adjusted_mode.vsync_start % 2 != 1 || + crtc_state->adjusted_mode.vsync_end % 2 != 1 || + crtc_state->adjusted_mode.vtotal % 2 != 1)) + return -EINVAL; + + /* progressive mode is hard-wired to 262 total lines */ + if (!(crtc_state->adjusted_mode.flags & + DRM_MODE_FLAG_INTERLACE) && + crtc_state->adjusted_mode.crtc_vtotal != 262) + return -EINVAL; + + break; + + case 625: + if (crtc_state->adjusted_mode.crtc_vdisplay < 1 || + crtc_state->adjusted_mode.crtc_vdisplay > 305 || + crtc_state->adjusted_mode.crtc_vsync_start - + crtc_state->adjusted_mode.crtc_vdisplay < 1 || + crtc_state->adjusted_mode.crtc_vsync_end - + crtc_state->adjusted_mode.crtc_vsync_start != 3 || + crtc_state->adjusted_mode.crtc_vtotal - + crtc_state->adjusted_mode.crtc_vsync_end < 2 || + crtc_state->adjusted_mode.crtc_vtotal > 312) + return -EINVAL; + + if ((crtc_state->adjusted_mode.flags & + DRM_MODE_FLAG_INTERLACE) && + (crtc_state->adjusted_mode.vdisplay % 2 != 0 || + crtc_state->adjusted_mode.vsync_start % 2 != 0 || + crtc_state->adjusted_mode.vsync_end % 2 != 0 || + crtc_state->adjusted_mode.vtotal % 2 != 1)) + return -EINVAL; + + /* progressive mode is hard-wired to 312 total lines */ + if (!(crtc_state->adjusted_mode.flags & + DRM_MODE_FLAG_INTERLACE) && + crtc_state->adjusted_mode.crtc_vtotal != 312) + return -EINVAL; + + break; + + default: + return -EINVAL; + } + + return 0; } static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = { .disable = vc4_vec_encoder_disable, .enable = vc4_vec_encoder_enable, - .mode_fixup = vc4_vec_encoder_mode_fixup, + .atomic_check = vc4_vec_encoder_atomic_check, }; static const struct vc4_vec_variant bcm2835_vec_variant = {