When using the modes that need the highest pixel rate we support (such
as 4k at 60Hz), using a 10 or 12 bpc output will put us over the limit
of what we can achieve.

In such a case, let's force our output to be YUV422 so that we can go
back down under the required clock rate.

Signed-off-by: Maxime Ripard <max...@cerno.tech>
---
 drivers/gpu/drm/vc4/vc4_hdmi.c | 37 +++++++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index c4f91d39d91c..12eda1e76338 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -1029,6 +1029,41 @@ static unsigned long vc4_hdmi_calc_pixel_rate(struct 
drm_bridge *bridge,
        return pixel_rate;
 }
 
+static u32 *vc4_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge 
*bridge,
+                                                      struct drm_bridge_state 
*bridge_state,
+                                                      struct drm_crtc_state 
*crtc_state,
+                                                      struct 
drm_connector_state *conn_state,
+                                                      unsigned int 
*num_output_fmts)
+{
+       struct vc4_hdmi *vc4_hdmi = bridge_to_vc4_hdmi(bridge);
+       unsigned long long pixel_rate = vc4_hdmi_calc_pixel_rate(bridge,
+                                                                bridge_state,
+                                                                crtc_state,
+                                                                conn_state);
+
+       /*
+        * If our pixel rate is too fast, force YUV422 and hope it works
+        */
+       if (pixel_rate > vc4_hdmi->variant->max_pixel_clock) {
+               u32 *output_fmts;
+
+               output_fmts = kzalloc(sizeof(*output_fmts), GFP_KERNEL);
+               if (!output_fmts)
+                       return NULL;
+
+               *output_fmts = MEDIA_BUS_FMT_UYVY8_1X16;
+               *num_output_fmts = 1;
+
+               return output_fmts;
+       }
+
+       return drm_atomic_helper_bridge_hdmi_get_output_bus_fmts(bridge,
+                                                                bridge_state,
+                                                                crtc_state,
+                                                                conn_state,
+                                                                
num_output_fmts);
+}
+
 static int vc4_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
                                        struct drm_bridge_state *bridge_state,
                                        struct drm_crtc_state *crtc_state,
@@ -1088,7 +1123,7 @@ static const struct drm_bridge_funcs 
vc4_hdmi_bridge_funcs = {
        .atomic_check = vc4_hdmi_bridge_atomic_check,
        .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
        .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
-       .atomic_get_output_bus_fmts = 
drm_atomic_helper_bridge_hdmi_get_output_bus_fmts,
+       .atomic_get_output_bus_fmts = 
vc4_hdmi_bridge_atomic_get_output_bus_fmts,
        .atomic_reset = drm_atomic_helper_bridge_reset,
        .mode_valid =   vc4_hdmi_bridge_mode_valid,
 };
-- 
2.30.2

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to