Merge branch 'randr-1.2' into nv50-branch
[nouveau] / src / nv_output.c
1 /*
2  * Copyright 2006 Dave Airlie
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *  Dave Airlie
25  */
26 /*
27  * this code uses ideas taken from the NVIDIA nv driver - the nvidia license
28  * decleration is at the bottom of this file as it is rather ugly 
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "xf86.h"
36 #include "os.h"
37 #include "mibank.h"
38 #include "globals.h"
39 #include "xf86.h"
40 #include "xf86Priv.h"
41 #include "xf86DDC.h"
42 #include "mipointer.h"
43 #include "windowstr.h"
44 #include <randrstr.h>
45 #include <X11/extensions/render.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 void NVOutputWriteRAMDAC(xf86OutputPtr output, CARD32 ramdac_reg, CARD32 val)
70 {
71     NVOutputPrivatePtr nv_output = output->driver_private;
72     ScrnInfoPtr pScrn = output->scrn;
73     NVPtr pNv = NVPTR(pScrn);
74
75     nvWriteRAMDAC(pNv, nv_output->ramdac, ramdac_reg, val);
76 }
77
78 CARD32 NVOutputReadRAMDAC(xf86OutputPtr output, CARD32 ramdac_reg)
79 {
80     NVOutputPrivatePtr nv_output = output->driver_private;
81     ScrnInfoPtr pScrn = output->scrn;
82     NVPtr pNv = NVPTR(pScrn);
83
84     return nvReadRAMDAC(pNv, nv_output->ramdac, ramdac_reg);
85 }
86
87 static void nv_output_backlight_enable(xf86OutputPtr output,  Bool on)
88 {
89     ScrnInfoPtr pScrn = output->scrn;
90     NVPtr pNv = NVPTR(pScrn);   
91
92     /* This is done differently on each laptop.  Here we
93        define the ones we know for sure. */
94     
95 #if defined(__powerpc__)
96     if((pNv->Chipset == 0x10DE0179) || 
97        (pNv->Chipset == 0x10DE0189) || 
98        (pNv->Chipset == 0x10DE0329))
99     {
100         /* NV17,18,34 Apple iMac, iBook, PowerBook */
101         CARD32 tmp_pmc, tmp_pcrt;
102         tmp_pmc = nvReadMC(pNv, 0x10F0) & 0x7FFFFFFF;
103         tmp_pcrt = nvReadCRTC0(pNv, NV_CRTC_081C) & 0xFFFFFFFC;
104         if(on) {
105             tmp_pmc |= (1 << 31);
106             tmp_pcrt |= 0x1;
107         }
108         nvWriteMC(pNv, 0x10F0, tmp_pmc);
109         nvWriteCRTC0(pNv, NV_CRTC_081C, tmp_pcrt);
110     }
111 #endif
112     
113     if(pNv->twoHeads && ((pNv->Chipset & 0x0ff0) != CHIPSET_NV11))
114         nvWriteMC(pNv, 0x130C, on ? 3 : 7);
115 }
116
117 static void
118 nv_panel_output_dpms(xf86OutputPtr output, int mode)
119 {
120
121     switch(mode) {
122     case DPMSModeStandby:
123     case DPMSModeSuspend:
124     case DPMSModeOff:
125         nv_output_backlight_enable(output, 0);
126         break;
127     case DPMSModeOn:
128         nv_output_backlight_enable(output, 1);
129     default:
130         break;
131     }
132 }
133
134 static void
135 nv_analog_output_dpms(xf86OutputPtr output, int mode)
136 {
137
138 }
139
140 static void
141 nv_digital_output_dpms(xf86OutputPtr output, int mode)
142 {
143     NVOutputPrivatePtr nv_output = output->driver_private;
144     xf86CrtcPtr crtc = output->crtc;
145     ScrnInfoPtr pScrn = output->scrn;
146     NVPtr pNv = NVPTR(pScrn);
147     NVCrtcPrivatePtr nv_crtc;
148
149     CARD32 fpcontrol;
150     
151     if (crtc)  {
152         nv_crtc = crtc->driver_private;
153         
154         fpcontrol = nvReadRAMDAC(pNv, nv_crtc->crtc, NV_RAMDAC_FP_CONTROL) & 0xCfffffCC;        
155         switch(mode) {
156         case DPMSModeStandby:
157         case DPMSModeSuspend:
158         case DPMSModeOff:
159             /* cut the TMDS output */       
160             fpcontrol |= 0x20000022;
161             break;
162         case DPMSModeOn:
163             fpcontrol |= nv_output->fpSyncs;
164         }
165         
166         nvWriteRAMDAC(pNv, nv_crtc->crtc, NV_RAMDAC_FP_CONTROL, fpcontrol);
167     }
168 }
169
170 void nv_output_save_state_ext(xf86OutputPtr output, RIVA_HW_STATE *state)
171 {
172     NVOutputPrivatePtr nv_output = output->driver_private;
173     ScrnInfoPtr pScrn = output->scrn;
174     NVPtr pNv = NVPTR(pScrn);
175     NVOutputRegPtr regp;
176
177     regp = &state->dac_reg[nv_output->ramdac];
178     regp->general       = NVOutputReadRAMDAC(output, NV_RAMDAC_GENERAL_CONTROL);
179     regp->fp_control    = NVOutputReadRAMDAC(output, NV_RAMDAC_FP_CONTROL);
180     regp->debug_0       = NVOutputReadRAMDAC(output, NV_RAMDAC_FP_DEBUG_0);
181     state->config       = nvReadFB(pNv, NV_PFB_CFG0);
182     
183     regp->output = NVOutputReadRAMDAC(output, NV_RAMDAC_OUTPUT);
184     
185     if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {
186         regp->dither = NVOutputReadRAMDAC(output, NV_RAMDAC_DITHER_NV11);
187     } else if(pNv->twoHeads) {
188         regp->dither = NVOutputReadRAMDAC(output, NV_RAMDAC_FP_DITHER);
189     }
190     //    regp->crtcSync = NVOutputReadRAMDAC(output, NV_RAMDAC_FP_HCRTC);
191     regp->nv10_cursync = NVOutputReadRAMDAC(output, NV_RAMDAC_NV10_CURSYNC);
192
193     if (nv_output->type == OUTPUT_DIGITAL) {
194         int i;
195
196         for (i = 0; i < 7; i++) {
197             uint32_t ramdac_reg = NV_RAMDAC_FP_HDISP_END + (i * 4);
198             
199             regp->fp_horiz_regs[i] = NVOutputReadRAMDAC(output, ramdac_reg);
200         }
201         
202         for (i = 0; i < 7; i++) {
203             uint32_t ramdac_reg = NV_RAMDAC_FP_VDISP_END + (i * 4);
204             
205             regp->fp_vert_regs[i] = NVOutputReadRAMDAC(output, ramdac_reg);
206         }
207     }
208
209 }
210
211 void nv_output_load_state_ext(xf86OutputPtr output, RIVA_HW_STATE *state)
212 {
213     NVOutputPrivatePtr nv_output = output->driver_private;
214     ScrnInfoPtr pScrn = output->scrn;
215     NVPtr pNv = NVPTR(pScrn);
216     NVOutputRegPtr regp;
217   
218     regp = &state->dac_reg[nv_output->ramdac];
219   
220     NVOutputWriteRAMDAC(output, NV_RAMDAC_FP_DEBUG_0, regp->debug_0);
221     NVOutputWriteRAMDAC(output, NV_RAMDAC_OUTPUT, regp->output);
222     NVOutputWriteRAMDAC(output, NV_RAMDAC_FP_CONTROL, regp->fp_control);
223     //    NVOutputWriteRAMDAC(output, NV_RAMDAC_FP_HCRTC, regp->crtcSync);
224   
225
226     if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {
227         NVOutputWriteRAMDAC(output, NV_RAMDAC_DITHER_NV11, regp->dither);
228     } else if(pNv->twoHeads) {
229         NVOutputWriteRAMDAC(output, NV_RAMDAC_FP_DITHER, regp->dither);
230     }
231   
232     NVOutputWriteRAMDAC(output, NV_RAMDAC_GENERAL_CONTROL, regp->general);
233     NVOutputWriteRAMDAC(output, NV_RAMDAC_NV10_CURSYNC, regp->nv10_cursync);
234
235     if (nv_output->type == OUTPUT_DIGITAL) {
236         int i;
237
238         for (i = 0; i < 7; i++) {
239             uint32_t ramdac_reg = NV_RAMDAC_FP_HDISP_END + (i * 4);
240             NVOutputWriteRAMDAC(output, ramdac_reg, regp->fp_horiz_regs[i]);
241         }
242         
243         for (i = 0; i < 7; i++) {
244             uint32_t ramdac_reg = NV_RAMDAC_FP_VDISP_END + (i * 4);
245             
246             NVOutputWriteRAMDAC(output, ramdac_reg, regp->fp_vert_regs[i]);
247         }
248     }
249
250 }
251
252
253 static void
254 nv_output_save (xf86OutputPtr output)
255 {
256     ScrnInfoPtr pScrn = output->scrn;
257     NVPtr pNv = NVPTR(pScrn);
258     RIVA_HW_STATE *state;
259   
260     state = &pNv->SavedReg;
261   
262     nv_output_save_state_ext(output, state);    
263   
264 }
265
266 static void
267 nv_output_restore (xf86OutputPtr output)
268 {
269     ScrnInfoPtr pScrn = output->scrn;
270     NVPtr pNv = NVPTR(pScrn);
271     RIVA_HW_STATE *state;
272   
273     state = &pNv->SavedReg;
274   
275     nv_output_load_state_ext(output, state);
276 }
277
278 static int
279 nv_output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
280 {
281     if (pMode->Flags & V_DBLSCAN)
282         return MODE_NO_DBLESCAN;
283   
284     if (pMode->Clock > 400000 || pMode->Clock < 25000)
285         return MODE_CLOCK_RANGE;
286   
287     return MODE_OK;
288 }
289
290
291 static Bool
292 nv_output_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
293                      DisplayModePtr adjusted_mode)
294 {
295     return TRUE;
296 }
297
298 static int
299 nv_output_tweak_panel(xf86OutputPtr output, NVRegPtr state)
300 {
301     NVOutputPrivatePtr nv_output = output->driver_private;
302     ScrnInfoPtr pScrn = output->scrn;
303     NVPtr pNv = NVPTR(pScrn);
304     NVOutputRegPtr regp;
305     int tweak = 0;
306   
307     regp = &state->dac_reg[nv_output->ramdac];
308     if (pNv->usePanelTweak) {
309         tweak = pNv->PanelTweak;
310     } else {
311         /* begin flat panel hacks */
312         /* This is unfortunate, but some chips need this register
313            tweaked or else you get artifacts where adjacent pixels are
314            swapped.  There are no hard rules for what to set here so all
315            we can do is experiment and apply hacks. */
316     
317         if(((pNv->Chipset & 0xffff) == 0x0328) && (regp->bpp == 32)) {
318             /* At least one NV34 laptop needs this workaround. */
319             tweak = -1;
320         }
321                 
322         if((pNv->Chipset & 0xfff0) == CHIPSET_NV31) {
323             tweak = 1;
324         }
325         /* end flat panel hacks */
326     }
327     return tweak;
328 }
329
330 static void
331 nv_output_mode_set_regs(xf86OutputPtr output, DisplayModePtr mode)
332 {
333     NVOutputPrivatePtr nv_output = output->driver_private;
334     ScrnInfoPtr pScrn = output->scrn;
335     int bpp;
336     NVPtr pNv = NVPTR(pScrn);
337     NVFBLayout *pLayout = &pNv->CurrentLayout;
338     RIVA_HW_STATE *state, *sv_state;
339     Bool is_fp = FALSE;
340     NVOutputRegPtr regp, savep;
341     xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
342     int i;
343
344     state = &pNv->ModeReg;
345     regp = &state->dac_reg[nv_output->ramdac];
346
347     sv_state = &pNv->SavedReg;
348     savep = &sv_state->dac_reg[nv_output->ramdac];
349             
350     if ((nv_output->type == OUTPUT_PANEL) || (nv_output->type == OUTPUT_DIGITAL))
351     {
352         is_fp = TRUE;
353
354         for (i = 0; i < 7; i++) {
355             regp->fp_horiz_regs[i] = savep->fp_horiz_regs[i];
356             regp->fp_vert_regs[i] = savep->fp_vert_regs[i];
357         }
358
359         regp->fp_horiz_regs[REG_DISP_END] = mode->CrtcHDisplay - 1;
360         regp->fp_horiz_regs[REG_DISP_TOTAL] = mode->CrtcHTotal - 1;
361         regp->fp_horiz_regs[REG_DISP_CRTC] = mode->CrtcHDisplay;
362         regp->fp_horiz_regs[REG_DISP_SYNC_START] = mode->CrtcHSyncStart - 1;
363         regp->fp_horiz_regs[REG_DISP_SYNC_END] = mode->CrtcHSyncEnd - 1;
364         regp->fp_horiz_regs[REG_DISP_VALID_START] = mode->CrtcHSkew;
365         regp->fp_horiz_regs[REG_DISP_VALID_END] = mode->CrtcHDisplay - 1;
366         
367         regp->fp_vert_regs[REG_DISP_END] = mode->CrtcVDisplay - 1;
368         regp->fp_vert_regs[REG_DISP_TOTAL] = mode->CrtcVTotal - 1;
369         regp->fp_vert_regs[REG_DISP_CRTC] = mode->CrtcVDisplay;
370         regp->fp_vert_regs[REG_DISP_SYNC_START] = mode->CrtcVSyncStart - 1;
371         regp->fp_vert_regs[REG_DISP_SYNC_END] = mode->CrtcVSyncEnd - 1;
372         regp->fp_vert_regs[REG_DISP_VALID_START] = 0;
373         regp->fp_vert_regs[REG_DISP_VALID_END] = mode->CrtcVDisplay - 1;
374     
375     }
376
377     if (pNv->Architecture >= NV_ARCH_10) 
378         regp->nv10_cursync = savep->nv10_cursync | (1<<25);
379
380     regp->bpp    = bpp;    /* this is not bitsPerPixel, it's 8,15,16,32 */
381
382     regp->debug_0 = savep->debug_0;
383     regp->fp_control = savep->fp_control & 0xfff000ff;
384     if(is_fp == 1) {
385         if(!pNv->fpScaler || (nv_output->fpWidth <= mode->HDisplay)
386            || (nv_output->fpHeight <= mode->VDisplay))
387         {
388             regp->fp_control |= (1 << 8) ;
389         }
390         regp->crtcSync = savep->crtcSync;
391         regp->crtcSync += nv_output_tweak_panel(output, state);
392
393         regp->debug_0 &= ~NV_RAMDAC_FP_DEBUG_0_PWRDOWN_BOTH;
394     }
395     else
396         regp->debug_0 |= NV_RAMDAC_FP_DEBUG_0_PWRDOWN_BOTH;
397
398     ErrorF("output %d debug_0 %08X\n", nv_output->ramdac, regp->debug_0);
399
400     if(pNv->twoHeads) {
401         if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {
402             regp->dither = savep->dither & ~0x00010000;
403             if(pNv->FPDither)
404                 regp->dither |= 0x00010000;
405         } else {
406             ErrorF("savep->dither %08X\n", savep->dither);
407             regp->dither = savep->dither & ~1;
408             if(pNv->FPDither)
409                 regp->dither |= 1;
410         } 
411     }
412
413     if(pLayout->depth < 24) 
414         bpp = pLayout->depth;
415     else bpp = 32;    
416
417     regp->general  = bpp == 16 ? 0x00101100 : 0x00100100;
418
419     if (pNv->alphaCursor)
420         regp->general |= (1<<29);
421
422     if(bpp != 8) /* DirectColor */
423         regp->general |= 0x00000030;
424
425     if (output->crtc) {
426         NVCrtcPrivatePtr nv_crtc = output->crtc->driver_private;
427         int two_crt = FALSE;
428         int two_mon = FALSE;
429
430         for (i = 0; i < config->num_output; i++) {
431             NVOutputPrivatePtr nv_output2 = config->output[i]->driver_private;
432
433             /* is it this output ?? */
434             if (config->output[i] == output)
435                 continue;
436
437             /* it the output connected */
438             if (config->output[i]->crtc == NULL)
439                 continue;
440
441             two_mon = TRUE;
442             if ((nv_output2->type == OUTPUT_ANALOG) && (nv_output->type == OUTPUT_ANALOG))
443                 two_crt = TRUE;
444         }
445
446         if (is_fp == TRUE)
447             regp->output = 0x0;
448         else 
449             regp->output = NV_RAMDAC_OUTPUT_DAC_ENABLE;
450
451         if (nv_crtc->crtc == 1 && two_mon)
452           regp->output |= NV_RAMDAC_OUTPUT_SELECT_CRTC2;
453
454         ErrorF("%d: crtc %d output%d: %04X: twocrt %d twomon %d\n", is_fp, nv_crtc->crtc, nv_output->ramdac, regp->output, two_crt, two_mon);
455     }
456 }
457
458 static void
459 nv_output_mode_set(xf86OutputPtr output, DisplayModePtr mode,
460                    DisplayModePtr adjusted_mode)
461 {
462     ScrnInfoPtr pScrn = output->scrn;
463     NVPtr pNv = NVPTR(pScrn);
464     RIVA_HW_STATE *state;
465
466     state = &pNv->ModeReg;
467
468     nv_output_mode_set_regs(output, mode);
469     nv_output_load_state_ext(output, state);
470 }
471
472 static Bool
473 nv_ddc_detect(xf86OutputPtr output)
474 {
475     /* no use for shared DDC output */
476     NVOutputPrivatePtr nv_output = output->driver_private;
477     xf86MonPtr ddc_mon;
478
479     ddc_mon = xf86OutputGetEDID(output, nv_output->pDDCBus);
480     if (!ddc_mon)
481         return 0;
482
483     if (ddc_mon->features.input_type && (nv_output->type == OUTPUT_ANALOG))
484         return 0;
485
486     if ((!ddc_mon->features.input_type) && (nv_output->type == OUTPUT_DIGITAL))
487         return 0;
488
489     return 1;
490 }
491
492 static Bool
493 nv_crt_load_detect(xf86OutputPtr output)
494 {
495     ScrnInfoPtr pScrn = output->scrn;
496     CARD32 reg_output, reg_test_ctrl, temp;
497     int present = FALSE;
498           
499     reg_output = NVOutputReadRAMDAC(output, NV_RAMDAC_OUTPUT);
500     reg_test_ctrl = NVOutputReadRAMDAC(output, NV_RAMDAC_TEST_CONTROL);
501
502     NVOutputWriteRAMDAC(output, NV_RAMDAC_TEST_CONTROL, (reg_test_ctrl & ~0x00010000));
503     
504     NVOutputWriteRAMDAC(output, NV_RAMDAC_OUTPUT, (reg_output & 0x0000FEEE));
505     usleep(1000);
506           
507     temp = NVOutputReadRAMDAC(output, NV_RAMDAC_OUTPUT);
508     NVOutputWriteRAMDAC(output, NV_RAMDAC_OUTPUT, temp | 1);
509
510     NVOutputWriteRAMDAC(output, NV_RAMDAC_TEST_DATA, 0x94050140);
511     temp = NVOutputReadRAMDAC(output, NV_RAMDAC_TEST_CONTROL);
512     NVOutputWriteRAMDAC(output, NV_RAMDAC_TEST_CONTROL, temp | 0x1000);
513
514     usleep(1000);
515           
516     present = (NVOutputReadRAMDAC(output, NV_RAMDAC_TEST_CONTROL) & (1 << 28)) ? TRUE : FALSE;
517           
518     temp = NVOutputReadRAMDAC(output, NV_RAMDAC_TEST_CONTROL);
519     NVOutputWriteRAMDAC(output, NV_RAMDAC_TEST_CONTROL, temp & 0x000EFFF);
520           
521     NVOutputWriteRAMDAC(output, NV_RAMDAC_OUTPUT, reg_output);
522     NVOutputWriteRAMDAC(output, NV_RAMDAC_TEST_CONTROL, reg_test_ctrl);
523     
524     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT detect returned %d\n",
525                present);
526
527     return present;
528
529 }
530
531 static xf86OutputStatus
532 nv_digital_output_detect(xf86OutputPtr output)
533 {
534     NVOutputPrivatePtr nv_output = output->driver_private;
535
536     if (nv_ddc_detect(output))
537         return XF86OutputStatusConnected;
538
539     return XF86OutputStatusDisconnected;
540 }
541
542
543 static xf86OutputStatus
544 nv_analog_output_detect(xf86OutputPtr output)
545 {
546     NVOutputPrivatePtr nv_output = output->driver_private;
547
548     if (nv_ddc_detect(output))
549         return XF86OutputStatusConnected;
550
551     /* seems a bit flaky on ramdac 1 */
552     if ((nv_output->ramdac==0) && nv_crt_load_detect(output))
553         return XF86OutputStatusConnected;
554     
555     return XF86OutputStatusDisconnected;
556 }
557
558 static DisplayModePtr
559 nv_output_get_modes(xf86OutputPtr output)
560 {
561     ScrnInfoPtr pScrn = output->scrn;
562     NVOutputPrivatePtr nv_output = output->driver_private;
563     xf86MonPtr ddc_mon;
564     DisplayModePtr ddc_modes, mode;
565     int i;
566
567
568     ddc_mon = xf86OutputGetEDID(output, nv_output->pDDCBus);
569
570     if (ddc_mon == NULL) {
571         xf86OutputSetEDID(output, ddc_mon);
572         return NULL;
573     }
574
575     if (ddc_mon->features.input_type && (nv_output->type == OUTPUT_ANALOG)) {
576         xf86OutputSetEDID(output, NULL);
577         return NULL;
578     }
579
580     if ((!ddc_mon->features.input_type) && (nv_output->type == OUTPUT_DIGITAL)) {
581         xf86OutputSetEDID(output, NULL);
582         return NULL;
583     }
584
585     xf86OutputSetEDID(output, ddc_mon);
586
587     ddc_modes = xf86OutputGetEDIDModes (output);          
588     return ddc_modes;
589
590 }
591
592 static void
593 nv_output_destroy (xf86OutputPtr output)
594 {
595     if (output->driver_private)
596         xfree (output->driver_private);
597
598 }
599
600 static void
601 nv_output_prepare(xf86OutputPtr output)
602 {
603
604 }
605
606 static void
607 nv_output_commit(xf86OutputPtr output)
608 {
609
610
611 }
612
613 static const xf86OutputFuncsRec nv_analog_output_funcs = {
614     .dpms = nv_analog_output_dpms,
615     .save = nv_output_save,
616     .restore = nv_output_restore,
617     .mode_valid = nv_output_mode_valid,
618     .mode_fixup = nv_output_mode_fixup,
619     .mode_set = nv_output_mode_set,
620     .detect = nv_analog_output_detect,
621     .get_modes = nv_output_get_modes,
622     .destroy = nv_output_destroy,
623     .prepare = nv_output_prepare,
624     .commit = nv_output_commit,
625 };
626
627 static const xf86OutputFuncsRec nv_digital_output_funcs = {
628     .dpms = nv_digital_output_dpms,
629     .save = nv_output_save,
630     .restore = nv_output_restore,
631     .mode_valid = nv_output_mode_valid,
632     .mode_fixup = nv_output_mode_fixup,
633     .mode_set = nv_output_mode_set,
634     .detect = nv_digital_output_detect,
635     .get_modes = nv_output_get_modes,
636     .destroy = nv_output_destroy,
637     .prepare = nv_output_prepare,
638     .commit = nv_output_commit,
639 };
640
641 static xf86OutputStatus
642 nv_output_lvds_detect(xf86OutputPtr output)
643 {
644     return XF86OutputStatusUnknown;    
645 }
646
647 static DisplayModePtr
648 nv_output_lvds_get_modes(xf86OutputPtr output)
649 {
650     ScrnInfoPtr pScrn = output->scrn;
651     NVOutputPrivatePtr nv_output = output->driver_private;
652
653     //    nv_output->fpWidth = NVOutputReadRAMDAC(output, NV_RAMDAC_FP_HDISP_END) + 1;
654     //    nv_output->fpHeight = NVOutputReadRAMDAC(output, NV_RAMDAC_FP_VDISP_END) + 1;
655     nv_output->fpSyncs = NVOutputReadRAMDAC(output, NV_RAMDAC_FP_CONTROL) & 0x30000033;
656     //    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel size is %i x %i\n",
657     //         nv_output->fpWidth, nv_output->fpHeight);
658
659     return NULL;
660
661 }
662
663 static const xf86OutputFuncsRec nv_lvds_output_funcs = {
664     .dpms = nv_panel_output_dpms,
665     .save = nv_output_save,
666     .restore = nv_output_restore,
667     .mode_valid = nv_output_mode_valid,
668     .mode_fixup = nv_output_mode_fixup,
669     .mode_set = nv_output_mode_set,
670     .detect = nv_output_lvds_detect,
671     .get_modes = nv_output_lvds_get_modes,
672     .destroy = nv_output_destroy,
673     .prepare = nv_output_prepare,
674     .commit = nv_output_commit,
675 };
676
677
678 static void nv_add_analog_output(ScrnInfoPtr pScrn, int i2c_index)
679 {
680   NVPtr pNv = NVPTR(pScrn);
681   xf86OutputPtr     output;
682   NVOutputPrivatePtr    nv_output;
683   char outputname[20];
684   int   crtc_mask = (1<<0) | (1<<1);
685
686   sprintf(outputname, "Analog-%d", pNv->analog_count);
687   output = xf86OutputCreate (pScrn, &nv_analog_output_funcs, outputname);
688   if (!output)
689     return;
690   nv_output = xnfcalloc (sizeof (NVOutputPrivateRec), 1);
691   if (!nv_output)
692   {
693     xf86OutputDestroy (output);
694     return;
695   }
696   
697   output->driver_private = nv_output;
698   nv_output->type = OUTPUT_ANALOG;
699
700   nv_output->ramdac = pNv->analog_count;
701
702   nv_output->pDDCBus = pNv->pI2CBus[i2c_index];
703
704   output->possible_crtcs = crtc_mask;
705   xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Adding output %s\n", outputname);
706   
707   pNv->analog_count++;
708 }
709
710
711 static void nv_add_digital_output(ScrnInfoPtr pScrn, int i2c_index)
712 {
713   NVPtr pNv = NVPTR(pScrn);
714   xf86OutputPtr     output;
715   NVOutputPrivatePtr    nv_output;
716   char outputname[20];
717   int   crtc_mask = (1<<0) | (1<<1);
718
719   sprintf(outputname, "Digital-%d", pNv->digital_count);
720   output = xf86OutputCreate (pScrn, &nv_digital_output_funcs, outputname);
721   if (!output)
722     return;
723   nv_output = xnfcalloc (sizeof (NVOutputPrivateRec), 1);
724   if (!nv_output)
725   {
726     xf86OutputDestroy (output);
727     return;
728   }
729   
730   output->driver_private = nv_output;
731   nv_output->type = OUTPUT_DIGITAL;
732   
733   nv_output->ramdac = pNv->digital_count;
734   
735   nv_output->pDDCBus = pNv->pI2CBus[i2c_index];
736   
737   output->possible_crtcs = crtc_mask;
738   xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Adding output %s\n", outputname);
739
740   pNv->digital_count++;
741 }
742 /**
743  * Set up the outputs according to what type of chip we are.
744  *
745  * Some outputs may not initialize, due to allocation failure or because a
746  * controller chip isn't found.
747  */
748
749 void Nv20SetupOutputs(ScrnInfoPtr pScrn)
750 {
751     NVPtr pNv = NVPTR(pScrn);
752     xf86OutputPtr           output;
753     NVOutputPrivatePtr    nv_output;
754     int i;
755     int num_analog_outputs = pNv->twoHeads ? 2 : 1;
756     int num_digital_outputs = 1;
757
758     for (i = 0 ; i < num_analog_outputs; i++) {
759       nv_add_analog_output(pScrn, i);
760     }
761
762     for (i = 0 ; i < num_digital_outputs; i++) {
763       nv_add_digital_output(pScrn, i);
764     }
765 }
766
767 void NvDCBSetupOutputs(ScrnInfoPtr pScrn)
768 {
769   unsigned char type, port, or;
770   NVPtr pNv = NVPTR(pScrn);
771   int i;
772
773   /* we setup the outputs up from the BIOS table */
774   if (pNv->dcb_entries) {
775     for (i = 0 ; i < pNv->dcb_entries; i++) {
776       type = pNv->dcb_table[i] & 0xf;
777       port = (pNv->dcb_table[i] >> 4) & 0xf;
778       or = ffs((pNv->dcb_table[i] >> 24) & 0xf) - 1;
779      
780       if (type < 4)
781         xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DCB entry: %d: %08X type: %d, port %d:, or %d\n", i, pNv->dcb_table[i], type, port, or);
782       if (type < 4 && port != 0xf) {
783         switch(type) {
784         case 0: /* analog */
785           nv_add_analog_output(pScrn, port);
786           break;
787         case 2:
788           nv_add_digital_output(pScrn, port);
789         default:
790           break;
791         }
792       }
793     }
794   } else
795     Nv20SetupOutputs(pScrn);
796
797 }
798
799 struct nv_i2c_struct {
800     int reg;
801     char *name;
802 } nv_i2c_buses[] = { 
803     { 0x3e, "DDC1" },
804     { 0x36, "DDC2" },
805     { 0x50, "TV" },
806 };
807
808
809 void NvSetupOutputs(ScrnInfoPtr pScrn)
810 {
811     int i;
812     NVPtr pNv = NVPTR(pScrn);
813     xf86OutputPtr           output;
814     NVOutputPrivatePtr    nv_output;
815
816     int num_outputs = pNv->twoHeads ? 2 : 1;
817     char outputname[20];
818     pNv->Television = FALSE;
819
820     /* add the 3 I2C buses */
821     for (i = 0; i < NV_I2C_BUSES; i++) {
822         NV_I2CInit(pScrn, &pNv->pI2CBus[i], nv_i2c_buses[i].reg, nv_i2c_buses[i].name);
823     }
824
825     NvDCBSetupOutputs(pScrn);
826
827 #if 0
828     if (pNv->Mobile) {
829         output = xf86OutputCreate(pScrn, &nv_output_funcs, OutputType[OUTPUT_LVDS]);
830         if (!output)
831             return;
832
833         nv_output = xnfcalloc(sizeof(NVOutputPrivateRec), 1);
834         if (!nv_output) {
835             xf86OutputDestroy(output);
836             return;
837         }
838
839         output->driver_private = nv_output;
840         nv_output->type = output_type;
841
842         output->possible_crtcs = i ? 1 : crtc_mask;
843     }
844 #endif
845 }
846
847
848 /*************************************************************************** \
849 |*                                                                           *|
850 |*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
851 |*                                                                           *|
852 |*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
853 |*     international laws.  Users and possessors of this source code are     *|
854 |*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
855 |*     use this code in individual and commercial software.                  *|
856 |*                                                                           *|
857 |*     Any use of this source code must include,  in the user documenta-     *|
858 |*     tion and  internal comments to the code,  notices to the end user     *|
859 |*     as follows:                                                           *|
860 |*                                                                           *|
861 |*       Copyright 1993-1999 NVIDIA, Corporation.  All rights reserved.      *|
862 |*                                                                           *|
863 |*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
864 |*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
865 |*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
866 |*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
867 |*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
868 |*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
869 |*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
870 |*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
871 |*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
872 |*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
873 |*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
874 |*                                                                           *|
875 |*     U.S. Government  End  Users.   This source code  is a "commercial     *|
876 |*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
877 |*     consisting  of "commercial  computer  software"  and  "commercial     *|
878 |*     computer  software  documentation,"  as such  terms  are  used in     *|
879 |*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
880 |*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
881 |*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
882 |*     all U.S. Government End Users  acquire the source code  with only     *|
883 |*     those rights set forth herein.                                        *|
884 |*                                                                           *|
885  \***************************************************************************/