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