2 * Copyright 2007 NVIDIA, Corporation
3 * Copyright 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 "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 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of 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
24 #include "nouveau_modeset.h"
25 #include "nouveau_crtc.h"
26 #include "nouveau_output.h"
27 #include "nouveau_connector.h"
29 /* Don't call the directly, only load state should do this on the long run*/
31 NV50CheckWriteVClk(ScrnInfoPtr pScrn)
33 NVPtr pNv = NVPTR(pScrn);
34 int t_start = GetTimeInMillis();
36 while (NVRead(pNv, NV50_DISPLAY_CTRL_STATE) & NV50_DISPLAY_CTRL_STATE_PENDING) {
37 /* An educated guess. */
38 const uint32_t supervisor = NVRead(pNv, NV50_DISPLAY_SUPERVISOR);
40 /* Just in case something goes bad, at least you can blindly restart your machine. */
41 if ((GetTimeInMillis() - t_start) > 5000) {
42 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "NV50CheckWriteVClk() timed out.\n");
43 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "A reboot is probably required now.\n");
47 /* Simply acknowledge it, maybe we should do more? */
48 if (supervisor & NV50_DISPLAY_SUPERVISOR_CRTCn) {
49 NVWrite(pNv, NV50_DISPLAY_SUPERVISOR, supervisor & NV50_DISPLAY_SUPERVISOR_CRTCn);
52 if (supervisor & NV50_DISPLAY_SUPERVISOR_CLK_MASK) {
53 if (supervisor & NV50_DISPLAY_SUPERVISOR_CLK_UPDATE) {
54 const uint32_t clockvar = NVRead(pNv, NV50_DISPLAY_UNK30_CTRL);
57 for(i = 0; i < 2; i++) {
58 nouveauCrtcPtr crtc = pNv->crtc[i];
62 mask = NV50_DISPLAY_UNK30_CTRL_UPDATE_VCLK1;
64 mask = NV50_DISPLAY_UNK30_CTRL_UPDATE_VCLK0;
67 crtc->SetPixelClock(crtc, crtc->pixel_clock);
68 /* Always do something if the supervisor wants a clock change. */
69 /* This is needed because you get a deadlock if you don't kick the NV50_CRTC0_CLK_CTRL2 register. */
70 if (crtc->modeset_lock) {
71 crtc->SetClockMode(crtc, crtc->pixel_clock);
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);
82 NVWrite(pNv, NV50_DISPLAY_SUPERVISOR, 1 << (ffs(supervisor & NV50_DISPLAY_SUPERVISOR_CLK_MASK) - 1));
83 NVWrite(pNv, NV50_DISPLAY_UNK30_CTRL, NV50_DISPLAY_UNK30_CTRL_PENDING);
88 void NV50DisplayCommand(ScrnInfoPtr pScrn, uint32_t addr, uint32_t value)
90 DDXMMIOH("NV50DisplayCommand: head %d addr 0x%X value 0x%X\n", 0, addr, value);
91 NVPtr pNv = NVPTR(pScrn);
92 NVWrite(pNv, NV50_DISPLAY_CTRL_VAL, value);
93 NVWrite(pNv, NV50_DISPLAY_CTRL_STATE, addr | 0x10000 | NV50_DISPLAY_CTRL_STATE_ENABLE | NV50_DISPLAY_CTRL_STATE_PENDING);
94 NV50CheckWriteVClk(pScrn);
97 void NV50CrtcCommand(nouveauCrtcPtr crtc, uint32_t addr, uint32_t value)
99 ScrnInfoPtr pScrn = crtc->scrn;
101 /* This head dependent offset is only for crtc commands. */
102 NV50DisplayCommand(pScrn, addr + 0x400 * crtc->index, value);
106 NV50CrtcModeValid(nouveauCrtcPtr crtc, DisplayModePtr mode)
112 NV50CrtcModeSet(nouveauCrtcPtr crtc, DisplayModePtr mode)
114 ScrnInfoPtr pScrn = crtc->scrn;
115 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcModeSet is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
117 /* Anyone know a more appropriate name? */
118 DisplayModePtr desired_mode = crtc->use_native_mode ? crtc->native_mode : mode;
120 /* Save the pixel clock for posterity. */
121 crtc->pixel_clock = desired_mode->Clock;
122 crtc->cur_mode = mode;
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;
128 /* I can't give this a proper name, anyone else can? */
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;
131 /* Another strange value, this time only for interlaced modes. */
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;
135 if (desired_mode->Flags & V_INTERLACE) {
137 vsync_start_to_end /= 2;
142 if (desired_mode->Flags & V_DBLSCAN) {
143 vsync_start_to_end -= 1;
150 /* NV50CrtcCommand includes head offset */
151 /* This is the native mode when DFP && !SCALE_PANEL */
152 NV50CrtcCommand(crtc, NV50_CRTC0_CLOCK, desired_mode->Clock | 0x800000);
153 NV50CrtcCommand(crtc, NV50_CRTC0_INTERLACE, (desired_mode->Flags & V_INTERLACE) ? 2 : 0);
154 NV50CrtcCommand(crtc, NV50_CRTC0_DISPLAY_START, 0);
155 NV50CrtcCommand(crtc, NV50_CRTC0_UNK82C, 0);
156 NV50CrtcCommand(crtc, NV50_CRTC0_DISPLAY_TOTAL, desired_mode->CrtcVTotal << 16 | desired_mode->CrtcHTotal);
157 NV50CrtcCommand(crtc, NV50_CRTC0_SYNC_DURATION, (vsync_dur - 1) << 16 | (hsync_dur - 1));
158 NV50CrtcCommand(crtc, NV50_CRTC0_SYNC_START_TO_BLANK_END, (vsync_start_to_end - 1) << 16 | (hsync_start_to_end - 1));
159 NV50CrtcCommand(crtc, NV50_CRTC0_MODE_UNK1, (vunk1 - 1) << 16 | (hunk1 - 1));
160 if (desired_mode->Flags & V_INTERLACE) {
161 NV50CrtcCommand(crtc, NV50_CRTC0_MODE_UNK2, (vunk2b - 1) << 16 | (vunk2a - 1));
163 NV50CrtcCommand(crtc, NV50_CRTC0_FB_SIZE, pScrn->virtualY << 16 | pScrn->virtualX);
165 /* Maybe move this calculation elsewhere? */
166 crtc->fb_pitch = pScrn->displayWidth * (pScrn->bitsPerPixel / 8);
167 NV50CrtcCommand(crtc, NV50_CRTC0_FB_PITCH, crtc->fb_pitch | 0x100000);
169 switch (pScrn->depth) {
171 NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_8BPP);
174 NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_15BPP);
177 NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_16BPP);
180 NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_24BPP);
183 crtc->SetDither(crtc);
184 NV50CrtcCommand(crtc, NV50_CRTC0_COLOR_CTRL, NV50_CRTC_COLOR_CTRL_MODE_COLOR);
185 NV50CrtcCommand(crtc, NV50_CRTC0_FB_POS, (crtc->y << 16) | (crtc->x));
186 /* This is the actual resolution of the mode. */
187 NV50CrtcCommand(crtc, NV50_CRTC0_REAL_RES, (mode->VDisplay << 16) | mode->HDisplay);
188 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_CENTER_OFFSET, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0));
190 /* Maybe move this as well? */
191 crtc->Blank(crtc, FALSE);
195 NV50CrtcSetPixelClock(nouveauCrtcPtr crtc, int clock)
197 ScrnInfoPtr pScrn = crtc->scrn;
198 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetPixelClock is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
200 NVPtr pNv = NVPTR(pScrn);
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;
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);
211 uint32_t reg1 = NVRead(pNv, pll_reg + 4);
212 uint32_t reg2 = NVRead(pNv, pll_reg + 8);
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.
217 NVWrite(pNv, NV50_CRTC0_CLK_CTRL1 + crtc->index * 0x800, NV50_CRTC_CLK_CTRL1_CONNECTED | 0x10000011);
219 /* Eventually we should learn ourselves what all the bits should be. */
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;
228 reg1 |= (M1 << 16) | N1;
229 reg2 |= (log2P << 28) | (M2 << 16) | N2;
231 NVWrite(pNv, pll_reg + 4, reg1);
232 NVWrite(pNv, pll_reg + 8, reg2);
236 NV50CrtcSetClockMode(nouveauCrtcPtr crtc, int clock)
238 ScrnInfoPtr pScrn = crtc->scrn;
239 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetClockMode is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
241 NVPtr pNv = NVPTR(pScrn);
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);
248 NV50CrtcSetFB(nouveauCrtcPtr crtc, struct nouveau_bo * buffer)
250 /* For the moment the actual hardware settings stays in ModeSet(). */
251 crtc->front_buffer = buffer;
255 NV50CrtcSetFBOffset(nouveauCrtcPtr crtc, uint32_t x, uint32_t y)
257 /* For the moment the actual hardware settings stays in ModeSet(). */
263 NV50CrtcBlank(nouveauCrtcPtr crtc, Bool blanked)
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");
268 NVPtr pNv = NVPTR(pScrn);
271 crtc->HideCursor(crtc, TRUE);
273 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE, NV50_CRTC0_CLUT_MODE_BLANK);
274 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, 0);
275 if (pNv->NVArch != 0x50)
276 NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_BLANK);
277 NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_BLANK);
278 if (pNv->NVArch != 0x50)
279 NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_BLANK);
281 NV50CrtcCommand(crtc, NV50_CRTC0_FB_OFFSET, crtc->front_buffer->offset >> 8);
282 NV50CrtcCommand(crtc, 0x864, 0);
283 NVWrite(pNv, NV50_DISPLAY_UNK_380, 0);
284 /* RAM is clamped to 256 MiB. */
285 NVWrite(pNv, NV50_DISPLAY_RAM_AMOUNT, pNv->RamAmountKBytes * 1024 - 1);
286 NVWrite(pNv, NV50_DISPLAY_UNK_388, 0x150000);
287 NVWrite(pNv, NV50_DISPLAY_UNK_38C, 0);
288 if (crtc->index == 1)
289 NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_OFFSET, pNv->Cursor2->offset >> 8);
291 NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_OFFSET, pNv->Cursor->offset >> 8);
292 if(pNv->NVArch != 0x50)
293 NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_UNBLANK);
295 if (crtc->cursor_visible)
296 crtc->ShowCursor(crtc, TRUE);
298 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE,
299 pScrn->depth == 8 ? NV50_CRTC0_CLUT_MODE_OFF : NV50_CRTC0_CLUT_MODE_ON);
300 /* Each CRTC has it's own CLUT. */
301 if (crtc->index == 1)
302 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, pNv->CLUT1->offset >> 8);
304 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, pNv->CLUT0->offset >> 8);
305 if (pNv->NVArch != 0x50)
306 NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_UNBLANK);
307 NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_UNBLANK);
312 NV50CrtcSetDither(nouveauCrtcPtr crtc)
314 ScrnInfoPtr pScrn = crtc->scrn;
315 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetDither is called (%s).\n", !crtc->modeset_lock ? "update" : "no update");
317 NV50CrtcCommand(crtc, NV50_CRTC0_DITHERING_CTRL, crtc->dithering ?
318 NV50_CRTC0_DITHERING_CTRL_ON : NV50_CRTC0_DITHERING_CTRL_OFF);
320 if (!crtc->modeset_lock)
321 NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
325 ComputeAspectScale(DisplayModePtr mode, DisplayModePtr adjusted_mode, int *outX, int *outY)
327 float scaleX, scaleY, scale;
329 scaleX = adjusted_mode->HDisplay / (float)mode->HDisplay;
330 scaleY = adjusted_mode->VDisplay / (float)mode->VDisplay;
337 *outX = mode->HDisplay * scale;
338 *outY = mode->VDisplay * scale;
342 NV50CrtcSetScaleMode(nouveauCrtcPtr crtc, int scale)
344 ScrnInfoPtr pScrn = crtc->scrn;
345 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetScale is called with mode %d for %s.\n", scale, crtc->index ? "CRTC1" : "CRTC0");
347 uint32_t scale_val = 0;
348 int outX = 0, outY = 0;
352 ComputeAspectScale(crtc->cur_mode, crtc->native_mode, &outX, &outY);
354 case SCALE_FULLSCREEN:
355 outX = crtc->native_mode->HDisplay;
356 outY = crtc->native_mode->VDisplay;
361 outX = crtc->cur_mode->HDisplay;
362 outY = crtc->cur_mode->VDisplay;
366 /* Got a better name for SCALER_ACTIVE? */
367 if ((crtc->cur_mode->Flags & V_DBLSCAN) || (crtc->cur_mode->Flags & V_INTERLACE) ||
368 crtc->cur_mode->HDisplay != outX || crtc->cur_mode->VDisplay != outY) {
369 scale_val = NV50_CRTC0_SCALE_CTRL_SCALER_ACTIVE;
371 scale_val = NV50_CRTC0_SCALE_CTRL_SCALER_INACTIVE;
374 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_CTRL, scale_val);
375 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_RES1, outY << 16 | outX);
376 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_RES2, outY << 16 | outX);
384 NV50CrtcShowCursor(nouveauCrtcPtr crtc, Bool forced_lock)
386 ScrnInfoPtr pScrn = crtc->scrn;
387 //xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcShowCursor is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
389 if (!crtc->modeset_lock)
390 crtc->cursor_visible = TRUE;
392 NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_CTRL, NV50_CRTC0_CURSOR_CTRL_SHOW);
394 /* Calling this during modeset will lock things up. */
395 if (!crtc->modeset_lock && !forced_lock)
396 NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
400 NV50CrtcHideCursor(nouveauCrtcPtr crtc, Bool forced_lock)
402 ScrnInfoPtr pScrn = crtc->scrn;
403 //xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcHideCursor is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
405 if (!crtc->modeset_lock)
406 crtc->cursor_visible = FALSE;
408 NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_CTRL, NV50_CRTC0_CURSOR_CTRL_HIDE);
410 /* Calling this during modeset will lock things up. */
411 if (!crtc->modeset_lock && !forced_lock)
412 NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
416 NV50CrtcSetCursorPosition(nouveauCrtcPtr crtc, int x, int y)
418 ScrnInfoPtr pScrn = crtc->scrn;
419 NVPtr pNv = NVPTR(pScrn);
420 NVWrite(pNv, NV50_CRTC0_CURSOR_POS + crtc->index * 0x1000, (y & 0xFFFF) << 16 | (x & 0xFFFF));
422 /* This is needed to allow the cursor to move. */
423 NVWrite(pNv, NV50_CRTC0_CURSOR_POS_CTRL + crtc->index * 0x1000, 0);
427 NV50CrtcLoadCursor(nouveauCrtcPtr crtc, Bool argb, uint32_t *src)
429 if (!argb) /* FIXME */
432 NVPtr pNv = NVPTR(crtc->scrn);
433 uint32_t *dst = NULL;
435 if (crtc->index == 1)
436 dst = (uint32_t *) pNv->Cursor2->map;
438 dst = (uint32_t *) pNv->Cursor->map;
440 /* Assume cursor is 64x64 */
441 memcpy(dst, src, 64 * 64 * 4);
449 * The indices are a bit strange, but i'll assume it's correct (taken from nv).
450 * The LUT resolution seems to be 14 bits on NV50 as opposed to the 8 bits of previous hardware.
452 #define NV50_LUT_INDEX(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8)))
454 NV50CrtcGammaSet(nouveauCrtcPtr crtc, uint16_t *red, uint16_t *green, uint16_t *blue, int size)
456 ScrnInfoPtr pScrn = crtc->scrn;
457 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcGammaSet is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
459 NVPtr pNv = NVPTR(pScrn);
463 /* Each CRTC has it's own CLUT. */
464 if (crtc->index == 1)
465 CLUT = pNv->CLUT1->map;
467 CLUT = pNv->CLUT0->map;
470 unsigned short red, green, blue, unused;
471 } *lut = (void *) CLUT;
473 switch (pScrn->depth) {
476 for (i = 0; i < 32; i++) {
477 index = NV50_LUT_INDEX(i, 5);
478 lut[index].red = red[i] >> 2;
479 lut[index].green = green[i] >> 2;
480 lut[index].blue = blue[i] >> 2;
485 for (i = 0; i < 32; i++) {
486 index = NV50_LUT_INDEX(i, 5);
487 lut[index].red = red[i] >> 2;
488 lut[index].blue = blue[i] >> 2;
491 /* Green has an extra bit. */
492 for (i = 0; i < 64; i++) {
493 index = NV50_LUT_INDEX(i, 6);
494 lut[index].green = green[i] >> 2;
499 for (i = 0; i < 256; i++) {
500 lut[i].red = red[i] >> 2;
501 lut[i].green = green[i] >> 2;
502 lut[i].blue = blue[i] >> 2;
509 NV50CrtcInit(ScrnInfoPtr pScrn)
512 NVPtr pNv = NVPTR(pScrn);
514 for (i=0; i < 2; i++) {
515 nouveauCrtcPtr crtc = xnfcalloc(sizeof(nouveauCrtcRec), 1);
519 /* Function pointers. */
520 crtc->ModeValid = NV50CrtcModeValid;
521 crtc->ModeSet = NV50CrtcModeSet;
522 crtc->SetPixelClock = NV50CrtcSetPixelClock;
523 crtc->SetClockMode = NV50CrtcSetClockMode;
525 crtc->SetFB = NV50CrtcSetFB;
526 crtc->SetFBOffset = NV50CrtcSetFBOffset;
528 crtc->Blank = NV50CrtcBlank;
529 crtc->SetDither = NV50CrtcSetDither;
531 crtc->SetScaleMode = NV50CrtcSetScaleMode;
533 crtc->ShowCursor = NV50CrtcShowCursor;
534 crtc->HideCursor = NV50CrtcHideCursor;
535 crtc->SetCursorPosition = NV50CrtcSetCursorPosition;
536 crtc->LoadCursor = NV50CrtcLoadCursor;
538 crtc->GammaSet = NV50CrtcGammaSet;
545 NV50CrtcDestroy(ScrnInfoPtr pScrn)
548 NVPtr pNv = NVPTR(pScrn);
550 for (i=0; i < 2; i++) {
551 nouveauCrtcPtr crtc = pNv->crtc[i];