pm2v_dac.c revision 1fb744b4
1/*
2 * Copyright 1997-2001 by Alan Hourihane <alanh@fairlite.demon.co.uk>
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Alan Hourihane not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Alan Hourihane makes no representations
11 * about the suitability of this software for any purpose.  It is provided
12 * "as is" without express or implied warranty.
13 *
14 * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL ALAN HOURIHANE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Authors:  Alan Hourihane, <alanh@fairlite.demon.co.uk>
23 *           Dirk Hohndel,   <hohndel@suse.de>
24 *	     Stefan Dirsch,  <sndirsch@suse.de>
25 *	     Helmut Fahrion, <hf@suse.de>
26 *
27 * this work is sponsored by S.u.S.E. GmbH, Fuerth, Elsa GmbH, Aachen and
28 * Siemens Nixdorf Informationssysteme
29 */
30
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#include "xf86.h"
36#include "xf86_OSproc.h"
37
38#include "xf86Pci.h"
39
40#include "glint_regs.h"
41#include "glint.h"
42
43static unsigned long
44PM2VDAC_CalculateClock
45(
46 unsigned long reqclock,		/* In kHz units */
47 unsigned long refclock,		/* In kHz units */
48 unsigned char *prescale,		/* ClkPreScale */
49 unsigned char *feedback, 		/* ClkFeedBackScale */
50 unsigned char *postscale		/* ClkPostScale */
51 )
52{
53    int			f, pre, post;
54    unsigned long	freq;
55    long		freqerr = 1000;
56    unsigned long  	actualclock = 0;
57    unsigned char	divide[5] = { 1, 2, 4, 8, 16 };
58
59    for (f=1;f<256;f++) {
60	for (pre=1;pre<256;pre++) {
61	    for (post=0;post<2;post++) {
62	    	freq = ((refclock * f) / (pre * (1 << divide[post])));
63		if ((reqclock > freq - freqerr)&&(reqclock < freq + freqerr)){
64		    freqerr = (reqclock > freq) ?
65					reqclock - freq : freq - reqclock;
66		    *feedback = f;
67		    *prescale = pre;
68		    *postscale = post;
69		    actualclock = freq;
70		}
71	    }
72	}
73    }
74
75    return(actualclock);
76}
77
78static void
79Permedia2VPreInitSecondary(ScrnInfoPtr pScrn)
80{
81    GLINTPtr pGlint = GLINTPTR(pScrn);
82
83    /* disable MCLK */
84    Permedia2vOutIndReg(pScrn, PM2VDACRDMClkControl, 0x00, 0);
85
86    /* boot new mclk values */
87    Permedia2vOutIndReg(pScrn, PM2VDACRDMClkPreScale, 0x00, 0x09);
88    Permedia2vOutIndReg(pScrn, PM2VDACRDMClkFeedbackScale, 0x00, 0x58);
89    Permedia2vOutIndReg(pScrn, PM2VDACRDMClkPostScale, 0x00, 0x01);
90
91    /* re-enable MCLK */
92    Permedia2vOutIndReg(pScrn, PM2VDACRDMClkControl, 0x00, 1);
93
94    /* spin until locked MCLK */
95    while ( (Permedia2vInIndReg(pScrn, PM2VDACRDMClkControl) & 0x2) == 0);
96
97    /* Now re-boot the SGRAM's */
98    GLINT_SLOW_WRITE_REG(0xe6002021,PMMemConfig);
99    GLINT_SLOW_WRITE_REG(0x00000020,PMBootAddress);
100}
101
102void
103Permedia2VPreInit(ScrnInfoPtr pScrn)
104{
105    GLINTPtr pGlint = GLINTPTR(pScrn);
106
107    if (IS_JPRO) {
108	/* Appian Jeronimo Pro 4x8mb (pm2v version) */
109	/* BIOS doesn't initialize the secondary heads, so we need to */
110
111        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
112	    "Appian Jeronimo Pro 4x8mb board detected and initialized.\n");
113
114	Permedia2VPreInitSecondary(pScrn);
115    }
116
117#if defined(__alpha__)
118    /*
119     * On Alpha, we have to init secondary PM2V cards, since
120     * int10 cannot be run on the OEMed cards with VGA disable
121     * jumpers.
122     */
123    if (!xf86IsPrimaryPci(pGlint->PciInfo)) {
124	if ( IS_QPM2V ) {
125
126	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
127		       "PM2V secondary: initializing\n");
128	    Permedia2VPreInitSecondary(pScrn);
129	}
130    }
131#endif /* __alpha__ */
132}
133
134Bool
135Permedia2VInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
136{
137    GLINTPtr pGlint = GLINTPTR(pScrn);
138    GLINTRegPtr pReg = &pGlint->ModeReg[0];
139    CARD32 temp1, temp2, temp3, temp4;
140
141    temp1 = 0;
142    temp2 = 0;
143#if X_BYTE_ORDER == X_BIG_ENDIAN
144    switch (pGlint->HwBpp) {
145    case 8:
146    case 24:
147	    temp1 = 0x00;
148	    temp2 = 0x00;
149	    break;
150
151    case 15:
152    case 16:
153	    temp1 = 0x02;
154	    temp2 = 0x02;
155	    break;
156
157    case 32:
158	    temp1 = 0x01;
159	    temp2 = 0x01;
160	    break;
161    default:
162	    break;
163    };
164#endif /* BIG_ENDIAN */
165
166    pReg->glintRegs[Aperture0 >> 3] = temp1;
167    pReg->glintRegs[Aperture1 >> 3] = temp2;
168
169    pReg->glintRegs[PMFramebufferWriteMask >> 3] = 0xFFFFFFFF;
170    pReg->glintRegs[PMBypassWriteMask >> 3] = 0xFFFFFFFF;
171
172    pReg->glintRegs[DFIFODis >> 3] = 0;
173    pReg->glintRegs[FIFODis >> 3] = 1;
174
175    if (pGlint->UseBlockWrite)
176	pReg->glintRegs[PMMemConfig >> 3] = GLINT_READ_REG(PMMemConfig) | 1<<21;
177
178    temp1 = mode->CrtcHSyncStart - mode->CrtcHDisplay;
179    temp2 = mode->CrtcVSyncStart - mode->CrtcVDisplay;
180    temp3 = mode->CrtcHSyncEnd - mode->CrtcHSyncStart;
181    temp4 = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
182
183    pReg->glintRegs[PMHTotal >> 3] = Shiftbpp(pScrn,mode->CrtcHTotal);
184    pReg->glintRegs[PMHsEnd >> 3] = Shiftbpp(pScrn, temp1 + temp3);
185    pReg->glintRegs[PMHsStart >> 3] = Shiftbpp(pScrn, temp1);
186    pReg->glintRegs[PMHbEnd >> 3] =
187			Shiftbpp(pScrn,mode->CrtcHTotal-mode->CrtcHDisplay);
188    pReg->glintRegs[PMScreenStride >> 3] =
189					Shiftbpp(pScrn,pScrn->displayWidth>>1);
190
191    pReg->glintRegs[PMVTotal >> 3] = mode->CrtcVTotal;
192    pReg->glintRegs[PMVsEnd >> 3] = temp2 + temp4;
193    pReg->glintRegs[PMVsStart >> 3] = temp2;
194    pReg->glintRegs[PMVbEnd >> 3] = mode->CrtcVTotal - mode->CrtcVDisplay;
195
196    /* The hw cursor needs /VSYNC to recognize vert retrace. We'll stick
197       both sync lines to active low here and if needed invert them
198       using the RAMDAC's RDSyncControl below. */
199    pReg->glintRegs[PMVideoControl >> 3] =
200	(1 << 5) | (1 << 3) | 1;
201
202    /* We stick the RAMDAC into 64bit mode */
203    /* And reduce the horizontal timings and clock by half */
204    pReg->glintRegs[PMVideoControl >> 3] |= 1<<16;
205    pReg->glintRegs[PMHTotal >> 3] >>= 1;
206    pReg->glintRegs[PMHsEnd >> 3] >>= 1;
207    pReg->glintRegs[PMHsStart >> 3] >>= 1;
208    pReg->glintRegs[PMHbEnd >> 3] >>= 1;
209
210    pReg->glintRegs[VClkCtl >> 3] = (GLINT_READ_REG(VClkCtl) & 0xFFFFFFFC);
211    pReg->glintRegs[PMScreenBase >> 3] = 0;
212    pReg->glintRegs[PMHTotal >> 3] -= 1;
213    pReg->glintRegs[PMHsStart >> 3] -= 1; /* PMHsStart */
214    pReg->glintRegs[PMVTotal >> 3] -= 1; /* PMVTotal */
215
216    pReg->glintRegs[ChipConfig >> 3] = GLINT_READ_REG(ChipConfig) & 0xFFFFFFDD;
217    pReg->DacRegs[PM2VDACRDDACControl] = 0x00;
218
219    {
220	/* Get the programmable clock values */
221    	unsigned char m,n,p;
222
223	(void) PM2VDAC_CalculateClock(mode->Clock/2,pGlint->RefClock,
224								&m,&n,&p);
225	pReg->DacRegs[PM2VDACRDDClk0PreScale] = m;
226	pReg->DacRegs[PM2VDACRDDClk0FeedbackScale] = n;
227	pReg->DacRegs[PM2VDACRDDClk0PostScale] = p;
228    }
229
230    pReg->glintRegs[PM2VDACRDIndexControl >> 3] = 0x00;
231
232    if (pScrn->rgbBits == 8)
233        pReg->DacRegs[PM2VDACRDMiscControl] = 0x01; /* 8bit DAC */
234    else
235	pReg->DacRegs[PM2VDACRDMiscControl] = 0x00; /* 6bit DAC */
236
237    pReg->DacRegs[PM2VDACRDSyncControl] = 0x00;
238    if (mode->Flags & V_PHSYNC)
239        pReg->DacRegs[PM2VDACRDSyncControl] |= 0x01; /* invert hsync */
240    if (mode->Flags & V_PVSYNC)
241        pReg->DacRegs[PM2VDACRDSyncControl] |= 0x08; /* invert vsync */
242
243    switch (pScrn->bitsPerPixel)
244    {
245    case 8:
246	pReg->DacRegs[PM2VDACRDPixelSize] = 0x00;
247	pReg->DacRegs[PM2VDACRDColorFormat] = 0x2E;
248    	break;
249    case 16:
250        pReg->DacRegs[PM2VDACRDMiscControl] |= 0x08;
251	pReg->DacRegs[PM2VDACRDPixelSize] = 0x01;
252	if (pScrn->depth == 15)
253	    pReg->DacRegs[PM2VDACRDColorFormat] = 0x61;
254	else
255	    pReg->DacRegs[PM2VDACRDColorFormat] = 0x70;
256    	break;
257    case 24:
258        pReg->DacRegs[PM2VDACRDMiscControl] |= 0x08;
259	pReg->DacRegs[PM2VDACRDPixelSize] = 0x04;
260	pReg->DacRegs[PM2VDACRDColorFormat] = 0x60;
261    	break;
262    case 32:
263        pReg->DacRegs[PM2VDACRDMiscControl] |= 0x08;
264	pReg->DacRegs[PM2VDACRDPixelSize] = 0x02;
265	pReg->DacRegs[PM2VDACRDColorFormat] = 0x20;
266	if (pScrn->overlayFlags & OVERLAY_8_32_PLANAR) {
267	    pReg->DacRegs[PM2VDACRDMiscControl] |= 0x18;
268	    pReg->DacRegs[PM2VDACRDOverlayKey] = pScrn->colorKey;
269	}
270    	break;
271    }
272
273    return(TRUE);
274}
275
276void
277Permedia2VSave(ScrnInfoPtr pScrn, GLINTRegPtr glintReg)
278{
279    GLINTPtr pGlint = GLINTPTR(pScrn);
280    int i;
281
282    /* We can't rely on the vgahw layer copying the font information
283     * back properly, due to problems with MMIO access to VGA space
284     * so we memcpy the information */
285    memcpy((CARD8*)pGlint->VGAdata,(CARD8*)pGlint->FbBase, 65536);
286
287    glintReg->glintRegs[ChipConfig >> 3] = GLINT_READ_REG(ChipConfig);
288    glintReg->glintRegs[Aperture0 >> 3]  = GLINT_READ_REG(Aperture0);
289    glintReg->glintRegs[Aperture1 >> 3]  = GLINT_READ_REG(Aperture1);
290    glintReg->glintRegs[PMFramebufferWriteMask >> 3] =
291					GLINT_READ_REG(PMFramebufferWriteMask);
292    glintReg->glintRegs[PMBypassWriteMask >> 3] =
293					GLINT_READ_REG(PMBypassWriteMask);
294    glintReg->glintRegs[DFIFODis >> 3]  = GLINT_READ_REG(DFIFODis);
295    glintReg->glintRegs[FIFODis >> 3]  = GLINT_READ_REG(FIFODis);
296    /* We only muck about with PMMemConfig, if user wants to */
297    if (pGlint->UseBlockWrite)
298	glintReg->glintRegs[PMMemConfig >> 3] = GLINT_READ_REG(PMMemConfig);
299    glintReg->glintRegs[PMHTotal >> 3] = GLINT_READ_REG(PMHTotal);
300    glintReg->glintRegs[PMHbEnd >> 3] = GLINT_READ_REG(PMHbEnd);
301    glintReg->glintRegs[PMHbEnd >> 3] = GLINT_READ_REG(PMHgEnd);
302    glintReg->glintRegs[PMScreenStride >> 3] = GLINT_READ_REG(PMScreenStride);
303    glintReg->glintRegs[PMHsStart >> 3] = GLINT_READ_REG(PMHsStart);
304    glintReg->glintRegs[PMHsEnd >> 3] = GLINT_READ_REG(PMHsEnd);
305    glintReg->glintRegs[PMVTotal >> 3] = GLINT_READ_REG(PMVTotal);
306    glintReg->glintRegs[PMVbEnd >> 3] = GLINT_READ_REG(PMVbEnd);
307    glintReg->glintRegs[PMVsStart >> 3] = GLINT_READ_REG(PMVsStart);
308    glintReg->glintRegs[PMVsEnd >> 3] = GLINT_READ_REG(PMVsEnd);
309    glintReg->glintRegs[PMScreenBase >> 3] = GLINT_READ_REG(PMScreenBase);
310    glintReg->glintRegs[PMVideoControl >> 3] = GLINT_READ_REG(PMVideoControl);
311    glintReg->glintRegs[VClkCtl >> 3] = GLINT_READ_REG(VClkCtl);
312
313    for (i=0;i<768;i++) {
314    	Permedia2ReadAddress(pScrn, i);
315	glintReg->cmap[i] = Permedia2ReadData(pScrn);
316    }
317
318    glintReg->glintRegs[PM2VDACRDIndexControl >> 3] =
319				GLINT_READ_REG(PM2VDACRDIndexControl);
320    glintReg->DacRegs[PM2VDACRDOverlayKey] =
321				Permedia2vInIndReg(pScrn, PM2VDACRDOverlayKey);
322    glintReg->DacRegs[PM2VDACRDSyncControl] =
323				Permedia2vInIndReg(pScrn, PM2VDACRDSyncControl);
324    glintReg->DacRegs[PM2VDACRDMiscControl] =
325				Permedia2vInIndReg(pScrn, PM2VDACRDMiscControl);
326    glintReg->DacRegs[PM2VDACRDDACControl] =
327				Permedia2vInIndReg(pScrn, PM2VDACRDDACControl);
328    glintReg->DacRegs[PM2VDACRDPixelSize] =
329				Permedia2vInIndReg(pScrn, PM2VDACRDPixelSize);
330    glintReg->DacRegs[PM2VDACRDColorFormat] =
331				Permedia2vInIndReg(pScrn, PM2VDACRDColorFormat);
332
333    glintReg->DacRegs[PM2VDACRDDClk0PreScale] = Permedia2vInIndReg(pScrn, PM2VDACRDDClk0PreScale);
334    glintReg->DacRegs[PM2VDACRDDClk0FeedbackScale] = Permedia2vInIndReg(pScrn, PM2VDACRDDClk0FeedbackScale);
335    glintReg->DacRegs[PM2VDACRDDClk0PostScale] = Permedia2vInIndReg(pScrn, PM2VDACRDDClk0PostScale);
336}
337
338void
339Permedia2VRestore(ScrnInfoPtr pScrn, GLINTRegPtr glintReg)
340{
341    GLINTPtr pGlint = GLINTPTR(pScrn);
342    CARD32 temp;
343    int i;
344
345    /* We can't rely on the vgahw layer copying the font information
346     * back properly, due to problems with MMIO access to VGA space
347     * so we memcpy the information */
348    if (pGlint->STATE)
349    	memcpy((CARD8*)pGlint->FbBase,(CARD8*)pGlint->VGAdata, 65536);
350
351    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[ChipConfig >> 3], ChipConfig);
352    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[Aperture0 >> 3], Aperture0);
353    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[Aperture1 >> 3], Aperture1);
354    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMFramebufferWriteMask >> 3],
355							PMFramebufferWriteMask);
356    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMBypassWriteMask >> 3],
357							PMBypassWriteMask);
358    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[DFIFODis >> 3], DFIFODis);
359    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[FIFODis >> 3], FIFODis);
360    /* We only muck about with PMMemConfig, if user wants to */
361    if (pGlint->UseBlockWrite)
362    	GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMMemConfig >> 3],PMMemConfig);
363    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMVideoControl >> 3],
364								PMVideoControl);
365    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMHbEnd >> 3], PMHgEnd);
366    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMScreenBase >> 3], PMScreenBase);
367    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[VClkCtl >> 3], VClkCtl);
368    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMScreenStride >> 3],
369								PMScreenStride);
370    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMHTotal >> 3], PMHTotal);
371    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMHbEnd >> 3], PMHbEnd);
372    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMHsStart >> 3], PMHsStart);
373    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMHsEnd >> 3], PMHsEnd);
374    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMVTotal >> 3], PMVTotal);
375    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMVbEnd >> 3], PMVbEnd);
376    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMVsStart >> 3], PMVsStart);
377    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMVsEnd >> 3], PMVsEnd);
378
379    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PM2VDACRDIndexControl >> 3],
380				PM2VDACRDIndexControl);
381    Permedia2vOutIndReg(pScrn, PM2VDACRDOverlayKey, 0x00,
382				glintReg->DacRegs[PM2VDACRDOverlayKey]);
383    Permedia2vOutIndReg(pScrn, PM2VDACRDSyncControl, 0x00,
384				glintReg->DacRegs[PM2VDACRDSyncControl]);
385    Permedia2vOutIndReg(pScrn, PM2VDACRDMiscControl, 0x00,
386				glintReg->DacRegs[PM2VDACRDMiscControl]);
387    Permedia2vOutIndReg(pScrn, PM2VDACRDDACControl, 0x00,
388				glintReg->DacRegs[PM2VDACRDDACControl]);
389    Permedia2vOutIndReg(pScrn, PM2VDACRDPixelSize, 0x00,
390				glintReg->DacRegs[PM2VDACRDPixelSize]);
391    Permedia2vOutIndReg(pScrn, PM2VDACRDColorFormat, 0x00,
392				glintReg->DacRegs[PM2VDACRDColorFormat]);
393
394    for (i=0;i<768;i++) {
395    	Permedia2WriteAddress(pScrn, i);
396	Permedia2WriteData(pScrn, glintReg->cmap[i]);
397    }
398
399    temp = Permedia2vInIndReg(pScrn, PM2VDACIndexClockControl) & 0xFC;
400    Permedia2vOutIndReg(pScrn, PM2VDACRDDClk0PreScale, 0x00,
401				glintReg->DacRegs[PM2VDACRDDClk0PreScale]);
402    Permedia2vOutIndReg(pScrn, PM2VDACRDDClk0FeedbackScale, 0x00,
403				glintReg->DacRegs[PM2VDACRDDClk0FeedbackScale]);
404    Permedia2vOutIndReg(pScrn, PM2VDACRDDClk0PostScale, 0x00,
405				glintReg->DacRegs[PM2VDACRDDClk0PostScale]);
406    Permedia2vOutIndReg(pScrn, PM2VDACIndexClockControl, 0x00, temp|0x03);
407}
408
409static void
410Permedia2vShowCursor(ScrnInfoPtr pScrn)
411{
412    /* Enable cursor - X11 mode */
413    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorMode, 0x00, 0x11);
414}
415
416static void Permedia2vLoadCursorCallback(ScrnInfoPtr pScrn);
417
418static void
419Permedia2vHideCursor(ScrnInfoPtr pScrn)
420{
421    GLINTPtr pGlint = GLINTPTR(pScrn);
422
423    /* Disable cursor - X11 mode */
424    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorMode, 0x00, 0x10);
425
426    /*
427     * For some reason, we need to clear the image as well as disable
428     * the cursor on PM2V, but not on PM3. The problem is noticeable
429     * only when running multi-head, as you can see the cursor get
430     * "left behind" on the screen it is leaving...
431     */
432    if (pGlint->Chipset == PCI_VENDOR_3DLABS_CHIP_PERMEDIA2V) {
433        memset(pGlint->HardwareCursorPattern, 0, 1024);
434	pGlint->LoadCursorCallback = Permedia2vLoadCursorCallback;
435    }
436}
437
438static void
439Permedia2vLoadCursorCallback(
440    ScrnInfoPtr pScrn
441)
442{
443    GLINTPtr pGlint = GLINTPTR(pScrn);
444    int i;
445
446    for (i=0; i<1024; i++)
447    	Permedia2vOutIndReg(pScrn, PM2VDACRDCursorPattern+i, 0x00,
448					pGlint->HardwareCursorPattern[i]);
449
450    pGlint->LoadCursorCallback = NULL;
451}
452
453static void
454Permedia2vLoadCursorImage(
455    ScrnInfoPtr pScrn,
456    unsigned char *src
457)
458{
459    GLINTPtr pGlint = GLINTPTR(pScrn);
460    int i;
461
462    for (i=0; i<1024; i++)
463	pGlint->HardwareCursorPattern[i] = *(src++);
464
465    pGlint->LoadCursorCallback = Permedia2vLoadCursorCallback;
466}
467
468static void
469Permedia2vSetCursorPosition(
470   ScrnInfoPtr pScrn,
471   int x, int y
472)
473{
474    x += 64;
475    y += 64;
476    /* Output position - "only" 11 bits of location documented */
477
478    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorHotSpotX, 0x00, 0x3f);
479    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorHotSpotY, 0x00, 0x3f);
480    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorXLow, 0x00, x & 0xFF);
481    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorXHigh, 0x00, (x>>8) & 0x0F);
482    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorYLow, 0x00, y & 0xFF);
483    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorYHigh, 0x00, (y>>8) & 0x0F);
484    Permedia2vOutIndReg(pScrn, PM2DACCursorControl, 0x00, 0x00);
485}
486
487static void
488Permedia2vCursorColorCallback(
489   ScrnInfoPtr pScrn
490)
491{
492    GLINTPtr pGlint = GLINTPTR(pScrn);
493    int fg = pGlint->FGCursor;
494    int bg = pGlint->BGCursor;
495
496    if ((pGlint->Chipset == PCI_VENDOR_3DLABS_CHIP_PERMEDIA3) ||
497	((pGlint->Chipset == PCI_VENDOR_3DLABS_CHIP_GAMMA) &&
498	 (pGlint->MultiChip == PCI_CHIP_3DLABS_PERMEDIA3)) ) {
499    /* PM3 uses last 2 indexes into hardware cursor palette fg first...*/
500    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorPalette+39, 0x00, (fg>>16)&0xff);
501    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorPalette+40, 0x00, (fg>>8)&0xff);
502    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorPalette+41, 0x00, fg & 0xff);
503
504    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorPalette+42, 0x00, (bg>>16)&0xff);
505    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorPalette+43, 0x00, (bg>>8)&0xff);
506    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorPalette+44, 0x00, bg & 0xff);
507    } else {
508    /* PM2v uses first 2 indexes into hardware cursor palette bg first...*/
509    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorPalette+0, 0x00, (bg>>16)&0xff);
510    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorPalette+1, 0x00, (bg>>8)&0xff);
511    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorPalette+2, 0x00, bg & 0xff);
512
513    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorPalette+3, 0x00, (fg>>16)&0xff);
514    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorPalette+4, 0x00, (fg>>8)&0xff);
515    Permedia2vOutIndReg(pScrn, PM2VDACRDCursorPalette+5, 0x00, fg & 0xff);
516    }
517    pGlint->CursorColorCallback = NULL;
518}
519
520static void
521Permedia2vSetCursorColors(
522   ScrnInfoPtr pScrn,
523   int bg, int fg
524)
525{
526    GLINTPtr pGlint = GLINTPTR(pScrn);
527
528    pGlint->FGCursor = fg;
529    pGlint->BGCursor = bg;
530
531    pGlint->CursorColorCallback = Permedia2vCursorColorCallback;
532}
533
534static Bool
535Permedia2vUseHWCursor(ScreenPtr pScr, CursorPtr pCurs)
536{
537    return TRUE;
538}
539
540Bool
541Permedia2vHWCursorInit(ScreenPtr pScreen)
542{
543    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
544    GLINTPtr pGlint = GLINTPTR(pScrn);
545    xf86CursorInfoPtr infoPtr;
546
547    infoPtr = xf86CreateCursorInfoRec();
548    if(!infoPtr) return FALSE;
549
550    pGlint->CursorInfoRec = infoPtr;
551
552    infoPtr->MaxWidth = 64;
553    infoPtr->MaxHeight = 64;
554    infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
555#if X_BYTE_ORDER == X_BIG_ENDIAN
556		HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
557#endif
558		HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1;
559    infoPtr->SetCursorColors = Permedia2vSetCursorColors;
560    infoPtr->SetCursorPosition = Permedia2vSetCursorPosition;
561    infoPtr->LoadCursorImage = Permedia2vLoadCursorImage;
562    infoPtr->HideCursor = Permedia2vHideCursor;
563    infoPtr->ShowCursor = Permedia2vShowCursor;
564    infoPtr->UseHWCursor = Permedia2vUseHWCursor;
565
566    return(xf86InitCursor(pScreen, infoPtr));
567}
568