*
  */
 
+#include <drm/drm_scdc_helper.h>
 #include "i915_drv.h"
 #include "intel_drv.h"
 
        return connector;
 }
 
+static int modeset_pipe(struct drm_crtc *crtc,
+                       struct drm_modeset_acquire_ctx *ctx)
+{
+       struct drm_atomic_state *state;
+       struct drm_crtc_state *crtc_state;
+       int ret;
+
+       state = drm_atomic_state_alloc(crtc->dev);
+       if (!state)
+               return -ENOMEM;
+
+       state->acquire_ctx = ctx;
+
+       crtc_state = drm_atomic_get_crtc_state(state, crtc);
+       if (IS_ERR(crtc_state)) {
+               ret = PTR_ERR(crtc_state);
+               goto out;
+       }
+
+       crtc_state->mode_changed = true;
+
+       ret = drm_atomic_add_affected_connectors(state, crtc);
+       if (ret)
+               goto out;
+
+       ret = drm_atomic_add_affected_planes(state, crtc);
+       if (ret)
+               goto out;
+
+       ret = drm_atomic_commit(state);
+       if (ret)
+               goto out;
+
+       return 0;
+
+ out:
+       drm_atomic_state_put(state);
+
+       return ret;
+}
+
+static int intel_hdmi_reset_link(struct intel_encoder *encoder,
+                                struct drm_modeset_acquire_ctx *ctx)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_hdmi *hdmi = enc_to_intel_hdmi(&encoder->base);
+       struct intel_connector *connector = hdmi->attached_connector;
+       struct i2c_adapter *adapter =
+               intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
+       struct drm_connector_state *conn_state;
+       struct intel_crtc_state *crtc_state;
+       struct intel_crtc *crtc;
+       u8 config;
+       int ret;
+
+       if (!connector || connector->base.status != connector_status_connected)
+               return 0;
+
+       ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
+                              ctx);
+       if (ret)
+               return ret;
+
+       conn_state = connector->base.state;
+
+       crtc = to_intel_crtc(conn_state->crtc);
+       if (!crtc)
+               return 0;
+
+       ret = drm_modeset_lock(&crtc->base.mutex, ctx);
+       if (ret)
+               return ret;
+
+       crtc_state = to_intel_crtc_state(crtc->base.state);
+
+       WARN_ON(!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI));
+
+       if (!crtc_state->base.active)
+               return 0;
+
+       if (!crtc_state->hdmi_high_tmds_clock_ratio &&
+           !crtc_state->hdmi_scrambling)
+               return 0;
+
+       if (conn_state->commit &&
+           !try_wait_for_completion(&conn_state->commit->hw_done))
+               return 0;
+
+       ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
+       if (ret < 0) {
+               DRM_ERROR("Failed to read TMDS config: %d\n", ret);
+               return 0;
+       }
+
+       if (!!(config & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40) ==
+           crtc_state->hdmi_high_tmds_clock_ratio &&
+           !!(config & SCDC_SCRAMBLING_ENABLE) ==
+           crtc_state->hdmi_scrambling)
+               return 0;
+
+       /*
+        * HDMI 2.0 says that one should not send scrambled data
+        * prior to configuring the sink scrambling, and that
+        * TMDS clock/data transmission should be suspended when
+        * changing the TMDS clock rate in the sink. So let's
+        * just do a full modeset here, even though some sinks
+        * would be perfectly happy if were to just reconfigure
+        * the SCDC settings on the fly.
+        */
+       return modeset_pipe(&crtc->base, ctx);
+}
+
+static bool intel_ddi_hotplug(struct intel_encoder *encoder,
+                             struct intel_connector *connector)
+{
+       struct drm_modeset_acquire_ctx ctx;
+       bool changed;
+       int ret;
+
+       changed = intel_encoder_hotplug(encoder, connector);
+
+       drm_modeset_acquire_init(&ctx, 0);
+
+       for (;;) {
+               ret = intel_hdmi_reset_link(encoder, &ctx);
+
+               if (ret == -EDEADLK) {
+                       drm_modeset_backoff(&ctx);
+                       continue;
+               }
+
+               break;
+       }
+
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+       WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
+
+       return changed;
+}
+
 static struct intel_connector *
 intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
 {
        drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
                         DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
 
+       if (init_hdmi)
+               intel_encoder->hotplug = intel_ddi_hotplug;
+       else
+               intel_encoder->hotplug = intel_encoder_hotplug;
        intel_encoder->compute_output_type = intel_ddi_compute_output_type;
        intel_encoder->compute_config = intel_ddi_compute_config;
        intel_encoder->enable = intel_enable_ddi;
 
        intel_runtime_pm_put(dev_priv);
 }
 
-static bool intel_hpd_irq_event(struct drm_device *dev,
-                               struct drm_connector *connector)
+bool intel_encoder_hotplug(struct intel_encoder *encoder,
+                          struct intel_connector *connector)
 {
+       struct drm_device *dev = connector->base.dev;
        enum drm_connector_status old_status;
 
        WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
-       old_status = connector->status;
+       old_status = connector->base.status;
 
-       connector->status = drm_helper_probe_detect(connector, NULL, false);
+       connector->base.status =
+               drm_helper_probe_detect(&connector->base, NULL, false);
 
-       if (old_status == connector->status)
+       if (old_status == connector->base.status)
                return false;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
-                     connector->base.id,
-                     connector->name,
+                     connector->base.base.id,
+                     connector->base.name,
                      drm_get_connector_status_name(old_status),
-                     drm_get_connector_status_name(connector->status));
+                     drm_get_connector_status_name(connector->base.status));
 
        return true;
 }
                if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) {
                        DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n",
                                      connector->name, intel_encoder->hpd_pin);
-                       if (intel_encoder->hot_plug)
-                               intel_encoder->hot_plug(intel_encoder);
-                       if (intel_hpd_irq_event(dev, connector))
-                               changed = true;
+
+                       changed |= intel_encoder->hotplug(intel_encoder,
+                                                         intel_connector);
                }
        }
        drm_connector_list_iter_end(&conn_iter);