瀏覽代碼

drm/nv50: supply encoder disable() hook for SOR outputs

Allows us to remove a driver hack that used to be necessary to disable
encoders in certain situations before setting up a mode.  The DRM has
better knowledge of when this is needed than the driver does.

This fixes a number of display switching issues.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Ben Skeggs 15 年之前
父節點
當前提交
ec7fc4a1a7

+ 4 - 2
drivers/gpu/drm/nouveau/nouveau_encoder.h

@@ -38,13 +38,15 @@ struct nouveau_encoder {
 	struct dcb_entry *dcb;
 	struct dcb_entry *dcb;
 	int or;
 	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;
 	struct drm_display_mode mode;
 	int last_dpms;
 	int last_dpms;
 
 
 	struct nv04_output_reg restore;
 	struct nv04_output_reg restore;
 
 
-	void (*disconnect)(struct nouveau_encoder *encoder);
-
 	union {
 	union {
 		struct {
 		struct {
 			int mc_unknown;
 			int mc_unknown;

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

@@ -440,40 +440,9 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
 {
 {
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
 	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);
 	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);
 	nv50_crtc_blank(nv_crtc, true);
 }
 }
 
 

+ 12 - 5
drivers/gpu/drm/nouveau/nv50_dac.c

@@ -37,13 +37,17 @@
 #include "nv50_display.h"
 #include "nv50_display.h"
 
 
 static void
 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 drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_channel *evo = dev_priv->evo;
 	struct nouveau_channel *evo = dev_priv->evo;
 	int ret;
 	int ret;
 
 
+	if (!nv_encoder->crtc)
+		return;
+
 	NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or);
 	NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or);
 
 
 	ret = RING_SPACE(evo, 2);
 	ret = RING_SPACE(evo, 2);
@@ -53,6 +57,8 @@ nv50_dac_disconnect(struct nouveau_encoder *nv_encoder)
 	}
 	}
 	BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1);
 	BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1);
 	OUT_RING(evo, 0);
 	OUT_RING(evo, 0);
+
+	nv_encoder->crtc = NULL;
 }
 }
 
 
 static enum drm_connector_status
 static enum drm_connector_status
@@ -243,6 +249,8 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
 	BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2);
 	BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2);
 	OUT_RING(evo, mode_ctl);
 	OUT_RING(evo, mode_ctl);
 	OUT_RING(evo, mode_ctl2);
 	OUT_RING(evo, mode_ctl2);
+
+	nv_encoder->crtc = encoder->crtc;
 }
 }
 
 
 static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
 static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
@@ -253,7 +261,8 @@ static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
 	.prepare = nv50_dac_prepare,
 	.prepare = nv50_dac_prepare,
 	.commit = nv50_dac_commit,
 	.commit = nv50_dac_commit,
 	.mode_set = nv50_dac_mode_set,
 	.mode_set = nv50_dac_mode_set,
-	.detect = nv50_dac_detect
+	.detect = nv50_dac_detect,
+	.disable = nv50_dac_disconnect
 };
 };
 
 
 static void
 static void
@@ -288,8 +297,6 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
 	nv_encoder->dcb = entry;
 	nv_encoder->dcb = entry;
 	nv_encoder->or = ffs(entry->or) - 1;
 	nv_encoder->or = ffs(entry->or) - 1;
 
 
-	nv_encoder->disconnect = nv50_dac_disconnect;
-
 	drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs,
 	drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs,
 			 DRM_MODE_ENCODER_DAC);
 			 DRM_MODE_ENCODER_DAC);
 	drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs);
 	drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs);

+ 25 - 7
drivers/gpu/drm/nouveau/nv50_sor.c

@@ -37,13 +37,17 @@
 #include "nv50_display.h"
 #include "nv50_display.h"
 
 
 static void
 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 drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_channel *evo = dev_priv->evo;
 	struct nouveau_channel *evo = dev_priv->evo;
 	int ret;
 	int ret;
 
 
+	if (!nv_encoder->crtc)
+		return;
+
 	NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or);
 	NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or);
 
 
 	ret = RING_SPACE(evo, 2);
 	ret = RING_SPACE(evo, 2);
@@ -53,6 +57,9 @@ nv50_sor_disconnect(struct nouveau_encoder *nv_encoder)
 	}
 	}
 	BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
 	BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
 	OUT_RING(evo, 0);
 	OUT_RING(evo, 0);
+
+	nv_encoder->crtc = NULL;
+	nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
 }
 }
 
 
 static void
 static void
@@ -94,14 +101,16 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
 	uint32_t val;
 	uint32_t val;
 	int or = nv_encoder->or;
 	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;
 	nv_encoder->last_dpms = mode;
 	list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
 	list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
 		struct nouveau_encoder *nvenc = nouveau_encoder(enc);
 		struct nouveau_encoder *nvenc = nouveau_encoder(enc);
 
 
 		if (nvenc == nv_encoder ||
 		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)
 		    nvenc->dcb->or != nv_encoder->dcb->or)
 			continue;
 			continue;
 
 
@@ -239,6 +248,14 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
 	}
 	}
 	BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
 	BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
 	OUT_RING(evo, mode_ctl);
 	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 = {
 static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
@@ -249,7 +266,9 @@ static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
 	.prepare = nv50_sor_prepare,
 	.prepare = nv50_sor_prepare,
 	.commit = nv50_sor_commit,
 	.commit = nv50_sor_commit,
 	.mode_set = nv50_sor_mode_set,
 	.mode_set = nv50_sor_mode_set,
-	.detect = NULL
+	.get_crtc = nv50_sor_crtc_get,
+	.detect = NULL,
+	.disable = nv50_sor_disconnect
 };
 };
 
 
 static void
 static void
@@ -300,8 +319,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry)
 
 
 	nv_encoder->dcb = entry;
 	nv_encoder->dcb = entry;
 	nv_encoder->or = ffs(entry->or) - 1;
 	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_init(dev, encoder, &nv50_sor_encoder_funcs, type);
 	drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs);
 	drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs);