/* (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 "regs.h" #include "mmio.h" #include "matrox.h" typedef struct { CoreLayerRegionConfig config; /* Stored registers */ struct { /* CRTC2 sub picture */ u32 c2DATACTL; u32 c2SPICSTARTADD0; u32 c2SPICSTARTADD1; u32 c2SUBPICLUT; } regs; } MatroxSpicLayerData; static void spic_calc_buffer( MatroxDriverData *mdrv, MatroxSpicLayerData *mspic, CoreSurface *surface, CoreSurfaceBufferLock *lock ); static void spic_set_buffer( MatroxDriverData *mdrv, MatroxSpicLayerData *mspic ); #define SPIC_SUPPORTED_OPTIONS (DLOP_ALPHACHANNEL | DLOP_OPACITY) /**********************/ static int spicLayerDataSize( void ) { return sizeof(MatroxSpicLayerData); } static DFBResult spicInitLayer( CoreLayer *layer, void *driver_data, void *layer_data, DFBDisplayLayerDescription *description, DFBDisplayLayerConfig *config, DFBColorAdjustment *adjustment ) { /* set capabilities and type */ description->caps = DLCAPS_SURFACE | DLCAPS_ALPHACHANNEL | DLCAPS_OPACITY; description->type = DLTF_GRAPHICS | DLTF_VIDEO | DLTF_STILL_PICTURE; /* set name */ snprintf( description->name, DFB_DISPLAY_LAYER_DESC_NAME_LENGTH, "Matrox CRTC2 Sub-Picture" ); /* fill out the default configuration */ config->flags = DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE | DLCONF_OPTIONS | DLCONF_SURFACE_CAPS; config->width = 720; config->height = (dfb_config->matrox_tv_std != DSETV_PAL) ? 480 : 576; config->pixelformat = DSPF_ALUT44; config->buffermode = DLBM_FRONTONLY; config->options = DLOP_NONE; config->surface_caps = DSCAPS_INTERLACED; return DFB_OK; } static DFBResult spicTestRegion( CoreLayer *layer, void *driver_data, void *layer_data, CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags *failed ) { CoreLayerRegionConfigFlags fail = 0; if (config->options & ~SPIC_SUPPORTED_OPTIONS) fail |= CLRCF_OPTIONS; /* Can't have both at the same time */ if (config->options & DLOP_ALPHACHANNEL && config->options & DLOP_OPACITY) fail |= CLRCF_OPTIONS; switch (config->opacity) { case 0x00: case 0xFF: break; default: if (!(config->options & DLOP_OPACITY)) fail |= CLRCF_OPACITY; } if (config->surface_caps & ~(DSCAPS_INTERLACED | DSCAPS_SEPARATED)) fail |= CLRCF_SURFACE_CAPS; if (config->format != DSPF_ALUT44) fail |= CLRCF_FORMAT; if (config->width != 720) fail |= CLRCF_WIDTH; if (config->surface_caps & DSCAPS_INTERLACED) { if (config->height != ((dfb_config->matrox_tv_std != DSETV_PAL) ? 480 : 576)) fail |= CLRCF_HEIGHT; } else { if (config->height != ((dfb_config->matrox_tv_std != DSETV_PAL) ? 240 : 288)) fail |= CLRCF_HEIGHT; } if (failed) *failed = fail; if (fail) return DFB_UNSUPPORTED; return DFB_OK; } static DFBResult spicAddRegion( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreLayerRegionConfig *config ) { return DFB_OK; } static DFBResult spicSetRegion( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags updated, CoreSurface *surface, CorePalette *palette, CoreSurfaceBufferLock *lock ) { MatroxDriverData *mdrv = (MatroxDriverData*) driver_data; MatroxSpicLayerData *mspic = (MatroxSpicLayerData*) layer_data; MatroxDeviceData *mdev = mdrv->device_data; volatile u8 *mmio = mdrv->mmio_base; /* remember configuration */ mspic->config = *config; if (updated & CLRCF_PALETTE) { u8 y, cb, cr; int i; for (i = 0; i < 16; i++) { RGB_TO_YCBCR( palette->entries[i].r, palette->entries[i].g, palette->entries[i].b, y, cb, cr ); mspic->regs.c2SUBPICLUT = (cr << 24) | (cb << 16) | (y << 8) | i; mga_out32( mmio, mspic->regs.c2SUBPICLUT, C2SUBPICLUT ); } } if (updated & (CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_FORMAT | CLRCF_SURFACE_CAPS | CLRCF_OPTIONS | CLRCF_OPACITY | CLRCF_SURFACE)) { spic_calc_buffer( mdrv, mspic, surface, lock ); spic_set_buffer( mdrv, mspic ); mspic->regs.c2DATACTL = mga_in32( mmio, C2DATACTL ); if (surface->config.caps & DSCAPS_INTERLACED || mdev->crtc2_separated) mspic->regs.c2DATACTL &= ~C2OFFSETDIVEN; else mspic->regs.c2DATACTL |= C2OFFSETDIVEN; if (config->opacity) mspic->regs.c2DATACTL |= C2SUBPICEN; else mspic->regs.c2DATACTL &= ~C2SUBPICEN; if (config->options & DLOP_ALPHACHANNEL) mspic->regs.c2DATACTL &= ~C2STATICKEYEN; else mspic->regs.c2DATACTL |= C2STATICKEYEN; mspic->regs.c2DATACTL &= ~C2STATICKEY; mspic->regs.c2DATACTL |= ((config->opacity + 1) << 20) & C2STATICKEY; mga_out32( mmio, mspic->regs.c2DATACTL, C2DATACTL); } return DFB_OK; } static DFBResult spicRemoveRegion( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data ) { MatroxDriverData *mdrv = (MatroxDriverData*) driver_data; MatroxSpicLayerData *mspic = (MatroxSpicLayerData*) layer_data; volatile u8 *mmio = mdrv->mmio_base; mspic->regs.c2DATACTL = mga_in32( mmio, C2DATACTL ); mspic->regs.c2DATACTL &= ~C2SUBPICEN; mga_out32( mmio, mspic->regs.c2DATACTL, C2DATACTL ); return DFB_OK; } static DFBResult spicFlipRegion( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreSurface *surface, DFBSurfaceFlipFlags flags, CoreSurfaceBufferLock *lock ) { MatroxDriverData *mdrv = (MatroxDriverData*) driver_data; MatroxSpicLayerData *mspic = (MatroxSpicLayerData*) layer_data; spic_calc_buffer( mdrv, mspic, surface, lock ); spic_set_buffer( mdrv, mspic ); dfb_surface_flip( surface, false ); return DFB_OK; } DisplayLayerFuncs matroxSpicFuncs = { .LayerDataSize = spicLayerDataSize, .InitLayer = spicInitLayer, .TestRegion = spicTestRegion, .AddRegion = spicAddRegion, .SetRegion = spicSetRegion, .RemoveRegion = spicRemoveRegion, .FlipRegion = spicFlipRegion, }; /* internal */ static void spic_calc_buffer( MatroxDriverData *mdrv, MatroxSpicLayerData *mspic, CoreSurface *surface, CoreSurfaceBufferLock *lock ) { unsigned int field_offset = lock->pitch; mspic->regs.c2SPICSTARTADD1 = lock->offset; mspic->regs.c2SPICSTARTADD0 = lock->offset; if (surface->config.caps & DSCAPS_SEPARATED) field_offset *= surface->config.size.h / 2; if (surface->config.caps & DSCAPS_INTERLACED) mspic->regs.c2SPICSTARTADD0 += field_offset; } static void spic_set_buffer( MatroxDriverData *mdrv, MatroxSpicLayerData *mspic ) { volatile u8 *mmio = mdrv->mmio_base; mga_out32( mmio, mspic->regs.c2SPICSTARTADD0, C2SPICSTARTADD0 ); mga_out32( mmio, mspic->regs.c2SPICSTARTADD1, C2SPICSTARTADD1 ); }