radeon_cursor.c revision b7e1c893
1/*
2 * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
3 *                VA Linux Systems Inc., Fremont, California.
4 *
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation on the rights to use, copy, modify, merge,
11 * publish, distribute, sublicense, and/or sell copies of the Software,
12 * and to permit persons to whom the Software is furnished to do so,
13 * subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial
17 * portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
23 * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#define RADEONCTRACE(x)
34/*#define RADEONCTRACE(x) RADEONTRACE(x) */
35
36/*
37 * Authors:
38 *   Kevin E. Martin <martin@xfree86.org>
39 *   Rickard E. Faith <faith@valinux.com>
40 *
41 * References:
42 *
43 * !!!! FIXME !!!!
44 *   RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical
45 *   Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April
46 *   1999.
47 *
48 *   RAGE 128 Software Development Manual (Technical Reference Manual P/N
49 *   SDK-G04000 Rev. 0.01), ATI Technologies: June 1999.
50 *
51 */
52
53				/* Driver data structures */
54#include "radeon.h"
55#include "radeon_version.h"
56#include "radeon_reg.h"
57#include "radeon_macros.h"
58
59				/* X and server generic header files */
60#include "xf86.h"
61
62#define CURSOR_WIDTH	64
63#define CURSOR_HEIGHT	64
64
65/*
66 * The cursor bits are always 32bpp.  On MSBFirst buses,
67 * configure byte swapping to swap 32 bit units when writing
68 * the cursor image.  Byte swapping must always be returned
69 * to its previous value before returning.
70 */
71#if X_BYTE_ORDER == X_BIG_ENDIAN
72
73#define CURSOR_SWAPPING_DECL_MMIO   unsigned char *RADEONMMIO = info->MMIO;
74#define CURSOR_SWAPPING_START() \
75  do { \
76    OUTREG(RADEON_SURFACE_CNTL, \
77	   (info->ModeReg->surface_cntl | \
78	     RADEON_NONSURF_AP0_SWP_32BPP | RADEON_NONSURF_AP1_SWP_32BPP) & \
79	   ~(RADEON_NONSURF_AP0_SWP_16BPP | RADEON_NONSURF_AP1_SWP_16BPP)); \
80  } while (0)
81#define CURSOR_SWAPPING_END()	(OUTREG(RADEON_SURFACE_CNTL, \
82					info->ModeReg->surface_cntl))
83
84#else
85
86#define CURSOR_SWAPPING_DECL_MMIO
87#define CURSOR_SWAPPING_START()
88#define CURSOR_SWAPPING_END()
89
90#endif
91
92static void
93avivo_setup_cursor(xf86CrtcPtr crtc, Bool enable)
94{
95    ScrnInfoPtr pScrn = crtc->scrn;
96    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
97    RADEONInfoPtr  info = RADEONPTR(crtc->scrn);
98    unsigned char     *RADEONMMIO = info->MMIO;
99
100    OUTREG(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset, 0);
101
102    if (enable) {
103	OUTREG(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
104	       info->fbLocation + radeon_crtc->cursor_offset + pScrn->fbOffset);
105	OUTREG(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
106	       ((CURSOR_WIDTH - 1) << 16) | (CURSOR_HEIGHT - 1));
107	OUTREG(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
108	       AVIVO_D1CURSOR_EN | (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
109    }
110}
111
112static void
113avivo_lock_cursor(xf86CrtcPtr crtc, Bool lock)
114{
115    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
116    RADEONInfoPtr  info = RADEONPTR(crtc->scrn);
117    unsigned char     *RADEONMMIO = info->MMIO;
118    uint32_t tmp;
119
120    tmp = INREG(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
121
122    if (lock)
123	tmp |= AVIVO_D1CURSOR_UPDATE_LOCK;
124    else
125	tmp &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
126
127    OUTREG(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, tmp);
128}
129
130void
131radeon_crtc_show_cursor (xf86CrtcPtr crtc)
132{
133    ScrnInfoPtr pScrn = crtc->scrn;
134    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
135    int crtc_id = radeon_crtc->crtc_id;
136    RADEONInfoPtr      info       = RADEONPTR(pScrn);
137    unsigned char     *RADEONMMIO = info->MMIO;
138
139    if (IS_AVIVO_VARIANT) {
140	avivo_lock_cursor(crtc, TRUE);
141	OUTREG(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
142	       INREG(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset)
143	       | AVIVO_D1CURSOR_EN);
144	avivo_setup_cursor(crtc, TRUE);
145	avivo_lock_cursor(crtc, FALSE);
146    } else {
147        switch (crtc_id) {
148        case 0:
149            OUTREG(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
150	    break;
151        case 1:
152            OUTREG(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
153	    break;
154        default:
155            return;
156        }
157
158        OUTREGP(RADEON_MM_DATA, RADEON_CRTC_CUR_EN | 2 << 20,
159                ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
160    }
161}
162
163void
164radeon_crtc_hide_cursor (xf86CrtcPtr crtc)
165{
166    ScrnInfoPtr pScrn = crtc->scrn;
167    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
168    int crtc_id = radeon_crtc->crtc_id;
169    RADEONInfoPtr      info       = RADEONPTR(pScrn);
170    unsigned char     *RADEONMMIO = info->MMIO;
171
172    if (IS_AVIVO_VARIANT) {
173	avivo_lock_cursor(crtc, TRUE);
174	OUTREG(AVIVO_D1CUR_CONTROL+ radeon_crtc->crtc_offset,
175	       INREG(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset)
176	       & ~(AVIVO_D1CURSOR_EN));
177	avivo_setup_cursor(crtc, FALSE);
178	avivo_lock_cursor(crtc, FALSE);
179    } else {
180	switch(crtc_id) {
181    	case 0:
182            OUTREG(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
183            break;
184    	case 1:
185	    OUTREG(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
186	    break;
187        default:
188	    return;
189        }
190
191        OUTREGP(RADEON_MM_DATA, 0, ~RADEON_CRTC_CUR_EN);
192   }
193}
194
195void
196radeon_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
197{
198    ScrnInfoPtr pScrn = crtc->scrn;
199    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
200    int crtc_id = radeon_crtc->crtc_id;
201    RADEONInfoPtr      info       = RADEONPTR(pScrn);
202    unsigned char     *RADEONMMIO = info->MMIO;
203    int xorigin = 0, yorigin = 0;
204    int stride = 256;
205    DisplayModePtr mode = &crtc->mode;
206
207    if (x < 0)                        xorigin = -x+1;
208    if (y < 0)                        yorigin = -y+1;
209    if (xorigin >= CURSOR_WIDTH)  xorigin = CURSOR_WIDTH - 1;
210    if (yorigin >= CURSOR_HEIGHT) yorigin = CURSOR_HEIGHT - 1;
211
212    if (IS_AVIVO_VARIANT) {
213	/* avivo cursor spans the full fb width */
214	if (crtc->rotatedData == NULL) {
215	    x += crtc->x;
216	    y += crtc->y;
217	}
218	avivo_lock_cursor(crtc, TRUE);
219	OUTREG(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, ((xorigin ? 0 : x) << 16)
220	       | (yorigin ? 0 : y));
221	OUTREG(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
222	avivo_lock_cursor(crtc, FALSE);
223    } else {
224	if (mode->Flags & V_DBLSCAN)
225	    y *= 2;
226
227	if (crtc_id == 0) {
228	    OUTREG(RADEON_CUR_HORZ_VERT_OFF,  (RADEON_CUR_LOCK
229					       | (xorigin << 16)
230					       | yorigin));
231	    OUTREG(RADEON_CUR_HORZ_VERT_POSN, (RADEON_CUR_LOCK
232					       | ((xorigin ? 0 : x) << 16)
233					       | (yorigin ? 0 : y)));
234	    RADEONCTRACE(("cursor_offset: 0x%x, yorigin: %d, stride: %d, temp %08X\n",
235			  radeon_crtc->cursor_offset + pScrn->fbOffset, yorigin, stride, temp));
236	    OUTREG(RADEON_CUR_OFFSET,
237		   radeon_crtc->cursor_offset + pScrn->fbOffset + yorigin * stride);
238	} else if (crtc_id == 1) {
239	    OUTREG(RADEON_CUR2_HORZ_VERT_OFF,  (RADEON_CUR2_LOCK
240						| (xorigin << 16)
241						| yorigin));
242	    OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK
243						| ((xorigin ? 0 : x) << 16)
244						| (yorigin ? 0 : y)));
245	    RADEONCTRACE(("cursor_offset2: 0x%x, yorigin: %d, stride: %d, temp %08X\n",
246			  radeon_crtc->cursor_offset + pScrn->fbOffset, yorigin, stride, temp));
247	    OUTREG(RADEON_CUR2_OFFSET,
248		   radeon_crtc->cursor_offset + pScrn->fbOffset + yorigin * stride);
249	}
250    }
251}
252
253void
254radeon_crtc_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
255{
256    ScrnInfoPtr pScrn = crtc->scrn;
257    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
258    RADEONInfoPtr info = RADEONPTR(pScrn);
259    uint32_t *pixels = (uint32_t *)(pointer)(info->FB + radeon_crtc->cursor_offset);
260    int            pixel, i;
261    CURSOR_SWAPPING_DECL_MMIO
262
263    RADEONCTRACE(("RADEONSetCursorColors\n"));
264
265#ifdef ARGB_CURSOR
266    /* Don't recolour cursors set with SetCursorARGB. */
267    if (info->cursor_argb)
268       return;
269#endif
270
271    fg |= 0xff000000;
272    bg |= 0xff000000;
273
274    /* Don't recolour the image if we don't have to. */
275    if (fg == info->cursor_fg && bg == info->cursor_bg)
276       return;
277
278    CURSOR_SWAPPING_START();
279
280    /* Note: We assume that the pixels are either fully opaque or fully
281     * transparent, so we won't premultiply them, and we can just
282     * check for non-zero pixel values; those are either fg or bg
283     */
284    for (i = 0; i < CURSOR_WIDTH * CURSOR_HEIGHT; i++, pixels++)
285       if ((pixel = *pixels))
286           *pixels = (pixel == info->cursor_fg) ? fg : bg;
287
288    CURSOR_SWAPPING_END();
289    info->cursor_fg = fg;
290    info->cursor_bg = bg;
291}
292
293#ifdef ARGB_CURSOR
294
295void
296radeon_crtc_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
297{
298    ScrnInfoPtr pScrn = crtc->scrn;
299    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
300    RADEONInfoPtr  info = RADEONPTR(pScrn);
301    CURSOR_SWAPPING_DECL_MMIO
302    uint32_t *d = (uint32_t *)(pointer)(info->FB + radeon_crtc->cursor_offset);
303
304    RADEONCTRACE(("RADEONLoadCursorARGB\n"));
305
306    info->cursor_argb = TRUE;
307
308    CURSOR_SWAPPING_START();
309
310    memcpy (d, image, CURSOR_HEIGHT * CURSOR_WIDTH * 4);
311
312    CURSOR_SWAPPING_END ();
313}
314
315#endif
316
317
318/* Initialize hardware cursor support. */
319Bool RADEONCursorInit(ScreenPtr pScreen)
320{
321    ScrnInfoPtr        pScrn   = xf86Screens[pScreen->myNum];
322    RADEONInfoPtr      info    = RADEONPTR(pScrn);
323    xf86CrtcConfigPtr  xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
324    int                width;
325    int		       width_bytes;
326    int                height;
327    int                size_bytes;
328    int                c;
329
330    size_bytes  = CURSOR_WIDTH * 4 * CURSOR_HEIGHT;
331    width       = pScrn->displayWidth;
332    width_bytes = width * (pScrn->bitsPerPixel / 8);
333    height      = ((size_bytes * xf86_config->num_crtc) + width_bytes - 1) / width_bytes;
334    int align = IS_AVIVO_VARIANT ? 4096 : 256;
335
336    if (!info->useEXA) {
337	for (c = 0; c < xf86_config->num_crtc; c++) {
338	    xf86CrtcPtr crtc = xf86_config->crtc[c];
339	    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
340
341	    radeon_crtc->cursor_offset =
342		radeon_legacy_allocate_memory(pScrn, &radeon_crtc->cursor_mem, size_bytes, align);
343
344	    if (radeon_crtc->cursor_offset == 0)
345		return FALSE;
346
347	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
348		       "Will use %d kb for hardware cursor %d at offset 0x%08x\n",
349		       (size_bytes * xf86_config->num_crtc) / 1024,
350		       c,
351		       (unsigned int)radeon_crtc->cursor_offset);
352	}
353    }
354
355    return xf86_cursors_init (pScreen, CURSOR_WIDTH, CURSOR_HEIGHT,
356			      (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
357			       HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
358			       HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
359			       HARDWARE_CURSOR_ARGB));
360}
361