From: Ville Syrjälä <ville.syrj...@linux.intel.com>

Account for the TMDS clock limits declared by the DFP/DP++ dongle
when determining what color depth we're going to use.

Signed-off-by: Ville Syrjälä <ville.syrj...@linux.intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c   | 67 ++++++++++++++++++++---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 50 ++++++++++-------
 drivers/gpu/drm/i915/display/intel_hdmi.h |  2 +
 3 files changed, 90 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c 
b/drivers/gpu/drm/i915/display/intel_dp.c
index 65202615c8f1..639a0c2e5a40 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -1918,18 +1918,69 @@ static bool intel_dp_supports_dsc(struct intel_dp 
*intel_dp,
                drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd);
 }
 
-static int intel_dp_compute_bpp(struct intel_dp *intel_dp,
-                               struct intel_crtc_state *pipe_config)
+static bool intel_dp_hdmi_ycbcr420(struct intel_dp *intel_dp,
+                                  const struct intel_crtc_state *crtc_state)
+{
+       return crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420;
+}
+
+static int intel_dp_hdmi_tmds_clock(struct intel_dp *intel_dp,
+                                   const struct intel_crtc_state *crtc_state, 
int bpc)
+{
+       int clock = crtc_state->hw.adjusted_mode.crtc_clock * bpc / 8;
+
+       if (intel_dp_hdmi_ycbcr420(intel_dp, crtc_state))
+               clock /= 2;
+
+       return clock;
+}
+
+static bool intel_dp_hdmi_tmds_clock_valid(struct intel_dp *intel_dp,
+                                          const struct intel_crtc_state 
*crtc_state, int bpc)
+{
+       int tmds_clock = intel_dp_hdmi_tmds_clock(intel_dp, crtc_state, bpc);
+
+       if (intel_dp->dfp.min_tmds_clock &&
+           tmds_clock < intel_dp->dfp.min_tmds_clock)
+               return false;
+
+       if (intel_dp->dfp.max_tmds_clock &&
+           tmds_clock > intel_dp->dfp.max_tmds_clock)
+               return false;
+
+       return true;
+}
+
+static bool intel_dp_hdmi_deep_color_possible(struct intel_dp *intel_dp,
+                                             const struct intel_crtc_state 
*crtc_state,
+                                             int bpc)
+{
+       bool has_hdmi_sink = intel_dp->has_hdmi_sink;
+
+       return intel_hdmi_deep_color_possible(crtc_state, bpc, has_hdmi_sink) &&
+               intel_dp_hdmi_tmds_clock_valid(intel_dp, crtc_state, bpc);
+}
+
+static int intel_dp_max_bpp(struct intel_dp *intel_dp,
+                           const struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
        struct intel_connector *intel_connector = intel_dp->attached_connector;
-       int bpp;
+       int bpp, bpc;
 
-       bpp = pipe_config->pipe_bpp;
+       bpc = crtc_state->pipe_bpp / 3;
 
        if (intel_dp->dfp.max_bpc)
-               bpp = min(bpp, 3 * intel_dp->dfp.max_bpc);
+               bpc = min_t(int, bpc, intel_dp->dfp.max_bpc);
 
+       if (intel_dp->dfp.min_tmds_clock) {
+               for (; bpc >= 10; bpc -= 2) {
+                       if (intel_dp_hdmi_deep_color_possible(intel_dp, 
crtc_state, bpc))
+                               break;
+               }
+       }
+
+       bpp = bpc * 3;
        if (intel_dp_is_edp(intel_dp)) {
                /* Get bpp from vbt only for panels that dont have bpp in edid 
*/
                if (intel_connector->base.display_info.bpc == 0 &&
@@ -2244,7 +2295,7 @@ intel_dp_compute_link_config(struct intel_encoder 
*encoder,
        limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
 
        limits.min_bpp = intel_dp_min_bpp(pipe_config);
-       limits.max_bpp = intel_dp_compute_bpp(intel_dp, pipe_config);
+       limits.max_bpp = intel_dp_max_bpp(intel_dp, pipe_config);
 
        if (intel_dp_is_edp(intel_dp)) {
                /*
@@ -3579,10 +3630,10 @@ void intel_dp_configure_protocol_converter(struct 
intel_dp *intel_dp)
 {
        u8 tmp;
 
-       if (intel_dp->dpcd[DP_DPCD_REV] < 0x13)
+       if (!drm_dp_is_branch(intel_dp->dpcd))
                return;
 
-       if (!drm_dp_is_branch(intel_dp->dpcd))
+       if (intel_dp->dpcd[DP_DPCD_REV] < 0x13)
                return;
 
        tmp = intel_dp->has_hdmi_sink ?
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c 
b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 31fec0050f8d..d6326a4a4a9a 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2218,35 +2218,18 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
        return intel_mode_valid_max_plane_size(dev_priv, mode);
 }
 
-static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
-                                    int bpc)
+bool intel_hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
+                                   int bpc, bool has_hdmi_sink)
 {
-       struct drm_i915_private *dev_priv =
-               to_i915(crtc_state->uapi.crtc->dev);
        struct drm_atomic_state *state = crtc_state->uapi.state;
        struct drm_connector_state *connector_state;
        struct drm_connector *connector;
-       const struct drm_display_mode *adjusted_mode =
-               &crtc_state->hw.adjusted_mode;
        int i;
 
-       if (HAS_GMCH(dev_priv))
-               return false;
-
-       if (bpc == 10 && INTEL_GEN(dev_priv) < 11)
-               return false;
-
        if (crtc_state->pipe_bpp < bpc * 3)
                return false;
 
-       if (!crtc_state->has_hdmi_sink)
-               return false;
-
-       /*
-        * HDMI deep color affects the clocks, so it's only possible
-        * when not cloning with other encoder types.
-        */
-       if (crtc_state->output_types != 1 << INTEL_OUTPUT_HDMI)
+       if (!has_hdmi_sink)
                return false;
 
        for_each_new_connector_in_state(state, connector, connector_state, i) {
@@ -2274,6 +2257,30 @@ static bool hdmi_deep_color_possible(const struct 
intel_crtc_state *crtc_state,
                }
        }
 
+       return true;
+}
+
+static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
+                                    int bpc)
+{
+       struct drm_i915_private *dev_priv =
+               to_i915(crtc_state->uapi.crtc->dev);
+       const struct drm_display_mode *adjusted_mode =
+               &crtc_state->hw.adjusted_mode;
+
+       if (HAS_GMCH(dev_priv))
+               return false;
+
+       if (bpc == 10 && INTEL_GEN(dev_priv) < 11)
+               return false;
+
+       /*
+        * HDMI deep color affects the clocks, so it's only possible
+        * when not cloning with other encoder types.
+        */
+       if (crtc_state->output_types != BIT(INTEL_OUTPUT_HDMI))
+               return false;
+
        /* Display Wa_1405510057:icl,ehl */
        if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 &&
            bpc == 10 && IS_GEN(dev_priv, 11) &&
@@ -2281,7 +2288,8 @@ static bool hdmi_deep_color_possible(const struct 
intel_crtc_state *crtc_state,
             adjusted_mode->crtc_hblank_start) % 8 == 2)
                return false;
 
-       return true;
+       return intel_hdmi_deep_color_possible(crtc_state, bpc,
+                                             crtc_state->has_hdmi_sink);
 }
 
 static bool
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h 
b/drivers/gpu/drm/i915/display/intel_hdmi.h
index d3659d0b408b..bd58c929f816 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.h
@@ -48,5 +48,7 @@ void intel_read_infoframe(struct intel_encoder *encoder,
                          const struct intel_crtc_state *crtc_state,
                          enum hdmi_infoframe_type type,
                          union hdmi_infoframe *frame);
+bool intel_hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
+                                   int bpc, bool has_hdmi_sink);
 
 #endif /* __INTEL_HDMI_H__ */
-- 
2.24.1

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

Reply via email to