/* (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH All rights reserved. Written by Denis Oliver Kropp , Andreas Hundt , Sven Neumann , Ville Syrjälä and Claudio Ciccani . 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include DFB_GRAPHICS_DRIVER( cyber5k ) #include "regs.h" #include "mmio.h" #include "cyber5k.h" #include "cyber5k_alpha.h" /* HACK */ volatile u8 *cyber_mmio = NULL; /* FIXME: support for destination color keying */ #define CYBER5K_DRAWING_FLAGS \ (DSDRAW_NOFX) #define CYBER5K_DRAWING_FUNCTIONS \ (DFXL_DRAWLINE | DFXL_DRAWRECTANGLE | DFXL_FILLRECTANGLE) #define CYBER5K_BLITTING_FLAGS \ (DSBLIT_SRC_COLORKEY) #define CYBER5K_BLITTING_FUNCTIONS \ (DFXL_BLIT) static bool cyber5kFillRectangle( void *drv, void *dev, DFBRectangle *rect ); static bool cyber5kFillRectangle24( void *drv, void *dev, DFBRectangle *rect ); static bool cyber5kDrawRectangle( void *drv, void *dev, DFBRectangle *rect ); static bool cyber5kDrawRectangle24( void *drv, void *dev, DFBRectangle *rect ); static bool cyber5kBlit( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ); static bool cyber5kBlit24( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ); static DFBResult cyber5kEngineSync( void *drv, void *dev ) { CyberDriverData *cdrv = (CyberDriverData*) drv; CyberDeviceData *cdev = (CyberDeviceData*) dev; cyber_waitidle( cdrv, cdev ); return DFB_OK; } static void cyber5kCheckState( void *drv, void *dev, CardState *state, DFBAccelerationMask accel ) { /* check destination format first */ switch (state->destination->config.format) { case DSPF_RGB16: case DSPF_RGB24: case DSPF_RGB32: case DSPF_ARGB: break; default: return; } if (DFB_DRAWING_FUNCTION( accel )) { /* if there are no other drawing flags than the supported */ if (state->drawingflags & ~CYBER5K_DRAWING_FLAGS) return; state->accel |= CYBER5K_DRAWING_FUNCTIONS; /* no line drawing in 24bit mode */ if (state->destination->config.format == DSPF_RGB24) state->accel &= ~DFXL_DRAWLINE; } else { /* if there are no other blitting flags than the supported and the source and destination formats are the same */ if (state->blittingflags & ~CYBER5K_BLITTING_FLAGS) return; if (state->source->config.format != state->destination->config.format) return; state->accel |= CYBER5K_BLITTING_FUNCTIONS; } } static inline void cyber5k_validate_dst( CyberDriverData *cdrv, CyberDeviceData *cdev, CardState *state, GraphicsDeviceFuncs *funcs ) { CoreSurface *dest = state->destination; if (cdev->v_dst) return; cdev->dst_pixeloffset = state->dst.offset / DFB_BYTES_PER_PIXEL(dest->config.format); cdev->dst_pixelpitch = state->dst.pitch / DFB_BYTES_PER_PIXEL(dest->config.format); switch (dest->config.format) { case DSPF_RGB16: funcs->FillRectangle = cyber5kFillRectangle; funcs->DrawRectangle = cyber5kDrawRectangle; funcs->Blit = cyber5kBlit; cyber_out16( cdrv->mmio_base, DSTWIDTH, cdev->dst_pixelpitch - 1 ); cyber_out8( cdrv->mmio_base, COPFMT, 1 ); break; case DSPF_RGB24: funcs->FillRectangle = cyber5kFillRectangle24; funcs->DrawRectangle = cyber5kDrawRectangle24; funcs->Blit = cyber5kBlit24; cyber_out16( cdrv->mmio_base, DSTWIDTH, cdev->dst_pixelpitch*3 -1); cyber_out8( cdrv->mmio_base, COPFMT, 2 ); break; case DSPF_RGB32: case DSPF_ARGB: funcs->FillRectangle = cyber5kFillRectangle; funcs->DrawRectangle = cyber5kDrawRectangle; funcs->Blit = cyber5kBlit; cyber_out16( cdrv->mmio_base, DSTWIDTH, cdev->dst_pixelpitch - 1 ); cyber_out8( cdrv->mmio_base, COPFMT, 3 ); break; default: D_BUG( "unexpected pixelformat!" ); break; } cdev->v_dst = 1; } static inline void cyber5k_validate_src( CyberDriverData *cdrv, CyberDeviceData *cdev, CardState *state ) { CoreSurface *source = state->source; if (cdev->v_src) return; cdev->src_pixeloffset = state->src.offset / DFB_BYTES_PER_PIXEL(source->config.format); cdev->src_pixelpitch = state->src.pitch / DFB_BYTES_PER_PIXEL(source->config.format); cyber_out16( cdrv->mmio_base, SRC1WIDTH, state->src.pitch /DFB_BYTES_PER_PIXEL(source->config.format) - 1); cdev->v_src = 1; } static inline void cyber5k_validate_color( CyberDriverData *cdrv, CyberDeviceData *cdev, CardState *state ) { u32 fill_color = 0; if (cdev->v_color) return; switch (state->destination->config.format) { case DSPF_RGB16: fill_color = PIXEL_RGB16( state->color.r, state->color.g, state->color.b ); break; case DSPF_RGB24: case DSPF_RGB32: fill_color = PIXEL_RGB32( state->color.r, state->color.g, state->color.b ); break; case DSPF_ARGB: fill_color = PIXEL_ARGB( state->color.a, state->color.r, state->color.g, state->color.b ); break; default: D_BUG( "unexpected pixelformat!" ); break; } cyber_out32( cdrv->mmio_base, FCOLOR, fill_color ); cdev->v_src_colorkey = 0; cdev->v_color = 1; } static inline void cyber5k_validate_src_colorkey( CyberDriverData *cdrv, CyberDeviceData *cdev, CardState *state ) { if (cdev->v_src_colorkey) return; cyber_out32( cdrv->mmio_base, FCOLOR, state->src_colorkey ); cyber_out32( cdrv->mmio_base, BCOLOR, state->src_colorkey ); cdev->v_color = 0; cdev->v_src_colorkey = 1; } static inline void cyber5k_validate_blitting_cmd( CyberDriverData *cdrv, CyberDeviceData *cdev, CardState *state ) { if (cdev->v_blitting_cmd) return; cdev->blitting_cmd = COP_PXBLT | PAT_FIXFGD | FGD_IS_SRC1; if (state->blittingflags & DSBLIT_SRC_COLORKEY) cdev->blitting_cmd |= TRANS_ENABLE | TRANS_IS_SRC1 | TRANS_INVERT; cdev->v_blitting_cmd = 1; } static void cyber5kSetState( void *drv, void *dev, GraphicsDeviceFuncs *funcs, CardState *state, DFBAccelerationMask accel ) { CyberDriverData *cdrv = (CyberDriverData*) drv; CyberDeviceData *cdev = (CyberDeviceData*) dev; if (state->mod_hw) { if (state->mod_hw & SMF_DESTINATION) cdev->v_dst = cdev->v_color = 0; else if (state->mod_hw & SMF_COLOR) cdev->v_color = 0; if (state->mod_hw & SMF_SOURCE) cdev->v_src = cdev->v_src_colorkey = 0; else if (state->mod_hw & SMF_SRC_COLORKEY) cdev->v_src_colorkey = 0; if (state->mod_hw & SMF_BLITTING_FLAGS) cdev->v_blitting_cmd = 0; } cyber5k_validate_dst( cdrv, cdev, state, funcs ); switch (accel) { case DFXL_DRAWLINE: case DFXL_DRAWRECTANGLE: case DFXL_FILLRECTANGLE: cyber5k_validate_color( cdrv, cdev, state ); state->set = CYBER5K_DRAWING_FUNCTIONS; break; case DFXL_BLIT: cyber5k_validate_src( cdrv, cdev, state ); cyber5k_validate_blitting_cmd( cdrv, cdev, state ); if (state->blittingflags & DSBLIT_SRC_COLORKEY) cyber5k_validate_src_colorkey( cdrv, cdev, state ); state->set = CYBER5K_BLITTING_FUNCTIONS; break; default: D_BUG( "unexpected drawing/blitting function!" ); break; } state->mod_hw = 0; } static bool cyber5kFillRectangle( void *drv, void *dev, DFBRectangle *rect ) { CyberDriverData *cdrv = (CyberDriverData*) drv; CyberDeviceData *cdev = (CyberDeviceData*) dev; volatile u8 *mmio = cdrv->mmio_base; cyber_waitidle( cdrv, cdev ); cyber_out32( mmio, DSTPTR, cdev->dst_pixeloffset + rect->y * cdev->dst_pixelpitch + rect->x ); cyber_out32( mmio, HEIGHTWIDTH, ((rect->h-1) << 16) | (rect->w-1) ); cyber_out32( mmio, PIXOP, COP_PXBLT | PAT_FIXFGD ); return true; } static bool cyber5kFillRectangle24( void *drv, void *dev, DFBRectangle *rect ) { CyberDriverData *cdrv = (CyberDriverData*) drv; CyberDeviceData *cdev = (CyberDeviceData*) dev; volatile u8 *mmio = cdrv->mmio_base; cyber_waitidle( cdrv, cdev ); cyber_out32( mmio, DSTPTR, (cdev->dst_pixeloffset + rect->y * cdev->dst_pixelpitch + rect->x) * 3 ); cyber_out8( mmio, DSTXROT, rect->x & 7 ); cyber_out32( mmio, HEIGHTWIDTH, ((rect->h-1) << 16) | (rect->w-1) ); cyber_out32( mmio, PIXOP, COP_PXBLT | PAT_FIXFGD ); return true; } static bool cyber5kDrawRectangle( void *drv, void *dev, DFBRectangle *rect ) { CyberDriverData *cdrv = (CyberDriverData*) drv; CyberDeviceData *cdev = (CyberDeviceData*) dev; volatile u8 *mmio = cdrv->mmio_base; u32 dst = cdev->dst_pixeloffset + rect->y * cdev->dst_pixelpitch + rect->x; cyber_waitidle( cdrv, cdev ); cyber_out32( mmio, DSTPTR, dst ); cyber_out32( mmio, DIMW, 0 ); cyber_out32( mmio, DIMH, rect->h - 1 ); cyber_out32( mmio, PIXOP, COP_PXBLT | PAT_FIXFGD ); cyber_waitidle( cdrv, cdev ); cyber_out32( mmio, DSTPTR, dst + rect->w - 1); cyber_out32( mmio, PIXOP, COP_PXBLT | PAT_FIXFGD ); cyber_waitidle( cdrv, cdev ); cyber_out32( mmio, DSTPTR, dst ); cyber_out32( mmio, DIMW, rect->w - 1 ); cyber_out32( mmio, DIMH, 0 ); cyber_out32( mmio, PIXOP, COP_PXBLT | PAT_FIXFGD ); cyber_waitidle( cdrv, cdev ); cyber_out32( mmio, DSTPTR, dst + cdev->dst_pixelpitch * (rect->h - 1) ); cyber_out32( mmio, PIXOP, COP_PXBLT | PAT_FIXFGD ); return true; } static bool cyber5kDrawRectangle24( void *drv, void *dev, DFBRectangle *rect ) { CyberDriverData *cdrv = (CyberDriverData*) drv; CyberDeviceData *cdev = (CyberDeviceData*) dev; volatile u8 *mmio = cdrv->mmio_base; u32 dst = cdev->dst_pixeloffset + (rect->y * cdev->dst_pixelpitch + rect->x) * 3; cyber_waitidle( cdrv, cdev ); cyber_out8( mmio, DSTXROT, rect->x & 7 ); cyber_out32( mmio, DSTPTR, dst ); cyber_out32( mmio, DIMW, rect->w - 1 ); cyber_out32( mmio, DIMH, 0 ); cyber_out32( mmio, PIXOP, COP_PXBLT | PAT_FIXFGD ); cyber_waitidle( cdrv, cdev ); cyber_out32( mmio, DSTPTR, dst + cdev->dst_pixelpitch * (rect->h-1) * 3 ); cyber_out32( mmio, PIXOP, COP_PXBLT | PAT_FIXFGD ); cyber_waitidle( cdrv, cdev ); cyber_out32( mmio, DSTPTR, dst ); cyber_out32( mmio, DIMW, 0 ); cyber_out32( mmio, DIMH, rect->h - 1 ); cyber_out32( mmio, PIXOP, COP_PXBLT | PAT_FIXFGD ); cyber_waitidle( cdrv, cdev ); cyber_out8( mmio, DSTXROT, (rect->x + rect->w - 1) & 7 ); cyber_out32( mmio, DSTPTR, dst + (rect->w-1) * 3 ); cyber_out32( mmio, PIXOP, COP_PXBLT | PAT_FIXFGD ); return true; } static bool cyber5kDrawLine( void *drv, void *dev, DFBRegion *line ) { CyberDriverData *cdrv = (CyberDriverData*) drv; CyberDeviceData *cdev = (CyberDeviceData*) dev; volatile u8 *mmio = cdrv->mmio_base; u32 cmd = COP_LINE_DRAW | PAT_FIXFGD; int dx; int dy; dx = line->x2 - line->x1; dy = line->y2 - line->y1; if (dx < 0) { dx = -dx; cmd |= DX_NEG; } if (dy < 0) { dy = -dy; cmd |= DY_NEG; } if (dx < dy) { int tmp; cmd |= YMAJOR; tmp = dx; dx = dy; dy = tmp; } cyber_waitidle( cdrv, cdev ); cyber_out32( mmio, DSTPTR, cdev->dst_pixeloffset + line->y1 * cdev->dst_pixelpitch + line->x1); cyber_out16( mmio, DIMW , dx); cyber_out16( mmio, K1 , 2*dy); cyber_out16( mmio, ERRORTERM, 2*dy-dx); cyber_out32( mmio, K2 ,2*(dy-dx)); cyber_out32( mmio, PIXOP , cmd); return true; } static bool cyber5kBlit( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ) { CyberDriverData *cdrv = (CyberDriverData*) drv; CyberDeviceData *cdev = (CyberDeviceData*) dev; volatile u8 *mmio = cdrv->mmio_base; u32 cmd = cdev->blitting_cmd; cyber_waitidle( cdrv, cdev ); if (rect->x < dx) { cmd |= DEC_X; rect->x += rect->w - 1; dx += rect->w - 1; } if (rect->y < dy) { cmd |= DEC_Y; rect->y += rect->h - 1; dy += rect->h - 1; } cyber_out32( mmio, DSTPTR, cdev->dst_pixeloffset + dy * cdev->dst_pixelpitch + dx ); cyber_out32( mmio, SRC1PTR, cdev->src_pixeloffset + rect->y * cdev->src_pixelpitch + rect->x ); cyber_out32( mmio, HEIGHTWIDTH, ((rect->h-1) << 16) | (rect->w-1) ); cyber_out32( mmio, PIXOP , cmd); return true; } static bool cyber5kBlit24( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ) { CyberDriverData *cdrv = (CyberDriverData*) drv; CyberDeviceData *cdev = (CyberDeviceData*) dev; volatile u8 *mmio = cdrv->mmio_base; u32 cmd = cdev->blitting_cmd; u32 src = 0; u32 dst = 0; cyber_waitidle( cdrv, cdev ); if (rect->x < dx) { cmd |= DEC_X; rect->x += rect->w - 1; dx += rect->w - 1; src += 2; dst += 2; } if (rect->y < dy) { cmd |= DEC_Y; rect->y += rect->h - 1; dy += rect->h - 1; } src += cdev->src_pixeloffset + rect->y * cdev->dst_pixelpitch + rect->x; dst += cdev->dst_pixeloffset + dy * cdev->dst_pixelpitch + dx; cyber_out32( mmio, DSTPTR , src ); cyber_out32( mmio, SRC1PTR , dst ); cyber_out32( mmio, HEIGHTWIDTH, ((rect->h-1) << 16) | (rect->w-1) ); cyber_out32( mmio, PIXOP , cmd ); return true; } /* primary layer hooks */ #define OSD_OPTIONS (DLOP_ALPHACHANNEL | DLOP_SRC_COLORKEY | DLOP_OPACITY) DisplayLayerFuncs oldPrimaryFuncs; void *oldPrimaryDriverData; static DFBResult osdInitLayer( CoreLayer *layer, void *driver_data, void *layer_data, DFBDisplayLayerDescription *description, DFBDisplayLayerConfig *config, DFBColorAdjustment *adjustment ) { DFBResult ret; /* call the original initialization function first */ ret = oldPrimaryFuncs.InitLayer( layer, oldPrimaryDriverData, layer_data, description, config, adjustment ); if (ret) return ret; /* set name */ snprintf(description->name, DFB_DISPLAY_LAYER_DESC_NAME_LENGTH, "CyberPro OSD"); /* add support for options */ config->flags |= DLCONF_OPTIONS; /* add some capabilities */ description->caps |= DLCAPS_ALPHACHANNEL | DLCAPS_OPACITY | DLCAPS_SRC_COLORKEY; return DFB_OK; } static DFBResult osdTestRegion( CoreLayer *layer, void *driver_data, void *layer_data, CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags *failed ) { DFBResult ret; CoreLayerRegionConfigFlags fail = 0; DFBDisplayLayerOptions options = config->options; /* remove options before calling the original function */ config->options = DLOP_NONE; /* call the original function */ ret = oldPrimaryFuncs.TestRegion( layer, oldPrimaryDriverData, layer_data, config, &fail ); /* check options if specified */ if (options) { /* any unsupported option wanted? */ if (options & ~OSD_OPTIONS) fail |= CLRCF_OPTIONS; /* opacity and alpha channel cannot be used at once */ if ((options & (DLOP_OPACITY | DLOP_ALPHACHANNEL)) == (DLOP_OPACITY | DLOP_ALPHACHANNEL)) { fail |= CLRCF_OPTIONS; } } /* restore options */ config->options = options; if (failed) *failed = fail; if (fail) return DFB_UNSUPPORTED; return ret; } static DFBResult osdSetRegion( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags updated, CoreSurface *surface, CorePalette *palette, CoreSurfaceBufferLock *lock ) { DFBResult ret; /* call the original function */ ret = oldPrimaryFuncs.SetRegion( layer, oldPrimaryDriverData, layer_data, region_data, config, updated, surface, palette, lock ); if (ret) return ret; /* select pixel based or global alpha */ if (config->options & DLOP_ALPHACHANNEL) cyber_select_alpha_src( ALPHA_GRAPHICS ); else cyber_select_alpha_src( ALPHA_REGISTER ); cyber_set_alpha_reg( config->opacity, config->opacity, config->opacity ); /* source color keying */ cyber_select_RAM_addr( RAM_CPU ); cyber_set_alpha_RAM_reg( 0, 0x00, 0x00, 0x00 ); cyber_select_magic_alpha_src( ALPHA_LOOKUP ); cyber_enable_magic_alpha_blend( config->options & DLOP_SRC_COLORKEY ); /* FIXME: hardcoded black color key */ cyber_set_magic_match_reg( 0, 0, 0 ); return DFB_OK; } DisplayLayerFuncs newPrimaryFuncs = { .InitLayer = osdInitLayer, .TestRegion = osdTestRegion, .SetRegion = osdSetRegion, }; /* exported symbols */ static int driver_probe( CoreGraphicsDevice *device ) { switch (dfb_gfxcard_get_accelerator( device )) { case FB_ACCEL_IGS_CYBER2000: case FB_ACCEL_IGS_CYBER2010: case FB_ACCEL_IGS_CYBER5000: #ifdef FB_ACCEL_IGS_CYBER5K case FB_ACCEL_IGS_CYBER5K: /* CyberPro 5xxx */ #endif return 1; } return 0; } static void driver_get_info( CoreGraphicsDevice *device, GraphicsDriverInfo *info ) { /* fill driver info structure */ snprintf( info->name, DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH, "Cyber Pro Driver" ); snprintf( info->vendor, DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH, "directfb.org" ); info->version.major = 0; info->version.minor = 4; info->driver_data_size = sizeof (CyberDriverData); info->device_data_size = sizeof (CyberDeviceData); } static DFBResult driver_init_driver( CoreGraphicsDevice *device, GraphicsDeviceFuncs *funcs, void *driver_data, void *device_data, CoreDFB *core ) { CyberDriverData *cdrv = (CyberDriverData*) driver_data; /* gain access to memory mapped registers */ cdrv->mmio_base = (volatile u8*) dfb_gfxcard_map_mmio( device, 0, -1 ); if (!cdrv->mmio_base) return DFB_IO; /* HACK */ cyber_mmio = cdrv->mmio_base; /* fill acceleration function table */ funcs->EngineSync = cyber5kEngineSync; funcs->CheckState = cyber5kCheckState; funcs->SetState = cyber5kSetState; funcs->FillRectangle = cyber5kFillRectangle; funcs->DrawRectangle = cyber5kDrawRectangle; funcs->DrawLine = cyber5kDrawLine; funcs->Blit = cyber5kBlit; /* install primary layer hooks */ dfb_layers_hook_primary( device, driver_data, &newPrimaryFuncs, &oldPrimaryFuncs, &oldPrimaryDriverData ); /* add the video underlay */ switch (dfb_gfxcard_get_accelerator( device )) { case FB_ACCEL_IGS_CYBER5000: #ifdef FB_ACCEL_IGS_CYBER5K case FB_ACCEL_IGS_CYBER5K: /* CyberPro 5xxx */ #endif dfb_layers_register( dfb_screens_at(DSCID_PRIMARY), driver_data, &cyberUnderlayFuncs ); } return DFB_OK; } static DFBResult driver_init_device( CoreGraphicsDevice *device, GraphicsDeviceInfo *device_info, void *driver_data, void *device_data ) { CyberDriverData *cdrv = (CyberDriverData*) driver_data; volatile u8 *mmio = cdrv->mmio_base; /* fill device info */ snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "Cyber Pro" ); snprintf( device_info->vendor, DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "TVIA" ); device_info->caps.flags = 0; device_info->caps.accel = CYBER5K_DRAWING_FUNCTIONS | CYBER5K_BLITTING_FUNCTIONS; device_info->caps.drawing = CYBER5K_DRAWING_FLAGS; device_info->caps.blitting = CYBER5K_BLITTING_FLAGS; device_info->limits.surface_byteoffset_alignment = 16; device_info->limits.surface_pixelpitch_alignment = 4; /* set fifo policy at startup */ cyber_grphw(0x74, 0x1b); cyber_grphw(0x75, 0x1e); cyber_grphw(0xD9, 0x0f); cyber_grphw(0xDA, 0x1b); cyber_grphw(0xDD, 0x00); cyber_seqw(0xD9, 0x0f); cyber_seqw(0xDA, 0x1b); cyber_seqw(0xDD, 0x00); cyber_out8 (mmio, COPFLAGS, 1); cyber_out8 (mmio, FMIX , 0x03); return DFB_OK; } static void driver_close_device( CoreGraphicsDevice *device, void *driver_data, void *device_data ) { } static void driver_close_driver( CoreGraphicsDevice *device, void *driver_data ) { CyberDriverData *cdrv = (CyberDriverData*) driver_data; dfb_gfxcard_unmap_mmio( device, cdrv->mmio_base, -1 ); }