drm/vc4: Make VEC progressive modes readily accessible
authorMateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
Wed, 14 Jul 2021 23:08:11 +0000 (01:08 +0200)
committerPhil Elwell <8911409+pelwell@users.noreply.github.com>
Mon, 1 Nov 2021 11:11:23 +0000 (11:11 +0000)
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 <kfyatek+publicgit@gmail.com>
drivers/gpu/drm/vc4/vc4_vec.c

index c4250dd..255e5c6 100644 (file)
@@ -251,7 +251,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;
@@ -285,61 +286,81 @@ static const struct debugfs_reg32 vec_regs[] = {
 };
 
 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,
@@ -399,16 +420,32 @@ static void vc4_vec_connector_destroy(struct drm_connector *connector)
 static int vc4_vec_connector_get_modes(struct drm_connector *connector)
 {
        struct drm_connector_state *state = connector->state;
-       struct drm_display_mode *mode;
-
-       mode = drm_mode_duplicate(connector->dev,
-                                 vc4_vec_tv_modes[state->tv.mode].mode);
-       if (!mode) {
+       struct drm_display_mode *interlaced_mode, *progressive_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;
 }
@@ -589,7 +626,7 @@ static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
                                        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 ||