add RAMDAC register read/write
[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 = (CARD32 *)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 = nvReadCurRAMDAC(pNv, 0x848) & 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 = nvReadCurRAMDAC(pNv, 0x0828);
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     nvReg->fifo = nvReadVGA(pNv, 0x1c) & ~(1<<5);
228
229     if(pNv->CRTCnumber) {
230        nvReg->head  = pNv->PCRTC0[0x00000860/4] & ~0x00001000;
231        nvReg->head2 = pNv->PCRTC0[0x00002860/4] | 0x00001000;
232        nvReg->crtcOwner = 3;
233        nvReg->pllsel |= 0x20000800;
234        nvReg->vpll = nvReadRAMDAC0(pNv, 0x0508);
235        if(pNv->twoStagePLL) 
236           nvReg->vpllB = nvReadRAMDAC0(pNv, 0x0578);
237     } else 
238     if(pNv->twoHeads) {
239        nvReg->head  =  pNv->PCRTC0[0x00000860/4] | 0x00001000;
240        nvReg->head2 =  pNv->PCRTC0[0x00002860/4] & ~0x00001000;
241        nvReg->crtcOwner = 0;
242        nvReg->vpll2 = nvReadRAMDAC0(pNv, 0x520);
243        if(pNv->twoStagePLL) 
244           nvReg->vpll2B = nvReadRAMDAC0(pNv, 0x57C);
245     }
246
247     nvReg->cursorConfig = 0x00000100;
248     if(mode->Flags & V_DBLSCAN)
249        nvReg->cursorConfig |= (1 << 4);
250     if(pNv->alphaCursor) {
251         if((pNv->Chipset & 0x0ff0) != CHIPSET_NV11) 
252            nvReg->cursorConfig |= 0x04011000;
253         else
254            nvReg->cursorConfig |= 0x14011000;
255         nvReg->general |= (1 << 29);
256     } else
257        nvReg->cursorConfig |= 0x02000000;
258
259     if(pNv->twoHeads) {
260         if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {
261            nvReg->dither = nvReadCurRAMDAC(pNv, 0x0528) & ~0x00010000;
262            if(pNv->FPDither)
263               nvReg->dither |= 0x00010000;
264         } else {
265            nvReg->dither = nvReadCurRAMDAC(pNv, 0x083C) & ~1;
266            if(pNv->FPDither)
267               nvReg->dither |= 1;
268         } 
269     }
270
271     nvReg->timingH = 0;
272     nvReg->timingV = 0;
273     nvReg->displayV = mode->CrtcVDisplay;
274
275     return (TRUE);
276 }
277
278 void 
279 NVDACRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, NVRegPtr nvReg,
280              Bool primary)
281 {
282     NVPtr pNv = NVPTR(pScrn);
283     int restore = VGA_SR_MODE;
284
285     if(primary) restore |= VGA_SR_CMAP | VGA_SR_FONTS;
286     NVLoadStateExt(pScrn, nvReg);
287 #if defined(__powerpc__)
288     restore &= ~VGA_SR_FONTS;
289 #endif
290     vgaHWRestore(pScrn, vgaReg, restore);
291 }
292
293 /*
294  * NVDACSave
295  *
296  * This function saves the video state.
297  */
298 void
299 NVDACSave(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, NVRegPtr nvReg,
300           Bool saveFonts)
301 {
302     NVPtr pNv = NVPTR(pScrn);
303
304 #if defined(__powerpc__)
305     saveFonts = FALSE;
306 #endif
307
308     vgaHWSave(pScrn, vgaReg, VGA_SR_CMAP | VGA_SR_MODE | 
309                              (saveFonts? VGA_SR_FONTS : 0));
310     NVUnloadStateExt(pNv, nvReg);
311
312     /* can't read this reliably on NV11 */
313     if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) 
314        nvReg->crtcOwner = pNv->CRTCnumber;
315 }
316
317 #define DEPTH_SHIFT(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8)))
318 #define MAKE_INDEX(in, w) (DEPTH_SHIFT(in, w) * 3)
319
320 void
321 NVDACLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
322                  VisualPtr pVisual )
323 {
324     int i, index;
325     NVPtr pNv = NVPTR(pScrn);
326     vgaRegPtr   pVga;
327
328     pVga = &VGAHWPTR(pScrn)->ModeReg;
329
330     switch(pNv->CurrentLayout.depth) {
331     case 15:
332         for(i = 0; i < numColors; i++) {
333             index = indices[i];
334             pVga->DAC[MAKE_INDEX(index, 5) + 0] = colors[index].red;
335             pVga->DAC[MAKE_INDEX(index, 5) + 1] = colors[index].green;
336             pVga->DAC[MAKE_INDEX(index, 5) + 2] = colors[index].blue;
337         }
338         break;
339     case 16:
340         for(i = 0; i < numColors; i++) {
341             index = indices[i];
342             pVga->DAC[MAKE_INDEX(index, 6) + 1] = colors[index].green;
343             if(index < 32) {
344                 pVga->DAC[MAKE_INDEX(index, 5) + 0] = colors[index].red;
345                 pVga->DAC[MAKE_INDEX(index, 5) + 2] = colors[index].blue;
346             }
347         }
348         break;
349     default:
350         for(i = 0; i < numColors; i++) {
351             index = indices[i];
352             pVga->DAC[index*3]     = colors[index].red;
353             pVga->DAC[(index*3)+1] = colors[index].green;
354             pVga->DAC[(index*3)+2] = colors[index].blue;
355         }
356         break;
357     }
358     vgaHWRestore(pScrn, pVga, VGA_SR_CMAP);
359 }
360
361 /*
362  * DDC1 support only requires DDC_SDA_MASK,
363  * DDC2 support requires DDC_SDA_MASK and DDC_SCL_MASK
364  */
365 #define DDC_SDA_READ_MASK  (1 << 3)
366 #define DDC_SCL_READ_MASK  (1 << 2)
367 #define DDC_SDA_WRITE_MASK (1 << 4)
368 #define DDC_SCL_WRITE_MASK (1 << 5)
369
370 static void
371 NV_I2CGetBits(I2CBusPtr b, int *clock, int *data)
372 {
373     NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
374     unsigned char val;
375
376     /* Get the result. */
377     VGA_WR08(pNv->PCIO, 0x3d4, pNv->DDCBase);
378     val = VGA_RD08(pNv->PCIO, 0x3d5);
379
380     *clock = (val & DDC_SCL_READ_MASK) != 0;
381     *data  = (val & DDC_SDA_READ_MASK) != 0;
382 }
383
384 static void
385 NV_I2CPutBits(I2CBusPtr b, int clock, int data)
386 {
387     NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
388     unsigned char val;
389
390     VGA_WR08(pNv->PCIO, 0x3d4, pNv->DDCBase + 1);
391     val = VGA_RD08(pNv->PCIO, 0x3d5) & 0xf0;
392     if (clock)
393         val |= DDC_SCL_WRITE_MASK;
394     else
395         val &= ~DDC_SCL_WRITE_MASK;
396
397     if (data)
398         val |= DDC_SDA_WRITE_MASK;
399     else
400         val &= ~DDC_SDA_WRITE_MASK;
401
402     VGA_WR08(pNv->PCIO, 0x3d4, pNv->DDCBase + 1);
403     VGA_WR08(pNv->PCIO, 0x3d5, val | 0x1);
404 }
405
406 Bool
407 NVDACi2cInit(ScrnInfoPtr pScrn)
408 {
409     NVPtr pNv = NVPTR(pScrn);
410     I2CBusPtr I2CPtr;
411
412     I2CPtr = xf86CreateI2CBusRec();
413     if(!I2CPtr) return FALSE;
414
415     pNv->I2C = I2CPtr;
416
417     I2CPtr->BusName    = "DDC";
418     I2CPtr->scrnIndex  = pScrn->scrnIndex;
419     I2CPtr->I2CPutBits = NV_I2CPutBits;
420     I2CPtr->I2CGetBits = NV_I2CGetBits;
421     I2CPtr->AcknTimeout = 5;
422
423     if (!xf86I2CBusInit(I2CPtr)) {
424         return FALSE;
425     }
426     return TRUE;
427 }
428