summaryrefslogtreecommitdiff
path: root/Source/DirectFB/gfxdrivers/ati128/ati128_overlay.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/gfxdrivers/ati128/ati128_overlay.c')
-rwxr-xr-xSource/DirectFB/gfxdrivers/ati128/ati128_overlay.c447
1 files changed, 447 insertions, 0 deletions
diff --git a/Source/DirectFB/gfxdrivers/ati128/ati128_overlay.c b/Source/DirectFB/gfxdrivers/ati128/ati128_overlay.c
new file mode 100755
index 0000000..0a96f7c
--- /dev/null
+++ b/Source/DirectFB/gfxdrivers/ati128/ati128_overlay.c
@@ -0,0 +1,447 @@
+/*
+ (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 <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.
+*/
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <direct/messages.h>
+
+#include <core/coredefs.h>
+#include <core/layers.h>
+#include <core/surface.h>
+
+#include "regs.h"
+#include "mmio.h"
+#include "ati128.h"
+
+typedef struct {
+ CoreLayerRegionConfig config;
+
+ /* overlay registers */
+ struct {
+ u32 H_INC;
+ u32 STEP_BY;
+ u32 Y_X_START;
+ u32 Y_X_END;
+ u32 V_INC;
+ u32 P1_BLANK_LINES_AT_TOP;
+ u32 P23_BLANK_LINES_AT_TOP;
+ u32 VID_BUF_PITCH0_VALUE;
+ u32 VID_BUF_PITCH1_VALUE;
+ u32 P1_X_START_END;
+ u32 P2_X_START_END;
+ u32 P3_X_START_END;
+ u32 VID_BUF0_BASE_ADRS;
+ u32 VID_BUF1_BASE_ADRS;
+ u32 VID_BUF2_BASE_ADRS;
+ u32 P1_V_ACCUM_INIT;
+ u32 P23_V_ACCUM_INIT;
+ u32 P1_H_ACCUM_INIT;
+ u32 P23_H_ACCUM_INIT;
+ u32 SCALE_CNTL;
+ } regs;
+} ATIOverlayLayerData;
+
+static void ov0_set_regs( ATI128DriverData *adrv, ATIOverlayLayerData *aov0 );
+static void ov0_calc_regs( ATI128DriverData *adrv, ATIOverlayLayerData *aov0,
+ CoreLayerRegionConfig *config, CoreSurface *surface,
+ CoreSurfaceBufferLock *lock );
+
+#define OV0_SUPPORTED_OPTIONS (DLOP_NONE)
+
+/**********************/
+
+static int
+ov0LayerDataSize( void )
+{
+ return sizeof(ATIOverlayLayerData);
+}
+
+static DFBResult
+ov0InitLayer( CoreLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ DFBDisplayLayerDescription *description,
+ DFBDisplayLayerConfig *config,
+ DFBColorAdjustment *adjustment )
+{
+ ATI128DriverData *adrv = (ATI128DriverData*) driver_data;
+ volatile u8 *mmio = adrv->mmio_base;
+
+ /* set capabilities and type */
+ description->caps = DLCAPS_SCREEN_LOCATION | DLCAPS_SURFACE;
+ description->type = DLTF_VIDEO | DLTF_STILL_PICTURE;
+
+ /* set name */
+ snprintf( description->name,
+ DFB_DISPLAY_LAYER_DESC_NAME_LENGTH, "ATI128 Overlay" );
+
+ /* 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_YUY2;
+ config->buffermode = DLBM_FRONTONLY;
+ config->options = DLOP_NONE;
+
+ /* fill out default color adjustment,
+ only fields set in flags will be accepted from applications */
+ adjustment->flags = DCAF_NONE;
+
+ /* reset overlay */
+ ati128_out32( mmio, OV0_SCALE_CNTL, 0x80000000 );
+ ati128_out32( mmio, OV0_EXCLUSIVE_HORZ, 0 );
+ ati128_out32( mmio, OV0_AUTO_FLIP_CNTL, 0 );
+ ati128_out32( mmio, OV0_FILTER_CNTL, 0x0000000f );
+ ati128_out32( mmio, OV0_COLOR_CNTL, 0x00101000 );
+ ati128_out32( mmio, OV0_KEY_CNTL, 0x10 );
+ ati128_out32( mmio, OV0_TEST, 0 );
+
+ return DFB_OK;
+}
+
+
+static void
+ov0OnOff( ATI128DriverData *adrv,
+ ATIOverlayLayerData *aov0,
+ int on )
+{
+ /* set/clear enable bit */
+ if (on)
+ aov0->regs.SCALE_CNTL |= R128_SCALER_ENABLE;
+ else
+ aov0->regs.SCALE_CNTL &= ~R128_SCALER_ENABLE;
+
+ /* write back to card */
+ ati128_out32( adrv->mmio_base, OV0_SCALE_CNTL, aov0->regs.SCALE_CNTL );
+}
+
+static DFBResult
+ov0TestRegion( CoreLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ CoreLayerRegionConfig *config,
+ CoreLayerRegionConfigFlags *failed )
+{
+ CoreLayerRegionConfigFlags fail = 0;
+
+ /* check for unsupported options */
+ if (config->options & ~OV0_SUPPORTED_OPTIONS)
+ fail |= CLRCF_OPTIONS;
+
+ /* check pixel format */
+ switch (config->format) {
+ case DSPF_YUY2:
+ case DSPF_UYVY:
+ case DSPF_I420:
+ case DSPF_YV12:
+ break;
+
+ default:
+ fail |= CLRCF_FORMAT;
+ }
+
+ /* check width */
+ if (config->width > 2048 || config->width < 1)
+ fail |= CLRCF_WIDTH;
+
+ /* check height */
+ if (config->height > 1024 || config->height < 1)
+ fail |= CLRCF_HEIGHT;
+
+ /* write back failing fields */
+ if (failed)
+ *failed = fail;
+
+ /* return failure if any field failed */
+ if (fail)
+ return DFB_UNSUPPORTED;
+
+ return DFB_OK;
+}
+
+static DFBResult
+ov0SetRegion( CoreLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ void *region_data,
+ CoreLayerRegionConfig *config,
+ CoreLayerRegionConfigFlags updated,
+ CoreSurface *surface,
+ CorePalette *palette,
+ CoreSurfaceBufferLock *lock )
+{
+ ATI128DriverData *adrv = (ATI128DriverData*) driver_data;
+ ATIOverlayLayerData *aov0 = (ATIOverlayLayerData*) layer_data;
+
+ /* remember configuration */
+ aov0->config = *config;
+
+ ov0_calc_regs( adrv, aov0, config, surface, lock );
+ ov0_set_regs( adrv, aov0 );
+
+ /* enable overlay */
+ ov0OnOff( adrv, aov0, 1 );
+
+ return DFB_OK;
+}
+
+static DFBResult
+ov0RemoveRegion( CoreLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ void *region_data )
+{
+ ATI128DriverData *adrv = (ATI128DriverData*) driver_data;
+ ATIOverlayLayerData *aov0 = (ATIOverlayLayerData*) layer_data;
+
+ /* disable overlay */
+ ov0OnOff( adrv, aov0, 0 );
+
+ return DFB_OK;
+}
+
+static DFBResult
+ov0FlipRegion( CoreLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ void *region_data,
+ CoreSurface *surface,
+ DFBSurfaceFlipFlags flags,
+ CoreSurfaceBufferLock *lock )
+{
+ ATI128DriverData *adrv = (ATI128DriverData*) driver_data;
+ ATIOverlayLayerData *aov0 = (ATIOverlayLayerData*) layer_data;
+
+ dfb_surface_flip( surface, false );
+
+ ov0_calc_regs( adrv, aov0, &aov0->config, surface, lock );
+ ov0_set_regs( adrv, aov0 );
+
+ return DFB_OK;
+}
+
+
+DisplayLayerFuncs atiOverlayFuncs = {
+ .LayerDataSize = ov0LayerDataSize,
+ .InitLayer = ov0InitLayer,
+
+ .TestRegion = ov0TestRegion,
+ .SetRegion = ov0SetRegion,
+ .RemoveRegion = ov0RemoveRegion,
+ .FlipRegion = ov0FlipRegion,
+};
+
+/* internal */
+
+static void ov0_set_regs( ATI128DriverData *adrv, ATIOverlayLayerData *aov0 )
+{
+ volatile u8 *mmio = adrv->mmio_base;
+
+ ati128_out32( mmio, OV0_REG_LOAD_CNTL, 1 );
+ while (!(ati128_in32( mmio, OV0_REG_LOAD_CNTL ) & (1 << 3)));
+
+ ati128_out32( mmio, OV0_H_INC,
+ aov0->regs.H_INC );
+
+ ati128_out32( mmio, OV0_STEP_BY,
+ aov0->regs.STEP_BY );
+
+ ati128_out32( mmio, OV0_Y_X_START,
+ aov0->regs.Y_X_START );
+
+ ati128_out32( mmio, OV0_Y_X_END,
+ aov0->regs.Y_X_END );
+
+ ati128_out32( mmio, OV0_V_INC,
+ aov0->regs.V_INC );
+
+ ati128_out32( mmio, OV0_P1_BLANK_LINES_AT_TOP,
+ aov0->regs.P1_BLANK_LINES_AT_TOP );
+
+ ati128_out32( mmio, OV0_P23_BLANK_LINES_AT_TOP,
+ aov0->regs.P23_BLANK_LINES_AT_TOP );
+
+ ati128_out32( mmio, OV0_VID_BUF_PITCH0_VALUE,
+ aov0->regs.VID_BUF_PITCH0_VALUE );
+
+ ati128_out32( mmio, OV0_VID_BUF_PITCH1_VALUE,
+ aov0->regs.VID_BUF_PITCH1_VALUE );
+
+ ati128_out32( mmio, OV0_P1_X_START_END,
+ aov0->regs.P1_X_START_END );
+
+ ati128_out32( mmio, OV0_P2_X_START_END,
+ aov0->regs.P2_X_START_END );
+
+ ati128_out32( mmio, OV0_P3_X_START_END,
+ aov0->regs.P3_X_START_END );
+
+ ati128_out32( mmio, OV0_VID_BUF0_BASE_ADRS,
+ aov0->regs.VID_BUF0_BASE_ADRS );
+
+ ati128_out32( mmio, OV0_VID_BUF1_BASE_ADRS,
+ aov0->regs.VID_BUF1_BASE_ADRS );
+
+ ati128_out32( mmio, OV0_VID_BUF2_BASE_ADRS,
+ aov0->regs.VID_BUF2_BASE_ADRS );
+
+ ati128_out32( mmio, OV0_P1_V_ACCUM_INIT,
+ aov0->regs.P1_V_ACCUM_INIT );
+
+ ati128_out32( mmio, OV0_P23_V_ACCUM_INIT,
+ aov0->regs.P23_V_ACCUM_INIT );
+
+ ati128_out32( mmio, OV0_P1_H_ACCUM_INIT,
+ aov0->regs.P1_H_ACCUM_INIT );
+
+ ati128_out32( mmio, OV0_P23_H_ACCUM_INIT,
+ aov0->regs.P23_H_ACCUM_INIT );
+
+ ati128_out32( mmio, OV0_SCALE_CNTL,
+ aov0->regs.SCALE_CNTL );
+
+ ati128_out32( mmio, OV0_REG_LOAD_CNTL, 0 );
+}
+
+static void ov0_calc_regs( ATI128DriverData *adrv,
+ ATIOverlayLayerData *aov0,
+ CoreLayerRegionConfig *config,
+ CoreSurface *surface,
+ CoreSurfaceBufferLock *lock )
+{
+ int h_inc, v_inc, step_by, tmp;
+ int p1_h_accum_init, p23_h_accum_init;
+ int p1_v_accum_init, p23_v_accum_init;
+
+ DFBRegion dstBox;
+ int dst_w;
+ int dst_h;
+ u32 offset_u = 0, offset_v = 0;
+
+ /* destination box */
+ dstBox.x1 = config->dest.x;
+ dstBox.y1 = config->dest.y;
+ dstBox.x2 = config->dest.x + config->dest.w;
+ dstBox.y2 = config->dest.y + config->dest.h;
+
+ /* destination size */
+ dst_w = config->dest.w;
+ dst_h = config->dest.h;
+
+ /* clear everything but the enable bit that may be set*/
+ aov0->regs.SCALE_CNTL &= R128_SCALER_ENABLE;
+
+
+ /* calculate incrementors */
+ h_inc = (surface->config.size.w << 12) / dst_w;
+ v_inc = (surface->config.size.h << 20) / dst_h;
+ step_by = 1;
+
+ while (h_inc >= (2 << 12)) {
+ step_by++;
+ h_inc >>= 1;
+ }
+
+ /* calculate values for horizontal accumulators */
+ tmp = 0x00028000 + (h_inc << 3);
+ p1_h_accum_init = ((tmp << 4) & 0x000f8000) | ((tmp << 12) & 0xf0000000);
+
+ tmp = 0x00028000 + (h_inc << 2);
+ p23_h_accum_init = ((tmp << 4) & 0x000f8000) | ((tmp << 12) & 0x70000000);
+
+ /* calculate values for vertical accumulators */
+ tmp = 0x00018000;
+ p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001;
+
+ tmp = 0x00018000;
+ p23_v_accum_init = ((tmp << 4) & 0x01ff8000) | 0x00000001;
+
+ /* choose pixel format and calculate buffer offsets for planar modes */
+ switch (surface->config.format) {
+ case DSPF_UYVY:
+ aov0->regs.SCALE_CNTL = R128_SCALER_SOURCE_YVYU422;
+ break;
+
+ case DSPF_YUY2:
+ aov0->regs.SCALE_CNTL = R128_SCALER_SOURCE_VYUY422;
+ break;
+
+ case DSPF_I420:
+ aov0->regs.SCALE_CNTL = R128_SCALER_SOURCE_YUV12;
+
+ offset_u = lock->offset +
+ surface->config.size.h * lock->pitch;
+ offset_v = offset_u +
+ (surface->config.size.h >> 1) * (lock->pitch >> 1);
+ break;
+
+ case DSPF_YV12:
+ aov0->regs.SCALE_CNTL = R128_SCALER_SOURCE_YUV12;
+
+ offset_v = lock->offset +
+ surface->config.size.h * lock->pitch;
+ offset_u = offset_v +
+ (surface->config.size.h >> 1) * (lock->pitch >> 1);
+ break;
+
+ default:
+ D_BUG("unexpected pixelformat");
+ aov0->regs.SCALE_CNTL = 0;
+ return;
+ }
+
+ aov0->regs.SCALE_CNTL |= R128_SCALER_DOUBLE_BUFFER |
+ R128_SCALER_BURST_PER_PLANE |
+ R128_SCALER_Y2R_TEMP |
+ R128_SCALER_PIX_EXPAND;
+
+ aov0->regs.H_INC = h_inc | ((h_inc >> 1) << 16);
+ aov0->regs.V_INC = v_inc;
+ aov0->regs.STEP_BY = step_by | (step_by << 8);
+ aov0->regs.Y_X_START = dstBox.x1 | (dstBox.y1 << 16);
+ aov0->regs.Y_X_END = dstBox.x2 | (dstBox.y2 << 16);
+ aov0->regs.P1_BLANK_LINES_AT_TOP = 0x00000fff | ((surface->config.size.h - 1) << 16);
+ aov0->regs.P23_BLANK_LINES_AT_TOP = 0x000007ff | ((((surface->config.size.h + 1) >> 1) - 1) << 16);
+ aov0->regs.VID_BUF_PITCH0_VALUE = lock->pitch;
+ aov0->regs.VID_BUF_PITCH1_VALUE = lock->pitch >> 1;
+ aov0->regs.P1_X_START_END = surface->config.size.w - 1;
+ aov0->regs.P2_X_START_END = (surface->config.size.w >> 1) - 1;
+ aov0->regs.P3_X_START_END = (surface->config.size.w >> 1) - 1;
+ aov0->regs.VID_BUF0_BASE_ADRS = lock->offset & 0x03fffff0;
+ aov0->regs.VID_BUF1_BASE_ADRS = (offset_u & 0x03fffff0) | 1;
+ aov0->regs.VID_BUF2_BASE_ADRS = (offset_v & 0x03fffff0) | 1;
+ aov0->regs.P1_H_ACCUM_INIT = p1_h_accum_init;
+ aov0->regs.P23_H_ACCUM_INIT = p23_h_accum_init;
+ aov0->regs.P1_V_ACCUM_INIT = p1_v_accum_init;
+ aov0->regs.P23_V_ACCUM_INIT = p23_v_accum_init;
+}
+