Merge tag 'drm-intel-next-2015-02-27' of git://anongit.freedesktop.org/drm-intel...
[cascardo/linux.git] / drivers / gpu / drm / i915 / intel_dp.c
index 5cecc20..d1141d3 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
@@ -239,7 +240,7 @@ uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes)
        return v;
 }
 
-void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
+static void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
 {
        int i;
        if (dst_bytes > 4)
@@ -1074,7 +1075,7 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector)
 }
 
 static void
-skl_edp_set_pll_config(struct intel_crtc_config *pipe_config, int link_bw)
+skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_bw)
 {
        u32 ctrl1;
 
@@ -1101,7 +1102,7 @@ skl_edp_set_pll_config(struct intel_crtc_config *pipe_config, int link_bw)
 }
 
 static void
-hsw_dp_set_ddi_pll_sel(struct intel_crtc_config *pipe_config, int link_bw)
+hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config, int link_bw)
 {
        switch (link_bw) {
        case DP_LINK_BW_1_62:
@@ -1118,7 +1119,7 @@ hsw_dp_set_ddi_pll_sel(struct intel_crtc_config *pipe_config, int link_bw)
 
 static void
 intel_dp_set_clock(struct intel_encoder *encoder,
-                  struct intel_crtc_config *pipe_config, int link_bw)
+                  struct intel_crtc_state *pipe_config, int link_bw)
 {
        struct drm_device *dev = encoder->base.dev;
        const struct dp_link_dpll *divisor = NULL;
@@ -1151,11 +1152,11 @@ intel_dp_set_clock(struct intel_encoder *encoder,
 
 bool
 intel_dp_compute_config(struct intel_encoder *encoder,
-                       struct intel_crtc_config *pipe_config)
+                       struct intel_crtc_state *pipe_config)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        enum port port = dp_to_dig_port(intel_dp)->port;
        struct intel_crtc *intel_crtc = encoder->new_crtc;
@@ -1269,7 +1270,7 @@ found:
                               &pipe_config->dp_m_n);
 
        if (intel_connector->panel.downclock_mode != NULL &&
-               intel_dp->drrs_state.type == SEAMLESS_DRRS_SUPPORT) {
+               dev_priv->drrs.type == SEAMLESS_DRRS_SUPPORT) {
                        pipe_config->has_drrs = true;
                        intel_link_compute_m_n(bpp, lane_count,
                                intel_connector->panel.downclock_mode->clock,
@@ -1295,11 +1296,12 @@ static void ironlake_set_pll_cpu_edp(struct intel_dp *intel_dp)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 dpa_ctl;
 
-       DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", crtc->config.port_clock);
+       DRM_DEBUG_KMS("eDP PLL enable for clock %d\n",
+                     crtc->config->port_clock);
        dpa_ctl = I915_READ(DP_A);
        dpa_ctl &= ~DP_PLL_FREQ_MASK;
 
-       if (crtc->config.port_clock == 162000) {
+       if (crtc->config->port_clock == 162000) {
                /* For a long time we've carried around a ILK-DevA w/a for the
                 * 160MHz clock. If we're really unlucky, it's still required.
                 */
@@ -1324,7 +1326,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        enum port port = dp_to_dig_port(intel_dp)->port;
        struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-       struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
+       struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
 
        /*
         * There are four kinds of DP registers:
@@ -1352,7 +1354,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
        intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
        intel_dp->DP |= DP_PORT_WIDTH(intel_dp->lane_count);
 
-       if (crtc->config.has_audio)
+       if (crtc->config->has_audio)
                intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
 
        /* Split out the IBX/CPU vs CPT settings */
@@ -1558,7 +1560,7 @@ void intel_edp_panel_vdd_on(struct intel_dp *intel_dp)
        vdd = edp_panel_vdd_on(intel_dp);
        pps_unlock(intel_dp);
 
-       WARN(!vdd, "eDP port %c VDD already requested on\n",
+       I915_STATE_WARN(!vdd, "eDP port %c VDD already requested on\n",
             port_name(dp_to_dig_port(intel_dp)->port));
 }
 
@@ -1642,7 +1644,7 @@ static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
        if (!is_edp(intel_dp))
                return;
 
-       WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on",
+       I915_STATE_WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on",
             port_name(dp_to_dig_port(intel_dp)->port));
 
        intel_dp->want_panel_vdd = false;
@@ -2013,7 +2015,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
 }
 
 static void intel_dp_get_config(struct intel_encoder *encoder,
-                               struct intel_crtc_config *pipe_config)
+                               struct intel_crtc_state *pipe_config)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        u32 tmp, flags = 0;
@@ -2050,7 +2052,7 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
                        flags |= DRM_MODE_FLAG_NVSYNC;
        }
 
-       pipe_config->adjusted_mode.flags |= flags;
+       pipe_config->base.adjusted_mode.flags |= flags;
 
        if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev) &&
            tmp & DP_COLOR_RANGE_16_235)
@@ -2073,7 +2075,7 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
        if (HAS_PCH_SPLIT(dev_priv->dev) && port != PORT_A)
                ironlake_check_encoder_dotclock(pipe_config, dotclock);
 
-       pipe_config->adjusted_mode.crtc_clock = dotclock;
+       pipe_config->base.adjusted_mode.crtc_clock = dotclock;
 
        if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp &&
            pipe_config->pipe_bpp > dev_priv->vbt.edp_bpp) {
@@ -2102,9 +2104,12 @@ static void intel_disable_dp(struct intel_encoder *encoder)
        struct drm_device *dev = encoder->base.dev;
        struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
 
-       if (crtc->config.has_audio)
+       if (crtc->config->has_audio)
                intel_audio_codec_disable(encoder);
 
+       if (HAS_PSR(dev) && !HAS_DDI(dev))
+               intel_psr_disable(intel_dp);
+
        /* Make sure the panel is off before trying to change the mode. But also
         * ensure that we have vdd while we switch off the panel. */
        intel_edp_panel_vdd_on(intel_dp);
@@ -2309,7 +2314,7 @@ static void intel_enable_dp(struct intel_encoder *encoder)
        intel_dp_complete_link_train(intel_dp);
        intel_dp_stop_link_train(intel_dp);
 
-       if (crtc->config.has_audio) {
+       if (crtc->config->has_audio) {
                DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
                                 pipe_name(crtc->pipe));
                intel_audio_codec_enable(encoder);
@@ -2329,6 +2334,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
        intel_edp_backlight_on(intel_dp);
+       intel_psr_enable(intel_dp);
 }
 
 static void g4x_pre_enable_dp(struct intel_encoder *encoder)
@@ -2685,11 +2691,14 @@ static uint8_t
 intel_dp_voltage_max(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct drm_i915_private *dev_priv = dev->dev_private;
        enum port port = dp_to_dig_port(intel_dp)->port;
 
-       if (INTEL_INFO(dev)->gen >= 9)
+       if (INTEL_INFO(dev)->gen >= 9) {
+               if (dev_priv->vbt.edp_low_vswing && port == PORT_A)
+                       return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
                return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
-       else if (IS_VALLEYVIEW(dev))
+       else if (IS_VALLEYVIEW(dev))
                return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
        else if (IS_GEN7(dev) && port == PORT_A)
                return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
@@ -2713,6 +2722,8 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
                        return DP_TRAIN_PRE_EMPH_LEVEL_2;
                case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
                        return DP_TRAIN_PRE_EMPH_LEVEL_1;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
                default:
                        return DP_TRAIN_PRE_EMPH_LEVEL_0;
                }
@@ -3195,6 +3206,9 @@ intel_hsw_signal_levels(uint8_t train_set)
                return DDI_BUF_TRANS_SELECT(7);
        case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
                return DDI_BUF_TRANS_SELECT(8);
+
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               return DDI_BUF_TRANS_SELECT(9);
        default:
                DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
                              "0x%x\n", signal_levels);
@@ -3515,8 +3529,6 @@ intel_dp_link_down(struct intel_dp *intel_dp)
        enum port port = intel_dig_port->port;
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc =
-               to_intel_crtc(intel_dig_port->base.base.crtc);
        uint32_t DP = intel_dp->DP;
 
        if (WARN_ON(HAS_DDI(dev)))
@@ -3541,8 +3553,6 @@ intel_dp_link_down(struct intel_dp *intel_dp)
 
        if (HAS_PCH_IBX(dev) &&
            I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
-               struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
-
                /* Hardware workaround: leaving our transcoder select
                 * set to transcoder B while it's off will prevent the
                 * corresponding HDMI output on transcoder A.
@@ -3553,18 +3563,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
                 */
                DP &= ~DP_PIPEB_SELECT;
                I915_WRITE(intel_dp->output_reg, DP);
-
-               /* Changes to enable or select take place the vblank
-                * after being written.
-                */
-               if (WARN_ON(crtc == NULL)) {
-                       /* We should never try to disable a port without a crtc
-                        * attached. For paranoia keep the code around for a
-                        * bit. */
-                       POSTING_READ(intel_dp->output_reg);
-                       msleep(50);
-               } else
-                       intel_wait_for_vblank(dev, intel_crtc->pipe);
+               POSTING_READ(intel_dp->output_reg);
        }
 
        DP &= ~DP_AUDIO_OUTPUT_ENABLE;
@@ -3769,7 +3768,7 @@ go_again:
                                intel_dp_stop_link_train(intel_dp);
                        }
 
-                       DRM_DEBUG_KMS("got esi %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+                       DRM_DEBUG_KMS("got esi %3ph\n", esi);
                        ret = drm_dp_mst_hpd_irq(&intel_dp->mst_mgr, esi, &handled);
 
                        if (handled) {
@@ -3785,7 +3784,7 @@ go_again:
 
                                bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
                                if (bret == true) {
-                                       DRM_DEBUG_KMS("got esi2 %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+                                       DRM_DEBUG_KMS("got esi2 %3ph\n", esi);
                                        goto go_again;
                                }
                        } else
@@ -3812,7 +3811,7 @@ go_again:
  *  3. Use Link Training from 2.5.3.3 and 3.5.1.3
  *  4. Check link status on receipt of hot-plug interrupt
  */
-void
+static void
 intel_dp_check_link_status(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -4306,7 +4305,6 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
 
        drm_dp_aux_unregister(&intel_dp->aux);
        intel_dp_mst_encoder_cleanup(intel_dig_port);
-       drm_encoder_cleanup(encoder);
        if (is_edp(intel_dp)) {
                cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
                /*
@@ -4322,6 +4320,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
                        intel_dp->edp_notifier.notifier_call = NULL;
                }
        }
+       drm_encoder_cleanup(encoder);
        kfree(intel_dig_port);
 }
 
@@ -4396,7 +4395,9 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
        .force = intel_dp_force,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_dp_set_property,
+       .atomic_get_property = intel_connector_atomic_get_property,
        .destroy = intel_dp_connector_destroy,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
@@ -4416,7 +4417,7 @@ intel_dp_hot_plug(struct intel_encoder *intel_encoder)
        return;
 }
 
-bool
+enum irqreturn
 intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 {
        struct intel_dp *intel_dp = &intel_dig_port->dp;
@@ -4424,7 +4425,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum intel_display_power_domain power_domain;
-       bool ret = true;
+       enum irqreturn ret = IRQ_NONE;
 
        if (intel_dig_port->base.type != INTEL_OUTPUT_EDP)
                intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
@@ -4438,7 +4439,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
                 */
                DRM_DEBUG_KMS("ignoring long hpd on eDP port %c\n",
                              port_name(intel_dig_port->port));
-               return false;
+               return IRQ_HANDLED;
        }
 
        DRM_DEBUG_KMS("got hpd irq on port %c - %s\n",
@@ -4483,7 +4484,9 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
                        drm_modeset_unlock(&dev->mode_config.connection_mutex);
                }
        }
-       ret = false;
+
+       ret = IRQ_HANDLED;
+
        goto put_power;
 mst_fail:
        /* if we were in MST mode, and device is not there get out of MST mode */
@@ -4741,39 +4744,46 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
                      I915_READ(pp_div_reg));
 }
 
-void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
+/**
+ * intel_dp_set_drrs_state - program registers for RR switch to take effect
+ * @dev: DRM device
+ * @refresh_rate: RR to be programmed
+ *
+ * This function gets called when refresh rate (RR) has to be changed from
+ * one frequency to another. Switches can be between high and low RR
+ * supported by the panel or to any other RR based on media playback (in
+ * this case, RR value needs to be passed from user space).
+ *
+ * The caller of this function needs to take a lock on dev_priv->drrs.
+ */
+static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_encoder *encoder;
-       struct intel_dp *intel_dp = NULL;
-       struct intel_crtc_config *config = NULL;
+       struct intel_digital_port *dig_port = NULL;
+       struct intel_dp *intel_dp = dev_priv->drrs.dp;
+       struct intel_crtc_state *config = NULL;
        struct intel_crtc *intel_crtc = NULL;
-       struct intel_connector *intel_connector = dev_priv->drrs.connector;
        u32 reg, val;
-       enum edp_drrs_refresh_rate_type index = DRRS_HIGH_RR;
+       enum drrs_refresh_rate_type index = DRRS_HIGH_RR;
 
        if (refresh_rate <= 0) {
                DRM_DEBUG_KMS("Refresh rate should be positive non-zero.\n");
                return;
        }
 
-       if (intel_connector == NULL) {
-               DRM_DEBUG_KMS("DRRS supported for eDP only.\n");
+       if (intel_dp == NULL) {
+               DRM_DEBUG_KMS("DRRS not supported.\n");
                return;
        }
 
        /*
-        * FIXME: This needs proper synchronization with psr state. But really
-        * hard to tell without seeing the user of this function of this code.
-        * Check locking and ordering once that lands.
+        * FIXME: This needs proper synchronization with psr state for some
+        * platforms that cannot have PSR and DRRS enabled at the same time.
         */
-       if (INTEL_INFO(dev)->gen < 8 && intel_psr_is_enabled(dev)) {
-               DRM_DEBUG_KMS("DRRS is disabled as PSR is enabled\n");
-               return;
-       }
 
-       encoder = intel_attached_encoder(&intel_connector->base);
-       intel_dp = enc_to_intel_dp(&encoder->base);
+       dig_port = dp_to_dig_port(intel_dp);
+       encoder = &dig_port->base;
        intel_crtc = encoder->new_crtc;
 
        if (!intel_crtc) {
@@ -4781,17 +4791,18 @@ void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
                return;
        }
 
-       config = &intel_crtc->config;
+       config = intel_crtc->config;
 
-       if (intel_dp->drrs_state.type < SEAMLESS_DRRS_SUPPORT) {
+       if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) {
                DRM_DEBUG_KMS("Only Seamless DRRS supported.\n");
                return;
        }
 
-       if (intel_connector->panel.downclock_mode->vrefresh == refresh_rate)
+       if (intel_dp->attached_connector->panel.downclock_mode->vrefresh ==
+                       refresh_rate)
                index = DRRS_LOW_RR;
 
-       if (index == intel_dp->drrs_state.refresh_rate_type) {
+       if (index == dev_priv->drrs.refresh_rate_type) {
                DRM_DEBUG_KMS(
                        "DRRS requested for previously set RR...ignoring\n");
                return;
@@ -4802,42 +4813,267 @@ void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
                return;
        }
 
-       if (INTEL_INFO(dev)->gen > 6 && INTEL_INFO(dev)->gen < 8) {
-               reg = PIPECONF(intel_crtc->config.cpu_transcoder);
+       if (INTEL_INFO(dev)->gen >= 8 && !IS_CHERRYVIEW(dev)) {
+               switch (index) {
+               case DRRS_HIGH_RR:
+                       intel_dp_set_m_n(intel_crtc, M1_N1);
+                       break;
+               case DRRS_LOW_RR:
+                       intel_dp_set_m_n(intel_crtc, M2_N2);
+                       break;
+               case DRRS_MAX_RR:
+               default:
+                       DRM_ERROR("Unsupported refreshrate type\n");
+               }
+       } else if (INTEL_INFO(dev)->gen > 6) {
+               reg = PIPECONF(intel_crtc->config->cpu_transcoder);
                val = I915_READ(reg);
+
                if (index > DRRS_HIGH_RR) {
-                       val |= PIPECONF_EDP_RR_MODE_SWITCH;
-                       intel_dp_set_m_n(intel_crtc);
+                       if (IS_VALLEYVIEW(dev))
+                               val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
+                       else
+                               val |= PIPECONF_EDP_RR_MODE_SWITCH;
                } else {
-                       val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
+                       if (IS_VALLEYVIEW(dev))
+                               val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV;
+                       else
+                               val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
                }
                I915_WRITE(reg, val);
        }
 
+       dev_priv->drrs.refresh_rate_type = index;
+
+       DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
+}
+
+/**
+ * intel_edp_drrs_enable - init drrs struct if supported
+ * @intel_dp: DP struct
+ *
+ * Initializes frontbuffer_bits and drrs.dp
+ */
+void intel_edp_drrs_enable(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct drm_crtc *crtc = dig_port->base.base.crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       if (!intel_crtc->config->has_drrs) {
+               DRM_DEBUG_KMS("Panel doesn't support DRRS\n");
+               return;
+       }
+
+       mutex_lock(&dev_priv->drrs.mutex);
+       if (WARN_ON(dev_priv->drrs.dp)) {
+               DRM_ERROR("DRRS already enabled\n");
+               goto unlock;
+       }
+
+       dev_priv->drrs.busy_frontbuffer_bits = 0;
+
+       dev_priv->drrs.dp = intel_dp;
+
+unlock:
+       mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+/**
+ * intel_edp_drrs_disable - Disable DRRS
+ * @intel_dp: DP struct
+ *
+ */
+void intel_edp_drrs_disable(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct drm_crtc *crtc = dig_port->base.base.crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       if (!intel_crtc->config->has_drrs)
+               return;
+
+       mutex_lock(&dev_priv->drrs.mutex);
+       if (!dev_priv->drrs.dp) {
+               mutex_unlock(&dev_priv->drrs.mutex);
+               return;
+       }
+
+       if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
+               intel_dp_set_drrs_state(dev_priv->dev,
+                       intel_dp->attached_connector->panel.
+                       fixed_mode->vrefresh);
+
+       dev_priv->drrs.dp = NULL;
+       mutex_unlock(&dev_priv->drrs.mutex);
+
+       cancel_delayed_work_sync(&dev_priv->drrs.work);
+}
+
+static void intel_edp_drrs_downclock_work(struct work_struct *work)
+{
+       struct drm_i915_private *dev_priv =
+               container_of(work, typeof(*dev_priv), drrs.work.work);
+       struct intel_dp *intel_dp;
+
+       mutex_lock(&dev_priv->drrs.mutex);
+
+       intel_dp = dev_priv->drrs.dp;
+
+       if (!intel_dp)
+               goto unlock;
+
        /*
-        * mutex taken to ensure that there is no race between differnt
-        * drrs calls trying to update refresh rate. This scenario may occur
-        * in future when idleness detection based DRRS in kernel and
-        * possible calls from user space to set differnt RR are made.
+        * The delayed work can race with an invalidate hence we need to
+        * recheck.
         */
 
-       mutex_lock(&intel_dp->drrs_state.mutex);
+       if (dev_priv->drrs.busy_frontbuffer_bits)
+               goto unlock;
 
-       intel_dp->drrs_state.refresh_rate_type = index;
+       if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR)
+               intel_dp_set_drrs_state(dev_priv->dev,
+                       intel_dp->attached_connector->panel.
+                       downclock_mode->vrefresh);
 
-       mutex_unlock(&intel_dp->drrs_state.mutex);
+unlock:
 
-       DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
+       mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+/**
+ * intel_edp_drrs_invalidate - Invalidate DRRS
+ * @dev: DRM device
+ * @frontbuffer_bits: frontbuffer plane tracking bits
+ *
+ * When there is a disturbance on screen (due to cursor movement/time
+ * update etc), DRRS needs to be invalidated, i.e. need to switch to
+ * high RR.
+ *
+ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
+ */
+void intel_edp_drrs_invalidate(struct drm_device *dev,
+               unsigned frontbuffer_bits)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc;
+       enum pipe pipe;
+
+       if (!dev_priv->drrs.dp)
+               return;
+
+       mutex_lock(&dev_priv->drrs.mutex);
+       crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
+       pipe = to_intel_crtc(crtc)->pipe;
+
+       if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) {
+               cancel_delayed_work_sync(&dev_priv->drrs.work);
+               intel_dp_set_drrs_state(dev_priv->dev,
+                               dev_priv->drrs.dp->attached_connector->panel.
+                               fixed_mode->vrefresh);
+       }
+
+       frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
+
+       dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
+       mutex_unlock(&dev_priv->drrs.mutex);
 }
 
+/**
+ * intel_edp_drrs_flush - Flush DRRS
+ * @dev: DRM device
+ * @frontbuffer_bits: frontbuffer plane tracking bits
+ *
+ * When there is no movement on screen, DRRS work can be scheduled.
+ * This DRRS work is responsible for setting relevant registers after a
+ * timeout of 1 second.
+ *
+ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
+ */
+void intel_edp_drrs_flush(struct drm_device *dev,
+               unsigned frontbuffer_bits)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc;
+       enum pipe pipe;
+
+       if (!dev_priv->drrs.dp)
+               return;
+
+       mutex_lock(&dev_priv->drrs.mutex);
+       crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
+       pipe = to_intel_crtc(crtc)->pipe;
+       dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
+
+       cancel_delayed_work_sync(&dev_priv->drrs.work);
+
+       if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR &&
+                       !dev_priv->drrs.busy_frontbuffer_bits)
+               schedule_delayed_work(&dev_priv->drrs.work,
+                               msecs_to_jiffies(1000));
+       mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+/**
+ * DOC: Display Refresh Rate Switching (DRRS)
+ *
+ * Display Refresh Rate Switching (DRRS) is a power conservation feature
+ * which enables swtching between low and high refresh rates,
+ * dynamically, based on the usage scenario. This feature is applicable
+ * for internal panels.
+ *
+ * Indication that the panel supports DRRS is given by the panel EDID, which
+ * would list multiple refresh rates for one resolution.
+ *
+ * DRRS is of 2 types - static and seamless.
+ * Static DRRS involves changing refresh rate (RR) by doing a full modeset
+ * (may appear as a blink on screen) and is used in dock-undock scenario.
+ * Seamless DRRS involves changing RR without any visual effect to the user
+ * and can be used during normal system usage. This is done by programming
+ * certain registers.
+ *
+ * Support for static/seamless DRRS may be indicated in the VBT based on
+ * inputs from the panel spec.
+ *
+ * DRRS saves power by switching to low RR based on usage scenarios.
+ *
+ * eDP DRRS:-
+ *        The implementation is based on frontbuffer tracking implementation.
+ * When there is a disturbance on the screen triggered by user activity or a
+ * periodic system activity, DRRS is disabled (RR is changed to high RR).
+ * When there is no movement on screen, after a timeout of 1 second, a switch
+ * to low RR is made.
+ *        For integration with frontbuffer tracking code,
+ * intel_edp_drrs_invalidate() and intel_edp_drrs_flush() are called.
+ *
+ * DRRS can be further extended to support other internal panels and also
+ * the scenario of video playback wherein RR is set based on the rate
+ * requested by userspace.
+ */
+
+/**
+ * intel_dp_drrs_init - Init basic DRRS work and mutex.
+ * @intel_connector: eDP connector
+ * @fixed_mode: preferred mode of panel
+ *
+ * This function is  called only once at driver load to initialize basic
+ * DRRS stuff.
+ *
+ * Returns:
+ * Downclock mode if panel supports it, else return NULL.
+ * DRRS support is determined by the presence of downclock mode (apart
+ * from VBT setting).
+ */
 static struct drm_display_mode *
-intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
-                       struct intel_connector *intel_connector,
-                       struct drm_display_mode *fixed_mode)
+intel_dp_drrs_init(struct intel_connector *intel_connector,
+               struct drm_display_mode *fixed_mode)
 {
        struct drm_connector *connector = &intel_connector->base;
-       struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_display_mode *downclock_mode = NULL;
 
@@ -4855,17 +5091,17 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
                                        (dev, fixed_mode, connector);
 
        if (!downclock_mode) {
-               DRM_DEBUG_KMS("DRRS not supported\n");
+               DRM_DEBUG_KMS("Downclock mode is not found. DRRS not supported\n");
                return NULL;
        }
 
-       dev_priv->drrs.connector = intel_connector;
+       INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work);
 
-       mutex_init(&intel_dp->drrs_state.mutex);
+       mutex_init(&dev_priv->drrs.mutex);
 
-       intel_dp->drrs_state.type = dev_priv->vbt.drrs_type;
+       dev_priv->drrs.type = dev_priv->vbt.drrs_type;
 
-       intel_dp->drrs_state.refresh_rate_type = DRRS_HIGH_RR;
+       dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR;
        DRM_DEBUG_KMS("seamless DRRS supported for eDP panel.\n");
        return downclock_mode;
 }
@@ -4885,7 +5121,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        struct edid *edid;
        enum pipe pipe = INVALID_PIPE;
 
-       intel_dp->drrs_state.type = DRRS_NOT_SUPPORTED;
+       dev_priv->drrs.type = DRRS_NOT_SUPPORTED;
 
        if (!is_edp(intel_dp))
                return true;
@@ -4934,7 +5170,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
                if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
                        fixed_mode = drm_mode_duplicate(dev, scan);
                        downclock_mode = intel_dp_drrs_init(
-                                               intel_dig_port,
                                                intel_connector, fixed_mode);
                        break;
                }
@@ -5086,7 +5321,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        intel_dp_aux_init(intel_dp, intel_connector);
 
        /* init MST on ports that can support it */
-       if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9) {
                if (port == PORT_B || port == PORT_C || port == PORT_D) {
                        intel_dp_mst_encoder_init(intel_dig_port,
                                                  intel_connector->base.base.id);