1/*
2 * Copyright (c) 2007 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
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "nv_include.h"
29
30static int
31NVDACPanelTweaks(NVPtr pNv, NVRegPtr state)
32{
33   int tweak = 0;
34
35   if(pNv->usePanelTweak) {
36       tweak = pNv->PanelTweak;
37   } else {
38       /* begin flat panel hacks */
39       /* This is unfortunate, but some chips need this register
40          tweaked or else you get artifacts where adjacent pixels are
41          swapped.  There are no hard rules for what to set here so all
42          we can do is experiment and apply hacks. */
43
44       if(((pNv->Chipset & 0xffff) == 0x0328) && (state->bpp == 32)) {
45#ifdef XSERVER_LIBPCIACCESS
46          if (((pNv->PciInfo->subvendor_id & 0xffff) == 0x1179) &&
47              ((pNv->PciInfo->subdevice_id & 0xffff) == 0x0020))
48#else
49          if (((pNv->PciInfo->subsysVendor & 0xffff) == 0x1179) &&
50              ((pNv->PciInfo->subsysCard & 0xffff) == 0x0020))
51#endif
52          {
53
54             /* Toshiba Tecra M2 */
55             tweak = 1;
56          } else {
57             /* At least one NV34 laptop needs this workaround. */
58             tweak = -1;
59          }
60       }
61
62       if((pNv->Chipset & 0xfff0) == 0x0310) {
63          tweak = 1;
64       }
65       /* end flat panel hacks */
66   }
67
68   return tweak;
69}
70
71Bool
72NVDACInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
73{
74    int i;
75    int horizDisplay    = (mode->CrtcHDisplay/8)   - 1;
76    int horizStart      = (mode->CrtcHSyncStart/8) - 1;
77    int horizEnd        = (mode->CrtcHSyncEnd/8)   - 1;
78    int horizTotal      = (mode->CrtcHTotal/8)     - 5;
79    int horizBlankStart = (mode->CrtcHDisplay/8)   - 1;
80    int horizBlankEnd   = (mode->CrtcHTotal/8)     - 1;
81    int vertDisplay     =  mode->CrtcVDisplay      - 1;
82    int vertStart       =  mode->CrtcVSyncStart    - 1;
83    int vertEnd         =  mode->CrtcVSyncEnd      - 1;
84    int vertTotal       =  mode->CrtcVTotal        - 2;
85    int vertBlankStart  =  mode->CrtcVDisplay      - 1;
86    int vertBlankEnd    =  mode->CrtcVTotal        - 1;
87
88    NVPtr pNv = NVPTR(pScrn);
89    NVRegPtr nvReg = &pNv->ModeReg;
90    NVFBLayout *pLayout = &pNv->CurrentLayout;
91    vgaRegPtr   pVga;
92
93    /*
94     * Initialize all of the generic VGA registers.  Don't bother with
95     * VGA_FIX_SYNC_PULSES, given the relevant CRTC settings are overridden
96     * below.  Ditto for the KGA workaround.
97     */
98    if (!vgaHWInit(pScrn, mode))
99        return(FALSE);
100
101    pVga = &VGAHWPTR(pScrn)->ModeReg;
102
103    /*
104     * Set all CRTC values.
105     */
106
107    if(mode->Flags & V_INTERLACE)
108        vertTotal |= 1;
109
110    if(pNv->FlatPanel == 1) {
111       vertStart = vertTotal - 3;
112       vertEnd = vertTotal - 2;
113       vertBlankStart = vertStart;
114       horizStart = horizTotal - 5;
115       horizEnd = horizTotal - 2;
116       horizBlankEnd = horizTotal + 4;
117       if(pNv->Architecture == NV_ARCH_30)
118           horizTotal += 2;
119    }
120
121    pVga->CRTC[0x0]  = NV_Set8Bits(horizTotal);
122    pVga->CRTC[0x1]  = NV_Set8Bits(horizDisplay);
123    pVga->CRTC[0x2]  = NV_Set8Bits(horizBlankStart);
124    pVga->CRTC[0x3]  = NV_SetBitField(horizBlankEnd,4:0,4:0)
125                       | NV_SetBit(7);
126    pVga->CRTC[0x4]  = NV_Set8Bits(horizStart);
127    pVga->CRTC[0x5]  = NV_SetBitField(horizBlankEnd,5:5,7:7)
128                       | NV_SetBitField(horizEnd,4:0,4:0);
129    pVga->CRTC[0x6]  = NV_SetBitField(vertTotal,7:0,7:0);
130    pVga->CRTC[0x7]  = NV_SetBitField(vertTotal,8:8,0:0)
131                       | NV_SetBitField(vertDisplay,8:8,1:1)
132                       | NV_SetBitField(vertStart,8:8,2:2)
133                       | NV_SetBitField(vertBlankStart,8:8,3:3)
134                       | NV_SetBit(4)
135                       | NV_SetBitField(vertTotal,9:9,5:5)
136                       | NV_SetBitField(vertDisplay,9:9,6:6)
137                       | NV_SetBitField(vertStart,9:9,7:7);
138    pVga->CRTC[0x9]  = NV_SetBitField(vertBlankStart,9:9,5:5)
139                       | NV_SetBit(6)
140                       | ((mode->Flags & V_DBLSCAN) ? 0x80 : 0x00);
141    pVga->CRTC[0x10] = NV_Set8Bits(vertStart);
142    pVga->CRTC[0x11] = NV_SetBitField(vertEnd,3:0,3:0) | NV_SetBit(5);
143    pVga->CRTC[0x12] = NV_Set8Bits(vertDisplay);
144    pVga->CRTC[0x13] = ((pLayout->displayWidth/8)*(pLayout->bitsPerPixel/8));
145    pVga->CRTC[0x15] = NV_Set8Bits(vertBlankStart);
146    pVga->CRTC[0x16] = NV_Set8Bits(vertBlankEnd);
147
148    pVga->Attribute[0x10] = 0x01;
149
150    if(pNv->Television)
151       pVga->Attribute[0x11] = 0x00;
152
153    nvReg->screen = NV_SetBitField(horizBlankEnd,6:6,4:4)
154                  | NV_SetBitField(vertBlankStart,10:10,3:3)
155                  | NV_SetBitField(vertStart,10:10,2:2)
156                  | NV_SetBitField(vertDisplay,10:10,1:1)
157                  | NV_SetBitField(vertTotal,10:10,0:0);
158
159    nvReg->horiz  = NV_SetBitField(horizTotal,8:8,0:0)
160                  | NV_SetBitField(horizDisplay,8:8,1:1)
161                  | NV_SetBitField(horizBlankStart,8:8,2:2)
162                  | NV_SetBitField(horizStart,8:8,3:3);
163
164    nvReg->extra  = NV_SetBitField(vertTotal,11:11,0:0)
165                    | NV_SetBitField(vertDisplay,11:11,2:2)
166                    | NV_SetBitField(vertStart,11:11,4:4)
167                    | NV_SetBitField(vertBlankStart,11:11,6:6);
168
169    if(mode->Flags & V_INTERLACE) {
170       horizTotal = (horizTotal >> 1) & ~1;
171       nvReg->interlace = NV_Set8Bits(horizTotal);
172       nvReg->horiz |= NV_SetBitField(horizTotal,8:8,4:4);
173    } else {
174       nvReg->interlace = 0xff;  /* interlace off */
175    }
176
177
178    /*
179     * Initialize DAC palette.
180     */
181    if(pLayout->bitsPerPixel != 8 )
182    {
183        for (i = 0; i < 256; i++)
184        {
185            pVga->DAC[i*3]     = i;
186            pVga->DAC[(i*3)+1] = i;
187            pVga->DAC[(i*3)+2] = i;
188        }
189    }
190
191    /*
192     * Calculate the extended registers.
193     */
194
195    if(pLayout->depth < 24)
196	i = pLayout->depth;
197    else i = 32;
198
199    if(pNv->Architecture >= NV_ARCH_10)
200	pNv->CURSOR = (U032 *)(pNv->FbStart + pNv->CursorStart);
201
202    NVCalcStateExt(pNv,
203                    nvReg,
204                    i,
205                    pLayout->displayWidth,
206                    mode->CrtcHDisplay,
207                    pScrn->virtualY,
208                    mode->Clock,
209                    mode->Flags);
210
211    nvReg->scale = pNv->PRAMDAC[0x00000848/4] & 0xfff000ff;
212    if(pNv->FlatPanel == 1) {
213       nvReg->pixel |= (1 << 7);
214       if(!pNv->fpScaler || (pNv->fpWidth <= mode->HDisplay)
215                         || (pNv->fpHeight <= mode->VDisplay))
216       {
217           nvReg->scale |= (1 << 8) ;
218       }
219       nvReg->crtcSync = pNv->PRAMDAC[0x0828/4];
220       nvReg->crtcSync += NVDACPanelTweaks(pNv, nvReg);
221       nvReg->crtcVSync = pNv->fpVTotal - 6;
222    }
223
224    nvReg->vpll = nvReg->pll;
225    nvReg->vpll2 = nvReg->pll;
226    nvReg->vpllB = nvReg->pllB;
227    nvReg->vpll2B = nvReg->pllB;
228
229    VGA_WR08(pNv->PCIO, 0x03D4, 0x1C);
230    nvReg->fifo = VGA_RD08(pNv->PCIO, 0x03D5) & ~(1<<5);
231
232    if(pNv->CRTCnumber) {
233       nvReg->head  = pNv->PCRTC0[0x00000860/4] & ~0x00001000;
234       nvReg->head2 = pNv->PCRTC0[0x00002860/4] | 0x00001000;
235       nvReg->crtcOwner = 3;
236       nvReg->pllsel |= 0x20000800;
237       nvReg->vpll = pNv->PRAMDAC0[0x0508/4];
238       if(pNv->twoStagePLL)
239          nvReg->vpllB = pNv->PRAMDAC0[0x0578/4];
240    } else
241    if(pNv->twoHeads) {
242       nvReg->head  =  pNv->PCRTC0[0x00000860/4] | 0x00001000;
243       nvReg->head2 =  pNv->PCRTC0[0x00002860/4] & ~0x00001000;
244       nvReg->crtcOwner = 0;
245       nvReg->vpll2 = pNv->PRAMDAC0[0x0520/4];
246       if(pNv->twoStagePLL)
247          nvReg->vpll2B = pNv->PRAMDAC0[0x057C/4];
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) != 0x0110)
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) == 0x0110) {
264           nvReg->dither = pNv->PRAMDAC[0x0528/4] & ~0x00010000;
265           if(pNv->FPDither)
266              nvReg->dither |= 0x00010000;
267        } else {
268           nvReg->dither = pNv->PRAMDAC[0x083C/4] & ~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
281void
282NVDACRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, NVRegPtr nvReg,
283             Bool primary)
284{
285    NVPtr pNv = NVPTR(pScrn);
286    int restore = VGA_SR_MODE;
287
288    if(primary) restore |= VGA_SR_CMAP | VGA_SR_FONTS;
289    NVLoadStateExt(pNv, nvReg);
290#if defined(__powerpc__)
291    restore &= ~VGA_SR_FONTS;
292#endif
293    vgaHWRestore(pScrn, vgaReg, restore);
294}
295
296/*
297 * NVDACSave
298 *
299 * This function saves the video state.
300 */
301void
302NVDACSave(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, NVRegPtr nvReg,
303          Bool saveFonts)
304{
305    NVPtr pNv = NVPTR(pScrn);
306
307#if defined(__powerpc__)
308    saveFonts = FALSE;
309#endif
310
311    vgaHWSave(pScrn, vgaReg, VGA_SR_CMAP | VGA_SR_MODE |
312                             (saveFonts? VGA_SR_FONTS : 0));
313    NVUnloadStateExt(pNv, nvReg);
314
315    /* can't read this reliably on NV11 */
316    if((pNv->Chipset & 0x0ff0) == 0x0110)
317       nvReg->crtcOwner = pNv->CRTCnumber;
318}
319
320#define DEPTH_SHIFT(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8)))
321#define MAKE_INDEX(in, w) (DEPTH_SHIFT(in, w) * 3)
322
323void
324NVDACLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
325                 VisualPtr pVisual )
326{
327    int i, index;
328    NVPtr pNv = NVPTR(pScrn);
329    vgaRegPtr   pVga;
330
331    pVga = &VGAHWPTR(pScrn)->ModeReg;
332
333    switch(pNv->CurrentLayout.depth) {
334    case 15:
335        for(i = 0; i < numColors; i++) {
336            index = indices[i];
337            pVga->DAC[MAKE_INDEX(index, 5) + 0] = colors[index].red;
338            pVga->DAC[MAKE_INDEX(index, 5) + 1] = colors[index].green;
339            pVga->DAC[MAKE_INDEX(index, 5) + 2] = colors[index].blue;
340        }
341        break;
342    case 16:
343        for(i = 0; i < numColors; i++) {
344            index = indices[i];
345            pVga->DAC[MAKE_INDEX(index, 6) + 1] = colors[index].green;
346	    if(index < 32) {
347            	pVga->DAC[MAKE_INDEX(index, 5) + 0] = colors[index].red;
348            	pVga->DAC[MAKE_INDEX(index, 5) + 2] = colors[index].blue;
349	    }
350        }
351        break;
352    default:
353	for(i = 0; i < numColors; i++) {
354            index = indices[i];
355            pVga->DAC[index*3]     = colors[index].red;
356            pVga->DAC[(index*3)+1] = colors[index].green;
357            pVga->DAC[(index*3)+2] = colors[index].blue;
358	}
359	break;
360    }
361    vgaHWRestore(pScrn, pVga, VGA_SR_CMAP);
362}
363
364/*
365 * DDC1 support only requires DDC_SDA_MASK,
366 * DDC2 support requires DDC_SDA_MASK and DDC_SCL_MASK
367 */
368#define DDC_SDA_READ_MASK  (1 << 3)
369#define DDC_SCL_READ_MASK  (1 << 2)
370#define DDC_SDA_WRITE_MASK (1 << 4)
371#define DDC_SCL_WRITE_MASK (1 << 5)
372
373static void
374NV_I2CGetBits(I2CBusPtr b, int *clock, int *data)
375{
376#ifdef XF86_SCRN_INTERFACE
377    NVPtr pNv = NVPTR(b->pScrn);
378#else
379    NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
380#endif
381    unsigned char val;
382
383    /* Get the result. */
384    VGA_WR08(pNv->PCIO, 0x3d4, pNv->DDCBase);
385    val = VGA_RD08(pNv->PCIO, 0x3d5);
386
387    *clock = (val & DDC_SCL_READ_MASK) != 0;
388    *data  = (val & DDC_SDA_READ_MASK) != 0;
389}
390
391static void
392NV_I2CPutBits(I2CBusPtr b, int clock, int data)
393{
394#ifdef XF86_SCRN_INTERFACE
395    NVPtr pNv = NVPTR(b->pScrn);
396#else
397    NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
398#endif
399    unsigned char val;
400
401    VGA_WR08(pNv->PCIO, 0x3d4, pNv->DDCBase + 1);
402    val = VGA_RD08(pNv->PCIO, 0x3d5) & 0xf0;
403    if (clock)
404        val |= DDC_SCL_WRITE_MASK;
405    else
406        val &= ~DDC_SCL_WRITE_MASK;
407
408    if (data)
409        val |= DDC_SDA_WRITE_MASK;
410    else
411        val &= ~DDC_SDA_WRITE_MASK;
412
413    VGA_WR08(pNv->PCIO, 0x3d4, pNv->DDCBase + 1);
414    VGA_WR08(pNv->PCIO, 0x3d5, val | 0x1);
415}
416
417Bool
418NVDACi2cInit(ScrnInfoPtr pScrn)
419{
420    NVPtr pNv = NVPTR(pScrn);
421    I2CBusPtr I2CPtr;
422
423    I2CPtr = xf86CreateI2CBusRec();
424    if(!I2CPtr) return FALSE;
425
426    pNv->I2C = I2CPtr;
427
428    I2CPtr->BusName    = "DDC";
429    I2CPtr->scrnIndex  = pScrn->scrnIndex;
430#ifdef XF86_SCRN_INTERFACE
431    I2CPtr->pScrn = pScrn;
432#endif
433    I2CPtr->I2CPutBits = NV_I2CPutBits;
434    I2CPtr->I2CGetBits = NV_I2CGetBits;
435    I2CPtr->AcknTimeout = 5;
436
437    if (!xf86I2CBusInit(I2CPtr)) {
438        return FALSE;
439    }
440    return TRUE;
441}
442