r128_cursor.c revision 42a55b46
1c582b7e3Smrg/*
2c582b7e3Smrg * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
3c582b7e3Smrg *                      Precision Insight, Inc., Cedar Park, Texas, and
4c582b7e3Smrg *                      VA Linux Systems Inc., Fremont, California.
5c582b7e3Smrg *
6c582b7e3Smrg * All Rights Reserved.
7c582b7e3Smrg *
8c582b7e3Smrg * Permission is hereby granted, free of charge, to any person obtaining
9c582b7e3Smrg * a copy of this software and associated documentation files (the
10c582b7e3Smrg * "Software"), to deal in the Software without restriction, including
11c582b7e3Smrg * without limitation on the rights to use, copy, modify, merge,
12c582b7e3Smrg * publish, distribute, sublicense, and/or sell copies of the Software,
13c582b7e3Smrg * and to permit persons to whom the Software is furnished to do so,
14c582b7e3Smrg * subject to the following conditions:
15c582b7e3Smrg *
16c582b7e3Smrg * The above copyright notice and this permission notice (including the
17c582b7e3Smrg * next paragraph) shall be included in all copies or substantial
18c582b7e3Smrg * portions of the Software.
19c582b7e3Smrg *
20c582b7e3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21c582b7e3Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22c582b7e3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23c582b7e3Smrg * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX
24c582b7e3Smrg * SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25c582b7e3Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26c582b7e3Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27c582b7e3Smrg * OTHER DEALINGS IN THE SOFTWARE.
28c582b7e3Smrg */
29c582b7e3Smrg
30c582b7e3Smrg/*
31c582b7e3Smrg * Authors:
32c582b7e3Smrg *   Rickard E. Faith <faith@valinux.com>
33c582b7e3Smrg *   Kevin E. Martin <martin@valinux.com>
34c582b7e3Smrg *
35c582b7e3Smrg * References:
36c582b7e3Smrg *
37c582b7e3Smrg *   RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical
38c582b7e3Smrg *   Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April
39c582b7e3Smrg *   1999.
40c582b7e3Smrg *
41c582b7e3Smrg *   RAGE 128 Software Development Manual (Technical Reference Manual P/N
42c582b7e3Smrg *   SDK-G04000 Rev. 0.01), ATI Technologies: June 1999.
43c582b7e3Smrg *
44c582b7e3Smrg */
45c582b7e3Smrg
46c582b7e3Smrg#ifdef HAVE_CONFIG_H
47c582b7e3Smrg#include "config.h"
48c582b7e3Smrg#endif
49c582b7e3Smrg
50c582b7e3Smrg				/* Driver data structures */
51c582b7e3Smrg#include "r128.h"
52c582b7e3Smrg#include "r128_reg.h"
53c582b7e3Smrg
54c582b7e3Smrg				/* X and server generic header files */
55c582b7e3Smrg#include "xf86.h"
56c582b7e3Smrg
5742a55b46Smrg				/* Because for EXA we need to use a different allocator */
5842a55b46Smrg#ifdef USE_EXA
5942a55b46Smrg#include "exa.h"
6042a55b46Smrg#endif
6142a55b46Smrg
62c582b7e3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
63c582b7e3Smrg#define P_SWAP32( a , b )                \
64c582b7e3Smrg       ((char *)a)[0] = ((char *)b)[3];  \
65c582b7e3Smrg       ((char *)a)[1] = ((char *)b)[2];  \
66c582b7e3Smrg       ((char *)a)[2] = ((char *)b)[1];  \
67c582b7e3Smrg       ((char *)a)[3] = ((char *)b)[0]
68c582b7e3Smrg
69c582b7e3Smrg#define P_SWAP16( a , b )                \
70c582b7e3Smrg       ((char *)a)[0] = ((char *)b)[1];  \
71c582b7e3Smrg       ((char *)a)[1] = ((char *)b)[0];  \
72c582b7e3Smrg       ((char *)a)[2] = ((char *)b)[3];  \
73c582b7e3Smrg       ((char *)a)[3] = ((char *)b)[2]
74c582b7e3Smrg#endif
75c582b7e3Smrg
76c582b7e3Smrg
77c582b7e3Smrg/* Set cursor foreground and background colors. */
78c582b7e3Smrgstatic void R128SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
79c582b7e3Smrg{
80c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
81c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
82c582b7e3Smrg
83c582b7e3Smrg    if(info->IsSecondary)
84c582b7e3Smrg    {
85c582b7e3Smrg        OUTREG(R128_CUR2_CLR0, bg);
86c582b7e3Smrg        OUTREG(R128_CUR2_CLR1, fg);
87c582b7e3Smrg    }
88c582b7e3Smrg    else
89c582b7e3Smrg    {
90c582b7e3Smrg    	OUTREG(R128_CUR_CLR0, bg);
91c582b7e3Smrg    	OUTREG(R128_CUR_CLR1, fg);
92c582b7e3Smrg    }
93c582b7e3Smrg}
94c582b7e3Smrg
95c582b7e3Smrg/* Set cursor position to (x,y) with offset into cursor bitmap at
96c582b7e3Smrg   (xorigin,yorigin). */
97c582b7e3Smrgstatic void R128SetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
98c582b7e3Smrg{
99c582b7e3Smrg    R128InfoPtr           info      = R128PTR(pScrn);
100c582b7e3Smrg    unsigned char         *R128MMIO = info->MMIO;
101c582b7e3Smrg    xf86CursorInfoPtr     cursor    = info->cursor;
102c582b7e3Smrg    int                   xorigin   = 0;
103c582b7e3Smrg    int                   yorigin   = 0;
104c582b7e3Smrg    int                   total_y   = pScrn->frameY1 - pScrn->frameY0;
105c582b7e3Smrg
106c582b7e3Smrg    if (x < 0)                        xorigin = -x;
107c582b7e3Smrg    if (y < 0)                        yorigin = -y;
108c582b7e3Smrg    if (y > total_y)                  y       = total_y;
109c582b7e3Smrg    if (info->Flags & V_DBLSCAN)      y       *= 2;
110c582b7e3Smrg    if (xorigin >= cursor->MaxWidth)  xorigin = cursor->MaxWidth - 1;
111c582b7e3Smrg    if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1;
112c582b7e3Smrg
113c582b7e3Smrg    if(!info->IsSecondary)
114c582b7e3Smrg    {
115c582b7e3Smrg    	OUTREG(R128_CUR_HORZ_VERT_OFF,  R128_CUR_LOCK | (xorigin << 16) | yorigin);
116c582b7e3Smrg    	OUTREG(R128_CUR_HORZ_VERT_POSN, (R128_CUR_LOCK
117c582b7e3Smrg				     | ((xorigin ? 0 : x) << 16)
118c582b7e3Smrg				     | (yorigin ? 0 : y)));
119c582b7e3Smrg    	OUTREG(R128_CUR_OFFSET,         info->cursor_start + yorigin * 16);
120c582b7e3Smrg    }
121c582b7e3Smrg    else
122c582b7e3Smrg    {
123c582b7e3Smrg        OUTREG(R128_CUR2_HORZ_VERT_OFF,  (R128_CUR2_LOCK
124c582b7e3Smrg				       | (xorigin << 16)
125c582b7e3Smrg				       | yorigin));
126c582b7e3Smrg        OUTREG(R128_CUR2_HORZ_VERT_POSN, (R128_CUR2_LOCK
127c582b7e3Smrg				       | ((xorigin ? 0 : x) << 16)
128c582b7e3Smrg				       | (yorigin ? 0 : y)));
129c582b7e3Smrg        OUTREG(R128_CUR2_OFFSET,
130c582b7e3Smrg			info->cursor_start + pScrn->fbOffset + yorigin * 16);
131c582b7e3Smrg    }
132c582b7e3Smrg}
133c582b7e3Smrg
134c582b7e3Smrg/* Copy cursor image from `image' to video memory.  R128SetCursorPosition
135c582b7e3Smrg   will be called after this, so we can ignore xorigin and yorigin. */
136c582b7e3Smrgstatic void R128LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image)
137c582b7e3Smrg{
138c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
139c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
140c582b7e3Smrg    CARD32        *s        = (pointer)image;
141c582b7e3Smrg    CARD32        *d        = (pointer)((CARD8*)info->FB + info->cursor_start);
142c582b7e3Smrg    int           y;
143c582b7e3Smrg    CARD32        save;
144c582b7e3Smrg
145c582b7e3Smrg    if(!info->IsSecondary)
146c582b7e3Smrg    {
147c582b7e3Smrg    	save = INREG(R128_CRTC_GEN_CNTL);
148c582b7e3Smrg    	OUTREG(R128_CRTC_GEN_CNTL, save & (CARD32)~R128_CRTC_CUR_EN);
149c582b7e3Smrg    }
150c582b7e3Smrg    else
151c582b7e3Smrg    {
152c582b7e3Smrg        save = INREG(R128_CRTC2_GEN_CNTL);
153c582b7e3Smrg        OUTREG(R128_CRTC2_GEN_CNTL, save & (CARD32)~R128_CRTC2_CUR_EN);
154c582b7e3Smrg    }
155c582b7e3Smrg
156c582b7e3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
157c582b7e3Smrg    switch(info->CurrentLayout.pixel_bytes) {
158c582b7e3Smrg    case 4:
159c582b7e3Smrg    case 3:
160c582b7e3Smrg	for (y = 0; y < 64; y++) {
161c582b7e3Smrg	    P_SWAP32(d,s);
162c582b7e3Smrg	    d++; s++;
163c582b7e3Smrg	    P_SWAP32(d,s);
164c582b7e3Smrg	    d++; s++;
165c582b7e3Smrg	    P_SWAP32(d,s);
166c582b7e3Smrg	    d++; s++;
167c582b7e3Smrg	    P_SWAP32(d,s);
168c582b7e3Smrg	    d++; s++;
169c582b7e3Smrg	}
170c582b7e3Smrg	break;
171c582b7e3Smrg    case 2:
172c582b7e3Smrg	for (y = 0; y < 64; y++) {
173c582b7e3Smrg	    P_SWAP16(d,s);
174c582b7e3Smrg	    d++; s++;
175c582b7e3Smrg	    P_SWAP16(d,s);
176c582b7e3Smrg	    d++; s++;
177c582b7e3Smrg	    P_SWAP16(d,s);
178c582b7e3Smrg	    d++; s++;
179c582b7e3Smrg	    P_SWAP16(d,s);
180c582b7e3Smrg	    d++; s++;
181c582b7e3Smrg	}
182c582b7e3Smrg	break;
183c582b7e3Smrg    default:
184c582b7e3Smrg	for (y = 0; y < 64; y++) {
185c582b7e3Smrg	    *d++ = *s++;
186c582b7e3Smrg	    *d++ = *s++;
187c582b7e3Smrg	    *d++ = *s++;
188c582b7e3Smrg	    *d++ = *s++;
189c582b7e3Smrg	}
190c582b7e3Smrg    }
191c582b7e3Smrg#else
192c582b7e3Smrg    for (y = 0; y < 64; y++) {
193c582b7e3Smrg	*d++ = *s++;
194c582b7e3Smrg	*d++ = *s++;
195c582b7e3Smrg	*d++ = *s++;
196c582b7e3Smrg	*d++ = *s++;
197c582b7e3Smrg    }
198c582b7e3Smrg#endif
199c582b7e3Smrg
200c582b7e3Smrg    /* Set the area after the cursor to be all transparent so that we
201c582b7e3Smrg       won't display corrupted cursors on the screen */
202c582b7e3Smrg    for (y = 0; y < 64; y++) {
203c582b7e3Smrg	*d++ = 0xffffffff; /* The AND bits */
204c582b7e3Smrg	*d++ = 0xffffffff;
205c582b7e3Smrg	*d++ = 0x00000000; /* The XOR bits */
206c582b7e3Smrg	*d++ = 0x00000000;
207c582b7e3Smrg    }
208c582b7e3Smrg
209c582b7e3Smrg
210c582b7e3Smrg    if(!info->IsSecondary)
211c582b7e3Smrg    	OUTREG(R128_CRTC_GEN_CNTL, save);
212c582b7e3Smrg    else
213c582b7e3Smrg        OUTREG(R128_CRTC2_GEN_CNTL, save);
214c582b7e3Smrg
215c582b7e3Smrg}
216c582b7e3Smrg
217c582b7e3Smrg/* Hide hardware cursor. */
218c582b7e3Smrgstatic void R128HideCursor(ScrnInfoPtr pScrn)
219c582b7e3Smrg{
220c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
221c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
222c582b7e3Smrg
223c582b7e3Smrg     if(info->IsSecondary)
224c582b7e3Smrg        OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_CUR_EN);
225c582b7e3Smrg     else
226c582b7e3Smrg    	OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_CUR_EN);
227c582b7e3Smrg}
228c582b7e3Smrg
229c582b7e3Smrg/* Show hardware cursor. */
230c582b7e3Smrgstatic void R128ShowCursor(ScrnInfoPtr pScrn)
231c582b7e3Smrg{
232c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
233c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
234c582b7e3Smrg
235c582b7e3Smrg    if(info->IsSecondary)
236c582b7e3Smrg    {
237c582b7e3Smrg         OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_CUR_EN,
238c582b7e3Smrg               ~R128_CRTC2_CUR_EN);
239c582b7e3Smrg    }
240c582b7e3Smrg    else
241c582b7e3Smrg    {
242c582b7e3Smrg    	OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_CUR_EN, ~R128_CRTC_CUR_EN);
243c582b7e3Smrg    }
244c582b7e3Smrg}
245c582b7e3Smrg
246c582b7e3Smrg/* Determine if hardware cursor is in use. */
247c582b7e3Smrgstatic Bool R128UseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
248c582b7e3Smrg{
24942a55b46Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
250c582b7e3Smrg    R128InfoPtr info  = R128PTR(pScrn);
251c582b7e3Smrg
252c582b7e3Smrg    return info->cursor_start ? TRUE : FALSE;
253c582b7e3Smrg}
254c582b7e3Smrg
255c582b7e3Smrg/* Initialize hardware cursor support. */
256c582b7e3SmrgBool R128CursorInit(ScreenPtr pScreen)
257c582b7e3Smrg{
25842a55b46Smrg    ScrnInfoPtr           pScrn   = xf86ScreenToScrn(pScreen);
259c582b7e3Smrg    R128InfoPtr           info    = R128PTR(pScrn);
260c582b7e3Smrg    xf86CursorInfoPtr     cursor;
26142a55b46Smrg    FBAreaPtr             fbarea  = NULL;
26242a55b46Smrg#ifdef USE_EXA
26342a55b46Smrg    ExaOffscreenArea*	  osArea  = NULL;
26442a55b46Smrg#else
26542a55b46Smrg    void*		  osArea  = NULL;
26642a55b46Smrg#endif
267c582b7e3Smrg    int                   width;
268c582b7e3Smrg    int                   height;
269c582b7e3Smrg    int                   size;
270c582b7e3Smrg
27142a55b46Smrg    int                   cpp = info->CurrentLayout.pixel_bytes;
272c582b7e3Smrg
273c582b7e3Smrg    if (!(cursor = info->cursor = xf86CreateCursorInfoRec())) return FALSE;
274c582b7e3Smrg
275c582b7e3Smrg    cursor->MaxWidth          = 64;
276c582b7e3Smrg    cursor->MaxHeight         = 64;
277c582b7e3Smrg    cursor->Flags             = (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
278c582b7e3Smrg				 | HARDWARE_CURSOR_SHOW_TRANSPARENT
279c582b7e3Smrg				 | HARDWARE_CURSOR_UPDATE_UNHIDDEN
280c582b7e3Smrg#if X_BYTE_ORDER == X_LITTLE_ENDIAN
281c582b7e3Smrg				 | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST
282c582b7e3Smrg#endif
283c582b7e3Smrg				 | HARDWARE_CURSOR_INVERT_MASK
284c582b7e3Smrg				 | HARDWARE_CURSOR_AND_SOURCE_WITH_MASK
285c582b7e3Smrg				 | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64
286c582b7e3Smrg				 | HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK);
287c582b7e3Smrg
288c582b7e3Smrg    cursor->SetCursorColors   = R128SetCursorColors;
289c582b7e3Smrg    cursor->SetCursorPosition = R128SetCursorPosition;
290c582b7e3Smrg    cursor->LoadCursorImage   = R128LoadCursorImage;
291c582b7e3Smrg    cursor->HideCursor        = R128HideCursor;
292c582b7e3Smrg    cursor->ShowCursor        = R128ShowCursor;
293c582b7e3Smrg    cursor->UseHWCursor       = R128UseHWCursor;
294c582b7e3Smrg
295c582b7e3Smrg    size                      = (cursor->MaxWidth/4) * cursor->MaxHeight;
296c582b7e3Smrg    width                     = pScrn->displayWidth;
297c582b7e3Smrg    height                    = (size*2 + 1023) / pScrn->displayWidth;
29842a55b46Smrg
29942a55b46Smrg    if(!info->useEXA) {
30042a55b46Smrg	fbarea = xf86AllocateOffscreenArea(pScreen, width, height,
30142a55b46Smrg					   16, NULL, NULL, NULL);
30242a55b46Smrg
30342a55b46Smrg	if (fbarea) {
30442a55b46Smrg	    info->cursor_start    = R128_ALIGN((fbarea->box.x1
30542a55b46Smrg					    + width * fbarea->box.y1)
30642a55b46Smrg					    * cpp, 16);
30742a55b46Smrg	    info->cursor_end      = info->cursor_start + size;
30842a55b46Smrg	}
30942a55b46Smrg    }
31042a55b46Smrg#ifdef USE_EXA
31142a55b46Smrg    else {
31242a55b46Smrg	osArea = exaOffscreenAlloc(pScreen, width * height, 16,
31342a55b46Smrg				   TRUE, NULL, NULL);
31442a55b46Smrg
31542a55b46Smrg	if (osArea) {
31642a55b46Smrg	    info->cursor_start	  = osArea->offset;
31742a55b46Smrg	    info->cursor_end	  = osArea->offset + osArea->size;
31842a55b46Smrg	}
31942a55b46Smrg    }
32042a55b46Smrg#endif
32142a55b46Smrg
32242a55b46Smrg    if ((!info->useEXA && !fbarea) || (info->useEXA && !osArea)) {
323c582b7e3Smrg	info->cursor_start    = 0;
324c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
325c582b7e3Smrg		   "Hardware cursor disabled"
326c582b7e3Smrg		   " due to insufficient offscreen memory\n");
327c582b7e3Smrg    }
328c582b7e3Smrg
329c582b7e3Smrg    R128TRACE(("R128CursorInit (0x%08x-0x%08x)\n",
330c582b7e3Smrg	       info->cursor_start, info->cursor_end));
331c582b7e3Smrg
332c582b7e3Smrg    return xf86InitCursor(pScreen, cursor);
333c582b7e3Smrg}
334