On 3/16/08, Maarten Maathuis <[EMAIL PROTECTED]> wrote:
> This is primarily targeted at Koala_BR, but if someone happens to have
>  a a fully working nouveay g80 setup, then go ahead.
>
>  Maarten.
>
>  (this is attempt 2, as 100 KiB seems to be the maximum allowed size)
>
>

And a combined patch.
diff --git a/src/nv50_crtc.c b/src/nv50_crtc.c
index 214c964..816362d 100644
--- a/src/nv50_crtc.c
+++ b/src/nv50_crtc.c
@@ -99,22 +99,8 @@ static const xf86CrtcFuncsRec nv50_crtc_funcs = {
 	.destroy = NULL,
 };
 
-void NV50DispCreateCrtcs(ScrnInfoPtr pScrn)
+const xf86CrtcFuncsRec * nv50_get_crtc_funcs()
 {
-	NVPtr pNv = NVPTR(pScrn);
-	Head head;
-	xf86CrtcPtr crtc;
-	NVCrtcPrivatePtr nv50_crtc;
-
-	/* Create a "crtc" object for each head */
-	for(head = HEAD0; head <= HEAD1; head++) {
-		crtc = xf86CrtcCreate(pScrn, &nv50_crtc_funcs);
-		if(!crtc) return;
-
-		nv50_crtc = xnfcalloc(sizeof(*nv50_crtc), 1);
-		nv50_crtc->head = head;
-		nv50_crtc->ditherEnabled = pNv->FPDither;
-		crtc->driver_private = nv50_crtc;
-	}
+	return &nv50_crtc_funcs;
 }
 
diff --git a/src/nv50_dac.c b/src/nv50_dac.c
index 0f9109a..74235d5 100644
--- a/src/nv50_dac.c
+++ b/src/nv50_dac.c
@@ -191,25 +191,8 @@ static const xf86OutputFuncsRec NV50DacOutputFuncs = {
 	.destroy = NV50DacDestroy,
 };
 
-xf86OutputPtr
-NV50CreateDac(ScrnInfoPtr pScrn, ORNum or)
+const xf86OutputFuncsRec * nv50_get_analog_output_funcs()
 {
-	NVOutputPrivatePtr nv_output = xnfcalloc(sizeof(*nv_output), 1);
-	xf86OutputPtr output;
-	char orName[5];
-
-	if(!nv_output)
-		return NULL;
-
-	snprintf(orName, 5, "VGA%i", or);
-	output = xf86OutputCreate(pScrn, &NV50DacOutputFuncs, orName);
-
-	nv_output->type = OUTPUT_ANALOG;
-	nv_output->output_resource = or;
-	output->driver_private = nv_output;
-	output->interlaceAllowed = TRUE;
-	output->doubleScanAllowed = TRUE;
-
-	return output;
+	return &NV50DacOutputFuncs;
 }
 
diff --git a/src/nv50_display.c b/src/nv50_display.c
index 5391fc9..55333a8 100644
--- a/src/nv50_display.c
+++ b/src/nv50_display.c
@@ -205,6 +205,7 @@ Bool
 NV50DispInit(ScrnInfoPtr pScrn)
 {
 	NVPtr pNv = NVPTR(pScrn);
+	uint32_t val;
 	if (NVRead(pNv, 0x00610024) & 0x100) {
 		NVWrite(pNv, 0x00610024, 0x100);
 		NVWrite(pNv, 0x006194e8, NVRead(pNv, 0x006194e8) & ~1);
@@ -214,20 +215,21 @@ NV50DispInit(ScrnInfoPtr pScrn)
 	NVWrite(pNv, 0x00610200, 0x2b00);
 	/* A bugfix (#12637) from the nv driver, to unlock the driver if it's left in a poor state */
 	do {
-		CARD32 val = NVRead(pNv, 0x00610200);
+		val = NVRead(pNv, 0x00610200);
 		if ((val & 0x9f0000) == 0x20000)
 			NVWrite(pNv, 0x00610200, val | 0x800000);
 
 		if ((val & 0x3f0000) == 0x30000)
 			NVWrite(pNv, 0x00610200, val | 0x200000);
-	} while ((NVRead(pNv, 0x00610200) & 0x1e0000) != 0);
+	} while ((val & 0x1e0000) != 0);
 	NVWrite(pNv, 0x00610300, 0x1);
 	NVWrite(pNv, 0x00610200, 0x1000b03);
 	while (!(NVRead(pNv, 0x00610200) & 0x40000000));
 
 	NV50DisplayCommand(pScrn, 0x84, 0);
 	NV50DisplayCommand(pScrn, 0x88, 0);
-	NV50DisplayCommand(pScrn, 0x874, 0);
+	/* Does the bios always use crtc0? */
+	NV50DisplayCommand(pScrn, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_BLANK);
 	NV50DisplayCommand(pScrn, 0x800, 0);
 	NV50DisplayCommand(pScrn, 0x810, 0);
 	NV50DisplayCommand(pScrn, 0x82c, 0);
@@ -248,7 +250,7 @@ NV50DispShutdown(ScrnInfoPtr pScrn)
 		NV50CrtcBlankScreen(crtc, TRUE);
 	}
 
-	NV50DisplayCommand(pScrn, 0x80, 0);
+	NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
 
 	for(i = 0; i < xf86_config->num_crtc; i++) {
 		xf86CrtcPtr crtc = xf86_config->crtc[i];
@@ -339,7 +341,7 @@ NV50CrtcModeSet(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_m
 			NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_24BPP); 
 			break;
 	}
-	NV50CrtcSetDither(crtc, nv_crtc->ditherEnabled, FALSE);
+	NV50CrtcSetDither(crtc, FALSE);
 	NV50CrtcCommand(crtc, 0x8a8, 0x40000);
 	NV50CrtcCommand(crtc, NV50_CRTC0_FB_POS, y << 16 | x);
 	NV50CrtcCommand(crtc, NV50_CRTC0_SCRN_SIZE, VDisplay << 16 | HDisplay);
@@ -361,10 +363,10 @@ NV50CrtcBlankScreen(xf86CrtcPtr crtc, Bool blank)
 		NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE, NV50_CRTC0_CLUT_MODE_BLANK);
 		NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, 0);
 		if(pNv->NVArch != 0x50)
-			NV50CrtcCommand(crtc, 0x85c, 0);
-		NV50CrtcCommand(crtc, 0x874, 0);
+			NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_BLANK);
+		NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_BLANK);
 		if(pNv->NVArch != 0x50)
-			NV50CrtcCommand(crtc, 0x89c, 0);
+			NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_BLANK);
 	} else {
 		NV50CrtcCommand(crtc, NV50_CRTC0_FB_OFFSET, pNv->FB->offset >> 8);
 		NV50CrtcCommand(crtc, 0x864, 0);
@@ -375,15 +377,15 @@ NV50CrtcBlankScreen(xf86CrtcPtr crtc, Bool blank)
 		NVWrite(pNv, 0x0061038C, 0);
 		NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_OFFSET, pNv->Cursor->offset >> 8);
 		if(pNv->NVArch != 0x50)
-			NV50CrtcCommand(crtc, 0x89c, 1);
+			NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_UNBLANK);
 		if(nv_crtc->cursorVisible)
 			NV50CrtcShowHideCursor(crtc, TRUE, FALSE);
 		NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE, 
 			pScrn->depth == 8 ? NV50_CRTC0_CLUT_MODE_OFF : NV50_CRTC0_CLUT_MODE_ON);
 		NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, pNv->CLUT->offset >> 8);
 		if(pNv->NVArch != 0x50)
-			NV50CrtcCommand(crtc, 0x85c, 1);
-		NV50CrtcCommand(crtc, 0x874, 1);
+			NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_UNBLANK);
+		NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL_BLANK, NV50_CRTC0_BLANK_CTRL_UNBLANK);
      }
 }
 
@@ -391,12 +393,13 @@ NV50CrtcBlankScreen(xf86CrtcPtr crtc, Bool blank)
 static void NV50CrtcShowHideCursor(xf86CrtcPtr crtc, Bool show, Bool update)
 {
 	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
+	ScrnInfoPtr pScrn = crtc->scrn;
 
-	NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR0, 
-		show ? NV50_CRTC0_CURSOR0_SHOW : NV50_CRTC0_CURSOR0_HIDE);
-	if(update) {
+	NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR, 
+		show ? NV50_CRTC0_CURSOR_SHOW : NV50_CRTC0_CURSOR_HIDE);
+	if (update) {
 		nv_crtc->cursorVisible = show;
-		NV50CrtcCommand(crtc, 0x80, 0);
+		NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
 	}
 }
 
@@ -438,15 +441,20 @@ NV50CrtcSkipModeFixup(xf86CrtcPtr crtc)
 }
 
 void
-NV50CrtcSetDither(xf86CrtcPtr crtc, Bool dither, Bool update)
+NV50CrtcSetDither(xf86CrtcPtr crtc, Bool update)
 {
-	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
+	xf86OutputPtr output = NVGetOutputFromCRTC(crtc);
+	ScrnInfoPtr pScrn = crtc->scrn;
 
-	nv_crtc->ditherEnabled = dither;
+	if (!output)
+		return;
 
-	NV50CrtcCommand(crtc, 0x8a0, dither ? 0x11 : 0);
-	if(update) 
-		NV50CrtcCommand(crtc, 0x80, 0);
+	NVOutputPrivatePtr nv_output = output->driver_private;
+
+	NV50CrtcCommand(crtc, NV50_CRTC0_DITHERING_CTRL, nv_output->dithering ? 
+			NV50_CRTC0_DITHERING_CTRL_ON : NV50_CRTC0_DITHERING_CTRL_OFF);
+	if (update) 
+		NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
 }
 
 static void ComputeAspectScale(DisplayModePtr mode, int *outX, int *outY)
@@ -499,6 +507,7 @@ void
 NV50CrtcCommit(xf86CrtcPtr crtc)
 {
 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+	ScrnInfoPtr pScrn = crtc->scrn;
 	int i, crtc_mask = 0;
 
 	/* If any heads are unused, blank them */
@@ -517,6 +526,6 @@ NV50CrtcCommit(xf86CrtcPtr crtc)
 		}
 	}
 
-	NV50CrtcCommand(crtc, 0x80, 0);
+	NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
 }
 
diff --git a/src/nv50_display.h b/src/nv50_display.h
index 74f2a26..d8c2498 100644
--- a/src/nv50_display.h
+++ b/src/nv50_display.h
@@ -15,9 +15,10 @@ void NV50CrtcEnableCursor(xf86CrtcPtr, Bool update);
 void NV50CrtcDisableCursor(xf86CrtcPtr, Bool update);
 void NV50CrtcSetCursorPosition(xf86CrtcPtr, int x, int y);
 void NV50CrtcSkipModeFixup(xf86CrtcPtr);
-void NV50CrtcSetDither(xf86CrtcPtr, Bool dither, Bool update);
+void NV50CrtcSetDither(xf86CrtcPtr, Bool update);
 void NV50CrtcSetScale(xf86CrtcPtr, DisplayModePtr, enum scaling_modes);
 
 void NV50DispCreateCrtcs(ScrnInfoPtr pScrn);
+const xf86CrtcFuncsRec * nv50_get_crtc_funcs();
 
 #endif
diff --git a/src/nv50_output.c b/src/nv50_output.c
index fa63b21..564db4c 100644
--- a/src/nv50_output.c
+++ b/src/nv50_output.c
@@ -30,143 +30,6 @@
 
 #include <xf86DDC.h>
 
-static Bool NV50ReadPortMapping(int scrnIndex, NVPtr pNv)
-{
-	 unsigned const char *VBIOS = (unsigned const char *)pNv->VBIOS.data;
-	 unsigned char *table2;
-	 unsigned char headerSize, entries;
-	 int i;
-	 CARD16 a;
-	 CARD32 b;
-
-	 if (!VBIOS)
-		goto fail;
-
-	 /* Clear the i2c map to invalid */
-	 for (i = 0; i < 4; i++)
-		pNv->i2cMap[i].dac = pNv->i2cMap[i].sor = -1;
-
-	if (*(CARD16*)VBIOS != 0xaa55) goto fail;
-
-	a = *(CARD16*)(VBIOS + 0x36);
-	table2 = (unsigned char*)VBIOS + a;
-
-	if (table2[0] != 0x40) goto fail;
-
-	b = *(CARD32*)(table2 + 6);
-	if (b != 0x4edcbdcb) goto fail;
-
-	headerSize = table2[1];
-	entries = table2[2];
-
-	for(i = 0; i < entries; i++) {
-		int type, port;
-		ORNum or;
-
-		b = *(CARD32*)&table2[headerSize + 8*i];
-		type = b & 0xf;
-		port = (b >> 4) & 0xf;
-		or = ffs((b >> 24) & 0xf) - 1;
-
-		if (type == 0xe)
-			break;
-
-		if(type < 4) {
-			switch(type) {
-				case 0: /* CRT */
-					if(pNv->i2cMap[port].dac != -1) {
-						xf86DrvMsg(scrnIndex, X_WARNING,
-							"DDC routing table corrupt!  DAC %i -> %i "
-							"for port %i\n",
-							or, pNv->i2cMap[port].dac, port);
-					}
-					pNv->i2cMap[port].dac = or;
-					break;
-				case 1: /* TV */
-					break;
-				case 2: /* TMDS */
-					if(pNv->i2cMap[port].sor != -1)
-						xf86DrvMsg(scrnIndex, X_WARNING,
-							"DDC routing table corrupt!  SOR %i -> %i "
-							"for port %i\n",
-							or, pNv->i2cMap[port].sor, port);
-					pNv->i2cMap[port].sor = or;
-					break;
-				case 3: /* LVDS */
-					pNv->lvds.present = TRUE;
-					pNv->lvds.or = or;
-					break;
-			}
-		}
-	}
-
-	xf86DrvMsg(scrnIndex, X_PROBED, "Connector map:\n");
-	if (pNv->lvds.present) {
-		xf86DrvMsg(scrnIndex, X_PROBED,
-			"  [N/A] -> SOR%i (LVDS)\n", pNv->lvds.or);
-	}
-	 for(i = 0; i < 4; i++) {
-		if(pNv->i2cMap[i].dac != -1)
-			xf86DrvMsg(scrnIndex, X_PROBED, "  Bus %i -> DAC%i\n", i, pNv->i2cMap[i].dac);
-		if(pNv->i2cMap[i].sor != -1)
-			xf86DrvMsg(scrnIndex, X_PROBED, "  Bus %i -> SOR%i\n", i, pNv->i2cMap[i].sor);
-	}
-
-	return TRUE;
-
-	fail:
-		xf86DrvMsg(scrnIndex, X_ERROR, "Couldn't find the DDC routing table.  "
-			"Mode setting will probably fail!\n");
-		return FALSE;
-}
-
-static void NV50_I2CPutBits(I2CBusPtr b, int clock, int data)
-{
-	NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
-	const int off = b->DriverPrivate.val * 0x18;
-
-	pNv->REGS[(0x0000E138+off)/4] = 4 | clock | data << 1;
-}
-
-static void NV50_I2CGetBits(I2CBusPtr b, int *clock, int *data)
-{
-	NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
-	const int off = b->DriverPrivate.val * 0x18;
-	unsigned char val;
-
-	val = pNv->REGS[(0x0000E138+off)/4];
-	*clock = !!(val & 1);
-	*data = !!(val & 2);
-}
-
-static I2CBusPtr
-NV50I2CInit(ScrnInfoPtr pScrn, const char *name, const int port)
-{
-	I2CBusPtr i2c;
-
-	/* Allocate the I2C bus structure */
-	i2c = xf86CreateI2CBusRec();
-	if(!i2c) return NULL;
-
-	i2c->BusName = strdup(name);
-	i2c->scrnIndex = pScrn->scrnIndex;
-	i2c->I2CPutBits = NV50_I2CPutBits;
-	i2c->I2CGetBits = NV50_I2CGetBits;
-	i2c->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
-	i2c->StartTimeout = 550;
-	i2c->BitTimeout = 40;
-	i2c->ByteTimeout = 40;
-	i2c->AcknTimeout = 40;
-	i2c->DriverPrivate.val = port;
-
-	if(xf86I2CBusInit(i2c)) {
-		return i2c;
-	} else {
-		xfree(i2c);
-		return NULL;
-	}
-}
-
 void
 NV50OutputSetPClk(xf86OutputPtr output, int pclk)
 {
@@ -245,72 +108,3 @@ NV50OutputDestroy(xf86OutputPtr output)
 
 	nv_output->pDDCBus = NULL;
 }
-
-Bool
-NV50CreateOutputs(ScrnInfoPtr pScrn)
-{
-	NVPtr pNv = NVPTR(pScrn);
-	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
-	int i;
-
-	if(!NV50ReadPortMapping(pScrn->scrnIndex, pNv))
-		return FALSE;
-
-	/* For each DDC port, create an output for the attached ORs */
-	for (i = 0; i < 4; i++) {
-		xf86OutputPtr dac = NULL, sor = NULL;
-		I2CBusPtr i2c;
-		char i2cName[16];
-
-		if(pNv->i2cMap[i].dac == -1 && pNv->i2cMap[i].sor == -1) {
-			/* No outputs on this port */
-			continue;
-		}
-
-		snprintf(i2cName, sizeof(i2cName), "I2C%i", i);
-		i2c = NV50I2CInit(pScrn, i2cName, i);
-		if (!i2c) {
-		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-				"Failed to initialize I2C for port %i.\n",
-				i);
-			continue;
-		}
-
-		if (pNv->i2cMap[i].dac != -1)
-			dac = NV50CreateDac(pScrn, pNv->i2cMap[i].dac);
-		if (pNv->i2cMap[i].sor != -1)
-			sor = NV50CreateSor(pScrn, pNv->i2cMap[i].sor, OUTPUT_TMDS);
-
-		if (dac) {
-			NVOutputPrivatePtr nv_output = dac->driver_private;
-
-			nv_output->pDDCBus = i2c;
-			nv_output->scaling_mode = SCALE_PANEL;
-		}
-		if (sor) {
-			NVOutputPrivatePtr nv_output = sor->driver_private;
-
-			nv_output->pDDCBus = i2c;
-			nv_output->scaling_mode = SCALE_ASPECT;
-		}
-	}
-
-	if (pNv->lvds.present) {
-		xf86OutputPtr lvds = NV50CreateSor(pScrn, pNv->lvds.or, OUTPUT_LVDS);
-		NVOutputPrivatePtr nv_output = lvds->driver_private;
-
-		nv_output->scaling_mode = SCALE_ASPECT;
-	}
-
-	/* For each output, set the crtc and clone masks */
-	for(i = 0; i < xf86_config->num_output; i++) {
-		xf86OutputPtr output = xf86_config->output[i];
-
-		/* Any output can connect to any head */
-		output->possible_crtcs = 0x3;
-		output->possible_clones = 0;
-	}
-
-	return TRUE;
-}
-
diff --git a/src/nv50_output.h b/src/nv50_output.h
index 53b913f..67f3deb 100644
--- a/src/nv50_output.h
+++ b/src/nv50_output.h
@@ -10,15 +10,18 @@ void NV50OutputPrepare(xf86OutputPtr);
 void NV50OutputCommit(xf86OutputPtr);
 DisplayModePtr NV50OutputGetDDCModes(xf86OutputPtr);
 void NV50OutputDestroy(xf86OutputPtr);
-Bool NV50CreateOutputs(ScrnInfoPtr);
 
 /* nv50_dac.c */
 xf86OutputPtr NV50CreateDac(ScrnInfoPtr, ORNum);
 Bool NV50DacLoadDetect(xf86OutputPtr);
 void NV50DacSetPClk(xf86OutputPtr output, int pclk);
+const xf86OutputFuncsRec * nv50_get_analog_output_funcs();
 
 /* nv50_sor.c */
 xf86OutputPtr NV50CreateSor(ScrnInfoPtr pScrn, ORNum or, NVOutputType type);
 void NV50SorSetPClk(xf86OutputPtr output, int pclk);
+const xf86OutputFuncsRec * nv50_get_tmds_output_funcs();
+const xf86OutputFuncsRec * nv50_get_lvds_output_funcs();
+DisplayModePtr GetLVDSNativeMode(ScrnInfoPtr pScrn);
 
 #endif
diff --git a/src/nv50_sor.c b/src/nv50_sor.c
index a04d928..4f408e5 100644
--- a/src/nv50_sor.c
+++ b/src/nv50_sor.c
@@ -252,150 +252,6 @@ NV50SorGetLVDSModes(xf86OutputPtr output)
 	return xf86DuplicateMode(nv_output->native_mode);
 }
 
-#define MAKE_ATOM(a) MakeAtom((a), sizeof(a) - 1, TRUE);
-
-struct property {
-	Atom atom;
-	INT32 range[2];
-};
-
-static struct {
-	struct property dither;
-	struct property scale;
-} properties;
-
-static void
-NV50SorCreateResources(xf86OutputPtr output)
-{
-	ScrnInfoPtr pScrn = output->scrn;
-	NVPtr pNv = NVPTR(pScrn);
-	int data, err;
-	const char *s;
-
-	/******** dithering ********/
-	properties.dither.atom = MAKE_ATOM("dither");
-	properties.dither.range[0] = 0;
-	properties.dither.range[1] = 1;
-	err = RRConfigureOutputProperty(output->randr_output,
-					properties.dither.atom, FALSE, TRUE, FALSE,
-					2, properties.dither.range);
-	if(err)
-		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-			"Failed to configure dithering property for %s: error %d\n",
-			output->name, err);
-
-	// Set the default value
-	data = pNv->FPDither;
-	err = RRChangeOutputProperty(output->randr_output, properties.dither.atom,
-					XA_INTEGER, 32, PropModeReplace, 1, &data,
-					FALSE, FALSE);
-	if(err)
-		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-			"Failed to set dithering property for %s: error %d\n",
-			output->name, err);
-
-	/******** scaling ********/
-	properties.scale.atom = MAKE_ATOM("scale");
-	err = RRConfigureOutputProperty(output->randr_output,
-					properties.scale.atom, FALSE, FALSE,
-					FALSE, 0, NULL);
-	if(err)
-		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-			"Failed to configure scaling property for %s: error %d\n",
-			output->name, err);
-
-	// Set the default value
-	s = "aspect";
-	err = RRChangeOutputProperty(output->randr_output, properties.scale.atom,
-					XA_STRING, 8, PropModeReplace, strlen(s),
-					(pointer)s, FALSE, FALSE);
-	if(err)
-		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-			"Failed to set scaling property for %s: error %d\n",
-			output->name, err);
-}
-
-static Bool
-NV50SorSetProperty(xf86OutputPtr output, Atom prop, RRPropertyValuePtr val)
-{
-	NVOutputPrivatePtr nv_output = output->driver_private;
-
-	if(prop == properties.dither.atom) {
-		INT32 i;
-
-		if (val->type != XA_INTEGER || val->format != 32 || val->size != 1)
-			return FALSE;
-
-		i = *(INT32*)val->data;
-		if (i < properties.dither.range[0] || i > properties.dither.range[1])
-			return FALSE;
-
-		NV50CrtcSetDither(output->crtc, i, TRUE);
-		return TRUE;
-	} else if (prop == properties.scale.atom) {
-		const char *s;
-		enum scaling_modes oldScale, scale;
-		int i;
-		const struct {
-			const char *name;
-			enum scaling_modes scale;
-		} modes[] = {
-			{ "panel", SCALE_PANEL },
-			{ "aspect", SCALE_ASPECT },
-			{ "fullscreen",   SCALE_FULLSCREEN },
-			{ "noscale", SCALE_NOSCALE },
-			{ NULL,     0 },
-		};
-
-		if (val->type != XA_STRING || val->format != 8)
-			return FALSE;
-		s = (char*)val->data;
-
-		for (i = 0; modes[i].name; i++) {
-			const char *name = modes[i].name;
-			const int len = strlen(name);
-
-			if(val->size == len && !strncmp(name, s, len)) {
-				scale = modes[i].scale;
-				break;
-			}
-		}
-		if (!modes[i].name)
-			return FALSE;
-		if (scale == SCALE_PANEL && nv_output->type == OUTPUT_LVDS)
-			// LVDS requires scaling
-			return FALSE;
-
-		oldScale = nv_output->scaling_mode;
-		nv_output->scaling_mode = scale;
-		if (output->crtc) {
-			xf86CrtcPtr crtc = output->crtc;
-
-			if (!xf86CrtcSetMode(crtc, &crtc->desiredMode, crtc->desiredRotation,
-					crtc->desiredX, crtc->desiredY)) {
-				xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
-						"Failed to set scaling to %s for output %s\n",
-						modes[i].name, output->name);
-
-				// Restore old scale and try again.
-				nv_output->scaling_mode = oldScale;
-				if (!xf86CrtcSetMode(crtc, &crtc->desiredMode,
-							crtc->desiredRotation, crtc->desiredX,
-							crtc->desiredY)) {
-					xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
-						"Failed to restore old scaling for output %s\n",
-						output->name);
-				}
-
-				return FALSE;
-			}
-		}
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
 static const xf86OutputFuncsRec NV50SorTMDSOutputFuncs = {
 	.dpms = NV50SorDPMSSet,
 	.save = NULL,
@@ -407,8 +263,8 @@ static const xf86OutputFuncsRec NV50SorTMDSOutputFuncs = {
 	.mode_set = NV50SorModeSet,
 	.detect = NV50SorDetect,
 	.get_modes = NV50OutputGetDDCModes,
-	.create_resources = NV50SorCreateResources,
-	.set_property = NV50SorSetProperty,
+	.create_resources = nv_digital_output_create_resources,
+	.set_property = nv_digital_output_set_property,
 	.destroy = NV50SorDestroy,
 };
 
@@ -423,11 +279,21 @@ static const xf86OutputFuncsRec NV50SorLVDSOutputFuncs = {
 	.mode_set = NV50SorModeSet,
 	.detect = NV50SorLVDSDetect,
 	.get_modes = NV50SorGetLVDSModes,
-	.create_resources = NV50SorCreateResources,
-	.set_property = NV50SorSetProperty,
+	.create_resources = nv_digital_output_create_resources,
+	.set_property = nv_digital_output_set_property,
 	.destroy = NV50SorDestroy,
 };
 
+const xf86OutputFuncsRec * nv50_get_tmds_output_funcs()
+{
+	return &NV50SorTMDSOutputFuncs;
+}
+
+const xf86OutputFuncsRec * nv50_get_lvds_output_funcs()
+{
+	return &NV50SorLVDSOutputFuncs;
+}
+
 static DisplayModePtr
 ReadLVDSNativeMode(ScrnInfoPtr pScrn, const int off)
 {
@@ -454,7 +320,7 @@ ReadLVDSNativeMode(ScrnInfoPtr pScrn, const int off)
 	return mode;
 }
 
-static DisplayModePtr
+DisplayModePtr
 GetLVDSNativeMode(ScrnInfoPtr pScrn)
 {
 	NVPtr pNv = NVPTR(pScrn);
@@ -468,55 +334,3 @@ GetLVDSNativeMode(ScrnInfoPtr pScrn)
 
 	return NULL;
 }
-
-xf86OutputPtr
-NV50CreateSor(ScrnInfoPtr pScrn, ORNum or, NVOutputType type)
-{
-	NVOutputPrivatePtr nv_output = xnfcalloc(sizeof(*nv_output), 1);
-	NVPtr pNv = NVPTR(pScrn);
-	xf86OutputPtr output;
-	char orName[5];
-	const xf86OutputFuncsRec *funcs;
-
-	if(!nv_output)
-		return NULL;
-
-	if(type == OUTPUT_LVDS) {
-		strcpy(orName, "LVDS");
-		funcs = &NV50SorLVDSOutputFuncs;
-
-		nv_output->native_mode = GetLVDSNativeMode(pScrn);
-
-		if(!nv_output->native_mode) {
-			xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
-				"Failed to find LVDS native mode\n");
-			xfree(nv_output);
-			return NULL;
-		}
-
-		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s native size %dx%d\n",
-			orName, nv_output->native_mode->HDisplay,
-			nv_output->native_mode->VDisplay);
-	} else {
-		snprintf(orName, 5, "DVI%d", or);
-		funcs = &NV50SorTMDSOutputFuncs;
-	}
-
-	output = xf86OutputCreate(pScrn, funcs, orName);
-
-	nv_output->output_resource = or;
-	nv_output->type = type;
-	output->driver_private = nv_output;
-	output->interlaceAllowed = TRUE;
-	output->doubleScanAllowed = TRUE;
-
-	if (type != OUTPUT_LVDS) {
-		NVWrite(pNv, 0x0061c00c + nv_output->output_resource * 0x800, 0x03010700);
-		NVWrite(pNv, 0x0061c010 + nv_output->output_resource * 0x800, 0x0000152f);
-		NVWrite(pNv, 0x0061c014 + nv_output->output_resource * 0x800, 0x00000000);
-		NVWrite(pNv, 0x0061c018 + nv_output->output_resource * 0x800, 0x00245af8);
-	}
-
-	return output;
-}
-
diff --git a/src/nv50reg.h b/src/nv50reg.h
index 70a2656..44fa8c5 100644
--- a/src/nv50reg.h
+++ b/src/nv50reg.h
@@ -30,36 +30,92 @@
 #define NV50_CRTC_VPLL2_A		0x00614904
 #define NV50_CRTC_VPLL2_B		0x00614908
 
+/* Clamped to 256 MiB */
+#define NV50_CRTC0_RAM_AMOUNT		0x00610384
+#define NV50_CRTC1_RAM_AMOUNT		0x00610784
+
 /* These things below are so called "commands" */
+#define NV50_UPDATE_DISPLAY		0x80
+
 #define NV50_CRTC0_CLOCK			0x804
-#define NV50_CRTC1_CLOCK			0xC04
 #define NV50_CRTC0_INTERLACE		0x808
-#define NV50_CRTC1_INTERLACE		0xC08
 
 #define NV50_CRTC0_HBLANK_START	0x814
 #define NV50_CRTC0_HSYNC_END		0x818
 #define NV50_CRTC0_HBLANK_END		0x81C
 #define NV50_CRTC0_HTOTAL			0x820
 
+/* You can't have a palette in 8 bit mode (=OFF) */
+#define NV50_CRTC0_CLUT_MODE		0x840
+	#define NV50_CRTC0_CLUT_MODE_BLANK		0x00000000
+	#define NV50_CRTC0_CLUT_MODE_OFF		0x80000000
+	#define NV50_CRTC0_CLUT_MODE_ON		0xC0000000
+#define NV50_CRTC0_CLUT_OFFSET		0x844
+
+/* Anyone know what part of the chip is triggered here precisely? */
+#define NV84_CRTC0_BLANK_UNK1		0x85C
+	#define NV84_CRTC0_BLANK_UNK1_BLANK	0x0
+	#define NV84_CRTC0_BLANK_UNK1_UNBLANK	0x1
+
+#define NV50_CRTC0_FB_OFFSET		0x860
+
+#define NV50_CRTC0_FB_SIZE			0x868
+#define NV50_CRTC0_PITCH			0x86C
+
+#define NV50_CRTC0_DEPTH			0x870
+	#define NV50_CRTC0_DEPTH_8BPP		0x1E00
+	#define NV50_CRTC0_DEPTH_15BPP	0xE900
+	#define NV50_CRTC0_DEPTH_16BPP	0xE800
+	#define NV50_CRTC0_DEPTH_24BPP	0xCF00
+
+/* I'm openminded to better interpretations. */
+/* This is an educated guess. */
+/* NV50 has RAMDAC and TMDS offchip, so it's unlikely to be that. */
+#define NV50_CRTC0_BLANK_CTRL		0x874
+	#define NV50_CRTC0_BLANK_CTRL_BLANK	0x0
+	#define NV50_CRTC0_BLANK_CTRL_UNBLANK	0x1
+
+#define NV50_CRTC0_CURSOR		0x880
+	#define NV50_CRTC0_CURSOR_SHOW		0x85000000
+	#define NV50_CRTC0_CURSOR_HIDE		0x05000000
+
+#define NV50_CRTC0_CURSOR_OFFSET	0x884
+
+/* Anyone know what part of the chip is triggered here precisely? */
+#define NV84_CRTC0_BLANK_UNK2		0x89C
+	#define NV84_CRTC0_BLANK_UNK2_BLANK	0x0
+	#define NV84_CRTC0_BLANK_UNK2_UNBLANK	0x1
+
+#define NV50_CRTC0_DITHERING_CTRL	0x8A0
+	#define NV50_CRTC0_DITHERING_CTRL_ON	0x11
+	#define NV50_CRTC0_DITHERING_CTRL_OFF	0x0
+
+#define NV50_CRTC0_FB_POS			0x8C0
+#define NV50_CRTC0_SCRN_SIZE		0x8C8
+
+#define NV50_CRTC1_CLOCK			0xC04
+#define NV50_CRTC1_INTERLACE		0xC08
+
 #define NV50_CRTC1_HBLANK_START	0xC14
 #define NV50_CRTC1_HSYNC_END		0xC18
 #define NV50_CRTC1_HBLANK_END		0xC1C
 #define NV50_CRTC1_HTOTAL			0xC20
 
-#define NV50_CRTC0_FB_SIZE			0x868
+#define NV50_CRTC1_CLUT_MODE		0xC40
+	#define NV50_CRTC1_CLUT_MODE_BLANK		0x00000000
+	#define NV50_CRTC1_CLUT_MODE_OFF		0x80000000
+	#define NV50_CRTC1_CLUT_MODE_ON		0xC0000000
+#define NV50_CRTC1_CLUT_OFFSET		0xC44
+
+/* Anyone know what part of the chip is triggered here precisely? */
+#define NV84_CRTC1_BLANK_UNK1		0xC5C
+	#define NV84_CRTC1_BLANK_UNK1_BLANK	0x0
+	#define NV84_CRTC1_BLANK_UNK1_UNBLANK	0x1
+
+#define NV50_CRTC1_FB_OFFSET		0xC60
+
 #define NV50_CRTC1_FB_SIZE			0xC68
-#define NV50_CRTC0_PITCH			0x86C
 #define NV50_CRTC1_PITCH			0xC6C
-#define NV50_CRTC0_FB_POS			0x8C0
-#define NV50_CRTC1_FB_POS			0xCC0
-#define NV50_CRTC0_SCRN_SIZE		0x8C8
-#define NV50_CRTC1_SCRN_SIZE		0xCC8
-
-#define NV50_CRTC0_DEPTH			0x870
-#define NV50_CRTC0_DEPTH_8BPP		0x1E00
-#define NV50_CRTC0_DEPTH_15BPP	0xE900
-#define NV50_CRTC0_DEPTH_16BPP	0xE800
-#define NV50_CRTC0_DEPTH_24BPP	0xCF00
 
 #define NV50_CRTC1_DEPTH			0xC70
 	#define NV50_CRTC1_DEPTH_8BPP		0x1E00
@@ -67,35 +123,27 @@
 	#define NV50_CRTC1_DEPTH_16BPP	0xE800
 	#define NV50_CRTC1_DEPTH_24BPP	0xCF00
 
-#define NV50_CRTC0_FB_OFFSET		0x860
-#define NV50_CRTC1_FB_OFFSET		0xC60
+/* I'm openminded to better interpretations. */
+#define NV50_CRTC1_BLANK_CTRL		0xC74
+	#define NV50_CRTC1_BLANK_CTRL_BLANK	0x0
+	#define NV50_CRTC1_BLANK_CTRL_UNBLANK	0x1
 
-#define NV50_CRTC0_CURSOR_OFFSET	0x884
-#define NV50_CRTC1_CURSOR_OFFSET	0xC84
+#define NV50_CRTC1_CURSOR		0xC80
+	#define NV50_CRTC1_CURSOR_SHOW		0x85000000
+	#define NV50_CRTC1_CURSOR_HIDE		0x05000000
 
-/* You can't have a palette in 8 bit mode (=OFF) */
-#define NV50_CRTC0_CLUT_MODE		0x840
-	#define NV50_CRTC0_CLUT_MODE_BLANK		0x00000000
-	#define NV50_CRTC0_CLUT_MODE_OFF		0x80000000
-	#define NV50_CRTC0_CLUT_MODE_ON		0xC0000000
-#define NV50_CRTC0_CLUT_OFFSET		0x844
-
-#define NV50_CRTC1_CLUT_MODE		0xC40
-	#define NV50_CRTC1_CLUT_MODE_BLANK		0x00000000
-	#define NV50_CRTC1_CLUT_MODE_OFF		0x80000000
-	#define NV50_CRTC1_CLUT_MODE_ON		0xC0000000
-#define NV50_CRTC1_CLUT_OFFSET		0xC44
+#define NV50_CRTC1_CURSOR_OFFSET	0xC84
 
-/* Clamped to 256 MiB */
-#define NV50_CRTC0_RAM_AMOUNT		0x00610384
-#define NV50_CRTC1_RAM_AMOUNT		0x00610784
+/* Anyone know what part of the chip is triggered here precisely? */
+#define NV84_CRTC1_BLANK_UNK2		0xC9C
+	#define NV84_CRTC1_BLANK_UNK2_BLANK	0x0
+	#define NV84_CRTC1_BLANK_UNK2_UNBLANK	0x1
 
-#define NV50_CRTC0_CURSOR0		0x880
-	#define NV50_CRTC0_CURSOR0_SHOW		0x85000000
-	#define NV50_CRTC0_CURSOR0_HIDE		0x05000000
+#define NV50_CRTC1_DITHERING_CTRL	0xCA0
+	#define NV50_CRTC1_DITHERING_CTRL_ON	0x11
+	#define NV50_CRTC1_DITHERING_CTRL_OFF	0x0
 
-#define NV50_CRTC1_CURSOR0		0xC80
-	#define NV50_CRTC1_CURSOR0_SHOW		0x85000000
-	#define NV50_CRTC1_CURSOR0_HIDE		0x05000000
+#define NV50_CRTC1_FB_POS			0xCC0
+#define NV50_CRTC1_SCRN_SIZE		0xCC8
 
 #endif /* __NV50REG_H_ */
diff --git a/src/nv_crtc.c b/src/nv_crtc.c
index 83bf3df..2d8e23c 100644
--- a/src/nv_crtc.c
+++ b/src/nv_crtc.c
@@ -102,7 +102,7 @@ void NVCrtcLockUnlock(xf86CrtcPtr crtc, Bool lock)
 	NVLockVgaCrtc(pNv, nv_crtc->head, lock);
 }
 
-static xf86OutputPtr
+xf86OutputPtr
 NVGetOutputFromCRTC(xf86CrtcPtr crtc)
 {
 	ScrnInfoPtr pScrn = crtc->scrn;
@@ -1228,8 +1228,8 @@ nv_crtc_mode_set_ramdac_regs(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModeP
 
 	/* Flatpanel support needs at least a NV10 */
 	if (pNv->twoHeads) {
-		if (pNv->FPDither || (is_lvds && !pNv->VBIOS.fp.if_is_24bit)) {
-			nv_crtc->ditherEnabled = TRUE;
+		/* Output property. */
+		if (nv_output && nv_output->dithering) {
 			if (pNv->NVArch == 0x11)
 				regp->dither = savep->dither | 0x00010000;
 			else {
@@ -1241,7 +1241,14 @@ nv_crtc_mode_set_ramdac_regs(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModeP
 				}
 			}
 		} else {
-			nv_crtc->ditherEnabled = FALSE;
+			if (pNv->NVArch != 0x11) {
+				/* reset them */
+				int i;
+				for (i = 0; i < 3; i++) {
+					regp->dither_regs[i] = savep->dither_regs[i];
+					regp->dither_regs[i + 3] = savep->dither_regs[i + 3];
+				}
+			}
 			regp->dither = savep->dither;
 		}
 	}
@@ -1744,7 +1751,9 @@ nv_crtc_init(ScrnInfoPtr pScrn, int crtc_num)
 	NVCrtcRegPtr regp = &pNv->ModeReg.crtc_reg[crtc_num];
 	int i;
 
-	if (pNv->NVArch >= 0x11)
+	if (pNv->Architecture == NV_ARCH_50)
+		crtc = xf86CrtcCreate(pScrn, nv50_get_crtc_funcs());
+	else if (pNv->NVArch >= 0x11)
 		crtc = xf86CrtcCreate(pScrn, &nv11_crtc_funcs);
 	else
 		crtc = xf86CrtcCreate(pScrn, &nv_crtc_funcs);
@@ -1754,10 +1763,12 @@ nv_crtc_init(ScrnInfoPtr pScrn, int crtc_num)
 	nv_crtc = xnfcalloc (sizeof (NVCrtcPrivateRec), 1);
 	nv_crtc->head = crtc_num;
 	nv_crtc->last_dpms = NV_DPMS_CLEARED;
-	nv_crtc->ditherEnabled = pNv->FPDither;
 
 	crtc->driver_private = nv_crtc;
 
+	if (pNv->Architecture == NV_ARCH_50)
+		return;
+
 	/* Initialise the default LUT table. */
 	for (i = 0; i < 256; i++) {
 		regp->DAC[i*3] = i;
diff --git a/src/nv_driver.c b/src/nv_driver.c
index 79a479a..03d153b 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -1424,23 +1424,19 @@ NVPreInit(ScrnInfoPtr pScrn, int flags)
 	NVCommonSetup(pScrn);
 
 	if (pNv->randr12_enable) {
-		if (pNv->Architecture < NV_ARCH_50) {
-			NVI2CInit(pScrn);
-
-			num_crtc = pNv->twoHeads ? 2 : 1;
-			for (i = 0; i < num_crtc; i++) {
-				nv_crtc_init(pScrn, i);
-			}
-
-			NvSetupOutputs(pScrn);
-		} else {
+		if (pNv->Architecture == NV_ARCH_50)
 			if (!NV50DispPreInit(pScrn))
 				NVPreInitFail("\n");
-			if (!NV50CreateOutputs(pScrn))
-				NVPreInitFail("\n");
-			NV50DispCreateCrtcs(pScrn);
+
+		NVI2CInit(pScrn);
+
+		num_crtc = pNv->twoHeads ? 2 : 1;
+		for (i = 0; i < num_crtc; i++) {
+			nv_crtc_init(pScrn, i);
 		}
 
+		NvSetupOutputs(pScrn);
+
 		if (!xf86InitialConfiguration(pScrn, FALSE))
 			NVPreInitFail("No valid modes.\n");
 	}
diff --git a/src/nv_i2c.c b/src/nv_i2c.c
index 8da2ca5..7b2aa49 100644
--- a/src/nv_i2c.c
+++ b/src/nv_i2c.c
@@ -46,10 +46,30 @@ NVI2CPutBits(I2CBusPtr b, int clock, int data)
 	NVWriteVgaCrtc(pNv, 0, b->DriverPrivate.uval + 1, val | 0x1);
 }
 
+static void NV50_I2CPutBits(I2CBusPtr b, int clock, int data)
+{
+	NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
+	const int off = b->DriverPrivate.val * 0x18;
+
+	NVWrite(pNv, (0x0000E138+off)/4, (4 | clock | data << 1));
+}
+
+static void NV50_I2CGetBits(I2CBusPtr b, int *clock, int *data)
+{
+	NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
+	const int off = b->DriverPrivate.val * 0x18;
+	unsigned char val;
+
+	val = NVRead(pNv, (0x0000E138+off)/4);
+	*clock = !!(val & 1);
+	*data = !!(val & 2);
+}
+
 Bool
 NV_I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg, char *name)
 {
 	I2CBusPtr pI2CBus;
+	NVPtr pNv = NVPTR(pScrn);
 
 	pI2CBus = xf86CreateI2CBusRec();
 	if(!pI2CBus)
@@ -57,9 +77,20 @@ NV_I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg, char *name)
 
 	pI2CBus->BusName    = name;
 	pI2CBus->scrnIndex  = pScrn->scrnIndex;
-	pI2CBus->I2CPutBits = NVI2CPutBits;
-	pI2CBus->I2CGetBits = NVI2CGetBits;
-	pI2CBus->AcknTimeout = 5;
+	if (pNv->Architecture == NV_ARCH_50) {
+		pI2CBus->I2CPutBits = NV50_I2CPutBits;
+		pI2CBus->I2CGetBits = NV50_I2CGetBits;
+		/* Could this be used for the rest as well? */
+		pI2CBus->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
+		pI2CBus->StartTimeout = 550;
+		pI2CBus->BitTimeout = 40;
+		pI2CBus->ByteTimeout = 40;
+		pI2CBus->AcknTimeout = 40;
+	} else {
+		pI2CBus->I2CPutBits = NVI2CPutBits;
+		pI2CBus->I2CGetBits = NVI2CGetBits;
+		pI2CBus->AcknTimeout = 5;
+	}
 
 	pI2CBus->DriverPrivate.uval = i2c_reg;
 
diff --git a/src/nv_output.c b/src/nv_output.c
index cb26c62..cea4bfd 100644
--- a/src/nv_output.c
+++ b/src/nv_output.c
@@ -738,6 +738,10 @@ static const struct {
 };
 static Atom scaling_mode_atom;
 
+#define DITHERING_MODE_NAME "DITHERING"
+static Atom dithering_atom;
+int32_t dithering_range[2];
+
 static int
 nv_scaling_mode_lookup(char *name, int size)
 {
@@ -756,7 +760,7 @@ nv_scaling_mode_lookup(char *name, int size)
 	return scaling_mode[i].mode;
 }
 
-static void
+void
 nv_digital_output_create_resources(xf86OutputPtr output)
 {
 	NVOutputPrivatePtr nv_output = output->driver_private;
@@ -791,9 +795,35 @@ nv_digital_output_create_resources(xf86OutputPtr output)
 		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
 			"Failed to set scaling mode, %d\n", error);
 	}
+
+	/*
+	 * Setup dithering property.
+	 */
+	dithering_atom = MakeAtom(DITHERING_MODE_NAME, sizeof(DITHERING_MODE_NAME) - 1, TRUE);
+
+	dithering_range[0] = 0;
+	dithering_range[1] = 1;
+
+	error = RRConfigureOutputProperty(output->randr_output,
+					dithering_atom, TRUE, TRUE, FALSE,
+					2, dithering_range);
+
+	if (error != 0) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			"RRConfigureOutputProperty error, %d\n", error);
+	}
+
+	error = RRChangeOutputProperty(output->randr_output, dithering_atom,
+					XA_INTEGER, 32, PropModeReplace, 1, &nv_output->dithering,
+					FALSE, FALSE);
+
+	if (error != 0) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			"Failed to set dithering mode, %d\n", error);
+	}
 }
 
-static Bool
+Bool
 nv_digital_output_set_property(xf86OutputPtr output, Atom property,
 				RRPropertyValuePtr value)
 {
@@ -819,6 +849,17 @@ nv_digital_output_set_property(xf86OutputPtr output, Atom property,
 
 		nv_output->scaling_mode = ret;
 		return TRUE;
+	} else if (property == dithering_atom) {
+		if (value->type != XA_INTEGER || value->format != 32)
+			return FALSE;
+
+		int32_t val = *(int32_t *) value->data;
+
+		if (val < dithering_range[0] || val > dithering_range[1])
+			return FALSE;
+
+		nv_output->dithering = val;
+		return TRUE;
 	}
 
 	return TRUE;
@@ -964,20 +1005,19 @@ static void nv_add_output(ScrnInfoPtr pScrn, int dcb_entry, const xf86OutputFunc
 
 	output->driver_private = nv_output;
 
+	/* needed for NV5x, used by pre-NV5x as well. */
+	nv_output->output_resource = ffs(pNv->dcb_table.entry[dcb_entry].or);
+
 	nv_output->pDDCBus = pNv->pI2CBus[i2c_index];
 	nv_output->dcb_entry = dcb_entry;
 	nv_output->type = pNv->dcb_table.entry[dcb_entry].type;
 	nv_output->last_dpms = NV_DPMS_CLEARED;
 
-	/* output route:
-	 * bit0: OUTPUT_0 valid
-	 * bit1: OUTPUT_1 valid
-	 * So lowest order has highest priority.
-	 * Below is guesswork:
-	 * bit2: All outputs valid
-	 */
-	/* We choose the preferred output resource initially. */
-	if (ffs(pNv->dcb_table.entry[dcb_entry].or) & OUTPUT_1)
+	/* Output property for tmds and lvds. */
+	nv_output->dithering = (pNv->FPDither || (nv_output->type == OUTPUT_LVDS && !pNv->VBIOS.fp.if_is_24bit));
+
+	/* This is mostly for tmds/lvds routing on pre-NV5x cards. */
+	if (nv_output->output_resource & OUTPUT_1)
 		nv_output->preferred_output = 1;
 	else
 		nv_output->preferred_output = 0;
@@ -996,16 +1036,69 @@ static void nv_add_output(ScrnInfoPtr pScrn, int dcb_entry, const xf86OutputFunc
 	}
 
 	output->possible_crtcs = pNv->dcb_table.entry[dcb_entry].heads;
+	output->interlaceAllowed = TRUE;
+	output->doubleScanAllowed = TRUE;
+
+	if (pNv->Architecture == NV_ARCH_50) {
+		if (nv_output->type == OUTPUT_TMDS) {
+			NVWrite(pNv, 0x0061c00c + nv_output->output_resource * 0x800, 0x03010700);
+			NVWrite(pNv, 0x0061c010 + nv_output->output_resource * 0x800, 0x0000152f);
+			NVWrite(pNv, 0x0061c014 + nv_output->output_resource * 0x800, 0x00000000);
+			NVWrite(pNv, 0x0061c018 + nv_output->output_resource * 0x800, 0x00245af8);
+		}
+
+		/* This needs to be handled in the same way as pre-NV5x on the long run. */
+		if (nv_output->type == OUTPUT_LVDS)
+			nv_output->native_mode = GetLVDSNativeMode(pScrn);
+	}
 
 	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Added output %s\n", outputname);
 }
 
+static const xf86OutputFuncsRec * nv_get_output_funcs(ScrnInfoPtr pScrn, int type)
+{
+	NVPtr pNv = NVPTR(pScrn);
+
+	if (pNv->Architecture == NV_ARCH_50) {
+		switch (type) {
+			case OUTPUT_ANALOG:
+				return nv50_get_analog_output_funcs();
+				break;
+			case OUTPUT_TMDS:
+				return nv50_get_tmds_output_funcs();
+				break;
+			case OUTPUT_LVDS:
+				return nv50_get_lvds_output_funcs();
+				break;
+			default:
+				return NULL;
+				break;
+		}
+	} else {
+		switch (type) {
+			case OUTPUT_ANALOG:
+				return &nv_analog_output_funcs;
+				break;
+			case OUTPUT_TMDS:
+				return &nv_tmds_output_funcs;
+				break;
+			case OUTPUT_LVDS:
+				return &nv_lvds_output_funcs;
+				break;
+			default:
+				return NULL;
+				break;
+		}
+	}
+}
+
 void NvSetupOutputs(ScrnInfoPtr pScrn)
 {
 	NVPtr pNv = NVPTR(pScrn);
 	int i, type, i2c_count[0xf];
 	char outputname[20];
 	int vga_count = 0, tv_count = 0, dvia_count = 0, dvid_count = 0, lvds_count = 0;
+	xf86OutputFuncsRec * funcs = NULL;
 
 	memset(pNv->pI2CBus, 0, sizeof(pNv->pI2CBus));
 	memset(i2c_count, 0, sizeof(i2c_count));
@@ -1024,24 +1117,24 @@ void NvSetupOutputs(ScrnInfoPtr pScrn)
 				sprintf(outputname, "VGA-%d", vga_count++);
 			else
 				sprintf(outputname, "DVI-A-%d", dvia_count++);
-			nv_add_output(pScrn, i, &nv_analog_output_funcs, outputname);
 			break;
 		case OUTPUT_TMDS:
 			sprintf(outputname, "DVI-D-%d", dvid_count++);
-			nv_add_output(pScrn, i, &nv_tmds_output_funcs, outputname);
 			break;
 		case OUTPUT_TV:
 			sprintf(outputname, "TV-%d", tv_count++);
-//			nv_add_output(pScrn, i, &nv_tv_output_funcs, outputname);
 			break;
 		case OUTPUT_LVDS:
 			sprintf(outputname, "LVDS-%d", lvds_count++);
-			nv_add_output(pScrn, i, &nv_lvds_output_funcs, outputname);
 			break;
 		default:
 			xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DCB type %d not known\n", type);
 			break;
 		}
+
+		funcs = (xf86OutputFuncsRec *) nv_get_output_funcs(pScrn, type);
+		if (funcs)
+			nv_add_output(pScrn, i, funcs, outputname);
 	}
 }
 
diff --git a/src/nv_proto.h b/src/nv_proto.h
index 71eb50e..857058c 100644
--- a/src/nv_proto.h
+++ b/src/nv_proto.h
@@ -87,10 +87,13 @@ void nv_crtc_init(ScrnInfoPtr pScrn, int crtc_num);
 void NVCrtcLockUnlock(xf86CrtcPtr crtc, Bool lock);
 void NVCrtcWriteCRTC(xf86CrtcPtr crtc, uint32_t reg, uint32_t val);
 void NVCrtcWriteRAMDAC(xf86CrtcPtr crtc, uint32_t reg, uint32_t val);
+xf86OutputPtr NVGetOutputFromCRTC(xf86CrtcPtr crtc);
 
 /* nv_output.c */
 void NvSetupOutputs(ScrnInfoPtr pScrn);
 uint32_t nv_get_clock_from_crtc(ScrnInfoPtr pScrn, RIVA_HW_STATE *state, uint8_t crtc);
+void nv_digital_output_create_resources(xf86OutputPtr output);
+Bool nv_digital_output_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value);
 
 /* nv_hw.c */
 uint32_t NVRead(NVPtr pNv, uint32_t reg);
diff --git a/src/nv_type.h b/src/nv_type.h
index 13d7803..e2eab41 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -187,7 +187,6 @@ typedef struct _NVCrtcPrivateRec {
 	int head;
 	uint8_t last_dpms;
 	Bool cursorVisible;
-	Bool ditherEnabled;
 	Bool skipModeFixup; /* NV50 only */
 	int pclk; /* Pixel clock in kHz */ /* NV50 only */
 #if NOUVEAU_EXA_PIXMAPS
@@ -213,6 +212,7 @@ typedef struct _NVOutputPrivateRec {
 	uint32_t fpHeight;
 	DisplayModePtr native_mode;
 	uint8_t scaling_mode;
+	Bool dithering;
 	NVOutputRegRec restore;
 } NVOutputPrivateRec, *NVOutputPrivatePtr;
 
_______________________________________________
Nouveau mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/nouveau

Reply via email to