/*
 * $Workfile: amd_lx_dga.c $
 * $Revision: #3 $
 * $Author: raymondd $
 * 
 * File contents: DGA(Direct Acess Graphics mode) is feature of
 *                XFree86 that allows the program to access directly to video
 *                memory on the graphics card.DGA supports the double
 *                flickering.This file has the functions to support the DGA
 *                modes.
 *
 * Project:       Geode Xfree Frame buffer device driver.
 *
 */

/* <LIC_AMD_STD>
 * Copyright (c) 2003-2005 Advanced Micro Devices, Inc.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to 
 * deal in the Software without restriction, including without limitation the 
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 
 * sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *  
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software.
 *  
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
 * IN THE SOFTWARE.
 * 
 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 * </LIC_AMD_STD>  */
/* <CTL_AMD_STD>
 * </CTL_AMD_STD>  */
/* <DOC_AMD_STD>
 * </DOC_AMD_STD>  */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "xf86.h"
#include "xf86_OSproc.h"
#include "xf86_ansic.h"
#include "xf86Pci.h"
#include "xf86PciInfo.h"
#include "xaa.h"
#include "xaalocal.h"
#include "nsc.h"
#include "dgaproc.h"

/* forward declarations */
Bool LXDGAInit(ScreenPtr pScrn);
static Bool LX_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **,
				int *, int *, int *);
static void LX_CloseFramebuffer(ScrnInfoPtr pScrni);
static Bool LX_SetMode(ScrnInfoPtr, DGAModePtr);
static int LX_GetViewport(ScrnInfoPtr);
static void LX_SetViewport(ScrnInfoPtr, int, int, int);
static void LX_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long);
static void LX_BlitRect(ScrnInfoPtr, int, int, int, int, int, int);

extern void LXAdjustFrame(int, int, int, int);
extern Bool LXSwitchMode(int, DisplayModePtr, int);
extern void LXAccelSync(ScrnInfoPtr pScrni);

static DGAFunctionRec LXDGAFuncs = {
   LX_OpenFramebuffer,
   LX_CloseFramebuffer,
   LX_SetMode,
   LX_SetViewport,
   LX_GetViewport,
   LXAccelSync,
   LX_FillRect,
   LX_BlitRect,
   NULL
};

/*----------------------------------------------------------------------------
 * LXDGAInit.
 *
 * Description	:This function is used to intiallize the DGA modes and sets the
			 	 viewport based on the screen mode.
 * Parameters.
 *	pScreeen	:Pointer to screen info structure.
 *
 * Returns		:TRUE on success and FALSE on failure.
 *
 * Comments		:This function prepares the DGA mode settings for
 *				 other func reference.
 *
*----------------------------------------------------------------------------
*/
Bool
LXDGAInit(ScreenPtr pScrn)
{
   ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum];
   GeodePtr pGeode = GEODEPTR(pScrni);
   DGAModePtr modes = NULL, newmodes = NULL, currentMode;
   DisplayModePtr pMode, firstMode;
   int Bpp = pScrni->bitsPerPixel >> 3;
   int num = 0;
   Bool oneMore;

   pMode = firstMode = pScrni->modes;
   DEBUGMSG(0, (0, X_NONE, "LXDGAInit %d\n", Bpp));
   while (pMode) {

      /* redundant but it can be used in future:if(0). */
      if (0) {				/*pScrni->displayWidth != pMode->HDisplay */
	 /* memory is allocated for dga to
	  *setup the viewport and mode parameters
	  */
	 newmodes = xrealloc(modes, (num + 2) * sizeof(DGAModeRec));
	 oneMore = TRUE;
      } else {
	 /* one record is allocated here */
	 newmodes = xrealloc(modes, (num + 1) * sizeof(DGAModeRec));
	 oneMore = FALSE;
      }
      if (!newmodes) {
	 xfree(modes);
	 return FALSE;
      }
      modes = newmodes;

    SECOND_PASS:			/* DGA mode flgas and viewport parametrs are set here. */

      currentMode = modes + num;
      num++;
      currentMode->mode = pMode;
      currentMode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE;
      currentMode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT;
      if (pMode->Flags & V_DBLSCAN)
	 currentMode->flags |= DGA_DOUBLESCAN;
      if (pMode->Flags & V_INTERLACE)
	 currentMode->flags |= DGA_INTERLACED;
      currentMode->byteOrder = pScrni->imageByteOrder;
      currentMode->depth = pScrni->depth;
      currentMode->bitsPerPixel = pScrni->bitsPerPixel;
      currentMode->red_mask = pScrni->mask.red;
      currentMode->green_mask = pScrni->mask.green;
      currentMode->blue_mask = pScrni->mask.blue;
      currentMode->visualClass = (Bpp == 1) ? PseudoColor : TrueColor;
      currentMode->viewportWidth = pMode->HDisplay;
      currentMode->viewportHeight = pMode->VDisplay;
      currentMode->xViewportStep = 1;
      currentMode->yViewportStep = 1;
      currentMode->viewportFlags = DGA_FLIP_RETRACE;
      currentMode->offset = 0;
      currentMode->address = pGeode->FBBase;
      if (oneMore) {			/* first one is narrow width */
	 currentMode->bytesPerScanline = ((pMode->HDisplay * Bpp) + 3) & ~3L;
	 currentMode->imageWidth = pMode->HDisplay;
	 currentMode->imageHeight = pMode->VDisplay;
	 currentMode->pixmapWidth = currentMode->imageWidth;
	 currentMode->pixmapHeight = currentMode->imageHeight;
	 currentMode->maxViewportX = currentMode->imageWidth -
	       currentMode->viewportWidth;
	 /* this might need to get clamped to some maximum */
	 currentMode->maxViewportY = currentMode->imageHeight -
	       currentMode->viewportHeight;
	 oneMore = FALSE;
	 goto SECOND_PASS;
      } else {
	 currentMode->bytesPerScanline =
	       ((pScrni->displayWidth * Bpp) + 3) & ~3L;
	 currentMode->imageWidth = pScrni->displayWidth;
	 currentMode->imageHeight = pMode->VDisplay;
	 currentMode->pixmapWidth = currentMode->imageWidth;
	 currentMode->pixmapHeight = currentMode->imageHeight;
	 currentMode->maxViewportX = currentMode->imageWidth -
	       currentMode->viewportWidth;
	 /* this might need to get clamped to some maximum */
	 currentMode->maxViewportY = currentMode->imageHeight -
	       currentMode->viewportHeight;
      }
      pMode = pMode->next;
      if (pMode == firstMode)
	 break;
   }
   pGeode->numDGAModes = num;
   pGeode->DGAModes = modes;
   return DGAInit(pScrn, &LXDGAFuncs, modes, num);
}

/*----------------------------------------------------------------------------
 * LX_SetMode.
 *
 * Description	:This function is sets into the DGA mode.
 *.
 * Parameters.
 *	pScreeen	:Pointer to screen info structure.
 *	pMode		:Points to the DGAmode ptr data
 * Returns		:TRUE on success and FALSE on failure.
 *
 * Comments		:none.
 *			
 *
*----------------------------------------------------------------------------
*/
static Bool
LX_SetMode(ScrnInfoPtr pScrni, DGAModePtr pMode)
{
   static int OldDisplayWidth[MAXSCREENS];
   int index = pScrni->pScreen->myNum;
   GeodePtr pGeode = GEODEPTR(pScrni);

   DEBUGMSG(0, (0, X_NONE, "LX_SetMode\n"));

   if (!pMode) {
      /* restore the original mode
       * * put the ScreenParameters back
       */
      pScrni->displayWidth = OldDisplayWidth[index];
      DEBUGMSG(0,
	       (0, X_NONE, "LX_SetMode !pMode %d\n", pScrni->displayWidth));
      LXSwitchMode(index, pScrni->currentMode, 0);
      pGeode->DGAactive = FALSE;
   } else {
      if (!pGeode->DGAactive) {		/* save the old parameters */
	 OldDisplayWidth[index] = pScrni->displayWidth;
	 pGeode->DGAactive = TRUE;
	 DEBUGMSG(0,
		  (0, X_NONE, "LX_SetMode pMode+ NA %d\n",
		   pScrni->displayWidth));
      }
      pGeode->PrevDisplayOffset = vg_get_display_offset();

      pScrni->displayWidth = pMode->bytesPerScanline /
	    (pMode->bitsPerPixel >> 3);
      DEBUGMSG(0,
	       (0, X_NONE, "LX_SetMode pMode+  %d\n", pScrni->displayWidth));
      LXSwitchMode(index, pMode->mode, 0);
   }
   /* enable/disable Compression */
   if (pGeode->Compression) {
      vg_set_compression_enable(!pGeode->DGAactive);
   }

   /* enable/disable cursor */
   if (pGeode->HWCursor) {
      vg_set_cursor_enable(!pGeode->DGAactive);
   }

   return TRUE;
}

/*----------------------------------------------------------------------------
 * LX_GetViewPort.
 *
 * Description	:This function is Gets the viewport window memory.
 *.
 * Parameters.
 *	pScrni		:Pointer to screen info structure.
 *	
 * Returns		:returns the viewport status.
 *
 * Comments		:none.
 *			
 *
*----------------------------------------------------------------------------
*/
static int
LX_GetViewport(ScrnInfoPtr pScrni)
{
   GeodePtr pGeode = GEODEPTR(pScrni);

   return pGeode->DGAViewportStatus;
}

/*----------------------------------------------------------------------------
 * LX_SetViewPort.
 *
 * Description	:This function is Gets the viewport window memory.
 *
 * Parameters.
 *	pScrni		:Pointer to screen info structure.
		x		:x-cordinate of viewport window
 *		y		:y-codinate of the viewport window.
 *	flags		:indicates the viewport to be flipped or not.
 * Returns		:returns the viewport status  as zero.
 *
 * Comments		:none.
 *			
*----------------------------------------------------------------------------
*/
static void
LX_SetViewport(ScrnInfoPtr pScrni, int x, int y, int flags)
{
   GeodePtr pGeode = GEODEPTR(pScrni);

   LXAdjustFrame(pScrni->pScreen->myNum, x, y, flags);
   pGeode->DGAViewportStatus = 0;	/*LXAdjustFrame loops until finished */
}

/*----------------------------------------------------------------------------
 * LX_FillRect.
 *
 * Description	:This function is Gets the viewport window memory.
 *.
 * Parameters.
 *	pScrni		:Pointer to screen info structure.
 *		x		:x-cordinate of viewport window
 *		y		:y-codinate of the viewport window.
 *		w		:width of the rectangle
 *      h		:height of the rectangle.
 *	color		:color to be filled in rectangle.
 *
 * Returns		:returns the viewport status  as zero.
 *
 * Comments		:This function is implemented by solidfill routines..
 *			
*----------------------------------------------------------------------------
*/
static void
LX_FillRect(ScrnInfoPtr pScrni, int x, int y,
	     int w, int h, unsigned long color)
{
   GeodePtr pGeode = GEODEPTR(pScrni);

   if (pGeode->AccelInfoRec) {
      (*pGeode->AccelInfoRec->SetupForSolidFill) (pScrni, color, GXcopy, ~0);
      (*pGeode->AccelInfoRec->SubsequentSolidFillRect) (pScrni, x, y, w, h);
      SET_SYNC_FLAG(pGeode->AccelInfoRec);
   }
}

/*----------------------------------------------------------------------------
 * LX_BlitRect.
 *
 * Description	:This function implementing Blit and it moves a
 *			 	 Rectangular block of data from one location to other
 *			 	 Location.
 *
 * Parameters.
 *	pScrni		:Pointer to screen info structure.
 *	srcx		:x-cordinate of the src rectangle
 *	srcy		:y-codinate of src rectangle.
 *	  w			:width of the rectangle
 *    h			:height of the rectangle.
 *	dstx		:x-cordinate of the dst rectangle.
 *	dsty		:y -coordinates of the dst rectangle.
 * Returns		:none.
 *
 * Comments		:none
 *			
*----------------------------------------------------------------------------
*/
static void
LX_BlitRect(ScrnInfoPtr pScrni,
	     int srcx, int srcy, int w, int h, int dstx, int dsty)
{
   GeodePtr pGeode = GEODEPTR(pScrni);

   if (pGeode->AccelInfoRec) {
      int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1;
      int ydir = (srcy < dsty) ? -1 : 1;

      (*pGeode->AccelInfoRec->SetupForScreenToScreenCopy)
	    (pScrni, xdir, ydir, GXcopy, ~0, -1);
      (*pGeode->AccelInfoRec->SubsequentScreenToScreenCopy) (pScrni, srcx,
							     srcy, dstx, dsty,
							     w, h);
      SET_SYNC_FLAG(pGeode->AccelInfoRec);
   }
}

/*----------------------------------------------------------------------------
 * LX_OpenFramebuffer.
 *
 * Description	:This function open the framebuffer driver for DGA.
 *			
 * Parameters.
 *	pScrni		:Pointer to screen info structure.
 *	srcx		:x-cordinate of the src rectangle
 *	srcy		:y-codinate of src rectangle.
 *		w		:width of the rectangle
 *    	h		:height of the rectangle.
 *	dstx		:x-cordinate of the dst rectangle.
 *	dsty		:y -coordinates of the dst rectangle.
 * Returns		:none.
 *
 * Comments		:none
 *			
*----------------------------------------------------------------------------
*/
static Bool
LX_OpenFramebuffer(ScrnInfoPtr pScrni,
		    char **name, unsigned char **mem,
		    int *size, int *offset, int *flags)
{
   GeodePtr pGeode = GEODEPTR(pScrni);

   *name = NULL;			/* no special device */
   *mem = (unsigned char *)pGeode->FBLinearAddr;
   *size = pGeode->FBAvail;
   *offset = 0;
   *flags = DGA_NEED_ROOT;
   return TRUE;
}

static void
LX_CloseFramebuffer(ScrnInfoPtr pScrni)
{
}

/* end of file */

