randr12: fix BIT bios LVDS dpms
[nouveau] / src / nv_output.c
1 /*
2  * Copyright 2006 Dave Airlie
3  * Copyright 2007 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 "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:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 /*
25  * this code uses ideas taken from the NVIDIA nv driver - the nvidia license
26  * decleration is at the bottom of this file as it is rather ugly 
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include "xf86.h"
34 #include "os.h"
35 #include "mibank.h"
36 #include "globals.h"
37 #include "xf86.h"
38 #include "xf86Priv.h"
39 #include "xf86DDC.h"
40 #include "mipointer.h"
41 #include "windowstr.h"
42 #include <randrstr.h>
43 #include <X11/extensions/render.h>
44 #include "X11/Xatom.h"
45
46 #include "xf86Crtc.h"
47 #include "nv_include.h"
48
49 const char *OutputType[] = {
50     "None",
51     "VGA",
52     "DVI",
53     "LVDS",
54     "S-video",
55     "Composite",
56 };
57
58 const char *MonTypeName[7] = {
59     "AUTO",
60     "NONE",
61     "CRT",
62     "LVDS",
63     "TMDS",
64     "CTV",
65     "STV"
66 };
67
68 /* 
69  * TMDS registers are indirect 8 bit registers.
70  * Reading is straightforward, writing a bit odd.
71  * Reading: Write adress (+write protect bit, do not forget this), then read value.
72  * Writing: Write adress (+write protect bit), write value, write adress again and write it again (+write protect bit).
73  */
74
75 void NVWriteTMDS(NVPtr pNv, int ramdac, uint32_t tmds_reg, uint32_t val)
76 {
77         nvWriteRAMDAC(pNv, ramdac, NV_RAMDAC_FP_TMDS_CONTROL, 
78                 (tmds_reg & 0xff) | NV_RAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE);
79
80         nvWriteRAMDAC(pNv, ramdac, NV_RAMDAC_FP_TMDS_DATA, val & 0xff);
81
82         nvWriteRAMDAC(pNv, ramdac, NV_RAMDAC_FP_TMDS_CONTROL, tmds_reg & 0xff);
83         nvWriteRAMDAC(pNv, ramdac, NV_RAMDAC_FP_TMDS_CONTROL, 
84                 (tmds_reg & 0xff) | NV_RAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE);
85 }
86
87 uint8_t NVReadTMDS(NVPtr pNv, int ramdac, uint32_t tmds_reg)
88 {
89         nvWriteRAMDAC(pNv, ramdac, NV_RAMDAC_FP_TMDS_CONTROL, 
90                 (tmds_reg & 0xff) | NV_RAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE);
91
92         return (nvReadRAMDAC(pNv, ramdac, NV_RAMDAC_FP_TMDS_DATA) & 0xff);
93 }
94
95 /* Two register sets exist, this one is only used for dual link dvi/lvds */
96
97 void NVWriteTMDS2(NVPtr pNv, int ramdac, uint32_t tmds_reg, uint32_t val)
98 {
99         nvWriteRAMDAC(pNv, ramdac, NV_RAMDAC_FP_TMDS_CONTROL_2, 
100                 (tmds_reg & 0xff) | NV_RAMDAC_FP_TMDS_CONTROL_2_WRITE_DISABLE);
101
102         nvWriteRAMDAC(pNv, ramdac, NV_RAMDAC_FP_TMDS_DATA_2, val & 0xff);
103
104         nvWriteRAMDAC(pNv, ramdac, NV_RAMDAC_FP_TMDS_CONTROL_2, tmds_reg & 0xff);
105         nvWriteRAMDAC(pNv, ramdac, NV_RAMDAC_FP_TMDS_CONTROL_2, 
106                 (tmds_reg & 0xff) | NV_RAMDAC_FP_TMDS_CONTROL_2_WRITE_DISABLE);
107 }
108
109 uint8_t NVReadTMDS2(NVPtr pNv, int ramdac, uint32_t tmds_reg)
110 {
111         nvWriteRAMDAC(pNv, ramdac, NV_RAMDAC_FP_TMDS_CONTROL_2, 
112                 (tmds_reg & 0xff) | NV_RAMDAC_FP_TMDS_CONTROL_2_WRITE_DISABLE);
113
114         return (nvReadRAMDAC(pNv, ramdac, NV_RAMDAC_FP_TMDS_DATA_2) & 0xff);
115 }
116
117 void NVOutputWriteTMDS(xf86OutputPtr output, uint32_t tmds_reg, uint32_t val)
118 {
119         NVOutputPrivatePtr nv_output = output->driver_private;
120         ScrnInfoPtr     pScrn = output->scrn;
121         NVPtr pNv = NVPTR(pScrn);
122
123         /* We must write to the "bus" of the output */
124         NVWriteTMDS(pNv, nv_output->preferred_output, tmds_reg, val);
125 }
126
127 uint8_t NVOutputReadTMDS(xf86OutputPtr output, uint32_t tmds_reg)
128 {
129         NVOutputPrivatePtr nv_output = output->driver_private;
130         ScrnInfoPtr     pScrn = output->scrn;
131         NVPtr pNv = NVPTR(pScrn);
132
133         /* We must read from the "bus" of the output */
134         return NVReadTMDS(pNv, nv_output->preferred_output, tmds_reg);
135 }
136
137 void NVOutputWriteTMDS2(xf86OutputPtr output, uint32_t tmds_reg, uint32_t val)
138 {
139         NVOutputPrivatePtr nv_output = output->driver_private;
140         ScrnInfoPtr     pScrn = output->scrn;
141         NVPtr pNv = NVPTR(pScrn);
142
143         /* We must write to the "bus" of the output */
144         NVWriteTMDS2(pNv, nv_output->preferred_output, tmds_reg, val);
145 }
146
147 uint8_t NVOutputReadTMDS2(xf86OutputPtr output, uint32_t tmds_reg)
148 {
149         NVOutputPrivatePtr nv_output = output->driver_private;
150         ScrnInfoPtr     pScrn = output->scrn;
151         NVPtr pNv = NVPTR(pScrn);
152
153         /* We must read from the "bus" of the output */
154         return NVReadTMDS2(pNv, nv_output->preferred_output, tmds_reg);
155 }
156
157 /* These functions now write into the output, instead of a specific ramdac */
158
159 void NVOutputWriteRAMDAC(xf86OutputPtr output, uint32_t ramdac_reg, uint32_t val)
160 {
161     NVOutputPrivatePtr nv_output = output->driver_private;
162     ScrnInfoPtr pScrn = output->scrn;
163     NVPtr pNv = NVPTR(pScrn);
164
165     nvWriteRAMDAC(pNv, nv_output->preferred_output, ramdac_reg, val);
166 }
167
168 uint32_t NVOutputReadRAMDAC(xf86OutputPtr output, uint32_t ramdac_reg)
169 {
170     NVOutputPrivatePtr nv_output = output->driver_private;
171     ScrnInfoPtr pScrn = output->scrn;
172     NVPtr pNv = NVPTR(pScrn);
173
174     return nvReadRAMDAC(pNv, nv_output->preferred_output, ramdac_reg);
175 }
176
177 static void dpms_update_output_ramdac(xf86OutputPtr output, int mode)
178 {
179         NVOutputPrivatePtr nv_output = output->driver_private;
180         ScrnInfoPtr pScrn = output->scrn;
181         NVPtr pNv = NVPTR(pScrn);
182         xf86CrtcPtr crtc = output->crtc;
183         if (!crtc)      /* we need nv_crtc, so give up */
184                 return;
185         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
186
187         /* We may be going for modesetting, so we must reset our output binding */
188         if (mode == DPMSModeOff) {
189                 NVWriteVGACR5758(pNv, nv_crtc->head, 0, 0x7f);
190                 NVWriteVGACR5758(pNv, nv_crtc->head, 2, 0);
191                 return;
192         }
193
194         /* The previous call was not a modeset, but a normal dpms call */
195         NVWriteVGACR5758(pNv, nv_crtc->head, 0, pNv->dcb_table.entry[nv_output->dcb_entry].type);
196         NVWriteVGACR5758(pNv, nv_crtc->head, 2, pNv->dcb_table.entry[nv_output->dcb_entry].or);
197 }
198
199 static void
200 nv_lvds_output_dpms(xf86OutputPtr output, int mode)
201 {
202         NVOutputPrivatePtr nv_output = output->driver_private;
203         NVPtr pNv = NVPTR(output->scrn);
204         xf86CrtcPtr crtc = output->crtc;
205         if (!crtc)      /* we need nv_crtc, so give up */
206                 return;
207         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
208         int pclk = 0;
209
210         ErrorF("nv_lvds_output_dpms is called with mode %d\n", mode);
211
212         dpms_update_output_ramdac(output, mode);
213
214         if (!pNv->dcb_table.entry[nv_output->dcb_entry].lvdsconf.use_power_scripts)
215                 return;
216
217         /* only need to pass in pclk for BIT bioses */
218         if (pNv->VBIOS.major_version > 4)
219                 pclk = nv_calc_tmds_clock_from_pll(output);
220
221         switch (mode) {
222         case DPMSModeStandby:
223         case DPMSModeSuspend:
224                 call_lvds_script(output->scrn, nv_crtc->head, nv_output->dcb_entry, LVDS_BACKLIGHT_OFF, pclk);
225                 break;
226         case DPMSModeOff:
227                 call_lvds_script(output->scrn, nv_crtc->head, nv_output->dcb_entry, LVDS_PANEL_OFF, pclk);
228                 break;
229         case DPMSModeOn:
230                 call_lvds_script(output->scrn, nv_crtc->head, nv_output->dcb_entry, LVDS_PANEL_ON, pclk);
231         default:
232                 break;
233         }
234 }
235
236 static void
237 nv_analog_output_dpms(xf86OutputPtr output, int mode)
238 {
239         xf86CrtcPtr crtc = output->crtc;
240
241         ErrorF("nv_analog_output_dpms is called with mode %d\n", mode);
242
243         dpms_update_output_ramdac(output, mode);
244
245         if (crtc) {
246                 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
247
248                 ErrorF("nv_analog_output_dpms is called for CRTC %d with mode %d\n", nv_crtc->head, mode);
249         }
250 }
251
252 static void
253 nv_tmds_output_dpms(xf86OutputPtr output, int mode)
254 {
255         xf86CrtcPtr crtc = output->crtc;
256         NVPtr pNv = NVPTR(output->scrn);
257
258         ErrorF("nv_tmds_output_dpms is called with mode %d\n", mode);
259
260         dpms_update_output_ramdac(output, mode);
261
262         /* Are we assigned a ramdac already?, else we will be activated during mode set */
263         if (crtc) {
264                 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
265
266                 ErrorF("nv_tmds_output_dpms is called for CRTC %d with mode %d\n", nv_crtc->head, mode);
267
268                 uint32_t fpcontrol = nvReadRAMDAC(pNv, nv_crtc->head, NV_RAMDAC_FP_CONTROL);
269                 switch(mode) {
270                         case DPMSModeStandby:
271                         case DPMSModeSuspend:
272                         case DPMSModeOff:
273                                 /* cut the TMDS output */           
274                                 fpcontrol |= 0x20000022;
275                                 break;
276                         case DPMSModeOn:
277                                 /* disable cutting the TMDS output */
278                                 fpcontrol &= ~0x20000022;
279                                 break;
280                 }
281                 nvWriteRAMDAC(pNv, nv_crtc->head, NV_RAMDAC_FP_CONTROL, fpcontrol);
282         }
283 }
284
285 void nv_output_save_state_ext(xf86OutputPtr output, RIVA_HW_STATE *state)
286 {
287         NVOutputPrivatePtr nv_output = output->driver_private;
288         NVOutputRegPtr regp;
289         int i;
290
291         regp = &state->dac_reg[nv_output->output_resource];
292
293         regp->output = NVOutputReadRAMDAC(output, NV_RAMDAC_OUTPUT);
294
295         /* NV11's don't seem to like this, so let's restrict it to digital outputs only. */
296         if (nv_output->type == OUTPUT_TMDS || nv_output->type == OUTPUT_LVDS) {
297                 /* Store the registers in case we need them again for something (like data for VT restore) */
298                 for (i = 0; i < 0xFF; i++) {
299                         regp->TMDS[i] = NVOutputReadTMDS(output, i);
300                 }
301
302                 for (i = 0; i < 0xFF; i++) {
303                         regp->TMDS2[i] = NVOutputReadTMDS2(output, i);
304                 }
305         }
306 }
307
308 void nv_output_load_state_ext(xf86OutputPtr output, RIVA_HW_STATE *state, Bool override)
309 {
310         NVOutputPrivatePtr nv_output = output->driver_private;
311         NVOutputRegPtr regp;
312
313         regp = &state->dac_reg[nv_output->output_resource];
314
315         /* This exists purely for proper text mode restore */
316         if (override) NVOutputWriteRAMDAC(output, NV_RAMDAC_OUTPUT, regp->output);
317 }
318
319 /* NOTE: Don't rely on this data for anything other than restoring VT's */
320
321 static void
322 nv_output_save (xf86OutputPtr output)
323 {
324         ScrnInfoPtr     pScrn = output->scrn;
325         NVPtr pNv = NVPTR(pScrn);
326         RIVA_HW_STATE *state;
327
328         ErrorF("nv_output_save is called\n");
329         state = &pNv->SavedReg;
330
331         /* Due to strange mapping of outputs we could have swapped analog and digital */
332         /* So we force save all the registers */
333         nv_output_save_state_ext(output, state);
334 }
335
336 uint32_t nv_calc_tmds_clock_from_pll(xf86OutputPtr output)
337 {
338         ScrnInfoPtr pScrn = output->scrn;
339         NVPtr pNv = NVPTR(pScrn);
340         RIVA_HW_STATE *state;
341         NVOutputRegPtr regp;
342         NVOutputPrivatePtr nv_output = output->driver_private;
343
344         state = &pNv->SavedReg;
345         /* Registers are stored by their preferred ramdac */
346         regp = &state->dac_reg[nv_output->output_resource];
347
348         /* Only do it once for a dvi-d/dvi-a pair */
349         Bool swapped_clock = FALSE;
350         Bool vpllb_disabled = FALSE;
351         /* Bit3 swaps crtc (clocks are bound to crtc) and output */
352         if (regp->TMDS[0x4] & (1 << 3)) {
353                 swapped_clock = TRUE;
354         }
355
356         uint8_t vpll_num = swapped_clock ^ nv_output->preferred_output;
357
358         uint32_t vplla = 0;
359         uint32_t vpllb = 0;
360
361         /* For the moment the syntax is the same for NV40 and earlier */
362         if (pNv->Architecture == NV_ARCH_40) {
363                 vplla = vpll_num ? state->vpll2_a : state->vpll1_a;
364                 vpllb = vpll_num ? state->vpll2_b : state->vpll1_b;
365         } else {
366                 vplla = vpll_num ? state->vpll2 : state->vpll;
367                 if (pNv->twoStagePLL)
368                         vpllb = vpll_num ? state->vpll2B : state->vpllB;
369         }
370
371         if (!pNv->twoStagePLL)
372                 vpllb_disabled = TRUE;
373
374         /* This is the dummy value nvidia sets when vpll is disabled */
375         if ((vpllb & 0xFFFF) == 0x11F)
376                 vpllb_disabled = TRUE;
377
378         uint8_t m1, m2, n1, n2, p;
379
380         m1 = vplla & 0xFF;
381         n1 = (vplla >> 8) & 0xFF;
382         p = (vplla >> 16) & 0x7;
383
384         if (vpllb_disabled) {
385                 m2 = 1;
386                 n2 = 1;
387         } else {
388                 m2 = vpllb & 0xFF;
389                 n2 = (vpllb >> 8) & 0xFF;
390         }
391
392         uint32_t clock = ((pNv->CrystalFreqKHz * n1 * n2)/(m1 * m2)) >> p;
393         ErrorF("The original bios clock seems to have been %d kHz\n", clock);
394         return clock;
395 }
396
397 void nv_set_tmds_registers(xf86OutputPtr output, uint32_t clock, Bool override, Bool crosswired)
398 {
399         ScrnInfoPtr pScrn = output->scrn;
400         NVOutputPrivatePtr nv_output = output->driver_private;
401         xf86CrtcPtr crtc = output->crtc;
402         /* We have no crtc, so what are we supposed to do now? */
403         /* This can only happen during VT restore */
404         if (crtc && !override) {
405                 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
406                 /*
407                  * Resetting all registers is a bad idea, it seems to work fine without it.
408                  */
409                 if (nv_output->type == OUTPUT_TMDS)
410                         run_tmds_table(pScrn, nv_output->dcb_entry, nv_crtc->head, clock/10);
411                 else
412                         call_lvds_script(pScrn, nv_crtc->head, nv_output->dcb_entry, LVDS_RESET, clock / 10);
413         } else {
414                 /*
415                  * We have no crtc, but we do know what output we are and if we were crosswired.
416                  * We can determine our crtc from this.
417                  */
418                 if (nv_output->type == OUTPUT_TMDS)
419                         run_tmds_table(pScrn, nv_output->dcb_entry, nv_output->preferred_output ^ crosswired, clock/10);
420                 else {
421                         call_lvds_script(pScrn, nv_output->preferred_output ^ crosswired, nv_output->dcb_entry, LVDS_RESET, clock / 10);
422                         call_lvds_script(pScrn, nv_output->preferred_output ^ crosswired, nv_output->dcb_entry, LVDS_PANEL_ON, clock / 10);
423                 }
424         }
425 }
426
427 static void
428 nv_output_restore (xf86OutputPtr output)
429 {
430         ScrnInfoPtr pScrn = output->scrn;
431         NVPtr pNv = NVPTR(pScrn);
432         RIVA_HW_STATE *state;
433         NVOutputPrivatePtr nv_output = output->driver_private;
434         ErrorF("nv_output_restore is called\n");
435
436         state = &pNv->SavedReg;
437         /* Select the default output resource for consistent restore. */
438         if (ffs(pNv->dcb_table.entry[nv_output->dcb_entry].or) & OUTPUT_1) {
439                 nv_output->output_resource = 1;
440         } else {
441                 nv_output->output_resource = 0;
442         }
443
444         /* Due to strange mapping of outputs we could have swapped analog and digital */
445         /* So we force load all the registers */
446         nv_output_load_state_ext(output, state, TRUE);
447 }
448
449 static int
450 nv_output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
451 {
452         if (pMode->Flags & V_DBLSCAN)
453                 return MODE_NO_DBLESCAN;
454
455         if (pMode->Clock > 400000 || pMode->Clock < 25000)
456                 return MODE_CLOCK_RANGE;
457
458         return MODE_OK;
459 }
460
461
462 static Bool
463 nv_output_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
464                      DisplayModePtr adjusted_mode)
465 {
466         NVOutputPrivatePtr nv_output = output->driver_private;
467         ErrorF("nv_output_mode_fixup is called\n");
468
469         /* For internal panels and gpu scaling on DVI we need the native mode */
470         if ((nv_output->type == OUTPUT_LVDS || (nv_output->type == OUTPUT_TMDS && nv_output->scaling_mode != SCALE_PANEL))) {
471                 adjusted_mode->HDisplay = nv_output->native_mode->HDisplay;
472                 adjusted_mode->HSkew = nv_output->native_mode->HSkew;
473                 adjusted_mode->HSyncStart = nv_output->native_mode->HSyncStart;
474                 adjusted_mode->HSyncEnd = nv_output->native_mode->HSyncEnd;
475                 adjusted_mode->HTotal = nv_output->native_mode->HTotal;
476                 adjusted_mode->VDisplay = nv_output->native_mode->VDisplay;
477                 adjusted_mode->VScan = nv_output->native_mode->VScan;
478                 adjusted_mode->VSyncStart = nv_output->native_mode->VSyncStart;
479                 adjusted_mode->VSyncEnd = nv_output->native_mode->VSyncEnd;
480                 adjusted_mode->VTotal = nv_output->native_mode->VTotal;
481                 adjusted_mode->Clock = nv_output->native_mode->Clock;
482
483                 xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V);
484         }
485
486         return TRUE;
487 }
488
489 static void
490 nv_output_mode_set_regs(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
491 {
492         NVOutputPrivatePtr nv_output = output->driver_private;
493         ScrnInfoPtr pScrn = output->scrn;
494         //RIVA_HW_STATE *state;
495         //NVOutputRegPtr regp, savep;
496         Bool is_fp = FALSE;
497         xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
498         int i;
499
500         /* It's getting quiet here, not removing function just yet, we may still need it */
501
502         //state = &pNv->ModeReg;
503         //regp = &state->dac_reg[nv_output->output_resource];
504
505         if (nv_output->type == OUTPUT_TMDS || nv_output->type == OUTPUT_LVDS)
506                 is_fp = TRUE;
507
508         if (output->crtc) {
509                 NVCrtcPrivatePtr nv_crtc = output->crtc->driver_private;
510                 int two_crt = FALSE;
511                 int two_mon = FALSE;
512
513                 for (i = 0; i < config->num_output; i++) {
514                         NVOutputPrivatePtr nv_output2 = config->output[i]->driver_private;
515
516                         /* is it this output ?? */
517                         if (config->output[i] == output)
518                                 continue;
519
520                         /* it the output connected */
521                         if (config->output[i]->crtc == NULL)
522                                 continue;
523
524                         two_mon = TRUE;
525                         if ((nv_output2->type == OUTPUT_ANALOG) && (nv_output->type == OUTPUT_ANALOG)) {
526                                 two_crt = TRUE;
527                         }
528                 }
529
530                 ErrorF("%d: crtc %d output %d twocrt %d twomon %d\n", is_fp, nv_crtc->head, nv_output->output_resource, two_crt, two_mon);
531         }
532 }
533
534 /* Only return if output is active (=have a crtc). */
535
536 static Bool 
537 nv_have_duallink(ScrnInfoPtr pScrn)
538 {
539         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
540         NVPtr pNv = NVPTR(pScrn);
541         int i;
542
543         for (i = 0; i < xf86_config->num_output; i++) {
544                 xf86OutputPtr output = xf86_config->output[i];
545                 NVOutputPrivatePtr nv_output = output->driver_private;
546                 if (pNv->dcb_table.entry[nv_output->dcb_entry].duallink_possible && 
547                         (pNv->dcb_table.entry[nv_output->dcb_entry].type == OUTPUT_LVDS || 
548                         pNv->dcb_table.entry[nv_output->dcb_entry].type == OUTPUT_TMDS) &&
549                         output->crtc) {
550
551                         return TRUE;
552                 }
553         }
554
555         return FALSE;
556 }
557
558 static void
559 nv_output_mode_set_routing(xf86OutputPtr output)
560 {
561         NVOutputPrivatePtr nv_output = output->driver_private;
562         xf86CrtcPtr crtc = output->crtc;
563         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
564         ScrnInfoPtr pScrn = output->scrn;
565         NVPtr pNv = NVPTR(pScrn);
566         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
567         Bool strange_mode = FALSE;
568         int i;
569
570         uint32_t output_reg[2] = {0, 0};
571
572         for (i = 0; i < xf86_config->num_output; i++) {
573                 xf86OutputPtr output2 = xf86_config->output[i];
574                 NVOutputPrivatePtr nv_output2 = output2->driver_private;
575                 if (output2->crtc) { /* enabled? */
576                         uint8_t ors = nv_output2->output_resource;
577                         if (nv_output2->type == OUTPUT_ANALOG)
578                                 output_reg[ors] = NV_RAMDAC_OUTPUT_DAC_ENABLE;
579                         if (ors != nv_output2->preferred_output)
580                                 strange_mode = TRUE;
581                 }
582         }
583
584         /* Some (most?) pre-NV30 cards have switchable crtc's. */
585         if (pNv->switchable_crtc) {
586                 uint8_t crtc0_index = nv_output->output_resource ^ nv_crtc->head;
587                 output_reg[~(crtc0_index) & 1] |= NV_RAMDAC_OUTPUT_SELECT_CRTC1;
588
589                 if (strange_mode)
590                         output_reg[crtc0_index] |= NV_RAMDAC_OUTPUT_SELECT_CRTC1;
591         }
592
593         /* The registers can't be considered seperately on most cards */
594         nvWriteRAMDAC(pNv, 0, NV_RAMDAC_OUTPUT, output_reg[0]);
595         nvWriteRAMDAC(pNv, 1, NV_RAMDAC_OUTPUT, output_reg[1]);
596
597         /* This could use refinement for flatpanels, but it should work this way */
598         if (pNv->NVArch < 0x44) {
599                 nvWriteRAMDAC(pNv, nv_crtc->head, NV_RAMDAC_TEST_CONTROL, 0xf0000000);
600                 if (pNv->Architecture == NV_ARCH_40)
601                         nvWriteRAMDAC(pNv, 0, NV_RAMDAC_670, 0xf0000000);
602         } else {
603                 nvWriteRAMDAC(pNv, nv_crtc->head, NV_RAMDAC_TEST_CONTROL, 0x00100000);
604                 nvWriteRAMDAC(pNv, 0, NV_RAMDAC_670, 0x00100000);
605         }
606 }
607
608 static void
609 nv_output_mode_set(xf86OutputPtr output, DisplayModePtr mode,
610                    DisplayModePtr adjusted_mode)
611 {
612         ScrnInfoPtr pScrn = output->scrn;
613         NVPtr pNv = NVPTR(pScrn);
614         NVOutputPrivatePtr nv_output = output->driver_private;
615         RIVA_HW_STATE *state;
616
617         ErrorF("nv_output_mode_set is called\n");
618
619         state = &pNv->ModeReg;
620
621         nv_output_mode_set_regs(output, mode, adjusted_mode);
622         nv_output_load_state_ext(output, state, FALSE);
623         if (nv_output->type == OUTPUT_TMDS || nv_output->type == OUTPUT_LVDS)
624                 nv_set_tmds_registers(output, adjusted_mode->Clock, FALSE, FALSE);
625
626         nv_output_mode_set_routing(output);
627 }
628
629 static xf86MonPtr
630 nv_get_edid(xf86OutputPtr output)
631 {
632         /* no use for shared DDC output */
633         NVOutputPrivatePtr nv_output = output->driver_private;
634         xf86MonPtr ddc_mon;
635
636         if (nv_output->pDDCBus == NULL)
637                 return NULL;
638
639         ddc_mon = xf86OutputGetEDID(output, nv_output->pDDCBus);
640         if (!ddc_mon)
641                 return NULL;
642
643         if (ddc_mon->features.input_type && (nv_output->type == OUTPUT_ANALOG))
644                 goto invalid;
645
646         if ((!ddc_mon->features.input_type) && (nv_output->type == OUTPUT_TMDS ||
647                                 nv_output->type == OUTPUT_LVDS))
648                 goto invalid;
649
650         return ddc_mon;
651
652 invalid:
653         xfree(ddc_mon);
654         return NULL;
655 }
656
657 static Bool
658 nv_ddc_detect(xf86OutputPtr output)
659 {
660         xf86MonPtr m = nv_get_edid(output);
661
662         if (m == NULL)
663                 return FALSE;
664
665         xfree(m);
666         return TRUE;
667 }
668
669 static Bool
670 nv_crt_load_detect(xf86OutputPtr output)
671 {
672         ScrnInfoPtr pScrn = output->scrn;
673         NVOutputPrivatePtr nv_output = output->driver_private;
674         NVPtr pNv = NVPTR(pScrn);
675         uint32_t reg_output, reg_test_ctrl, temp;
676         Bool present = FALSE;
677
678         /* For some reason we get false positives on output 1, maybe due tv-out? */
679         if (nv_output->preferred_output == 1) {
680                 return FALSE;
681         }
682
683         if (nv_output->pDDCBus != NULL) {
684                 xf86MonPtr ddc_mon = xf86OutputGetEDID(output, nv_output->pDDCBus);
685                 /* Is there a digital flatpanel on this channel? */
686                 if (ddc_mon && ddc_mon->features.input_type) {
687                         return FALSE;
688                 }
689         }
690
691         reg_output = nvReadRAMDAC(pNv, nv_output->preferred_output, NV_RAMDAC_OUTPUT);
692         reg_test_ctrl = nvReadRAMDAC(pNv, nv_output->preferred_output, NV_RAMDAC_TEST_CONTROL);
693
694         nvWriteRAMDAC(pNv, nv_output->preferred_output, NV_RAMDAC_TEST_CONTROL, (reg_test_ctrl & ~0x00010000));
695
696         nvWriteRAMDAC(pNv, nv_output->preferred_output, NV_RAMDAC_OUTPUT, (reg_output & 0x0000FEEE));
697         usleep(1000);
698
699         temp = nvReadRAMDAC(pNv, nv_output->preferred_output, NV_RAMDAC_OUTPUT);
700         nvWriteRAMDAC(pNv, nv_output->preferred_output, NV_RAMDAC_OUTPUT, temp | 1);
701
702         nvWriteRAMDAC(pNv, nv_output->preferred_output, NV_RAMDAC_TEST_DATA, 0x94050140);
703         temp = nvReadRAMDAC(pNv, nv_output->preferred_output, NV_RAMDAC_TEST_CONTROL);
704         nvWriteRAMDAC(pNv, nv_output->preferred_output, NV_RAMDAC_TEST_CONTROL, temp | 0x1000);
705
706         usleep(1000);
707
708         present = (nvReadRAMDAC(pNv, nv_output->preferred_output, NV_RAMDAC_TEST_CONTROL) & (1 << 28)) ? TRUE : FALSE;
709
710         temp = NVOutputReadRAMDAC(output, NV_RAMDAC_TEST_CONTROL);
711         nvWriteRAMDAC(pNv, nv_output->preferred_output, NV_RAMDAC_TEST_CONTROL, temp & 0x000EFFF);
712
713         nvWriteRAMDAC(pNv, nv_output->preferred_output, NV_RAMDAC_OUTPUT, reg_output);
714         nvWriteRAMDAC(pNv, nv_output->preferred_output, NV_RAMDAC_TEST_CONTROL, reg_test_ctrl);
715
716         if (present) {
717                 ErrorF("A crt was detected on output %d with no ddc support\n", nv_output->preferred_output);
718                 return TRUE;
719         }
720
721         return FALSE;
722 }
723
724 static xf86OutputStatus
725 nv_tmds_output_detect(xf86OutputPtr output)
726 {
727         ErrorF("nv_tmds_output_detect is called\n");
728
729         if (nv_ddc_detect(output))
730                 return XF86OutputStatusConnected;
731
732         return XF86OutputStatusDisconnected;
733 }
734
735
736 static xf86OutputStatus
737 nv_analog_output_detect(xf86OutputPtr output)
738 {
739         ErrorF("nv_analog_output_detect is called\n");
740
741         if (nv_ddc_detect(output))
742                 return XF86OutputStatusConnected;
743
744         //if (nv_crt_load_detect(output))
745         //      return XF86OutputStatusConnected;
746
747         return XF86OutputStatusDisconnected;
748 }
749
750 static DisplayModePtr
751 nv_output_get_modes(xf86OutputPtr output)
752 {
753         NVOutputPrivatePtr nv_output = output->driver_private;
754         xf86MonPtr ddc_mon;
755         DisplayModePtr ddc_modes;
756
757         ErrorF("nv_output_get_modes is called\n");
758
759         ddc_mon = nv_get_edid(output);
760
761         xf86OutputSetEDID(output, ddc_mon);
762
763         if (ddc_mon == NULL)
764                 return NULL;
765
766         ddc_modes = xf86OutputGetEDIDModes (output);
767
768         if (nv_output->type == OUTPUT_TMDS || nv_output->type == OUTPUT_LVDS) {
769                 int i;
770                 DisplayModePtr mode;
771
772                 for (i = 0; i < 4; i++) {
773                         /* We only look at detailed timings atm */
774                         if (ddc_mon->det_mon[i].type != DT)
775                                 continue;
776                         /* Selecting only based on width ok? */
777                         if (ddc_mon->det_mon[i].section.d_timings.h_active > nv_output->fpWidth) {
778                                 nv_output->fpWidth = ddc_mon->det_mon[i].section.d_timings.h_active;
779                                 nv_output->fpHeight = ddc_mon->det_mon[i].section.d_timings.v_active;
780                         }
781                 }
782
783                 if (nv_output->native_mode)
784                         xfree(nv_output->native_mode);
785                 nv_output->native_mode = NULL;
786                 if (nv_output->type == OUTPUT_TMDS) {
787                         DisplayModePtr cvtmode;
788                         /* Add a native resolution mode that is preferred */
789                         /* Reduced blanking should be fine on DVI monitor */
790                         cvtmode = xf86CVTMode(nv_output->fpWidth, nv_output->fpHeight, 60.0, TRUE, FALSE);
791                         cvtmode->type = M_T_DRIVER | M_T_PREFERRED;
792
793                         /* can xf86CVTMode generate invalid modes? */
794                         if (output->funcs->mode_valid(output, cvtmode) == MODE_OK) {
795                                 ddc_modes = xf86ModesAdd(ddc_modes, cvtmode);
796                                 nv_output->native_mode = xf86DuplicateMode(cvtmode);
797                         } else {
798                                 xf86DeleteMode(&cvtmode, cvtmode);
799                         }
800                 }
801
802                 if (!nv_output->native_mode)
803                         for (mode = ddc_modes; mode != NULL; mode = mode->next)
804                                 if (mode->HDisplay == nv_output->fpWidth &&
805                                     mode->VDisplay == nv_output->fpHeight) {
806                                         nv_output->native_mode = xf86DuplicateMode(mode);
807                                         break;
808                                 }
809                 if (!nv_output->native_mode) {
810                         ErrorF("Really bad stuff happening, CVT mode bad and no other native mode can be found.\n");
811                         ErrorF("Bailing out\n");
812                         return NULL;
813                 }
814
815                 /* We want the new mode to be the only preferred one */
816                 for (mode = ddc_modes; mode != NULL; mode = mode->next)
817                         if (mode->type & M_T_PREFERRED && !xf86ModesEqual(mode, nv_output->native_mode))
818                                 mode->type &= ~M_T_PREFERRED;
819         }
820
821         return ddc_modes;
822 }
823
824 static void
825 nv_output_destroy (xf86OutputPtr output)
826 {
827         ErrorF("nv_output_destroy is called\n");
828         NVOutputPrivatePtr nv_output = output->driver_private;
829
830         if (nv_output) {
831                 if (nv_output->native_mode)
832                         xfree(nv_output->native_mode);
833                 xfree(output->driver_private);
834         }
835 }
836
837 static void
838 nv_output_prepare(xf86OutputPtr output)
839 {
840         ErrorF("nv_output_prepare is called\n");
841         NVOutputPrivatePtr nv_output = output->driver_private;
842         ScrnInfoPtr pScrn = output->scrn;
843         xf86CrtcPtr crtc = output->crtc;
844         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
845         NVPtr pNv = NVPTR(pScrn);
846         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
847         int i;
848
849         output->funcs->dpms(output, DPMSModeOff);
850
851         /* Set our output type and output routing possibilities to the right registers */
852         NVWriteVGACR5758(pNv, nv_crtc->head, 0, pNv->dcb_table.entry[nv_output->dcb_entry].type);
853         NVWriteVGACR5758(pNv, nv_crtc->head, 2, pNv->dcb_table.entry[nv_output->dcb_entry].or);
854
855         /*
856          * Here we detect output resource conflicts.
857          * We do this based on connected monitors, since we need to catch this before something important happens.
858          */
859
860         uint8_t output_resource_mask = 0;
861         for (i = 0; i < xf86_config->num_output; i++) {
862                 xf86OutputPtr output2 = xf86_config->output[i];
863                 NVOutputPrivatePtr nv_output2 = output2->driver_private;
864
865                 /* I don't know how well this will deal with triple connected output situations. */
866                 if (output2 != output && output2->crtc) { /* output in use? */
867                         output_resource_mask |= (nv_output2->output_resource + 1); /* +1 to actually get a non-zero value */
868                 }
869         }
870
871         uint8_t or = pNv->dcb_table.entry[nv_output->dcb_entry].or;
872         /* Do we have a output resource conflict? */
873         if (output_resource_mask & (nv_output->output_resource + 1)) {
874                 if (or == ffs(or)) { /* we need this output resource */
875                         for (i = 0; i < xf86_config->num_output; i++) { /* let's find the other */
876                                 xf86OutputPtr output2 = xf86_config->output[i];
877                                 NVOutputPrivatePtr nv_output2 = output2->driver_private;
878
879                                 if (output2 != output && output2->status == XF86OutputStatusConnected) {
880                                         if (nv_output->output_resource == nv_output2->output_resource) {
881                                                 nv_output2->output_resource ^= 1;
882                                                 break; /* We don't deal with triple outputs yet */
883                                         }
884                                 }
885                         }
886                 } else { /* we have alternatives */
887                         nv_output->output_resource ^= 1;
888                 }
889         }
890 }
891
892 static void
893 nv_output_commit(xf86OutputPtr output)
894 {
895         ErrorF("nv_output_commit is called\n");
896
897         output->funcs->dpms(output, DPMSModeOn);
898 }
899
900 static const xf86OutputFuncsRec nv_analog_output_funcs = {
901     .dpms = nv_analog_output_dpms,
902     .save = nv_output_save,
903     .restore = nv_output_restore,
904     .mode_valid = nv_output_mode_valid,
905     .mode_fixup = nv_output_mode_fixup,
906     .mode_set = nv_output_mode_set,
907     .detect = nv_analog_output_detect,
908     .get_modes = nv_output_get_modes,
909     .destroy = nv_output_destroy,
910     .prepare = nv_output_prepare,
911     .commit = nv_output_commit,
912 };
913
914 #ifdef RANDR_12_INTERFACE
915 /*
916  * Several scaling modes exist, let the user choose.
917  */
918 #define SCALING_MODE_NAME "SCALING_MODE"
919 static const struct {
920         char *name;
921         enum scaling_modes mode;
922 } scaling_mode[] = {
923         { "panel", SCALE_PANEL },
924         { "fullscreen", SCALE_FULLSCREEN },
925         { "aspect", SCALE_ASPECT },
926         { "noscale", SCALE_NOSCALE },
927         { NULL, SCALE_INVALID}
928 };
929 static Atom scaling_mode_atom;
930
931 static int
932 nv_scaling_mode_lookup(char *name, int size)
933 {
934         int i;
935
936         /* for when name is zero terminated */
937         if (size < 0)
938                 size = strlen(name);
939
940         for (i = 0; scaling_mode[i].name; i++)
941                 /* We're getting non-terminated strings */
942                 if (strlen(scaling_mode[i].name) >= size &&
943                                 !strncasecmp(name, scaling_mode[i].name, size))
944                         break;
945
946         return scaling_mode[i].mode;
947 }
948
949 static void
950 nv_digital_output_create_resources(xf86OutputPtr output)
951 {
952         NVOutputPrivatePtr nv_output = output->driver_private;
953         ScrnInfoPtr pScrn = output->scrn;
954         int error, i;
955
956         /*
957          * Setup scaling mode property.
958          */
959         scaling_mode_atom = MakeAtom(SCALING_MODE_NAME, sizeof(SCALING_MODE_NAME) - 1, TRUE);
960
961         error = RRConfigureOutputProperty(output->randr_output,
962                                         scaling_mode_atom, TRUE, FALSE, FALSE,
963                                         0, NULL);
964
965         if (error != 0) {
966                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
967                         "RRConfigureOutputProperty error, %d\n", error);
968         }
969
970         char *existing_scale_name = NULL;
971         for (i = 0; scaling_mode[i].name; i++)
972                 if (scaling_mode[i].mode == nv_output->scaling_mode)
973                         existing_scale_name = scaling_mode[i].name;
974
975         error = RRChangeOutputProperty(output->randr_output, scaling_mode_atom,
976                                         XA_STRING, 8, PropModeReplace, 
977                                         strlen(existing_scale_name),
978                                         existing_scale_name, FALSE, TRUE);
979
980         if (error != 0) {
981                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
982                         "Failed to set scaling mode, %d\n", error);
983         }
984 }
985
986 static Bool
987 nv_digital_output_set_property(xf86OutputPtr output, Atom property,
988                                 RRPropertyValuePtr value)
989 {
990         NVOutputPrivatePtr nv_output = output->driver_private;
991
992         if (property == scaling_mode_atom) {
993                 int32_t ret;
994                 char *name = NULL;
995
996                 if (value->type != XA_STRING || value->format != 8)
997                         return FALSE;
998
999                 name = (char *) value->data;
1000
1001                 /* Match a string to a scaling mode */
1002                 ret = nv_scaling_mode_lookup(name, value->size);
1003                 if (ret == SCALE_INVALID)
1004                         return FALSE;
1005
1006                 /* LVDS must always use gpu scaling. */
1007                 if (ret == SCALE_PANEL && nv_output->type == OUTPUT_LVDS)
1008                         return FALSE;
1009
1010                 nv_output->scaling_mode = ret;
1011                 return TRUE;
1012         }
1013
1014         return TRUE;
1015 }
1016
1017 #endif /* RANDR_12_INTERFACE */
1018
1019 static int 
1020 nv_tmds_output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
1021 {
1022         ScrnInfoPtr pScrn = output->scrn;
1023         NVPtr pNv = NVPTR(pScrn);
1024         NVOutputPrivatePtr nv_output = output->driver_private;
1025
1026         /* We can't exceed the native mode.*/
1027         if (pMode->HDisplay > nv_output->fpWidth || pMode->VDisplay > nv_output->fpHeight)
1028                 return MODE_PANEL;
1029
1030         if (pNv->dcb_table.entry[nv_output->dcb_entry].duallink_possible) {
1031                 if (pMode->Clock > 330000) /* 2x165 MHz */
1032                         return MODE_CLOCK_RANGE;
1033         } else {
1034                 if (pMode->Clock > 165000) /* 165 MHz */
1035                         return MODE_CLOCK_RANGE;
1036         }
1037
1038         return nv_output_mode_valid(output, pMode);
1039 }
1040
1041 static const xf86OutputFuncsRec nv_tmds_output_funcs = {
1042         .dpms = nv_tmds_output_dpms,
1043         .save = nv_output_save,
1044         .restore = nv_output_restore,
1045         .mode_valid = nv_tmds_output_mode_valid,
1046         .mode_fixup = nv_output_mode_fixup,
1047         .mode_set = nv_output_mode_set,
1048         .detect = nv_tmds_output_detect,
1049         .get_modes = nv_output_get_modes,
1050         .destroy = nv_output_destroy,
1051         .prepare = nv_output_prepare,
1052         .commit = nv_output_commit,
1053 #ifdef RANDR_12_INTERFACE
1054         .create_resources = nv_digital_output_create_resources,
1055         .set_property = nv_digital_output_set_property,
1056 #endif /* RANDR_12_INTERFACE */
1057 };
1058
1059 static int nv_lvds_output_mode_valid
1060 (xf86OutputPtr output, DisplayModePtr pMode)
1061 {
1062         NVOutputPrivatePtr nv_output = output->driver_private;
1063
1064         /* No modes > panel's native res */
1065         if (pMode->HDisplay > nv_output->fpWidth || pMode->VDisplay > nv_output->fpHeight)
1066                 return MODE_PANEL;
1067
1068         return nv_output_mode_valid(output, pMode);
1069 }
1070
1071 static xf86OutputStatus
1072 nv_lvds_output_detect(xf86OutputPtr output)
1073 {
1074         ErrorF("nv_lvds_output_detect is called\n");
1075         ScrnInfoPtr pScrn = output->scrn;
1076         NVPtr pNv = NVPTR(pScrn);
1077         NVOutputPrivatePtr nv_output = output->driver_private;
1078
1079         if (pNv->dcb_table.entry[nv_output->dcb_entry].lvdsconf.use_straps_for_mode &&
1080             pNv->VBIOS.fp.native_mode)
1081                 return XF86OutputStatusConnected;
1082         if (nv_ddc_detect(output))
1083                 return XF86OutputStatusConnected;
1084
1085         return XF86OutputStatusDisconnected;
1086 }
1087
1088 static DisplayModePtr
1089 nv_lvds_output_get_modes(xf86OutputPtr output)
1090 {
1091         ErrorF("nv_lvds_output_get_modes is called\n");
1092         ScrnInfoPtr pScrn = output->scrn;
1093         NVPtr pNv = NVPTR(pScrn);
1094         NVOutputPrivatePtr nv_output = output->driver_private;
1095         DisplayModePtr modes;
1096
1097         if ((modes = nv_output_get_modes(output)))
1098                 return modes;
1099
1100         /* it is possible to set up a mode from what we can read from the
1101          * RAMDAC registers, but if we can't read the BIOS table correctly
1102          * we might as well give up */
1103         if (!pNv->dcb_table.entry[nv_output->dcb_entry].lvdsconf.use_straps_for_mode ||
1104             (pNv->VBIOS.fp.native_mode == NULL))
1105                 return NULL;
1106
1107         nv_output->fpWidth = NVOutputReadRAMDAC(output, NV_RAMDAC_FP_HDISP_END) + 1;
1108         nv_output->fpHeight = NVOutputReadRAMDAC(output, NV_RAMDAC_FP_VDISP_END) + 1;
1109         nv_output->fpSyncs = NVOutputReadRAMDAC(output, NV_RAMDAC_FP_CONTROL) & 0x30000033;
1110
1111         if (pNv->VBIOS.fp.native_mode->HDisplay != nv_output->fpWidth ||
1112                 pNv->VBIOS.fp.native_mode->VDisplay != nv_output->fpHeight) {
1113                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1114                         "Panel size mismatch; ignoring RAMDAC\n");
1115                 nv_output->fpWidth = pNv->VBIOS.fp.native_mode->HDisplay;
1116                 nv_output->fpHeight = pNv->VBIOS.fp.native_mode->VDisplay;
1117         }
1118
1119         xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel size is %u x %u\n",
1120                 nv_output->fpWidth, nv_output->fpHeight);
1121
1122         nv_output->native_mode = xf86DuplicateMode(pNv->VBIOS.fp.native_mode);
1123
1124         return xf86DuplicateMode(pNv->VBIOS.fp.native_mode);
1125 }
1126
1127 static const xf86OutputFuncsRec nv_lvds_output_funcs = {
1128         .dpms = nv_lvds_output_dpms,
1129         .save = nv_output_save,
1130         .restore = nv_output_restore,
1131         .mode_valid = nv_lvds_output_mode_valid,
1132         .mode_fixup = nv_output_mode_fixup,
1133         .mode_set = nv_output_mode_set,
1134         .detect = nv_lvds_output_detect,
1135         .get_modes = nv_lvds_output_get_modes,
1136         .destroy = nv_output_destroy,
1137         .prepare = nv_output_prepare,
1138         .commit = nv_output_commit,
1139 #ifdef RANDR_12_INTERFACE
1140         .create_resources = nv_digital_output_create_resources,
1141         .set_property = nv_digital_output_set_property,
1142 #endif /* RANDR_12_INTERFACE */
1143 };
1144
1145 static void nv_add_analog_output(ScrnInfoPtr pScrn, int dcb_entry, Bool dvi_pair)
1146 {
1147         NVPtr pNv = NVPTR(pScrn);
1148         xf86OutputPtr       output;
1149         NVOutputPrivatePtr    nv_output;
1150         char outputname[20];
1151         Bool create_output = TRUE;
1152         int i2c_index = pNv->dcb_table.entry[dcb_entry].i2c_index;
1153
1154         /* DVI have an analog connector and a digital one, differentiate between that and a normal vga */
1155         if (dvi_pair) {
1156                 sprintf(outputname, "DVI-A-%d", pNv->dvi_a_count);
1157                 pNv->dvi_a_count++;
1158         } else {
1159                 sprintf(outputname, "VGA-%d", pNv->vga_count);
1160                 pNv->vga_count++;
1161         }
1162
1163         nv_output = xnfcalloc (sizeof (NVOutputPrivateRec), 1);
1164         if (!nv_output) {
1165                 return;
1166         }
1167
1168         nv_output->dcb_entry = dcb_entry;
1169
1170         if (pNv->dcb_table.i2c_read[i2c_index] && pNv->pI2CBus[i2c_index] == NULL)
1171                 NV_I2CInit(pScrn, &pNv->pI2CBus[i2c_index], pNv->dcb_table.i2c_read[i2c_index], xstrdup(outputname));
1172
1173         nv_output->type = OUTPUT_ANALOG;
1174
1175         /* output route:
1176          * bit0: OUTPUT_0 valid
1177          * bit1: OUTPUT_1 valid
1178          * So lowest order has highest priority.
1179          * Below is guesswork:
1180          * bit2: All outputs valid
1181          */
1182         /* We choose the preferred output resource initially. */
1183         if (ffs(pNv->dcb_table.entry[dcb_entry].or) & OUTPUT_1) {
1184                 nv_output->preferred_output = 1;
1185                 nv_output->output_resource = 1;
1186         } else {
1187                 nv_output->preferred_output = 0;
1188                 nv_output->output_resource = 0;
1189         }
1190
1191         nv_output->bus = pNv->dcb_table.entry[dcb_entry].bus;
1192
1193         if (!create_output) {
1194                 xfree(nv_output);
1195                 return;
1196         }
1197
1198         /* Delay creation of output until we actually know we want it */
1199         output = xf86OutputCreate (pScrn, &nv_analog_output_funcs, outputname);
1200         if (!output)
1201                 return;
1202
1203         output->driver_private = nv_output;
1204
1205         nv_output->pDDCBus = pNv->pI2CBus[i2c_index];
1206
1207         if (pNv->switchable_crtc) {
1208                 output->possible_crtcs = pNv->dcb_table.entry[dcb_entry].heads;
1209         } else {
1210                 output->possible_crtcs = (1 << nv_output->preferred_output);
1211         }
1212
1213         xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Adding output %s\n", outputname);
1214 }
1215
1216 static void nv_add_digital_output(ScrnInfoPtr pScrn, int dcb_entry, int lvds)
1217 {
1218         NVPtr pNv = NVPTR(pScrn);
1219         xf86OutputPtr       output;
1220         NVOutputPrivatePtr    nv_output;
1221         char outputname[20];
1222         Bool create_output = TRUE;
1223         int i2c_index = pNv->dcb_table.entry[dcb_entry].i2c_index;
1224
1225         if (lvds) {
1226                 sprintf(outputname, "LVDS-%d", pNv->lvds_count);
1227                 pNv->lvds_count++;
1228         } else {
1229                 sprintf(outputname, "DVI-D-%d", pNv->dvi_d_count);
1230                 pNv->dvi_d_count++;
1231         }
1232
1233         nv_output = xnfcalloc (sizeof (NVOutputPrivateRec), 1);
1234
1235         if (!nv_output) {
1236                 return;
1237         }
1238
1239         nv_output->dcb_entry = dcb_entry;
1240
1241         if (pNv->dcb_table.i2c_read[i2c_index] && pNv->pI2CBus[i2c_index] == NULL)
1242                 NV_I2CInit(pScrn, &pNv->pI2CBus[i2c_index], pNv->dcb_table.i2c_read[i2c_index], xstrdup(outputname));
1243
1244         nv_output->pDDCBus = pNv->pI2CBus[i2c_index];
1245
1246         /* output route:
1247          * bit0: OUTPUT_0 valid
1248          * bit1: OUTPUT_1 valid
1249          * So lowest order has highest priority.
1250          * Below is guesswork:
1251          * bit2: All outputs valid
1252          */
1253         /* We choose the preferred output resource initially. */
1254         if (ffs(pNv->dcb_table.entry[dcb_entry].or) & OUTPUT_1) {
1255                 nv_output->preferred_output = 1;
1256                 nv_output->output_resource = 1;
1257         } else {
1258                 nv_output->preferred_output = 0;
1259                 nv_output->output_resource = 0;
1260         }
1261
1262         nv_output->bus = pNv->dcb_table.entry[dcb_entry].bus;
1263
1264         if (lvds) {
1265                 nv_output->type = OUTPUT_LVDS;
1266                 /* comment below two lines to test LVDS under RandR12.
1267                  * If your screen "blooms" or "bleeds" (i.e. has a developing
1268                  * white / psychedelic pattern) then KILL X IMMEDIATELY
1269                  * (ctrl+alt+backspace) & if the effect continues reset power */
1270                 ErrorF("Output refused because we don't accept LVDS at the moment.\n");
1271                 create_output = FALSE;
1272         } else {
1273                 nv_output->type = OUTPUT_TMDS;
1274         }
1275
1276         if (!create_output) {
1277                 xfree(nv_output);
1278                 return;
1279         }
1280
1281         /* Delay creation of output until we are certain is desirable */
1282         if (lvds)
1283                 output = xf86OutputCreate (pScrn, &nv_lvds_output_funcs, outputname);
1284         else
1285                 output = xf86OutputCreate (pScrn, &nv_tmds_output_funcs, outputname);
1286         if (!output)
1287                 return;
1288
1289         output->driver_private = nv_output;
1290
1291         if (pNv->fpScaler) /* GPU Scaling */
1292                 nv_output->scaling_mode = SCALE_ASPECT;
1293         else /* Panel scaling */
1294                 nv_output->scaling_mode = SCALE_PANEL;
1295
1296 #ifdef RANDR_12_INTERFACE
1297         if (xf86GetOptValString(pNv->Options, OPTION_SCALING_MODE)) {
1298                 nv_output->scaling_mode = nv_scaling_mode_lookup(xf86GetOptValString(pNv->Options, OPTION_SCALING_MODE), -1);
1299                 if (nv_output->scaling_mode == SCALE_INVALID)
1300                         nv_output->scaling_mode = SCALE_ASPECT; /* default */
1301         }
1302 #endif /* RANDR_12_INTERFACE */
1303
1304         /* Due to serious problems we have to restrict the crtc's for certain types of outputs. */
1305         /* This is a result of problems with G70 cards that have a dvi with ffs(or) == 1 */
1306         /* Anyone know what the solution for this is? */
1307         if (nv_output->preferred_output == 0) {
1308                 output->possible_crtcs = (1 << 0);
1309         } else {
1310                 if (pNv->switchable_crtc) {
1311                         output->possible_crtcs = pNv->dcb_table.entry[dcb_entry].heads;
1312                 } else {
1313                         output->possible_crtcs = (1 << nv_output->preferred_output);
1314                 }
1315         }
1316
1317         xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Adding output %s\n", outputname);
1318 }
1319
1320 void NvDCBSetupOutputs(ScrnInfoPtr pScrn)
1321 {
1322         NVPtr pNv = NVPTR(pScrn);
1323         int i, type, i2c_count[0xf];
1324
1325         pNv->switchable_crtc = FALSE;
1326         /* I was wrong, again. */
1327         if (pNv->NVArch > 0x11 && pNv->twoHeads)
1328                 pNv->switchable_crtc = TRUE;
1329
1330         memset(i2c_count, 0, sizeof(i2c_count));
1331         for (i = 0 ; i < pNv->dcb_table.entries; i++)
1332                 i2c_count[pNv->dcb_table.entry[i].i2c_index]++;
1333
1334         /* we setup the outputs up from the BIOS table */
1335         for (i = 0 ; i < pNv->dcb_table.entries; i++) {
1336                 type = pNv->dcb_table.entry[i].type;
1337                 if (type > 3) {
1338                         xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DCB type %d not known\n", type);
1339                         continue;
1340                 }
1341
1342                 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);
1343
1344                 switch(type) {
1345                 case OUTPUT_ANALOG:
1346                         nv_add_analog_output(pScrn, i, (i2c_count[pNv->dcb_table.entry[i].i2c_index] > 1));
1347                         break;
1348                 case OUTPUT_TMDS:
1349                         nv_add_digital_output(pScrn, i, 0);
1350                         break;
1351                 case OUTPUT_LVDS:
1352                         nv_add_digital_output(pScrn, i, 1);
1353                         break;
1354                 default:
1355                         break;
1356                 }
1357         }
1358 }
1359
1360 void NvSetupOutputs(ScrnInfoPtr pScrn)
1361 {
1362         NVPtr pNv = NVPTR(pScrn);
1363
1364         pNv->Television = FALSE;
1365
1366         memset(pNv->pI2CBus, 0, sizeof(pNv->pI2CBus));
1367         NvDCBSetupOutputs(pScrn);
1368 }
1369
1370 /*************************************************************************** \
1371 |*                                                                           *|
1372 |*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
1373 |*                                                                           *|
1374 |*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
1375 |*     international laws.  Users and possessors of this source code are     *|
1376 |*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
1377 |*     use this code in individual and commercial software.                  *|
1378 |*                                                                           *|
1379 |*     Any use of this source code must include,  in the user documenta-     *|
1380 |*     tion and  internal comments to the code,  notices to the end user     *|
1381 |*     as follows:                                                           *|
1382 |*                                                                           *|
1383 |*       Copyright 1993-1999 NVIDIA, Corporation.  All rights reserved.      *|
1384 |*                                                                           *|
1385 |*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
1386 |*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
1387 |*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
1388 |*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
1389 |*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
1390 |*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
1391 |*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
1392 |*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
1393 |*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
1394 |*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
1395 |*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
1396 |*                                                                           *|
1397 |*     U.S. Government  End  Users.   This source code  is a "commercial     *|
1398 |*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
1399 |*     consisting  of "commercial  computer  software"  and  "commercial     *|
1400 |*     computer  software  documentation,"  as such  terms  are  used in     *|
1401 |*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
1402 |*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
1403 |*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
1404 |*     all U.S. Government End Users  acquire the source code  with only     *|
1405 |*     those rights set forth herein.                                        *|
1406 |*                                                                           *|
1407  \***************************************************************************/