2 * Copyright (c) 2007 NVIDIA, Corporation
3 * Copyright (c) 2008 Maarten Maathuis
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:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
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.
30 #include "nv_include.h"
31 #include "nv50_type.h"
32 #include "nv50_cursor.h"
33 #include "nv50_display.h"
34 #include "nv50_output.h"
36 static void NV50CrtcShowHideCursor(xf86CrtcPtr crtc, Bool show, Bool update);
38 void NV50CrtcSetPClk(xf86CrtcPtr crtc)
40 ScrnInfoPtr pScrn = crtc->scrn;
41 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetPClk is called.\n");
43 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
44 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
45 NVPtr pNv = NVPTR(pScrn);
48 /* I don't know why exactly, but these were in my table. */
49 uint32_t pll_reg = nv_crtc->head ? NV50_CRTC1_CLK_CTRL1 : NV50_CRTC0_CLK_CTRL1;
51 int NM1 = 0xbeef, NM2 = 0xdead, log2P;
52 struct pll_lims pll_lim;
53 get_pll_limits(pScrn, pll_reg, &pll_lim);
54 /* NV5x hardware doesn't seem to support a single vco mode, otherwise the blob is hiding it well. */
55 getMNP_double(pScrn, &pll_lim, nv_crtc->pclk, &NM1, &NM2, &log2P);
57 uint32_t reg1 = NVRead(pNv, pll_reg + 4);
58 uint32_t reg2 = NVRead(pNv, pll_reg + 8);
60 /* bit0: The blob (and bios) seem to have this on (almost) always.
61 * I'm hoping this (experiment) will fix my image stability issues.
63 NVWrite(pNv, NV50_CRTC0_CLK_CTRL1 + nv_crtc->head * 0x800, NV50_CRTC_CLK_CTRL1_CONNECTED | 0x10000011);
65 /* Eventually we should learn ourselves what all the bits should be. */
69 uint8_t N1 = (NM1 >> 8) & 0xFF;
70 uint8_t M1 = NM1 & 0xFF;
71 uint8_t N2 = (NM2 >> 8) & 0xFF;
72 uint8_t M2 = NM2 & 0xFF;
74 reg1 |= (M1 << 16) | N1;
75 reg2 |= (log2P << 28) | (M2 << 16) | N2;
77 NVWrite(pNv, pll_reg + 4, reg1);
78 NVWrite(pNv, pll_reg + 8, reg2);
80 /* There seem to be a few indicator bits, which are similar to the SOR_CTRL bits. */
81 NVWrite(pNv, NV50_CRTC0_CLK_CTRL2 + nv_crtc->head * 0x800, 0);
83 for(i = 0; i < xf86_config->num_output; i++) {
84 xf86OutputPtr output = xf86_config->output[i];
86 if(output->crtc != crtc)
88 NV50OutputSetPClk(output, nv_crtc->pclk);
93 NV50CrtcGetHead(xf86CrtcPtr crtc)
95 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
100 NV50DispPreInit(ScrnInfoPtr pScrn)
102 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50DispPreInit is called.\n");
104 NVPtr pNv = NVPTR(pScrn);
105 /* These labels are guesswork based on symmetry (2 SOR's and 3 DAC's exist)*/
106 NVWrite(pNv, 0x00610184, NVRead(pNv, 0x00614004));
107 NVWrite(pNv, 0x00610190 + 0 * 0x10, NVRead(pNv, 0x00616100 + 0 * 0x800));
108 NVWrite(pNv, 0x00610190 + 1 * 0x10, NVRead(pNv, 0x00616100 + 1 * 0x800));
109 NVWrite(pNv, 0x00610194 + 0 * 0x10, NVRead(pNv, 0x00616104 + 0 * 0x800));
110 NVWrite(pNv, 0x00610194 + 1 * 0x10, NVRead(pNv, 0x00616104 + 1 * 0x800));
111 NVWrite(pNv, 0x00610198 + 0 * 0x10, NVRead(pNv, 0x00616108 + 0 * 0x800));
112 NVWrite(pNv, 0x00610198 + 1 * 0x10, NVRead(pNv, 0x00616108 + 1 * 0x800));
113 NVWrite(pNv, 0x0061019c + 0 * 0x10, NVRead(pNv, 0x0061610c + 0 * 0x800));
114 NVWrite(pNv, 0x0061019c + 1 * 0x10, NVRead(pNv, 0x0061610c + 1 * 0x800));
115 NVWrite(pNv, 0x006101d0 + DAC0 * 0x4, NVRead(pNv, 0x0061a000 + DAC0 * 0x800));
116 NVWrite(pNv, 0x006101d0 + DAC1 * 0x4, NVRead(pNv, 0x0061a000 + DAC1 * 0x800));
117 NVWrite(pNv, 0x006101d0 + DAC2 * 0x4, NVRead(pNv, 0x0061a000 + DAC2 * 0x800));
118 NVWrite(pNv, 0x006101e0 + SOR0 * 0x4, NVRead(pNv, 0x0061c000 + SOR0 * 0x800));
119 NVWrite(pNv, 0x006101e0 + SOR1 * 0x4, NVRead(pNv, 0x0061c000 + SOR1 * 0x800));
120 NVWrite(pNv, NV50_DAC0_DPMS_CTRL, 0x00550000 | NV50_DAC_DPMS_CTRL_PENDING);
121 NVWrite(pNv, NV50_DAC0_CLK_CTRL2, 0x00000001);
122 NVWrite(pNv, NV50_DAC1_DPMS_CTRL, 0x00550000 | NV50_DAC_DPMS_CTRL_PENDING);
123 NVWrite(pNv, NV50_DAC1_CLK_CTRL2, 0x00000001);
124 NVWrite(pNv, NV50_DAC2_DPMS_CTRL, 0x00550000 | NV50_DAC_DPMS_CTRL_PENDING);
125 NVWrite(pNv, NV50_DAC2_CLK_CTRL2, 0x00000001);
131 NV50DispInit(ScrnInfoPtr pScrn)
133 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50DispInit is called.\n");
135 NVPtr pNv = NVPTR(pScrn);
137 if (NVRead(pNv, NV50_DISPLAY_SUPERVISOR) & 0x100) {
138 NVWrite(pNv, NV50_DISPLAY_SUPERVISOR, 0x100);
139 NVWrite(pNv, 0x006194e8, NVRead(pNv, 0x006194e8) & ~1);
140 while (NVRead(pNv, 0x006194e8) & 2);
143 NVWrite(pNv, NV50_DISPLAY_UNK200_CTRL, 0x2b00);
144 /* A bugfix (#12637) from the nv driver, to unlock the driver if it's left in a poor state */
146 val = NVRead(pNv, NV50_DISPLAY_UNK200_CTRL);
147 if ((val & 0x9f0000) == 0x20000)
148 NVWrite(pNv, NV50_DISPLAY_UNK200_CTRL, val | 0x800000);
150 if ((val & 0x3f0000) == 0x30000)
151 NVWrite(pNv, NV50_DISPLAY_UNK200_CTRL, val | 0x200000);
152 } while ((val & 0x1e0000) != 0);
153 NVWrite(pNv, NV50_DISPLAY_CTRL_STATE, NV50_DISPLAY_CTRL_STATE_ENABLE);
154 NVWrite(pNv, NV50_DISPLAY_UNK200_CTRL, 0x1000b03);
155 while (!(NVRead(pNv, NV50_DISPLAY_UNK200_CTRL) & 0x40000000));
157 NV50DisplayCommand(pScrn, 0x84, 0);
158 NV50DisplayCommand(pScrn, 0x88, 0);
159 /* The GetLVDSNativeMode() function is proof that more than crtc0 is used by the bios. */
160 NV50DisplayCommand(pScrn, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_BLANK);
161 NV50DisplayCommand(pScrn, 0x800, 0);
162 NV50DisplayCommand(pScrn, NV50_CRTC0_DISPLAY_START, 0);
163 NV50DisplayCommand(pScrn, 0x82c, 0);
169 NV50DispShutdown(ScrnInfoPtr pScrn)
171 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50DispShutdown is called.\n");
172 NVPtr pNv = NVPTR(pScrn);
173 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
176 for(i = 0; i < xf86_config->num_crtc; i++) {
177 xf86CrtcPtr crtc = xf86_config->crtc[i];
179 NV50CrtcBlankScreen(crtc, TRUE);
182 NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
184 for(i = 0; i < xf86_config->num_crtc; i++) {
185 xf86CrtcPtr crtc = xf86_config->crtc[i];
186 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
188 /* I think this is some kind of trigger to reinitialise the supervisor. */
189 /* Without anything active (this is shutdown) it's likely to disable itself. */
190 /* The blob doesn't do it quite this way., it seems to do 0x30C as init and end. */
191 /* It doesn't wait for a non-zero value either. */
194 if (nv_crtc->head == 1)
195 mask = NV50_DISPLAY_SUPERVISOR_CRTC1;
197 mask = NV50_DISPLAY_SUPERVISOR_CRTC0;
199 NVWrite(pNv, NV50_DISPLAY_SUPERVISOR, mask);
200 while(!(NVRead(pNv, NV50_DISPLAY_SUPERVISOR) & mask));
204 NVWrite(pNv, NV50_DISPLAY_UNK200_CTRL, 0x0);
205 NVWrite(pNv, NV50_DISPLAY_CTRL_STATE, NV50_DISPLAY_CTRL_STATE_DISABLE);
206 while ((NVRead(pNv, NV50_DISPLAY_UNK200_CTRL) & 0x1e0000) != 0);
207 while ((NVRead(pNv, 0x0061c030 + SOR0 * 0x800) & 0x10000000));
208 while ((NVRead(pNv, 0x0061c030 + SOR1 * 0x800) & 0x10000000));
212 NV50CrtcModeSet(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, int x, int y)
214 ScrnInfoPtr pScrn = crtc->scrn;
215 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcModeSet is called with position (%d, %d).\n", x, y);
217 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
219 nv_crtc->pclk = adjusted_mode->Clock;
221 uint32_t hsync_dur = adjusted_mode->CrtcHSyncEnd - adjusted_mode->CrtcHSyncStart;
222 uint32_t vsync_dur = adjusted_mode->CrtcVSyncEnd - adjusted_mode->CrtcVSyncStart;
223 uint32_t hsync_start_to_end = adjusted_mode->CrtcHBlankEnd - adjusted_mode->CrtcHSyncStart;
224 uint32_t vsync_start_to_end = adjusted_mode->CrtcVBlankEnd - adjusted_mode->CrtcVSyncStart;
225 /* I can't give this a proper name, anyone else can? */
226 uint32_t hunk1 = adjusted_mode->CrtcHTotal - adjusted_mode->CrtcHSyncStart + adjusted_mode->CrtcHBlankStart;
227 uint32_t vunk1 = adjusted_mode->CrtcVTotal - adjusted_mode->CrtcVSyncStart + adjusted_mode->CrtcVBlankStart;
228 /* Another strange value, this time only for interlaced modes. */
229 uint32_t vunk2a = 2*adjusted_mode->CrtcVTotal - adjusted_mode->CrtcVSyncStart + adjusted_mode->CrtcVBlankStart;
230 uint32_t vunk2b = adjusted_mode->CrtcVTotal - adjusted_mode->CrtcVSyncStart + adjusted_mode->CrtcVBlankEnd;
232 if (adjusted_mode->Flags & V_INTERLACE) {
234 vsync_start_to_end /= 2;
239 if (adjusted_mode->Flags & V_DBLSCAN) {
240 vsync_start_to_end -= 1;
247 /* NV50CrtcCommand includes head offset */
248 /* This is the native mode when DFP && !SCALE_PANEL */
249 NV50CrtcCommand(crtc, NV50_CRTC0_CLOCK, adjusted_mode->Clock | 0x800000);
250 NV50CrtcCommand(crtc, NV50_CRTC0_INTERLACE, (adjusted_mode->Flags & V_INTERLACE) ? 2 : 0);
251 NV50CrtcCommand(crtc, NV50_CRTC0_DISPLAY_START, 0);
252 NV50CrtcCommand(crtc, 0x82c, 0);
253 NV50CrtcCommand(crtc, NV50_CRTC0_DISPLAY_TOTAL, adjusted_mode->CrtcVTotal << 16 | adjusted_mode->CrtcHTotal);
254 NV50CrtcCommand(crtc, NV50_CRTC0_SYNC_DURATION, (vsync_dur - 1) << 16 | (hsync_dur - 1));
255 NV50CrtcCommand(crtc, NV50_CRTC0_SYNC_START_TO_BLANK_END, (vsync_start_to_end - 1) << 16 | (hsync_start_to_end - 1));
256 NV50CrtcCommand(crtc, NV50_CRTC0_MODE_UNK1, (vunk1 - 1) << 16 | (hunk1 - 1));
257 if (adjusted_mode->Flags & V_INTERLACE) {
258 NV50CrtcCommand(crtc, NV50_CRTC0_MODE_UNK2, (vunk2b - 1) << 16 | (vunk2a - 1));
260 NV50CrtcCommand(crtc, NV50_CRTC0_FB_SIZE, pScrn->virtualY << 16 | pScrn->virtualX);
261 NV50CrtcCommand(crtc, NV50_CRTC0_PITCH, pScrn->displayWidth * (pScrn->bitsPerPixel / 8) | 0x100000);
262 switch(pScrn->depth) {
264 NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_8BPP);
267 NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_15BPP);
270 NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_16BPP);
273 NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_24BPP);
276 NV50CrtcSetDither(crtc, FALSE);
277 NV50CrtcCommand(crtc, NV50_CRTC0_UNK_8A8, 0x40000);
278 NV50CrtcCommand(crtc, NV50_CRTC0_FB_POS, y << 16 | x);
279 /* This is the actual resolution of the mode. */
280 NV50CrtcCommand(crtc, NV50_CRTC0_SCRN_SIZE, (mode->VDisplay << 16) | mode->HDisplay);
281 NV50CrtcCommand(crtc, 0x8d4, 0);
283 NV50CrtcBlankScreen(crtc, FALSE);
287 NV50CrtcBlankScreen(xf86CrtcPtr crtc, Bool blank)
289 ScrnInfoPtr pScrn = crtc->scrn;
290 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcBlankScreen is called (%s).\n", blank ? "blanked" : "unblanked");
292 NVPtr pNv = NVPTR(pScrn);
293 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
296 NV50CrtcShowHideCursor(crtc, FALSE, FALSE);
298 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE, NV50_CRTC0_CLUT_MODE_BLANK);
299 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, 0);
300 if(pNv->NVArch != 0x50)
301 NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_BLANK);
302 NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_BLANK);
303 if(pNv->NVArch != 0x50)
304 NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_BLANK);
306 NV50CrtcCommand(crtc, NV50_CRTC0_FB_OFFSET, pNv->FB->offset >> 8);
307 NV50CrtcCommand(crtc, 0x864, 0);
308 NVWrite(pNv, 0x00610380, 0);
309 /* RAM is clamped to 256 MiB. */
310 NVWrite(pNv, NV50_CRTC0_RAM_AMOUNT, pNv->RamAmountKBytes * 1024 - 1);
311 NVWrite(pNv, 0x00610388, 0x150000);
312 NVWrite(pNv, 0x0061038C, 0);
313 if (nv_crtc->head == 1)
314 NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_OFFSET, pNv->Cursor2->offset >> 8);
316 NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_OFFSET, pNv->Cursor->offset >> 8);
317 if(pNv->NVArch != 0x50)
318 NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_UNBLANK);
319 if(nv_crtc->cursorVisible)
320 NV50CrtcShowHideCursor(crtc, TRUE, FALSE);
321 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE,
322 pScrn->depth == 8 ? NV50_CRTC0_CLUT_MODE_OFF : NV50_CRTC0_CLUT_MODE_ON);
323 /* Each CRTC has it's own CLUT. */
324 if (nv_crtc->head == 1)
325 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, pNv->CLUT1->offset >> 8);
327 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, pNv->CLUT0->offset >> 8);
328 if(pNv->NVArch != 0x50)
329 NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_UNBLANK);
330 NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_UNBLANK);
334 /******************************** Cursor stuff ********************************/
335 static void NV50CrtcShowHideCursor(xf86CrtcPtr crtc, Bool show, Bool update)
337 ScrnInfoPtr pScrn = crtc->scrn;
338 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcShowHideCursor is called (%s, %s).\n", show ? "show" : "hide", update ? "update" : "no update");
340 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
342 NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR,
343 show ? NV50_CRTC0_CURSOR_SHOW : NV50_CRTC0_CURSOR_HIDE);
345 nv_crtc->cursorVisible = show;
346 NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
350 void NV50CrtcShowCursor(xf86CrtcPtr crtc)
352 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
354 /* Calling NV50_UPDATE_DISPLAY during modeset will lock up everything. */
355 if (nv_crtc->modeset_lock)
358 NV50CrtcShowHideCursor(crtc, TRUE, TRUE);
361 void NV50CrtcHideCursor(xf86CrtcPtr crtc)
363 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
365 /* Calling NV50_UPDATE_DISPLAY during modeset will lock up everything. */
366 if (nv_crtc->modeset_lock)
369 NV50CrtcShowHideCursor(crtc, FALSE, TRUE);
372 /******************************** CRTC stuff ********************************/
375 NV50CrtcPrepare(xf86CrtcPtr crtc)
377 ScrnInfoPtr pScrn = crtc->scrn;
378 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcPrepare is called.\n");
380 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
381 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
384 nv_crtc->modeset_lock = TRUE;
386 for(i = 0; i < xf86_config->num_output; i++) {
387 xf86OutputPtr output = xf86_config->output[i];
390 output->funcs->mode_set(output, NULL, NULL);
395 NV50CrtcSetDither(xf86CrtcPtr crtc, Bool update)
397 ScrnInfoPtr pScrn = crtc->scrn;
398 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetDither is called (%s).\n", update ? "update" : "no update");
400 xf86OutputPtr output = NULL;
401 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
404 for (i = 0; i < xf86_config->num_output; i++) {
405 if (xf86_config->output[i]->crtc == crtc) {
406 output = xf86_config->output[i];
414 NVOutputPrivatePtr nv_output = output->driver_private;
416 NV50CrtcCommand(crtc, NV50_CRTC0_DITHERING_CTRL, nv_output->dithering ?
417 NV50_CRTC0_DITHERING_CTRL_ON : NV50_CRTC0_DITHERING_CTRL_OFF);
419 NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
422 static void ComputeAspectScale(DisplayModePtr mode, DisplayModePtr adjusted_mode, int *outX, int *outY)
424 float scaleX, scaleY, scale;
426 scaleX = adjusted_mode->HDisplay / (float)mode->HDisplay;
427 scaleY = adjusted_mode->VDisplay / (float)mode->VDisplay;
434 *outX = mode->HDisplay * scale;
435 *outY = mode->VDisplay * scale;
438 void NV50CrtcSetScale(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, enum scaling_modes scale)
440 ScrnInfoPtr pScrn = crtc->scrn;
441 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetScale is called.\n");
443 int outX = 0, outY = 0;
447 ComputeAspectScale(mode, adjusted_mode, &outX, &outY);
450 case SCALE_FULLSCREEN:
451 outX = adjusted_mode->HDisplay;
452 outY = adjusted_mode->VDisplay;
456 outX = mode->HDisplay;
457 outY = mode->VDisplay;
461 /* What kind of mode is this precisely? */
462 if ((mode->Flags & V_DBLSCAN) || (mode->Flags & V_INTERLACE) ||
463 mode->HDisplay != outX || mode->VDisplay != outY) {
464 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_CTRL, 9);
466 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_CTRL, 0);
468 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_REG1, outY << 16 | outX);
469 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_REG2, outY << 16 | outX);
473 NV50CrtcCommit(xf86CrtcPtr crtc)
475 ScrnInfoPtr pScrn = crtc->scrn;
476 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcCommit is called.\n");
478 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
479 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
480 int i, crtc_mask = 0;
482 /* If any heads are unused, blank them */
483 for(i = 0; i < xf86_config->num_output; i++) {
484 xf86OutputPtr output = xf86_config->output[i];
487 /* XXXagp: This assumes that xf86_config->crtc[i] is HEADi */
488 crtc_mask |= 1 << NV50CrtcGetHead(output->crtc);
492 for(i = 0; i < xf86_config->num_crtc; i++) {
493 if(!((1 << i) & crtc_mask)) {
494 NV50CrtcBlankScreen(xf86_config->crtc[i], TRUE);
498 xf86_reload_cursors (pScrn->pScreen);
500 NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
502 nv_crtc->modeset_lock = FALSE;