NV50: Give a few registers an UNK label.
[nouveau] / src / nv50_crtc.c
1 /*
2  * Copyright (c) 2007 NVIDIA, Corporation
3  * Copyright (c) 2008 Maarten Maathuis
4  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
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.
23  */
24
25 #include "nv_include.h"
26
27 /* Don't call the directly, only load state should do this on the long run*/
28 void NV50CheckWriteVClk(ScrnInfoPtr pScrn)
29 {
30         NVPtr pNv = NVPTR(pScrn);
31         int t_start = GetTimeInMillis();
32
33         while (NVRead(pNv, NV50_DISPLAY_CTRL_STATE) & NV50_DISPLAY_CTRL_STATE_PENDING) {
34                 /* An educated guess. */
35                 const uint32_t supervisor = NVRead(pNv, NV50_DISPLAY_SUPERVISOR);
36
37                 /* Just in case something goes bad, at least you can blindly restart your machine. */
38                 if ((GetTimeInMillis() - t_start) > 5000) {
39                         xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "NV50CheckWriteVClk() timed out.\n");
40                         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "A reboot is probably required now.\n");
41                         break;
42                 }
43
44                 /* Simply acknowledge it, maybe we should do more? */
45                 if (supervisor & NV50_DISPLAY_SUPERVISOR_CRTCn) {
46                         NVWrite(pNv, NV50_DISPLAY_SUPERVISOR, supervisor & NV50_DISPLAY_SUPERVISOR_CRTCn);
47                 }
48
49                 if (supervisor & NV50_DISPLAY_SUPERVISOR_CLK_MASK) {
50                         if (supervisor & NV50_DISPLAY_SUPERVISOR_CLK_UPDATE) {
51                                 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
52                                 const uint32_t clockvar = NVRead(pNv, NV50_DISPLAY_UNK30_CTRL);
53                                 int i;
54
55                                 for(i = 0; i < xf86_config->num_crtc; i++) {
56                                         xf86CrtcPtr crtc = xf86_config->crtc[i];
57                                         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
58                                         uint32_t mask = 0;
59
60                                         if (nv_crtc->head == 1)
61                                                 mask = NV50_DISPLAY_UNK30_CTRL_UPDATE_VCLK1;
62                                         else
63                                                 mask = NV50_DISPLAY_UNK30_CTRL_UPDATE_VCLK0;
64
65                                         /* Always do something if the supervisor wants a clock change. */
66                                         /* 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));
69                                 }
70                         }
71
72                         NVWrite(pNv, NV50_DISPLAY_SUPERVISOR, 1 << (ffs(supervisor & NV50_DISPLAY_SUPERVISOR_CLK_MASK) - 1));
73                         NVWrite(pNv, NV50_DISPLAY_UNK30_CTRL, NV50_DISPLAY_UNK30_CTRL_PENDING);
74                 }
75         }
76 }
77
78 void NV50DisplayCommand(ScrnInfoPtr pScrn, CARD32 addr, CARD32 value)
79 {
80         DDXMMIOH("NV50DisplayCommand: head %d addr 0x%X value 0x%X\n", 0, addr, value);
81         NVPtr pNv = NVPTR(pScrn);
82         NVWrite(pNv, NV50_DISPLAY_CTRL_VAL, value);
83         NVWrite(pNv, NV50_DISPLAY_CTRL_STATE, addr | 0x10000 | NV50_DISPLAY_CTRL_STATE_ENABLE | NV50_DISPLAY_CTRL_STATE_PENDING);
84         NV50CheckWriteVClk(pScrn);
85 }
86
87 void NV50CrtcCommand(xf86CrtcPtr crtc, CARD32 addr, CARD32 value)
88 {
89         ScrnInfoPtr pScrn = crtc->scrn;
90         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
91
92         /* This head dependent offset may not be true everywere */
93         NV50DisplayCommand(pScrn, addr + 0x400 * nv_crtc->head, value);
94 }
95
96 void NV50CrtcSetPClk(xf86CrtcPtr crtc, Bool update)
97 {
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         }
151 }
152
153 static void
154 NV50CrtcSetDither(xf86CrtcPtr crtc, Bool update)
155 {
156         ScrnInfoPtr pScrn = crtc->scrn;
157         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetDither is called (%s).\n", update ? "update" : "no update");
158
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;
172
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);
187
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;
194         /* 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;
197         /* 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;
200
201         if (adjusted_mode->Flags & V_INTERLACE) {
202                 vsync_dur /= 2;
203                 vsync_start_to_end  /= 2;
204                 vunk1 /= 2;
205                 vunk2a /= 2;
206                 vunk2b /= 2;
207                 /* magic */
208                 if (adjusted_mode->Flags & V_DBLSCAN) {
209                         vsync_start_to_end -= 1;
210                         vunk1 -= 1;
211                         vunk2a -= 1;
212                         vunk2b -= 1;
213                 }
214         }
215
216         /* NV50CrtcCommand includes head offset */
217         /* 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);
220         NV50CrtcCommand(crtc, NV50_CRTC0_DISPLAY_START, 0);
221         NV50CrtcCommand(crtc, NV50_CRTC0_UNK82C, 0);
222         NV50CrtcCommand(crtc, NV50_CRTC0_DISPLAY_TOTAL, adjusted_mode->CrtcVTotal << 16 | adjusted_mode->CrtcHTotal);
223         NV50CrtcCommand(crtc, NV50_CRTC0_SYNC_DURATION, (vsync_dur - 1) << 16 | (hsync_dur - 1));
224         NV50CrtcCommand(crtc, NV50_CRTC0_SYNC_START_TO_BLANK_END, (vsync_start_to_end - 1) << 16 | (hsync_start_to_end - 1));
225         NV50CrtcCommand(crtc, NV50_CRTC0_MODE_UNK1, (vunk1 - 1) << 16 | (hunk1 - 1));
226         if (adjusted_mode->Flags & V_INTERLACE) {
227                 NV50CrtcCommand(crtc, NV50_CRTC0_MODE_UNK2, (vunk2b - 1) << 16 | (vunk2a - 1));
228         }
229         NV50CrtcCommand(crtc, NV50_CRTC0_FB_SIZE, pScrn->virtualY << 16 | pScrn->virtualX);
230         NV50CrtcCommand(crtc, NV50_CRTC0_PITCH, pScrn->displayWidth * (pScrn->bitsPerPixel / 8) | 0x100000);
231         switch (pScrn->depth) {
232                 case 8:
233                         NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_8BPP); 
234                         break;
235                 case 15:
236                         NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_15BPP);
237                         break;
238                 case 16:
239                         NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_16BPP);
240                         break;
241                 case 24:
242                         NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_24BPP); 
243                         break;
244         }
245         NV50CrtcSetDither(crtc, FALSE);
246         NV50CrtcCommand(crtc, NV50_CRTC0_UNK_8A8, 0x40000);
247         NV50CrtcCommand(crtc, NV50_CRTC0_FB_POS, y << 16 | x);
248         /* This is the actual resolution of the mode. */
249         NV50CrtcCommand(crtc, NV50_CRTC0_SCRN_SIZE, (mode->VDisplay << 16) | mode->HDisplay);
250         NV50CrtcCommand(crtc, 0x8d4, 0);
251
252         NV50CrtcBlankScreen(crtc, FALSE);
253 }
254
255 void
256 NV50CrtcBlankScreen(xf86CrtcPtr crtc, Bool blank)
257 {
258         ScrnInfoPtr pScrn = crtc->scrn;
259         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcBlankScreen is called (%s).\n", blank ? "blanked" : "unblanked");
260
261         NVPtr pNv = NVPTR(pScrn);
262         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
263
264         if (blank) {
265                 NV50CrtcShowHideCursor(crtc, FALSE, FALSE);
266
267                 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE, NV50_CRTC0_CLUT_MODE_BLANK);
268                 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, 0);
269                 if(pNv->NVArch != 0x50)
270                         NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_BLANK);
271                 NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_BLANK);
272                 if(pNv->NVArch != 0x50)
273                         NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_BLANK);
274         } else {
275                 NV50CrtcCommand(crtc, NV50_CRTC0_FB_OFFSET, pNv->FB->offset >> 8);
276                 NV50CrtcCommand(crtc, 0x864, 0);
277                 NVWrite(pNv, NV50_DISPLAY_UNK_380, 0);
278                 /* RAM is clamped to 256 MiB. */
279                 NVWrite(pNv, NV50_DISPLAY_RAM_AMOUNT, pNv->RamAmountKBytes * 1024 - 1);
280                 NVWrite(pNv, NV50_DISPLAY_UNK_388, 0x150000);
281                 NVWrite(pNv, NV50_DISPLAY_UNK_38C, 0);
282                 if (nv_crtc->head == 1)
283                         NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_OFFSET, pNv->Cursor2->offset >> 8);
284                 else
285                         NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_OFFSET, pNv->Cursor->offset >> 8);
286                 if(pNv->NVArch != 0x50)
287                         NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_UNBLANK);
288                 if(nv_crtc->cursorVisible)
289                         NV50CrtcShowHideCursor(crtc, TRUE, FALSE);
290                 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE, 
291                         pScrn->depth == 8 ? NV50_CRTC0_CLUT_MODE_OFF : NV50_CRTC0_CLUT_MODE_ON);
292                 /* Each CRTC has it's own CLUT. */
293                 if (nv_crtc->head == 1)
294                         NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, pNv->CLUT1->offset >> 8);
295                 else
296                         NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, pNv->CLUT0->offset >> 8);
297                 if(pNv->NVArch != 0x50)
298                         NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_UNBLANK);
299                 NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_UNBLANK);
300         }
301 }
302
303 static void
304 nv50_crtc_prepare(xf86CrtcPtr crtc)
305 {
306         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;
314
315         for(i = 0; i < xf86_config->num_output; i++) {
316                 xf86OutputPtr output = xf86_config->output[i];
317
318                 if (!output->crtc)
319                         output->funcs->mode_set(output, NULL, NULL);
320         }
321 }
322
323 static void ComputeAspectScale(DisplayModePtr mode, DisplayModePtr adjusted_mode, int *outX, int *outY)
324 {
325         float scaleX, scaleY, scale;
326
327         scaleX = adjusted_mode->HDisplay / (float)mode->HDisplay;
328         scaleY = adjusted_mode->VDisplay / (float)mode->VDisplay;
329
330         if(scaleX > scaleY)
331                 scale = scaleY;
332         else
333                 scale = scaleX;
334
335         *outX = mode->HDisplay * scale;
336         *outY = mode->VDisplay * scale;
337 }
338
339 void NV50CrtcSetScale(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, enum scaling_modes scale)
340 {
341         ScrnInfoPtr pScrn = crtc->scrn;
342         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetScale is called.\n");
343
344         int outX = 0, outY = 0;
345
346         switch(scale) {
347                 case SCALE_ASPECT:
348                         ComputeAspectScale(mode, adjusted_mode, &outX, &outY);
349                         break;
350                 case SCALE_PANEL:
351                 case SCALE_FULLSCREEN:
352                         outX = adjusted_mode->HDisplay;
353                         outY = adjusted_mode->VDisplay;
354                         break;
355                 case SCALE_NOSCALE:
356                 default:
357                         outX = mode->HDisplay;
358                         outY = mode->VDisplay;
359                         break;
360         }
361
362         /* What kind of mode is this precisely? */
363         if ((mode->Flags & V_DBLSCAN) || (mode->Flags & V_INTERLACE) ||
364                 mode->HDisplay != outX || mode->VDisplay != outY) {
365                 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_CTRL, 9);
366         } else {
367                 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_CTRL, 0);
368         }
369         NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_REG1, outY << 16 | outX);
370         NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_REG2, outY << 16 | outX);
371 }
372
373 static void
374 nv50_crtc_commit(xf86CrtcPtr crtc)
375 {
376         ScrnInfoPtr pScrn = crtc->scrn;
377         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_commit is called.\n");
378
379         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
380         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
381         int i, crtc_mask = 0;
382
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];
386
387                 if (output->crtc) {
388                         NVCrtcPrivatePtr nv_crtc = output->crtc->driver_private;
389                         crtc_mask |= (1 << nv_crtc->head);
390                 }
391         }
392
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         }
398
399         xf86_reload_cursors (pScrn->pScreen);
400
401         NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
402
403         nv_crtc->modeset_lock = FALSE;
404 }
405
406 static Bool nv50_crtc_lock(xf86CrtcPtr crtc)
407 {
408         return FALSE;
409 }
410
411 /*
412  * The indices are a bit strange, but i'll assume it's correct (taken from nv).
413  * The LUT resolution seems to be 14 bits on NV50 as opposed to the 8 bits of previous hardware.
414  */
415 #define NV50_LUT_INDEX(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8)))
416 static void
417 nv50_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
418                                         int size)
419 {
420         ScrnInfoPtr pScrn = crtc->scrn;
421         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_gamma_set is called.\n");
422
423         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
424         NVPtr pNv = NVPTR(pScrn);
425         uint32_t index, i;
426         void * CLUT = NULL;
427
428         /* Each CRTC has it's own CLUT. */
429         if (nv_crtc->head == 1)
430                 CLUT = pNv->CLUT1->map;
431         else
432                 CLUT = pNv->CLUT0->map;
433
434         volatile struct {
435                 unsigned short red, green, blue, unused;
436         } *lut = (void *) CLUT;
437
438         switch (pScrn->depth) {
439         case 15:
440                 /* R5G5B5 */
441                 for (i = 0; i < 32; i++) {
442                         index = NV50_LUT_INDEX(i, 5);
443                         lut[index].red = red[i] >> 2;
444                         lut[index].green = green[i] >> 2;
445                         lut[index].blue = blue[i] >> 2;
446                 }
447                 break;
448         case 16:
449                 /* R5G6B5 */
450                 for (i = 0; i < 32; i++) {
451                         index = NV50_LUT_INDEX(i, 5);
452                         lut[index].red = red[i] >> 2;
453                         lut[index].blue = blue[i] >> 2;
454                 }
455
456                 /* Green has an extra bit. */
457                 for (i = 0; i < 64; i++) {
458                         index = NV50_LUT_INDEX(i, 6);
459                         lut[index].green = green[i] >> 2;
460                 }
461                 break;
462         default:
463                 /* R8G8B8 */
464                 for (i = 0; i < 256; i++) {
465                         lut[i].red = red[i] >> 2;
466                         lut[i].green = green[i] >> 2;
467                         lut[i].blue = blue[i] >> 2;
468                 }
469                 break;
470         }
471 }
472
473 static void
474 nv50_crtc_dpms_set(xf86CrtcPtr crtc, int mode)
475 {
476 }
477
478 static Bool
479 nv50_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
480                      DisplayModePtr adjusted_mode)
481 {
482         return TRUE;
483 }
484
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()
506 {
507         return &nv50_crtc_funcs;
508 }
509