drm/nv50: use alternate source of SOR_MODE_CTRL for DP hack
[safe/jmp/linux-2.6] / drivers / gpu / drm / nouveau / nv50_sor.c
index 8c28046..812778d 100644 (file)
@@ -44,7 +44,7 @@ nv50_sor_disconnect(struct nouveau_encoder *nv_encoder)
        struct nouveau_channel *evo = dev_priv->evo;
        int ret;
 
-       NV_DEBUG(dev, "Disconnecting SOR %d\n", nv_encoder->or);
+       NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or);
 
        ret = RING_SPACE(evo, 2);
        if (ret) {
@@ -70,7 +70,7 @@ nv50_sor_dp_link_train(struct drm_encoder *encoder)
        }
 
        if (dpe->script0) {
-               NV_DEBUG(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
+               NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
                nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0),
                                            nv_encoder->dcb);
        }
@@ -79,7 +79,7 @@ nv50_sor_dp_link_train(struct drm_encoder *encoder)
                NV_ERROR(dev, "SOR-%d: link training failed\n", nv_encoder->or);
 
        if (dpe->script1) {
-               NV_DEBUG(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
+               NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
                nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1),
                                            nv_encoder->dcb);
        }
@@ -90,10 +90,24 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
 {
        struct drm_device *dev = encoder->dev;
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+       struct drm_encoder *enc;
        uint32_t val;
        int or = nv_encoder->or;
 
-       NV_DEBUG(dev, "or %d mode %d\n", or, mode);
+       NV_DEBUG_KMS(dev, "or %d mode %d\n", or, 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->or != nv_encoder->dcb->or)
+                       continue;
+
+               if (nvenc->last_dpms == DRM_MODE_DPMS_ON)
+                       return;
+       }
 
        /* wait for it to be done */
        if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_CTRL(or),
@@ -142,7 +156,7 @@ nv50_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct nouveau_connector *connector;
 
-       NV_DEBUG(encoder->dev, "or %d\n", nv_encoder->or);
+       NV_DEBUG_KMS(encoder->dev, "or %d\n", nv_encoder->or);
 
        connector = nouveau_encoder_connector_get(nv_encoder);
        if (!connector) {
@@ -182,7 +196,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        uint32_t mode_ctl = 0;
        int ret;
 
-       NV_DEBUG(dev, "or %d\n", nv_encoder->or);
+       NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or);
 
        nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON);
 
@@ -197,7 +211,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                        mode_ctl = 0x0200;
                break;
        case OUTPUT_DP:
-               mode_ctl |= 0x00050000;
+               mode_ctl |= (nv_encoder->dp.mc_unknown << 16);
                if (nv_encoder->dcb->sorconf.link & 1)
                        mode_ctl |= 0x00000800;
                else
@@ -246,7 +260,7 @@ nv50_sor_destroy(struct drm_encoder *encoder)
        if (!encoder)
                return;
 
-       NV_DEBUG(encoder->dev, "\n");
+       NV_DEBUG_KMS(encoder->dev, "\n");
 
        drm_encoder_cleanup(encoder);
 
@@ -265,7 +279,7 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
        bool dum;
        int type;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        switch (entry->type) {
        case OUTPUT_TMDS:
@@ -305,5 +319,28 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
        encoder->possible_crtcs = entry->heads;
        encoder->possible_clones = 0;
 
+       if (nv_encoder->dcb->type == OUTPUT_DP) {
+               int or = nv_encoder->or, link = !(entry->dpconf.sor.link & 1);
+               uint32_t tmp;
+
+               tmp = nv_rd32(dev, 0x61c700 + (or * 0x800));
+
+               switch ((tmp & 0x00000f00) >> 8) {
+               case 8:
+               case 9:
+                       nv_encoder->dp.mc_unknown = (tmp & 0x000f0000) >> 16;
+                       tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
+                       nv_encoder->dp.unk0 = tmp & 0x000001fc;
+                       tmp = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link));
+                       nv_encoder->dp.unk1 = tmp & 0x010f7f3f;
+                       break;
+               default:
+                       break;
+               }
+
+               if (!nv_encoder->dp.mc_unknown)
+                       nv_encoder->dp.mc_unknown = 5;
+       }
+
        return 0;
 }