NV50: Share output properties.
[nouveau] / src / nv_output.c
1 /*
2  * Copyright 2006 Dave Airlie
3  * Copyright 2007 Maarten Maathuis
4  * Copyright 2007 Stuart Bennett
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25 /*
26  * this code uses ideas taken from the NVIDIA nv driver - the nvidia license
27  * decleration is at the bottom of this file as it is rather ugly 
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include "xf86.h"
35 #include "os.h"
36 #include "mibank.h"
37 #include "globals.h"
38 #include "xf86.h"
39 #include "xf86Priv.h"
40 #include "xf86DDC.h"
41 #include "mipointer.h"
42 #include "windowstr.h"
43 #include <randrstr.h>
44 #include <X11/extensions/render.h>
45 #include "X11/Xatom.h"
46
47 #include "xf86Crtc.h"
48 #include "nv_include.h"
49
50 const char *OutputType[] = {
51     "None",
52     "VGA",
53     "DVI",
54     "LVDS",
55     "S-video",
56     "Composite",
57 };
58
59 const char *MonTypeName[7] = {
60     "AUTO",
61     "NONE",
62     "CRT",
63     "LVDS",
64     "TMDS",
65     "CTV",
66     "STV"
67 };
68
69 static int nv_output_ramdac_offset(xf86OutputPtr output)
70 {
71         NVOutputPrivatePtr nv_output = output->driver_private;
72         int offset = 0;
73
74         if (nv_output->or & (8 | OUTPUT_C))
75                 offset += 0x68;
76         if (nv_output->or & (8 | OUTPUT_B))
77                 offset += 0x2000;
78
79         return offset;
80 }
81
82 static Bool dpms_common(xf86OutputPtr output, int mode)
83 {
84         NVOutputPrivatePtr nv_output = output->driver_private;
85         NVPtr pNv = NVPTR(output->scrn);
86         xf86CrtcPtr crtc = output->crtc;
87         NVCrtcPrivatePtr nv_crtc;
88
89         if (nv_output->last_dpms == mode) /* Don't do unnecessary mode changes. */
90                 return FALSE;
91
92         nv_output->last_dpms = mode;
93
94         if (!crtc)      /* we need nv_crtc, so give up */
95                 return TRUE;
96         nv_crtc = crtc->driver_private;
97
98         if (pNv->NVArch >= 0x17 && pNv->twoHeads) {
99                 /* We may be going for modesetting, so we must reset our output binding */
100                 if (mode == DPMSModeOff) {
101                         NVWriteVgaCrtc5758(pNv, nv_crtc->head, 0, 0x7f);
102                         NVWriteVgaCrtc5758(pNv, nv_crtc->head, 2, 0);
103                 } else {
104                         NVWriteVgaCrtc5758(pNv, nv_crtc->head, 0, nv_output->type);
105                         NVWriteVgaCrtc5758(pNv, nv_crtc->head, 2, nv_output->or);
106                 }
107         }
108
109         return TRUE;
110 }
111
112 static void
113 nv_lvds_output_dpms(xf86OutputPtr output, int mode)
114 {
115         ScrnInfoPtr pScrn = output->scrn;
116         NVPtr pNv = NVPTR(pScrn);
117         NVOutputPrivatePtr nv_output = output->driver_private;
118         xf86CrtcPtr crtc = output->crtc;
119         int oldmode = nv_output->last_dpms;
120
121         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_lvds_output_dpms is called with mode %d.\n", mode);
122
123         if (!dpms_common(output, mode))
124                 return;
125
126         if (crtc && pNv->dcb_table.entry[nv_output->dcb_entry].lvdsconf.use_power_scripts) {
127                 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
128                 int pclk = nv_get_clock_from_crtc(pScrn, &pNv->ModeReg, nv_crtc->head);
129
130                 switch (mode) {
131                 case DPMSModeStandby:
132                 case DPMSModeSuspend:
133                         call_lvds_script(pScrn, nv_crtc->head, nv_output->dcb_entry, LVDS_BACKLIGHT_OFF, pclk);
134                         break;
135                 case DPMSModeOff:
136                         call_lvds_script(pScrn, nv_crtc->head, nv_output->dcb_entry, LVDS_PANEL_OFF, pclk);
137                         break;
138                 case DPMSModeOn:
139                         if (oldmode == DPMSModeStandby || oldmode == DPMSModeSuspend)
140                                 call_lvds_script(pScrn, nv_crtc->head, nv_output->dcb_entry, LVDS_BACKLIGHT_ON, pclk);
141                         else
142                                 call_lvds_script(pScrn, nv_crtc->head, nv_output->dcb_entry, LVDS_PANEL_ON, pclk);
143                 default:
144                         break;
145                 }
146         }
147 }
148
149 static void
150 nv_analog_output_dpms(xf86OutputPtr output, int mode)
151 {
152         ScrnInfoPtr pScrn = output->scrn;
153         NVPtr pNv = NVPTR(output->scrn);
154
155         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_analog_output_dpms is called with mode %d.\n", mode);
156
157         dpms_common(output, mode);
158
159         if (pNv->twoHeads) {
160                 uint32_t outputval = NVReadRAMDAC(pNv, 0, NV_RAMDAC_OUTPUT + nv_output_ramdac_offset(output));
161
162                 switch (mode) {
163                 case DPMSModeOff:
164                         NVWriteRAMDAC(pNv, 0, NV_RAMDAC_OUTPUT + nv_output_ramdac_offset(output),
165                                       outputval & ~NV_RAMDAC_OUTPUT_DAC_ENABLE);
166                         break;
167                 case DPMSModeOn:
168                         NVWriteRAMDAC(pNv, 0, NV_RAMDAC_OUTPUT + nv_output_ramdac_offset(output),
169                                       outputval | NV_RAMDAC_OUTPUT_DAC_ENABLE);
170                         break;
171                 }
172         }
173 }
174
175 static void
176 nv_tmds_output_dpms(xf86OutputPtr output, int mode)
177 {
178         xf86CrtcPtr crtc = output->crtc;
179         ScrnInfoPtr pScrn = output->scrn;
180
181         xf86DrvMsg(pScrn->scrnIndex, X_INFO,"nv_tmds_output_dpms is called with mode %d.\n", mode);
182
183         if (!dpms_common(output, mode))
184                 return;
185
186         /* Are we assigned a ramdac already?, else we will be activated during mode set */
187         if (crtc) {
188                 NVPtr pNv = NVPTR(output->scrn);
189                 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
190                 uint32_t fpcontrol = NVReadRAMDAC(pNv, nv_crtc->head, NV_RAMDAC_FP_CONTROL);
191
192                 switch (mode) {
193                 case DPMSModeStandby:
194                 case DPMSModeSuspend:
195                 case DPMSModeOff:
196                         /* cut the TMDS output */           
197                         fpcontrol |= 0x20000022;
198                         break;
199                 case DPMSModeOn:
200                         /* disable cutting the TMDS output */
201                         fpcontrol &= ~0x20000022;
202                         break;
203                 }
204                 NVWriteRAMDAC(pNv, nv_crtc->head, NV_RAMDAC_FP_CONTROL, fpcontrol);
205         }
206 }
207
208 static void nv_output_save(xf86OutputPtr output)
209 {
210         ScrnInfoPtr pScrn = output->scrn;
211         NVPtr pNv = NVPTR(pScrn);
212         NVOutputPrivatePtr nv_output = output->driver_private;
213
214         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_output_save is called.\n");
215
216         if (pNv->twoHeads)
217                 nv_output->restore.output = NVReadRAMDAC(pNv, 0, NV_RAMDAC_OUTPUT + nv_output_ramdac_offset(output));
218
219         if (nv_output->type == OUTPUT_TMDS || nv_output->type == OUTPUT_LVDS) {
220                 int ramdac = (nv_output->or & OUTPUT_C) >> 2;
221
222                 nv_output->restore.head = ((nv_dcb_read_tmds(pNv, nv_output->dcb_entry, 0, 0x4) & 0x8) >> 3) ^ ramdac;
223         }
224 }
225
226 uint32_t nv_get_clock_from_crtc(ScrnInfoPtr pScrn, RIVA_HW_STATE *state, uint8_t crtc)
227 {
228         NVPtr pNv = NVPTR(pScrn);
229         Bool vpllb_disabled = FALSE;
230         uint32_t vplla = state->crtc_reg[crtc].vpll_a;
231         uint32_t vpllb = state->crtc_reg[crtc].vpll_b;
232         uint8_t m1, m2, n1, n2, p;
233
234         if (!pNv->twoStagePLL)
235                 vpllb_disabled = TRUE;
236
237         /* This is the dummy value nvidia sets when vpll is disabled */
238         if ((vpllb & 0xFFFF) == 0x11F)
239                 vpllb_disabled = TRUE;
240
241         if (!(vpllb & NV31_RAMDAC_ENABLE_VCO2) && pNv->NVArch != 0x30)
242                 vpllb_disabled = TRUE;
243
244         if (!(vplla & NV30_RAMDAC_ENABLE_VCO2) && pNv->NVArch == 0x30)
245                 vpllb_disabled = TRUE;
246
247         if (pNv->NVArch == 0x30) {
248                 m1 = vplla & 0x7;
249                 n1 = (vplla >> 8) & 0xFF;
250                 p = (vplla >> 16) & 0x7;
251         } else {
252                 m1 = vplla & 0xFF;
253                 n1 = (vplla >> 8) & 0xFF;
254                 p = (vplla >> 16) & 0x7;
255         }
256
257         if (vpllb_disabled) {
258                 m2 = 1;
259                 n2 = 1;
260         } else {
261                 if (pNv->NVArch == 0x30) {
262                         m2 = (vplla >> 4) & 0x7;
263                         n2 = ((vplla >> 19) & 0x7) | (((vplla >> 24) & 0x3) << 3);
264                 } else {
265                         m2 = vpllb & 0xFF;
266                         n2 = (vpllb >> 8) & 0xFF;
267                 }
268         }
269
270         /* avoid div by 0, if used on pNv->ModeReg before ModeReg set up */
271         if (!m1 || !m2)
272                 return 0;
273
274         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "The clock seems to be %d kHz.\n", (uint32_t)((pNv->CrystalFreqKHz * n1 * n2)/(m1 * m2)) >> p);
275         return ((pNv->CrystalFreqKHz * n1 * n2)/(m1 * m2)) >> p;
276 }
277
278 static void nv_output_restore(xf86OutputPtr output)
279 {
280         ScrnInfoPtr pScrn = output->scrn;
281         NVPtr pNv = NVPTR(pScrn);
282         RIVA_HW_STATE *state = &pNv->SavedReg;
283         NVOutputPrivatePtr nv_output = output->driver_private;
284
285         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_output_restore is called.\n");
286
287         if (nv_output->type == OUTPUT_TMDS || nv_output->type == OUTPUT_LVDS) {
288                 uint32_t clock = nv_get_clock_from_crtc(pScrn, state, nv_output->restore.head);
289
290                 if (nv_output->type == OUTPUT_TMDS)
291                         run_tmds_table(pScrn, nv_output->dcb_entry, nv_output->restore.head, clock);
292                 else {
293                         /* on panels where we do reset after pclk change, PANEL_ON will also RESET */
294                         if (!pNv->VBIOS.fp.reset_after_pclk_change)
295                                 call_lvds_script(pScrn, nv_output->restore.head, nv_output->dcb_entry, LVDS_RESET, clock);
296                         call_lvds_script(pScrn, nv_output->restore.head, nv_output->dcb_entry, LVDS_PANEL_ON, clock);
297                 }
298         }
299
300         if (pNv->twoHeads)
301                 NVWriteRAMDAC(pNv, 0, NV_RAMDAC_OUTPUT + nv_output_ramdac_offset(output), nv_output->restore.output);
302
303         nv_output->last_dpms = NV_DPMS_CLEARED;
304 }
305
306 static int
307 nv_output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
308 {
309         if (pMode->Flags & V_DBLSCAN)
310                 return MODE_NO_DBLESCAN;
311
312         if (pMode->Clock > 400000 || pMode->Clock < 25000)
313                 return MODE_CLOCK_RANGE;
314
315         return MODE_OK;
316 }
317
318
319 static Bool
320 nv_output_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
321                      DisplayModePtr adjusted_mode)
322 {
323         NVOutputPrivatePtr nv_output = output->driver_private;
324         ScrnInfoPtr pScrn = output->scrn;
325
326         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_output_mode_fixup is called.\n");
327
328         /* For internal panels and gpu scaling on DVI we need the native mode */
329         if ((nv_output->type == OUTPUT_LVDS || (nv_output->type == OUTPUT_TMDS && nv_output->scaling_mode != SCALE_PANEL))) {
330                 adjusted_mode->HDisplay = nv_output->native_mode->HDisplay;
331                 adjusted_mode->HSkew = nv_output->native_mode->HSkew;
332                 adjusted_mode->HSyncStart = nv_output->native_mode->HSyncStart;
333                 adjusted_mode->HSyncEnd = nv_output->native_mode->HSyncEnd;
334                 adjusted_mode->HTotal = nv_output->native_mode->HTotal;
335                 adjusted_mode->VDisplay = nv_output->native_mode->VDisplay;
336                 adjusted_mode->VScan = nv_output->native_mode->VScan;
337                 adjusted_mode->VSyncStart = nv_output->native_mode->VSyncStart;
338                 adjusted_mode->VSyncEnd = nv_output->native_mode->VSyncEnd;
339                 adjusted_mode->VTotal = nv_output->native_mode->VTotal;
340                 adjusted_mode->Clock = nv_output->native_mode->Clock;
341                 adjusted_mode->Flags = nv_output->native_mode->Flags;
342
343                 xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V);
344         }
345
346         return TRUE;
347 }
348
349 static void
350 nv_output_mode_set(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
351 {
352         NVOutputPrivatePtr nv_output = output->driver_private;
353         ScrnInfoPtr pScrn = output->scrn;
354         NVPtr pNv = NVPTR(pScrn);
355         NVCrtcPrivatePtr nv_crtc = output->crtc->driver_private;
356
357         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_output_mode_set is called.\n");
358
359         if (nv_output->type == OUTPUT_TMDS)
360                 run_tmds_table(pScrn, nv_output->dcb_entry, nv_crtc->head, adjusted_mode->Clock);
361         /* on panels where we do reset after pclk change, DPMS on will do this */
362         else if (nv_output->type == OUTPUT_LVDS && !pNv->VBIOS.fp.reset_after_pclk_change)
363                 call_lvds_script(pScrn, nv_crtc->head, nv_output->dcb_entry, LVDS_RESET, adjusted_mode->Clock);
364
365         if (pNv->twoHeads) {
366                 NVOutputPrivatePtr nv_output = output->driver_private;
367                 uint32_t outputval = 0;
368
369                 if (nv_output->type == OUTPUT_ANALOG)
370                         /* bit 16-19 are bits that are set on some G70 cards,
371                          * but don't seem to have much effect */
372                         outputval = nv_crtc->head << 8 | NV_RAMDAC_OUTPUT_DAC_ENABLE;
373
374                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV_RAMDAC_OUTPUT: 0x%X\n", outputval);
375
376                 NVWriteRAMDAC(pNv, 0, NV_RAMDAC_OUTPUT + nv_output_ramdac_offset(output), outputval);
377         }
378
379         /* This could use refinement for flatpanels, but it should work this way */
380         if (pNv->NVArch < 0x44)
381                 NVWriteRAMDAC(pNv, 0, NV_RAMDAC_TEST_CONTROL + nv_output_ramdac_offset(output), 0xf0000000);
382         else
383                 NVWriteRAMDAC(pNv, 0, NV_RAMDAC_TEST_CONTROL + nv_output_ramdac_offset(output), 0x00100000);
384 }
385
386 static xf86MonPtr
387 nv_get_edid(xf86OutputPtr output)
388 {
389         NVOutputPrivatePtr nv_output = output->driver_private;
390         xf86MonPtr ddc_mon;
391
392         if (nv_output->pDDCBus == NULL)
393                 return NULL;
394
395         ddc_mon = xf86OutputGetEDID(output, nv_output->pDDCBus);
396         if (!ddc_mon)
397                 return NULL;
398
399         if (ddc_mon->features.input_type && (nv_output->type == OUTPUT_ANALOG))
400                 goto invalid;
401
402         if ((!ddc_mon->features.input_type) && (nv_output->type == OUTPUT_TMDS ||
403                                 nv_output->type == OUTPUT_LVDS))
404                 goto invalid;
405
406         return ddc_mon;
407
408 invalid:
409         xfree(ddc_mon);
410         return NULL;
411 }
412
413 static Bool
414 nv_ddc_detect(xf86OutputPtr output)
415 {
416         xf86MonPtr m = nv_get_edid(output);
417
418         if (m == NULL)
419                 return FALSE;
420
421         xfree(m);
422         return TRUE;
423 }
424
425 static Bool
426 nv_load_detect(xf86OutputPtr output)
427 {
428         ScrnInfoPtr pScrn = output->scrn;
429         NVOutputPrivatePtr nv_output = output->driver_private;
430         NVPtr pNv = NVPTR(pScrn);
431         uint32_t testval, regoffset = nv_output_ramdac_offset(output);
432         uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput, saved_rtest_ctrl, temp;
433         int present = 0;
434
435 #define RGB_TEST_DATA(r,g,b) (r << 0 | g << 10 | b << 20)
436         testval = RGB_TEST_DATA(0x140, 0x140, 0x140); /* 0x94050140 */
437         if (pNv->VBIOS.dactestval)
438                 testval = pNv->VBIOS.dactestval;
439
440         saved_rtest_ctrl = NVReadRAMDAC(pNv, 0, NV_RAMDAC_TEST_CONTROL + regoffset);
441         NVWriteRAMDAC(pNv, 0, NV_RAMDAC_TEST_CONTROL + regoffset, saved_rtest_ctrl & ~0x00010000);
442
443         if (pNv->NVArch >= 0x17) {
444                 saved_powerctrl_2 = nvReadMC(pNv, NV_PBUS_POWERCTRL_2);
445
446                 nvWriteMC(pNv, NV_PBUS_POWERCTRL_2, saved_powerctrl_2 & 0xd7ffffff);
447                 if (regoffset == 0x68) {
448                         saved_powerctrl_4 = nvReadMC(pNv, NV_PBUS_POWERCTRL_4);
449                         nvWriteMC(pNv, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf);
450                 }
451         }
452
453         usleep(4000);
454
455         saved_routput = NVReadRAMDAC(pNv, 0, NV_RAMDAC_OUTPUT + regoffset);
456         /* nv driver and nv31 use 0xfffffeee
457          * nv34 and 6600 use 0xfffffece */
458         NVWriteRAMDAC(pNv, 0, NV_RAMDAC_OUTPUT + regoffset, saved_routput & 0xfffffece);
459         usleep(1000);
460
461         temp = NVReadRAMDAC(pNv, 0, NV_RAMDAC_OUTPUT + regoffset);
462         NVWriteRAMDAC(pNv, 0, NV_RAMDAC_OUTPUT + regoffset, temp | 1);
463
464         /* no regoffset on purpose */
465         NVWriteRAMDAC(pNv, 0, NV_RAMDAC_TEST_DATA, 1 << 31 | testval);
466         temp = NVReadRAMDAC(pNv, 0, NV_RAMDAC_TEST_CONTROL);
467         NVWriteRAMDAC(pNv, 0, NV_RAMDAC_TEST_CONTROL, temp | 0x1000);
468         usleep(1000);
469
470         present = NVReadRAMDAC(pNv, 0, NV_RAMDAC_TEST_CONTROL + regoffset) & (1 << 28);
471
472         /* no regoffset on purpose */
473         temp = NVReadRAMDAC(pNv, 0, NV_RAMDAC_TEST_CONTROL);
474         NVWriteRAMDAC(pNv, 0, NV_RAMDAC_TEST_CONTROL, temp & 0xffffefff);
475         NVWriteRAMDAC(pNv, 0, NV_RAMDAC_TEST_DATA, 0);
476
477         /* bios does something more complex for restoring, but I think this is good enough */
478         NVWriteRAMDAC(pNv, 0, NV_RAMDAC_OUTPUT + regoffset, saved_routput);
479         NVWriteRAMDAC(pNv, 0, NV_RAMDAC_TEST_CONTROL + regoffset, saved_rtest_ctrl);
480         if (pNv->NVArch >= 0x17) {
481                 if (regoffset == 0x68)
482                         nvWriteMC(pNv, NV_PBUS_POWERCTRL_4, saved_powerctrl_4);
483                 nvWriteMC(pNv, NV_PBUS_POWERCTRL_2, saved_powerctrl_2);
484         }
485
486         if (present) {
487                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Load detected on output %c\n", '@' + ffs(nv_output->or));
488                 return TRUE;
489         }
490
491         return FALSE;
492 }
493
494 static xf86OutputStatus
495 nv_tmds_output_detect(xf86OutputPtr output)
496 {
497         ScrnInfoPtr pScrn = output->scrn;
498
499         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_tmds_output_detect is called.\n");
500
501         if (nv_ddc_detect(output))
502                 return XF86OutputStatusConnected;
503
504         return XF86OutputStatusDisconnected;
505 }
506
507
508 static xf86OutputStatus
509 nv_analog_output_detect(xf86OutputPtr output)
510 {
511         ScrnInfoPtr pScrn = output->scrn;
512         NVPtr pNv = NVPTR(pScrn);
513
514         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_analog_output_detect is called.\n");
515
516         if (nv_ddc_detect(output))
517                 return XF86OutputStatusConnected;
518
519         /* we don't have a load det function for early cards */
520         if (!pNv->twoHeads || pNv->NVArch == 0x11)
521                 return XF86OutputStatusUnknown;
522         else if (pNv->twoHeads && nv_load_detect(output))
523                 return XF86OutputStatusConnected;
524
525         return XF86OutputStatusDisconnected;
526 }
527
528 static DisplayModePtr
529 nv_output_get_modes(xf86OutputPtr output, xf86MonPtr mon)
530 {
531         ScrnInfoPtr pScrn = output->scrn;
532         NVOutputPrivatePtr nv_output = output->driver_private;
533         DisplayModePtr ddc_modes;
534
535         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_output_get_modes is called.\n");
536
537         xf86OutputSetEDID(output, mon);
538
539         ddc_modes = xf86OutputGetEDIDModes(output);
540
541         if (nv_output->type == OUTPUT_TMDS || nv_output->type == OUTPUT_LVDS) {
542                 int i;
543                 DisplayModePtr mode;
544
545                 for (i = 0; i < DET_TIMINGS; i++) {
546                         /* We only look at detailed timings atm */
547                         if (mon->det_mon[i].type != DT)
548                                 continue;
549                         /* Selecting only based on width ok? */
550                         if (mon->det_mon[i].section.d_timings.h_active > nv_output->fpWidth) {
551                                 nv_output->fpWidth = mon->det_mon[i].section.d_timings.h_active;
552                                 nv_output->fpHeight = mon->det_mon[i].section.d_timings.v_active;
553                         }
554                 }
555                 if (!(nv_output->fpWidth && nv_output->fpHeight)) {
556                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No EDID detailed timings available, bailing out.\n");
557                         return NULL;
558                 }
559
560                 if (nv_output->native_mode)
561                         xfree(nv_output->native_mode);
562
563                 /* Prefer ddc modes. */
564                 for (mode = ddc_modes; mode != NULL; mode = mode->next) {
565                         if (mode->HDisplay == nv_output->fpWidth &&
566                                 mode->VDisplay == nv_output->fpHeight) {
567                                 /* Take the preferred mode when it exists. */
568                                 if (mode->type & M_T_PREFERRED) {
569                                         nv_output->native_mode = xf86DuplicateMode(mode);
570                                         break;
571                                 }
572                                 /* Find the highest refresh mode otherwise. */
573                                 if (!nv_output->native_mode || (mode->VRefresh > nv_output->native_mode->VRefresh)) {
574                                         mode->type |= M_T_PREFERRED;
575                                         nv_output->native_mode = xf86DuplicateMode(mode);
576                                 }
577                         }
578                 }
579         }
580
581         if (nv_output->type == OUTPUT_LVDS)
582                 setup_edid_dual_link_lvds(pScrn, nv_output->native_mode->Clock);
583
584         return ddc_modes;
585 }
586
587 static DisplayModePtr
588 nv_output_get_ddc_modes(xf86OutputPtr output)
589 {
590         xf86MonPtr ddc_mon;
591         ScrnInfoPtr pScrn = output->scrn;
592
593         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_output_get_ddc_modes is called.\n");
594
595         ddc_mon = nv_get_edid(output);
596
597         if (ddc_mon == NULL)
598                 return NULL;
599
600         return nv_output_get_modes(output, ddc_mon);
601 }
602
603 static void
604 nv_output_destroy (xf86OutputPtr output)
605 {
606         NVOutputPrivatePtr nv_output = output->driver_private;
607         ScrnInfoPtr pScrn = output->scrn;
608
609         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_output_destroy is called.\n");
610
611         if (nv_output) {
612                 if (nv_output->native_mode)
613                         xfree(nv_output->native_mode);
614                 xfree(output->driver_private);
615         }
616 }
617
618 static void nv_output_prepare_sel_clk(xf86OutputPtr output)
619 {
620         NVOutputPrivatePtr nv_output = output->driver_private;
621         NVPtr pNv = NVPTR(output->scrn);
622         NVRegPtr state = &pNv->ModeReg;
623
624         /* SEL_CLK is only used on the primary ramdac
625          * It toggles spread spectrum PLL output and sets the bindings of PLLs
626          * to heads on digital outputs
627          */
628         if (nv_output->type == OUTPUT_TMDS || nv_output->type == OUTPUT_LVDS) {
629                 NVCrtcPrivatePtr nv_crtc = output->crtc->driver_private;
630                 bool crossed_clocks = nv_crtc->head ^ (nv_output->or & OUTPUT_C) >> 2;
631                 int i;
632
633                 state->sel_clk &= ~(0x5 << 16);
634                 /* Even with two dvi, this should not conflict. */
635                 if (crossed_clocks)
636                         state->sel_clk |= (0x1 << 16);
637                 else
638                         state->sel_clk |= (0x4 << 16);
639
640                 /* nv30:
641                  *      bit 0           NVClk spread spectrum on/off
642                  *      bit 2           MemClk spread spectrum on/off
643                  *      bit 4           PixClk1 spread spectrum on/off
644                  *      bit 6           PixClk2 spread spectrum on/off
645                  *
646                  * nv40 (observations from bios behaviour and mmio traces):
647                  *      bit 4           seems to get set when output is on head A - likely related to PixClk1
648                  *      bit 6           seems to get set when output is on head B - likely related to PixClk2
649                  *      bits 5&7        set as for bits 4&6, but do not appear on cards using 4&6
650                  *
651                  *      bits 8&10       seen on dual dvi outputs; possibly means "bits 4&6, dual dvi"
652                  *
653                  *      Note that the circumstances for setting the bits at all is unclear
654                  */
655                 for (i = 1; i <= 2; i++) {
656                         uint32_t var = (state->sel_clk >> 4*i) & 0xf;
657                         int shift = 0; /* assume (var & 0x5) by default */
658
659                         if (!var)
660                                 continue;
661                         if (var & 0xa)
662                                 shift = 1;
663
664                         state->sel_clk &= ~(0xf << 4*i);
665                         if (crossed_clocks)
666                                 state->sel_clk |= (0x4 << (4*i + shift));
667                         else
668                                 state->sel_clk |= (0x1 << (4*i + shift));
669                 }
670         }
671 }
672
673 static void
674 nv_output_prepare(xf86OutputPtr output)
675 {
676         ScrnInfoPtr pScrn = output->scrn;
677
678         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_output_prepare is called.\n");
679
680         output->funcs->dpms(output, DPMSModeOff);
681
682         /* calculate sel_clk now, and write it in nv_crtc_set_mode before calculating PLLs */
683         nv_output_prepare_sel_clk(output);
684 }
685
686 static void
687 nv_output_commit(xf86OutputPtr output)
688 {
689         ScrnInfoPtr pScrn = output->scrn;
690         xf86CrtcPtr crtc = output->crtc;
691
692         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_output_commit is called.\n");
693
694         if (crtc) {
695                 NVOutputPrivatePtr nv_output = output->driver_private;
696                 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
697                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Output %s is running on CRTC %d using output %c\n", output->name, nv_crtc->head, '@' + ffs(nv_output->or));
698         }
699
700         output->funcs->dpms(output, DPMSModeOn);
701 }
702
703 static const xf86OutputFuncsRec nv_analog_output_funcs = {
704     .dpms = nv_analog_output_dpms,
705     .save = nv_output_save,
706     .restore = nv_output_restore,
707     .mode_valid = nv_output_mode_valid,
708     .mode_fixup = nv_output_mode_fixup,
709     .mode_set = nv_output_mode_set,
710     .detect = nv_analog_output_detect,
711     .get_modes = nv_output_get_ddc_modes,
712     .destroy = nv_output_destroy,
713     .prepare = nv_output_prepare,
714     .commit = nv_output_commit,
715 };
716
717 /*
718  * Several scaling modes exist, let the user choose.
719  */
720 #define SCALING_MODE_NAME "SCALING_MODE"
721 static const struct {
722         char *name;
723         enum scaling_modes mode;
724 } scaling_mode[] = {
725         { "panel", SCALE_PANEL },
726         { "fullscreen", SCALE_FULLSCREEN },
727         { "aspect", SCALE_ASPECT },
728         { "noscale", SCALE_NOSCALE },
729         { NULL, SCALE_INVALID}
730 };
731 static Atom scaling_mode_atom;
732
733 #define DITHERING_MODE_NAME "DITHERING"
734 static Atom dithering_atom;
735 int32_t dithering_range[2];
736
737 static int
738 nv_scaling_mode_lookup(char *name, int size)
739 {
740         int i;
741
742         /* for when name is zero terminated */
743         if (size < 0)
744                 size = strlen(name);
745
746         for (i = 0; scaling_mode[i].name; i++)
747                 /* We're getting non-terminated strings */
748                 if (strlen(scaling_mode[i].name) >= size &&
749                                 !strncasecmp(name, scaling_mode[i].name, size))
750                         break;
751
752         return scaling_mode[i].mode;
753 }
754
755 void
756 nv_digital_output_create_resources(xf86OutputPtr output)
757 {
758         NVOutputPrivatePtr nv_output = output->driver_private;
759         ScrnInfoPtr pScrn = output->scrn;
760         int error, i;
761
762         /*
763          * Setup scaling mode property.
764          */
765         scaling_mode_atom = MakeAtom(SCALING_MODE_NAME, sizeof(SCALING_MODE_NAME) - 1, TRUE);
766
767         error = RRConfigureOutputProperty(output->randr_output,
768                                         scaling_mode_atom, TRUE, FALSE, FALSE,
769                                         0, NULL);
770
771         if (error != 0) {
772                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
773                         "RRConfigureOutputProperty error, %d\n", error);
774         }
775
776         char *existing_scale_name = NULL;
777         for (i = 0; scaling_mode[i].name; i++)
778                 if (scaling_mode[i].mode == nv_output->scaling_mode)
779                         existing_scale_name = scaling_mode[i].name;
780
781         error = RRChangeOutputProperty(output->randr_output, scaling_mode_atom,
782                                         XA_STRING, 8, PropModeReplace, 
783                                         strlen(existing_scale_name),
784                                         existing_scale_name, FALSE, TRUE);
785
786         if (error != 0) {
787                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
788                         "Failed to set scaling mode, %d\n", error);
789         }
790
791         /*
792          * Setup dithering property.
793          */
794         dithering_atom = MakeAtom(DITHERING_MODE_NAME, sizeof(DITHERING_MODE_NAME) - 1, TRUE);
795
796         dithering_range[0] = 0;
797         dithering_range[1] = 1;
798
799         error = RRConfigureOutputProperty(output->randr_output,
800                                         dithering_atom, TRUE, TRUE, FALSE,
801                                         2, dithering_range);
802
803         if (error != 0) {
804                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
805                         "RRConfigureOutputProperty error, %d\n", error);
806         }
807
808         error = RRChangeOutputProperty(output->randr_output, dithering_atom,
809                                         XA_INTEGER, 32, PropModeReplace, 1, &nv_output->dithering,
810                                         FALSE, FALSE);
811
812         if (error != 0) {
813                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
814                         "Failed to set dithering mode, %d\n", error);
815         }
816 }
817
818 Bool
819 nv_digital_output_set_property(xf86OutputPtr output, Atom property,
820                                 RRPropertyValuePtr value)
821 {
822         NVOutputPrivatePtr nv_output = output->driver_private;
823
824         if (property == scaling_mode_atom) {
825                 int32_t ret;
826                 char *name = NULL;
827
828                 if (value->type != XA_STRING || value->format != 8)
829                         return FALSE;
830
831                 name = (char *) value->data;
832
833                 /* Match a string to a scaling mode */
834                 ret = nv_scaling_mode_lookup(name, value->size);
835                 if (ret == SCALE_INVALID)
836                         return FALSE;
837
838                 /* LVDS must always use gpu scaling. */
839                 if (ret == SCALE_PANEL && nv_output->type == OUTPUT_LVDS)
840                         return FALSE;
841
842                 nv_output->scaling_mode = ret;
843                 return TRUE;
844         } else if (property == dithering_atom) {
845                 if (value->type != XA_INTEGER || value->format != 32)
846                         return FALSE;
847
848                 int32_t val = *(int32_t *) value->data;
849
850                 if (val < dithering_range[0] || val > dithering_range[1])
851                         return FALSE;
852
853                 nv_output->dithering = val;
854                 return TRUE;
855         }
856
857         return TRUE;
858 }
859
860 static int 
861 nv_tmds_output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
862 {
863         ScrnInfoPtr pScrn = output->scrn;
864         NVPtr pNv = NVPTR(pScrn);
865         NVOutputPrivatePtr nv_output = output->driver_private;
866
867         /* We can't exceed the native mode.*/
868         if (pMode->HDisplay > nv_output->fpWidth || pMode->VDisplay > nv_output->fpHeight)
869                 return MODE_PANEL;
870
871         if (pNv->dcb_table.entry[nv_output->dcb_entry].duallink_possible) {
872                 if (pMode->Clock > 330000) /* 2x165 MHz */
873                         return MODE_CLOCK_RANGE;
874         } else {
875                 if (pMode->Clock > 165000) /* 165 MHz */
876                         return MODE_CLOCK_RANGE;
877         }
878
879         return nv_output_mode_valid(output, pMode);
880 }
881
882 static const xf86OutputFuncsRec nv_tmds_output_funcs = {
883         .dpms = nv_tmds_output_dpms,
884         .save = nv_output_save,
885         .restore = nv_output_restore,
886         .mode_valid = nv_tmds_output_mode_valid,
887         .mode_fixup = nv_output_mode_fixup,
888         .mode_set = nv_output_mode_set,
889         .detect = nv_tmds_output_detect,
890         .get_modes = nv_output_get_ddc_modes,
891         .destroy = nv_output_destroy,
892         .prepare = nv_output_prepare,
893         .commit = nv_output_commit,
894         .create_resources = nv_digital_output_create_resources,
895         .set_property = nv_digital_output_set_property,
896 };
897
898 static int nv_lvds_output_mode_valid
899 (xf86OutputPtr output, DisplayModePtr pMode)
900 {
901         NVOutputPrivatePtr nv_output = output->driver_private;
902
903         /* No modes > panel's native res */
904         if (pMode->HDisplay > nv_output->fpWidth || pMode->VDisplay > nv_output->fpHeight)
905                 return MODE_PANEL;
906
907         return nv_output_mode_valid(output, pMode);
908 }
909
910 static xf86OutputStatus
911 nv_lvds_output_detect(xf86OutputPtr output)
912 {
913         ScrnInfoPtr pScrn = output->scrn;
914         NVPtr pNv = NVPTR(pScrn);
915         NVOutputPrivatePtr nv_output = output->driver_private;
916
917         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_lvds_output_detect is called.\n");
918
919         if (nv_ddc_detect(output))
920                 return XF86OutputStatusConnected;
921         if (pNv->dcb_table.entry[nv_output->dcb_entry].lvdsconf.use_straps_for_mode &&
922             pNv->VBIOS.fp.native_mode)
923                 return XF86OutputStatusConnected;
924         if (pNv->VBIOS.fp.edid)
925                 return XF86OutputStatusConnected;
926
927         return XF86OutputStatusDisconnected;
928 }
929
930 static DisplayModePtr
931 nv_lvds_output_get_modes(xf86OutputPtr output)
932 {
933         ScrnInfoPtr pScrn = output->scrn;
934         NVPtr pNv = NVPTR(pScrn);
935         NVOutputPrivatePtr nv_output = output->driver_private;
936         DisplayModePtr modes;
937
938         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_lvds_output_get_modes is called.\n");
939
940         if ((modes = nv_output_get_ddc_modes(output)))
941                 return modes;
942
943         if (!pNv->dcb_table.entry[nv_output->dcb_entry].lvdsconf.use_straps_for_mode ||
944             (pNv->VBIOS.fp.native_mode == NULL)) {
945                 xf86MonPtr edid_mon;
946
947                 if (!pNv->VBIOS.fp.edid)
948                         return NULL;
949
950                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using hardcoded BIOS FP EDID\n");
951                 edid_mon = xf86InterpretEDID(pScrn->scrnIndex, pNv->VBIOS.fp.edid);
952                 return nv_output_get_modes(output, edid_mon);
953         }
954
955         nv_output->fpWidth = pNv->VBIOS.fp.native_mode->HDisplay;
956         nv_output->fpHeight = pNv->VBIOS.fp.native_mode->VDisplay;
957
958         xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel size is %u x %u\n",
959                 nv_output->fpWidth, nv_output->fpHeight);
960
961         nv_output->native_mode = xf86DuplicateMode(pNv->VBIOS.fp.native_mode);
962
963         return xf86DuplicateMode(pNv->VBIOS.fp.native_mode);
964 }
965
966 static const xf86OutputFuncsRec nv_lvds_output_funcs = {
967         .dpms = nv_lvds_output_dpms,
968         .save = nv_output_save,
969         .restore = nv_output_restore,
970         .mode_valid = nv_lvds_output_mode_valid,
971         .mode_fixup = nv_output_mode_fixup,
972         .mode_set = nv_output_mode_set,
973         .detect = nv_lvds_output_detect,
974         .get_modes = nv_lvds_output_get_modes,
975         .destroy = nv_output_destroy,
976         .prepare = nv_output_prepare,
977         .commit = nv_output_commit,
978         .create_resources = nv_digital_output_create_resources,
979         .set_property = nv_digital_output_set_property,
980 };
981
982 static void nv_add_output(ScrnInfoPtr pScrn, int dcb_entry, const xf86OutputFuncsRec *output_funcs, char *outputname)
983 {
984         NVPtr pNv = NVPTR(pScrn);
985         xf86OutputPtr output;
986         NVOutputPrivatePtr nv_output;
987
988         int i2c_index = pNv->dcb_table.entry[dcb_entry].i2c_index;
989         if (pNv->dcb_table.i2c_read[i2c_index] && pNv->pI2CBus[i2c_index] == NULL)
990                 NV_I2CInit(pScrn, &pNv->pI2CBus[i2c_index], pNv->dcb_table.i2c_read[i2c_index], xstrdup(outputname));
991
992         if (!(output = xf86OutputCreate(pScrn, output_funcs, outputname)))
993                 return;
994
995         if (!(nv_output = xnfcalloc(sizeof(NVOutputPrivateRec), 1)))
996                 return;
997
998         output->driver_private = nv_output;
999
1000         /* needed for NV5x, used by pre-NV5x as well. */
1001         nv_output->output_resource = ffs(pNv->dcb_table.entry[dcb_entry].or);
1002
1003         nv_output->pDDCBus = pNv->pI2CBus[i2c_index];
1004         nv_output->dcb_entry = dcb_entry;
1005         nv_output->type = pNv->dcb_table.entry[dcb_entry].type;
1006         nv_output->last_dpms = NV_DPMS_CLEARED;
1007
1008         /* or:
1009          * First set bit (LSB->MSB) defines output:
1010          * bit0: OUTPUT_A
1011          * bit1: OUTPUT_B
1012          * bit2: OUTPUT_C
1013          *
1014          * If bit following first set bit is also set, output is capable of dual-link
1015          */
1016         nv_output->or = pNv->dcb_table.entry[dcb_entry].or;
1017
1018         /* Output property for tmds and lvds. */
1019         nv_output->dithering = (pNv->FPDither || (nv_output->type == OUTPUT_LVDS && !pNv->VBIOS.fp.if_is_24bit));
1020
1021         if (nv_output->type == OUTPUT_LVDS || nv_output->type == OUTPUT_TMDS) {
1022                 if (pNv->fpScaler) /* GPU Scaling */
1023                         nv_output->scaling_mode = SCALE_ASPECT;
1024                 else if (nv_output->type == OUTPUT_LVDS)
1025                         nv_output->scaling_mode = SCALE_NOSCALE;
1026                 else
1027                         nv_output->scaling_mode = SCALE_PANEL;
1028
1029                 if (xf86GetOptValString(pNv->Options, OPTION_SCALING_MODE)) {
1030                         nv_output->scaling_mode = nv_scaling_mode_lookup(xf86GetOptValString(pNv->Options, OPTION_SCALING_MODE), -1);
1031                         if (nv_output->scaling_mode == SCALE_INVALID)
1032                                 nv_output->scaling_mode = SCALE_ASPECT; /* default */
1033                 }
1034         }
1035
1036         output->possible_crtcs = pNv->dcb_table.entry[dcb_entry].heads;
1037         output->interlaceAllowed = TRUE;
1038         output->doubleScanAllowed = TRUE;
1039
1040         if (pNv->Architecture == NV_ARCH_50) {
1041                 if (nv_output->type == OUTPUT_TMDS) {
1042                         NVWrite(pNv, 0x0061c00c + nv_output->output_resource * 0x800, 0x03010700);
1043                         NVWrite(pNv, 0x0061c010 + nv_output->output_resource * 0x800, 0x0000152f);
1044                         NVWrite(pNv, 0x0061c014 + nv_output->output_resource * 0x800, 0x00000000);
1045                         NVWrite(pNv, 0x0061c018 + nv_output->output_resource * 0x800, 0x00245af8);
1046                 }
1047
1048                 /* This needs to be handled in the same way as pre-NV5x on the long run. */
1049                 if (nv_output->type == OUTPUT_LVDS)
1050                         nv_output->native_mode = GetLVDSNativeMode(pScrn);
1051         }
1052
1053         xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Added output %s\n", outputname);
1054 }
1055
1056 static const xf86OutputFuncsRec * nv_get_output_funcs(ScrnInfoPtr pScrn, int type)
1057 {
1058         NVPtr pNv = NVPTR(pScrn);
1059
1060         if (pNv->Architecture == NV_ARCH_50) {
1061                 switch (type) {
1062                         case OUTPUT_ANALOG:
1063                                 return nv50_get_analog_output_funcs();
1064                                 break;
1065                         case OUTPUT_TMDS:
1066                                 return nv50_get_tmds_output_funcs();
1067                                 break;
1068                         case OUTPUT_LVDS:
1069                                 return nv50_get_lvds_output_funcs();
1070                                 break;
1071                         default:
1072                                 return NULL;
1073                                 break;
1074                 }
1075         } else {
1076                 switch (type) {
1077                         case OUTPUT_ANALOG:
1078                                 return &nv_analog_output_funcs;
1079                                 break;
1080                         case OUTPUT_TMDS:
1081                                 return &nv_tmds_output_funcs;
1082                                 break;
1083                         case OUTPUT_LVDS:
1084                                 return &nv_lvds_output_funcs;
1085                                 break;
1086                         default:
1087                                 return NULL;
1088                                 break;
1089                 }
1090         }
1091 }
1092
1093 void NvSetupOutputs(ScrnInfoPtr pScrn)
1094 {
1095         NVPtr pNv = NVPTR(pScrn);
1096         int i, type, i2c_count[0xf];
1097         char outputname[20];
1098         int vga_count = 0, tv_count = 0, dvia_count = 0, dvid_count = 0, lvds_count = 0;
1099         xf86OutputFuncsRec * funcs = NULL;
1100
1101         memset(pNv->pI2CBus, 0, sizeof(pNv->pI2CBus));
1102         memset(i2c_count, 0, sizeof(i2c_count));
1103         for (i = 0 ; i < pNv->dcb_table.entries; i++)
1104                 i2c_count[pNv->dcb_table.entry[i].i2c_index]++;
1105
1106         /* we setup the outputs up from the BIOS table */
1107         for (i = 0 ; i < pNv->dcb_table.entries; i++) {
1108                 type = pNv->dcb_table.entry[i].type;
1109
1110                 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DCB entry %d: type: %d, i2c_index: %d, heads: %d, bus: %d, or: %d\n", i, type, pNv->dcb_table.entry[i].i2c_index, pNv->dcb_table.entry[i].heads, pNv->dcb_table.entry[i].bus, pNv->dcb_table.entry[i].or);
1111
1112                 switch (type) {
1113                 case OUTPUT_ANALOG:
1114                         if (i2c_count[pNv->dcb_table.entry[i].i2c_index] == 1)
1115                                 sprintf(outputname, "VGA-%d", vga_count++);
1116                         else
1117                                 sprintf(outputname, "DVI-A-%d", dvia_count++);
1118                         break;
1119                 case OUTPUT_TMDS:
1120                         sprintf(outputname, "DVI-D-%d", dvid_count++);
1121                         break;
1122                 case OUTPUT_TV:
1123                         sprintf(outputname, "TV-%d", tv_count++);
1124                         break;
1125                 case OUTPUT_LVDS:
1126                         sprintf(outputname, "LVDS-%d", lvds_count++);
1127                         break;
1128                 default:
1129                         xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DCB type %d not known\n", type);
1130                         break;
1131                 }
1132
1133                 funcs = (xf86OutputFuncsRec *) nv_get_output_funcs(pScrn, type);
1134                 if (funcs)
1135                         nv_add_output(pScrn, i, funcs, outputname);
1136         }
1137 }
1138
1139 /*************************************************************************** \
1140 |*                                                                           *|
1141 |*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
1142 |*                                                                           *|
1143 |*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
1144 |*     international laws.  Users and possessors of this source code are     *|
1145 |*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
1146 |*     use this code in individual and commercial software.                  *|
1147 |*                                                                           *|
1148 |*     Any use of this source code must include,  in the user documenta-     *|
1149 |*     tion and  internal comments to the code,  notices to the end user     *|
1150 |*     as follows:                                                           *|
1151 |*                                                                           *|
1152 |*       Copyright 1993-1999 NVIDIA, Corporation.  All rights reserved.      *|
1153 |*                                                                           *|
1154 |*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
1155 |*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
1156 |*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
1157 |*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
1158 |*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
1159 |*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
1160 |*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
1161 |*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
1162 |*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
1163 |*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
1164 |*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
1165 |*                                                                           *|
1166 |*     U.S. Government  End  Users.   This source code  is a "commercial     *|
1167 |*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
1168 |*     consisting  of "commercial  computer  software"  and  "commercial     *|
1169 |*     computer  software  documentation,"  as such  terms  are  used in     *|
1170 |*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
1171 |*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
1172 |*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
1173 |*     all U.S. Government End Users  acquire the source code  with only     *|
1174 |*     those rights set forth herein.                                        *|
1175 |*                                                                           *|
1176  \***************************************************************************/