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