1 /*
2 * Hardware cursor support for CL-GD546x -- The Laugna family
3 *
4 * lg_hwcurs.c
5 *
6 * (c) 1998 Corin Anderson.
7 * corina@the4cs.com
8 * Tukwila, WA
9 *
10 * Much of this code is inspired by the HW cursor code from XFree86
11 * 3.3.3.
12 */
13
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17
18 #include "xf86.h"
19 #include "xf86_OSproc.h"
20 #include "compiler.h"
21
22 #include "xf86Pci.h"
23
24 #include "vgaHW.h"
25
26 #include "cir.h"
27 #define _LG_PRIVATE_
28 #include "lg.h"
29 #include "lg_xaa.h" /* For BitBLT engine macros */
30
31 /*
32 #define LG_CURSOR_DEBUG
33 */
34
35 #define CURSORWIDTH 64
36 #define CURSORHEIGHT 64
37 #define CURSORSIZE (CURSORWIDTH*CURSORHEIGHT/8)
38
39 /* Some registers used for the HW cursor. */
40 enum {
41 PALETTE_READ_ADDR = 0x00A4,
42 PALETTE_WRITE_ADDR = 0x00A8,
43 PALETTE_DATA = 0x00AC,
44
45 PALETTE_STATE = 0x00B0,
46 CURSOR_X_POS = 0x00E0,
47 CURSOR_Y_POS = 0x00E2,
48 CURSOR_PRESET = 0x00E4,
49 CURSOR_CONTROL = 0x00E6,
50 CURSOR_ADDR = 0x00E8
51 };
52
53
54 static void
55 LgFindCursorTile(ScrnInfoPtr pScrn, int *x, int *y, int *width, int *height,
56 CARD32 *curAddr);
57
58
59 /*
60 * Set the FG and BG colors of the HW cursor.
61 */
LgSetCursorColors(ScrnInfoPtr pScrn,int bg,int fg)62 static void LgSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
63 {
64 const CirPtr pCir = CIRPTR(pScrn);
65
66 #ifdef LG_CURSOR_DEBUG
67 ErrorF("LgSetCursorColors\n");
68 #endif
69
70 /* Enable access to cursor colors in palette */
71 memwb(PALETTE_STATE, (memrb(PALETTE_STATE) | (1<<3)));
72
73 /* Slam in the color */
74
75 memwb(PALETTE_WRITE_ADDR, 0x00);
76 memwb(PALETTE_DATA, (bg >> 16));
77 memwb(PALETTE_DATA, (bg >> 8));
78 memwb(PALETTE_DATA, (bg >> 0));
79 memwb(PALETTE_WRITE_ADDR, 0x0F);
80 memwb(PALETTE_DATA, (fg >> 16));
81 memwb(PALETTE_DATA, (fg >> 8));
82 memwb(PALETTE_DATA, (fg >> 0));
83
84 /* Disable access to cursor colors */
85 memwb(PALETTE_STATE, (memrb(PALETTE_STATE) & ~(1<<3)));
86 }
87
88
89 /*
90 * Set the (x,y) position of the pointer.
91 *
92 * Note: (x,y) are /frame/ relative, not /framebuffer/ relative.
93 * That is, if the virtual desktop has been panned all the way to
94 * the right, and the pointer is to be in the upper-right hand corner
95 * of the viewable screen, the pointer coords are (0,0) (even though
96 * the pointer is on, say (550,0) wrt the frame buffer). This is, of
97 * course, a /good/ thing -- we don't want to have to deal with where
98 * the virtual display is, etc, in the cursor code.
99 *
100 */
LgSetCursorPosition(ScrnInfoPtr pScrn,int x,int y)101 static void LgSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
102 {
103 const CirPtr pCir = CIRPTR(pScrn);
104
105 #if 0
106 #ifdef LG_CURSOR_DEBUG
107 ErrorF("LgSetCursorPosition %d %d\n", x, y);
108 #endif
109 #endif
110
111 if (x < 0 || y < 0) {
112 CARD16 oldPreset = memrw(CURSOR_PRESET);
113 CARD16 newPreset = 0x8080 & oldPreset; /* Reserved bits */
114
115 if (x < 0) {
116 newPreset |= ((-x & 0x7F) << 8);
117 x = 0;
118 }
119
120 if (y < 0) {
121 newPreset |= ((-y & 0x7F) << 0);
122 y = 0;
123 }
124
125 memww(CURSOR_PRESET, newPreset);
126 pCir->CursorIsSkewed = TRUE;
127 } else if (pCir->CursorIsSkewed) {
128 /* Reset the hotspot location. */
129 memww(CURSOR_PRESET, memrw(CURSOR_PRESET & 0x8080));
130 pCir->CursorIsSkewed = FALSE;
131 }
132
133 /* Commit the new position to the card. */
134 memww(CURSOR_X_POS, x);
135 memww(CURSOR_Y_POS, y);
136 }
137
138
139 /*
140 * Load the cursor image to the card. The cursor image is given in
141 * bits. The format is: ???
142 */
LgLoadCursorImage(ScrnInfoPtr pScrn,unsigned char * bits)143 static void LgLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *bits)
144 {
145 const CirPtr pCir = CIRPTR(pScrn);
146 const LgPtr pLg = LGPTR(pCir);
147
148 volatile CARD32 *pXCursorBits = (CARD32 *)bits;
149
150 int l, w;
151
152 #ifdef LG_CURSOR_DEBUG
153 ErrorF("LgLoadCursorImage\n");
154 #endif
155
156 /* All ("all") we have to do is a simple CPU-to-screen copy of the
157 cursor image to the frame buffer. */
158
159 while (!LgREADY()) {}
160 ;
161
162 /* Wait until there's ample room in the chip's queue */
163 while (memrb(QFREE) < 10) {}
164 ;
165
166 LgSETMODE(HOST2SCR); /* Host-to-screen blit */
167 LgSETROP(0x00CC); /* Source copy */
168
169 /* First, copy our transparent cursor image to the next 1/2 tile boundry */
170 /* Destination */
171 LgSETMDSTXY(pLg->HWCursorImageX+pLg->HWCursorTileWidth, pLg->HWCursorImageY);
172
173 /* Set the source pitch. 0 means that, worst case, the source is
174 alligned only on a byte boundry */
175 LgSETMPHASE1(0);
176
177 LgSETMEXTENTSNOMONOQW(pLg->HWCursorTileWidth, pLg->HWCursorTileHeight);
178
179 for (l = 0; l < CURSORHEIGHT; l++) {
180 /* Plane 0 */
181 for (w = 0; w < CURSORWIDTH >> 5; w++)
182 memwl(HOSTDATA, 0x00000000);
183 /* Plane 1 */
184 for (w = 0; w < CURSORWIDTH >> 5; w++)
185 memwl(HOSTDATA, 0x00000000);
186 }
187
188 /* Now, copy the real cursor image */
189
190 /* Set the destination */
191 LgSETMDSTXY(pLg->HWCursorImageX, pLg->HWCursorImageY);
192
193 /* Set the source pitch. 0 means that, worst case, the source is
194 alligned only on a byte boundry */
195 LgSETMPHASE1(0);
196
197 /* Always copy an entire cursor image to the card. */
198 LgSETMEXTENTSNOMONOQW(pLg->HWCursorTileWidth, pLg->HWCursorTileHeight);
199
200 for (l = 0; l < CURSORHEIGHT; l++) {
201 /* Plane 0 */
202 for (w = 0; w < CURSORWIDTH >> 5; w++)
203 memwl(HOSTDATA, *pXCursorBits++);
204 /* Plane 1 */
205 for (w = 0; w < CURSORWIDTH >> 5; w++)
206 memwl(HOSTDATA, *pXCursorBits++);
207 }
208
209 while (!LgREADY())
210 ;
211 }
212
213
214
215 /*
216 * LgFindCursorTile() finds the tile of display memory that will be
217 * used to load the pointer image into. The tile chosen will be the
218 * last tile in the last line of the frame buffer.
219 */
220 static void
LgFindCursorTile(ScrnInfoPtr pScrn,int * x,int * y,int * width,int * height,CARD32 * curAddr)221 LgFindCursorTile(ScrnInfoPtr pScrn, int *x, int *y, int *width, int *height,
222 CARD32 *curAddr)
223 {
224 CirPtr pCir = CIRPTR(pScrn);
225 LgPtr pLg = LGPTR(pCir);
226
227 int videoRam = pScrn->videoRam; /* in K */
228 int tileHeight = LgLineData[pLg->lineDataIndex].width?8:16;
229 int tileWidth = LgLineData[pLg->lineDataIndex].width?256:128;
230 int tilesPerLine = LgLineData[pLg->lineDataIndex].tilesPerLine;
231 int filledOutTileLines, leftoverMem;
232 int yTile, xTile;
233 int tileNumber;
234
235 filledOutTileLines = videoRam / (tilesPerLine * 2); /* tiles are 2K */
236 leftoverMem = videoRam - filledOutTileLines*tilesPerLine*2;
237
238 if (leftoverMem > 0) {
239 yTile = filledOutTileLines;
240 } else {
241 /* There is no incomplete row of tiles. Then just use the last
242 tile in the last line */
243 yTile = filledOutTileLines - 1;
244 }
245 xTile = 0; /* Always use the first tile in the determined tile row */
246
247 /* The (x,y) coords of the pointer image. */
248 if (x)
249 *x = xTile * tileWidth;
250 if (y)
251 *y = yTile * tileHeight;
252
253 if (width)
254 *width = tileWidth;
255 if (height)
256 *height = tileHeight / 2;
257
258 /* Now, compute the linear address of the cursor image. This process
259 is unpleasant because the memory is tiled, and we essetially have
260 to undo the tiling computation. */
261 if (curAddr) {
262 unsigned int nIL; /* Interleaving */
263 nIL = pLg->memInterleave==0x00? 1 : (pLg->memInterleave==0x40 ? 2 : 4);
264
265 if (PCI_CHIP_GD5465 == pCir->Chipset) {
266 /* The Where's The Cursor formula changed for the 5465. It's really
267 kinda wierd now. */
268 unsigned long page, bank;
269 unsigned int nX, nY;
270
271 nX = xTile * tileWidth;
272 nY = yTile * tileHeight;
273
274 page = (nY / (tileHeight * nIL)) * tilesPerLine + nX / tileWidth;
275 bank = (nX/tileWidth + nY/tileHeight) % nIL + page/(512*nIL);
276 page = page & 0x1FF;
277 *curAddr = bank*1024*1024L + page*2048 + (nY%tileHeight)*tileWidth;
278 } else {
279 tileNumber = (tilesPerLine*nIL) * (yTile/nIL) + yTile % nIL;
280 *curAddr = tileNumber * 2048;
281 }
282 }
283 }
284
285
286
287
288 /*
289 * Hide/disable the HW cursor.
290 */
LgHideCursor(ScrnInfoPtr pScrn)291 void LgHideCursor(ScrnInfoPtr pScrn)
292 {
293 const CirPtr pCir = CIRPTR(pScrn);
294
295 /* To hide the cursor, we kick it off into the corner, and then set the
296 cursor image to be a transparent bitmap. That way, if X continues
297 to move the cursor while it is hidden, there is no way that the user
298 can move the cursor back on screen!
299
300 We don't just clear the cursor enable bit because doesn't work in some
301 cases (like when switching back to text mode).
302 */
303
304 #ifdef LG_CURSOR_DEBUG
305 ErrorF("LgHideCursor\n");
306 #endif
307
308 memww(CURSOR_CONTROL, (memrw(CURSOR_CONTROL) & 0xFFFE));
309 }
310
LgShowCursor(ScrnInfoPtr pScrn)311 void LgShowCursor(ScrnInfoPtr pScrn)
312 {
313 const CirPtr pCir = CIRPTR(pScrn);
314 const LgPtr pLg = LGPTR(pCir);
315
316 #ifdef LG_CURSOR_DEBUG
317 ErrorF("LgShowCursor\n");
318 #endif
319
320 memww(CURSOR_CONTROL,(memrw(CURSOR_CONTROL) | (1<<0)));
321 memww(CURSOR_ADDR,(pLg->HWCursorAddr & 0x7FFC));
322 }
323
324
325 /*
326 * Can the HW cursor be used?
327 */
LgUseHWCursor(ScreenPtr pScreen,CursorPtr pCurs)328 static Bool LgUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
329 {
330 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
331
332 #ifdef LG_CURSOR_DEBUG
333 ErrorF("LgUseHWCursor\n");
334 #endif
335
336 if(pScrn->bitsPerPixel < 8)
337 return FALSE;
338
339 return TRUE;
340 }
341
342
343 /*
344 * Initialize all the fun HW cursor code.
345 */
LgHWCursorInit(ScreenPtr pScreen)346 Bool LgHWCursorInit(ScreenPtr pScreen)
347 {
348 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
349 CirPtr pCir = CIRPTR(pScrn);
350 xf86CursorInfoPtr infoPtr;
351
352 #ifdef LG_CURSOR_DEBUG
353 ErrorF("LgHWCursorInit\n");
354 #endif
355
356 infoPtr = xf86CreateCursorInfoRec();
357 if(!infoPtr) return FALSE;
358
359 pCir->CursorInfoRec = infoPtr;
360 LgFindCursorTile(pScrn, &pCir->chip.lg->HWCursorImageX, &pCir->chip.lg->HWCursorImageY,
361 &pCir->chip.lg->HWCursorTileWidth, &pCir->chip.lg->HWCursorTileHeight,
362 &pCir->chip.lg->HWCursorAddr);
363 /* Keep only bits 22:10 of the address. */
364 pCir->chip.lg->HWCursorAddr = (pCir->chip.lg->HWCursorAddr >> 8) & 0x7FFC;
365
366 pCir->CursorIsSkewed = FALSE;
367
368 infoPtr->MaxWidth = CURSORWIDTH;
369 infoPtr->MaxHeight = CURSORHEIGHT;
370 infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
371 | HARDWARE_CURSOR_AND_SOURCE_WITH_MASK
372 | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64;
373 infoPtr->SetCursorColors = LgSetCursorColors;
374 infoPtr->SetCursorPosition = LgSetCursorPosition;
375 infoPtr->LoadCursorImage = LgLoadCursorImage;
376 infoPtr->HideCursor = LgHideCursor;
377 infoPtr->ShowCursor = LgShowCursor;
378 infoPtr->UseHWCursor = LgUseHWCursor;
379
380 #ifdef LG_CURSOR_DEBUG
381 ErrorF("LgHWCursorInit before xf86InitCursor\n");
382 #endif
383
384 return(xf86InitCursor(pScreen, infoPtr));
385 }
386