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 { \
76486efd68Smrg  if (info->ChipFamily < CHIP_FAMILY_R600) \
77209ff23fSmrg    OUTREG(RADEON_SURFACE_CNTL, \
78209ff23fSmrg	   (info->ModeReg->surface_cntl | \
79209ff23fSmrg	     RADEON_NONSURF_AP0_SWP_32BPP | RADEON_NONSURF_AP1_SWP_32BPP) & \
80209ff23fSmrg	   ~(RADEON_NONSURF_AP0_SWP_16BPP | RADEON_NONSURF_AP1_SWP_16BPP)); \
81209ff23fSmrg  } while (0)
82486efd68Smrg#define CURSOR_SWAPPING_END()	\
83486efd68Smrg  do { \
84486efd68Smrg  if (info->ChipFamily < CHIP_FAMILY_R600) \
85486efd68Smrg      OUTREG(RADEON_SURFACE_CNTL, info->ModeReg->surface_cntl); \
86486efd68Smrg  } while (0)
87209ff23fSmrg#else
88209ff23fSmrg
89209ff23fSmrg#define CURSOR_SWAPPING_DECL_MMIO
90209ff23fSmrg#define CURSOR_SWAPPING_START()
91209ff23fSmrg#define CURSOR_SWAPPING_END()
92209ff23fSmrg
93209ff23fSmrg#endif
94209ff23fSmrg
95209ff23fSmrgstatic void
96209ff23fSmrgavivo_setup_cursor(xf86CrtcPtr crtc, Bool enable)
97209ff23fSmrg{
98209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
99209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
100209ff23fSmrg    RADEONInfoPtr  info = RADEONPTR(crtc->scrn);
101209ff23fSmrg    unsigned char     *RADEONMMIO = info->MMIO;
102209ff23fSmrg
103486efd68Smrg    /* always use the same cursor mode even if the cursor is disabled,
104486efd68Smrg     * otherwise you may end up with cursor curruption bands
105486efd68Smrg     */
106486efd68Smrg    OUTREG(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset, (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
107209ff23fSmrg
108209ff23fSmrg    if (enable) {
10970cce690Smrg	uint64_t location = info->fbLocation + radeon_crtc->cursor_offset + pScrn->fbOffset;
110f1bc02b7Smrg	if (info->ChipFamily >= CHIP_FAMILY_RV770) {
111f1bc02b7Smrg	    if (radeon_crtc->crtc_id)
11270cce690Smrg		OUTREG(R700_D2CUR_SURFACE_ADDRESS_HIGH, (location >> 32) & 0xf);
113f1bc02b7Smrg	    else
11470cce690Smrg		OUTREG(R700_D1CUR_SURFACE_ADDRESS_HIGH, (location >> 32) & 0xf);
115f1bc02b7Smrg	}
116209ff23fSmrg	OUTREG(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
117209ff23fSmrg	       info->fbLocation + radeon_crtc->cursor_offset + pScrn->fbOffset);
118209ff23fSmrg	OUTREG(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
119209ff23fSmrg	       AVIVO_D1CURSOR_EN | (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
120209ff23fSmrg    }
121209ff23fSmrg}
122209ff23fSmrg
123209ff23fSmrgstatic void
124209ff23fSmrgavivo_lock_cursor(xf86CrtcPtr crtc, Bool lock)
125209ff23fSmrg{
126209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
127209ff23fSmrg    RADEONInfoPtr  info = RADEONPTR(crtc->scrn);
128209ff23fSmrg    unsigned char     *RADEONMMIO = info->MMIO;
129209ff23fSmrg    uint32_t tmp;
130209ff23fSmrg
131209ff23fSmrg    tmp = INREG(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
132209ff23fSmrg
133209ff23fSmrg    if (lock)
134209ff23fSmrg	tmp |= AVIVO_D1CURSOR_UPDATE_LOCK;
135209ff23fSmrg    else
136209ff23fSmrg	tmp &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
137209ff23fSmrg
138209ff23fSmrg    OUTREG(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, tmp);
139209ff23fSmrg}
140209ff23fSmrg
141f1bc02b7Smrgstatic void
142f1bc02b7Smrgevergreen_setup_cursor(xf86CrtcPtr crtc, Bool enable)
143f1bc02b7Smrg{
144f1bc02b7Smrg    ScrnInfoPtr pScrn = crtc->scrn;
145f1bc02b7Smrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
146f1bc02b7Smrg    RADEONInfoPtr  info = RADEONPTR(crtc->scrn);
147f1bc02b7Smrg    unsigned char     *RADEONMMIO = info->MMIO;
148f1bc02b7Smrg
149f1bc02b7Smrg    /* always use the same cursor mode even if the cursor is disabled,
150f1bc02b7Smrg     * otherwise you may end up with cursor curruption bands
151f1bc02b7Smrg     */
152f1bc02b7Smrg    OUTREG(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset,
153f1bc02b7Smrg	   EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT));
154f1bc02b7Smrg
155f1bc02b7Smrg    if (enable) {
15670cce690Smrg	uint64_t location = info->fbLocation + radeon_crtc->cursor_offset + pScrn->fbOffset;
15770cce690Smrg	OUTREG(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
15870cce690Smrg	       (location >> 32) & 0xf);
159f1bc02b7Smrg	OUTREG(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
16070cce690Smrg	       location & EVERGREEN_CUR_SURFACE_ADDRESS_MASK);
161f1bc02b7Smrg	OUTREG(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset,
162f1bc02b7Smrg	       EVERGREEN_CURSOR_EN | EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT));
163f1bc02b7Smrg    }
164f1bc02b7Smrg}
165f1bc02b7Smrg
166f1bc02b7Smrgstatic void
167f1bc02b7Smrgevergreen_lock_cursor(xf86CrtcPtr crtc, Bool lock)
168f1bc02b7Smrg{
169f1bc02b7Smrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
170f1bc02b7Smrg    RADEONInfoPtr  info = RADEONPTR(crtc->scrn);
171f1bc02b7Smrg    unsigned char     *RADEONMMIO = info->MMIO;
172f1bc02b7Smrg    uint32_t tmp;
173f1bc02b7Smrg
174f1bc02b7Smrg    tmp = INREG(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
175f1bc02b7Smrg
176f1bc02b7Smrg    if (lock)
177f1bc02b7Smrg	tmp |= EVERGREEN_CURSOR_UPDATE_LOCK;
178f1bc02b7Smrg    else
179f1bc02b7Smrg	tmp &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
180f1bc02b7Smrg
181f1bc02b7Smrg    OUTREG(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, tmp);
182f1bc02b7Smrg}
183f1bc02b7Smrg
184209ff23fSmrgvoid
185209ff23fSmrgradeon_crtc_show_cursor (xf86CrtcPtr crtc)
186209ff23fSmrg{
187209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
188209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
189209ff23fSmrg    int crtc_id = radeon_crtc->crtc_id;
190209ff23fSmrg    RADEONInfoPtr      info       = RADEONPTR(pScrn);
191209ff23fSmrg    unsigned char     *RADEONMMIO = info->MMIO;
192209ff23fSmrg
193f1bc02b7Smrg    if (IS_DCE4_VARIANT) {
194f1bc02b7Smrg	evergreen_lock_cursor(crtc, TRUE);
195f1bc02b7Smrg	evergreen_setup_cursor(crtc, TRUE);
196f1bc02b7Smrg	evergreen_lock_cursor(crtc, FALSE);
197f1bc02b7Smrg    } else if (IS_AVIVO_VARIANT) {
198209ff23fSmrg	avivo_lock_cursor(crtc, TRUE);
199209ff23fSmrg	avivo_setup_cursor(crtc, TRUE);
200209ff23fSmrg	avivo_lock_cursor(crtc, FALSE);
201209ff23fSmrg    } else {
202209ff23fSmrg        switch (crtc_id) {
203209ff23fSmrg        case 0:
204209ff23fSmrg            OUTREG(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
205209ff23fSmrg	    break;
206209ff23fSmrg        case 1:
207209ff23fSmrg            OUTREG(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
208209ff23fSmrg	    break;
209209ff23fSmrg        default:
210209ff23fSmrg            return;
211209ff23fSmrg        }
212209ff23fSmrg
213f1bc02b7Smrg        OUTREGP(RADEON_MM_DATA, RADEON_CRTC_CUR_EN | 2 << 20,
214209ff23fSmrg                ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
215209ff23fSmrg    }
216209ff23fSmrg}
217209ff23fSmrg
218209ff23fSmrgvoid
219209ff23fSmrgradeon_crtc_hide_cursor (xf86CrtcPtr crtc)
220209ff23fSmrg{
221209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
222209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
223209ff23fSmrg    int crtc_id = radeon_crtc->crtc_id;
224209ff23fSmrg    RADEONInfoPtr      info       = RADEONPTR(pScrn);
225209ff23fSmrg    unsigned char     *RADEONMMIO = info->MMIO;
226209ff23fSmrg
227f1bc02b7Smrg    if (IS_DCE4_VARIANT) {
228f1bc02b7Smrg	evergreen_lock_cursor(crtc, TRUE);
229f1bc02b7Smrg	evergreen_setup_cursor(crtc, FALSE);
23069d0ef43Smrg	evergreen_lock_cursor(crtc, FALSE);
231f1bc02b7Smrg    } else if (IS_AVIVO_VARIANT) {
232209ff23fSmrg	avivo_lock_cursor(crtc, TRUE);
233209ff23fSmrg	avivo_setup_cursor(crtc, FALSE);
234209ff23fSmrg	avivo_lock_cursor(crtc, FALSE);
235209ff23fSmrg    } else {
236209ff23fSmrg	switch(crtc_id) {
237209ff23fSmrg    	case 0:
238209ff23fSmrg            OUTREG(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
239209ff23fSmrg            break;
240209ff23fSmrg    	case 1:
241209ff23fSmrg	    OUTREG(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
242209ff23fSmrg	    break;
243209ff23fSmrg        default:
244209ff23fSmrg	    return;
245209ff23fSmrg        }
246209ff23fSmrg
247209ff23fSmrg        OUTREGP(RADEON_MM_DATA, 0, ~RADEON_CRTC_CUR_EN);
248209ff23fSmrg   }
249209ff23fSmrg}
250209ff23fSmrg
251209ff23fSmrgvoid
252209ff23fSmrgradeon_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
253209ff23fSmrg{
254209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
255486efd68Smrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
256209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
257209ff23fSmrg    int crtc_id = radeon_crtc->crtc_id;
258209ff23fSmrg    RADEONInfoPtr      info       = RADEONPTR(pScrn);
259209ff23fSmrg    unsigned char     *RADEONMMIO = info->MMIO;
260209ff23fSmrg    int xorigin = 0, yorigin = 0;
261209ff23fSmrg    int stride = 256;
262209ff23fSmrg    DisplayModePtr mode = &crtc->mode;
26370cce690Smrg    int w = CURSOR_WIDTH;
264209ff23fSmrg
265209ff23fSmrg    if (x < 0)                        xorigin = -x+1;
266209ff23fSmrg    if (y < 0)                        yorigin = -y+1;
267209ff23fSmrg    if (xorigin >= CURSOR_WIDTH)  xorigin = CURSOR_WIDTH - 1;
268209ff23fSmrg    if (yorigin >= CURSOR_HEIGHT) yorigin = CURSOR_HEIGHT - 1;
269209ff23fSmrg
27070cce690Smrg    if (IS_AVIVO_VARIANT) {
271209ff23fSmrg	/* avivo cursor spans the full fb width */
272b7e1c893Smrg	if (crtc->rotatedData == NULL) {
273b7e1c893Smrg	    x += crtc->x;
274b7e1c893Smrg	    y += crtc->y;
275b7e1c893Smrg	}
276486efd68Smrg
277486efd68Smrg	if (pRADEONEnt->Controller[0]->enabled &&
278486efd68Smrg	    pRADEONEnt->Controller[1]->enabled) {
279486efd68Smrg	    int cursor_end, frame_end;
280486efd68Smrg
281486efd68Smrg	    cursor_end = x - xorigin + w;
282486efd68Smrg	    frame_end = crtc->x + mode->CrtcHDisplay;
283486efd68Smrg
284486efd68Smrg	    if (cursor_end >= frame_end) {
285486efd68Smrg		w = w - (cursor_end - frame_end);
286486efd68Smrg		if (!(frame_end & 0x7f))
287486efd68Smrg		    w--;
288486efd68Smrg	    } else {
289486efd68Smrg		if (!(cursor_end & 0x7f))
290486efd68Smrg		    w--;
291486efd68Smrg	    }
292486efd68Smrg	    if (w <= 0)
293486efd68Smrg		w = 1;
294486efd68Smrg	}
29570cce690Smrg    }
296486efd68Smrg
29770cce690Smrg    if (IS_DCE4_VARIANT) {
29870cce690Smrg	evergreen_lock_cursor(crtc, TRUE);
29970cce690Smrg	OUTREG(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, ((xorigin ? 0 : x) << 16)
30070cce690Smrg	       | (yorigin ? 0 : y));
30170cce690Smrg	OUTREG(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
30270cce690Smrg	OUTREG(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
30370cce690Smrg	       ((w - 1) << 16) | (CURSOR_HEIGHT - 1));
30470cce690Smrg	evergreen_lock_cursor(crtc, FALSE);
30570cce690Smrg    } else if (IS_AVIVO_VARIANT) {
306209ff23fSmrg	avivo_lock_cursor(crtc, TRUE);
307209ff23fSmrg	OUTREG(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, ((xorigin ? 0 : x) << 16)
308209ff23fSmrg	       | (yorigin ? 0 : y));
309209ff23fSmrg	OUTREG(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
310486efd68Smrg	OUTREG(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset, ((w - 1) << 16) | (CURSOR_HEIGHT - 1));
311209ff23fSmrg	avivo_lock_cursor(crtc, FALSE);
312209ff23fSmrg    } else {
313b7e1c893Smrg	if (mode->Flags & V_DBLSCAN)
314b7e1c893Smrg	    y *= 2;
315b7e1c893Smrg
316209ff23fSmrg	if (crtc_id == 0) {
317209ff23fSmrg	    OUTREG(RADEON_CUR_HORZ_VERT_OFF,  (RADEON_CUR_LOCK
318209ff23fSmrg					       | (xorigin << 16)
319209ff23fSmrg					       | yorigin));
320209ff23fSmrg	    OUTREG(RADEON_CUR_HORZ_VERT_POSN, (RADEON_CUR_LOCK
321209ff23fSmrg					       | ((xorigin ? 0 : x) << 16)
322209ff23fSmrg					       | (yorigin ? 0 : y)));
323209ff23fSmrg	    RADEONCTRACE(("cursor_offset: 0x%x, yorigin: %d, stride: %d, temp %08X\n",
324209ff23fSmrg			  radeon_crtc->cursor_offset + pScrn->fbOffset, yorigin, stride, temp));
325209ff23fSmrg	    OUTREG(RADEON_CUR_OFFSET,
326209ff23fSmrg		   radeon_crtc->cursor_offset + pScrn->fbOffset + yorigin * stride);
327209ff23fSmrg	} else if (crtc_id == 1) {
328209ff23fSmrg	    OUTREG(RADEON_CUR2_HORZ_VERT_OFF,  (RADEON_CUR2_LOCK
329209ff23fSmrg						| (xorigin << 16)
330209ff23fSmrg						| yorigin));
331209ff23fSmrg	    OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK
332209ff23fSmrg						| ((xorigin ? 0 : x) << 16)
333209ff23fSmrg						| (yorigin ? 0 : y)));
334209ff23fSmrg	    RADEONCTRACE(("cursor_offset2: 0x%x, yorigin: %d, stride: %d, temp %08X\n",
335209ff23fSmrg			  radeon_crtc->cursor_offset + pScrn->fbOffset, yorigin, stride, temp));
336209ff23fSmrg	    OUTREG(RADEON_CUR2_OFFSET,
337209ff23fSmrg		   radeon_crtc->cursor_offset + pScrn->fbOffset + yorigin * stride);
338209ff23fSmrg	}
339209ff23fSmrg    }
340209ff23fSmrg}
341209ff23fSmrg
342209ff23fSmrgvoid
343209ff23fSmrgradeon_crtc_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
344209ff23fSmrg{
345209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
346209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
347209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
34851b40f85Smrg    uint32_t *pixels = (uint32_t *)(pointer)(info->FB + pScrn->fbOffset + radeon_crtc->cursor_offset);
349209ff23fSmrg    int            pixel, i;
350209ff23fSmrg    CURSOR_SWAPPING_DECL_MMIO
351209ff23fSmrg
352209ff23fSmrg    RADEONCTRACE(("RADEONSetCursorColors\n"));
353209ff23fSmrg
354209ff23fSmrg#ifdef ARGB_CURSOR
355209ff23fSmrg    /* Don't recolour cursors set with SetCursorARGB. */
356209ff23fSmrg    if (info->cursor_argb)
357209ff23fSmrg       return;
358209ff23fSmrg#endif
359209ff23fSmrg
360209ff23fSmrg    fg |= 0xff000000;
361209ff23fSmrg    bg |= 0xff000000;
362209ff23fSmrg
363209ff23fSmrg    /* Don't recolour the image if we don't have to. */
364209ff23fSmrg    if (fg == info->cursor_fg && bg == info->cursor_bg)
365209ff23fSmrg       return;
366209ff23fSmrg
367209ff23fSmrg    CURSOR_SWAPPING_START();
368209ff23fSmrg
369209ff23fSmrg    /* Note: We assume that the pixels are either fully opaque or fully
370209ff23fSmrg     * transparent, so we won't premultiply them, and we can just
371209ff23fSmrg     * check for non-zero pixel values; those are either fg or bg
372209ff23fSmrg     */
373209ff23fSmrg    for (i = 0; i < CURSOR_WIDTH * CURSOR_HEIGHT; i++, pixels++)
374209ff23fSmrg       if ((pixel = *pixels))
375209ff23fSmrg           *pixels = (pixel == info->cursor_fg) ? fg : bg;
376209ff23fSmrg
377209ff23fSmrg    CURSOR_SWAPPING_END();
378209ff23fSmrg    info->cursor_fg = fg;
379209ff23fSmrg    info->cursor_bg = bg;
380209ff23fSmrg}
381209ff23fSmrg
382209ff23fSmrg#ifdef ARGB_CURSOR
383209ff23fSmrg
384209ff23fSmrgvoid
385209ff23fSmrgradeon_crtc_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
386209ff23fSmrg{
387209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
388209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
389209ff23fSmrg    RADEONInfoPtr  info = RADEONPTR(pScrn);
390209ff23fSmrg    CURSOR_SWAPPING_DECL_MMIO
39151b40f85Smrg    uint32_t *d = (uint32_t *)(pointer)(info->FB + pScrn->fbOffset + radeon_crtc->cursor_offset);
392209ff23fSmrg
393209ff23fSmrg    RADEONCTRACE(("RADEONLoadCursorARGB\n"));
394209ff23fSmrg
395209ff23fSmrg    info->cursor_argb = TRUE;
396209ff23fSmrg
397209ff23fSmrg    CURSOR_SWAPPING_START();
398209ff23fSmrg
399209ff23fSmrg    memcpy (d, image, CURSOR_HEIGHT * CURSOR_WIDTH * 4);
400209ff23fSmrg
401209ff23fSmrg    CURSOR_SWAPPING_END ();
402209ff23fSmrg}
403209ff23fSmrg
404209ff23fSmrg#endif
405209ff23fSmrg
406209ff23fSmrg
407209ff23fSmrg/* Initialize hardware cursor support. */
408209ff23fSmrgBool RADEONCursorInit(ScreenPtr pScreen)
409209ff23fSmrg{
410c135ecebSveego    ScrnInfoPtr        pScrn   = xf86ScreenToScrn(pScreen);
411209ff23fSmrg    RADEONInfoPtr      info    = RADEONPTR(pScrn);
412486efd68Smrg    unsigned char     *RADEONMMIO = info->MMIO;
413209ff23fSmrg    xf86CrtcConfigPtr  xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
414209ff23fSmrg    int                c;
415209ff23fSmrg
416486efd68Smrg    for (c = 0; c < xf86_config->num_crtc; c++) {
417486efd68Smrg	xf86CrtcPtr crtc = xf86_config->crtc[c];
418486efd68Smrg	RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
419209ff23fSmrg
420486efd68Smrg	if (!info->useEXA) {
421486efd68Smrg	    int size_bytes  = CURSOR_WIDTH * 4 * CURSOR_HEIGHT;
422486efd68Smrg	    int align = IS_AVIVO_VARIANT ? 4096 : 256;
423209ff23fSmrg
424b7e1c893Smrg	    radeon_crtc->cursor_offset =
425f1bc02b7Smrg		radeon_legacy_allocate_memory(pScrn, &radeon_crtc->cursor_mem,
426f1bc02b7Smrg				size_bytes, align, RADEON_GEM_DOMAIN_VRAM);
427b7e1c893Smrg
428b7e1c893Smrg	    if (radeon_crtc->cursor_offset == 0)
429b7e1c893Smrg		return FALSE;
430b7e1c893Smrg
431b7e1c893Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
432b7e1c893Smrg		       "Will use %d kb for hardware cursor %d at offset 0x%08x\n",
433b7e1c893Smrg		       (size_bytes * xf86_config->num_crtc) / 1024,
434b7e1c893Smrg		       c,
435b7e1c893Smrg		       (unsigned int)radeon_crtc->cursor_offset);
436209ff23fSmrg	}
437486efd68Smrg	/* set the cursor mode the same on both crtcs to avoid corruption */
438f1bc02b7Smrg	/* XXX check if this is needed on evergreen */
439486efd68Smrg	if (IS_AVIVO_VARIANT)
440486efd68Smrg	    OUTREG(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
441486efd68Smrg		   (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
442209ff23fSmrg    }
443209ff23fSmrg
444209ff23fSmrg    return xf86_cursors_init (pScreen, CURSOR_WIDTH, CURSOR_HEIGHT,
445209ff23fSmrg			      (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
446209ff23fSmrg			       HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
447209ff23fSmrg			       HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
448209ff23fSmrg			       HARDWARE_CURSOR_ARGB));
449209ff23fSmrg}
450