/* DP DSC small joiner has 2 FIFOs each of 640 x 6 bytes */
 #define DP_DSC_MAX_SMALL_JOINER_RAM_BUFFER     61440
+#define DP_DSC_MIN_SUPPORTED_BPC               8
+#define DP_DSC_MAX_SUPPORTED_BPC               10
 
 /* DP DSC throughput values used for slice count calculations KPixels/s */
 #define DP_DSC_PEAK_PIXEL_RATE                 2720000
        int min_bpp, max_bpp;
 };
 
+static bool intel_dp_source_supports_dsc(struct intel_dp *intel_dp,
+                                        const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       /* FIXME: FEC needed for external DP until then reject DSC on DP */
+       if (!intel_dp_is_edp(intel_dp))
+               return false;
+
+       return INTEL_GEN(dev_priv) >= 10 &&
+               pipe_config->cpu_transcoder != TRANSCODER_A;
+}
+
+static bool intel_dp_supports_dsc(struct intel_dp *intel_dp,
+                                 const struct intel_crtc_state *pipe_config)
+{
+       return intel_dp_source_supports_dsc(intel_dp, pipe_config) &&
+               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)
 {
        return false;
 }
 
+static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc)
+{
+       int i, num_bpc;
+       u8 dsc_bpc[3] = {0};
+
+       num_bpc = drm_dp_dsc_sink_supported_input_bpcs(intel_dp->dsc_dpcd,
+                                                      dsc_bpc);
+       for (i = 0; i < num_bpc; i++) {
+               if (dsc_max_bpc >= dsc_bpc[i])
+                       return dsc_bpc[i] * 3;
+       }
+
+       return 0;
+}
+
+static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
+                                       struct intel_crtc_state *pipe_config,
+                                       struct drm_connector_state *conn_state,
+                                       struct link_config_limits *limits)
+{
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       u8 dsc_max_bpc;
+       int pipe_bpp;
+
+       if (!intel_dp_supports_dsc(intel_dp, pipe_config))
+               return false;
+
+       dsc_max_bpc = min_t(u8, DP_DSC_MAX_SUPPORTED_BPC,
+                           conn_state->max_requested_bpc);
+
+       pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, dsc_max_bpc);
+       if (pipe_bpp < DP_DSC_MIN_SUPPORTED_BPC * 3) {
+               DRM_DEBUG_KMS("No DSC support for less than 8bpc\n");
+               return false;
+       }
+
+       /*
+        * For now enable DSC for max bpp, max link rate, max lane count.
+        * Optimize this later for the minimum possible link rate/lane count
+        * with DSC enabled for the requested mode.
+        */
+       pipe_config->pipe_bpp = pipe_bpp;
+       pipe_config->port_clock = intel_dp->common_rates[limits->max_clock];
+       pipe_config->lane_count = limits->max_lane_count;
+
+       if (intel_dp_is_edp(intel_dp)) {
+               pipe_config->dsc_params.compressed_bpp =
+                       min_t(u16, drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4,
+                             pipe_config->pipe_bpp);
+               pipe_config->dsc_params.slice_count =
+                       drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
+                                                       true);
+       } else {
+               u16 dsc_max_output_bpp;
+               u8 dsc_dp_slice_count;
+
+               dsc_max_output_bpp =
+                       intel_dp_dsc_get_output_bpp(pipe_config->port_clock,
+                                                   pipe_config->lane_count,
+                                                   adjusted_mode->crtc_clock,
+                                                   adjusted_mode->crtc_hdisplay);
+               dsc_dp_slice_count =
+                       intel_dp_dsc_get_slice_count(intel_dp,
+                                                    adjusted_mode->crtc_clock,
+                                                    adjusted_mode->crtc_hdisplay);
+               if (!dsc_max_output_bpp || !dsc_dp_slice_count) {
+                       DRM_DEBUG_KMS("Compressed BPP/Slice Count not supported\n");
+                       return false;
+               }
+               pipe_config->dsc_params.compressed_bpp = min_t(u16,
+                                                              dsc_max_output_bpp >> 4,
+                                                              pipe_config->pipe_bpp);
+               pipe_config->dsc_params.slice_count = dsc_dp_slice_count;
+       }
+       /*
+        * VDSC engine operates at 1 Pixel per clock, so if peak pixel rate
+        * is greater than the maximum Cdclock and if slice count is even
+        * then we need to use 2 VDSC instances.
+        */
+       if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq) {
+               if (pipe_config->dsc_params.slice_count > 1) {
+                       pipe_config->dsc_params.dsc_split = true;
+               } else {
+                       DRM_DEBUG_KMS("Cannot split stream to use 2 VDSC instances\n");
+                       return false;
+               }
+       }
+       pipe_config->dsc_params.compression_enable = true;
+       DRM_DEBUG_KMS("DP DSC computed with Input Bpp = %d "
+                     "Compressed Bpp = %d Slice Count = %d\n",
+                     pipe_config->pipe_bpp,
+                     pipe_config->dsc_params.compressed_bpp,
+                     pipe_config->dsc_params.slice_count);
+
+       return true;
+}
+
 static bool
 intel_dp_compute_link_config(struct intel_encoder *encoder,
-                            struct intel_crtc_state *pipe_config)
+                            struct intel_crtc_state *pipe_config,
+                            struct drm_connector_state *conn_state)
 {
        struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        struct link_config_limits limits;
        int common_len;
+       bool ret;
 
        common_len = intel_dp_common_len_rate_limit(intel_dp,
                                                    intel_dp->max_link_rate);
                      intel_dp->common_rates[limits.max_clock],
                      limits.max_bpp, adjusted_mode->crtc_clock);
 
-       if (intel_dp_is_edp(intel_dp)) {
+       if (intel_dp_is_edp(intel_dp))
                /*
                 * Optimize for fast and narrow. eDP 1.3 section 3.3 and eDP 1.4
                 * section A.1: "It is recommended that the minimum number of
                 * Note that we use the max clock and lane count for eDP 1.3 and
                 * earlier, and fast vs. wide is irrelevant.
                 */
-               if (!intel_dp_compute_link_config_fast(intel_dp, pipe_config,
-                                                      &limits))
-                       return false;
-       } else {
+               ret = intel_dp_compute_link_config_fast(intel_dp, pipe_config,
+                                                       &limits);
+       else
                /* Optimize for slow and wide. */
-               if (!intel_dp_compute_link_config_wide(intel_dp, pipe_config,
-                                                      &limits))
+               ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config,
+                                                       &limits);
+
+       /* enable compression if the mode doesn't fit available BW */
+       if (!ret) {
+               if (!intel_dp_dsc_compute_config(intel_dp, pipe_config,
+                                                conn_state, &limits))
                        return false;
        }
 
-       DRM_DEBUG_KMS("DP lane count %d clock %d bpp %d\n",
-                     pipe_config->lane_count, pipe_config->port_clock,
-                     pipe_config->pipe_bpp);
+       if (pipe_config->dsc_params.compression_enable) {
+               DRM_DEBUG_KMS("DP lane count %d clock %d Input bpp %d Compressed bpp %d\n",
+                             pipe_config->lane_count, pipe_config->port_clock,
+                             pipe_config->pipe_bpp,
+                             pipe_config->dsc_params.compressed_bpp);
 
-       DRM_DEBUG_KMS("DP link rate required %i available %i\n",
-                     intel_dp_link_required(adjusted_mode->crtc_clock,
-                                            pipe_config->pipe_bpp),
-                     intel_dp_max_data_rate(pipe_config->port_clock,
-                                            pipe_config->lane_count));
+               DRM_DEBUG_KMS("DP link rate required %i available %i\n",
+                             intel_dp_link_required(adjusted_mode->crtc_clock,
+                                                    pipe_config->dsc_params.compressed_bpp),
+                             intel_dp_max_data_rate(pipe_config->port_clock,
+                                                    pipe_config->lane_count));
+       } else {
+               DRM_DEBUG_KMS("DP lane count %d clock %d bpp %d\n",
+                             pipe_config->lane_count, pipe_config->port_clock,
+                             pipe_config->pipe_bpp);
 
+               DRM_DEBUG_KMS("DP link rate required %i available %i\n",
+                             intel_dp_link_required(adjusted_mode->crtc_clock,
+                                                    pipe_config->pipe_bpp),
+                             intel_dp_max_data_rate(pipe_config->port_clock,
+                                                    pipe_config->lane_count));
+       }
        return true;
 }
 
        if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
                return false;
 
-       if (!intel_dp_compute_link_config(encoder, pipe_config))
+       if (!intel_dp_compute_link_config(encoder, pipe_config, conn_state))
                return false;
 
        if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) {
                        intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_LIMITED;
        }
 
-       intel_link_compute_m_n(pipe_config->pipe_bpp, pipe_config->lane_count,
-                              adjusted_mode->crtc_clock,
-                              pipe_config->port_clock,
-                              &pipe_config->dp_m_n,
-                              constant_n);
+       if (!pipe_config->dsc_params.compression_enable)
+               intel_link_compute_m_n(pipe_config->pipe_bpp,
+                                      pipe_config->lane_count,
+                                      adjusted_mode->crtc_clock,
+                                      pipe_config->port_clock,
+                                      &pipe_config->dp_m_n,
+                                      constant_n);
+       else
+               intel_link_compute_m_n(pipe_config->dsc_params.compression_enable,
+                                      pipe_config->lane_count,
+                                      adjusted_mode->crtc_clock,
+                                      pipe_config->port_clock,
+                                      &pipe_config->dp_m_n,
+                                      constant_n);
 
        if (intel_connector->panel.downclock_mode != NULL &&
                dev_priv->drrs.type == SEAMLESS_DRRS_SUPPORT) {