[Nouveau] [PATCH 3/4] nv50: power down unused DACs

Maxim Levitsky maximlevitsky at gmail.com
Sat Jan 21 14:14:26 PST 2012


signed-off-by: Maxim Levitsky <maximlevitsky at gmail.com>
---
 drivers/gpu/drm/nouveau/nv50_dac.c     |   47 +++++++++++++++++++++++++++-----
 drivers/gpu/drm/nouveau/nv50_display.c |    2 +-
 2 files changed, 41 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c
index a0f2beb..5cc0fb2 100644
--- a/drivers/gpu/drm/nouveau/nv50_dac.c
+++ b/drivers/gpu/drm/nouveau/nv50_dac.c
@@ -70,10 +70,12 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
 	struct drm_device *dev = encoder->dev;
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	enum drm_connector_status status = connector_status_disconnected;
-	uint32_t dpms_state, load_pattern, load_state;
+	uint32_t dpms_state, load_pattern, load_state, clk;
 	int or = nv_encoder->or;
 
-	nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(or), 0x00000001);
+	clk = nv_rd32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(or));
+	nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(or), 0x01);
+
 	dpms_state = nv_rd32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or));
 
 	nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
@@ -115,6 +117,8 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
 	else
 		NV_DEBUG_KMS(dev, "Load was not detected on output with or %d\n", or);
 
+	nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(or), clk);
+
 	return status;
 }
 
@@ -123,7 +127,7 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode)
 {
 	struct drm_device *dev = encoder->dev;
 	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-	uint32_t val;
+	uint32_t val, clk;
 	int or = nv_encoder->or;
 
 	NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
@@ -138,9 +142,13 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode)
 	}
 
 	val = nv_rd32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or)) & ~0x7F;
+	clk = nv_rd32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(or));
 
-	if (mode != DRM_MODE_DPMS_ON)
+	if (mode != DRM_MODE_DPMS_ON) {
 		val |= NV50_PDISPLAY_DAC_DPMS_CTRL_BLANKED;
+		clk |= 0x02;
+	} else
+		clk &= ~0x02;
 
 	switch (mode) {
 	case DRM_MODE_DPMS_STANDBY:
@@ -160,6 +168,9 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode)
 
 	nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or), val |
 		NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
+
+	nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(or), clk);
+
 }
 
 static void
@@ -292,6 +303,29 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
 {
 	struct nouveau_encoder *nv_encoder;
 	struct drm_encoder *encoder;
+	int type, or;
+
+	switch (entry->type) {
+	case OUTPUT_ANALOG:
+		type = DRM_MODE_ENCODER_DAC;
+		break;
+	case OUTPUT_TV:
+		type = DRM_MODE_ENCODER_TVDAC;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	or = ffs(entry->or) - 1;
+
+	if (type == DRM_MODE_ENCODER_DAC)
+		nv_wr32(connector->dev, NV50_PDISPLAY_DAC_CLK_CTRL1(or), 0x00000003);
+	else
+		nv_wr32(connector->dev, NV50_PDISPLAY_DAC_CLK_CTRL1(or), 0x80000002);
+
+	/* FIXME: add support for TV-out */
+	if (type != DRM_MODE_ENCODER_DAC)
+		return -EINVAL;
 
 	nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
 	if (!nv_encoder)
@@ -299,10 +333,9 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
 	encoder = to_drm_encoder(nv_encoder);
 
 	nv_encoder->dcb = entry;
-	nv_encoder->or = ffs(entry->or) - 1;
+	nv_encoder->or = or;
 
-	drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs,
-			 DRM_MODE_ENCODER_DAC);
+	drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs, type);
 	drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs);
 
 	encoder->possible_crtcs = entry->heads;
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 7ba28e0..c1806cb 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -185,7 +185,6 @@ nv50_display_init(struct drm_device *dev)
 	for (i = 0; i < 3; i++) {
 		nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(i), 0x00550000 |
 			NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
-		nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(i), 0x00000001);
 	}
 
 	/* The precise purpose is unknown, i suspect it has something to do
@@ -359,6 +358,7 @@ nv50_display_create(struct drm_device *dev)
 			nv50_sor_create(connector, entry);
 			break;
 		case OUTPUT_ANALOG:
+		case OUTPUT_TV:
 			nv50_dac_create(connector, entry);
 			break;
 		default:
-- 
1.7.5.4



More information about the Nouveau mailing list