Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

NV50: Rework the modesetting code into a different model.

- There is now interface independent code for most things.
- This structure, although not exclusive, is only used for NV50 atm.
- The change in approach is that the concept of a connector is added to the model (randr12 sucks in this aspect).
- I'm hacking around randr trying to create a single output for each connector, the indices are the bus numbers.
- Limitations: Hot swapping vga and dvi of same monitor will not make randr12 think it changed, so for the moment force a change.
- Concept is largely inspired by the radeonhd driver.
  • Loading branch information...
commit a7af057ff67cf5d7baf78d852dee5ac69b24e706 1 parent 5e1b570
authored May 05, 2008
2  autogen.sh
@@ -9,4 +9,4 @@ cd $srcdir
9 9
 autoreconf -v --install || exit 1
10 10
 cd $ORIGDIR || exit $?
11 11
 
12  
-$srcdir/configure --enable-maintainer-mode "$@"
  12
+$srcdir/configure "$@"
7  src/Makefile.am
@@ -78,6 +78,13 @@ nouveau_drv_la_SOURCES = \
78 78
 			 nv50_exa.c \
79 79
 			 nv50_output.c \
80 80
 			 nv50_sor.c \
  81
+			 nv50_randr.c \
  82
+			 nv50_randr.h \
  83
+			 nv50_connector.c \
81 84
 			 nv50reg.h \
  85
+			 nouveau_crtc.h \
  86
+			 nouveau_output.h \
  87
+			 nouveau_connector.h \
  88
+			 nouveau_modeset.h \
82 89
 			 nv_pcicompat.h
83 90
 
65  src/nouveau_connector.h
... ...
@@ -0,0 +1,65 @@
  1
+/*
  2
+ * Copyright 2008 Maarten Maathuis
  3
+ *
  4
+ * Permission is hereby granted, free of charge, to any person obtaining a
  5
+ * copy of this software and associated documentation files (the "Software"),
  6
+ * to deal in the Software without restriction, including without limitation
  7
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8
+ * and/or sell copies of the Software, and to permit persons to whom the
  9
+ * Software is furnished to do so, subject to the following conditions:
  10
+ *
  11
+ * The above copyright notice and this permission notice shall be included in
  12
+ * all copies or substantial portions of the Software.
  13
+ *
  14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  18
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
  19
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20
+ * SOFTWARE.
  21
+ */
  22
+
  23
+#ifndef __NOUVEAU_CONNECTOR_H_
  24
+#define __NOUVEAU_CONNECTOR_H_
  25
+
  26
+#include "nv_include.h"
  27
+#include "nouveau_modeset.h"
  28
+#include "nouveau_crtc.h"
  29
+#include "nouveau_output.h"
  30
+
  31
+/* I have yet to find specific information on connectors, so it's all derived from outputs. */
  32
+typedef enum {
  33
+	CONNECTOR_NONE = 4,
  34
+	CONNECTOR_VGA = 0,
  35
+	CONNECTOR_DVI = 1,
  36
+	CONNECTOR_TV = 2,
  37
+	CONNECTOR_PANEL = 3
  38
+} NVConnectorType;
  39
+
  40
+#define MAX_OUTPUTS_PER_CONNECTOR 2
  41
+
  42
+typedef struct nouveauConnector {
  43
+	ScrnInfoPtr scrn;
  44
+	int index;
  45
+
  46
+	char *name;
  47
+	Bool active;
  48
+
  49
+	NVConnectorType type;
  50
+
  51
+	I2CBusPtr pDDCBus;
  52
+	int i2c_index;
  53
+
  54
+	/* For load detect amongst other things. */
  55
+	nouveauOutputPtr outputs[MAX_OUTPUTS_PER_CONNECTOR];
  56
+	int connected_output;
  57
+
  58
+	Bool hotplug_detected; /* better name? */
  59
+	/* Function pointers. */
  60
+	Bool (*HotplugDetect) (nouveauConnectorPtr connector);
  61
+	xf86MonPtr (*DDCDetect) (nouveauConnectorPtr connector);
  62
+	DisplayModePtr (*GetDDCModes) (nouveauConnectorPtr connector);
  63
+} nouveauConnectorRec;
  64
+
  65
+#endif /* __NOUVEAU_CONNECTOR_H_ */
80  src/nouveau_crtc.h
... ...
@@ -0,0 +1,80 @@
  1
+/*
  2
+ * Copyright 2008 Maarten Maathuis
  3
+ *
  4
+ * Permission is hereby granted, free of charge, to any person obtaining a
  5
+ * copy of this software and associated documentation files (the "Software"),
  6
+ * to deal in the Software without restriction, including without limitation
  7
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8
+ * and/or sell copies of the Software, and to permit persons to whom the
  9
+ * Software is furnished to do so, subject to the following conditions:
  10
+ *
  11
+ * The above copyright notice and this permission notice shall be included in
  12
+ * all copies or substantial portions of the Software.
  13
+ *
  14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  18
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
  19
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20
+ * SOFTWARE.
  21
+ */
  22
+ 
  23
+#ifndef __NOUVEAU_CRTC_H_
  24
+#define __NOUVEAU_CRTC_H_
  25
+
  26
+#include "nv_include.h"
  27
+#include "nouveau_modeset.h"
  28
+
  29
+typedef struct nouveauCrtc {
  30
+	ScrnInfoPtr scrn;
  31
+
  32
+	char *name;
  33
+	uint8_t index;
  34
+	Bool active;
  35
+
  36
+	/* Scanout area. */
  37
+	struct nouveau_bo * front_buffer;
  38
+	uint32_t fb_pitch;
  39
+	uint32_t x; /* relative to the frontbuffer */
  40
+	uint32_t y;
  41
+
  42
+	/* Options and some state. */
  43
+	Bool modeset_lock;
  44
+	Bool dithering;
  45
+	Bool cursor_visible;
  46
+	Bool use_native_mode;
  47
+	int scale_mode;
  48
+	int pixel_clock;
  49
+
  50
+	/* Mode info. */
  51
+	DisplayModePtr cur_mode;
  52
+	DisplayModePtr native_mode;
  53
+	DisplayModePtr mode_list;
  54
+
  55
+	/* Function pointers. */
  56
+	Bool (*ModeValid) (nouveauCrtcPtr crtc, DisplayModePtr mode);
  57
+	void (*ModeSet) (nouveauCrtcPtr crtc, DisplayModePtr mode);
  58
+	void (*SetPixelClock) (nouveauCrtcPtr crtc, int clock);
  59
+	void (*SetClockMode) (nouveauCrtcPtr crtc, int clock); /* maybe another name? */
  60
+
  61
+	void (*SetFB) (nouveauCrtcPtr crtc, struct nouveau_bo * buffer);
  62
+	void (*SetFBOffset) (nouveauCrtcPtr crtc, uint32_t x, uint32_t y);
  63
+
  64
+	void (*Blank) (nouveauCrtcPtr crtc, Bool blanked);
  65
+	void (*SetDither) (nouveauCrtcPtr crtc);
  66
+
  67
+	void (*SetScaleMode) (nouveauCrtcPtr crtc, int scale);
  68
+
  69
+	void (*ShowCursor) (nouveauCrtcPtr crtc, Bool forced_lock);
  70
+	void (*HideCursor) (nouveauCrtcPtr crtc, Bool forced_lock);
  71
+	void (*SetCursorPosition) (nouveauCrtcPtr crtc, int x, int y);
  72
+	void (*LoadCursor) (nouveauCrtcPtr crtc, Bool argb, uint32_t *src);
  73
+
  74
+	void (*GammaSet) (nouveauCrtcPtr crtc, uint16_t *red, uint16_t *green, uint16_t *blue, int size);
  75
+
  76
+	void (*Save) (nouveauCrtcPtr crtc);
  77
+	void (*Load) (nouveauCrtcPtr crtc);
  78
+} nouveauCrtcRec;
  79
+
  80
+#endif /* __NOUVEAU_CRTC_H_ */
31  src/nouveau_modeset.h
... ...
@@ -0,0 +1,31 @@
  1
+/*
  2
+ * Copyright 2008 Maarten Maathuis
  3
+ *
  4
+ * Permission is hereby granted, free of charge, to any person obtaining a
  5
+ * copy of this software and associated documentation files (the "Software"),
  6
+ * to deal in the Software without restriction, including without limitation
  7
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8
+ * and/or sell copies of the Software, and to permit persons to whom the
  9
+ * Software is furnished to do so, subject to the following conditions:
  10
+ *
  11
+ * The above copyright notice and this permission notice shall be included in
  12
+ * all copies or substantial portions of the Software.
  13
+ *
  14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  18
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
  19
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20
+ * SOFTWARE.
  21
+ */
  22
+ 
  23
+#ifndef __NOUVEAU_MODESET_H_
  24
+#define __NOUVEAU_MODESET_H_
  25
+
  26
+/* Forward declarations. */
  27
+typedef struct nouveauCrtc *nouveauCrtcPtr;
  28
+typedef struct nouveauConnector *nouveauConnectorPtr;
  29
+typedef struct nouveauOutput *nouveauOutputPtr;
  30
+
  31
+#endif /* __NOUVEAU_MODESET_H_ */
66  src/nouveau_output.h
... ...
@@ -0,0 +1,66 @@
  1
+/*
  2
+ * Copyright 2008 Maarten Maathuis
  3
+ *
  4
+ * Permission is hereby granted, free of charge, to any person obtaining a
  5
+ * copy of this software and associated documentation files (the "Software"),
  6
+ * to deal in the Software without restriction, including without limitation
  7
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8
+ * and/or sell copies of the Software, and to permit persons to whom the
  9
+ * Software is furnished to do so, subject to the following conditions:
  10
+ *
  11
+ * The above copyright notice and this permission notice shall be included in
  12
+ * all copies or substantial portions of the Software.
  13
+ *
  14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  18
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
  19
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20
+ * SOFTWARE.
  21
+ */
  22
+
  23
+#ifndef __NOUVEAU_OUTPUT_H_
  24
+#define __NOUVEAU_OUTPUT_H_
  25
+
  26
+#include "nv_include.h"
  27
+#include "nouveau_modeset.h"
  28
+#include "nouveau_crtc.h"
  29
+#include "nouveau_connector.h"
  30
+
  31
+typedef struct nouveauOutput {
  32
+	ScrnInfoPtr scrn;
  33
+
  34
+	char *name;
  35
+	Bool active;
  36
+	nouveauOutputPtr next;
  37
+
  38
+	nouveauCrtcPtr crtc;
  39
+	nouveauConnectorPtr connector; /* the one that is currently in use, not all possibilities. */
  40
+
  41
+	/* This can change in rare circumstances, when an output resource is shared. */
  42
+	struct dcb_entry *dcb;
  43
+	int type;
  44
+	uint8_t allowed_crtc; /* bit0: crtc0, bit1: crtc1 */
  45
+	int scale_mode;
  46
+	Bool dithering;
  47
+
  48
+	/* Mode stuff. */
  49
+	DisplayModePtr native_mode;
  50
+
  51
+	/* Function pointers. */
  52
+	int (*ModeValid) (nouveauOutputPtr output, DisplayModePtr mode);
  53
+	void (*ModeSet) (nouveauOutputPtr output, DisplayModePtr mode);
  54
+	void (*SetClockMode) (nouveauOutputPtr output, int clock); /* maybe another name? */
  55
+
  56
+	/* This will handle the case where output resources are shared. */
  57
+	int (*Sense) (nouveauOutputPtr output); /* this is not for ddc or load detect, and will often just return a fixed type. */
  58
+	Bool (*Detect) (nouveauOutputPtr output); /* usually only load detect, everything else is at the connector level. */
  59
+
  60
+	void (*SetPowerMode) (nouveauOutputPtr output, int mode);
  61
+
  62
+	void (*Save) (nouveauOutputPtr output);
  63
+	void (*Load) (nouveauOutputPtr output);
  64
+} nouveauOutputRec;
  65
+
  66
+#endif /* __NOUVEAU_OUTPUT_H_ */
116  src/nv50_connector.c
... ...
@@ -0,0 +1,116 @@
  1
+/*
  2
+ * Copyright 2008 Maarten Maathuis
  3
+ *
  4
+ * Permission is hereby granted, free of charge, to any person obtaining a
  5
+ * copy of this software and associated documentation files (the "Software"),
  6
+ * to deal in the Software without restriction, including without limitation
  7
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8
+ * and/or sell copies of the Software, and to permit persons to whom the
  9
+ * Software is furnished to do so, subject to the following conditions:
  10
+ *
  11
+ * The above copyright notice and this permission notice shall be included in
  12
+ * all copies or substantial portions of the Software.
  13
+ *
  14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  18
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
  19
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20
+ * SOFTWARE.
  21
+ */
  22
+
  23
+#include "nouveau_modeset.h"
  24
+#include "nouveau_crtc.h"
  25
+#include "nouveau_output.h"
  26
+#include "nouveau_connector.h"
  27
+
  28
+static xf86MonPtr
  29
+NV50ConnectorGetEDID(nouveauConnectorPtr connector)
  30
+{
  31
+	ScrnInfoPtr pScrn = connector->scrn;
  32
+	NVPtr pNv = NVPTR(pScrn);
  33
+	xf86MonPtr rval = NULL;
  34
+
  35
+	NVWrite(pNv, NV50_I2C_PORT(connector->pDDCBus->DriverPrivate.val), NV50_I2C_START);
  36
+
  37
+	rval = xf86DoEDID_DDC2(pScrn->scrnIndex, connector->pDDCBus);
  38
+
  39
+	NVWrite(pNv, NV50_I2C_PORT(connector->pDDCBus->DriverPrivate.val), NV50_I2C_STOP);
  40
+
  41
+	return rval;
  42
+}
  43
+
  44
+static xf86MonPtr
  45
+NV50ConnectorDDCDetect(nouveauConnectorPtr connector)
  46
+{
  47
+	ScrnInfoPtr pScrn = connector->scrn;
  48
+	xf86MonPtr ddc_mon;
  49
+
  50
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50ConnectorDDCDetect is called.\n");
  51
+
  52
+	if (!connector->pDDCBus)
  53
+		return FALSE;
  54
+
  55
+	ddc_mon = NV50ConnectorGetEDID(connector);
  56
+
  57
+	return ddc_mon;
  58
+}
  59
+
  60
+static DisplayModePtr
  61
+NV50ConnectorGetDDCModes(nouveauConnectorPtr connector)
  62
+{
  63
+	ScrnInfoPtr pScrn = connector->scrn;
  64
+	xf86MonPtr ddc_mon;
  65
+
  66
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50ConnectorGetDDCModes is called.\n");
  67
+
  68
+	ddc_mon = NV50ConnectorGetEDID(connector);
  69
+
  70
+	if (!ddc_mon)
  71
+		return NULL;
  72
+
  73
+	return xf86DDCGetModes(pScrn->scrnIndex, ddc_mon);
  74
+}
  75
+
  76
+void
  77
+NV50ConnectorInit(ScrnInfoPtr pScrn)
  78
+{
  79
+	int i;
  80
+	NVPtr pNv = NVPTR(pScrn);
  81
+
  82
+	/* Maybe a bit overdone, because often only 3 or 4 connectors are present. */
  83
+	for (i = 0; i < MAX_NUM_DCB_ENTRIES; i++) {
  84
+		nouveauConnectorPtr connector = xnfcalloc(sizeof(nouveauConnectorRec), 1);
  85
+		connector->scrn = pScrn;
  86
+		connector->index = i;
  87
+
  88
+		char connector_name[20];
  89
+		sprintf(connector_name, "Connector-%d", i);
  90
+		connector->name = xstrdup(connector_name);
  91
+
  92
+		/* Function pointers. */
  93
+		connector->DDCDetect = NV50ConnectorDDCDetect;
  94
+		connector->GetDDCModes = NV50ConnectorGetDDCModes;
  95
+		connector->HotplugDetect = NULL;
  96
+
  97
+		pNv->connector[i] = connector;
  98
+	}
  99
+}
  100
+
  101
+void
  102
+NV50ConnectorDestroy(ScrnInfoPtr pScrn)
  103
+{
  104
+	int i;
  105
+	NVPtr pNv = NVPTR(pScrn);
  106
+
  107
+	/* Maybe a bit overdone, because often only 3 or 4 connectors are present. */
  108
+	for (i = 0; i < MAX_NUM_DCB_ENTRIES; i++) {
  109
+		nouveauConnectorPtr connector = pNv->connector[i];
  110
+
  111
+		xfree(connector->name);
  112
+		xfree(connector);
  113
+		pNv->connector[i] = NULL;
  114
+	}
  115
+}
  116
+
507  src/nv50_crtc.c
... ...
@@ -1,31 +1,34 @@
1 1
 /*
2  
- * Copyright (c) 2007 NVIDIA, Corporation
3  
- * Copyright (c) 2008 Maarten Maathuis
  2
+ * Copyright 2007 NVIDIA, Corporation
  3
+ * Copyright 2008 Maarten Maathuis
4 4
  *
5 5
  * Permission is hereby granted, free of charge, to any person obtaining a
6  
- * copy of this software and associated documentation files (the
7  
- * "Software"), to deal in the Software without restriction, including
8  
- * without limitation the rights to use, copy, modify, merge, publish,
9  
- * distribute, sublicense, and/or sell copies of the Software, and to
10  
- * permit persons to whom the Software is furnished to do so, subject to
11  
- * the following conditions:
  6
+ * copy of this software and associated documentation files (the "Software"),
  7
+ * to deal in the Software without restriction, including without limitation
  8
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9
+ * and/or sell copies of the Software, and to permit persons to whom the
  10
+ * Software is furnished to do so, subject to the following conditions:
12 11
  *
13  
- * The above copyright notice and this permission notice shall be included
14  
- * in all copies or substantial portions of the Software.
  12
+ * The above copyright notice and this permission notice shall be included in
  13
+ * all copies or substantial portions of the Software.
15 14
  *
16  
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  15
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  19
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
  20
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21
+ * SOFTWARE.
23 22
  */
24 23
 
25  
-#include "nv_include.h"
  24
+#include "nouveau_modeset.h"
  25
+#include "nouveau_crtc.h"
  26
+#include "nouveau_output.h"
  27
+#include "nouveau_connector.h"
26 28
 
27 29
 /* Don't call the directly, only load state should do this on the long run*/
28  
-void NV50CheckWriteVClk(ScrnInfoPtr pScrn)
  30
+static void 
  31
+NV50CheckWriteVClk(ScrnInfoPtr pScrn)
29 32
 {
30 33
 	NVPtr pNv = NVPTR(pScrn);
31 34
 	int t_start = GetTimeInMillis();
@@ -48,24 +51,31 @@ void NV50CheckWriteVClk(ScrnInfoPtr pScrn)
48 51
 
49 52
 		if (supervisor & NV50_DISPLAY_SUPERVISOR_CLK_MASK) {
50 53
 			if (supervisor & NV50_DISPLAY_SUPERVISOR_CLK_UPDATE) {
51  
-				xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
52 54
 				const uint32_t clockvar = NVRead(pNv, NV50_DISPLAY_UNK30_CTRL);
53 55
 				int i;
54 56
 
55  
-				for(i = 0; i < xf86_config->num_crtc; i++) {
56  
-					xf86CrtcPtr crtc = xf86_config->crtc[i];
57  
-					NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
  57
+				for(i = 0; i < 2; i++) {
  58
+					nouveauCrtcPtr crtc = pNv->crtc[i];
58 59
 					uint32_t mask = 0;
59 60
 
60  
-					if (nv_crtc->head == 1)
  61
+					if (crtc->index == 1)
61 62
 						mask = NV50_DISPLAY_UNK30_CTRL_UPDATE_VCLK1;
62 63
 					else
63 64
 						mask = NV50_DISPLAY_UNK30_CTRL_UPDATE_VCLK0;
64 65
 
  66
+					if (clockvar & mask)
  67
+						crtc->SetPixelClock(crtc, crtc->pixel_clock);
65 68
 					/* Always do something if the supervisor wants a clock change. */
66 69
 					/* This is needed because you get a deadlock if you don't kick the NV50_CRTC0_CLK_CTRL2 register. */
67  
-					if (nv_crtc->modeset_lock || (clockvar & mask))
68  
-						NV50CrtcSetPClk(crtc, !!(clockvar & mask));
  70
+					if (crtc->modeset_lock) {
  71
+						crtc->SetClockMode(crtc, crtc->pixel_clock);
  72
+
  73
+						nouveauOutputPtr output;
  74
+						for (output = pNv->output; output != NULL; output = output->next) {
  75
+							if (output->crtc == crtc)
  76
+								output->SetClockMode(output, crtc->pixel_clock);
  77
+						}
  78
+					}
69 79
 				}
70 80
 			}
71 81
 
@@ -84,128 +94,52 @@ void NV50DisplayCommand(ScrnInfoPtr pScrn, uint32_t addr, uint32_t value)
84 94
 	NV50CheckWriteVClk(pScrn);
85 95
 }
86 96
 
87  
-void NV50CrtcCommand(xf86CrtcPtr crtc, uint32_t addr, uint32_t value)
  97
+void NV50CrtcCommand(nouveauCrtcPtr crtc, uint32_t addr, uint32_t value)
88 98
 {
89 99
 	ScrnInfoPtr pScrn = crtc->scrn;
90  
-	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
91 100
 
92  
-	/* This head dependent offset may not be true everywere */
93  
-	NV50DisplayCommand(pScrn, addr + 0x400 * nv_crtc->head, value);
  101
+	/* This head dependent offset is only for crtc commands. */
  102
+	NV50DisplayCommand(pScrn, addr + 0x400 * crtc->index, value);
94 103
 }
95 104
 
96  
-void NV50CrtcSetPClk(xf86CrtcPtr crtc, Bool update)
  105
+static Bool
  106
+NV50CrtcModeValid(nouveauCrtcPtr crtc, DisplayModePtr mode)
97 107
 {
98  
-	ScrnInfoPtr pScrn = crtc->scrn;
99  
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetPClk is called (%s).\n", update ? "update" : "no update");
100  
-
101  
-	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
102  
-	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
103  
-	NVPtr pNv = NVPTR(pScrn);
104  
-	int i;
105  
-
106  
-	/* Sometimes NV50_CRTC0_CLK_CTRL2 needs a kick, but the clock needs no update. */
107  
-	if (update) {
108  
-		/* I don't know why exactly, but these were in my table. */
109  
-		uint32_t pll_reg = nv_crtc->head ? NV50_CRTC1_CLK_CTRL1 : NV50_CRTC0_CLK_CTRL1;
110  
-
111  
-		int NM1 = 0xbeef, NM2 = 0xdead, log2P;
112  
-		struct pll_lims pll_lim;
113  
-		get_pll_limits(pScrn, pll_reg, &pll_lim);
114  
-		/* NV5x hardware doesn't seem to support a single vco mode, otherwise the blob is hiding it well. */
115  
-		getMNP_double(pScrn, &pll_lim, nv_crtc->pclk, &NM1, &NM2, &log2P);
116  
-
117  
-		uint32_t reg1 = NVRead(pNv, pll_reg + 4);
118  
-		uint32_t reg2 = NVRead(pNv, pll_reg + 8);
119  
-
120  
-		/* bit0: The blob (and bios) seem to have this on (almost) always.
121  
-		 *          I'm hoping this (experiment) will fix my image stability issues.
122  
-		 */
123  
-		NVWrite(pNv, NV50_CRTC0_CLK_CTRL1 + nv_crtc->head * 0x800, NV50_CRTC_CLK_CTRL1_CONNECTED | 0x10000011);
124  
-
125  
-		/* Eventually we should learn ourselves what all the bits should be. */
126  
-		reg1 &= 0xff00ff00;
127  
-		reg2 &= 0x8000ff00;
128  
-
129  
-		uint8_t N1 = (NM1 >> 8) & 0xFF;
130  
-		uint8_t M1 = NM1 & 0xFF;
131  
-		uint8_t N2 = (NM2 >> 8) & 0xFF;
132  
-		uint8_t M2 = NM2 & 0xFF;
133  
-
134  
-		reg1 |= (M1 << 16) | N1;
135  
-		reg2 |= (log2P << 28) | (M2 << 16) | N2;
136  
-
137  
-		NVWrite(pNv, pll_reg + 4, reg1);
138  
-		NVWrite(pNv, pll_reg + 8, reg2);
139  
-	}
140  
-
141  
-	/* There seem to be a few indicator bits, which are similar to the SOR_CTRL bits. */
142  
-	NVWrite(pNv, NV50_CRTC0_CLK_CTRL2 + nv_crtc->head * 0x800, 0);
143  
-
144  
-	for(i = 0; i < xf86_config->num_output; i++) {
145  
-		xf86OutputPtr output = xf86_config->output[i];
146  
-
147  
-		if(output->crtc != crtc)
148  
-			continue;
149  
-		NV50OutputSetPClk(output, nv_crtc->pclk);
150  
-	}
  108
+	return TRUE;
151 109
 }
152 110
 
153 111
 static void
154  
-NV50CrtcSetDither(xf86CrtcPtr crtc, Bool update)
  112
+NV50CrtcModeSet(nouveauCrtcPtr crtc, DisplayModePtr mode)
155 113
 {
156 114
 	ScrnInfoPtr pScrn = crtc->scrn;
157  
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetDither is called (%s).\n", update ? "update" : "no update");
  115
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcModeSet is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
158 116
 
159  
-	xf86OutputPtr output = NULL;
160  
-	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
161  
-	int i;
162  
-
163  
-	for (i = 0; i < xf86_config->num_output; i++) {
164  
-		if (xf86_config->output[i]->crtc == crtc) {
165  
-			output = xf86_config->output[i];
166  
-			break;
167  
-		}
168  
-	}
169  
-
170  
-	if (!output)
171  
-		return;
  117
+	/* Anyone know a more appropriate name? */
  118
+	DisplayModePtr desired_mode = crtc->use_native_mode ? crtc->native_mode : mode;
172 119
 
173  
-	NVOutputPrivatePtr nv_output = output->driver_private;
174  
-
175  
-	NV50CrtcCommand(crtc, NV50_CRTC0_DITHERING_CTRL, nv_output->dithering ? 
176  
-			NV50_CRTC0_DITHERING_CTRL_ON : NV50_CRTC0_DITHERING_CTRL_OFF);
177  
-	if (update) 
178  
-		NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
179  
-}
180  
-
181  
-static void
182  
-nv50_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, int x, int y)
183  
-{
184  
-	ScrnInfoPtr pScrn = crtc->scrn;
185  
-	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
186  
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_mode_set is called for %s with position (%d, %d).\n", nv_crtc->head ? "CRTC1" : "CRTC0", x, y);
  120
+	/* Save the pixel clock for posterity. */
  121
+	crtc->pixel_clock = desired_mode->Clock;
  122
+	crtc->cur_mode = mode;
187 123
 
188  
-	nv_crtc->pclk = adjusted_mode->Clock;
189  
-
190  
-	uint32_t hsync_dur = adjusted_mode->CrtcHSyncEnd - adjusted_mode->CrtcHSyncStart;
191  
-	uint32_t vsync_dur = adjusted_mode->CrtcVSyncEnd - adjusted_mode->CrtcVSyncStart;
192  
-	uint32_t hsync_start_to_end = adjusted_mode->CrtcHBlankEnd - adjusted_mode->CrtcHSyncStart;
193  
-	uint32_t vsync_start_to_end = adjusted_mode->CrtcVBlankEnd - adjusted_mode->CrtcVSyncStart;
  124
+	uint32_t hsync_dur = desired_mode->CrtcHSyncEnd - desired_mode->CrtcHSyncStart;
  125
+	uint32_t vsync_dur = desired_mode->CrtcVSyncEnd - desired_mode->CrtcVSyncStart;
  126
+	uint32_t hsync_start_to_end = desired_mode->CrtcHBlankEnd - desired_mode->CrtcHSyncStart;
  127
+	uint32_t vsync_start_to_end = desired_mode->CrtcVBlankEnd - desired_mode->CrtcVSyncStart;
194 128
 	/* I can't give this a proper name, anyone else can? */
195  
-	uint32_t hunk1 = adjusted_mode->CrtcHTotal - adjusted_mode->CrtcHSyncStart + adjusted_mode->CrtcHBlankStart;
196  
-	uint32_t vunk1 = adjusted_mode->CrtcVTotal - adjusted_mode->CrtcVSyncStart + adjusted_mode->CrtcVBlankStart;
  129
+	uint32_t hunk1 = desired_mode->CrtcHTotal - desired_mode->CrtcHSyncStart + desired_mode->CrtcHBlankStart;
  130
+	uint32_t vunk1 = desired_mode->CrtcVTotal - desired_mode->CrtcVSyncStart + desired_mode->CrtcVBlankStart;
197 131
 	/* Another strange value, this time only for interlaced modes. */
198  
-	uint32_t vunk2a = 2*adjusted_mode->CrtcVTotal - adjusted_mode->CrtcVSyncStart + adjusted_mode->CrtcVBlankStart;
199  
-	uint32_t vunk2b = adjusted_mode->CrtcVTotal - adjusted_mode->CrtcVSyncStart + adjusted_mode->CrtcVBlankEnd;
  132
+	uint32_t vunk2a = 2*desired_mode->CrtcVTotal - desired_mode->CrtcVSyncStart + desired_mode->CrtcVBlankStart;
  133
+	uint32_t vunk2b = desired_mode->CrtcVTotal - desired_mode->CrtcVSyncStart + desired_mode->CrtcVBlankEnd;
200 134
 
201  
-	if (adjusted_mode->Flags & V_INTERLACE) {
  135
+	if (desired_mode->Flags & V_INTERLACE) {
202 136
 		vsync_dur /= 2;
203 137
 		vsync_start_to_end  /= 2;
204 138
 		vunk1 /= 2;
205 139
 		vunk2a /= 2;
206 140
 		vunk2b /= 2;
207 141
 		/* magic */
208  
-		if (adjusted_mode->Flags & V_DBLSCAN) {
  142
+		if (desired_mode->Flags & V_DBLSCAN) {
209 143
 			vsync_start_to_end -= 1;
210 144
 			vunk1 -= 1;
211 145
 			vunk2a -= 1;
@@ -215,19 +149,23 @@ nv50_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjuste
215 149
 
216 150
 	/* NV50CrtcCommand includes head offset */
217 151
 	/* This is the native mode when DFP && !SCALE_PANEL */
218  
-	NV50CrtcCommand(crtc, NV50_CRTC0_CLOCK, adjusted_mode->Clock | 0x800000);
219  
-	NV50CrtcCommand(crtc, NV50_CRTC0_INTERLACE, (adjusted_mode->Flags & V_INTERLACE) ? 2 : 0);
  152
+	NV50CrtcCommand(crtc, NV50_CRTC0_CLOCK, desired_mode->Clock | 0x800000);
  153
+	NV50CrtcCommand(crtc, NV50_CRTC0_INTERLACE, (desired_mode->Flags & V_INTERLACE) ? 2 : 0);
220 154
 	NV50CrtcCommand(crtc, NV50_CRTC0_DISPLAY_START, 0);
221 155
 	NV50CrtcCommand(crtc, NV50_CRTC0_UNK82C, 0);
222  
-	NV50CrtcCommand(crtc, NV50_CRTC0_DISPLAY_TOTAL, adjusted_mode->CrtcVTotal << 16 | adjusted_mode->CrtcHTotal);
  156
+	NV50CrtcCommand(crtc, NV50_CRTC0_DISPLAY_TOTAL, desired_mode->CrtcVTotal << 16 | desired_mode->CrtcHTotal);
223 157
 	NV50CrtcCommand(crtc, NV50_CRTC0_SYNC_DURATION, (vsync_dur - 1) << 16 | (hsync_dur - 1));
224 158
 	NV50CrtcCommand(crtc, NV50_CRTC0_SYNC_START_TO_BLANK_END, (vsync_start_to_end - 1) << 16 | (hsync_start_to_end - 1));
225 159
 	NV50CrtcCommand(crtc, NV50_CRTC0_MODE_UNK1, (vunk1 - 1) << 16 | (hunk1 - 1));
226  
-	if (adjusted_mode->Flags & V_INTERLACE) {
  160
+	if (desired_mode->Flags & V_INTERLACE) {
227 161
 		NV50CrtcCommand(crtc, NV50_CRTC0_MODE_UNK2, (vunk2b - 1) << 16 | (vunk2a - 1));
228 162
 	}
229 163
 	NV50CrtcCommand(crtc, NV50_CRTC0_FB_SIZE, pScrn->virtualY << 16 | pScrn->virtualX);
230  
-	NV50CrtcCommand(crtc, NV50_CRTC0_PITCH, pScrn->displayWidth * (pScrn->bitsPerPixel / 8) | 0x100000);
  164
+
  165
+	/* Maybe move this calculation elsewhere? */
  166
+	crtc->fb_pitch = pScrn->displayWidth * (pScrn->bitsPerPixel / 8);
  167
+	NV50CrtcCommand(crtc, NV50_CRTC0_PITCH, crtc->fb_pitch | 0x100000);
  168
+
231 169
 	switch (pScrn->depth) {
232 170
 		case 8:
233 171
 			NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_8BPP); 
@@ -242,92 +180,156 @@ nv50_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjuste
242 180
 			NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_24BPP); 
243 181
 			break;
244 182
 	}
245  
-	NV50CrtcSetDither(crtc, FALSE);
  183
+	crtc->SetDither(crtc);
246 184
 	NV50CrtcCommand(crtc, NV50_CRTC0_COLOR_CTRL, NV50_CRTC_COLOR_CTRL_MODE_COLOR);
247  
-	NV50CrtcCommand(crtc, NV50_CRTC0_FB_POS, y << 16 | x);
  185
+	NV50CrtcCommand(crtc, NV50_CRTC0_FB_POS, (crtc->y << 16) | (crtc->x));
248 186
 	/* This is the actual resolution of the mode. */
249 187
 	NV50CrtcCommand(crtc, NV50_CRTC0_REAL_RES, (mode->VDisplay << 16) | mode->HDisplay);
250 188
 	NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_CENTER_OFFSET, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0));
251 189
 
252  
-	NV50CrtcBlankScreen(crtc, FALSE);
  190
+	/* Maybe move this as well? */
  191
+	crtc->Blank(crtc, FALSE);
253 192
 }
254 193
 
255  
-void
256  
-NV50CrtcBlankScreen(xf86CrtcPtr crtc, Bool blank)
  194
+static void
  195
+NV50CrtcSetPixelClock(nouveauCrtcPtr crtc, int clock)
  196
+{
  197
+	ScrnInfoPtr pScrn = crtc->scrn;
  198
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetPixelClock is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
  199
+
  200
+	NVPtr pNv = NVPTR(pScrn);
  201
+
  202
+	/* I don't know why exactly, but these were in my table. */
  203
+	uint32_t pll_reg = crtc->index ? NV50_CRTC1_CLK_CTRL1 : NV50_CRTC0_CLK_CTRL1;
  204
+
  205
+	int NM1 = 0xbeef, NM2 = 0xdead, log2P;
  206
+	struct pll_lims pll_lim;
  207
+	get_pll_limits(pScrn, pll_reg, &pll_lim);
  208
+	/* NV5x hardware doesn't seem to support a single vco mode, otherwise the blob is hiding it well. */
  209
+	getMNP_double(pScrn, &pll_lim, clock, &NM1, &NM2, &log2P);
  210
+
  211
+	uint32_t reg1 = NVRead(pNv, pll_reg + 4);
  212
+	uint32_t reg2 = NVRead(pNv, pll_reg + 8);
  213
+
  214
+	/* bit0: The blob (and bios) seem to have this on (almost) always.
  215
+	 *          I'm hoping this (experiment) will fix my image stability issues.
  216
+	 */
  217
+	NVWrite(pNv, NV50_CRTC0_CLK_CTRL1 + crtc->index * 0x800, NV50_CRTC_CLK_CTRL1_CONNECTED | 0x10000011);
  218
+
  219
+	/* Eventually we should learn ourselves what all the bits should be. */
  220
+	reg1 &= 0xff00ff00;
  221
+	reg2 &= 0x8000ff00;
  222
+
  223
+	uint8_t N1 = (NM1 >> 8) & 0xFF;
  224
+	uint8_t M1 = NM1 & 0xFF;
  225
+	uint8_t N2 = (NM2 >> 8) & 0xFF;
  226
+	uint8_t M2 = NM2 & 0xFF;
  227
+
  228
+	reg1 |= (M1 << 16) | N1;
  229
+	reg2 |= (log2P << 28) | (M2 << 16) | N2;
  230
+
  231
+	NVWrite(pNv, pll_reg + 4, reg1);
  232
+	NVWrite(pNv, pll_reg + 8, reg2);
  233
+}
  234
+
  235
+static void
  236
+NV50CrtcSetClockMode(nouveauCrtcPtr crtc, int clock)
257 237
 {
258 238
 	ScrnInfoPtr pScrn = crtc->scrn;
259  
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcBlankScreen is called (%s).\n", blank ? "blanked" : "unblanked");
  239
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetClockMode is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
260 240
 
261 241
 	NVPtr pNv = NVPTR(pScrn);
262  
-	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
263 242
 
264  
-	if (blank) {
265  
-		NV50CrtcShowHideCursor(crtc, FALSE, FALSE);
  243
+	/* There seem to be a few indicator bits, which are similar to the SOR_CTRL bits. */
  244
+	NVWrite(pNv, NV50_CRTC0_CLK_CTRL2 + crtc->index * 0x800, 0);
  245
+}
  246
+
  247
+static void
  248
+NV50CrtcSetFB(nouveauCrtcPtr crtc, struct nouveau_bo * buffer)
  249
+{
  250
+	/* For the moment the actual hardware settings stays in ModeSet(). */
  251
+	crtc->front_buffer = buffer;
  252
+}
  253
+
  254
+static void 
  255
+NV50CrtcSetFBOffset(nouveauCrtcPtr crtc, uint32_t x, uint32_t y)
  256
+{
  257
+	/* For the moment the actual hardware settings stays in ModeSet(). */
  258
+	crtc->x = x;
  259
+	crtc->y = y;
  260
+}
  261
+
  262
+static void 
  263
+NV50CrtcBlank(nouveauCrtcPtr crtc, Bool blanked)
  264
+{
  265
+	ScrnInfoPtr pScrn = crtc->scrn;
  266
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcBlank is called (%s) for %s.\n", blanked ? "blanked" : "unblanked", crtc->index ? "CRTC1" : "CRTC0");
  267
+
  268
+	NVPtr pNv = NVPTR(pScrn);
  269
+
  270
+	if (blanked) {
  271
+		crtc->HideCursor(crtc, TRUE);
266 272
 
267 273
 		NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE, NV50_CRTC0_CLUT_MODE_BLANK);
268 274
 		NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, 0);
269  
-		if(pNv->NVArch != 0x50)
  275
+		if (pNv->NVArch != 0x50)
270 276
 			NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_BLANK);
271 277
 		NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_BLANK);
272  
-		if(pNv->NVArch != 0x50)
  278
+		if (pNv->NVArch != 0x50)
273 279
 			NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_BLANK);
274 280
 	} else {
275  
-		NV50CrtcCommand(crtc, NV50_CRTC0_FB_OFFSET, pNv->FB->offset >> 8);
  281
+		NV50CrtcCommand(crtc, NV50_CRTC0_FB_OFFSET, crtc->front_buffer->offset >> 8);
276 282
 		NV50CrtcCommand(crtc, 0x864, 0);
277 283
 		NVWrite(pNv, NV50_DISPLAY_UNK_380, 0);
278 284
 		/* RAM is clamped to 256 MiB. */
279 285
 		NVWrite(pNv, NV50_DISPLAY_RAM_AMOUNT, pNv->RamAmountKBytes * 1024 - 1);
280 286
 		NVWrite(pNv, NV50_DISPLAY_UNK_388, 0x150000);
281 287
 		NVWrite(pNv, NV50_DISPLAY_UNK_38C, 0);
282  
-		if (nv_crtc->head == 1)
  288
+		if (crtc->index == 1)
283 289
 			NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_OFFSET, pNv->Cursor2->offset >> 8);
284 290
 		else
285 291
 			NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_OFFSET, pNv->Cursor->offset >> 8);
286 292
 		if(pNv->NVArch != 0x50)
287 293
 			NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_UNBLANK);
288  
-		if(nv_crtc->cursorVisible)
289  
-			NV50CrtcShowHideCursor(crtc, TRUE, FALSE);
  294
+
  295
+		if (crtc->cursor_visible)
  296
+			crtc->ShowCursor(crtc, TRUE);
  297
+
290 298
 		NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE, 
291 299
 			pScrn->depth == 8 ? NV50_CRTC0_CLUT_MODE_OFF : NV50_CRTC0_CLUT_MODE_ON);
292 300
 		/* Each CRTC has it's own CLUT. */
293  
-		if (nv_crtc->head == 1)
  301
+		if (crtc->index == 1)
294 302
 			NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, pNv->CLUT1->offset >> 8);
295 303
 		else
296 304
 			NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, pNv->CLUT0->offset >> 8);
297  
-		if(pNv->NVArch != 0x50)
  305
+		if (pNv->NVArch != 0x50)
298 306
 			NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_UNBLANK);
299 307
 		NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_UNBLANK);
300 308
 	}
301 309
 }
302 310
 
303 311
 static void
304  
-nv50_crtc_prepare(xf86CrtcPtr crtc)
  312
+NV50CrtcSetDither(nouveauCrtcPtr crtc)
305 313
 {
306 314
 	ScrnInfoPtr pScrn = crtc->scrn;
307  
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_prepare is called.\n");
308  
-
309  
-	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
310  
-	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
311  
-	int i;
312  
-
313  
-	nv_crtc->modeset_lock = TRUE;
  315
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetDither is called (%s).\n", !crtc->modeset_lock ? "update" : "no update");
314 316
 
315  
-	for(i = 0; i < xf86_config->num_output; i++) {
316  
-		xf86OutputPtr output = xf86_config->output[i];
  317
+	NV50CrtcCommand(crtc, NV50_CRTC0_DITHERING_CTRL, crtc->dithering ? 
  318
+			NV50_CRTC0_DITHERING_CTRL_ON : NV50_CRTC0_DITHERING_CTRL_OFF);
317 319
 
318  
-		if (!output->crtc)
319  
-			output->funcs->mode_set(output, NULL, NULL);
320  
-	}
  320
+	if (!crtc->modeset_lock)
  321
+		NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
321 322
 }
322 323
 
323  
-static void ComputeAspectScale(DisplayModePtr mode, DisplayModePtr adjusted_mode, int *outX, int *outY)
  324
+static void
  325
+ComputeAspectScale(DisplayModePtr mode, DisplayModePtr adjusted_mode, int *outX, int *outY)
324 326
 {
325 327
 	float scaleX, scaleY, scale;
326 328
 
327 329
 	scaleX = adjusted_mode->HDisplay / (float)mode->HDisplay;
328 330
 	scaleY = adjusted_mode->VDisplay / (float)mode->VDisplay;
329 331
 
330  
-	if(scaleX > scaleY)
  332
+	if (scaleX > scaleY)
331 333
 		scale = scaleY;
332 334
 	else
333 335
 		scale = scaleX;
@@ -336,32 +338,33 @@ static void ComputeAspectScale(DisplayModePtr mode, DisplayModePtr adjusted_mode
336 338
 	*outY = mode->VDisplay * scale;
337 339
 }
338 340
 
339  
-void NV50CrtcSetScale(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, enum scaling_modes scale)
  341
+static void
  342
+NV50CrtcSetScaleMode(nouveauCrtcPtr crtc, int scale)
340 343
 {
341 344
 	ScrnInfoPtr pScrn = crtc->scrn;
342  
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetScale is called.\n");
  345
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetScale is called with mode %d for %s.\n", scale, crtc->index ? "CRTC1" : "CRTC0");
343 346
 
344 347
 	int outX = 0, outY = 0;
345 348
 
346 349
 	switch(scale) {
347 350
 		case SCALE_ASPECT:
348  
-			ComputeAspectScale(mode, adjusted_mode, &outX, &outY);
  351
+			ComputeAspectScale(crtc->cur_mode, crtc->native_mode, &outX, &outY);
349 352
 			break;
350  
-		case SCALE_PANEL:
351 353
 		case SCALE_FULLSCREEN:
352  
-			outX = adjusted_mode->HDisplay;
353  
-			outY = adjusted_mode->VDisplay;
  354
+			outX = crtc->native_mode->HDisplay;
  355
+			outY = crtc->native_mode->VDisplay;
354 356
 			break;
355 357
 		case SCALE_NOSCALE:
  358
+		case SCALE_PANEL:
356 359
 		default:
357  
-			outX = mode->HDisplay;
358  
-			outY = mode->VDisplay;
  360
+			outX = crtc->cur_mode->HDisplay;
  361
+			outY = crtc->cur_mode->VDisplay;
359 362
 			break;
360 363
 	}
361 364
 
362 365
 	/* Got a better name for SCALER_ACTIVE? */
363  
-	if ((mode->Flags & V_DBLSCAN) || (mode->Flags & V_INTERLACE) ||
364  
-		mode->HDisplay != outX || mode->VDisplay != outY) {
  366
+	if ((crtc->cur_mode->Flags & V_DBLSCAN) || (crtc->cur_mode->Flags & V_INTERLACE) ||
  367
+		crtc->cur_mode->HDisplay != outX || crtc->cur_mode->VDisplay != outY) {
365 368
 		NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_CTRL, NV50_CRTC0_SCALE_CTRL_SCALER_ACTIVE);
366 369
 	} else {
367 370
 		NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_CTRL, NV50_CRTC0_SCALE_CTRL_SCALER_INACTIVE);
@@ -370,63 +373,92 @@ void NV50CrtcSetScale(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adju
370 373
 	NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_RES2, outY << 16 | outX);
371 374
 }
372 375
 
  376
+/*
  377
+ * Cursor stuff.
  378
+ */
  379
+
373 380
 static void
374  
-nv50_crtc_commit(xf86CrtcPtr crtc)
  381
+NV50CrtcShowCursor(nouveauCrtcPtr crtc, Bool forced_lock)
375 382
 {
376 383
 	ScrnInfoPtr pScrn = crtc->scrn;
377  
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_commit is called.\n");
  384
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcShowCursor is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
378 385
 
379  
-	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
380  
-	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
381  
-	int i, crtc_mask = 0;
  386
+	if (!crtc->modeset_lock)
  387
+		crtc->cursor_visible = TRUE;
382 388
 
383  
-	/* If any heads are unused, blank them */
384  
-	for (i = 0; i < xf86_config->num_output; i++) {
385  
-		xf86OutputPtr output = xf86_config->output[i];
  389
+	NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR, NV50_CRTC0_CURSOR_SHOW);
386 390
 
387  
-		if (output->crtc) {
388  
-			NVCrtcPrivatePtr nv_crtc = output->crtc->driver_private;
389  
-			crtc_mask |= (1 << nv_crtc->head);
390  
-		}
391  
-	}
  391
+	/* Calling this during modeset will lock things up. */
  392
+	if (!crtc->modeset_lock && !forced_lock)
  393
+		NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
  394
+}
392 395
 
393  
-	for (i = 0; i < xf86_config->num_crtc; i++) {
394  
-		if(!((1 << i) & crtc_mask)) {
395  
-			NV50CrtcBlankScreen(xf86_config->crtc[i], TRUE);
396  
-		}
397  
-	}
  396
+static void
  397
+NV50CrtcHideCursor(nouveauCrtcPtr crtc, Bool forced_lock)
  398
+{
  399
+	ScrnInfoPtr pScrn = crtc->scrn;
  400
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcHideCursor is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
  401
+
  402
+	if (!crtc->modeset_lock)
  403
+		crtc->cursor_visible = FALSE;
  404
+
  405
+	NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR, NV50_CRTC0_CURSOR_HIDE);
398 406
 
399  
-	xf86_reload_cursors (pScrn->pScreen);
  407
+	/* Calling this during modeset will lock things up. */
  408
+	if (!crtc->modeset_lock && !forced_lock)
  409
+		NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
  410
+}
400 411
 
401  
-	NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
  412
+static void
  413
+NV50CrtcSetCursorPosition(nouveauCrtcPtr crtc, int x, int y)
  414
+{
  415
+	ScrnInfoPtr pScrn = crtc->scrn;
  416
+	NVPtr pNv = NVPTR(pScrn);
  417
+	NVWrite(pNv, NV50_CRTC0_CURSOR_POS + crtc->index * 0x1000, (y & 0xFFFF) << 16 | (x & 0xFFFF));
402 418
 
403  
-	nv_crtc->modeset_lock = FALSE;
  419
+	/* This is needed to allow the cursor to move. */
  420
+	NVWrite(pNv, NV50_CRTC0_CURSOR_POS_CTRL + crtc->index * 0x1000, 0);
404 421
 }
405 422
 
406  
-static Bool nv50_crtc_lock(xf86CrtcPtr crtc)
  423
+static void
  424
+NV50CrtcLoadCursor(nouveauCrtcPtr crtc, Bool argb, uint32_t *src)
407 425
 {
408  
-	return FALSE;
  426
+	if (!argb) /* FIXME */
  427
+		return;
  428
+
  429
+	NVPtr pNv = NVPTR(crtc->scrn);
  430
+	uint32_t *dst = NULL;
  431
+
  432
+	if (crtc->index == 1)
  433
+		dst = (uint32_t *) pNv->Cursor2->map;
  434
+	else
  435
+		dst = (uint32_t *) pNv->Cursor->map;
  436
+
  437
+	/* Assume cursor is 64x64 */
  438
+	memcpy(dst, src, 64 * 64 * 4);
409 439
 }
410 440
 
411 441
 /*
  442
+ * Gamma stuff.
  443
+ */
  444
+
  445
+/*
412 446
  * The indices are a bit strange, but i'll assume it's correct (taken from nv).
413 447
  * The LUT resolution seems to be 14 bits on NV50 as opposed to the 8 bits of previous hardware.
414 448
  */
415 449
 #define NV50_LUT_INDEX(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8)))
416 450
 static void
417  
-nv50_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
418  
-					int size)
  451
+NV50CrtcGammaSet(nouveauCrtcPtr crtc, uint16_t *red, uint16_t *green, uint16_t *blue, int size)
419 452
 {
420 453
 	ScrnInfoPtr pScrn = crtc->scrn;
421  
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_gamma_set is called.\n");
  454
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcGammaSet is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
422 455
 
423  
-	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
424 456
 	NVPtr pNv = NVPTR(pScrn);
425 457
 	uint32_t index, i;
426 458
 	void * CLUT = NULL;
427 459
 
428 460
 	/* Each CRTC has it's own CLUT. */
429  
-	if (nv_crtc->head == 1)
  461
+	if (crtc->index == 1)
430 462
 		CLUT = pNv->CLUT1->map;
431 463
 	else
432 464
 		CLUT = pNv->CLUT0->map;
@@ -470,40 +502,53 @@ nv50_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
470 502
 	}
471 503
 }
472 504
 
473  
-static void
474  
-nv50_crtc_dpms_set(xf86CrtcPtr crtc, int mode)
  505
+void
  506
+NV50CrtcInit(ScrnInfoPtr pScrn)
475 507
 {
476  
-}
  508
+	int i;
  509
+	NVPtr pNv = NVPTR(pScrn);
477 510
 
478  
-static Bool
479  
-nv50_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
480  
-		     DisplayModePtr adjusted_mode)
481  
-{
482  
-	return TRUE;
  511
+	for (i=0; i < 2; i++) {
  512
+		nouveauCrtcPtr crtc = xnfcalloc(sizeof(nouveauCrtcRec), 1);
  513
+		crtc->scrn = pScrn;
  514
+		crtc->index = i;
  515
+
  516
+		/* Function pointers. */
  517
+		crtc->ModeValid = NV50CrtcModeValid;
  518
+		crtc->ModeSet = NV50CrtcModeSet;
  519
+		crtc->SetPixelClock = NV50CrtcSetPixelClock;
  520
+		crtc->SetClockMode = NV50CrtcSetClockMode;
  521
+
  522
+		crtc->SetFB = NV50CrtcSetFB;
  523
+		crtc->SetFBOffset = NV50CrtcSetFBOffset;
  524
+
  525
+		crtc->Blank = NV50CrtcBlank;
  526
+		crtc->SetDither = NV50CrtcSetDither;
  527
+
  528
+		crtc->SetScaleMode = NV50CrtcSetScaleMode;
  529
+
  530
+		crtc->ShowCursor = NV50CrtcShowCursor;
  531
+		crtc->HideCursor = NV50CrtcHideCursor;
  532
+		crtc->SetCursorPosition = NV50CrtcSetCursorPosition;
  533
+		crtc->LoadCursor = NV50CrtcLoadCursor;
  534
+
  535
+		crtc->GammaSet = NV50CrtcGammaSet;
  536
+
  537
+		pNv->crtc[i] = crtc;
  538
+	}
483 539
 }
484 540
 
485  
-static const xf86CrtcFuncsRec nv50_crtc_funcs = {
486  
-	.dpms = nv50_crtc_dpms_set,
487  
-	.save = NULL,
488  
-	.restore = NULL,
489  
-	.lock = nv50_crtc_lock,
490  
-	.unlock = NULL,
491  
-	.mode_fixup = nv50_crtc_mode_fixup,
492  
-	.prepare = nv50_crtc_prepare,
493  
-	.mode_set = nv50_crtc_mode_set,
494  
-	.gamma_set = nv50_crtc_gamma_set,
495  
-	.commit = nv50_crtc_commit,
496  
-	.shadow_create = NULL,
497  
-	.shadow_destroy = NULL,
498  
-	.set_cursor_position = nv50_crtc_set_cursor_position,
499  
-	.show_cursor = nv50_crtc_show_cursor,
500  
-	.hide_cursor = nv50_crtc_hide_cursor,
501  
-	.load_cursor_argb = nv50_crtc_load_cursor_argb,
502  
-	.destroy = NULL,
503  
-};
504  
-
505  
-const xf86CrtcFuncsRec * nv50_get_crtc_funcs()
  541
+void
  542
+NV50CrtcDestroy(ScrnInfoPtr pScrn)
506 543
 {
507  
-	return &nv50_crtc_funcs;
508  
-}
  544
+	int i;
  545
+	NVPtr pNv = NVPTR(pScrn);
  546
+
  547
+	for (i=0; i < 2; i++) {
  548
+		nouveauCrtcPtr crtc = pNv->crtc[i];
509 549
 
  550
+		xfree(crtc->name);
  551
+		xfree(crtc);
  552
+		pNv->crtc[i] = NULL;
  553
+	}
  554
+}
81  src/nv50_cursor.c
@@ -28,86 +28,22 @@
28 28
 
29 29
 #include "nv_include.h"
30 30
 
31  
-void NV50CrtcShowHideCursor(xf86CrtcPtr crtc, Bool show, Bool update)
32  
-{
33  
-	ScrnInfoPtr pScrn = crtc->scrn;
34  
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcShowHideCursor is called (%s, %s).\n", show ? "show" : "hide", update ? "update" : "no update");
35  
-
36  
-	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
37  
-
38  
-	NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR, 
39  
-		show ? NV50_CRTC0_CURSOR_SHOW : NV50_CRTC0_CURSOR_HIDE);
40  
-	if (update) {
41  
-		nv_crtc->cursorVisible = show;
42  
-		NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
43  
-	}
44  
-}
45  
-
46  
-void nv50_crtc_show_cursor(xf86CrtcPtr crtc)
47  
-{
48  
-	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
49  
-
50  
-	/* Calling NV50_UPDATE_DISPLAY during modeset will lock up everything. */
51  
-	if (nv_crtc->modeset_lock)
52  
-		return;
53  
-
54  
-	NV50CrtcShowHideCursor(crtc, TRUE, TRUE);
55  
-}
56  
-
57  
-void nv50_crtc_hide_cursor(xf86CrtcPtr crtc)
58  
-{
59  
-	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
60  
-
61  
-	/* Calling NV50_UPDATE_DISPLAY during modeset will lock up everything. */
62  
-	if (nv_crtc->modeset_lock)
63  
-		return;
64  
-
65  
-	NV50CrtcShowHideCursor(crtc, FALSE, TRUE);
66  
-}
67  
-
68  
-void nv50_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
69  
-{
70  
-	NVPtr pNv = NVPTR(crtc->scrn);
71  
-	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
72  
-
73  
-	NVWrite(pNv, NV50_CRTC0_CURSOR_POS + nv_crtc->head * 0x1000, (y & 0xFFFF) << 16 | (x & 0xFFFF));
74  
-
75  
-	/* This is needed to allow the cursor to move. */
76  
-	NVWrite(pNv, NV50_CRTC0_CURSOR_POS_CTRL + nv_crtc->head * 0x1000, 0);
77  
-}
78  
-
79  
-void nv50_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *src)
80  
-{
81  
-	NVPtr pNv = NVPTR(crtc->scrn);
82  
-	NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
83  
-	uint32_t *dst = NULL;
84  
-
85  
-	if (nv_crtc->head == 1)
86  
-		dst = (uint32_t *) pNv->Cursor2->map;
87  
-	else
88  
-		dst = (uint32_t *) pNv->Cursor->map;
89  
-
90  
-	/* Assume cursor is 64x64 */
91