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