savage_cursor.c revision 2b2b4fcb
1/*
2 * Copyright (C) 1994-2000 The XFree86 Project, Inc.  All Rights Reserved.
3 * Copyright (c) 2003-2006, X.Org Foundation
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 * FITESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18 * COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Except as contained in this notice, the name of the copyright holder(s)
24 * and author(s) shall not be used in advertising or otherwise to promote
25 * the sale, use or other dealings in this Software without prior written
26 * authorization from the copyright holder(s) and author(s).
27 */
28
29/**
30 * \file savage_cursor.c
31 * Hardware cursor support for S3 Savage driver. Taken with very few changes
32 * from the s3virge cursor file.
33 *
34 * \author S. Marineau (19/04/97)
35 * \author Amancio Hasty
36 * \author Jon Tombs
37 * \author Tim Roberts
38 */
39
40#ifdef HAVE_CONFIG_H
41#include "config.h"
42#endif
43
44#include "savage_driver.h"
45
46static void SavageLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src);
47static void SavageSetCursorPosition(ScrnInfoPtr pScrn, int x, int y);
48static void SavageSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg);
49
50
51/*
52 * Read/write to the DAC via MMIO
53 */
54
55#define inCRReg(reg) (VGAHWPTR(pScrn))->readCrtc( VGAHWPTR(pScrn), reg )
56#define outCRReg(reg, val) (VGAHWPTR(pScrn))->writeCrtc( VGAHWPTR(pScrn), reg, val )
57#define inSRReg(reg) (VGAHWPTR(pScrn))->readSeq( VGAHWPTR(pScrn), reg )
58#define outSRReg(reg, val) (VGAHWPTR(pScrn))->writeSeq( VGAHWPTR(pScrn), reg, val )
59#if 0
60#define inStatus1() (VGAHWPTR(pScrn))->readST01( VGAHWPTR(pScrn) )
61#endif
62
63/*
64 * certain HW cursor operations seem
65 * to require a delay to prevent lockups.
66 */
67#define waitHSync(n) { \
68                       int num = n; \
69                       while (num--) { \
70			 while (inStatus1() & 0x01){};\
71                         while (!(inStatus1() & 0x01)){};\
72                        } \
73                      }
74#define MAX_CURS 64
75
76/*
77 * Disable HW Cursor on stretched LCDs. We don't know how to
78 * detect if display is stretched. Therefore we cannot rescale
79 * the HW cursor position.
80 */
81
82#if 0
83static Bool
84SavageUseHWCursor(ScreenPtr pScr, CursorPtr pCurs)
85{
86    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScr);
87    SavagePtr psav = SAVPTR(pScrn);
88
89    if (psav->PanelX != pScrn->currentMode->HDisplay
90	|| psav->PanelY != pScrn->currentMode->VDisplay) {
91	/* BIT 1 : CRT is active, BIT 2 : LCD is active */
92	unsigned char cr6d = inCRReg( 0x6d );
93	if (cr6d & 0x02)
94	    return FALSE;
95    }
96    return TRUE;
97}
98#endif
99
100Bool
101SavageHWCursorInit(ScreenPtr pScreen)
102{
103    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
104    SavagePtr psav = SAVPTR(pScrn);
105    xf86CursorInfoPtr infoPtr;
106
107    infoPtr = xf86CreateCursorInfoRec();
108    if(!infoPtr)
109        return FALSE;
110
111    psav->CursorInfoRec = infoPtr;
112
113    infoPtr->MaxWidth = MAX_CURS;
114    infoPtr->MaxHeight = MAX_CURS;
115    infoPtr->Flags = HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16 |
116		     HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
117		     HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
118		     HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
119	             HARDWARE_CURSOR_INVERT_MASK;
120#if 0
121    /*
122     * The /MX family is apparently unique among the Savages, in that
123     * the cursor color is always straight RGB.  The rest of the Savages
124     * use palettized values at 8-bit when not clock doubled.
125     */
126
127    if (((psav->Chipset != S3_SAVAGE4)
128	 && (inSRReg(0x18) & 0x80) && (inSRReg(0x15) & 0x50))
129	|| S3_SAVAGE_MOBILE_SERIES(psav->Chipset))
130	infoPtr->Flags |= HARDWARE_CURSOR_TRUECOLOR_AT_8BPP;
131#endif
132    /*
133     * With streams engine the Cursor seems to be ALWAYS TrueColor
134     *except at least the Savage4
135     */
136    if (psav->Chipset != S3_SAVAGE4)
137	infoPtr->Flags |= HARDWARE_CURSOR_TRUECOLOR_AT_8BPP;
138
139    infoPtr->SetCursorColors = SavageSetCursorColors;
140    infoPtr->SetCursorPosition = SavageSetCursorPosition;
141    infoPtr->LoadCursorImage = SavageLoadCursorImage;
142    infoPtr->HideCursor = SavageHideCursor;
143    infoPtr->ShowCursor = SavageShowCursor;
144    infoPtr->UseHWCursor = NULL;
145#if 0 /*AGD:  HW cursor seems to work fine even with expansion... */
146    if ((S3_SAVAGE_MOBILE_SERIES(psav->Chipset)
147	 || (S3_MOBILE_TWISTER_SERIES(psav->Chipset))) && !psav->CrtOnly)
148	infoPtr->UseHWCursor = SavageUseHWCursor;
149    else
150	infoPtr->UseHWCursor = NULL;
151#endif
152    if( !psav->CursorKByte )
153	psav->CursorKByte = pScrn->videoRam - 4;
154
155    return xf86InitCursor(pScreen, infoPtr);
156}
157
158void
159SavageShowCursor(ScrnInfoPtr pScrn)
160{
161    SavagePtr psav = SAVPTR(pScrn);
162
163   /* Turn cursor on. */
164   if (psav->IsSecondary) {
165       SelectIGA2();
166       outCRReg( 0x45, inCRReg(0x45) | 0x01 );
167       SelectIGA1();
168   } else {
169       outCRReg( 0x45, inCRReg(0x45) | 0x01 );
170   }
171   SAVPTR(pScrn)->hwc_on = TRUE;
172}
173
174
175void
176SavageHideCursor(ScrnInfoPtr pScrn)
177{
178    SavagePtr psav = SAVPTR(pScrn);
179
180    /* Turn cursor off. */
181
182    if( S3_SAVAGE4_SERIES( SAVPTR(pScrn)->Chipset ) )
183    {
184       waitHSync(5);
185    }
186    if (psav->IsSecondary) {
187        SelectIGA2();
188	outCRReg( 0x45, inCRReg(0x45) & 0xfe ); /* cursor2 */
189	SelectIGA1();
190    } else {
191        outCRReg( 0x45, inCRReg(0x45) & 0xfe );
192    }
193    SAVPTR(pScrn)->hwc_on = FALSE;
194}
195
196static void
197SavageLoadCursorImage(
198    ScrnInfoPtr pScrn,
199    unsigned char* src)
200{
201    SavagePtr psav = SAVPTR(pScrn);
202
203    /* Set cursor location in frame buffer.  */
204    if (psav->IsSecondary) {
205	SelectIGA2();
206    	/* Set cursor location in frame buffer.  */
207    	outCRReg( 0x4d, (0xff & psav->CursorKByte));
208    	outCRReg( 0x4c, (0xff00 & psav->CursorKByte) >> 8);
209	SelectIGA1();
210    } else {
211        outCRReg( 0x4d, (0xff & (CARD32)psav->CursorKByte));
212        outCRReg( 0x4c, (0xff00 & (CARD32)psav->CursorKByte) >> 8);
213    }
214
215    /* Upload the cursor image to the frame buffer. */
216    memcpy(psav->FBBase + psav->CursorKByte * 1024, src, 1024);
217
218    if( S3_SAVAGE4_SERIES( psav->Chipset ) ) {
219	/*
220	 * Bug in Savage4 Rev B requires us to do an MMIO read after
221	 * loading the cursor.
222	 */
223	volatile unsigned int i = ALT_STATUS_WORD0;
224	(void)i++;	/* Not to be optimised out */
225    }
226}
227
228static void
229SavageSetCursorPosition(
230     ScrnInfoPtr pScrn,
231     int x,
232     int y)
233{
234    SavagePtr psav = SAVPTR(pScrn);
235    unsigned char xoff, yoff, byte;
236
237    if( S3_SAVAGE4_SERIES( SAVPTR(pScrn)->Chipset ) )
238    {
239	waitHSync(5);
240    }
241    /* adjust for frame buffer base address granularity */
242    if (pScrn->bitsPerPixel == 8)
243	x += ((pScrn->frameX0) & 3);
244    else if (pScrn->bitsPerPixel == 16)
245	x += ((pScrn->frameX0) & 1);
246    else if (pScrn->bitsPerPixel == 32)
247	x += ((pScrn->frameX0+2) & 3) - 2;
248
249    /*
250    * Make these even when used.  There is a bug/feature on at least
251    * some chipsets that causes a "shadow" of the cursor in interlaced
252    * mode.  Making this even seems to have no visible effect, so just
253    * do it for the generic case.
254    */
255
256    if (x < 0) {
257	xoff = ((-x) & 0xFE);
258	x = 0;
259    } else {
260	xoff = 0;
261    }
262
263    if (y < 0) {
264	yoff = ((-y) & 0xFE);
265	y = 0;
266    } else {
267	yoff = 0;
268    }
269
270    /* This is the recommended order to move the cursor */
271        if (psav->IsSecondary) {
272	SelectIGA2();
273    	outCRReg( 0x46, (x & 0xff00)>>8 );
274    	outCRReg( 0x47, (x & 0xff) );
275    	outCRReg( 0x49, (y & 0xff) );
276    	outCRReg( 0x4e, xoff );
277    	outCRReg( 0x4f, yoff );
278    	outCRReg( 0x48, (y & 0xff00)>>8 );
279	SelectIGA1();
280    } else {
281        outCRReg( 0x46, (x & 0xff00)>>8 );
282        outCRReg( 0x47, (x & 0xff) );
283        outCRReg( 0x49, (y & 0xff) );
284        outCRReg( 0x4e, xoff );
285        outCRReg( 0x4f, yoff );
286        outCRReg( 0x48, (y & 0xff00)>>8 );
287    }
288
289    /* fix for HW cursor on crtc2 */
290    byte = inCRReg( 0x46 );
291    outCRReg( 0x46, byte );
292
293}
294
295
296static void
297SavageSetCursorColors(
298    ScrnInfoPtr pScrn,
299    int bg,
300    int fg)
301{
302    SavagePtr psav = SAVPTR(pScrn);
303#if 0
304    Bool bNeedExtra = FALSE;
305#endif
306
307    /* Clock doubled modes need an extra cursor stack write. */
308
309#if 0
310    bNeedExtra =
311        (psav->CursorInfoRec->Flags & HARDWARE_CURSOR_TRUECOLOR_AT_8BPP);
312#endif
313
314    /* With the streams engine on HW Cursor seems to be 24bpp ALWAYS */
315    if( 1
316#if 0
317	|| S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
318 	(pScrn->depth == 24) ||
319 	((pScrn->depth == 8) && bNeedExtra)
320#endif
321	)
322    {
323	/* Do it straight, full 24 bit color. */
324       if (psav->IsSecondary) {
325            /* cursor 2 */
326	    /* Reset the cursor color stack pointer */
327	    SelectIGA2();
328	    inCRReg(0x45);
329	    /* Write low, mid, high bytes - foreground */
330	    outCRReg(0x4a, fg);
331	    outCRReg(0x4a, fg >> 8);
332	    outCRReg(0x4a, fg >> 16);
333	    /* Reset the cursor color stack pointer */
334	    inCRReg(0x45);
335	    /* Write low, mid, high bytes - background */
336	    outCRReg(0x4b, bg);
337	    outCRReg(0x4b, bg >> 8);
338	    outCRReg(0x4b, bg >> 16);
339	    SelectIGA1();
340	} else {
341	    /* Reset the cursor color stack pointer */
342	    inCRReg(0x45);
343	    /* Write low, mid, high bytes - foreground */
344	    outCRReg(0x4a, fg);
345	    outCRReg(0x4a, fg >> 8);
346	    outCRReg(0x4a, fg >> 16);
347	    /* Reset the cursor color stack pointer */
348	    inCRReg(0x45);
349	    /* Write low, mid, high bytes - background */
350	    outCRReg(0x4b, bg);
351	    outCRReg(0x4b, bg >> 8);
352	    outCRReg(0x4b, bg >> 16);
353	}
354	return;
355    }
356#if 0
357    else if( (pScrn->depth == 15) || (pScrn->depth == 16) )
358    {
359	if (pScrn->depth == 15) {
360	    fg = ((fg & 0xf80000) >> 9) |
361		((fg & 0xf800) >> 6) |
362		((fg & 0xf8) >> 3);
363	    bg = ((bg & 0xf80000) >> 9) |
364		((bg & 0xf800) >> 6) |
365		((bg & 0xf8) >> 3);
366	} else {
367	    fg = ((fg & 0xf80000) >> 8) |
368		((fg & 0xfc00) >> 5) |
369		((fg & 0xf8) >> 3);
370	    bg = ((bg & 0xf80000) >> 8) |
371		((bg & 0xfc00) >> 5) |
372		((bg & 0xf8) >> 3);
373	}
374	/* Reset the cursor color stack pointer */
375        inCRReg( 0x45 );
376        outCRReg( 0x4a, fg );
377        outCRReg( 0x4a, fg>>8 );
378	if( bNeedExtra )
379	{
380	    outCRReg( 0x4a, fg );
381	    outCRReg( 0x4a, fg>>8 );
382	}
383	/* Reset the cursor color stack pointer */
384        inCRReg( 0x45 );
385        outCRReg( 0x4b, bg );
386        outCRReg( 0x4b, bg>>8 );
387	if( bNeedExtra )
388	{
389	    outCRReg( 0x4b, bg );
390	    outCRReg( 0x4b, bg>>8 );
391	}
392    }
393    else if( pScrn->depth == 8 )
394    {
395	/* Reset the cursor color stack pointer */
396	inCRReg(0x45);
397	/* Write foreground */
398	outCRReg(0x4a, fg);
399	outCRReg(0x4a, fg);
400	/* Reset the cursor color stack pointer */
401	inCRReg(0x45);
402	/* Write background */
403	outCRReg(0x4b, bg);
404	outCRReg(0x4b, bg);
405    }
406#endif
407}
408