176888252Smrg/* 276888252Smrg * Hardware cursor support for CL-GD546x -- The Laugna family 376888252Smrg * 476888252Smrg * lg_hwcurs.c 576888252Smrg * 676888252Smrg * (c) 1998 Corin Anderson. 776888252Smrg * corina@the4cs.com 876888252Smrg * Tukwila, WA 976888252Smrg * 1076888252Smrg * Much of this code is inspired by the HW cursor code from XFree86 1176888252Smrg * 3.3.3. 1276888252Smrg */ 1376888252Smrg 1476888252Smrg#ifdef HAVE_CONFIG_H 1576888252Smrg#include "config.h" 1676888252Smrg#endif 1776888252Smrg 1876888252Smrg#include "xf86.h" 1976888252Smrg#include "xf86_OSproc.h" 2076888252Smrg#include "compiler.h" 2176888252Smrg 2276888252Smrg#include "xf86Pci.h" 2376888252Smrg 2476888252Smrg#include "vgaHW.h" 2576888252Smrg 2676888252Smrg#include "cir.h" 2776888252Smrg#define _LG_PRIVATE_ 2876888252Smrg#include "lg.h" 2976888252Smrg#include "lg_xaa.h" /* For BitBLT engine macros */ 3076888252Smrg 3176888252Smrg/* 3276888252Smrg#define LG_CURSOR_DEBUG 3376888252Smrg*/ 3476888252Smrg 3576888252Smrg#define CURSORWIDTH 64 3676888252Smrg#define CURSORHEIGHT 64 3776888252Smrg#define CURSORSIZE (CURSORWIDTH*CURSORHEIGHT/8) 3876888252Smrg 3976888252Smrg/* Some registers used for the HW cursor. */ 4076888252Smrgenum { 4176888252Smrg PALETTE_READ_ADDR = 0x00A4, 4276888252Smrg PALETTE_WRITE_ADDR = 0x00A8, 4376888252Smrg PALETTE_DATA = 0x00AC, 4476888252Smrg 4576888252Smrg PALETTE_STATE = 0x00B0, 4676888252Smrg CURSOR_X_POS = 0x00E0, 4776888252Smrg CURSOR_Y_POS = 0x00E2, 4876888252Smrg CURSOR_PRESET = 0x00E4, 4976888252Smrg CURSOR_CONTROL = 0x00E6, 5076888252Smrg CURSOR_ADDR = 0x00E8 5176888252Smrg}; 5276888252Smrg 5376888252Smrg 5476888252Smrgstatic void 5576888252SmrgLgFindCursorTile(ScrnInfoPtr pScrn, int *x, int *y, int *width, int *height, 5676888252Smrg CARD32 *curAddr); 5776888252Smrg 5876888252Smrg 5976888252Smrg/* 6076888252Smrg * Set the FG and BG colors of the HW cursor. 6176888252Smrg */ 6276888252Smrgstatic void LgSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) 6376888252Smrg{ 6476888252Smrg const CirPtr pCir = CIRPTR(pScrn); 6576888252Smrg 6676888252Smrg#ifdef LG_CURSOR_DEBUG 6776888252Smrg ErrorF("LgSetCursorColors\n"); 6876888252Smrg#endif 6976888252Smrg 7076888252Smrg /* Enable access to cursor colors in palette */ 7176888252Smrg memwb(PALETTE_STATE, (memrb(PALETTE_STATE) | (1<<3))); 7276888252Smrg 7376888252Smrg /* Slam in the color */ 7476888252Smrg 7576888252Smrg memwb(PALETTE_WRITE_ADDR, 0x00); 7676888252Smrg memwb(PALETTE_DATA, (bg >> 16)); 7776888252Smrg memwb(PALETTE_DATA, (bg >> 8)); 7876888252Smrg memwb(PALETTE_DATA, (bg >> 0)); 7976888252Smrg memwb(PALETTE_WRITE_ADDR, 0x0F); 8076888252Smrg memwb(PALETTE_DATA, (fg >> 16)); 8176888252Smrg memwb(PALETTE_DATA, (fg >> 8)); 8276888252Smrg memwb(PALETTE_DATA, (fg >> 0)); 8376888252Smrg 8476888252Smrg /* Disable access to cursor colors */ 8576888252Smrg memwb(PALETTE_STATE, (memrb(PALETTE_STATE) & ~(1<<3))); 8676888252Smrg} 8776888252Smrg 8876888252Smrg 8976888252Smrg/* 9076888252Smrg * Set the (x,y) position of the pointer. 9176888252Smrg * 9276888252Smrg * Note: (x,y) are /frame/ relative, not /framebuffer/ relative. 9376888252Smrg * That is, if the virtual desktop has been panned all the way to 9476888252Smrg * the right, and the pointer is to be in the upper-right hand corner 9576888252Smrg * of the viewable screen, the pointer coords are (0,0) (even though 9676888252Smrg * the pointer is on, say (550,0) wrt the frame buffer). This is, of 9776888252Smrg * course, a /good/ thing -- we don't want to have to deal with where 9876888252Smrg * the virtual display is, etc, in the cursor code. 9976888252Smrg * 10076888252Smrg */ 10176888252Smrgstatic void LgSetCursorPosition(ScrnInfoPtr pScrn, int x, int y) 10276888252Smrg{ 10376888252Smrg const CirPtr pCir = CIRPTR(pScrn); 10476888252Smrg 10576888252Smrg#if 0 10676888252Smrg#ifdef LG_CURSOR_DEBUG 10776888252Smrg ErrorF("LgSetCursorPosition %d %d\n", x, y); 10876888252Smrg#endif 10976888252Smrg#endif 11076888252Smrg 11176888252Smrg if (x < 0 || y < 0) { 11276888252Smrg CARD16 oldPreset = memrw(CURSOR_PRESET); 11376888252Smrg CARD16 newPreset = 0x8080 & oldPreset; /* Reserved bits */ 11476888252Smrg 11576888252Smrg if (x < 0) { 11676888252Smrg newPreset |= ((-x & 0x7F) << 8); 11776888252Smrg x = 0; 11876888252Smrg } 11976888252Smrg 12076888252Smrg if (y < 0) { 12176888252Smrg newPreset |= ((-y & 0x7F) << 0); 12276888252Smrg y = 0; 12376888252Smrg } 12476888252Smrg 12576888252Smrg memww(CURSOR_PRESET, newPreset); 12676888252Smrg pCir->CursorIsSkewed = TRUE; 12776888252Smrg } else if (pCir->CursorIsSkewed) { 12876888252Smrg /* Reset the hotspot location. */ 12976888252Smrg memww(CURSOR_PRESET, memrw(CURSOR_PRESET & 0x8080)); 13076888252Smrg pCir->CursorIsSkewed = FALSE; 13176888252Smrg } 13276888252Smrg 13376888252Smrg /* Commit the new position to the card. */ 13476888252Smrg memww(CURSOR_X_POS, x); 13576888252Smrg memww(CURSOR_Y_POS, y); 13676888252Smrg} 13776888252Smrg 13876888252Smrg 13976888252Smrg/* 14076888252Smrg * Load the cursor image to the card. The cursor image is given in 14176888252Smrg * bits. The format is: ??? 14276888252Smrg */ 14376888252Smrgstatic void LgLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *bits) 14476888252Smrg{ 14576888252Smrg const CirPtr pCir = CIRPTR(pScrn); 14676888252Smrg const LgPtr pLg = LGPTR(pCir); 14776888252Smrg 14876888252Smrg volatile CARD32 *pXCursorBits = (CARD32 *)bits; 14976888252Smrg 15076888252Smrg int l, w; 15176888252Smrg 15276888252Smrg#ifdef LG_CURSOR_DEBUG 15376888252Smrg ErrorF("LgLoadCursorImage\n"); 15476888252Smrg#endif 15576888252Smrg 15676888252Smrg /* All ("all") we have to do is a simple CPU-to-screen copy of the 15776888252Smrg cursor image to the frame buffer. */ 15876888252Smrg 15976888252Smrg while (!LgREADY()) {} 16076888252Smrg ; 16176888252Smrg 16276888252Smrg /* Wait until there's ample room in the chip's queue */ 16376888252Smrg while (memrb(QFREE) < 10) {} 16476888252Smrg ; 16576888252Smrg 16676888252Smrg LgSETMODE(HOST2SCR); /* Host-to-screen blit */ 16776888252Smrg LgSETROP(0x00CC); /* Source copy */ 16876888252Smrg 1690814a2baSmrg /* First, copy our transparent cursor image to the next 1/2 tile boundary */ 17076888252Smrg /* Destination */ 17176888252Smrg LgSETMDSTXY(pLg->HWCursorImageX+pLg->HWCursorTileWidth, pLg->HWCursorImageY); 17276888252Smrg 17376888252Smrg /* Set the source pitch. 0 means that, worst case, the source is 1740814a2baSmrg aligned only on a byte boundary */ 17576888252Smrg LgSETMPHASE1(0); 17676888252Smrg 17776888252Smrg LgSETMEXTENTSNOMONOQW(pLg->HWCursorTileWidth, pLg->HWCursorTileHeight); 17876888252Smrg 17976888252Smrg for (l = 0; l < CURSORHEIGHT; l++) { 18076888252Smrg /* Plane 0 */ 18176888252Smrg for (w = 0; w < CURSORWIDTH >> 5; w++) 18276888252Smrg memwl(HOSTDATA, 0x00000000); 18376888252Smrg /* Plane 1 */ 18476888252Smrg for (w = 0; w < CURSORWIDTH >> 5; w++) 18576888252Smrg memwl(HOSTDATA, 0x00000000); 18676888252Smrg } 18776888252Smrg 18876888252Smrg /* Now, copy the real cursor image */ 18976888252Smrg 19076888252Smrg /* Set the destination */ 19176888252Smrg LgSETMDSTXY(pLg->HWCursorImageX, pLg->HWCursorImageY); 19276888252Smrg 19376888252Smrg /* Set the source pitch. 0 means that, worst case, the source is 1940814a2baSmrg aligned only on a byte boundary */ 19576888252Smrg LgSETMPHASE1(0); 19676888252Smrg 19776888252Smrg /* Always copy an entire cursor image to the card. */ 19876888252Smrg LgSETMEXTENTSNOMONOQW(pLg->HWCursorTileWidth, pLg->HWCursorTileHeight); 19976888252Smrg 20076888252Smrg for (l = 0; l < CURSORHEIGHT; l++) { 20176888252Smrg /* Plane 0 */ 20276888252Smrg for (w = 0; w < CURSORWIDTH >> 5; w++) 20376888252Smrg memwl(HOSTDATA, *pXCursorBits++); 20476888252Smrg /* Plane 1 */ 20576888252Smrg for (w = 0; w < CURSORWIDTH >> 5; w++) 20676888252Smrg memwl(HOSTDATA, *pXCursorBits++); 20776888252Smrg } 20876888252Smrg 20976888252Smrg while (!LgREADY()) 21076888252Smrg ; 21176888252Smrg} 21276888252Smrg 21376888252Smrg 21476888252Smrg 21576888252Smrg/* 21676888252Smrg * LgFindCursorTile() finds the tile of display memory that will be 21776888252Smrg * used to load the pointer image into. The tile chosen will be the 21876888252Smrg * last tile in the last line of the frame buffer. 21976888252Smrg */ 22076888252Smrgstatic void 22176888252SmrgLgFindCursorTile(ScrnInfoPtr pScrn, int *x, int *y, int *width, int *height, 22276888252Smrg CARD32 *curAddr) 22376888252Smrg{ 22476888252Smrg CirPtr pCir = CIRPTR(pScrn); 22576888252Smrg LgPtr pLg = LGPTR(pCir); 22676888252Smrg 22776888252Smrg int videoRam = pScrn->videoRam; /* in K */ 22876888252Smrg int tileHeight = LgLineData[pLg->lineDataIndex].width?8:16; 22976888252Smrg int tileWidth = LgLineData[pLg->lineDataIndex].width?256:128; 23076888252Smrg int tilesPerLine = LgLineData[pLg->lineDataIndex].tilesPerLine; 23176888252Smrg int filledOutTileLines, leftoverMem; 23276888252Smrg int yTile, xTile; 23376888252Smrg int tileNumber; 23476888252Smrg 23576888252Smrg filledOutTileLines = videoRam / (tilesPerLine * 2); /* tiles are 2K */ 23676888252Smrg leftoverMem = videoRam - filledOutTileLines*tilesPerLine*2; 23776888252Smrg 23876888252Smrg if (leftoverMem > 0) { 23976888252Smrg yTile = filledOutTileLines; 24076888252Smrg } else { 24176888252Smrg /* There is no incomplete row of tiles. Then just use the last 24276888252Smrg tile in the last line */ 24376888252Smrg yTile = filledOutTileLines - 1; 24476888252Smrg } 24576888252Smrg xTile = 0; /* Always use the first tile in the determined tile row */ 24676888252Smrg 24776888252Smrg /* The (x,y) coords of the pointer image. */ 24876888252Smrg if (x) 24976888252Smrg *x = xTile * tileWidth; 25076888252Smrg if (y) 25176888252Smrg *y = yTile * tileHeight; 25276888252Smrg 25376888252Smrg if (width) 25476888252Smrg *width = tileWidth; 25576888252Smrg if (height) 25676888252Smrg *height = tileHeight / 2; 25776888252Smrg 25876888252Smrg /* Now, compute the linear address of the cursor image. This process 25976888252Smrg is unpleasant because the memory is tiled, and we essetially have 26076888252Smrg to undo the tiling computation. */ 26176888252Smrg if (curAddr) { 26276888252Smrg unsigned int nIL; /* Interleaving */ 26376888252Smrg nIL = pLg->memInterleave==0x00? 1 : (pLg->memInterleave==0x40 ? 2 : 4); 26476888252Smrg 26576888252Smrg if (PCI_CHIP_GD5465 == pCir->Chipset) { 26676888252Smrg /* The Where's The Cursor formula changed for the 5465. It's really 2670814a2baSmrg kinda weird now. */ 26876888252Smrg unsigned long page, bank; 26976888252Smrg unsigned int nX, nY; 27076888252Smrg 27176888252Smrg nX = xTile * tileWidth; 27276888252Smrg nY = yTile * tileHeight; 27376888252Smrg 27476888252Smrg page = (nY / (tileHeight * nIL)) * tilesPerLine + nX / tileWidth; 27576888252Smrg bank = (nX/tileWidth + nY/tileHeight) % nIL + page/(512*nIL); 27676888252Smrg page = page & 0x1FF; 27776888252Smrg *curAddr = bank*1024*1024L + page*2048 + (nY%tileHeight)*tileWidth; 27876888252Smrg } else { 27976888252Smrg tileNumber = (tilesPerLine*nIL) * (yTile/nIL) + yTile % nIL; 28076888252Smrg *curAddr = tileNumber * 2048; 28176888252Smrg } 28276888252Smrg } 28376888252Smrg} 28476888252Smrg 28576888252Smrg 28676888252Smrg 28776888252Smrg 28876888252Smrg/* 28976888252Smrg * Hide/disable the HW cursor. 29076888252Smrg */ 29176888252Smrgvoid LgHideCursor(ScrnInfoPtr pScrn) 29276888252Smrg{ 29376888252Smrg const CirPtr pCir = CIRPTR(pScrn); 29476888252Smrg 29576888252Smrg /* To hide the cursor, we kick it off into the corner, and then set the 29676888252Smrg cursor image to be a transparent bitmap. That way, if X continues 29776888252Smrg to move the cursor while it is hidden, there is no way that the user 29876888252Smrg can move the cursor back on screen! 29976888252Smrg 30076888252Smrg We don't just clear the cursor enable bit because doesn't work in some 30176888252Smrg cases (like when switching back to text mode). 30276888252Smrg */ 30376888252Smrg 30476888252Smrg#ifdef LG_CURSOR_DEBUG 30576888252Smrg ErrorF("LgHideCursor\n"); 30676888252Smrg#endif 30776888252Smrg 30876888252Smrg memww(CURSOR_CONTROL, (memrw(CURSOR_CONTROL) & 0xFFFE)); 30976888252Smrg} 31076888252Smrg 31176888252Smrgvoid LgShowCursor(ScrnInfoPtr pScrn) 31276888252Smrg{ 31376888252Smrg const CirPtr pCir = CIRPTR(pScrn); 31476888252Smrg const LgPtr pLg = LGPTR(pCir); 31576888252Smrg 31676888252Smrg#ifdef LG_CURSOR_DEBUG 31776888252Smrg ErrorF("LgShowCursor\n"); 31876888252Smrg#endif 31976888252Smrg 32076888252Smrg memww(CURSOR_CONTROL,(memrw(CURSOR_CONTROL) | (1<<0))); 32176888252Smrg memww(CURSOR_ADDR,(pLg->HWCursorAddr & 0x7FFC)); 32276888252Smrg} 32376888252Smrg 32476888252Smrg 32576888252Smrg/* 32676888252Smrg * Can the HW cursor be used? 32776888252Smrg */ 32876888252Smrgstatic Bool LgUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) 32976888252Smrg{ 33063847c39Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 33176888252Smrg 33276888252Smrg#ifdef LG_CURSOR_DEBUG 33376888252Smrg ErrorF("LgUseHWCursor\n"); 33476888252Smrg#endif 33576888252Smrg 33676888252Smrg if(pScrn->bitsPerPixel < 8) 33776888252Smrg return FALSE; 33876888252Smrg 33976888252Smrg return TRUE; 34076888252Smrg} 34176888252Smrg 34276888252Smrg 34376888252Smrg/* 34476888252Smrg * Initialize all the fun HW cursor code. 34576888252Smrg */ 34676888252SmrgBool LgHWCursorInit(ScreenPtr pScreen) 34776888252Smrg{ 34863847c39Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 34976888252Smrg CirPtr pCir = CIRPTR(pScrn); 35076888252Smrg xf86CursorInfoPtr infoPtr; 35176888252Smrg 35276888252Smrg#ifdef LG_CURSOR_DEBUG 35376888252Smrg ErrorF("LgHWCursorInit\n"); 35476888252Smrg#endif 35576888252Smrg 35676888252Smrg infoPtr = xf86CreateCursorInfoRec(); 35776888252Smrg if(!infoPtr) return FALSE; 35876888252Smrg 35976888252Smrg pCir->CursorInfoRec = infoPtr; 36076888252Smrg LgFindCursorTile(pScrn, &pCir->chip.lg->HWCursorImageX, &pCir->chip.lg->HWCursorImageY, 36176888252Smrg &pCir->chip.lg->HWCursorTileWidth, &pCir->chip.lg->HWCursorTileHeight, 36276888252Smrg &pCir->chip.lg->HWCursorAddr); 36376888252Smrg /* Keep only bits 22:10 of the address. */ 36476888252Smrg pCir->chip.lg->HWCursorAddr = (pCir->chip.lg->HWCursorAddr >> 8) & 0x7FFC; 36576888252Smrg 36676888252Smrg pCir->CursorIsSkewed = FALSE; 36776888252Smrg 36876888252Smrg infoPtr->MaxWidth = CURSORWIDTH; 36976888252Smrg infoPtr->MaxHeight = CURSORHEIGHT; 37076888252Smrg infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP 37176888252Smrg | HARDWARE_CURSOR_AND_SOURCE_WITH_MASK 37276888252Smrg | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64; 37376888252Smrg infoPtr->SetCursorColors = LgSetCursorColors; 37476888252Smrg infoPtr->SetCursorPosition = LgSetCursorPosition; 37576888252Smrg infoPtr->LoadCursorImage = LgLoadCursorImage; 37676888252Smrg infoPtr->HideCursor = LgHideCursor; 37776888252Smrg infoPtr->ShowCursor = LgShowCursor; 37876888252Smrg infoPtr->UseHWCursor = LgUseHWCursor; 37976888252Smrg 38076888252Smrg#ifdef LG_CURSOR_DEBUG 38176888252Smrg ErrorF("LgHWCursorInit before xf86InitCursor\n"); 38276888252Smrg#endif 38376888252Smrg 38476888252Smrg return(xf86InitCursor(pScreen, infoPtr)); 38576888252Smrg} 386