drm/i915/dp: Enable DSC via the connector decompression AUX
authorImre Deak <imre.deak@intel.com>
Tue, 24 Oct 2023 10:22:18 +0000 (13:22 +0300)
committerImre Deak <imre.deak@intel.com>
Wed, 8 Nov 2023 15:22:19 +0000 (17:22 +0200)
Enable DSC using the DSC AUX device stored for this purpose in the
connector. For clarity add separate functions to enable/disable the
decompression, since these sequences will diverge more in follow-up
patches that also enable/disable DSC passthrough and on MST do the
actual enabling/disabling only for the first/last user of the given
AUX device. As a preparation for the latter refcounting change, also
pass the atomic state to the functions.

While at it set/clear only the DP_DECOMPRESSION_EN flag in the
DP_DSC_ENABLE DPCD register, preserving the reserved register bits.

Besides preserving the reserved register bits, the behavior stays as
before, as DSC is still only enabled for the first MST stream (which a
follow-up patch changes, enabling it for all streams).

v2:
- Add a helper function setting/clearing the decompression flag,
  preserving the reserved register bits.
v3:
- Add separate functions to enable/disable decompression and pass the
  atomic state to these.
- Add DocBook for both functions.

Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v2)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-24-imre.deak@intel.com
drivers/gpu/drm/i915/display/intel_ddi.c
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/intel_dp.h
drivers/gpu/drm/i915/display/intel_dp_mst.c

index cc2a38fc22d0d71b9151053ce5f1484008aab743..6cec72ac6422ef6f5c651995cc96f2e44732945d 100644 (file)
@@ -2539,7 +2539,9 @@ static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state,
 
        intel_dp_configure_protocol_converter(intel_dp, crtc_state);
        if (!is_mst)
-               intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true);
+               intel_dp_sink_enable_decompression(state,
+                                                  to_intel_connector(conn_state->connector),
+                                                  crtc_state);
 
        /*
         * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit
@@ -2692,7 +2694,9 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
 
        intel_dp_configure_protocol_converter(intel_dp, crtc_state);
        if (!is_mst)
-               intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true);
+               intel_dp_sink_enable_decompression(state,
+                                                  to_intel_connector(conn_state->connector),
+                                                  crtc_state);
        /*
         * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit
         * in the FEC_CONFIGURATION register to 1 before initiating link
@@ -2773,8 +2777,9 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
                intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
        intel_dp_configure_protocol_converter(intel_dp, crtc_state);
        if (!is_mst)
-               intel_dp_sink_set_decompression_state(intel_dp, crtc_state,
-                                                     true);
+               intel_dp_sink_enable_decompression(state,
+                                                  to_intel_connector(conn_state->connector),
+                                                  crtc_state);
        intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true);
        intel_dp_start_link_train(intel_dp, crtc_state);
        if ((port != PORT_A || DISPLAY_VER(dev_priv) >= 9) &&
@@ -3360,6 +3365,8 @@ static void intel_disable_ddi_dp(struct intel_atomic_state *state,
                                 const struct drm_connector_state *old_conn_state)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+       struct intel_connector *connector =
+               to_intel_connector(old_conn_state->connector);
 
        intel_dp->link_trained = false;
 
@@ -3368,8 +3375,8 @@ static void intel_disable_ddi_dp(struct intel_atomic_state *state,
        intel_psr_disable(intel_dp, old_crtc_state);
        intel_edp_backlight_off(old_conn_state);
        /* Disable the decompression in DP Sink */
-       intel_dp_sink_set_decompression_state(intel_dp, old_crtc_state,
-                                             false);
+       intel_dp_sink_disable_decompression(state,
+                                           connector, old_crtc_state);
        /* Disable Ignore_MSA bit in DP Sink */
        intel_dp_sink_set_msa_timing_par_ignore_state(intel_dp, old_crtc_state,
                                                      false);
index 8ee2d891558688b321259284d92ffd75405bcd23..7d098a8c994c2d5176a2fbe849a2d3c57d1b937e 100644 (file)
@@ -2937,24 +2937,94 @@ static bool downstream_hpd_needs_d0(struct intel_dp *intel_dp)
                intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
 }
 
-void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
-                                          const struct intel_crtc_state *crtc_state,
-                                          bool enable)
+static int
+write_dsc_decompression_flag(struct drm_dp_aux *aux, u8 flag, bool set)
 {
-       struct drm_i915_private *i915 = dp_to_i915(intel_dp);
-       int ret;
+       int err;
+       u8 val;
 
-       if (!crtc_state->dsc.compression_enable)
-               return;
+       err = drm_dp_dpcd_readb(aux, DP_DSC_ENABLE, &val);
+       if (err < 0)
+               return err;
 
-       ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_DSC_ENABLE,
-                                enable ? DP_DECOMPRESSION_EN : 0);
-       if (ret < 0)
+       if (set)
+               val |= flag;
+       else
+               val &= ~flag;
+
+       return drm_dp_dpcd_writeb(aux, DP_DSC_ENABLE, val);
+}
+
+static void
+intel_dp_sink_set_dsc_decompression(struct intel_connector *connector,
+                                   bool enable)
+{
+       struct drm_i915_private *i915 = to_i915(connector->base.dev);
+
+       if (write_dsc_decompression_flag(connector->dp.dsc_decompression_aux,
+                                        DP_DECOMPRESSION_EN, enable) < 0)
                drm_dbg_kms(&i915->drm,
                            "Failed to %s sink decompression state\n",
                            str_enable_disable(enable));
 }
 
+/**
+ * intel_dp_sink_enable_decompression - Enable DSC decompression in sink/last branch device
+ * @state: atomic state
+ * @connector: connector to enable the decompression for
+ * @new_crtc_state: new state for the CRTC driving @connector
+ *
+ * Enable the DSC decompression if required in the %DP_DSC_ENABLE DPCD
+ * register of the appropriate sink/branch device. On SST this is always the
+ * sink device, whereas on MST based on each device's DSC capabilities it's
+ * either the last branch device (enabling decompression in it) or both the
+ * last branch device (enabling passthrough in it) and the sink device
+ * (enabling decompression in it).
+ */
+void intel_dp_sink_enable_decompression(struct intel_atomic_state *state,
+                                       struct intel_connector *connector,
+                                       const struct intel_crtc_state *new_crtc_state)
+{
+       struct drm_i915_private *i915 = to_i915(state->base.dev);
+
+       if (!new_crtc_state->dsc.compression_enable)
+               return;
+
+       if (drm_WARN_ON(&i915->drm,
+                       !connector->dp.dsc_decompression_aux))
+               return;
+
+       /* TODO: Enable passthrough in the MST last branch device if needed. */
+       intel_dp_sink_set_dsc_decompression(connector, true);
+}
+
+/**
+ * intel_dp_sink_disable_decompression - Disable DSC decompression in sink/last branch device
+ * @state: atomic state
+ * @connector: connector to disable the decompression for
+ * @old_crtc_state: old state for the CRTC driving @connector
+ *
+ * Disable the DSC decompression if required in the %DP_DSC_ENABLE DPCD
+ * register of the appropriate sink/branch device, corresponding to the
+ * sequence in intel_dp_sink_enable_decompression().
+ */
+void intel_dp_sink_disable_decompression(struct intel_atomic_state *state,
+                                        struct intel_connector *connector,
+                                        const struct intel_crtc_state *old_crtc_state)
+{
+       struct drm_i915_private *i915 = to_i915(state->base.dev);
+
+       if (!old_crtc_state->dsc.compression_enable)
+               return;
+
+       if (drm_WARN_ON(&i915->drm,
+                       !connector->dp.dsc_decompression_aux))
+               return;
+
+       intel_dp_sink_set_dsc_decompression(connector, false);
+       /* TODO: Disable passthrough in the MST last branch device if needed. */
+}
+
 static void
 intel_edp_init_source_oui(struct intel_dp *intel_dp, bool careful)
 {
index 2080575fef69a6cfc1d018e81dad3af10d728148..7cc23d846dfbf64a1a537705515efff1c4bc4409 100644 (file)
@@ -57,9 +57,12 @@ int intel_dp_retrain_link(struct intel_encoder *encoder,
 void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode);
 void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
                                           const struct intel_crtc_state *crtc_state);
-void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
-                                          const struct intel_crtc_state *crtc_state,
-                                          bool enable);
+void intel_dp_sink_enable_decompression(struct intel_atomic_state *state,
+                                       struct intel_connector *connector,
+                                       const struct intel_crtc_state *new_crtc_state);
+void intel_dp_sink_disable_decompression(struct intel_atomic_state *state,
+                                        struct intel_connector *connector,
+                                        const struct intel_crtc_state *old_crtc_state);
 void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
 void intel_dp_encoder_shutdown(struct intel_encoder *intel_encoder);
 void intel_dp_encoder_flush_work(struct drm_encoder *encoder);
index eab69f57655d9796b44166254db011d9685df80f..bc992e77ffc7ad6bcb471d3cc03d0a70ce4bbebd 100644 (file)
@@ -782,7 +782,7 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state,
                 * TODO: disable decompression for all streams/in any MST ports, not
                 * only in the first downstream branch device.
                 */
-               intel_dp_sink_set_decompression_state(intel_dp, old_crtc_state, false);
+               intel_dp_sink_disable_decompression(state, connector, old_crtc_state);
 }
 
 static void intel_mst_post_disable_dp(struct intel_atomic_state *state,
@@ -944,7 +944,7 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state,
                 * TODO: enable decompression for all streams/in any MST ports, not
                 * only in the first downstream branch device.
                 */
-               intel_dp_sink_set_decompression_state(intel_dp, pipe_config, true);
+               intel_dp_sink_enable_decompression(state, connector, pipe_config);
                dig_port->base.pre_enable(state, &dig_port->base,
                                                pipe_config, NULL);
        }