From bfd6f67af0450e29378d390386210ac91c5dcfce Mon Sep 17 00:00:00 2001 From: Mateusz Kwiatkowski Date: Thu, 15 Jul 2021 01:08:11 +0200 Subject: [PATCH] drm/vc4: Make VEC progressive modes readily accessible Add predefined modelines for the 240p (NTSC) and 288p (PAL) progressive modes, and report them through vc4_vec_connector_get_modes(). Signed-off-by: Mateusz Kwiatkowski --- drivers/gpu/drm/vc4/vc4_vec.c | 73 ++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 18 deletions(-) --- a/drivers/gpu/drm/vc4/vc4_vec.c +++ b/drivers/gpu/drm/vc4/vc4_vec.c @@ -228,7 +228,8 @@ enum vc4_vec_tv_mode_id { }; struct vc4_vec_tv_mode { - const struct drm_display_mode *mode; + const struct drm_display_mode *interlaced_mode; + const struct drm_display_mode *progressive_mode; u32 config0; u32 config1; u32 custom_freq; @@ -262,61 +263,81 @@ static const struct debugfs_reg32 vec_re }; static const struct drm_display_mode drm_mode_480i = { - DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500, + DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0, 480, 480 + 7, 480 + 7 + 6, 525, 0, DRM_MODE_FLAG_INTERLACE) }; +static const struct drm_display_mode drm_mode_240p = { + DRM_MODE("720x240", DRM_MODE_TYPE_DRIVER, 13500, + 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0, + 240, 240 + 3, 240 + 3 + 3, 262, 0, 0) +}; + static const struct drm_display_mode drm_mode_576i = { - DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500, + DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0, 576, 576 + 4, 576 + 4 + 6, 625, 0, DRM_MODE_FLAG_INTERLACE) }; +static const struct drm_display_mode drm_mode_288p = { + DRM_MODE("720x288", DRM_MODE_TYPE_DRIVER, 13500, + 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0, + 288, 288 + 2, 288 + 2 + 3, 312, 0, 0) +}; + static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = { [VC4_VEC_TV_MODE_NTSC] = { - .mode = &drm_mode_480i, + .interlaced_mode = &drm_mode_480i, + .progressive_mode = &drm_mode_240p, .config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN, .config1 = VEC_CONFIG1_C_CVBS_CVBS, }, [VC4_VEC_TV_MODE_NTSC_J] = { - .mode = &drm_mode_480i, + .interlaced_mode = &drm_mode_480i, + .progressive_mode = &drm_mode_240p, .config0 = VEC_CONFIG0_NTSC_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS, }, [VC4_VEC_TV_MODE_NTSC_443] = { /* NTSC with PAL chroma frequency */ - .mode = &drm_mode_480i, + .interlaced_mode = &drm_mode_480i, + .progressive_mode = &drm_mode_240p, .config0 = VEC_CONFIG0_NTSC_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ, .custom_freq = 0x2a098acb, }, [VC4_VEC_TV_MODE_PAL] = { - .mode = &drm_mode_576i, + .interlaced_mode = &drm_mode_576i, + .progressive_mode = &drm_mode_288p, .config0 = VEC_CONFIG0_PAL_BDGHI_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS, }, [VC4_VEC_TV_MODE_PAL_M] = { - .mode = &drm_mode_480i, + .interlaced_mode = &drm_mode_480i, + .progressive_mode = &drm_mode_240p, .config0 = VEC_CONFIG0_PAL_M_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS, }, [VC4_VEC_TV_MODE_PAL_N] = { - .mode = &drm_mode_576i, + .interlaced_mode = &drm_mode_576i, + .progressive_mode = &drm_mode_288p, .config0 = VEC_CONFIG0_PAL_N_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS, }, [VC4_VEC_TV_MODE_PAL60] = { /* PAL-M with chroma frequency of regular PAL */ - .mode = &drm_mode_480i, + .interlaced_mode = &drm_mode_480i, + .progressive_mode = &drm_mode_240p, .config0 = VEC_CONFIG0_PAL_M_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ, .custom_freq = 0x2a098acb, }, [VC4_VEC_TV_MODE_SECAM] = { - .mode = &drm_mode_576i, + .interlaced_mode = &drm_mode_576i, + .progressive_mode = &drm_mode_288p, .config0 = VEC_CONFIG0_SECAM_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS, .custom_freq = 0x29c71c72, @@ -370,16 +391,32 @@ vc4_vec_connector_detect(struct drm_conn static int vc4_vec_connector_get_modes(struct drm_connector *connector) { struct drm_connector_state *state = connector->state; - struct drm_display_mode *mode; + struct drm_display_mode *interlaced_mode, *progressive_mode; - mode = drm_mode_duplicate(connector->dev, - vc4_vec_tv_modes[state->tv.mode].mode); - if (!mode) { + interlaced_mode = + drm_mode_duplicate(connector->dev, + vc4_vec_tv_modes[state->tv.mode].interlaced_mode); + progressive_mode = + drm_mode_duplicate(connector->dev, + vc4_vec_tv_modes[state->tv.mode].progressive_mode); + if (!interlaced_mode || !progressive_mode) { DRM_ERROR("Failed to create a new display mode\n"); + drm_mode_destroy(connector->dev, interlaced_mode); + drm_mode_destroy(connector->dev, progressive_mode); return -ENOMEM; } - drm_mode_probed_add(connector, mode); + if (connector->cmdline_mode.specified && + connector->cmdline_mode.refresh_specified && + !connector->cmdline_mode.interlace) + /* progressive mode set at boot, let's make it preferred */ + progressive_mode->type |= DRM_MODE_TYPE_PREFERRED; + else + /* otherwise, interlaced mode is preferred */ + interlaced_mode->type |= DRM_MODE_TYPE_PREFERRED; + + drm_mode_probed_add(connector, interlaced_mode); + drm_mode_probed_add(connector, progressive_mode); return 1; } @@ -576,7 +613,7 @@ static int vc4_vec_encoder_atomic_check( struct drm_connector_state *conn_state) { const struct drm_display_mode *reference_mode = - vc4_vec_tv_modes[conn_state->tv.mode].mode; + vc4_vec_tv_modes[conn_state->tv.mode].interlaced_mode; if (crtc_state->adjusted_mode.crtc_clock != reference_mode->clock || crtc_state->adjusted_mode.crtc_htotal != reference_mode->htotal ||