Initial revision
[nouveau] / src / nv_dac.c
1 /* $XConsortium: nv_driver.c /main/3 1996/10/28 05:13:37 kaleb $ */
2 /*
3  * Copyright 1996-1997  David J. McKay
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the 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  * DAVID J. MCKAY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
20  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23
24 /* Hacked together from mga driver and 3.3.4 NVIDIA driver by Jarno Paananen
25    <jpaana@s2.org> */
26
27 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_dac.c,v 1.31 2003/01/02 20:44:56 mvojkovi Exp $ */
28
29 #include "nv_include.h"
30
31 Bool
32 NVDACInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
33 {
34     int i;
35     int horizDisplay    = (mode->CrtcHDisplay/8)   - 1;
36     int horizStart      = (mode->CrtcHSyncStart/8) - 1;
37     int horizEnd        = (mode->CrtcHSyncEnd/8)   - 1;
38     int horizTotal      = (mode->CrtcHTotal/8)     - 5;
39     int horizBlankStart = (mode->CrtcHDisplay/8)   - 1;
40     int horizBlankEnd   = (mode->CrtcHTotal/8)     - 1;
41     int vertDisplay     =  mode->CrtcVDisplay      - 1;
42     int vertStart       =  mode->CrtcVSyncStart    - 1;
43     int vertEnd         =  mode->CrtcVSyncEnd      - 1;
44     int vertTotal       =  mode->CrtcVTotal        - 2;
45     int vertBlankStart  =  mode->CrtcVDisplay      - 1;
46     int vertBlankEnd    =  mode->CrtcVTotal        - 1;
47    
48
49     NVPtr pNv = NVPTR(pScrn);
50     NVRegPtr nvReg = &pNv->ModeReg;
51     NVFBLayout *pLayout = &pNv->CurrentLayout;
52     vgaRegPtr   pVga;
53
54     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NVDACInit\n"));
55     
56     /*
57      * This will initialize all of the generic VGA registers.
58      */
59     if (!vgaHWInit(pScrn, mode))
60         return(FALSE);
61
62     pVga = &VGAHWPTR(pScrn)->ModeReg;
63
64     /*
65      * Set all CRTC values.
66      */
67
68     if(mode->Flags & V_INTERLACE) 
69         vertTotal |= 1;
70
71     if(pNv->FlatPanel == 1) {
72        vertStart = vertTotal - 3;  
73        vertEnd = vertTotal - 2;
74        vertBlankStart = vertStart;
75        horizStart = horizTotal - 3;
76        horizEnd = horizTotal - 2;   
77        horizBlankEnd = horizTotal + 4;    
78     }
79
80     pVga->CRTC[0x0]  = Set8Bits(horizTotal);
81     pVga->CRTC[0x1]  = Set8Bits(horizDisplay);
82     pVga->CRTC[0x2]  = Set8Bits(horizBlankStart);
83     pVga->CRTC[0x3]  = SetBitField(horizBlankEnd,4:0,4:0) 
84                        | SetBit(7);
85     pVga->CRTC[0x4]  = Set8Bits(horizStart);
86     pVga->CRTC[0x5]  = SetBitField(horizBlankEnd,5:5,7:7)
87                        | SetBitField(horizEnd,4:0,4:0);
88     pVga->CRTC[0x6]  = SetBitField(vertTotal,7:0,7:0);
89     pVga->CRTC[0x7]  = SetBitField(vertTotal,8:8,0:0)
90                        | SetBitField(vertDisplay,8:8,1:1)
91                        | SetBitField(vertStart,8:8,2:2)
92                        | SetBitField(vertBlankStart,8:8,3:3)
93                        | SetBit(4)
94                        | SetBitField(vertTotal,9:9,5:5)
95                        | SetBitField(vertDisplay,9:9,6:6)
96                        | SetBitField(vertStart,9:9,7:7);
97     pVga->CRTC[0x9]  = SetBitField(vertBlankStart,9:9,5:5)
98                        | SetBit(6)
99                        | ((mode->Flags & V_DBLSCAN) ? 0x80 : 0x00);
100     pVga->CRTC[0x10] = Set8Bits(vertStart);
101     pVga->CRTC[0x11] = SetBitField(vertEnd,3:0,3:0) | SetBit(5);
102     pVga->CRTC[0x12] = Set8Bits(vertDisplay);
103     pVga->CRTC[0x13] = ((pLayout->displayWidth/8)*(pLayout->bitsPerPixel/8));
104     pVga->CRTC[0x15] = Set8Bits(vertBlankStart);
105     pVga->CRTC[0x16] = Set8Bits(vertBlankEnd);
106
107     pVga->Attribute[0x10] = 0x01;
108
109     nvReg->screen = SetBitField(horizBlankEnd,6:6,4:4)
110                   | SetBitField(vertBlankStart,10:10,3:3)
111                   | SetBitField(vertStart,10:10,2:2)
112                   | SetBitField(vertDisplay,10:10,1:1)
113                   | SetBitField(vertTotal,10:10,0:0);
114
115     nvReg->horiz  = SetBitField(horizTotal,8:8,0:0) 
116                   | SetBitField(horizDisplay,8:8,1:1)
117                   | SetBitField(horizBlankStart,8:8,2:2)
118                   | SetBitField(horizStart,8:8,3:3);
119
120     nvReg->extra  = SetBitField(vertTotal,11:11,0:0)
121                     | SetBitField(vertDisplay,11:11,2:2)
122                     | SetBitField(vertStart,11:11,4:4)
123                     | SetBitField(vertBlankStart,11:11,6:6);
124
125     if(mode->Flags & V_INTERLACE) {
126        horizTotal = (horizTotal >> 1) & ~1;
127        nvReg->interlace = Set8Bits(horizTotal);
128        nvReg->horiz |= SetBitField(horizTotal,8:8,4:4);
129     } else {
130        nvReg->interlace = 0xff;  /* interlace off */
131     }
132
133
134     /*
135      * Initialize DAC palette.
136      */
137     if(pLayout->bitsPerPixel != 8 )
138     {
139         for (i = 0; i < 256; i++)
140         {
141             pVga->DAC[i*3]     = i;
142             pVga->DAC[(i*3)+1] = i;
143             pVga->DAC[(i*3)+2] = i;
144         }
145     }
146     
147     /*
148      * Calculate the extended registers.
149      */
150
151     if(pLayout->depth < 24) 
152         i = pLayout->depth;
153     else i = 32;
154
155     if(pNv->riva.Architecture >= NV_ARCH_10)
156         pNv->riva.CURSOR = (U032 *)(pNv->FbStart + pNv->riva.CursorStart);
157
158     pNv->riva.LockUnlock(&pNv->riva, 0);
159
160     pNv->riva.CalcStateExt(&pNv->riva, 
161                            nvReg,
162                            i,
163                            pLayout->displayWidth,
164                            mode->CrtcHDisplay,
165                            pScrn->virtualY,
166                            mode->Clock,
167                            mode->Flags);
168
169     nvReg->scale = pNv->riva.PRAMDAC[0x00000848/4] & 0xfff000ff;
170     if(pNv->FlatPanel == 1) {
171        nvReg->pixel |= (1 << 7);
172        nvReg->scale |= (1 << 8) ;
173     }
174     if(pNv->SecondCRTC) {
175        nvReg->head  = pNv->riva.PCRTC0[0x00000860/4] & ~0x00001000;
176        nvReg->head2 = pNv->riva.PCRTC0[0x00002860/4] | 0x00001000;
177        nvReg->crtcOwner = 3;
178        nvReg->pllsel |= 0x20000800;
179        nvReg->vpll2 = nvReg->vpll;
180     } else 
181     if(pNv->riva.twoHeads) {
182        nvReg->head  =  pNv->riva.PCRTC0[0x00000860/4] | 0x00001000;
183        nvReg->head2 =  pNv->riva.PCRTC0[0x00002860/4] & ~0x00001000;
184        nvReg->crtcOwner = 0;
185        nvReg->vpll2 = pNv->riva.PRAMDAC0[0x00000520/4];
186     }
187
188     nvReg->cursorConfig = 0x00000100;
189     if(mode->Flags & V_DBLSCAN)
190        nvReg->cursorConfig |= (1 << 4);
191     if(pNv->alphaCursor) {
192         nvReg->cursorConfig |= 0x04011000;
193         nvReg->general |= (1 << 29);
194
195         if((pNv->Chipset & 0x0ff0) == 0x0110) {
196             nvReg->dither = pNv->riva.PRAMDAC[0x0528/4] & ~0x00010000;
197             if(pNv->riva.flatPanel & FP_DITHER)
198                nvReg->dither |= 0x00010000;
199             else
200                nvReg->cursorConfig |= (1 << 28);
201         } else 
202         if((pNv->riva.Chipset & 0x0ff0) >= 0x0170) {
203            nvReg->dither = pNv->riva.PRAMDAC[0x083C/4] & ~1;
204            nvReg->cursorConfig |= (1 << 28);
205            if(pNv->riva.flatPanel & FP_DITHER)
206               nvReg->dither |= 1;
207         } else {
208            nvReg->cursorConfig |= (1 << 28);
209         }
210     } else
211        nvReg->cursorConfig |= 0x02000000;
212
213     nvReg->vpllB = 0;
214     nvReg->vpll2B = 0;
215
216     return (TRUE);
217 }
218
219 void 
220 NVDACRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, NVRegPtr nvReg,
221              Bool primary)
222 {
223     NVPtr pNv = NVPTR(pScrn);
224     int restore = VGA_SR_MODE;
225
226     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NVDACRestore\n"));
227
228     if(primary) restore |= VGA_SR_CMAP | VGA_SR_FONTS;
229     else if((pNv->Chipset & 0xffff) == 0x0018) 
230         restore |= VGA_SR_CMAP;
231     pNv->riva.LoadStateExt(&pNv->riva, nvReg);
232 #if defined(__powerpc__)
233     restore &= ~VGA_SR_FONTS;
234 #endif
235     vgaHWRestore(pScrn, vgaReg, restore);
236 }
237
238 /*
239  * NVDACSave
240  *
241  * This function saves the video state.
242  */
243 void
244 NVDACSave(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, NVRegPtr nvReg,
245           Bool saveFonts)
246 {
247     NVPtr pNv = NVPTR(pScrn);
248     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NVDACSave\n"));
249
250 #if defined(__powerpc__)
251     saveFonts = FALSE;
252 #endif
253
254     vgaHWSave(pScrn, vgaReg, VGA_SR_CMAP | VGA_SR_MODE | 
255                              (saveFonts? VGA_SR_FONTS : 0));
256     pNv->riva.UnloadStateExt(&pNv->riva, nvReg);
257
258     if((pNv->Chipset & 0x0ff0) == 0x0110) 
259        nvReg->crtcOwner = ((pNv->Chipset & 0x0fff) == 0x0112) ? 3 : 0;
260 }
261
262 #define DEPTH_SHIFT(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8)))
263 #define MAKE_INDEX(in, w) (DEPTH_SHIFT(in, w) * 3)
264
265 void
266 NVDACLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
267                  VisualPtr pVisual )
268 {
269     int i, index;
270     NVPtr pNv = NVPTR(pScrn);
271     vgaRegPtr   pVga;
272
273     pVga = &VGAHWPTR(pScrn)->ModeReg;
274
275     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NVDACLoadPalette\n"));
276
277     if((pNv->riva.Architecture == NV_ARCH_03) && 
278        (pNv->CurrentLayout.depth != 8))
279            return;
280
281     switch(pNv->CurrentLayout.depth) {
282     case 15:
283         for(i = 0; i < numColors; i++) {
284             index = indices[i];
285             pVga->DAC[MAKE_INDEX(index, 5) + 0] = colors[index].red;
286             pVga->DAC[MAKE_INDEX(index, 5) + 1] = colors[index].green;
287             pVga->DAC[MAKE_INDEX(index, 5) + 2] = colors[index].blue;
288         }
289         break;
290     case 16:
291         for(i = 0; i < numColors; i++) {
292             index = indices[i];
293             pVga->DAC[MAKE_INDEX(index, 6) + 1] = colors[index].green;
294             if(index < 32) {
295                 pVga->DAC[MAKE_INDEX(index, 5) + 0] = colors[index].red;
296                 pVga->DAC[MAKE_INDEX(index, 5) + 2] = colors[index].blue;
297             }
298         }
299         break;
300     default:
301         for(i = 0; i < numColors; i++) {
302             index = indices[i];
303             pVga->DAC[index*3]     = colors[index].red;
304             pVga->DAC[(index*3)+1] = colors[index].green;
305             pVga->DAC[(index*3)+2] = colors[index].blue;
306         }
307         break;
308     }
309     vgaHWRestore(pScrn, pVga, VGA_SR_CMAP);
310 }
311
312 /*
313  * DDC1 support only requires DDC_SDA_MASK,
314  * DDC2 support requires DDC_SDA_MASK and DDC_SCL_MASK
315  */
316 #define DDC_SDA_READ_MASK  (1 << 3)
317 #define DDC_SCL_READ_MASK  (1 << 2)
318 #define DDC_SDA_WRITE_MASK (1 << 4)
319 #define DDC_SCL_WRITE_MASK (1 << 5)
320
321 static unsigned int
322 NV_ddc1Read(ScrnInfoPtr pScrn)
323 {
324     NVPtr pNv = NVPTR(pScrn);
325     unsigned char val;
326
327     /* wait for Vsync */
328     while(VGA_RD08(pNv->riva.PCIO, 0x3da) & 0x08);
329     while(!(VGA_RD08(pNv->riva.PCIO, 0x3da) & 0x08));
330
331     /* Get the result */
332     VGA_WR08(pNv->riva.PCIO, 0x3d4, pNv->DDCBase);
333     val = VGA_RD08(pNv->riva.PCIO, 0x3d5);
334     DEBUG(ErrorF("NV_ddc1Read(%p,...) returns %d\n",
335                  pScrn, val));
336     return (val & DDC_SDA_READ_MASK) != 0;
337 }
338
339 static void
340 NV_I2CGetBits(I2CBusPtr b, int *clock, int *data)
341 {
342     NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
343     unsigned char val;
344
345     /* Get the result. */
346     VGA_WR08(pNv->riva.PCIO, 0x3d4, pNv->DDCBase);
347     val = VGA_RD08(pNv->riva.PCIO, 0x3d5);
348
349     *clock = (val & DDC_SCL_READ_MASK) != 0;
350     *data  = (val & DDC_SDA_READ_MASK) != 0;
351     DEBUG(ErrorF("NV_I2CGetBits(%p,...) val=0x%x, returns clock %d, data %d\n",
352                  b, val, *clock, *data));
353 }
354
355 static void
356 NV_I2CPutBits(I2CBusPtr b, int clock, int data)
357 {
358     NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
359     unsigned char val;
360
361     VGA_WR08(pNv->riva.PCIO, 0x3d4, pNv->DDCBase + 1);
362     val = VGA_RD08(pNv->riva.PCIO, 0x3d5) & 0xf0;
363     if (clock)
364         val |= DDC_SCL_WRITE_MASK;
365     else
366         val &= ~DDC_SCL_WRITE_MASK;
367
368     if (data)
369         val |= DDC_SDA_WRITE_MASK;
370     else
371         val &= ~DDC_SDA_WRITE_MASK;
372
373     VGA_WR08(pNv->riva.PCIO, 0x3d4, pNv->DDCBase + 1);
374     VGA_WR08(pNv->riva.PCIO, 0x3d5, val | 0x1);
375     
376     DEBUG(ErrorF("NV_I2CPutBits(%p, %d, %d) val=0x%x\n", b, clock, data, val));
377 }
378
379 static Bool
380 NV_i2cInit(ScrnInfoPtr pScrn)
381 {
382     NVPtr pNv = NVPTR(pScrn);
383     I2CBusPtr I2CPtr;
384
385     I2CPtr = xf86CreateI2CBusRec();
386     if(!I2CPtr) return FALSE;
387
388     pNv->I2C = I2CPtr;
389
390     I2CPtr->BusName    = "DDC";
391     I2CPtr->scrnIndex  = pScrn->scrnIndex;
392     I2CPtr->I2CPutBits = NV_I2CPutBits;
393     I2CPtr->I2CGetBits = NV_I2CGetBits;
394     I2CPtr->AcknTimeout = 5;
395
396     if (!xf86I2CBusInit(I2CPtr)) {
397         return FALSE;
398     }
399     return TRUE;
400 }
401
402 /*
403  * NVRamdacInit
404  */
405 void
406 NVRamdacInit(ScrnInfoPtr pScrn)
407 {
408     NVPtr pNv = NVPTR(pScrn);
409     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NVRamdacInit\n"));
410     pNv->ddc1Read = NV_ddc1Read;
411     /* vgaHWddc1SetSpeed will only work if the card is in VGA mode */
412     pNv->DDC1SetSpeed = vgaHWddc1SetSpeed;
413     pNv->i2cInit = NV_i2cInit;
414 }
415