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