struct dcb_entry *dcb;
        int or;
 
+       /* different to drm_encoder.crtc, this reflects what's
+        * actually programmed on the hw, not the proposed crtc */
+       struct drm_crtc *crtc;
+
        struct drm_display_mode mode;
        int last_dpms;
 
        struct nv04_output_reg restore;
 
-       void (*disconnect)(struct nouveau_encoder *encoder);
-
        union {
                struct {
                        int mc_unknown;
 
 {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct drm_device *dev = crtc->dev;
-       struct drm_encoder *encoder;
-       uint32_t dac = 0, sor = 0;
 
        NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
 
-       /* Disconnect all unused encoders. */
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-
-               if (!drm_helper_encoder_in_use(encoder))
-                       continue;
-
-               if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
-                   nv_encoder->dcb->type == OUTPUT_TV)
-                       dac |= (1 << nv_encoder->or);
-               else
-                       sor |= (1 << nv_encoder->or);
-       }
-
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-
-               if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
-                   nv_encoder->dcb->type == OUTPUT_TV) {
-                       if (dac & (1 << nv_encoder->or))
-                               continue;
-               } else {
-                       if (sor & (1 << nv_encoder->or))
-                               continue;
-               }
-
-               nv_encoder->disconnect(nv_encoder);
-       }
-
        nv50_crtc_blank(nv_crtc, true);
 }
 
 
 #include "nv50_display.h"
 
 static void
-nv50_dac_disconnect(struct nouveau_encoder *nv_encoder)
+nv50_dac_disconnect(struct drm_encoder *encoder)
 {
-       struct drm_device *dev = to_drm_encoder(nv_encoder)->dev;
+       struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+       struct drm_device *dev = encoder->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_channel *evo = dev_priv->evo;
        int ret;
 
+       if (!nv_encoder->crtc)
+               return;
+
        NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or);
 
        ret = RING_SPACE(evo, 2);
        }
        BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1);
        OUT_RING(evo, 0);
+
+       nv_encoder->crtc = NULL;
 }
 
 static enum drm_connector_status
        BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2);
        OUT_RING(evo, mode_ctl);
        OUT_RING(evo, mode_ctl2);
+
+       nv_encoder->crtc = encoder->crtc;
 }
 
 static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
        .prepare = nv50_dac_prepare,
        .commit = nv50_dac_commit,
        .mode_set = nv50_dac_mode_set,
-       .detect = nv50_dac_detect
+       .detect = nv50_dac_detect,
+       .disable = nv50_dac_disconnect
 };
 
 static void
        nv_encoder->dcb = entry;
        nv_encoder->or = ffs(entry->or) - 1;
 
-       nv_encoder->disconnect = nv50_dac_disconnect;
-
        drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs,
                         DRM_MODE_ENCODER_DAC);
        drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs);
 
 #include "nv50_display.h"
 
 static void
-nv50_sor_disconnect(struct nouveau_encoder *nv_encoder)
+nv50_sor_disconnect(struct drm_encoder *encoder)
 {
-       struct drm_device *dev = to_drm_encoder(nv_encoder)->dev;
+       struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+       struct drm_device *dev = encoder->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_channel *evo = dev_priv->evo;
        int ret;
 
+       if (!nv_encoder->crtc)
+               return;
+
        NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or);
 
        ret = RING_SPACE(evo, 2);
        }
        BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
        OUT_RING(evo, 0);
+
+       nv_encoder->crtc = NULL;
+       nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
 }
 
 static void
        uint32_t val;
        int or = nv_encoder->or;
 
-       NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
+       NV_DEBUG_KMS(dev, "or %d type %d mode %d\n", or, nv_encoder->dcb->type, mode);
 
        nv_encoder->last_dpms = mode;
        list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
                struct nouveau_encoder *nvenc = nouveau_encoder(enc);
 
                if (nvenc == nv_encoder ||
-                   nvenc->disconnect != nv50_sor_disconnect ||
+                   (nvenc->dcb->type != OUTPUT_TMDS &&
+                    nvenc->dcb->type != OUTPUT_LVDS &&
+                    nvenc->dcb->type != OUTPUT_DP) ||
                    nvenc->dcb->or != nv_encoder->dcb->or)
                        continue;
 
        }
        BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
        OUT_RING(evo, mode_ctl);
+
+       nv_encoder->crtc = encoder->crtc;
+}
+
+static struct drm_crtc *
+nv50_sor_crtc_get(struct drm_encoder *encoder)
+{
+       return nouveau_encoder(encoder)->crtc;
 }
 
 static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
        .prepare = nv50_sor_prepare,
        .commit = nv50_sor_commit,
        .mode_set = nv50_sor_mode_set,
-       .detect = NULL
+       .get_crtc = nv50_sor_crtc_get,
+       .detect = NULL,
+       .disable = nv50_sor_disconnect
 };
 
 static void
 
        nv_encoder->dcb = entry;
        nv_encoder->or = ffs(entry->or) - 1;
-
-       nv_encoder->disconnect = nv50_sor_disconnect;
+       nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
 
        drm_encoder_init(dev, encoder, &nv50_sor_encoder_funcs, type);
        drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs);