radeon_cursor.c revision b7e1c893
1209ff23fSmrg/*
2209ff23fSmrg * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
3209ff23fSmrg *                VA Linux Systems Inc., Fremont, California.
4209ff23fSmrg *
5209ff23fSmrg * All Rights Reserved.
6209ff23fSmrg *
7209ff23fSmrg * Permission is hereby granted, free of charge, to any person obtaining
8209ff23fSmrg * a copy of this software and associated documentation files (the
9209ff23fSmrg * "Software"), to deal in the Software without restriction, including
10209ff23fSmrg * without limitation on the rights to use, copy, modify, merge,
11209ff23fSmrg * publish, distribute, sublicense, and/or sell copies of the Software,
12209ff23fSmrg * and to permit persons to whom the Software is furnished to do so,
13209ff23fSmrg * subject to the following conditions:
14209ff23fSmrg *
15209ff23fSmrg * The above copyright notice and this permission notice (including the
16209ff23fSmrg * next paragraph) shall be included in all copies or substantial
17209ff23fSmrg * portions of the Software.
18209ff23fSmrg *
19209ff23fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20209ff23fSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21209ff23fSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22209ff23fSmrg * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
23209ff23fSmrg * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24209ff23fSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25209ff23fSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26209ff23fSmrg * DEALINGS IN THE SOFTWARE.
27209ff23fSmrg */
28209ff23fSmrg
29209ff23fSmrg#ifdef HAVE_CONFIG_H
30209ff23fSmrg#include "config.h"
31209ff23fSmrg#endif
32209ff23fSmrg
33209ff23fSmrg#define RADEONCTRACE(x)
34209ff23fSmrg/*#define RADEONCTRACE(x) RADEONTRACE(x) */
35209ff23fSmrg
36209ff23fSmrg/*
37209ff23fSmrg * Authors:
38209ff23fSmrg *   Kevin E. Martin <martin@xfree86.org>
39209ff23fSmrg *   Rickard E. Faith <faith@valinux.com>
40209ff23fSmrg *
41209ff23fSmrg * References:
42209ff23fSmrg *
43209ff23fSmrg * !!!! FIXME !!!!
44209ff23fSmrg *   RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical
45209ff23fSmrg *   Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April
46209ff23fSmrg *   1999.
47209ff23fSmrg *
48209ff23fSmrg *   RAGE 128 Software Development Manual (Technical Reference Manual P/N
49209ff23fSmrg *   SDK-G04000 Rev. 0.01), ATI Technologies: June 1999.
50209ff23fSmrg *
51209ff23fSmrg */
52209ff23fSmrg
53209ff23fSmrg				/* Driver data structures */
54209ff23fSmrg#include "radeon.h"
55209ff23fSmrg#include "radeon_version.h"
56209ff23fSmrg#include "radeon_reg.h"
57209ff23fSmrg#include "radeon_macros.h"
58209ff23fSmrg
59209ff23fSmrg				/* X and server generic header files */
60209ff23fSmrg#include "xf86.h"
61209ff23fSmrg
62209ff23fSmrg#define CURSOR_WIDTH	64
63209ff23fSmrg#define CURSOR_HEIGHT	64
64209ff23fSmrg
65209ff23fSmrg/*
66209ff23fSmrg * The cursor bits are always 32bpp.  On MSBFirst buses,
67209ff23fSmrg * configure byte swapping to swap 32 bit units when writing
68209ff23fSmrg * the cursor image.  Byte swapping must always be returned
69209ff23fSmrg * to its previous value before returning.
70209ff23fSmrg */
71209ff23fSmrg#if X_BYTE_ORDER == X_BIG_ENDIAN
72209ff23fSmrg
73209ff23fSmrg#define CURSOR_SWAPPING_DECL_MMIO   unsigned char *RADEONMMIO = info->MMIO;
74209ff23fSmrg#define CURSOR_SWAPPING_START() \
75209ff23fSmrg  do { \
76209ff23fSmrg    OUTREG(RADEON_SURFACE_CNTL, \
77209ff23fSmrg	   (info->ModeReg->surface_cntl | \
78209ff23fSmrg	     RADEON_NONSURF_AP0_SWP_32BPP | RADEON_NONSURF_AP1_SWP_32BPP) & \
79209ff23fSmrg	   ~(RADEON_NONSURF_AP0_SWP_16BPP | RADEON_NONSURF_AP1_SWP_16BPP)); \
80209ff23fSmrg  } while (0)
81209ff23fSmrg#define CURSOR_SWAPPING_END()	(OUTREG(RADEON_SURFACE_CNTL, \
82209ff23fSmrg					info->ModeReg->surface_cntl))
83209ff23fSmrg
84209ff23fSmrg#else
85209ff23fSmrg
86209ff23fSmrg#define CURSOR_SWAPPING_DECL_MMIO
87209ff23fSmrg#define CURSOR_SWAPPING_START()
88209ff23fSmrg#define CURSOR_SWAPPING_END()
89209ff23fSmrg
90209ff23fSmrg#endif
91209ff23fSmrg
92209ff23fSmrgstatic void
93209ff23fSmrgavivo_setup_cursor(xf86CrtcPtr crtc, Bool enable)
94209ff23fSmrg{
95209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
96209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
97209ff23fSmrg    RADEONInfoPtr  info = RADEONPTR(crtc->scrn);
98209ff23fSmrg    unsigned char     *RADEONMMIO = info->MMIO;
99209ff23fSmrg
100209ff23fSmrg    OUTREG(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset, 0);
101209ff23fSmrg
102209ff23fSmrg    if (enable) {
103209ff23fSmrg	OUTREG(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
104209ff23fSmrg	       info->fbLocation + radeon_crtc->cursor_offset + pScrn->fbOffset);
105209ff23fSmrg	OUTREG(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
106209ff23fSmrg	       ((CURSOR_WIDTH - 1) << 16) | (CURSOR_HEIGHT - 1));
107209ff23fSmrg	OUTREG(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
108209ff23fSmrg	       AVIVO_D1CURSOR_EN | (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
109209ff23fSmrg    }
110209ff23fSmrg}
111209ff23fSmrg
112209ff23fSmrgstatic void
113209ff23fSmrgavivo_lock_cursor(xf86CrtcPtr crtc, Bool lock)
114209ff23fSmrg{
115209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
116209ff23fSmrg    RADEONInfoPtr  info = RADEONPTR(crtc->scrn);
117209ff23fSmrg    unsigned char     *RADEONMMIO = info->MMIO;
118209ff23fSmrg    uint32_t tmp;
119209ff23fSmrg
120209ff23fSmrg    tmp = INREG(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
121209ff23fSmrg
122209ff23fSmrg    if (lock)
123209ff23fSmrg	tmp |= AVIVO_D1CURSOR_UPDATE_LOCK;
124209ff23fSmrg    else
125209ff23fSmrg	tmp &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
126209ff23fSmrg
127209ff23fSmrg    OUTREG(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, tmp);
128209ff23fSmrg}
129209ff23fSmrg
130209ff23fSmrgvoid
131209ff23fSmrgradeon_crtc_show_cursor (xf86CrtcPtr crtc)
132209ff23fSmrg{
133209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
134209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
135209ff23fSmrg    int crtc_id = radeon_crtc->crtc_id;
136209ff23fSmrg    RADEONInfoPtr      info       = RADEONPTR(pScrn);
137209ff23fSmrg    unsigned char     *RADEONMMIO = info->MMIO;
138209ff23fSmrg
139209ff23fSmrg    if (IS_AVIVO_VARIANT) {
140209ff23fSmrg	avivo_lock_cursor(crtc, TRUE);
141209ff23fSmrg	OUTREG(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
142209ff23fSmrg	       INREG(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset)
143209ff23fSmrg	       | AVIVO_D1CURSOR_EN);
144209ff23fSmrg	avivo_setup_cursor(crtc, TRUE);
145209ff23fSmrg	avivo_lock_cursor(crtc, FALSE);
146209ff23fSmrg    } else {
147209ff23fSmrg        switch (crtc_id) {
148209ff23fSmrg        case 0:
149209ff23fSmrg            OUTREG(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
150209ff23fSmrg	    break;
151209ff23fSmrg        case 1:
152209ff23fSmrg            OUTREG(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
153209ff23fSmrg	    break;
154209ff23fSmrg        default:
155209ff23fSmrg            return;
156209ff23fSmrg        }
157209ff23fSmrg
158209ff23fSmrg        OUTREGP(RADEON_MM_DATA, RADEON_CRTC_CUR_EN | 2 << 20,
159209ff23fSmrg                ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
160209ff23fSmrg    }
161209ff23fSmrg}
162209ff23fSmrg
163209ff23fSmrgvoid
164209ff23fSmrgradeon_crtc_hide_cursor (xf86CrtcPtr crtc)
165209ff23fSmrg{
166209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
167209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
168209ff23fSmrg    int crtc_id = radeon_crtc->crtc_id;
169209ff23fSmrg    RADEONInfoPtr      info       = RADEONPTR(pScrn);
170209ff23fSmrg    unsigned char     *RADEONMMIO = info->MMIO;
171209ff23fSmrg
172209ff23fSmrg    if (IS_AVIVO_VARIANT) {
173209ff23fSmrg	avivo_lock_cursor(crtc, TRUE);
174209ff23fSmrg	OUTREG(AVIVO_D1CUR_CONTROL+ radeon_crtc->crtc_offset,
175209ff23fSmrg	       INREG(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset)
176209ff23fSmrg	       & ~(AVIVO_D1CURSOR_EN));
177209ff23fSmrg	avivo_setup_cursor(crtc, FALSE);
178209ff23fSmrg	avivo_lock_cursor(crtc, FALSE);
179209ff23fSmrg    } else {
180209ff23fSmrg	switch(crtc_id) {
181209ff23fSmrg    	case 0:
182209ff23fSmrg            OUTREG(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
183209ff23fSmrg            break;
184209ff23fSmrg    	case 1:
185209ff23fSmrg	    OUTREG(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
186209ff23fSmrg	    break;
187209ff23fSmrg        default:
188209ff23fSmrg	    return;
189209ff23fSmrg        }
190209ff23fSmrg
191209ff23fSmrg        OUTREGP(RADEON_MM_DATA, 0, ~RADEON_CRTC_CUR_EN);
192209ff23fSmrg   }
193209ff23fSmrg}
194209ff23fSmrg
195209ff23fSmrgvoid
196209ff23fSmrgradeon_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
197209ff23fSmrg{
198209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
199209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
200209ff23fSmrg    int crtc_id = radeon_crtc->crtc_id;
201209ff23fSmrg    RADEONInfoPtr      info       = RADEONPTR(pScrn);
202209ff23fSmrg    unsigned char     *RADEONMMIO = info->MMIO;
203209ff23fSmrg    int xorigin = 0, yorigin = 0;
204209ff23fSmrg    int stride = 256;
205209ff23fSmrg    DisplayModePtr mode = &crtc->mode;
206209ff23fSmrg
207209ff23fSmrg    if (x < 0)                        xorigin = -x+1;
208209ff23fSmrg    if (y < 0)                        yorigin = -y+1;
209209ff23fSmrg    if (xorigin >= CURSOR_WIDTH)  xorigin = CURSOR_WIDTH - 1;
210209ff23fSmrg    if (yorigin >= CURSOR_HEIGHT) yorigin = CURSOR_HEIGHT - 1;
211209ff23fSmrg
212209ff23fSmrg    if (IS_AVIVO_VARIANT) {
213209ff23fSmrg	/* avivo cursor spans the full fb width */
214b7e1c893Smrg	if (crtc->rotatedData == NULL) {
215b7e1c893Smrg	    x += crtc->x;
216b7e1c893Smrg	    y += crtc->y;
217b7e1c893Smrg	}
218209ff23fSmrg	avivo_lock_cursor(crtc, TRUE);
219209ff23fSmrg	OUTREG(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, ((xorigin ? 0 : x) << 16)
220209ff23fSmrg	       | (yorigin ? 0 : y));
221209ff23fSmrg	OUTREG(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
222209ff23fSmrg	avivo_lock_cursor(crtc, FALSE);
223209ff23fSmrg    } else {
224b7e1c893Smrg	if (mode->Flags & V_DBLSCAN)
225b7e1c893Smrg	    y *= 2;
226b7e1c893Smrg
227209ff23fSmrg	if (crtc_id == 0) {
228209ff23fSmrg	    OUTREG(RADEON_CUR_HORZ_VERT_OFF,  (RADEON_CUR_LOCK
229209ff23fSmrg					       | (xorigin << 16)
230209ff23fSmrg					       | yorigin));
231209ff23fSmrg	    OUTREG(RADEON_CUR_HORZ_VERT_POSN, (RADEON_CUR_LOCK
232209ff23fSmrg					       | ((xorigin ? 0 : x) << 16)
233209ff23fSmrg					       | (yorigin ? 0 : y)));
234209ff23fSmrg	    RADEONCTRACE(("cursor_offset: 0x%x, yorigin: %d, stride: %d, temp %08X\n",
235209ff23fSmrg			  radeon_crtc->cursor_offset + pScrn->fbOffset, yorigin, stride, temp));
236209ff23fSmrg	    OUTREG(RADEON_CUR_OFFSET,
237209ff23fSmrg		   radeon_crtc->cursor_offset + pScrn->fbOffset + yorigin * stride);
238209ff23fSmrg	} else if (crtc_id == 1) {
239209ff23fSmrg	    OUTREG(RADEON_CUR2_HORZ_VERT_OFF,  (RADEON_CUR2_LOCK
240209ff23fSmrg						| (xorigin << 16)
241209ff23fSmrg						| yorigin));
242209ff23fSmrg	    OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK
243209ff23fSmrg						| ((xorigin ? 0 : x) << 16)
244209ff23fSmrg						| (yorigin ? 0 : y)));
245209ff23fSmrg	    RADEONCTRACE(("cursor_offset2: 0x%x, yorigin: %d, stride: %d, temp %08X\n",
246209ff23fSmrg			  radeon_crtc->cursor_offset + pScrn->fbOffset, yorigin, stride, temp));
247209ff23fSmrg	    OUTREG(RADEON_CUR2_OFFSET,
248209ff23fSmrg		   radeon_crtc->cursor_offset + pScrn->fbOffset + yorigin * stride);
249209ff23fSmrg	}
250209ff23fSmrg    }
251209ff23fSmrg}
252209ff23fSmrg
253209ff23fSmrgvoid
254209ff23fSmrgradeon_crtc_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
255209ff23fSmrg{
256209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
257209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
258209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
259209ff23fSmrg    uint32_t *pixels = (uint32_t *)(pointer)(info->FB + radeon_crtc->cursor_offset);
260209ff23fSmrg    int            pixel, i;
261209ff23fSmrg    CURSOR_SWAPPING_DECL_MMIO
262209ff23fSmrg
263209ff23fSmrg    RADEONCTRACE(("RADEONSetCursorColors\n"));
264209ff23fSmrg
265209ff23fSmrg#ifdef ARGB_CURSOR
266209ff23fSmrg    /* Don't recolour cursors set with SetCursorARGB. */
267209ff23fSmrg    if (info->cursor_argb)
268209ff23fSmrg       return;
269209ff23fSmrg#endif
270209ff23fSmrg
271209ff23fSmrg    fg |= 0xff000000;
272209ff23fSmrg    bg |= 0xff000000;
273209ff23fSmrg
274209ff23fSmrg    /* Don't recolour the image if we don't have to. */
275209ff23fSmrg    if (fg == info->cursor_fg && bg == info->cursor_bg)
276209ff23fSmrg       return;
277209ff23fSmrg
278209ff23fSmrg    CURSOR_SWAPPING_START();
279209ff23fSmrg
280209ff23fSmrg    /* Note: We assume that the pixels are either fully opaque or fully
281209ff23fSmrg     * transparent, so we won't premultiply them, and we can just
282209ff23fSmrg     * check for non-zero pixel values; those are either fg or bg
283209ff23fSmrg     */
284209ff23fSmrg    for (i = 0; i < CURSOR_WIDTH * CURSOR_HEIGHT; i++, pixels++)
285209ff23fSmrg       if ((pixel = *pixels))
286209ff23fSmrg           *pixels = (pixel == info->cursor_fg) ? fg : bg;
287209ff23fSmrg
288209ff23fSmrg    CURSOR_SWAPPING_END();
289209ff23fSmrg    info->cursor_fg = fg;
290209ff23fSmrg    info->cursor_bg = bg;
291209ff23fSmrg}
292209ff23fSmrg
293209ff23fSmrg#ifdef ARGB_CURSOR
294209ff23fSmrg
295209ff23fSmrgvoid
296209ff23fSmrgradeon_crtc_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
297209ff23fSmrg{
298209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
299209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
300209ff23fSmrg    RADEONInfoPtr  info = RADEONPTR(pScrn);
301209ff23fSmrg    CURSOR_SWAPPING_DECL_MMIO
302209ff23fSmrg    uint32_t *d = (uint32_t *)(pointer)(info->FB + radeon_crtc->cursor_offset);
303209ff23fSmrg
304209ff23fSmrg    RADEONCTRACE(("RADEONLoadCursorARGB\n"));
305209ff23fSmrg
306209ff23fSmrg    info->cursor_argb = TRUE;
307209ff23fSmrg
308209ff23fSmrg    CURSOR_SWAPPING_START();
309209ff23fSmrg
310209ff23fSmrg    memcpy (d, image, CURSOR_HEIGHT * CURSOR_WIDTH * 4);
311209ff23fSmrg
312209ff23fSmrg    CURSOR_SWAPPING_END ();
313209ff23fSmrg}
314209ff23fSmrg
315209ff23fSmrg#endif
316209ff23fSmrg
317209ff23fSmrg
318209ff23fSmrg/* Initialize hardware cursor support. */
319209ff23fSmrgBool RADEONCursorInit(ScreenPtr pScreen)
320209ff23fSmrg{
321209ff23fSmrg    ScrnInfoPtr        pScrn   = xf86Screens[pScreen->myNum];
322209ff23fSmrg    RADEONInfoPtr      info    = RADEONPTR(pScrn);
323209ff23fSmrg    xf86CrtcConfigPtr  xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
324209ff23fSmrg    int                width;
325209ff23fSmrg    int		       width_bytes;
326209ff23fSmrg    int                height;
327209ff23fSmrg    int                size_bytes;
328209ff23fSmrg    int                c;
329209ff23fSmrg
330209ff23fSmrg    size_bytes  = CURSOR_WIDTH * 4 * CURSOR_HEIGHT;
331209ff23fSmrg    width       = pScrn->displayWidth;
332209ff23fSmrg    width_bytes = width * (pScrn->bitsPerPixel / 8);
333209ff23fSmrg    height      = ((size_bytes * xf86_config->num_crtc) + width_bytes - 1) / width_bytes;
334b7e1c893Smrg    int align = IS_AVIVO_VARIANT ? 4096 : 256;
335209ff23fSmrg
336209ff23fSmrg    if (!info->useEXA) {
337b7e1c893Smrg	for (c = 0; c < xf86_config->num_crtc; c++) {
338b7e1c893Smrg	    xf86CrtcPtr crtc = xf86_config->crtc[c];
339b7e1c893Smrg	    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
340209ff23fSmrg
341b7e1c893Smrg	    radeon_crtc->cursor_offset =
342b7e1c893Smrg		radeon_legacy_allocate_memory(pScrn, &radeon_crtc->cursor_mem, size_bytes, align);
343b7e1c893Smrg
344b7e1c893Smrg	    if (radeon_crtc->cursor_offset == 0)
345b7e1c893Smrg		return FALSE;
346b7e1c893Smrg
347b7e1c893Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
348b7e1c893Smrg		       "Will use %d kb for hardware cursor %d at offset 0x%08x\n",
349b7e1c893Smrg		       (size_bytes * xf86_config->num_crtc) / 1024,
350b7e1c893Smrg		       c,
351b7e1c893Smrg		       (unsigned int)radeon_crtc->cursor_offset);
352209ff23fSmrg	}
353209ff23fSmrg    }
354209ff23fSmrg
355209ff23fSmrg    return xf86_cursors_init (pScreen, CURSOR_WIDTH, CURSOR_HEIGHT,
356209ff23fSmrg			      (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
357209ff23fSmrg			       HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
358209ff23fSmrg			       HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
359209ff23fSmrg			       HARDWARE_CURSOR_ARGB));
360209ff23fSmrg}
361