1/*
2 * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
3 *                      Precision Insight, Inc., Cedar Park, Texas, and
4 *                      VA Linux Systems Inc., Fremont, California.
5 *
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation on the rights to use, copy, modify, merge,
12 * publish, distribute, sublicense, and/or sell copies of the Software,
13 * and to permit persons to whom the Software is furnished to do so,
14 * subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial
18 * portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX
24 * SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 */
29
30/*
31 * Authors:
32 *   Rickard E. Faith <faith@valinux.com>
33 *   Kevin E. Martin <martin@valinux.com>
34 *
35 * References:
36 *
37 *   RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical
38 *   Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April
39 *   1999.
40 *
41 *   RAGE 128 Software Development Manual (Technical Reference Manual P/N
42 *   SDK-G04000 Rev. 0.01), ATI Technologies: June 1999.
43 *
44 */
45
46#ifdef HAVE_CONFIG_H
47#include "config.h"
48#endif
49
50				/* Driver data structures */
51#include "r128.h"
52#include "r128_reg.h"
53
54				/* X and server generic header files */
55#include "xf86.h"
56
57				/* Because for EXA we need to use a different allocator */
58#ifdef USE_EXA
59#include "exa.h"
60#endif
61
62#define CURSOR_WIDTH    64
63#define CURSOR_HEIGHT   64
64
65void r128_crtc_show_cursor(xf86CrtcPtr crtc)
66{
67    ScrnInfoPtr pScrn = crtc->scrn;
68    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
69    R128InfoPtr info = R128PTR(pScrn);
70    unsigned char *R128MMIO = info->MMIO;
71    int crtc_id = r128_crtc->crtc_id;
72
73    switch (crtc_id) {
74    case 0:
75        OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_CUR_EN, ~R128_CRTC_CUR_EN);
76        break;
77    case 1:
78        OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_CUR_EN, ~R128_CRTC2_CUR_EN);
79        break;
80    default:
81        return;
82    }
83}
84
85void r128_crtc_hide_cursor(xf86CrtcPtr crtc)
86{
87    ScrnInfoPtr pScrn = crtc->scrn;
88    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
89    R128InfoPtr info = R128PTR(pScrn);
90    unsigned char *R128MMIO = info->MMIO;
91    int crtc_id = r128_crtc->crtc_id;
92
93    switch (crtc_id) {
94    case 0:
95        OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_CUR_EN);
96        break;
97    case 1:
98        OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_CUR_EN);
99        break;
100    default:
101        return;
102    }
103}
104
105void r128_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
106{
107    ScrnInfoPtr pScrn = crtc->scrn;
108    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
109    R128InfoPtr info = R128PTR(pScrn);
110    unsigned char *R128MMIO = info->MMIO;
111    int crtc_id = r128_crtc->crtc_id;
112
113    switch (crtc_id) {
114    case 0:
115        OUTREG(R128_CUR_CLR0, bg);
116        OUTREG(R128_CUR_CLR1, fg);
117        break;
118    case 1:
119        OUTREG(R128_CUR2_CLR0, bg);
120        OUTREG(R128_CUR2_CLR1, fg);
121        break;
122    default:
123        return;
124    }
125}
126
127void r128_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
128{
129    ScrnInfoPtr           pScrn         = crtc->scrn;
130    R128InfoPtr           info          = R128PTR(pScrn);
131    R128CrtcPrivatePtr    r128_crtc     = crtc->driver_private;
132    unsigned char         *R128MMIO     = info->MMIO;
133    int                   crtc_id       = r128_crtc->crtc_id;
134
135    int xorigin = 0, yorigin = 0;
136    DisplayModePtr mode = &crtc->mode;
137
138    if (x < 0) xorigin = -x + 1;
139    if (y < 0) yorigin = -y + 1;
140    if (xorigin >= CURSOR_WIDTH)  xorigin = CURSOR_WIDTH - 1;
141    if (yorigin >= CURSOR_HEIGHT) yorigin = CURSOR_HEIGHT - 1;
142
143    if (mode->Flags & V_INTERLACE)
144        y /= 2;
145    else if (mode->Flags & V_DBLSCAN)
146        y *= 2;
147
148    if(crtc_id == 0) {
149        OUTREG(R128_CUR_HORZ_VERT_OFF, (R128_CUR_LOCK | (xorigin << 16) | yorigin));
150        OUTREG(R128_CUR_HORZ_VERT_POSN, (R128_CUR_LOCK | ((xorigin ? 0 : x) << 16) | (yorigin ? 0 : y)));
151        OUTREG(R128_CUR_OFFSET, r128_crtc->cursor_offset + pScrn->fbOffset + yorigin * 16);
152    } else if (crtc_id == 1) {
153        OUTREG(R128_CUR2_HORZ_VERT_OFF, (R128_CUR2_LOCK | (xorigin << 16) | yorigin));
154        OUTREG(R128_CUR2_HORZ_VERT_POSN, (R128_CUR2_LOCK | ((xorigin ? 0 : x) << 16) | (yorigin ? 0 : y)));
155        OUTREG(R128_CUR2_OFFSET, r128_crtc->cursor_offset + pScrn->fbOffset + yorigin * 16);
156    }
157}
158
159void r128_crtc_load_cursor_image(xf86CrtcPtr crtc, unsigned char *src)
160{
161    ScrnInfoPtr pScrn = crtc->scrn;
162    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
163    int crtc_id = r128_crtc->crtc_id;
164
165    R128InfoPtr   info      = R128PTR(pScrn);
166    unsigned char *R128MMIO = info->MMIO;
167    uint32_t      save1     = 0;
168    uint32_t      save2     = 0;
169
170    if (crtc_id == 0) {
171	save1 = INREG(R128_CRTC_GEN_CNTL);
172	OUTREG(R128_CRTC_GEN_CNTL, save1 & (uint32_t)~R128_CRTC_CUR_EN);
173    } else if (crtc_id == 1) {
174	save2 = INREG(R128_CRTC2_GEN_CNTL);
175	OUTREG(R128_CRTC2_GEN_CNTL, save2 & (uint32_t)~R128_CRTC2_CUR_EN);
176    }
177
178#if X_BYTE_ORDER == X_BIG_ENDIAN
179    if (info->CurrentLayout.pixel_bytes == 4 || info->CurrentLayout.pixel_bytes == 3)
180        R128CopySwap(info->FB + r128_crtc->cursor_offset + pScrn->fbOffset, src,
181                     CURSOR_WIDTH * CURSOR_HEIGHT / 4, APER_0_BIG_ENDIAN_32BPP_SWAP);
182    else if (info->CurrentLayout.pixel_bytes == 2)
183        R128CopySwap(info->FB + r128_crtc->cursor_offset + pScrn->fbOffset, src,
184                     CURSOR_WIDTH * CURSOR_HEIGHT / 4, APER_0_BIG_ENDIAN_16BPP_SWAP);
185    else
186#endif
187    memcpy(info->FB + r128_crtc->cursor_offset + pScrn->fbOffset, src, CURSOR_WIDTH * CURSOR_HEIGHT / 4);
188
189    if (crtc_id == 0)
190	OUTREG(R128_CRTC_GEN_CNTL, save1);
191    else
192        OUTREG(R128_CRTC2_GEN_CNTL, save2);
193}
194
195/* Initialize hardware cursor support. */
196Bool R128CursorInit(ScreenPtr pScreen)
197{
198    ScrnInfoPtr           pScrn   = xf86ScreenToScrn(pScreen);
199    R128InfoPtr           info    = R128PTR(pScrn);
200    FBAreaPtr             fbarea  = NULL;
201#ifdef USE_EXA
202    ExaOffscreenArea*	  osArea  = NULL;
203#else
204    void*		  osArea  = NULL;
205#endif
206    xf86CrtcConfigPtr     xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
207    uint32_t              cursor_offset = 0;
208    int                   cpp = info->CurrentLayout.pixel_bytes;
209    int                   width;
210    int                   width_bytes;
211    int                   height;
212    int                   size;
213    int                   size_bytes;
214    int                   c;
215
216    size                      = CURSOR_WIDTH * CURSOR_HEIGHT / 4;
217    size_bytes                = size * 2;
218    width                     = pScrn->displayWidth;
219    width_bytes               = width * (pScrn->bitsPerPixel / 8);
220    height                    = ((size_bytes * xf86_config->num_crtc) + width_bytes - 1) / width_bytes;
221
222    if(!info->useEXA) {
223	fbarea = xf86AllocateOffscreenArea(pScreen, width, height,
224					   16, NULL, NULL, NULL);
225
226	if (fbarea)
227	    cursor_offset = R128_ALIGN((fbarea->box.x1 + width * fbarea->box.y1) * cpp, 16);
228    }
229#ifdef USE_EXA
230    else {
231	osArea = exaOffscreenAlloc(pScreen, width * height, 16,
232				   TRUE, NULL, NULL);
233
234	if (osArea)
235	    cursor_offset = osArea->offset;
236    }
237#endif
238
239    if ((!info->useEXA && !fbarea) || (info->useEXA && !osArea)) {
240	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
241		   "Hardware cursor disabled"
242		   " due to insufficient offscreen memory\n");
243        return FALSE;
244    } else {
245        for (c = 0; c < xf86_config->num_crtc; c++) {
246            xf86CrtcPtr crtc = xf86_config->crtc[c];
247	    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
248
249            r128_crtc->cursor_offset = cursor_offset + (c * size);
250            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
251		       "Will use %d kb for hardware cursor %d at offset 0x%08x\n",
252		       (size_bytes * xf86_config->num_crtc) / 1024, c,
253		       (unsigned int)r128_crtc->cursor_offset);
254        }
255    }
256
257    return xf86_cursors_init(pScreen, CURSOR_WIDTH, CURSOR_HEIGHT,
258			     (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
259			      HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
260			      HARDWARE_CURSOR_SHOW_TRANSPARENT |
261			      HARDWARE_CURSOR_UPDATE_UNHIDDEN |
262#if X_BYTE_ORDER == X_LITTLE_ENDIAN
263			      HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
264#endif
265			      HARDWARE_CURSOR_INVERT_MASK |
266			      HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
267			      HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64));
268}
269