[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

xserver-xorg-video-nouveau: Changes to 'upstream-experimental'



 configure.ac          |    9 
 src/Makefile.am       |    5 
 src/drmmode_display.c |  925 +++++++++------
 src/drmmode_display.h |   67 -
 src/nouveau_bios.h    |   76 -
 src/nouveau_calc.c    |  612 ++++++++++
 src/nouveau_crtc.h    |    1 
 src/nouveau_dri2.c    |  213 +++
 src/nouveau_exa.c     |  326 ++++-
 src/nouveau_hw.c      |  970 ++++++++++++++++
 src/nouveau_hw.h      |  335 +++++
 src/nouveau_local.h   |   26 
 src/nouveau_xv.c      |  212 ---
 src/nv04_exa.c        |   20 
 src/nv04_xv_blit.c    |    6 
 src/nv10_exa.c        |   10 
 src/nv10_xv_ovl.c     |    6 
 src/nv30_exa.c        |    8 
 src/nv30_xv_tex.c     |   15 
 src/nv40_exa.c        |   22 
 src/nv40_xv_tex.c     |    4 
 src/nv50_connector.c  |   20 
 src/nv50_crtc.c       |   23 
 src/nv50_dac.c        |    4 
 src/nv50_display.c    |    1 
 src/nv50_exa.c        |   32 
 src/nv50_output.c     |  153 +-
 src/nv50_randr.c      |   70 -
 src/nv50_sor.c        |   97 -
 src/nv50_xv.c         |   21 
 src/nv50reg.h         |   13 
 src/nv_bios.c         | 3004 +++++++++++++++++++++++---------------------------
 src/nv_const.h        |    6 
 src/nv_crtc.c         | 1093 ++++--------------
 src/nv_cursor.c       |  473 +------
 src/nv_dac.c          |   17 
 src/nv_dma.c          |   11 
 src/nv_dri.c          |  141 --
 src/nv_driver.c       |  492 ++++----
 src/nv_hw.c           |  947 ---------------
 src/nv_i2c.c          |   37 
 src/nv_include.h      |    4 
 src/nv_output.c       |  815 +++++++++----
 src/nv_proto.h        |   80 -
 src/nv_setup.c        |   92 -
 src/nv_shadow.c       |   50 
 src/nv_type.h         |  181 +--
 src/nvreg.h           |  539 ++++----
 48 files changed, 6524 insertions(+), 5760 deletions(-)

New commits:
commit 9656762ba186e91dd2b3b7f3f9427ba520982f9d
Author: Ben Skeggs <bskeggs@redhat.com>
Date:   Thu May 14 10:26:44 2009 +1000

    nv50: fix multiple-display hangs when encoders swap crtcs

diff --git a/src/nouveau_crtc.h b/src/nouveau_crtc.h
index d86dc90..45d0eee 100644
--- a/src/nouveau_crtc.h
+++ b/src/nouveau_crtc.h
@@ -32,6 +32,7 @@ typedef struct nouveauCrtc {
 	char *name;
 	uint8_t index;
 	Bool active;
+	Bool blanked;
 
 	/* Scanout area. */
 	struct nouveau_bo * front_buffer;
diff --git a/src/nv50_crtc.c b/src/nv50_crtc.c
index 64dc85f..3502dd7 100644
--- a/src/nv50_crtc.c
+++ b/src/nv50_crtc.c
@@ -308,6 +308,8 @@ NV50CrtcBlank(nouveauCrtcPtr crtc, Bool blanked)
 			NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_UNBLANK);
 		NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_UNBLANK);
 	}
+
+	crtc->blanked = blanked;
 }
 
 static void
diff --git a/src/nv50_randr.c b/src/nv50_randr.c
index 3459f05..a261a3b 100644
--- a/src/nv50_randr.c
+++ b/src/nv50_randr.c
@@ -67,17 +67,35 @@ nv50_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
 static void
 nv50_crtc_prepare(xf86CrtcPtr crtc)
 {
-	ScrnInfoPtr pScrn = crtc->scrn;
 	NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_prepare is called for %s.\n", nv_crtc->crtc->index ? "CRTC1" : "CRTC0");
-
+	ScrnInfoPtr pScrn = crtc->scrn;
 	NVPtr pNv = NVPTR(pScrn);
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+	nouveauOutputPtr output;
+	int i;
+
+	/* Rewire internal stucts to match randr-1.2... yet again.. */
+	for (i = 0; i < xf86_config->num_output; i++) {
+		xf86OutputPtr output = xf86_config->output[i];
+		NV50OutputPrivatePtr nv50_output = output->driver_private;
+		nouveauOutputPtr nv_output = nv50_output->output;
+
+		if (output->crtc) {
+			NV50CrtcPrivatePtr nv50_crtc =
+				output->crtc->driver_private;
+			nv_output->crtc = nv50_crtc->crtc;
+		} else {
+			nv_output->crtc = NULL;
+		}
+	}
+
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		   "nv50_crtc_prepare is called for %s.\n",
+		   nv_crtc->crtc->index ? "CRTC1" : "CRTC0");
 
 	nv_crtc->crtc->active = TRUE;
 	nv_crtc->crtc->modeset_lock = TRUE;
 
-	nouveauOutputPtr output;
-
 	/* Detach any unused outputs. */
 	for (output = pNv->output; output != NULL; output = output->next) {
 		if (!output->crtc)
@@ -171,7 +189,8 @@ nv50_crtc_show_cursor(xf86CrtcPtr crtc)
 	NV50CrtcPrivatePtr nv_crtc = crtc->driver_private;
 	//xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_show_cursor is called for %s.\n", nv_crtc->crtc->index ? "CRTC1" : "CRTC0");
 
-	nv_crtc->crtc->ShowCursor(nv_crtc->crtc, FALSE);
+	if (!nv_crtc->crtc->blanked)
+		nv_crtc->crtc->ShowCursor(nv_crtc->crtc, FALSE);
 }
 
 static void

commit d70eed91b2909ba0b20415ab1d5a099fb6b39b08
Author: Stuart Bennett <stuart@freedesktop.org>
Date:   Tue May 12 16:54:33 2009 +0100

    randr12: fix digital dpms regression
    
    introduced in 3971dda57004894d5d4fc9420aa00da400815af9
    
    setting two different "blank" DPMS modes (say Suspend, followed by Off)
    consecutively would lead to the saved fp control value getting overwritten
    with FP_TG_CONTROL_OFF flavoured state, so DPMS on would then never work
    
    also, an improvement to LVDS DPMS state caching

diff --git a/src/nv_crtc.c b/src/nv_crtc.c
index 4ccac45..83d5e40 100644
--- a/src/nv_crtc.c
+++ b/src/nv_crtc.c
@@ -182,7 +182,7 @@ nv_crtc_dpms(xf86CrtcPtr crtc, int mode)
 	/* nv4ref indicates these two RPC1 bits inhibit h/v sync */
 	crtc1A = NVReadVgaCrtc(pNv, nv_crtc->head, NV_CIO_CRE_RPC1_INDEX) & ~0xC0;
 	switch(mode) {
-		case DPMSModeStandby:
+	case DPMSModeStandby:
 		/* Screen: Off; HSync: Off, VSync: On -- Not Supported */
 		seq1 = 0x20;
 		crtc17 = 0x80;
diff --git a/src/nv_output.c b/src/nv_output.c
index dd0cede..e04b743 100644
--- a/src/nv_output.c
+++ b/src/nv_output.c
@@ -831,6 +831,12 @@ static void nv_digital_output_prepare_sel_clk(NVPtr pNv, struct nouveau_encoder
 			   NV_PRAMDAC_FP_TG_CONTROL_HSYNC_DISABLE |	\
 			   NV_PRAMDAC_FP_TG_CONTROL_VSYNC_DISABLE)
 
+static bool is_fpc_off(uint32_t fpc)
+{
+	return ((fpc & (FP_TG_CONTROL_ON | FP_TG_CONTROL_OFF)) ==
+							FP_TG_CONTROL_OFF);
+}
+
 static void
 nv_output_prepare(xf86OutputPtr output)
 {
@@ -963,8 +969,7 @@ static void dpms_update_fp_control(ScrnInfoPtr pScrn, struct nouveau_encoder *nv
 		nv_crtc = to_nouveau_crtc(crtc);
 		fpc = &pNv->ModeReg.crtc_reg[nv_crtc->head].fp_control;
 
-		if ((*fpc & (FP_TG_CONTROL_ON | FP_TG_CONTROL_OFF)) ==
-							FP_TG_CONTROL_OFF)
+		if (is_fpc_off(*fpc))
 			/* using saved value is ok, as (is_digital && dpms_on &&
 			 * fp_control==OFF) is (at present) *only* true when
 			 * fpc's most recent change was by below "off" code
@@ -979,7 +984,7 @@ static void dpms_update_fp_control(ScrnInfoPtr pScrn, struct nouveau_encoder *nv
 			fpc = &pNv->ModeReg.crtc_reg[nv_crtc->head].fp_control;
 
 			nv_crtc->fp_users &= ~(1 << nv_encoder->dcb->index);
-			if (!nv_crtc->fp_users) {
+			if (!is_fpc_off(*fpc) && !nv_crtc->fp_users) {
 				nv_crtc->dpms_saved_fp_control = *fpc;
 				/* cut the FP output */
 				*fpc &= ~FP_TG_CONTROL_ON;
@@ -990,10 +995,17 @@ static void dpms_update_fp_control(ScrnInfoPtr pScrn, struct nouveau_encoder *nv
 		}
 }
 
+static bool is_powersaving_dpms(int mode)
+{
+	return (mode == DPMSModeStandby || mode == DPMSModeSuspend ||
+							mode == DPMSModeOff);
+}
+
 static void
 lvds_encoder_dpms(ScrnInfoPtr pScrn, struct nouveau_encoder *nv_encoder, xf86CrtcPtr crtc, int mode)
 {
 	NVPtr pNv = NVPTR(pScrn);
+	bool was_powersaving = is_powersaving_dpms(nv_encoder->last_dpms);
 
 	if (nv_encoder->last_dpms == mode)
 		return;
@@ -1002,6 +1014,9 @@ lvds_encoder_dpms(ScrnInfoPtr pScrn, struct nouveau_encoder *nv_encoder, xf86Crt
 	NV_TRACE(pScrn, "Setting dpms mode %d on lvds encoder (output %d)\n",
 		 mode, nv_encoder->dcb->index);
 
+	if (was_powersaving && is_powersaving_dpms(mode))
+		return;
+
 	if (nv_encoder->dcb->lvdsconf.use_power_scripts) {
 		/* when removing an output, crtc may not be set, but PANEL_OFF
 		 * must still be run

commit 10721038b854d9945ae551c6aa382b90f5d743e1
Author: Ben Skeggs <skeggsb@gmail.com>
Date:   Thu May 7 21:39:41 2009 +1000

    exa: use exaDriverAlloc() to prevent issues across exa changes

diff --git a/src/nouveau_exa.c b/src/nouveau_exa.c
index b7bcc87..949f747 100644
--- a/src/nouveau_exa.c
+++ b/src/nouveau_exa.c
@@ -546,7 +546,8 @@ nouveau_exa_init(ScreenPtr pScreen)
 	NVPtr pNv = NVPTR(pScrn);
 	ExaDriverPtr exa;
 
-	if(!(exa = (ExaDriverPtr)xnfcalloc(sizeof(ExaDriverRec), 1))) {
+	exa = exaDriverAlloc();
+	if (!exa) {
 		pNv->NoAccel = TRUE;
 		return FALSE;
 	}

commit 8502a8024354b88a4f19c7ad355268bb20772356
Author: Stuart Bennett <stuart@freedesktop.org>
Date:   Wed May 6 18:01:54 2009 +0100

    Fix server regeneration again
    
    The DRM is now opened in PreInit, so it must not be closed in CloseScreen,
    as the DRM wouldn't then be open in the subsequent ScreenInit

diff --git a/src/nv_driver.c b/src/nv_driver.c
index b8598a2..2b3a596 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -786,8 +786,6 @@ NVCloseScreen(int scrnIndex, ScreenPtr pScreen)
 		nouveau_dri2_fini(pScreen);
 #endif
 
-	NVCloseDRM(pScrn);
-
 	if (pNv->randr12_enable)
 		xf86_cursors_fini(pScreen);
 	if (pNv->ShadowPtr) {
@@ -842,6 +840,8 @@ NVFreeScreen(int scrnIndex, int flags)
 	if (!pNv)
 		return;
 
+	NVCloseDRM(pScrn);
+
 	if (pNv->Architecture == NV_ARCH_50 && !pNv->kms_enable) {
 		NV50ConnectorDestroy(pScrn);
 		NV50OutputDestroy(pScrn);

commit 7a796a94d0c0e18a77c5c50a0f9ca9c218d7201f
Author: Stuart Bennett <stuart@freedesktop.org>
Date:   Thu Apr 30 16:04:59 2009 +0100

    randr12: off-chip lvds for nv28 (rh#487456)
    
    Quite how this possibly works with the off-chip DVI connector the laptop
    in question also claims to have is unclear: I suspect that (at least in
    nouveau's implementation) it doesn't.  Sadly we've no dvi-in-use reg dump
    to see what should be done.

diff --git a/src/nv_output.c b/src/nv_output.c
index 68776e6..dd0cede 100644
--- a/src/nv_output.c
+++ b/src/nv_output.c
@@ -877,6 +877,8 @@ nv_output_prepare(xf86OutputPtr output)
 				*cr_lcd |= head ? 0x0 : 0x8;
 			else {
 				*cr_lcd |= (nv_encoder->dcb->or << 4) & 0x30;
+				if (nv_encoder->dcb->type == OUTPUT_LVDS)
+					*cr_lcd |= 0x30;
 				if ((*cr_lcd & 0x30) == (*cr_lcd_oth & 0x30)) {
 					/* avoid being connected to both crtcs */
 					*cr_lcd_oth &= ~0x30;

commit 5959512ef5ce20aa52bbd41d5d987392f27b9e65
Author: Stuart Bennett <stuart@freedesktop.org>
Date:   Wed May 6 14:44:40 2009 +0100

    'drmCheckModesettingSupported' implicit function declaration fix

diff --git a/src/nv_driver.c b/src/nv_driver.c
index 74855ce..b8598a2 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -27,6 +27,9 @@
 #include "xorg-server.h"
 #include "xf86int10.h"
 #include "xf86drm.h"
+#ifdef XF86DRM_MODE
+#include "xf86drmMode.h"
+#endif
 
 /*
  * Forward definitions for the functions that make up the driver.

commit f62719e2ac8b04d4496dc56d5fa181934bcea9f7
Author: Peter Hjalmarsson <xake@rymdraket.net>
Date:   Wed May 6 14:43:22 2009 +0100

    Unused variable warning fixes

diff --git a/src/nv50_sor.c b/src/nv50_sor.c
index 1e271a8..ea18e77 100644
--- a/src/nv50_sor.c
+++ b/src/nv50_sor.c
@@ -110,7 +110,6 @@ NV50SorSetClockMode(nouveauOutputPtr output, int clock)
 	ScrnInfoPtr pScrn = output->scrn;
 	NVPtr pNv = NVPTR(pScrn);
 	const int limit = output->dcb->type == OUTPUT_LVDS ? 112000 : 165000;
-	int ret;
 
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 		   "NV50SorSetClockMode is called.\n");
diff --git a/src/nv_i2c.c b/src/nv_i2c.c
index 2725370..e8b2e29 100644
--- a/src/nv_i2c.c
+++ b/src/nv_i2c.c
@@ -85,7 +85,6 @@ NVI2CPutBits(I2CBusPtr b, int clock, int data)
 static uint32_t NV50_GetI2CPort(ScrnInfoPtr pScrn, int index)
 {
 	NVPtr pNv = NVPTR(pScrn);
-	uint32_t reg;
 
 	if (index <= 3)
 		return 0xe138 + (index * 24);

commit c8260ef52b58234335bdbfab31364d3d25840c21
Author: Pierre Pronchery <khorben@defora.org>
Date:   Wed May 6 14:32:34 2009 +0100

    Fix crash with Xinerama enabled
    
    From the mailing list, minor tweaks by Stuart Bennett

diff --git a/src/nv_driver.c b/src/nv_driver.c
index 92232dd..74855ce 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -1926,8 +1926,9 @@ NVLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
 			break;
 		}
 
-		/* Make the change through RandR */
-		RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
+		if (crtc->randr_crtc)
+			/* Make the change through RandR */
+			RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
 	}
 }
 

commit 1a478edbd58bb2eb1a41f22dea893c6d85902318
Author: Stuart Bennett <stuart@freedesktop.org>
Date:   Wed May 6 02:23:42 2009 +0100

    randr12: de-magic ramdac general control values

diff --git a/src/nv_crtc.c b/src/nv_crtc.c
index 6de8733..4ccac45 100644
--- a/src/nv_crtc.c
+++ b/src/nv_crtc.c
@@ -566,19 +566,13 @@ nv_crtc_mode_set_regs(xf86CrtcPtr crtc, DisplayModePtr mode)
 		/* Only bit that bios and blob set. */
 		regp->nv10_cursync = (1 << 25);
 
-	switch (pScrn->depth) {
-		case 24:
-		case 15:
-			regp->ramdac_gen_ctrl = 0x00100130;
-			break;
-		case 16:
-		default:
-			regp->ramdac_gen_ctrl = 0x00101130;
-			break;
-	}
+	regp->ramdac_gen_ctrl = NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS |
+				NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL |
+				NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON;
+	if (pScrn->depth == 16)
+		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
 	if (pNv->alphaCursor)
-		/* PIPE_LONG mode, something to do with the size of the cursor? */
-		regp->ramdac_gen_ctrl |= 1 << 29;
+		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_PIPE_LONG;
 
 	regp->ramdac_630 = 0; /* turn off green mode (tv test pattern?) */
 
diff --git a/src/nvreg.h b/src/nvreg.h
index ef750c2..060e243 100644
--- a/src/nvreg.h
+++ b/src/nvreg.h
@@ -342,8 +342,11 @@
 
 #define NV_PRAMDAC_GENERAL_CONTROL			0x00680600
 #	define NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON		(3 << 4)
+#	define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL		(1 << 8)
+#	define NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL		(1 << 12)
 #	define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_75OHM	(2 << 16)
 #	define NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS		(1 << 20)
+#	define NV_PRAMDAC_GENERAL_CONTROL_PIPE_LONG		(2 << 28)
 #define NV_PRAMDAC_TEST_CONTROL				0x00680608
 #	define NV_PRAMDAC_TEST_CONTROL_TP_INS_EN_ASSERTED	(1 << 12)
 #	define NV_PRAMDAC_TEST_CONTROL_PWRDWN_DAC_OFF		(1 << 16)

commit 6c209a87d2d90b39fddc446378b370bd7fb81f6b
Author: Stuart Bennett <stuart@freedesktop.org>
Date:   Tue Apr 7 14:37:05 2009 +0100

    randr12: pre-nv17 load detection
    
    Sampling heuristic as close to nvidia's as mmiotrace-based inference admits
    
    Works on both nv05 and nv11

diff --git a/src/nv_output.c b/src/nv_output.c
index b76922f..68776e6 100644
--- a/src/nv_output.c
+++ b/src/nv_output.c
@@ -2,7 +2,7 @@
  * Copyright 2003 NVIDIA, Corporation
  * Copyright 2006 Dave Airlie
  * Copyright 2007 Maarten Maathuis
- * Copyright 2007-2008 Stuart Bennett
+ * Copyright 2007-2009 Stuart Bennett
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -25,6 +25,7 @@
  */
 
 #include <X11/Xatom.h>
+#include <X11/Xos.h>	/* X_GETTIMEOFDAY */
 #include "nv_include.h"
 
 #define MULTIPLE_ENCODERS(e) (e & (e - 1))
@@ -57,8 +58,182 @@ static int nv_get_digital_bound_head(NVPtr pNv, int or)
 	return (((NVReadRAMDAC(pNv, ramdac, NV_PRAMDAC_FP_TMDS_DATA) & 0x8) >> 3) ^ ramdac);
 }
 
+#define WAIT_FOR(cond, timeout_us) __extension__ ({	\
+	struct timeval begin, cur;			\
+	long d_secs, d_usecs, diff = 0;			\
+							\
+	X_GETTIMEOFDAY(&begin);				\
+	while (!(cond) && diff < timeout_us) {		\
+		X_GETTIMEOFDAY(&cur);			\
+		d_secs  = cur.tv_sec - begin.tv_sec;	\
+		d_usecs = cur.tv_usec - begin.tv_usec;	\
+		diff = d_secs * 1000000 + d_usecs;	\
+	};						\
+	diff >= timeout_us ? -EAGAIN : 0;		\
+})
+
+/*
+ * arbitrary limit to number of sense oscillations tolerated in one sample
+ * period (observed to be at least 13 in "nvidia")
+ */
+#define MAX_HBLANK_OSC 20
+
+/*
+ * arbitrary limit to number of conflicting sample pairs to tolerate at a
+ * voltage step (observed to be at least 5 in "nvidia")
+ */
+#define MAX_SAMPLE_PAIRS 10
+
+static int sample_load_twice(NVPtr pNv, bool sense[2])
+{
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		bool sense_a, sense_b, sense_b_prime;
+		int j = 0;
+
+		/*
+		 * wait for bit 0 clear -- out of hblank -- (say reg value 0x4),
+		 * then wait for transition 0x4->0x5->0x4: enter hblank, leave
+		 * hblank again
+		 * use a 10ms timeout (guards against crtc being inactive, in
+		 * which case blank state would never change)
+		 */
+		if (WAIT_FOR(!(VGA_RD08(pNv->REGS, NV_PRMCIO_INP0__COLOR) & 1), 10000))
+			return -EWOULDBLOCK;
+		if (WAIT_FOR(VGA_RD08(pNv->REGS, NV_PRMCIO_INP0__COLOR) & 1, 10000))
+			return -EWOULDBLOCK;
+		if (WAIT_FOR(!(VGA_RD08(pNv->REGS, NV_PRMCIO_INP0__COLOR) & 1), 10000))
+			return -EWOULDBLOCK;
+
+		WAIT_FOR(0, 100);	/* faster than usleep(100) */
+		/* when level triggers, sense is _LO_ */
+		sense_a = VGA_RD08(pNv->REGS, NV_PRMCIO_INP0) & 0x10;
+
+		/* take another reading until it agrees with sense_a... */
+		do {
+			WAIT_FOR(0, 100);
+			sense_b = VGA_RD08(pNv->REGS, NV_PRMCIO_INP0) & 0x10;
+			if (sense_a != sense_b) {
+				sense_b_prime = VGA_RD08(pNv->REGS, NV_PRMCIO_INP0) & 0x10;
+				if (sense_b == sense_b_prime) {
+					/* ... unless two consecutive subsequent
+					 * samples agree; sense_a is replaced */
+					sense_a = sense_b;
+					/* force mis-match so we loop */
+					sense_b = !sense_a;
+				}
+			}
+		} while ((sense_a != sense_b) && ++j < MAX_HBLANK_OSC);
+
+		if (j == MAX_HBLANK_OSC)
+			/* with so much oscillation, default to sense:LO */
+			sense[i] = false;
+		else
+			sense[i] = sense_a;
+	}
+
+	return 0;
+}
+
+static bool nv_legacy_load_detect(ScrnInfoPtr pScrn)
+{
+	NVPtr pNv = NVPTR(pScrn);
+	uint8_t saved_seq1, saved_pi, saved_rpc1;
+	uint8_t saved_palette0[3], saved_palette_mask;
+	uint32_t saved_rtest_ctrl, saved_rgen_ctrl;
+	int i;
+	uint8_t blue;
+	bool sense = true;
+
+	/*
+	 * for this detection to work, there needs to be a mode set up on the
+	 * CRTC.  this is presumed to be the case
+	 */
+
+	if (pNv->twoHeads)
+		/* only implemented for head A for now */
+		NVSetOwner(pNv, 0);
+
+	saved_seq1 = NVReadVgaSeq(pNv, 0, NV_VIO_SR_CLOCK_INDEX);
+	NVWriteVgaSeq(pNv, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1 & ~0x20);
+
+	saved_rtest_ctrl = NVReadRAMDAC(pNv, 0, NV_PRAMDAC_TEST_CONTROL);
+	NVWriteRAMDAC(pNv, 0, NV_PRAMDAC_TEST_CONTROL,
+		      saved_rtest_ctrl & ~NV_PRAMDAC_TEST_CONTROL_PWRDWN_DAC_OFF);
+
+	usleep(10000);
+
+	saved_pi = NVReadVgaCrtc(pNv, 0, NV_CIO_CRE_PIXEL_INDEX);
+	NVWriteVgaCrtc(pNv, 0, NV_CIO_CRE_PIXEL_INDEX,
+		       saved_pi & ~(0x80 | MASK(NV_CIO_CRE_PIXEL_FORMAT)));
+	saved_rpc1 = NVReadVgaCrtc(pNv, 0, NV_CIO_CRE_RPC1_INDEX);
+	NVWriteVgaCrtc(pNv, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1 & ~0xc0);
+
+	VGA_WR08(pNv->REGS, NV_PRMDIO_READ_MODE_ADDRESS, 0x0);
+	for (i = 0; i < 3; i++)
+		saved_palette0[i] = NV_RD08(pNv->REGS, NV_PRMDIO_PALETTE_DATA);
+	saved_palette_mask = NV_RD08(pNv->REGS, NV_PRMDIO_PIXEL_MASK);
+	VGA_WR08(pNv->REGS, NV_PRMDIO_PIXEL_MASK, 0);
+
+	saved_rgen_ctrl = NVReadRAMDAC(pNv, 0, NV_PRAMDAC_GENERAL_CONTROL);
+	NVWriteRAMDAC(pNv, 0, NV_PRAMDAC_GENERAL_CONTROL,
+		      (saved_rgen_ctrl & ~(NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS |
+					   NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_75OHM)) |
+		      NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON);
+
+	blue = 8;	/* start of test range */
+
+	do {
+		bool sense_pair[2];
+
+		VGA_WR08(pNv->REGS, NV_PRMDIO_WRITE_MODE_ADDRESS, 0);
+		NV_WR08(pNv->REGS, NV_PRMDIO_PALETTE_DATA, 0);
+		NV_WR08(pNv->REGS, NV_PRMDIO_PALETTE_DATA, 0);
+		/* testing blue won't find monochrome monitors.  I don't care */
+		NV_WR08(pNv->REGS, NV_PRMDIO_PALETTE_DATA, blue);
+
+		i = 0;
+		/* take sample pairs until both samples in the pair agree */
+		do {
+			if (sample_load_twice(pNv, sense_pair))
+				goto out;
+		} while ((sense_pair[0] != sense_pair[1]) &&
+							++i < MAX_SAMPLE_PAIRS);
+
+		if (i == MAX_SAMPLE_PAIRS)
+			/* too much oscillation defaults to LO */
+			sense = false;
+		else
+			sense = sense_pair[0];
+
+	/*
+	 * if sense goes LO before blue ramps to 0x18, monitor is not connected.
+	 * ergo, if blue gets to 0x18, monitor must be connected
+	 */
+	} while (++blue < 0x18 && sense);
+
+out:
+	VGA_WR08(pNv->REGS, NV_PRMDIO_PIXEL_MASK, saved_palette_mask);
+	NVWriteRAMDAC(pNv, 0, NV_PRAMDAC_GENERAL_CONTROL, saved_rgen_ctrl);
+	VGA_WR08(pNv->REGS, NV_PRMDIO_WRITE_MODE_ADDRESS, 0);
+	for (i = 0; i < 3; i++)
+		NV_WR08(pNv->REGS, NV_PRMDIO_PALETTE_DATA, saved_palette0[i]);
+	NVWriteRAMDAC(pNv, 0, NV_PRAMDAC_TEST_CONTROL, saved_rtest_ctrl);
+	NVWriteVgaCrtc(pNv, 0, NV_CIO_CRE_PIXEL_INDEX, saved_pi);
+	NVWriteVgaCrtc(pNv, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1);
+	NVWriteVgaSeq(pNv, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1);
+
+	if (blue == 0x18) {
+		NV_TRACE(pScrn, "Load detected on head A\n");
+		return true;
+	}
+
+	return false;
+}
+
 static bool
-nv_load_detect(ScrnInfoPtr pScrn, struct nouveau_encoder *nv_encoder)
+nv_nv17_load_detect(ScrnInfoPtr pScrn, struct nouveau_encoder *nv_encoder)
 {
 	NVPtr pNv = NVPTR(pScrn);
 	uint32_t testval, regoffset = nv_output_ramdac_offset(nv_encoder);
@@ -216,11 +391,12 @@ nv_output_detect(xf86OutputPtr output)
 		    xf86CheckBoolOption(output->conf_monitor->mon_option_lst,
 					"Enable", FALSE))
 			ret = XF86OutputStatusConnected;
-		/* we don't have a load det function for early cards */
-		else if (!pNv->gf4_disp_arch)
-			ret = XF86OutputStatusUnknown;
-		else if (nv_load_detect(pScrn, det_encoder))
-			ret = XF86OutputStatusConnected;
+		else if (pNv->gf4_disp_arch) {
+			if (nv_nv17_load_detect(pScrn, det_encoder))
+				ret = XF86OutputStatusConnected;
+		} else
+			 if (nv_legacy_load_detect(pScrn))
+				ret = XF86OutputStatusConnected;
 	} else if ((det_encoder = find_encoder_by_type(OUTPUT_LVDS))) {
 		if (det_encoder->dcb->lvdsconf.use_straps_for_mode) {
 			if (nouveau_bios_fp_mode(pScrn, NULL))
diff --git a/src/nvreg.h b/src/nvreg.h
index 30c0f01..ef750c2 100644
--- a/src/nvreg.h
+++ b/src/nvreg.h
@@ -195,6 +195,7 @@
 #	define NV_CIO_AR_PLANE_INDEX		0x12
 #	define NV_CIO_AR_HPP_INDEX		0x13
 #	define NV_CIO_AR_CSEL_INDEX		0x14
+#define NV_PRMCIO_INP0			0x006013c2
 #define NV_PRMCIO_CRX__COLOR		0x006013d4
 #define NV_PRMCIO_CR__COLOR		0x006013d5
 	/* Standard VGA CRTC registers */
@@ -257,6 +258,7 @@
 #	define NV_CIO_CR_ARX_INDEX		0x26	/* attribute index -- ro copy of 0x60.3c0 */
 #	define NV_CIO_CRE_CHIP_ID_INDEX		0x27	/* chip revision */
 #	define NV_CIO_CRE_PIXEL_INDEX		0x28
+#		define NV_CIO_CRE_PIXEL_FORMAT		1:0
 #	define NV_CIO_CRE_HEB__INDEX		0x2d	/* horizontal extra bits? */
 #		define NV_CIO_CRE_HEB_HDT_8		0:0
 #		define NV_CIO_CRE_HEB_HDE_8		1:1
@@ -339,6 +341,9 @@
 #	define NV_RAMDAC_580_VPLL2_ACTIVE			(1 << 28)
 
 #define NV_PRAMDAC_GENERAL_CONTROL			0x00680600
+#	define NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON		(3 << 4)
+#	define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_75OHM	(2 << 16)
+#	define NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS		(1 << 20)
 #define NV_PRAMDAC_TEST_CONTROL				0x00680608
 #	define NV_PRAMDAC_TEST_CONTROL_TP_INS_EN_ASSERTED	(1 << 12)
 #	define NV_PRAMDAC_TEST_CONTROL_PWRDWN_DAC_OFF		(1 << 16)

commit 3971dda57004894d5d4fc9420aa00da400815af9
Author: Stuart Bennett <stuart@freedesktop.org>
Date:   Thu Apr 30 19:31:27 2009 +0100

    randr12: fix fp_control again again again
    
    As prophesied, 9c991d3a84ad16f893b739282403eb01e02bb57f broke something:
    turning off a digital output, then turning on an analogue output on the
    same crtc as previously used by the digital output led to FP_TG_CONTROL
    being turned on again when the (unmodified by analogue mode_set) fp_control
    state was written out
    
    So, belt and braces attempt to get this right, one more time

diff --git a/src/nv_output.c b/src/nv_output.c
index a910c09..b76922f 100644
--- a/src/nv_output.c
+++ b/src/nv_output.c
@@ -669,16 +669,19 @@ nv_output_prepare(xf86OutputPtr output)
 
 	output->funcs->dpms(output, DPMSModeOff);
 
-	if (nv_encoder->dcb->type == OUTPUT_ANALOG &&
-	    NVReadRAMDAC(pNv, head, NV_PRAMDAC_FP_TG_CONTROL) &
-			 FP_TG_CONTROL_ON) {
-		/* digital remnants must be cleaned before new crtc values
-		 * programmed.  delay is time for the vga stuff to realise it's
-		 * in control again
-		 */
-		NVWriteRAMDAC(pNv, head, NV_PRAMDAC_FP_TG_CONTROL,
-			      FP_TG_CONTROL_OFF);
-		usleep(50000);
+	if (nv_encoder->dcb->type == OUTPUT_ANALOG) {
+		if (NVReadRAMDAC(pNv, head, NV_PRAMDAC_FP_TG_CONTROL) &
+							FP_TG_CONTROL_ON) {
+			/* digital remnants must be cleaned before new crtc
+			 * values programmed.  delay is time for the vga stuff
+			 * to realise it's in control again
+			 */
+			NVWriteRAMDAC(pNv, head, NV_PRAMDAC_FP_TG_CONTROL,
+				      FP_TG_CONTROL_OFF);
+			usleep(50000);
+		}
+		/* don't inadvertently turn it on when state written later */
+		crtcstate[head].fp_control = FP_TG_CONTROL_OFF;
 	}
 
 	/* calculate some output specific CRTC regs now, so that they can be
@@ -744,16 +747,17 @@ nv_output_mode_set(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adj
 		run_tmds_table(pScrn, dcbe, head, adjusted_mode->Clock);
 	else if (dcbe->type == OUTPUT_LVDS)
 		call_lvds_script(pScrn, dcbe, head, LVDS_RESET, adjusted_mode->Clock);
+	if (dcbe->type == OUTPUT_LVDS || dcbe->type == OUTPUT_TMDS)
+		/* update fp_control state for any changes made by scripts,
+		 * so correct value is written at DPMS on */
+		pNv->ModeReg.crtc_reg[head].fp_control =
+			NVReadRAMDAC(pNv, head, NV_PRAMDAC_FP_TG_CONTROL);
 
 	/* This could use refinement for flatpanels, but it should work this way */
 	if (pNv->NVArch < 0x44)
 		NVWriteRAMDAC(pNv, 0, NV_PRAMDAC_TEST_CONTROL + nv_output_ramdac_offset(nv_encoder), 0xf0000000);
 	else
 		NVWriteRAMDAC(pNv, 0, NV_PRAMDAC_TEST_CONTROL + nv_output_ramdac_offset(nv_encoder), 0x00100000);
-
-	/* update fp_control state for any changes made by scripts, for dpms */
-	pNv->ModeReg.crtc_reg[head].fp_control =
-			NVReadRAMDAC(pNv, head, NV_PRAMDAC_FP_TG_CONTROL);
 }
 
 static void
@@ -773,28 +777,37 @@ static void dpms_update_fp_control(ScrnInfoPtr pScrn, struct nouveau_encoder *nv
 {
 	NVPtr pNv = NVPTR(pScrn);
 	struct nouveau_crtc *nv_crtc;
-	uint32_t fpc;
+	uint32_t *fpc;
 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
 	int i;
 
 	if (mode == DPMSModeOn) {
 		nv_crtc = to_nouveau_crtc(crtc);
-		fpc = pNv->ModeReg.crtc_reg[nv_crtc->head].fp_control;
+		fpc = &pNv->ModeReg.crtc_reg[nv_crtc->head].fp_control;
+
+		if ((*fpc & (FP_TG_CONTROL_ON | FP_TG_CONTROL_OFF)) ==
+							FP_TG_CONTROL_OFF)
+			/* using saved value is ok, as (is_digital && dpms_on &&
+			 * fp_control==OFF) is (at present) *only* true when
+			 * fpc's most recent change was by below "off" code
+			 */
+			*fpc = nv_crtc->dpms_saved_fp_control;
 
 		nv_crtc->fp_users |= 1 << nv_encoder->dcb->index;
-		NVWriteRAMDAC(pNv, nv_crtc->head, NV_PRAMDAC_FP_TG_CONTROL, fpc);
+		NVWriteRAMDAC(pNv, nv_crtc->head, NV_PRAMDAC_FP_TG_CONTROL, *fpc);
 	} else
 		for (i = 0; i < xf86_config->num_crtc; i++) {
 			nv_crtc = to_nouveau_crtc(xf86_config->crtc[i]);
-			fpc = pNv->ModeReg.crtc_reg[nv_crtc->head].fp_control;
+			fpc = &pNv->ModeReg.crtc_reg[nv_crtc->head].fp_control;
 
 			nv_crtc->fp_users &= ~(1 << nv_encoder->dcb->index);
 			if (!nv_crtc->fp_users) {
+				nv_crtc->dpms_saved_fp_control = *fpc;
 				/* cut the FP output */
-				fpc &= ~FP_TG_CONTROL_ON;
-				fpc |= FP_TG_CONTROL_OFF;
+				*fpc &= ~FP_TG_CONTROL_ON;
+				*fpc |= FP_TG_CONTROL_OFF;
 				NVWriteRAMDAC(pNv, nv_crtc->head,
-					      NV_PRAMDAC_FP_TG_CONTROL, fpc);
+					      NV_PRAMDAC_FP_TG_CONTROL, *fpc);
 			}
 		}
 }
diff --git a/src/nv_type.h b/src/nv_type.h
index d3ccb14..482b5a6 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -213,6 +213,7 @@ struct nouveau_crtc {
 	uint8_t last_dpms;
 	ExaOffscreenArea *shadow;
 	int fp_users;
+	uint32_t dpms_saved_fp_control;
 	int saturation, sharpness;
 };
 

commit 0ef16031c7e27ffabb0299e9463def125bd5e72c
Author: Stuart Bennett <stuart@freedesktop.org>
Date:   Thu Apr 30 15:27:33 2009 +0100

    randr12: solve off-chip encoder crtc exclusion in prepare, rather than dpms

diff --git a/src/nv_output.c b/src/nv_output.c
index d6cd6b7..a910c09 100644
--- a/src/nv_output.c
+++ b/src/nv_output.c
@@ -661,7 +661,9 @@ nv_output_prepare(xf86OutputPtr output)
 	struct nouveau_encoder *nv_encoder = to_nouveau_encoder(output);
 	NVPtr pNv = NVPTR(output->scrn);
 	int head = to_nouveau_crtc(output->crtc)->head;
-	uint8_t *cr_lcd = &pNv->ModeReg.crtc_reg[head].CRTC[NV_CIO_CRE_LCD__INDEX];
+	struct nv_crtc_reg *crtcstate = pNv->ModeReg.crtc_reg;
+	uint8_t *cr_lcd = &crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX];
+	uint8_t *cr_lcd_oth = &crtcstate[head ^ 1].CRTC[NV_CIO_CRE_LCD__INDEX];
 	bool digital_op = nv_encoder->dcb->type == OUTPUT_LVDS ||
 			  nv_encoder->dcb->type == OUTPUT_TMDS;
 
@@ -694,8 +696,16 @@ nv_output_prepare(xf86OutputPtr output)
 		if (digital_op && pNv->twoHeads) {
 			if (nv_encoder->dcb->location == DCB_LOC_ON_CHIP)
 				*cr_lcd |= head ? 0x0 : 0x8;
-			else
+			else {
 				*cr_lcd |= (nv_encoder->dcb->or << 4) & 0x30;
+				if ((*cr_lcd & 0x30) == (*cr_lcd_oth & 0x30)) {
+					/* avoid being connected to both crtcs */
+					*cr_lcd_oth &= ~0x30;
+					NVWriteVgaCrtc(pNv, head ^ 1,
+						       NV_CIO_CRE_LCD__INDEX,
+						       *cr_lcd_oth);
+				}
+			}
 		}
 	}
 }
@@ -857,8 +867,6 @@ vga_encoder_dpms(ScrnInfoPtr pScrn, struct nouveau_encoder *nv_encoder, xf86Crtc
 static void
 tmds_encoder_dpms(ScrnInfoPtr pScrn, struct nouveau_encoder *nv_encoder, xf86CrtcPtr crtc, int mode)
 {
-	NVPtr pNv = NVPTR(pScrn);
-
 	if (nv_encoder->last_dpms == mode)
 		return;
 	nv_encoder->last_dpms = mode;
@@ -867,24 +875,6 @@ tmds_encoder_dpms(ScrnInfoPtr pScrn, struct nouveau_encoder *nv_encoder, xf86Crt
 		 mode, nv_encoder->dcb->index);
 
 	dpms_update_fp_control(pScrn, nv_encoder, crtc, mode);
-
-	if (nv_encoder->dcb->location != DCB_LOC_ON_CHIP && pNv->twoHeads) {
-		if (mode == DPMSModeOn) {
-			int head = to_nouveau_crtc(crtc)->head;
-
-			NVWriteVgaCrtc(pNv, head, NV_CIO_CRE_LCD__INDEX,
-				       pNv->ModeReg.crtc_reg[head].CRTC[NV_CIO_CRE_LCD__INDEX]);
-		} else {
-			int i;
-			uint8_t mask = pNv->gf4_disp_arch ?
-				       ~((nv_encoder->dcb->or << 4) & 0x30) :
-				       ~0x10;
-
-			for (i = 0; i < 2; i++)
-				NVWriteVgaCrtc(pNv, i, NV_CIO_CRE_LCD__INDEX,
-					       NVReadVgaCrtc(pNv, i, NV_CIO_CRE_LCD__INDEX) & mask);
-		}
-	}
 }
 
 static void nv_output_dpms(xf86OutputPtr output, int mode)
diff --git a/src/nv_type.h b/src/nv_type.h
index 2ec4fba..d3ccb14 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -122,7 +122,7 @@ struct nouveau_pll_vals {
 	int refclk;
 };
 
-typedef struct _nv_crtc_reg 
+typedef struct nv_crtc_reg
 {
 	unsigned char MiscOutReg;     /* */
 	uint8_t CRTC[0x9f];
@@ -161,7 +161,7 @@ typedef struct _nv_crtc_reg
 	uint32_t ramdac_a34;
 } NVCrtcRegRec, *NVCrtcRegPtr;
 
-typedef struct _nv_output_reg
+typedef struct nv_output_reg
 {
 	uint32_t output;
 	int head;

commit 0447ce06989d5599e268fdb8a4ba7bebf72f5c95
Author: Stuart Bennett <stuart@freedesktop.org>
Date:   Sat Apr 4 20:08:32 2009 +0100

    randr12: simplify nv11 digital encoder-crtc binding
    
    Always setting |0x10 on the appropriate crtc for nv11 digital is fine;
    it's what the proprietary driver does, even if the bios doesn't
    
    Fix some line lengths in nv_output_mode_set() too

diff --git a/src/nv_bios.c b/src/nv_bios.c
index cc5f5c4..f34f86a 100644
--- a/src/nv_bios.c
+++ b/src/nv_bios.c
@@ -4232,7 +4232,7 @@ static void fabricate_dvi_i_output(struct parsed_dcb *dcb, bool twoHeads)
 	entry->i2c_index = LEGACY_I2C_PANEL;
 	entry->heads = twoHeads ? 3 : 1;
 	entry->location = !DCB_LOC_ON_CHIP;	/* ie OFF CHIP */
-	entry->or = 1;	/* naturally on head A; see setting of CRE_LCD__INDEX */
+	entry->or = 1;	/* means |0x10 gets set on CRE_LCD__INDEX */
 	entry->duallink_possible = false; /* SiI164 and co. are single link */
 
 #if 0
diff --git a/src/nv_output.c b/src/nv_output.c
index 972aa86..d6cd6b7 100644
--- a/src/nv_output.c
+++ b/src/nv_output.c
@@ -661,7 +661,7 @@ nv_output_prepare(xf86OutputPtr output)
 	struct nouveau_encoder *nv_encoder = to_nouveau_encoder(output);
 	NVPtr pNv = NVPTR(output->scrn);
 	int head = to_nouveau_crtc(output->crtc)->head;
-	uint8_t *lcdi = &pNv->ModeReg.crtc_reg[head].CRTC[NV_CIO_CRE_LCD__INDEX];
+	uint8_t *cr_lcd = &pNv->ModeReg.crtc_reg[head].CRTC[NV_CIO_CRE_LCD__INDEX];
 	bool digital_op = nv_encoder->dcb->type == OUTPUT_LVDS ||
 			  nv_encoder->dcb->type == OUTPUT_TMDS;
 
@@ -689,21 +689,13 @@ nv_output_prepare(xf86OutputPtr output)
 	/* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f)
 	 * at LCD__INDEX which we don't alter
 	 */
-	if (!(*lcdi & 0x44)) {
-		*lcdi = 0;
-		if (digital_op) {
-			*lcdi = 0x3;
+	if (!(*cr_lcd & 0x44)) {
+		*cr_lcd = digital_op ? 0x3 : 0x0;
+		if (digital_op && pNv->twoHeads) {
 			if (nv_encoder->dcb->location == DCB_LOC_ON_CHIP)
-				*lcdi |= head ? 0x0 : 0x8;
-			else if (pNv->gf4_disp_arch)
-				*lcdi |= (nv_encoder->dcb->or << 4) & 0x30;
-			else if (pNv->twoHeads)
-				/* the guess here is that 0x10 gets set when
-				 * the output is not on its "natural" crtc
-				 * (lvds naturally on head b, tmds head a)
-				 */
-				*lcdi |= (head + 1 != nv_encoder->dcb->or) ?
-					 0x10 : 0x00;
+				*cr_lcd |= head ? 0x0 : 0x8;
+			else
+				*cr_lcd |= (nv_encoder->dcb->or << 4) & 0x30;
 		}
 	}
 }
@@ -714,12 +706,12 @@ nv_output_mode_set(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adj
 	struct nouveau_encoder *nv_encoder = to_nouveau_encoder(output);
 	ScrnInfoPtr pScrn = output->scrn;
 	NVPtr pNv = NVPTR(pScrn);
-	struct nouveau_crtc *nv_crtc = to_nouveau_crtc(output->crtc);
+	struct dcb_entry *dcbe = nv_encoder->dcb;
+	int head = to_nouveau_crtc(output->crtc)->head;
 
-	NV_TRACE(pScrn, "%s called for encoder %d\n", __func__,


Reply to: