drm/vc4: FKMS Block modes with odd horizontal timing values on Pi4
authorDave Stevenson <dave.stevenson@raspberrypi.com>
Fri, 3 Jul 2020 15:06:55 +0000 (16:06 +0100)
committerPhil Elwell <8911409+pelwell@users.noreply.github.com>
Fri, 3 Jul 2020 16:14:31 +0000 (17:14 +0100)
Pi4 HDMI pipeline is 2 pixels/clock and can not produce timings
that have odd values for active pixels, front porch, sync width,
or back porch.
Detect these modes and block them within fkms.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
drivers/gpu/drm/vc4/vc4_firmware_kms.c

index a173ca4..ff72648 100644 (file)
@@ -44,6 +44,7 @@ struct get_display_cfg {
 
 struct vc4_fkms {
        struct get_display_cfg cfg;
 
 struct vc4_fkms {
        struct get_display_cfg cfg;
+       bool bcm2711;
 };
 
 #define PLANES_PER_CRTC                3
 };
 
 #define PLANES_PER_CRTC                3
@@ -1097,6 +1098,17 @@ vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
                break;
        }
 
                break;
        }
 
+       /* Pi4 can't generate odd horizontal timings on HDMI, so reject modes
+        * that would set them.
+        */
+       if (fkms->bcm2711 &&
+           (vc4_crtc->display_number == 2 || vc4_crtc->display_number == 7) &&
+           ((mode->hdisplay |                          /* active */
+             (mode->hsync_start - mode->hdisplay) |    /* front porch */
+             (mode->hsync_end - mode->hsync_start) |   /* sync pulse */
+             (mode->htotal - mode->hsync_end)) & 1))   /* back porch */
+               return MODE_H_ILLEGAL;
+
        return MODE_OK;
 }
 
        return MODE_OK;
 }
 
@@ -1282,6 +1294,8 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
 
 static const struct of_device_id vc4_firmware_kms_dt_match[] = {
        { .compatible = "raspberrypi,rpi-firmware-kms" },
 
 static const struct of_device_id vc4_firmware_kms_dt_match[] = {
        { .compatible = "raspberrypi,rpi-firmware-kms" },
+       { .compatible = "raspberrypi,rpi-firmware-kms-2711",
+         .data = (void *)1 },
        {}
 };
 
        {}
 };
 
@@ -1815,6 +1829,7 @@ static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
        struct drm_device *drm = dev_get_drvdata(master);
        struct vc4_dev *vc4 = to_vc4_dev(drm);
        struct device_node *firmware_node;
        struct drm_device *drm = dev_get_drvdata(master);
        struct vc4_dev *vc4 = to_vc4_dev(drm);
        struct device_node *firmware_node;
+       const struct of_device_id *match;
        struct vc4_crtc **crtc_list;
        u32 num_displays, display_num;
        struct vc4_fkms *fkms;
        struct vc4_crtc **crtc_list;
        u32 num_displays, display_num;
        struct vc4_fkms *fkms;
@@ -1827,6 +1842,12 @@ static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
        if (!fkms)
                return -ENOMEM;
 
        if (!fkms)
                return -ENOMEM;
 
+       match = of_match_device(vc4_firmware_kms_dt_match, dev);
+       if (!match)
+               return -ENODEV;
+       if (match->data)
+               fkms->bcm2711 = true;
+
        /* firmware kms doesn't have precise a scanoutpos implementation, so
         * we can't do the precise vblank timestamp mode.
         */
        /* firmware kms doesn't have precise a scanoutpos implementation, so
         * we can't do the precise vblank timestamp mode.
         */