/*****************************************************************************/
/* Copyright (c) 2008 NXP B.V.                                               */
/*                                                                           */
/* This library is free software; you can redistribute it and/or             */
/* modify it under the terms of the GNU Lesser General Public                */
/* License as published by the Free Software Foundation, using               */
/* version 2.1 of the License.                                               */
/*                                                                           */
/* This library is distributed in the hope that it will be useful,           */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU          */
/* Lesser General Public License for more details.                           */
/*                                                                           */
/* You should have received a copy of the GNU Lesser General Public          */
/* License along with this library; if not, write to the Free Software       */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA   */
/*                                                                           */
/*****************************************************************************/
/*
   NXP STB22X Driver

   Code is derived from TI Davinci driver.

   TI Davinci driver

   (c) Copyright 2007  Telio AG

   Written by Denis Oliver Kropp <dok@directfb.org>

   Code is derived from VMWare driver.

   (c) Copyright 2001-2007  The DirectFB Organization (directfb.org)
   (c) Copyright 2000-2004  Convergence (integrated media) GmbH

   All rights reserved.

   Written by Denis Oliver Kropp <dok@directfb.org>,
              Andreas Hundt <andi@fischlustig.de>,
              Sven Neumann <neo@directfb.org>,
              Ville Syrjälä <syrjala@sci.fi> and
              Claudio Ciccani <klan@users.sf.net>.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*//**
    @file   phStbDFB_gfx_pool.c
    @brief  Implemetation of Surface Pool for Graphics Layers.

@b  Component:  phStbDFB.

*//*

Rev Date        Author      Comments
--------------------------------------------------------------------------------
  1 20080103    laird       New version for DirectFB 1.1.1
  2 20080716    laird       Rework.
  3 20080716    laird       Adding support for video layers.
  4 20080902    laird       Updating debug prints
  5 20080904    neill/laird Add support for multiple framebuffers
  6 20080905    laird       Change Debug Domain names.
  7 20080905    neill       Fix problems with single framebuffers
  8 20080908    neill       Simplify phStbDFB_GfxLock
  9 20080917    laird       GFX_POOL priority now needs to be PREFERRED - it means it
                            is preferred to devmem for surfaces.
 10 20081014    batelaan    Use ansi structure initialiser syntax
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

/***********************************************
* INCLUDE FILES                                *
************************************************/
#include "phStbDFB_internal.h"

/***********************************************
* LOCAL MACROS                                 *
* recommendation only: <MODULE><_WORD>+        *
************************************************/

/******************************************************************
* LOCAL TYPEDEFS                                                  *
* recommendation only:                [p]phStbTemplate_<Word>+_t  *
*******************************************************************/
D_DEBUG_DOMAIN( phStbDFB_Gfx_Surfaces, "NXP/STB22X/GSurf", "GFX Framebuffer Surface Pool" );
D_DEBUG_DOMAIN( phStbDFB_Gfx_SurfLock, "NXP/STB22X/GLock", "GFX Framebuffer Surface Pool Locks" );

typedef struct {
     int             magic;
} StbDFB_GfxPoolData_t;

typedef struct {
     int             magic;

     CoreDFB        *core;
     void           *mem[2];
     unsigned long   phys[2];
} StbDFB_GfxPoolLocalData_t;

typedef struct {
     int   magic;

     int   fb_id;
     int   offset;
     int   pitch;
     int   size;
} StbDFB_GfxAllocationData_t;

/******************************************************************
* STATIC FUNCTION PROTOTYPES                  <Module>_<Word>+    *
*******************************************************************/

/******************************************************************
* STATIC DATA                  g[k|p|kp|pk|kpk]<Module>_<Word>+   *
*******************************************************************/

/**************************************************************************
* EXPORTED DATA                     g[k|p|kp|pk|kpk]phStbTemplate_<Word>+ *
***************************************************************************/

/*******************************************************************************
* FUNCTION IMPLEMENTATION  <Module>[_<Word>+] for static functions             *
*                          tm[<screen>]<Module>[_<Word>+] for exported functions*
********************************************************************************/

/**********************************************************************************************************************/
static int
phStbDFB_GfxPoolDataSize()
{
     return sizeof(StbDFB_GfxPoolData_t);
}

/**********************************************************************************************************************/
static int
phStbDFB_GfxPoolLocalDataSize()
{
     return sizeof(StbDFB_GfxPoolLocalData_t);
}

/**********************************************************************************************************************/
static int
phStbDFB_GfxAllocationDataSize()
{
     return sizeof(StbDFB_GfxAllocationData_t);
}

/**********************************************************************************************************************/
static DFBResult
phStbDFB_GfxInitPool( CoreDFB                    *core,
                      CoreSurfacePool            *pool,
                      void                       *pool_data,
                      void                       *pool_local,
                      void                       *system_data,
                      CoreSurfacePoolDescription *ret_desc )
{
     StbDFB_GfxPoolData_t       *data  = pool_data;
     StbDFB_GfxPoolLocalData_t  *local = pool_local;
     phStbDFB_DriverData_t *pdrv = dfb_gfxcard_get_driver_data();
     phStbDFB_DeviceData_t *pdev = dfb_gfxcard_get_device_data();

     D_DEBUG_ENTER( phStbDFB_Gfx_Surfaces, " pool->pool_id=%d", pool->pool_id);

     D_ASSERT( core != NULL );
     D_MAGIC_ASSERT( pool, CoreSurfacePool );
     D_ASSERT( data != NULL );
     D_ASSERT( local != NULL );
     D_ASSERT( ret_desc != NULL );

     ret_desc->caps     = CSPCAPS_NONE;
     ret_desc->access   = CSAF_CPU_READ | CSAF_CPU_WRITE | CSAF_GPU_READ | CSAF_GPU_WRITE | CSAF_SHARED;
     ret_desc->types    = CSTF_LAYER | CSTF_SHARED | CSTF_EXTERNAL;
     ret_desc->priority = CSPP_PREFERED;

     snprintf( ret_desc->name, DFB_SURFACE_POOL_DESC_NAME_LENGTH, "GFX Pool" );

     local->core = core;
     local->mem[0]  = pdrv->fb[PH_STBDFB_SCREEN_MAIN_GRAPHICS1].mem;
     local->phys[0] = pdev->fix[PH_STBDFB_SCREEN_MAIN_GRAPHICS1].smem_start;
     D_DEBUG_AT( phStbDFB_Gfx_Surfaces, " -> fb0->mem=%p fb0->phys=%p\n",
                 local->mem[0],
                 local->phys[0]);

     local->mem[1]  = pdrv->fb[PH_STBDFB_SCREEN_MAIN_GRAPHICS2].mem;
     local->phys[1] = pdev->fix[PH_STBDFB_SCREEN_MAIN_GRAPHICS2].smem_start;
     D_DEBUG_AT( phStbDFB_Gfx_Surfaces, " -> fb1->mem=%p fb1->phys=%p\n",
                 local->mem[1],
                 local->phys[1]);

     D_MAGIC_SET( data, StbDFB_GfxPoolData_t );
     D_MAGIC_SET( local, StbDFB_GfxPoolLocalData_t );

     D_DEBUG_EXIT( phStbDFB_Gfx_Surfaces, "" );
     return DFB_OK;
}

/**********************************************************************************************************************/
static DFBResult
phStbDFB_GfxJoinPool( CoreDFB         *core,
                      CoreSurfacePool *pool,
                      void            *pool_data,
                      void            *pool_local,
                      void            *system_data )
{
     StbDFB_GfxPoolData_t       *data  = pool_data;
     StbDFB_GfxPoolLocalData_t  *local = pool_local;
     phStbDFB_DriverData_t *pdrv  = dfb_gfxcard_get_driver_data();
     phStbDFB_DeviceData_t *pdev  = dfb_gfxcard_get_device_data();

     D_DEBUG_ENTER( phStbDFB_Gfx_Surfaces, "" );

     D_ASSERT( core != NULL );
     D_MAGIC_ASSERT( pool, CoreSurfacePool );
     D_MAGIC_ASSERT( data, StbDFB_GfxPoolData_t );
     D_ASSERT( local != NULL );

     (void) data;

     local->core = core;
     local->mem[0]  = pdrv->fb[PH_STBDFB_SCREEN_MAIN_GRAPHICS1].mem;
     local->phys[0] = pdev->fix[PH_STBDFB_SCREEN_MAIN_GRAPHICS1].smem_start;
     D_DEBUG_AT( phStbDFB_Gfx_Surfaces, " -> fb0->mem=%p fb0->phys=%p\n",
                 local->mem[0],
                 local->phys[0]);

     local->mem[1]  = pdrv->fb[PH_STBDFB_SCREEN_MAIN_GRAPHICS2].mem;
     local->phys[1] = pdev->fix[PH_STBDFB_SCREEN_MAIN_GRAPHICS2].smem_start;
     D_DEBUG_AT( phStbDFB_Gfx_Surfaces, " -> fb1->mem=%p fb1->phys=%p\n",
                 local->mem[1],
                 local->phys[1]);

     D_MAGIC_SET( local, StbDFB_GfxPoolLocalData_t );

     D_DEBUG_EXIT( phStbDFB_Gfx_Surfaces, "" );
     return DFB_OK;
}

/**********************************************************************************************************************/
static DFBResult
phStbDFB_GfxDestroyPool( CoreSurfacePool *pool,
                         void            *pool_data,
                         void            *pool_local )
{
     StbDFB_GfxPoolData_t      *data  = pool_data;
     StbDFB_GfxPoolLocalData_t *local = pool_local;

     D_DEBUG_ENTER( phStbDFB_Gfx_Surfaces, "" );

     D_MAGIC_ASSERT( pool, CoreSurfacePool );
     D_MAGIC_ASSERT( data, StbDFB_GfxPoolData_t );
     D_MAGIC_ASSERT( local, StbDFB_GfxPoolLocalData_t );

     D_MAGIC_CLEAR( data );
     D_MAGIC_CLEAR( local );

     D_DEBUG_EXIT( phStbDFB_Gfx_Surfaces, "" );
     return DFB_OK;
}

/**********************************************************************************************************************/
static DFBResult
phStbDFB_GfxLeavePool( CoreSurfacePool *pool,
                       void            *pool_data,
                       void            *pool_local )
{
     StbDFB_GfxPoolData_t      *data  = pool_data;
     StbDFB_GfxPoolLocalData_t *local = pool_local;

     D_DEBUG_ENTER( phStbDFB_Gfx_Surfaces, "" );

     D_MAGIC_ASSERT( pool, CoreSurfacePool );
     D_MAGIC_ASSERT( data, StbDFB_GfxPoolData_t );
     D_MAGIC_ASSERT( local, StbDFB_GfxPoolLocalData_t );

     (void) data;

     D_MAGIC_CLEAR( local );

     D_DEBUG_EXIT( phStbDFB_Gfx_Surfaces, "" );
     return DFB_OK;
}

/**********************************************************************************************************************/
static DFBResult
phStbDFB_GfxTestConfig( CoreSurfacePool         *pool,
                        void                    *pool_data,
                        void                    *pool_local,
                        CoreSurfaceBuffer       *buffer,
                        const CoreSurfaceConfig *config )
{
     CoreSurface      *surface;
     StbDFB_GfxPoolData_t      *data  = pool_data;
     StbDFB_GfxPoolLocalData_t *local = pool_local;
     phStbDFB_DriverData_t *pdrv  = dfb_gfxcard_get_driver_data();

     D_DEBUG_ENTER( phStbDFB_Gfx_Surfaces, " buffer ( %p )", buffer );

     D_MAGIC_ASSERT( pool, CoreSurfacePool );
     D_MAGIC_ASSERT( data, StbDFB_GfxPoolData_t );
     D_MAGIC_ASSERT( local, StbDFB_GfxPoolLocalData_t );
     D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );

     (void) data;
     (void) local;

     surface = buffer->surface;
     D_MAGIC_ASSERT( surface, CoreSurface );

     if ((surface->type & CSTF_LAYER) &&
         ((surface->resource_id == pdrv->resource_id[PH_STBDFB_SCREEN_MAIN_GRAPHICS1])||
          (surface->resource_id == pdrv->resource_id[PH_STBDFB_SCREEN_MAIN_GRAPHICS2])))
     {
         D_DEBUG_EXIT( phStbDFB_Gfx_Surfaces, " Surface can be allocated" );
         return DFB_OK;
     }

     D_DEBUG_EXIT( phStbDFB_Gfx_Surfaces, " Surface cannot be allocated" );
     return DFB_UNSUPPORTED;
}

/**********************************************************************************************************************/
static DFBResult
phStbDFB_GfxAllocateBuffer( CoreSurfacePool       *pool,
                            void                  *pool_data,
                            void                  *pool_local,
                            CoreSurfaceBuffer     *buffer,
                            CoreSurfaceAllocation *allocation,
                            void                  *alloc_data )
{
     CoreSurface       *surface;
     StbDFB_GfxPoolData_t       *data  = pool_data;
     StbDFB_GfxPoolLocalData_t  *local = pool_local;
     StbDFB_GfxAllocationData_t *alloc = alloc_data;
     phStbDFB_DeviceData_t *pdev  = dfb_gfxcard_get_device_data();
     phStbDFB_DriverData_t *pdrv  = dfb_gfxcard_get_driver_data();

     D_DEBUG_ENTER( phStbDFB_Gfx_Surfaces, " buffer ( %p )", buffer );

     D_MAGIC_ASSERT( pool, CoreSurfacePool );
     D_MAGIC_ASSERT( data, StbDFB_GfxPoolData_t );
     D_MAGIC_ASSERT( local, StbDFB_GfxPoolLocalData_t );
     D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );

     (void) data;
     (void) local;

     surface = buffer->surface;
     D_MAGIC_ASSERT( surface, CoreSurface );

     if ((surface->type & CSTF_LAYER) &&
         ((surface->resource_id == pdrv->resource_id[PH_STBDFB_SCREEN_MAIN_GRAPHICS1]) ||
          (surface->resource_id == pdrv->resource_id[PH_STBDFB_SCREEN_MAIN_GRAPHICS2])))
     {
          int index = dfb_surface_buffer_index( buffer );

          alloc->pitch  = pdev->fix[surface->resource_id].line_length;
          alloc->size   = pdev->var[surface->resource_id].yres * alloc->pitch;
          alloc->offset = index * alloc->size;
          alloc->fb_id  = surface->resource_id;

          D_DEBUG_AT( phStbDFB_Gfx_Surfaces, " -> index is %d: offset %d, pitch %d, size %d\n",
                      index,
                      alloc->offset,
                      alloc->pitch,
                      alloc->size );

          allocation->size   = alloc->size;
          allocation->offset = alloc->offset;

          D_MAGIC_SET( alloc, StbDFB_GfxAllocationData_t );

          return DFB_OK;
     }

     D_DEBUG_EXIT( phStbDFB_Gfx_Surfaces, "" );
     return DFB_BUG;
}

/**********************************************************************************************************************/
static DFBResult
phStbDFB_GfxDeallocateBuffer( CoreSurfacePool       *pool,
                              void                  *pool_data,
                              void                  *pool_local,
                              CoreSurfaceBuffer     *buffer,
                              CoreSurfaceAllocation *allocation,
                              void                  *alloc_data )
{
     StbDFB_GfxPoolData_t       *data  = pool_data;
     StbDFB_GfxAllocationData_t *alloc = alloc_data;
     CoreSurface       *surface;
     phStbDFB_DriverData_t *pdrv  = dfb_gfxcard_get_driver_data();

     D_DEBUG_ENTER( phStbDFB_Gfx_Surfaces, " buffer ( %p )", buffer );

     D_MAGIC_ASSERT( pool, CoreSurfacePool );
     D_MAGIC_ASSERT( data, StbDFB_GfxPoolData_t );
     D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );
     D_MAGIC_ASSERT( alloc, StbDFB_GfxAllocationData_t );

     surface = buffer->surface;
     D_MAGIC_ASSERT( surface, CoreSurface );

     if ((surface->type & CSTF_LAYER) &&
         ((surface->resource_id == pdrv->resource_id[PH_STBDFB_SCREEN_MAIN_GRAPHICS1]) ||
          (surface->resource_id == pdrv->resource_id[PH_STBDFB_SCREEN_MAIN_GRAPHICS2])))
     {
         (void) data;

         D_MAGIC_CLEAR( alloc );
     }

     D_DEBUG_EXIT( phStbDFB_Gfx_Surfaces, "" );
     return DFB_OK;
}

/**********************************************************************************************************************/
static DFBResult
phStbDFB_GfxLock( CoreSurfacePool       *pool,
                  void                  *pool_data,
                  void                  *pool_local,
                  CoreSurfaceAllocation *allocation,
                  void                  *alloc_data,
                  CoreSurfaceBufferLock *lock )
{
     StbDFB_GfxPoolLocalData_t  *local = pool_local;
     StbDFB_GfxAllocationData_t *alloc = alloc_data;

     D_MAGIC_ASSERT( pool, CoreSurfacePool );
     D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation );
     D_MAGIC_ASSERT( alloc, StbDFB_GfxAllocationData_t );
     D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock );

     D_DEBUG_ENTER( phStbDFB_Gfx_SurfLock, " lock->buffer ( %p ) alloc->fb_id=%d", lock->buffer, alloc->fb_id );

     allocation->size   = alloc->size;
     allocation->offset = alloc->offset;

     lock->pitch  = alloc->pitch;
     lock->offset = alloc->offset;
     lock->addr   = local->mem[alloc->fb_id]  + alloc->offset;
     lock->phys   = local->phys[alloc->fb_id] + alloc->offset;

     D_DEBUG_AT( phStbDFB_Gfx_SurfLock, " -> offset %lu, pitch %d, addr %p, phys 0x%08lx\n",
                 lock->offset, lock->pitch, lock->addr, lock->phys );

     D_DEBUG_EXIT( phStbDFB_Gfx_SurfLock, "" );
     return DFB_OK;
}

/**********************************************************************************************************************/
static DFBResult
phStbDFB_GfxUnlock( CoreSurfacePool       *pool,
                    void                  *pool_data,
                    void                  *pool_local,
                    CoreSurfaceAllocation *allocation,
                    void                  *alloc_data,
                    CoreSurfaceBufferLock *lock )
{
     StbDFB_GfxAllocationData_t *alloc = alloc_data;

     D_MAGIC_ASSERT( pool, CoreSurfacePool );
     D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation );
     D_MAGIC_ASSERT( alloc, StbDFB_GfxAllocationData_t );
     D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock );

     D_DEBUG_ENTER( phStbDFB_Gfx_SurfLock, " lock->buffer ( %p )", lock->buffer );

     (void) alloc;

     D_DEBUG_EXIT( phStbDFB_Gfx_SurfLock, "" );
     return DFB_OK;
}

/**********************************************************************************************************************/
const SurfacePoolFuncs phStbDFB_Gfx_SurfacePoolFuncs = {
     .PoolDataSize =       phStbDFB_GfxPoolDataSize,
     .PoolLocalDataSize =  phStbDFB_GfxPoolLocalDataSize,
     .AllocationDataSize = phStbDFB_GfxAllocationDataSize,

     .InitPool =           phStbDFB_GfxInitPool,
     .JoinPool =           phStbDFB_GfxJoinPool,
     .DestroyPool =        phStbDFB_GfxDestroyPool,
     .LeavePool =          phStbDFB_GfxLeavePool,

     .TestConfig =         phStbDFB_GfxTestConfig,
     .AllocateBuffer =     phStbDFB_GfxAllocateBuffer,
     .DeallocateBuffer =   phStbDFB_GfxDeallocateBuffer,

     .Lock =               phStbDFB_GfxLock,
     .Unlock =             phStbDFB_GfxUnlock
};

