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