瀏覽代碼

drm/nv50: fix DP->DVI if output has been programmed for native DP previously

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Ben Skeggs 15 年之前
父節點
當前提交
7149eee87a
共有 2 個文件被更改,包括 32 次插入0 次删除
  1. 1 0
      drivers/gpu/drm/nouveau/nouveau_reg.h
  2. 31 0
      drivers/gpu/drm/nouveau/nv50_display.c

+ 1 - 0
drivers/gpu/drm/nouveau/nouveau_reg.h

@@ -814,6 +814,7 @@
 #define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE                           0x80000000
 #define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE                           0x80000000
 #define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL                            0x00000fff
 #define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL                            0x00000fff
 #define NV50_SOR_DP_CTRL(i,l)            (0x0061c10c + (i) * 0x800 + (l) * 0x80)
 #define NV50_SOR_DP_CTRL(i,l)            (0x0061c10c + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_CTRL_ENABLED                                     0x00000001
 #define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED                      0x00004000
 #define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED                      0x00004000
 #define NV50_SOR_DP_CTRL_LANE_MASK                                   0x001f0000
 #define NV50_SOR_DP_CTRL_LANE_MASK                                   0x001f0000
 #define NV50_SOR_DP_CTRL_LANE_0_ENABLED                              0x00010000
 #define NV50_SOR_DP_CTRL_LANE_0_ENABLED                              0x00010000

+ 31 - 0
drivers/gpu/drm/nouveau/nv50_display.c

@@ -821,6 +821,36 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb)
 	}
 	}
 }
 }
 
 
+/* If programming a TMDS output on a SOR that can also be configured for
+ * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
+ *
+ * It looks like the VBIOS TMDS scripts make an attempt at this, however,
+ * the VBIOS scripts on at least one board I have only switch it off on
+ * link 0, causing a blank display if the output has previously been
+ * programmed for DisplayPort.
+ */
+static void
+nv50_display_unk20_dp_set_tmds(struct drm_device *dev, struct dcb_entry *dcb)
+{
+	int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
+	struct drm_encoder *encoder;
+	u32 tmp;
+
+	if (dcb->type != OUTPUT_TMDS)
+		return;
+
+	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_DP) {
+			tmp  = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
+			tmp &= ~NV50_SOR_DP_CTRL_ENABLED;
+			nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
+			break;
+		}
+	}
+}
+
 static void
 static void
 nv50_display_unk20_handler(struct drm_device *dev)
 nv50_display_unk20_handler(struct drm_device *dev)
 {
 {
@@ -845,6 +875,7 @@ nv50_display_unk20_handler(struct drm_device *dev)
 	nouveau_bios_run_display_table(dev, dcbent, script, pclk);
 	nouveau_bios_run_display_table(dev, dcbent, script, pclk);
 
 
 	nv50_display_unk20_dp_hack(dev, dcbent);
 	nv50_display_unk20_dp_hack(dev, dcbent);
+	nv50_display_unk20_dp_set_tmds(dev, dcbent);
 
 
 	tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head));
 	tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head));
 	tmp &= ~0x000000f;
 	tmp &= ~0x000000f;