kms/vc4_hdmi: Refuse 4096x2160@60 hdmi modes
authorDom Cobley <popcornmix@gmail.com>
Tue, 17 May 2022 11:46:42 +0000 (12:46 +0100)
committerPhil Elwell <8911409+pelwell@users.noreply.github.com>
Thu, 26 May 2022 13:50:01 +0000 (14:50 +0100)
These are no reliable without overclocking.
See: https://github.com/raspberrypi/linux/issues/5034

Signed-off-by: Dom Cobley <popcornmix@gmail.com>
drivers/gpu/drm/vc4/vc4_drv.h
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/vc4/vc4_hvs.c

index 0f600a3..4a8940c 100644 (file)
@@ -351,6 +351,12 @@ struct vc4_hvs {
         * available.
         */
        bool vc5_hdmi_enable_scrambling;
+
+       /*
+        * 4096x2160@60 requires a core overclock to work, so register
+        * whether that is sufficient.
+        */
+       bool vc5_hdmi_enable_4096by2160;
 };
 
 struct vc4_plane {
index ed5c21e..5d37cd0 100644 (file)
@@ -1822,6 +1822,7 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
        struct drm_connector *connector = &vc4_hdmi->connector;
        struct drm_connector_state *old_conn_state = drm_atomic_get_old_connector_state(conn_state->state, connector);
        struct vc4_hdmi_connector_state *old_vc4_state = conn_state_to_vc4_hdmi_conn_state(old_conn_state);
+       struct vc4_dev *vc4 = to_vc4_dev(connector->dev);
        unsigned long long pixel_rate = mode->clock * 1000;
        unsigned long long tmds_rate;
        int ret;
@@ -1846,6 +1847,12 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
                        return -EINVAL;
        }
 
+       /* 4096x2160@60 is not reliable without overclocking core */
+       if (mode->hdisplay > 3840 && mode->vdisplay >= 2160 &&
+           drm_mode_vrefresh(mode) >= 50 &&
+           !vc4->hvs->vc5_hdmi_enable_4096by2160)
+               return -EINVAL;
+
        /*
         * The 1440p@60 pixel rate is in the same range than the first
         * WiFi channel (between 2.4GHz and 2.422GHz with 22MHz
@@ -1877,6 +1884,8 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
                            const struct drm_display_mode *mode)
 {
        struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+       const struct drm_connector *connector = &vc4_hdmi->connector;
+       struct vc4_dev *vc4 = to_vc4_dev(connector->dev);
 
        if (vc4_hdmi->variant->unsupported_odd_h_timings &&
            !(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
@@ -1884,6 +1893,11 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
             (mode->hsync_end % 2) || (mode->htotal % 2)))
                return MODE_H_ILLEGAL;
 
+       if (mode->hdisplay > 3840 && mode->vdisplay >= 2160 &&
+           drm_mode_vrefresh(mode) >= 50 &&
+           !vc4->hvs->vc5_hdmi_enable_4096by2160)
+               return MODE_CLOCK_HIGH;
+
        return vc4_hdmi_encoder_clock_valid(vc4_hdmi, mode->clock * 1000);
 }
 
index 8969d23..b0acdff 100644 (file)
@@ -897,6 +897,7 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
        hvs->regset.nregs = ARRAY_SIZE(hvs_regs);
 
        if (vc4->is_vc5) {
+               unsigned long min_rate;
                unsigned long max_rate;
 
                hvs->core_clk = devm_clk_get(&pdev->dev, NULL);
@@ -909,6 +910,10 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
                if (max_rate >= 550000000)
                        hvs->vc5_hdmi_enable_scrambling = true;
 
+               min_rate = clk_get_min_rate(hvs->core_clk);
+               if (min_rate >= 600000000)
+                       hvs->vc5_hdmi_enable_4096by2160 = true;
+
                ret = clk_prepare_enable(hvs->core_clk);
                if (ret) {
                        dev_err(&pdev->dev, "Couldn't enable the core clock\n");