minor link_head_and_output cleanup
[nouveau] / src / nv_dac.c
1  /***************************************************************************\
2 |*                                                                           *|
3 |*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
4 |*                                                                           *|
5 |*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
6 |*     international laws.  Users and possessors of this source code are     *|
7 |*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
8 |*     use this code in individual and commercial software.                  *|
9 |*                                                                           *|
10 |*     Any use of this source code must include,  in the user documenta-     *|
11 |*     tion and  internal comments to the code,  notices to the end user     *|
12 |*     as follows:                                                           *|
13 |*                                                                           *|
14 |*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
15 |*                                                                           *|
16 |*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
17 |*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
18 |*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
19 |*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
20 |*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
21 |*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
22 |*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
23 |*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
24 |*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
25 |*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
26 |*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
27 |*                                                                           *|
28 |*     U.S. Government  End  Users.   This source code  is a "commercial     *|
29 |*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
30 |*     consisting  of "commercial  computer  software"  and  "commercial     *|
31 |*     computer  software  documentation,"  as such  terms  are  used in     *|
32 |*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
33 |*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
34 |*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
35 |*     all U.S. Government End Users  acquire the source code  with only     *|
36 |*     those rights set forth herein.                                        *|
37 |*                                                                           *|
38  \***************************************************************************/
39
40 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_dac.c,v 1.45 2005/07/09 00:53:00 mvojkovi Exp $ */
41
42 #include "nv_include.h"
43
44 static int
45 NVDACPanelTweaks(NVPtr pNv, NVRegPtr state)
46 {
47    int tweak = 0;
48
49    if(pNv->usePanelTweak) {
50        tweak = pNv->PanelTweak;
51    } else {
52        /* begin flat panel hacks */
53        /* This is unfortunate, but some chips need this register
54           tweaked or else you get artifacts where adjacent pixels are
55           swapped.  There are no hard rules for what to set here so all
56           we can do is experiment and apply hacks. */
57
58        if(((pNv->Chipset & 0xffff) == 0x0328) && (state->bpp == 32)) {
59           /* At least one NV34 laptop needs this workaround. */
60           tweak = -1;
61        }
62
63        if((pNv->Chipset & 0xfff0) == CHIPSET_NV31) {
64           tweak = 1;
65        }
66        /* end flat panel hacks */
67    }
68
69    return tweak;
70 }
71
72 Bool
73 NVDACInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
74 {
75     int i;
76     int horizDisplay    = (mode->CrtcHDisplay/8)   - 1;
77     int horizStart      = (mode->CrtcHSyncStart/8) - 1;
78     int horizEnd        = (mode->CrtcHSyncEnd/8)   - 1;
79     int horizTotal      = (mode->CrtcHTotal/8)     - 5;
80     int horizBlankStart = (mode->CrtcHDisplay/8)   - 1;
81     int horizBlankEnd   = (mode->CrtcHTotal/8)     - 1;
82     int vertDisplay     =  mode->CrtcVDisplay      - 1;
83     int vertStart       =  mode->CrtcVSyncStart    - 1;
84     int vertEnd         =  mode->CrtcVSyncEnd      - 1;
85     int vertTotal       =  mode->CrtcVTotal        - 2;
86     int vertBlankStart  =  mode->CrtcVDisplay      - 1;
87     int vertBlankEnd    =  mode->CrtcVTotal        - 1;
88    
89     NVPtr pNv = NVPTR(pScrn);
90     NVRegPtr nvReg = &pNv->ModeReg;
91     NVFBLayout *pLayout = &pNv->CurrentLayout;
92     vgaRegPtr   pVga;
93
94     /*
95      * Initialize all of the generic VGA registers.  Don't bother with
96      * VGA_FIX_SYNC_PULSES, given the relevant CRTC settings are overridden
97      * below.  Ditto for the KGA workaround.
98      */
99     if (!vgaHWInit(pScrn, mode))
100         return(FALSE);
101
102     pVga = &VGAHWPTR(pScrn)->ModeReg;
103
104     /*
105      * Set all CRTC values.
106      */
107
108     if(mode->Flags & V_INTERLACE) 
109         vertTotal |= 1;
110
111     if(pNv->FlatPanel == 1) {
112         vertStart = vertTotal - 3;  
113         vertEnd = vertTotal - 2;
114         vertBlankStart = vertStart;
115         horizStart = horizTotal - 5;
116         horizEnd = horizTotal - 2;   
117         horizBlankEnd = horizTotal + 4;   
118         if ( pNv->Architecture == NV_ARCH_30 || pNv->Architecture == NV_ARCH_20 || pNv->Architecture == NV_ARCH_10 )    { 
119                 /* This reportedly works around Xv some overlay bandwidth problems*/
120                 horizTotal += 2;
121                 }
122     }
123
124     pVga->CRTC[0x0]  = Set8Bits(horizTotal);
125     pVga->CRTC[0x1]  = Set8Bits(horizDisplay);
126     pVga->CRTC[0x2]  = Set8Bits(horizBlankStart);
127     pVga->CRTC[0x3]  = SetBitField(horizBlankEnd,4:0,4:0) 
128                        | SetBit(7);
129     pVga->CRTC[0x4]  = Set8Bits(horizStart);
130     pVga->CRTC[0x5]  = SetBitField(horizBlankEnd,5:5,7:7)
131                        | SetBitField(horizEnd,4:0,4:0);
132     pVga->CRTC[0x6]  = SetBitField(vertTotal,7:0,7:0);
133     pVga->CRTC[0x7]  = SetBitField(vertTotal,8:8,0:0)
134                        | SetBitField(vertDisplay,8:8,1:1)
135                        | SetBitField(vertStart,8:8,2:2)
136                        | SetBitField(vertBlankStart,8:8,3:3)
137                        | SetBit(4)
138                        | SetBitField(vertTotal,9:9,5:5)
139                        | SetBitField(vertDisplay,9:9,6:6)
140                        | SetBitField(vertStart,9:9,7:7);
141     pVga->CRTC[0x9]  = SetBitField(vertBlankStart,9:9,5:5)
142                        | SetBit(6)
143                        | ((mode->Flags & V_DBLSCAN) ? 0x80 : 0x00);
144     pVga->CRTC[0x10] = Set8Bits(vertStart);
145     pVga->CRTC[0x11] = SetBitField(vertEnd,3:0,3:0) | SetBit(5);
146     pVga->CRTC[0x12] = Set8Bits(vertDisplay);
147     pVga->CRTC[0x13] = ((pLayout->displayWidth/8)*(pLayout->bitsPerPixel/8));
148     pVga->CRTC[0x15] = Set8Bits(vertBlankStart);
149     pVga->CRTC[0x16] = Set8Bits(vertBlankEnd);
150
151     pVga->Attribute[0x10] = 0x01;
152
153     if(pNv->Television)
154        pVga->Attribute[0x11] = 0x00;
155
156     nvReg->screen = SetBitField(horizBlankEnd,6:6,4:4)
157                   | SetBitField(vertBlankStart,10:10,3:3)
158                   | SetBitField(vertStart,10:10,2:2)
159                   | SetBitField(vertDisplay,10:10,1:1)
160                   | SetBitField(vertTotal,10:10,0:0);
161
162     nvReg->horiz  = SetBitField(horizTotal,8:8,0:0) 
163                   | SetBitField(horizDisplay,8:8,1:1)
164                   | SetBitField(horizBlankStart,8:8,2:2)
165                   | SetBitField(horizStart,8:8,3:3);
166
167     nvReg->extra  = SetBitField(vertTotal,11:11,0:0)
168                     | SetBitField(vertDisplay,11:11,2:2)
169                     | SetBitField(vertStart,11:11,4:4)
170                     | SetBitField(vertBlankStart,11:11,6:6);
171
172     if(mode->Flags & V_INTERLACE) {
173        horizTotal = (horizTotal >> 1) & ~1;
174        nvReg->interlace = Set8Bits(horizTotal);
175        nvReg->horiz |= SetBitField(horizTotal,8:8,4:4);
176     } else {
177        nvReg->interlace = 0xff;  /* interlace off */
178     }
179
180
181     /*
182      * Initialize DAC palette.
183      */
184     if(pLayout->bitsPerPixel != 8 )
185     {
186         for (i = 0; i < 256; i++)
187         {
188             pVga->DAC[i*3]     = i;
189             pVga->DAC[(i*3)+1] = i;
190             pVga->DAC[(i*3)+2] = i;
191         }
192     }
193     
194     /*
195      * Calculate the extended registers.
196      */
197
198     if(pLayout->depth < 24) 
199         i = pLayout->depth;
200     else i = 32;
201
202     if(pNv->Architecture >= NV_ARCH_10)
203         pNv->CURSOR = (CARD32 *)pNv->Cursor->map;
204
205     NVCalcStateExt(pNv, 
206                     nvReg,
207                     i,
208                     pLayout->displayWidth,
209                     mode->CrtcHDisplay,
210                     pScrn->virtualY,
211                     mode->Clock,
212                     mode->Flags);
213
214     nvReg->scale = nvReadCurRAMDAC(pNv, NV_RAMDAC_FP_CONTROL) & 0xfff000ff;
215     if(pNv->FlatPanel == 1) {
216        nvReg->pixel |= (1 << 7);
217        if(!pNv->fpScaler || (pNv->fpWidth <= mode->HDisplay)
218                          || (pNv->fpHeight <= mode->VDisplay))
219        {
220            nvReg->scale |= (1 << 8) ;
221        }
222        nvReg->crtcSync = nvReadCurRAMDAC(pNv, NV_RAMDAC_FP_HCRTC);
223        nvReg->crtcSync += NVDACPanelTweaks(pNv, nvReg);
224     }
225
226     nvReg->vpll = nvReg->pll;
227     nvReg->vpll2 = nvReg->pll;
228     nvReg->vpllB = nvReg->pllB;
229     nvReg->vpll2B = nvReg->pllB;
230
231     nvReg->fifo = nvReadVGA(pNv, 0x1c) & ~(1<<5);
232
233     if(pNv->crtc_active[1]) {
234        nvReg->head  = nvReadCRTC(pNv, 0, NV_CRTC_FSEL) & ~0x00001000;
235        nvReg->head2 = nvReadCRTC(pNv, 1, NV_CRTC_FSEL) | 0x00001000;
236        nvReg->crtcOwner = 3;
237        nvReg->pllsel |= 0x20000800;
238        nvReg->vpll = nvReadRAMDAC0(pNv, NV_RAMDAC_VPLL);
239        if(pNv->twoStagePLL) 
240           nvReg->vpllB = nvReadRAMDAC0(pNv, NV_RAMDAC_VPLL_B);
241     } else if(pNv->twoHeads) {
242        nvReg->head  =  nvReadCRTC(pNv, 0, NV_CRTC_FSEL) | 0x00001000;
243        nvReg->head2 =  nvReadCRTC(pNv, 1, NV_CRTC_FSEL) & ~0x00001000;
244        nvReg->crtcOwner = 0;
245        nvReg->vpll2 = nvReadRAMDAC0(pNv, NV_RAMDAC_VPLL2);
246        if(pNv->twoStagePLL) 
247           nvReg->vpll2B = nvReadRAMDAC0(pNv, NV_RAMDAC_VPLL2_B);
248     }
249
250     nvReg->cursorConfig = 0x00000100;
251     if(mode->Flags & V_DBLSCAN)
252        nvReg->cursorConfig |= (1 << 4);
253     if(pNv->alphaCursor) {
254         if((pNv->Chipset & 0x0ff0) != CHIPSET_NV11) 
255            nvReg->cursorConfig |= 0x04011000;
256         else
257            nvReg->cursorConfig |= 0x14011000;
258         nvReg->general |= (1 << 29);
259     } else
260        nvReg->cursorConfig |= 0x02000000;
261
262     if(pNv->twoHeads) {
263         if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {
264            nvReg->dither = nvReadCurRAMDAC(pNv, NV_RAMDAC_DITHER_NV11) & ~0x00010000;
265            if(pNv->FPDither)
266               nvReg->dither |= 0x00010000;
267         } else {
268            nvReg->dither = nvReadCurRAMDAC(pNv, NV_RAMDAC_FP_DITHER) & ~1;
269            if(pNv->FPDither)
270               nvReg->dither |= 1;
271         } 
272     }
273
274     nvReg->timingH = 0;
275     nvReg->timingV = 0;
276     nvReg->displayV = mode->CrtcVDisplay;
277
278     return (TRUE);
279 }
280
281 void 
282 NVDACRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, NVRegPtr nvReg,
283              Bool primary)
284 {
285     int restore = VGA_SR_MODE;
286
287     if(primary) restore |= VGA_SR_CMAP | VGA_SR_FONTS;
288     NVLoadStateExt(pScrn, nvReg);
289 #if defined(__powerpc__)
290     restore &= ~VGA_SR_FONTS;
291 #endif
292     vgaHWRestore(pScrn, vgaReg, restore);
293 }
294
295 /*
296  * NVDACSave
297  *
298  * This function saves the video state.
299  */
300 void
301 NVDACSave(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, NVRegPtr nvReg,
302           Bool saveFonts)
303 {
304     NVPtr pNv = NVPTR(pScrn);
305
306 #if defined(__powerpc__)
307     saveFonts = FALSE;
308 #endif
309
310     vgaHWSave(pScrn, vgaReg, VGA_SR_CMAP | VGA_SR_MODE | 
311                              (saveFonts? VGA_SR_FONTS : 0));
312     NVUnloadStateExt(pNv, nvReg);
313
314         /* can't read this reliably on NV11 */
315         if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {
316                 /* 0 if inactive -> crtc0 is active, otherwise 1 */
317                 nvReg->crtcOwner = pNv->crtc_active[1];
318         }
319 }
320
321 #define DEPTH_SHIFT(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8)))
322 #define MAKE_INDEX(in, w) (DEPTH_SHIFT(in, w) * 3)
323
324 void
325 NVDACLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
326                  VisualPtr pVisual )
327 {
328     int i, index;
329     NVPtr pNv = NVPTR(pScrn);
330     vgaRegPtr   pVga;
331
332     pVga = &VGAHWPTR(pScrn)->ModeReg;
333
334     switch(pNv->CurrentLayout.depth) {
335     case 15:
336         for(i = 0; i < numColors; i++) {
337             index = indices[i];
338             pVga->DAC[MAKE_INDEX(index, 5) + 0] = colors[index].red;
339             pVga->DAC[MAKE_INDEX(index, 5) + 1] = colors[index].green;
340             pVga->DAC[MAKE_INDEX(index, 5) + 2] = colors[index].blue;
341         }
342         break;
343     case 16:
344         for(i = 0; i < numColors; i++) {
345             index = indices[i];
346             pVga->DAC[MAKE_INDEX(index, 6) + 1] = colors[index].green;
347             if(index < 32) {
348                 pVga->DAC[MAKE_INDEX(index, 5) + 0] = colors[index].red;
349                 pVga->DAC[MAKE_INDEX(index, 5) + 2] = colors[index].blue;
350             }
351         }
352         break;
353     default:
354         for(i = 0; i < numColors; i++) {
355             index = indices[i];
356             pVga->DAC[index*3]     = colors[index].red;
357             pVga->DAC[(index*3)+1] = colors[index].green;
358             pVga->DAC[(index*3)+2] = colors[index].blue;
359         }
360         break;
361     }
362     vgaHWRestore(pScrn, pVga, VGA_SR_CMAP);
363 }
364
365 /*
366  * DDC1 support only requires DDC_SDA_MASK,
367  * DDC2 support requires DDC_SDA_MASK and DDC_SCL_MASK
368  */
369 #define DDC_SDA_READ_MASK  (1 << 3)
370 #define DDC_SCL_READ_MASK  (1 << 2)
371 #define DDC_SDA_WRITE_MASK (1 << 4)
372 #define DDC_SCL_WRITE_MASK (1 << 5)
373
374 static void
375 NV_I2CGetBits(I2CBusPtr b, int *clock, int *data)
376 {
377     NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
378     unsigned char val;
379
380     /* Get the result. */
381     val = nvReadVGA(pNv, pNv->DDCBase);
382
383     *clock = (val & DDC_SCL_READ_MASK) != 0;
384     *data  = (val & DDC_SDA_READ_MASK) != 0;
385 }
386
387 static void
388 NV_I2CPutBits(I2CBusPtr b, int clock, int data)
389 {
390     NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
391     unsigned char val;
392
393     val = nvReadVGA(pNv, pNv->DDCBase + 1) & 0xf0;
394     if (clock)
395         val |= DDC_SCL_WRITE_MASK;
396     else
397         val &= ~DDC_SCL_WRITE_MASK;
398
399     if (data)
400         val |= DDC_SDA_WRITE_MASK;
401     else
402         val &= ~DDC_SDA_WRITE_MASK;
403
404     nvWriteVGA(pNv, pNv->DDCBase + 1, val | 0x1);
405 }
406
407 Bool
408 NVDACi2cInit(ScrnInfoPtr pScrn)
409 {
410     NVPtr pNv = NVPTR(pScrn);
411     I2CBusPtr I2CPtr;
412
413     I2CPtr = xf86CreateI2CBusRec();
414     if(!I2CPtr) return FALSE;
415
416     pNv->I2C = I2CPtr;
417
418     I2CPtr->BusName    = "DDC";
419     I2CPtr->scrnIndex  = pScrn->scrnIndex;
420     I2CPtr->I2CPutBits = NV_I2CPutBits;
421     I2CPtr->I2CGetBits = NV_I2CGetBits;
422     I2CPtr->AcknTimeout = 5;
423
424     if (!xf86I2CBusInit(I2CPtr)) {
425         return FALSE;
426     }
427     return TRUE;
428 }
429