Whoa, how did that happen...
[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     }
119
120     pVga->CRTC[0x0]  = Set8Bits(horizTotal);
121     pVga->CRTC[0x1]  = Set8Bits(horizDisplay);
122     pVga->CRTC[0x2]  = Set8Bits(horizBlankStart);
123     pVga->CRTC[0x3]  = SetBitField(horizBlankEnd,4:0,4:0) 
124                        | SetBit(7);
125     pVga->CRTC[0x4]  = Set8Bits(horizStart);
126     pVga->CRTC[0x5]  = SetBitField(horizBlankEnd,5:5,7:7)
127                        | SetBitField(horizEnd,4:0,4:0);
128     pVga->CRTC[0x6]  = SetBitField(vertTotal,7:0,7:0);
129     pVga->CRTC[0x7]  = SetBitField(vertTotal,8:8,0:0)
130                        | SetBitField(vertDisplay,8:8,1:1)
131                        | SetBitField(vertStart,8:8,2:2)
132                        | SetBitField(vertBlankStart,8:8,3:3)
133                        | SetBit(4)
134                        | SetBitField(vertTotal,9:9,5:5)
135                        | SetBitField(vertDisplay,9:9,6:6)
136                        | SetBitField(vertStart,9:9,7:7);
137     pVga->CRTC[0x9]  = SetBitField(vertBlankStart,9:9,5:5)
138                        | SetBit(6)
139                        | ((mode->Flags & V_DBLSCAN) ? 0x80 : 0x00);
140     pVga->CRTC[0x10] = Set8Bits(vertStart);
141     pVga->CRTC[0x11] = SetBitField(vertEnd,3:0,3:0) | SetBit(5);
142     pVga->CRTC[0x12] = Set8Bits(vertDisplay);
143     pVga->CRTC[0x13] = ((pLayout->displayWidth/8)*(pLayout->bitsPerPixel/8));
144     pVga->CRTC[0x15] = Set8Bits(vertBlankStart);
145     pVga->CRTC[0x16] = Set8Bits(vertBlankEnd);
146
147     pVga->Attribute[0x10] = 0x01;
148
149     if(pNv->Television)
150        pVga->Attribute[0x11] = 0x00;
151
152     nvReg->screen = SetBitField(horizBlankEnd,6:6,4:4)
153                   | SetBitField(vertBlankStart,10:10,3:3)
154                   | SetBitField(vertStart,10:10,2:2)
155                   | SetBitField(vertDisplay,10:10,1:1)
156                   | SetBitField(vertTotal,10:10,0:0);
157
158     nvReg->horiz  = SetBitField(horizTotal,8:8,0:0) 
159                   | SetBitField(horizDisplay,8:8,1:1)
160                   | SetBitField(horizBlankStart,8:8,2:2)
161                   | SetBitField(horizStart,8:8,3:3);
162
163     nvReg->extra  = SetBitField(vertTotal,11:11,0:0)
164                     | SetBitField(vertDisplay,11:11,2:2)
165                     | SetBitField(vertStart,11:11,4:4)
166                     | SetBitField(vertBlankStart,11:11,6:6);
167
168     if(mode->Flags & V_INTERLACE) {
169        horizTotal = (horizTotal >> 1) & ~1;
170        nvReg->interlace = Set8Bits(horizTotal);
171        nvReg->horiz |= SetBitField(horizTotal,8:8,4:4);
172     } else {
173        nvReg->interlace = 0xff;  /* interlace off */
174     }
175
176
177     /*
178      * Initialize DAC palette.
179      */
180     if(pLayout->bitsPerPixel != 8 )
181     {
182         for (i = 0; i < 256; i++)
183         {
184             pVga->DAC[i*3]     = i;
185             pVga->DAC[(i*3)+1] = i;
186             pVga->DAC[(i*3)+2] = i;
187         }
188     }
189     
190     /*
191      * Calculate the extended registers.
192      */
193
194     if(pLayout->depth < 24) 
195         i = pLayout->depth;
196     else i = 32;
197
198     if(pNv->Architecture >= NV_ARCH_10)
199         pNv->CURSOR = (U032 *)pNv->Cursor->map;
200
201     NVCalcStateExt(pNv, 
202                     nvReg,
203                     i,
204                     pLayout->displayWidth,
205                     mode->CrtcHDisplay,
206                     pScrn->virtualY,
207                     mode->Clock,
208                     mode->Flags);
209
210     nvReg->scale = pNv->PRAMDAC[0x00000848/4] & 0xfff000ff;
211     if(pNv->FlatPanel == 1) {
212        nvReg->pixel |= (1 << 7);
213        if(!pNv->fpScaler || (pNv->fpWidth <= mode->HDisplay)
214                          || (pNv->fpHeight <= mode->VDisplay))
215        {
216            nvReg->scale |= (1 << 8) ;
217        }
218        nvReg->crtcSync = pNv->PRAMDAC[0x0828/4];
219        nvReg->crtcSync += NVDACPanelTweaks(pNv, nvReg);
220     }
221
222     nvReg->vpll = nvReg->pll;
223     nvReg->vpll2 = nvReg->pll;
224     nvReg->vpllB = nvReg->pllB;
225     nvReg->vpll2B = nvReg->pllB;
226
227     VGA_WR08(pNv->PCIO, 0x03D4, 0x1C);
228     nvReg->fifo = VGA_RD08(pNv->PCIO, 0x03D5) & ~(1<<5);
229
230     if(pNv->CRTCnumber) {
231        nvReg->head  = pNv->PCRTC0[0x00000860/4] & ~0x00001000;
232        nvReg->head2 = pNv->PCRTC0[0x00002860/4] | 0x00001000;
233        nvReg->crtcOwner = 3;
234        nvReg->pllsel |= 0x20000800;
235        nvReg->vpll = pNv->PRAMDAC0[0x0508/4];
236        if(pNv->twoStagePLL) 
237           nvReg->vpllB = pNv->PRAMDAC0[0x0578/4];
238     } else 
239     if(pNv->twoHeads) {
240        nvReg->head  =  pNv->PCRTC0[0x00000860/4] | 0x00001000;
241        nvReg->head2 =  pNv->PCRTC0[0x00002860/4] & ~0x00001000;
242        nvReg->crtcOwner = 0;
243        nvReg->vpll2 = pNv->PRAMDAC0[0x0520/4];
244        if(pNv->twoStagePLL) 
245           nvReg->vpll2B = pNv->PRAMDAC0[0x057C/4];
246     }
247
248     nvReg->cursorConfig = 0x00000100;
249     if(mode->Flags & V_DBLSCAN)
250        nvReg->cursorConfig |= (1 << 4);
251     if(pNv->alphaCursor) {
252         if((pNv->Chipset & 0x0ff0) != CHIPSET_NV11) 
253            nvReg->cursorConfig |= 0x04011000;
254         else
255            nvReg->cursorConfig |= 0x14011000;
256         nvReg->general |= (1 << 29);
257     } else
258        nvReg->cursorConfig |= 0x02000000;
259
260     if(pNv->twoHeads) {
261         if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {
262            nvReg->dither = pNv->PRAMDAC[0x0528/4] & ~0x00010000;
263            if(pNv->FPDither)
264               nvReg->dither |= 0x00010000;
265         } else {
266            nvReg->dither = pNv->PRAMDAC[0x083C/4] & ~1;
267            if(pNv->FPDither)
268               nvReg->dither |= 1;
269         } 
270     }
271
272     nvReg->timingH = 0;
273     nvReg->timingV = 0;
274     nvReg->displayV = mode->CrtcVDisplay;
275
276     return (TRUE);
277 }
278
279 void 
280 NVDACRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, NVRegPtr nvReg,
281              Bool primary)
282 {
283     NVPtr pNv = NVPTR(pScrn);
284     int restore = VGA_SR_MODE;
285
286     if(primary) restore |= VGA_SR_CMAP | VGA_SR_FONTS;
287     NVLoadStateExt(pScrn, nvReg);
288 #if defined(__powerpc__)
289     restore &= ~VGA_SR_FONTS;
290 #endif
291     vgaHWRestore(pScrn, vgaReg, restore);
292 }
293
294 /*
295  * NVDACSave
296  *
297  * This function saves the video state.
298  */
299 void
300 NVDACSave(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, NVRegPtr nvReg,
301           Bool saveFonts)
302 {
303     NVPtr pNv = NVPTR(pScrn);
304
305 #if defined(__powerpc__)
306     saveFonts = FALSE;
307 #endif
308
309     vgaHWSave(pScrn, vgaReg, VGA_SR_CMAP | VGA_SR_MODE | 
310                              (saveFonts? VGA_SR_FONTS : 0));
311     NVUnloadStateExt(pNv, nvReg);
312
313     /* can't read this reliably on NV11 */
314     if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) 
315        nvReg->crtcOwner = pNv->CRTCnumber;
316 }
317
318 #define DEPTH_SHIFT(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8)))
319 #define MAKE_INDEX(in, w) (DEPTH_SHIFT(in, w) * 3)
320
321 void
322 NVDACLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
323                  VisualPtr pVisual )
324 {
325     int i, index;
326     NVPtr pNv = NVPTR(pScrn);
327     vgaRegPtr   pVga;
328
329     pVga = &VGAHWPTR(pScrn)->ModeReg;
330
331     switch(pNv->CurrentLayout.depth) {
332     case 15:
333         for(i = 0; i < numColors; i++) {
334             index = indices[i];
335             pVga->DAC[MAKE_INDEX(index, 5) + 0] = colors[index].red;
336             pVga->DAC[MAKE_INDEX(index, 5) + 1] = colors[index].green;
337             pVga->DAC[MAKE_INDEX(index, 5) + 2] = colors[index].blue;
338         }
339         break;
340     case 16:
341         for(i = 0; i < numColors; i++) {
342             index = indices[i];
343             pVga->DAC[MAKE_INDEX(index, 6) + 1] = colors[index].green;
344             if(index < 32) {
345                 pVga->DAC[MAKE_INDEX(index, 5) + 0] = colors[index].red;
346                 pVga->DAC[MAKE_INDEX(index, 5) + 2] = colors[index].blue;
347             }
348         }
349         break;
350     default:
351         for(i = 0; i < numColors; i++) {
352             index = indices[i];
353             pVga->DAC[index*3]     = colors[index].red;
354             pVga->DAC[(index*3)+1] = colors[index].green;
355             pVga->DAC[(index*3)+2] = colors[index].blue;
356         }
357         break;
358     }
359     vgaHWRestore(pScrn, pVga, VGA_SR_CMAP);
360 }
361
362 /*
363  * DDC1 support only requires DDC_SDA_MASK,
364  * DDC2 support requires DDC_SDA_MASK and DDC_SCL_MASK
365  */
366 #define DDC_SDA_READ_MASK  (1 << 3)
367 #define DDC_SCL_READ_MASK  (1 << 2)
368 #define DDC_SDA_WRITE_MASK (1 << 4)
369 #define DDC_SCL_WRITE_MASK (1 << 5)
370
371 static void
372 NV_I2CGetBits(I2CBusPtr b, int *clock, int *data)
373 {
374     NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
375     unsigned char val;
376
377     /* Get the result. */
378     VGA_WR08(pNv->PCIO, 0x3d4, pNv->DDCBase);
379     val = VGA_RD08(pNv->PCIO, 0x3d5);
380
381     *clock = (val & DDC_SCL_READ_MASK) != 0;
382     *data  = (val & DDC_SDA_READ_MASK) != 0;
383 }
384
385 static void
386 NV_I2CPutBits(I2CBusPtr b, int clock, int data)
387 {
388     NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
389     unsigned char val;
390
391     VGA_WR08(pNv->PCIO, 0x3d4, pNv->DDCBase + 1);
392     val = VGA_RD08(pNv->PCIO, 0x3d5) & 0xf0;
393     if (clock)
394         val |= DDC_SCL_WRITE_MASK;
395     else
396         val &= ~DDC_SCL_WRITE_MASK;
397
398     if (data)
399         val |= DDC_SDA_WRITE_MASK;
400     else
401         val &= ~DDC_SDA_WRITE_MASK;
402
403     VGA_WR08(pNv->PCIO, 0x3d4, pNv->DDCBase + 1);
404     VGA_WR08(pNv->PCIO, 0x3d5, 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