/*
   TI Davinci driver - Graphics Layer

   (c) Copyright 2007  Telio AG

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

   Code is derived from VMWare driver.

   (c) Copyright 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
   (c) Copyright 2000-2004  Convergence (integrated media) GmbH

   All rights reserved.

   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.
*/

//#define DIRECT_ENABLE_DEBUG

#include <config.h>

#include <asm/types.h>

#include <stdio.h>
#include <sys/ioctl.h>

#include <directfb.h>
#include <directfb_util.h>

#include <core/layers.h>
#include <core/surface.h>
#include <core/surface_buffer.h>

#include <gfx/convert.h>

#include <direct/memcpy.h>
#include <direct/messages.h>

#include "davincifb.h"

#include "davinci_gfxdriver.h"
#include "davinci_osd.h"


#define D_OSDERROR(x...) do {} while (0)


D_DEBUG_DOMAIN( Davinci_OSD, "Davinci/OSD", "TI Davinci OSD" );

/**********************************************************************************************************************/

static int
osdLayerDataSize( void )
{
     return sizeof(DavinciOSDLayerData);
}

static DFBResult
osdInitLayer( CoreLayer                  *layer,
              void                       *driver_data,
              void                       *layer_data,
              DFBDisplayLayerDescription *description,
              DFBDisplayLayerConfig      *config,
              DFBColorAdjustment         *adjustment )
{
     int                  ret;
     DavinciDriverData   *ddrv = driver_data;
     DavinciOSDLayerData *dosd = layer_data;

     D_DEBUG_AT( Davinci_OSD, "%s()\n", __FUNCTION__ );

     ret = ioctl( ddrv->fb[OSD0].fd, FBIOGET_VSCREENINFO, &dosd->var0 );
     if (ret) {
          D_PERROR( "Davinci/OSD: FBIOGET_VSCREENINFO (fb%d) failed!\n", OSD0 );
          return DFB_INIT;
     }

     ret = ioctl( ddrv->fb[OSD1].fd, FBIOGET_VSCREENINFO, &dosd->var1 );
     if (ret) {
          D_PERROR( "Davinci/OSD: FBIOGET_VSCREENINFO (fb%d) failed!\n", OSD1 );
          return DFB_INIT;
     }

     ret = ioctl( ddrv->fb[OSD0].fd, FBIO_ENABLE_DISABLE_WIN, 0 );
     if (ret)
          D_OSDERROR( "Davinci/OSD: FBIO_ENABLE_DISABLE_WIN (fb%d - %d)!\n", OSD0, 0 );

     ret = ioctl( ddrv->fb[OSD1].fd, FBIO_ENABLE_DISABLE_WIN, 0 );
     if (ret)
          D_OSDERROR( "Davinci/OSD: FBIO_ENABLE_DISABLE_WIN (fb%d - %d)!\n", OSD1, 0 );

     /* set capabilities and type */
     description->caps = DLCAPS_SURFACE | DLCAPS_ALPHACHANNEL | DLCAPS_OPACITY | DLCAPS_SCREEN_POSITION |
                         DLCAPS_SRC_COLORKEY;
     description->type = DLTF_GRAPHICS;

     /* set name */
     snprintf( description->name, DFB_DISPLAY_LAYER_DESC_NAME_LENGTH, "TI Davinci OSD" );

     /* fill out the default configuration */
     config->flags       = DLCONF_WIDTH       | DLCONF_HEIGHT |
                           DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE | DLCONF_OPTIONS;
     config->width       = 640;
     config->height      = 480;
     config->pixelformat = DSPF_RGB16;
     config->buffermode  = DLBM_FRONTONLY;
     config->options     = DLOP_ALPHACHANNEL;

     return DFB_OK;
}

static DFBResult
osdTestRegion( CoreLayer                  *layer,
               void                       *driver_data,
               void                       *layer_data,
               CoreLayerRegionConfig      *config,
               CoreLayerRegionConfigFlags *failed )
{
     CoreLayerRegionConfigFlags fail = 0;

     D_DEBUG_AT( Davinci_OSD, "%s()\n", __FUNCTION__ );

     if (config->options & ~DAVINCI_OSD_SUPPORTED_OPTIONS)
          fail |= CLRCF_OPTIONS;

     switch (config->format) {
          case DSPF_RGB444:
          case DSPF_RGB555:
          case DSPF_RGB16:
          case DSPF_RGB32:
          case DSPF_ARGB4444:
          case DSPF_ARGB1555:
          case DSPF_ARGB:
               break;

          default:
               fail |= CLRCF_FORMAT;
     }

     if (config->width  < 8 || config->width  > 1920)
          fail |= CLRCF_WIDTH;

     if (config->height < 8 || config->height > 1080)
          fail |= CLRCF_HEIGHT;

     if (config->dest.x < 0 || config->dest.y < 0)
          fail |= CLRCF_DEST;

     if (config->dest.x + config->dest.w > 1920)
          fail |= CLRCF_DEST;

     if (config->dest.y + config->dest.h > 1080)
          fail |= CLRCF_DEST;

     if (failed)
          *failed = fail;

     if (fail)
          return DFB_UNSUPPORTED;

     return DFB_OK;
}

static DFBResult
osdSetRegion( CoreLayer                  *layer,
              void                       *driver_data,
              void                       *layer_data,
              void                       *region_data,
              CoreLayerRegionConfig      *config,
              CoreLayerRegionConfigFlags  updated,
              CoreSurface                *surface,
              CorePalette                *palette,
              CoreSurfaceBufferLock      *lock )
{
     int                  ret;
     DavinciDriverData   *ddrv = driver_data;
     DavinciDeviceData   *ddev = ddrv->ddev;
     DavinciOSDLayerData *dosd = layer_data;

     D_DEBUG_AT( Davinci_OSD, "%s()\n", __FUNCTION__ );

     D_ASSERT( ddrv != NULL );
     D_ASSERT( ddev != NULL );
     D_ASSERT( dosd != NULL );

     ret = ioctl( ddrv->fb[OSD0].fd, FBIO_ENABLE_DISABLE_WIN, 0 );
     if (ret)
          D_OSDERROR( "Davinci/OSD: FBIO_ENABLE_DISABLE_WIN (fb%d - %d)!\n", OSD0, 0 );

     ret = ioctl( ddrv->fb[OSD1].fd, FBIO_ENABLE_DISABLE_WIN, 0 );
     if (ret)
          D_OSDERROR( "Davinci/OSD: FBIO_ENABLE_DISABLE_WIN (fb%d - %d)!\n", OSD1, 0 );

     ioctl( ddrv->fb[OSD0].fd, FBIO_WAITFORVSYNC );

     /* Update blend parameters? */
     if (updated & (CLRCF_OPTIONS | CLRCF_OPACITY | CLRCF_SRCKEY | CLRCF_FORMAT)) {
          vpbe_blink_option_t        blink = {0};
          vpbe_bitmap_blend_params_t blend = {0};

          D_DEBUG_AT( Davinci_OSD, "  -> %s\n", dfb_pixelformat_name( config->format ) );

          if (config->options & DLOP_SRC_COLORKEY) {
               blend.enable_colorkeying = 1;
               blend.colorkey           = dfb_color_to_pixel( DSPF_RGB16,
                                                              config->src_key.r,
                                                              config->src_key.g,
                                                              config->src_key.b );

               D_DEBUG_AT( Davinci_OSD, "  -> color key 0x%02x (%02x %02x %02x)\n",
                           blend.colorkey, config->src_key.r, config->src_key.g, config->src_key.b );
          }
          else if (config->options & DLOP_OPACITY) {
               blend.bf = config->opacity >> 5;

               D_DEBUG_AT( Davinci_OSD, "  -> opacity %d/7\n", blend.bf );
          }
          else
               blend.bf = 7;

          ret = ioctl( ddrv->fb[OSD0].fd, FBIO_SET_BITMAP_BLEND_FACTOR, &blend );
          if (ret)
               D_PERROR( "Davinci/OSD: FBIO_SET_BITMAP_BLEND_FACTOR (fb%d)!\n", OSD0 );

          if (config->options & DLOP_ALPHACHANNEL)
               dosd->alpha = DFB_PIXELFORMAT_HAS_ALPHA( config->format );
          else
               dosd->alpha = 0;

          D_DEBUG_AT( Davinci_OSD, "  -> %salpha channel\n", dosd->alpha ? "" : "no " );

          if (dosd->alpha) {
               if (ioctl( ddrv->fb[OSD0].fd, FBIO_ENABLE_DISABLE_ATTRIBUTE_WIN, dosd->alpha ))
                    D_OSDERROR( "Davinci/OSD: FBIO_ENABLE_DISABLE_ATTRIBUTE_WIN (fb%d - %d)!\n", OSD0, dosd->alpha );
          }

          if (ioctl( ddrv->fb[OSD1].fd, FBIO_SET_BLINK_INTERVAL, &blink ))
               D_OSDERROR( "Davinci/OSD: FBIO_SET_BLINK_INTERVAL (fb%d - disable)!\n", OSD1 );
     }

     /* Update size? */
     if (updated & (CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_BUFFERMODE)) {
          vpbe_window_position_t win_pos;

          D_DEBUG_AT( Davinci_OSD, "  -> %dx%d\n", config->width, config->height );

/*********************************** Start workaround ***********************************/
          win_pos.xpos = 0;
          win_pos.ypos = 0;

          ret = ioctl( ddrv->fb[OSD0].fd, FBIO_SETPOS, &win_pos );
          if (ret)
               D_OSDERROR( "Davinci/OSD: FBIO_SETPOS (fb%d - %d,%d) failed!\n", OSD0, win_pos.xpos, win_pos.ypos );

          ret = ioctl( ddrv->fb[OSD1].fd, FBIO_SETPOS, &win_pos );
          if (ret)
               D_OSDERROR( "Davinci/OSD: FBIO_SETPOS (fb%d - %d,%d) failed!\n", OSD1, win_pos.xpos, win_pos.ypos );

          updated |= CLRCF_DEST;

          dosd->var0.yoffset = dosd->var1.yoffset = 0;
/*********************************** End workaround ***********************************/

          /* Set width and height. */
          dosd->var0.xres = config->width;
          dosd->var0.yres = config->height;
          dosd->var1.xres = config->width;
          dosd->var1.yres = config->height;

          dosd->var0.yres_virtual = ddrv->fb[OSD0].size / ddev->fix[OSD0].line_length;

          ret = ioctl( ddrv->fb[OSD0].fd, FBIOPUT_VSCREENINFO, &dosd->var0 );
          if (ret)
               D_PERROR( "Davinci/OSD: FBIOPUT_VSCREENINFO (fb%d) failed!\n", OSD0 );

          ret = ioctl( ddrv->fb[OSD1].fd, FBIOPUT_VSCREENINFO, &dosd->var1 );
          if (ret)
               D_PERROR( "Davinci/OSD: FBIOPUT_VSCREENINFO (fb%d) failed!\n", OSD1 );
     }

     /* Update position? */
     if (updated & CLRCF_DEST) {
          vpbe_window_position_t win_pos;

          D_DEBUG_AT( Davinci_OSD, "  -> %d, %d\n", config->dest.x, config->dest.y );

          /* Set horizontal and vertical offset. */
          win_pos.xpos = config->dest.x;
          win_pos.ypos = config->dest.y;

          ret = ioctl( ddrv->fb[OSD0].fd, FBIO_SETPOS, &win_pos );
          if (ret)
               D_OSDERROR( "Davinci/OSD: FBIO_SETPOS (fb%d - %d,%d) failed!\n", OSD0, config->dest.x, config->dest.y );

          ret = ioctl( ddrv->fb[OSD1].fd, FBIO_SETPOS, &win_pos );
          if (ret)
               D_OSDERROR( "Davinci/OSD: FBIO_SETPOS (fb%d - %d,%d) failed!\n", OSD1, config->dest.x, config->dest.y );
     }

     davincifb_pan_display( &ddrv->fb[OSD0], &dosd->var0,
                            (config->format == DSPF_RGB16) ? lock : NULL, DSFLIP_NONE, 0, 0 );

     ret = ioctl( ddrv->fb[OSD0].fd, FBIOGET_FSCREENINFO, &ddev->fix[OSD0] );
     if (ret)
          D_PERROR( "Davinci/OSD: FBIOGET_FSCREENINFO (fb%d) failed!\n", OSD0 );

     ret = ioctl( ddrv->fb[OSD1].fd, FBIOGET_FSCREENINFO, &ddev->fix[OSD1] );
     if (ret)
          D_PERROR( "Davinci/OSD: FBIOGET_FSCREENINFO (fb%d) failed!\n", OSD1 );

     dosd->enable = true;

     if (ioctl( ddrv->fb[OSD0].fd, FBIO_ENABLE_DISABLE_ATTRIBUTE_WIN, 0 ))
          D_OSDERROR( "Davinci/OSD: FBIO_ENABLE_DISABLE_ATTRIBUTE_WIN (fb%d - %d)!\n", OSD0, 0 );

     return DFB_OK;
}

static DFBResult
osdRemoveRegion( CoreLayer *layer,
                 void      *driver_data,
                 void      *layer_data,
                 void      *region_data )
{
     int                  ret;
     DavinciDriverData   *ddrv = driver_data;
     DavinciOSDLayerData *dosd = layer_data;

     D_DEBUG_AT( Davinci_OSD, "%s()\n", __FUNCTION__ );

     D_ASSERT( ddrv != NULL );

     ret = ioctl( ddrv->fb[OSD0].fd, FBIO_ENABLE_DISABLE_WIN, 0 );
     if (ret)
          D_OSDERROR( "Davinci/OSD: FBIO_ENABLE_DISABLE_WIN (fb%d - %d)!\n", OSD0, 0 );

     ret = ioctl( ddrv->fb[OSD1].fd, FBIO_ENABLE_DISABLE_WIN, 0 );
     if (ret)
          D_OSDERROR( "Davinci/OSD: FBIO_ENABLE_DISABLE_WIN (fb%d - %d)!\n", OSD1, 0 );

     dosd->enable = false;

     return DFB_OK;
}

static void
update_buffers( DavinciDriverData     *ddrv,
                DavinciDeviceData     *ddev,
                CoreSurface           *surface,
                CoreSurfaceBufferLock *lock,
                const DFBRegion       *update )
{
     DFBRectangle       rect;
     CoreSurfaceBuffer *buffer;

     D_ASSERT( ddrv != NULL );
     D_ASSERT( ddev != NULL );
     D_ASSERT( surface != NULL );
     D_ASSERT( lock != NULL );
     DFB_REGION_ASSERT_IF( update );

     buffer = lock->buffer;
     D_ASSERT( buffer != NULL );

     if (update) {
          rect = DFB_RECTANGLE_INIT_FROM_REGION( update );

          if (rect.x & 1) {
               rect.x &= ~1;
               rect.w++;
          }

          if (rect.w & 1)
               rect.w++;
     }
     else {
          rect.x = 0;
          rect.y = 0;
          rect.w = surface->config.size.w;
          rect.h = surface->config.size.h;
     }

     /* Can we use the DSP? */
     if (ddrv->c64x_present) {
          int           i;
          int           lines = ddev->fix[OSD0].line_length == ddev->fix[OSD1].line_length ? rect.h : 1;
          unsigned long rgb   = ddev->fix[OSD0].smem_start + rect.x * 2 + rect.y * ddev->fix[OSD0].line_length;
          unsigned long alpha = ddev->fix[OSD1].smem_start + rect.x / 2 + rect.y * ddev->fix[OSD1].line_length;
          unsigned long src   = lock->phys                 + rect.x * 4 + rect.y * lock->pitch;

          //D_ASSUME( ddev->fix[OSD0].line_length == ddev->fix[OSD1].line_length );

          dfb_gfxcard_lock( GDLF_NONE );

          /* Dither ARGB to RGB16+A3 using the DSP. */
          for (i=0; i<rect.h; i+=lines) {
               if (lines > rect.h - i)
                    lines = rect.h - i;
               
               davinci_c64x_dither_argb__L( &ddrv->tasks, rgb, alpha,
                                         ddev->fix[OSD0].line_length, src, lock->pitch, rect.w, lines );

               if (ddev->fix[OSD0].line_length != ddev->fix[OSD1].line_length && lines > 1) {
                    davinci_c64x_blit_32__L( &ddrv->tasks,
                                          alpha + ddev->fix[OSD1].line_length, ddev->fix[OSD1].line_length,
                                          alpha + ddev->fix[OSD0].line_length, ddev->fix[OSD0].line_length,
                                          rect.w/2, lines - 1 );
               }

               rgb   += lines * ddev->fix[OSD0].line_length;
               alpha += lines * ddev->fix[OSD1].line_length;
               src   += lines * lock->pitch;
          }

          /* Flush the write cache. */
          davinci_c64x_write_back_all( &ddrv->c64x );


          davinci_c64x_emit_tasks( &ddrv->c64x, &ddrv->tasks, C64X_TEF_RESET );


          dfb_gfxcard_unlock();
     }
     else {
          u32  *src32 = lock->addr + rect.y * lock->pitch + DFB_BYTES_PER_LINE( buffer->format, rect.x );
          int   sp4   = lock->pitch / 4;
          u32  *dst32 = ddrv->fb[OSD0].mem + rect.y * ddev->fix[OSD0].line_length + rect.x * 2;
          int   dp4   = ddev->fix[OSD0].line_length / 4;
          u8   *dst8  = ddrv->fb[OSD1].mem + rect.y * ddev->fix[OSD1].line_length + rect.x / 2;
          int   dp    = ddev->fix[OSD1].line_length;
          int   w2    = rect.w / 2;
          u32   z     = 0;

          switch (buffer->format) {
               case DSPF_ARGB4444:
                    while (rect.h--) {
                         int x;

                         for (x=0; x<w2; x++) {
                              dst32[x] = ((src32[x] & 0x0f000f00) << 4) | ((src32[x] & 0x08000800)     ) |
                                         ((src32[x] & 0x00f000f0) << 3) | ((src32[x] & 0x00c000c0) >> 1) |
                                         ((src32[x] & 0x000f000f) << 1) | ((src32[x] & 0x00080008) >> 3);

                              dst8[x] = ((src32[x] & 0xe0000000) >> 29) | ((src32[x] & 0x0000e000) >> 9);
                         }

                         src32 += sp4;
                         dst32 += dp4;
                         dst8  += dp;
                    }
                    break;

               case DSPF_ARGB1555:
                    while (rect.h--) {
                         int x;

                         for (x=0; x<w2; x++) {
                              dst32[x] = ((src32[x] & 0x7c007c00) << 1) |
                                         ((src32[x] & 0x03e003e0) << 1) |
                                          (src32[x] & 0x003f003f);

                              dst8[x] = ((src32[x] & 0x80000000) ? 0x70 : 0x00) |
                                        ((src32[x] & 0x00008000) ? 0x07 : 0x00);
                         }

                         src32 += sp4;
                         dst32 += dp4;
                         dst8  += dp;
                    }
                    break;

               case DSPF_ARGB:
                    while (rect.h--) {
                         int x;

                         for (x=0; x<w2; x++) {
                              register u32 s0 = src32[(x<<1)+0];
                              register u32 s1 = src32[(x<<1)+1];

                              dst32[x] = ((s0 & 0x00f80000) >>  8) |
                                         ((s0 & 0x0000fc00) >>  5) |
                                         ((s0 & 0x000000f8) >>  3) |
                                         ((s1 & 0x00f80000) <<  8) |
                                         ((s1 & 0x0000fc00) << 11) |
                                         ((s1 & 0x000000f8) << 13) ;

#ifndef DAVINCI_NO_DITHER
                              if ((s0 & s1) >> 24 == 0xff)
                                   dst8[x] = 0x77;
                              else {
                                   register int pt, da;

                                   z ^= ((z << 13) | (z >> 19));
                                   z += 0x87654321;
                                   pt = s0 - ((s0 & 0xf8000000) >> 3);
                                   da = (((pt >> 29) & 0x07)  + ( ((z&0x1f) - ((pt >> 24) & 0x1f))>>31 )) << 4;

                                   z ^= ((z << 13) | (z >> 19));
                                   z += 0x87654321;
                                   pt = s1 - ((s1 & 0xf8000000) >> 3);
                                   da |= (((pt >> 29) & 0x07) + ( ((z&0x1f) - ((pt >> 24) & 0x1f))>>31 ));


                                   dst8[x] = da;
                              }
#else
                              dst8[x] = ((s0 & 0xe0000000) >> 25) |
                                        ((s1 & 0xe0000000) >> 29) ;
#endif
                         }

                         src32 += sp4;
                         dst32 += dp4;
                         dst8  += dp;
                    }
                    break;

               default:
                    D_ONCE( "unsupported format" );
          }
     }
}

static void
update_rgb( DavinciDriverData     *ddrv,
            DavinciDeviceData     *ddev,
            CoreSurface           *surface,
            CoreSurfaceBufferLock *lock,
            const DFBRegion       *update )
{
     DFBRectangle       rect;
     CoreSurfaceBuffer *buffer;

     D_ASSERT( ddrv != NULL );
     D_ASSERT( ddev != NULL );
     D_ASSERT( surface != NULL );
     D_ASSERT( lock != NULL );
     DFB_REGION_ASSERT_IF( update );

     buffer = lock->buffer;
     D_ASSERT( buffer != NULL );

     if (update)
          rect = DFB_RECTANGLE_INIT_FROM_REGION( update );
     else {
          rect.x = 0;
          rect.y = 0;
          rect.w = surface->config.size.w;
          rect.h = surface->config.size.h;
     }

     dfb_convert_to_rgb16( buffer->format,
                           lock->addr + rect.y * lock->pitch + DFB_BYTES_PER_LINE( buffer->format, rect.x ),
                           lock->pitch,
                           surface->config.size.h,
                           ddrv->fb[OSD0].mem + rect.y * ddev->fix[OSD0].line_length + rect.x * 2,
                           ddev->fix[OSD0].line_length,
                           rect.w, rect.h );
}

static void
enable_osd( DavinciDriverData   *ddrv,
            DavinciOSDLayerData *dosd )
{
     if (!dosd->enable)
          return;

     ioctl( ddrv->fb[OSD0].fd, FBIO_WAITFORVSYNC );

     if (ioctl( ddrv->fb[OSD0].fd, FBIO_ENABLE_DISABLE_ATTRIBUTE_WIN, dosd->alpha ))
          D_OSDERROR( "Davinci/OSD: FBIO_ENABLE_DISABLE_ATTRIBUTE_WIN (fb%d - %d)!\n", OSD0, dosd->alpha );

     if (ioctl( ddrv->fb[OSD0].fd, FBIO_ENABLE_DISABLE_WIN, 1 ))
          D_OSDERROR( "Davinci/OSD: FBIO_ENABLE_DISABLE_WIN (fb%d - %d)!\n", OSD0, 1 );

     if (ioctl( ddrv->fb[OSD1].fd, FBIO_ENABLE_DISABLE_WIN, dosd->alpha ))
          D_OSDERROR( "Davinci/OSD: FBIO_ENABLE_DISABLE_WIN (fb%d - %d)!\n", OSD1, dosd->alpha );

     dosd->enable = false;
}

static DFBResult
osdFlipRegion( CoreLayer             *layer,
               void                  *driver_data,
               void                  *layer_data,
               void                  *region_data,
               CoreSurface           *surface,
               DFBSurfaceFlipFlags    flags,
               CoreSurfaceBufferLock *lock )
{
     CoreSurfaceBuffer   *buffer;
     DavinciDriverData   *ddrv = driver_data;
     DavinciDeviceData   *ddev = ddrv->ddev;
     DavinciOSDLayerData *dosd = layer_data;

     D_DEBUG_AT( Davinci_OSD, "%s()\n", __FUNCTION__ );

     D_ASSERT( surface != NULL );
     D_ASSERT( lock != NULL );
     D_ASSERT( ddrv != NULL );
     D_ASSERT( ddev != NULL );

     buffer = lock->buffer;
     D_ASSERT( buffer != NULL );

     if (buffer->format != DSPF_RGB16) {
          if (DFB_PIXELFORMAT_HAS_ALPHA( buffer->format ))
               update_buffers( ddrv, ddev, surface, lock, NULL );
          else
               update_rgb( ddrv, ddev, surface, lock, NULL );
     }
     else
          davincifb_pan_display( &ddrv->fb[OSD0], &dosd->var0, lock, flags, 0, 0 );

     dfb_surface_flip( surface, false );

     enable_osd( ddrv, dosd );

     return DFB_OK;
}

static DFBResult
osdUpdateRegion( CoreLayer             *layer,
                 void                  *driver_data,
                 void                  *layer_data,
                 void                  *region_data,
                 CoreSurface           *surface,
                 const DFBRegion       *update,
                 CoreSurfaceBufferLock *lock )
{
     CoreSurfaceBuffer   *buffer;
     DavinciDriverData   *ddrv = driver_data;
     DavinciDeviceData   *ddev = ddrv->ddev;
     DavinciOSDLayerData *dosd = layer_data;

     D_DEBUG_AT( Davinci_OSD, "%s()\n", __FUNCTION__ );

     D_ASSERT( surface != NULL );
     D_ASSERT( lock != NULL );
     D_ASSERT( ddrv != NULL );
     D_ASSERT( ddev != NULL );

     buffer = lock->buffer;
     D_ASSERT( buffer != NULL );

     if (buffer->format != DSPF_RGB16) {
          if (DFB_PIXELFORMAT_HAS_ALPHA( buffer->format ))
               update_buffers( ddrv, ddev, surface, lock, update );
          else
               update_rgb( ddrv, ddev, surface, lock, update );
     }

     enable_osd( ddrv, dosd );

     return DFB_OK;
}

const DisplayLayerFuncs davinciOSDLayerFuncs = {
     .LayerDataSize = osdLayerDataSize,
     .InitLayer     = osdInitLayer,

     .TestRegion    = osdTestRegion,
     .SetRegion     = osdSetRegion,
     .RemoveRegion  = osdRemoveRegion,
     .FlipRegion    = osdFlipRegion,
     .UpdateRegion  = osdUpdateRegion,
};

