From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/gfxdrivers/mach64/mach64.c | 1640 ++++++++++++++++++++++++++++ 1 file changed, 1640 insertions(+) create mode 100755 Source/DirectFB/gfxdrivers/mach64/mach64.c (limited to 'Source/DirectFB/gfxdrivers/mach64/mach64.c') diff --git a/Source/DirectFB/gfxdrivers/mach64/mach64.c b/Source/DirectFB/gfxdrivers/mach64/mach64.c new file mode 100755 index 0000000..84fd571 --- /dev/null +++ b/Source/DirectFB/gfxdrivers/mach64/mach64.c @@ -0,0 +1,1640 @@ +/* + (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 + +#include + +#include + + +DFB_GRAPHICS_DRIVER( mach64 ) + + +#include "regs.h" +#include "mmio.h" +#include "mach64_state.h" +#include "mach64.h" + + +/* driver capability flags */ + + +#define MACH64_SUPPORTED_DRAWINGFLAGS \ + (DSDRAW_DST_COLORKEY | DSDRAW_SRC_PREMULTIPLY) + +#define MACH64_SUPPORTED_BLITTINGFLAGS \ + (DSBLIT_SRC_COLORKEY | DSBLIT_DST_COLORKEY) + +#define MACH64_SUPPORTED_DRAWINGFUNCTIONS \ + (DFXL_FILLRECTANGLE | DFXL_DRAWRECTANGLE | DFXL_DRAWLINE) + +#define MACH64_SUPPORTED_BLITTINGFUNCTIONS \ + (DFXL_BLIT) + + +#define MACH64GT_SUPPORTED_DRAWINGFLAGS \ + (DSDRAW_DST_COLORKEY | DSDRAW_BLEND | DSDRAW_SRC_PREMULTIPLY) + +#define MACH64GT_SUPPORTED_BLITTINGFLAGS \ + (DSBLIT_SRC_COLORKEY | DSBLIT_DST_COLORKEY | DSBLIT_BLEND_COLORALPHA | \ + DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE | DSBLIT_DEINTERLACE | \ + DSBLIT_SRC_PREMULTCOLOR) + +#define MACH64GT_SUPPORTED_DRAWINGFUNCTIONS \ + (DFXL_FILLRECTANGLE | DFXL_DRAWRECTANGLE | DFXL_DRAWLINE | DFXL_FILLTRIANGLE) + +#define MACH64GT_SUPPORTED_BLITTINGFUNCTIONS \ + (DFXL_BLIT | DFXL_STRETCHBLIT) + + +static bool mach64DrawLine2D( void *drv, void *dev, DFBRegion *line ); +static bool mach64DrawLine3D( void *drv, void *dev, DFBRegion *line ); + +static bool mach64Blit2D( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ); + +static bool mach64BlitScaleOld( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ); +static bool mach64StretchBlitScaleOld( void *drv, void *dev, DFBRectangle *srect, DFBRectangle *drect ); + +static bool mach64BlitScale( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ); +static bool mach64StretchBlitScale( void *drv, void *dev, DFBRectangle *srect, DFBRectangle *drect ); + +static bool mach64BlitTexOld( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ); +static bool mach64StretchBlitTexOld( void *drv, void *dev, DFBRectangle *srect, DFBRectangle *drect ); + +static bool mach64BlitTex( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ); +static bool mach64StretchBlitTex( void *drv, void *dev, DFBRectangle *srect, DFBRectangle *drect ); + +/* required implementations */ + +static void mach64EngineReset( void *drv, void *dev ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + volatile u8 *mmio = mdrv->mmio_base; + + mach64_waitidle( mdrv, mdev ); + + mach64_waitfifo( mdrv, mdev, 2 ); + + mach64_out32( mmio, DP_WRITE_MSK, 0xFFFFFFFF ); + mach64_out32( mmio, DP_MIX, FRGD_MIX_SRC | BKGD_MIX_DST ); + + if (mdrv->accelerator == FB_ACCEL_ATI_MACH64GT) { + mach64_waitfifo( mdrv, mdev, 12 ); + + /* Some 3D registers aren't accessible without this. */ + mach64_out32( mmio, SCALE_3D_CNTL, SCALE_3D_FCN_SHADE ); + + mach64_out32( mmio, SRC_CNTL, 0 ); + mach64_out32( mmio, Z_CNTL, 0 ); + + mach64_out32( mmio, RED_X_INC, 0 ); + mach64_out32( mmio, RED_Y_INC, 0 ); + mach64_out32( mmio, GREEN_X_INC, 0 ); + mach64_out32( mmio, GREEN_Y_INC, 0 ); + mach64_out32( mmio, BLUE_X_INC, 0 ); + mach64_out32( mmio, BLUE_Y_INC, 0 ); + mach64_out32( mmio, ALPHA_X_INC, 0 ); + mach64_out32( mmio, ALPHA_Y_INC, 0 ); + + mach64_out32( mmio, SCALE_3D_CNTL, 0 ); + } + + if (mdev->chip >= CHIP_3D_RAGE_PRO) + mach64_out32( mmio, HW_DEBUG, mdev->hw_debug ); +} + +static DFBResult mach64EngineSync( void *drv, void *dev ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + mach64_waitidle( mdrv, mdev ); + + return DFB_OK; +} + +static void mach64FlushTextureCache( void *drv, void *dev ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + volatile u8 *mmio = mdrv->mmio_base; + + if (mdev->chip >= CHIP_3D_RAGE_PRO) { + mach64_waitfifo( mdrv, mdev, 1 ); + mach64_out32( mmio, TEX_CNTL, TEX_CACHE_FLUSH ); + } +} + +static bool mach64_use_scaler( Mach64DeviceData *mdev, + CardState *state, DFBAccelerationMask accel ) +{ + if (accel & DFXL_STRETCHBLIT || + state->source->config.format != state->destination->config.format || + state->blittingflags & (DSBLIT_BLEND_COLORALPHA | DSBLIT_DEINTERLACE)) + return true; + + return false; +} + +static bool mach64_use_tex( Mach64DeviceData *mdev, + CardState *state, DFBAccelerationMask accel ) +{ + if (state->blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | + DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR)) + return true; + + /* + * 3D Rage II chips lock up if the scaler is used with destination + * color keying. Using the texture engine works however. + */ + if (mdev->chip < CHIP_3D_RAGE_PRO && + mach64_use_scaler( mdev, state, accel ) && + state->blittingflags & DSBLIT_DST_COLORKEY) + return true; + + return false; +} + +static bool mach64_use_scaler_3d( Mach64DeviceData *mdev, + CardState *state, DFBAccelerationMask accel ) +{ + if (DFB_DRAWING_FUNCTION( accel )) { + if (state->drawingflags & DSDRAW_BLEND) + return true; + } else { + if (accel & DFXL_STRETCHBLIT || + state->source->config.format != state->destination->config.format || + state->blittingflags & (DSBLIT_BLEND_COLORALPHA | DSBLIT_DEINTERLACE | + DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE | + DSBLIT_SRC_PREMULTCOLOR)) + return true; + } + + return false; +} + +static bool mach64_check_blend( Mach64DeviceData *mdev, CardState *state ) +{ + switch (state->src_blend) { + case DSBF_SRCCOLOR: + case DSBF_INVSRCCOLOR: + return false; + case DSBF_DESTALPHA: + case DSBF_INVDESTALPHA: + case DSBF_SRCALPHASAT: + if (mdev->chip < CHIP_3D_RAGE_PRO) + return false; + default: + break; + } + + switch (state->dst_blend) { + case DSBF_DESTCOLOR: + case DSBF_INVDESTCOLOR: + case DSBF_SRCALPHASAT: + return false; + case DSBF_DESTALPHA: + case DSBF_INVDESTALPHA: + if (mdev->chip < CHIP_3D_RAGE_PRO) + return false; + default: + break; + } + + return true; +} + +static void mach64CheckState( void *drv, void *dev, + CardState *state, DFBAccelerationMask accel ) +{ + switch (state->destination->config.format) { + case DSPF_RGB332: + case DSPF_RGB555: + case DSPF_ARGB1555: + case DSPF_RGB16: + case DSPF_RGB32: + case DSPF_ARGB: + break; + default: + return; + } + + if (DFB_DRAWING_FUNCTION( accel )) { + if (state->drawingflags & ~MACH64_SUPPORTED_DRAWINGFLAGS) + return; + + state->accel |= MACH64_SUPPORTED_DRAWINGFUNCTIONS; + } else { + if (state->source->config.format != state->destination->config.format) + return; + + if (state->blittingflags & ~MACH64_SUPPORTED_BLITTINGFLAGS) + return; + + /* Can't do source and destination color keying at the same time. */ + if (state->blittingflags & DSBLIT_SRC_COLORKEY && + state->blittingflags & DSBLIT_DST_COLORKEY) + return; + + state->accel |= MACH64_SUPPORTED_BLITTINGFUNCTIONS; + } +} + +static void mach64GTCheckState( void *drv, void *dev, + CardState *state, DFBAccelerationMask accel ) +{ + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + switch (state->destination->config.format) { + case DSPF_RGB444: + case DSPF_ARGB4444: + /* Not supported. */ + if (mdev->chip < CHIP_3D_RAGE_PRO) + return; + + /* Causes the chip to lock up. */ + if (mdev->chip < CHIP_3D_RAGE_XLXC && + mach64_use_scaler_3d( mdev, state, accel )) + return; + case DSPF_RGB332: + case DSPF_RGB555: + case DSPF_ARGB1555: + case DSPF_RGB16: + case DSPF_RGB32: + case DSPF_ARGB: + break; + default: + return; + } + + if (DFB_DRAWING_FUNCTION( accel )) { + if (state->drawingflags & ~MACH64GT_SUPPORTED_DRAWINGFLAGS) + return; + + if (state->drawingflags & DSDRAW_BLEND && + !mach64_check_blend( mdev, state )) + return; + + /* Causes the chip to lock up. */ + if (state->drawingflags & DSDRAW_BLEND && + state->drawingflags & DSDRAW_DST_COLORKEY) + return; + + state->accel |= MACH64GT_SUPPORTED_DRAWINGFUNCTIONS; + } else { + CoreSurface *source = state->source; + + switch (source->config.format) { + case DSPF_RGB332: + case DSPF_RGB555: + case DSPF_ARGB1555: + case DSPF_RGB444: + case DSPF_ARGB4444: + case DSPF_RGB16: + case DSPF_RGB32: + case DSPF_ARGB: + break; + default: + return; + } + + if (state->blittingflags & ~MACH64GT_SUPPORTED_BLITTINGFLAGS) + return; + + if (state->blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA) && + !mach64_check_blend( mdev, state )) + return; + + /* Can't do alpha modulation. */ + if (state->blittingflags & DSBLIT_BLEND_ALPHACHANNEL && + state->blittingflags & DSBLIT_BLEND_COLORALPHA) + return; + + /* Can't do source and destination color keying at the same time. */ + if (state->blittingflags & DSBLIT_SRC_COLORKEY && + state->blittingflags & DSBLIT_DST_COLORKEY) + return; + + /* Causes the chip to lock up. */ + if (state->blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA) && + state->blittingflags & DSBLIT_DST_COLORKEY) + return; + + if (mach64_use_tex( mdev, state, accel )) { + /* Max texture size is 1024x1024. */ + if (source->config.size.w > 1024 || source->config.size.h > 1024) + return; + + state->accel |= MACH64GT_SUPPORTED_BLITTINGFUNCTIONS; + } else if (mach64_use_scaler( mdev, state, accel )) { + /* Max scaler source size depends on the chip type. */ + if (mdev->chip < CHIP_3D_RAGE_PRO) { + /* Tested on 3D Rage II+ and IIC. */ + if (source->config.size.w > 4095 || source->config.size.h > 4095) + return; + } else { + /* Tested on 3D Rage LT Pro, XL and Mobility. */ + if (source->config.size.w > 4096 || source->config.size.h > 16384) + return; + } + + state->accel |= MACH64GT_SUPPORTED_BLITTINGFUNCTIONS; + } else + state->accel |= accel; + } +} + +static void mach64SetState( void *drv, void *dev, + GraphicsDeviceFuncs *funcs, + CardState *state, DFBAccelerationMask accel ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + volatile u8 *mmio = mdrv->mmio_base; + + if (state->mod_hw == SMF_ALL) { + mdev->valid = 0; + } else if (state->mod_hw) { + if (state->mod_hw & SMF_SOURCE) + MACH64_INVALIDATE( m_source | m_srckey ); + + if (state->mod_hw & SMF_SRC_COLORKEY) + MACH64_INVALIDATE( m_srckey ); + + if (state->mod_hw & SMF_DESTINATION) + MACH64_INVALIDATE( m_color | m_dstkey ); + + if (state->mod_hw & SMF_COLOR) + MACH64_INVALIDATE( m_color ); + + if (state->mod_hw & SMF_DST_COLORKEY) + MACH64_INVALIDATE( m_dstkey ); + + if (state->mod_hw & SMF_BLITTING_FLAGS) + MACH64_INVALIDATE( m_srckey | m_dstkey | m_disable_key ); + + if (state->mod_hw & SMF_DRAWING_FLAGS) + MACH64_INVALIDATE( m_color | m_dstkey | m_disable_key ); + } + + if (state->mod_hw & SMF_DESTINATION) + mach64_set_destination( mdrv, mdev, state ); + + switch (accel) { + case DFXL_FILLRECTANGLE: + case DFXL_DRAWRECTANGLE: + case DFXL_DRAWLINE: + mach64_waitfifo( mdrv, mdev, 2 ); + mach64_out32( mmio, DP_SRC, FRGD_SRC_FRGD_CLR ); + mach64_out32( mmio, DP_PIX_WIDTH, mdev->pix_width ); + + mach64_set_color( mdrv, mdev, state ); + + if (state->drawingflags & DSDRAW_DST_COLORKEY) + mach64_set_dst_colorkey( mdrv, mdev, state ); + else + mach64_disable_colorkey( mdrv, mdev ); + + funcs->DrawLine = mach64DrawLine2D; + + state->set = DFXL_FILLRECTANGLE | DFXL_DRAWRECTANGLE | DFXL_DRAWLINE; + break; + case DFXL_BLIT: + mach64_set_source( mdrv, mdev, state ); + + mach64_waitfifo( mdrv, mdev, 2 ); + mach64_out32( mmio, DP_SRC, FRGD_SRC_BLIT ); + mach64_out32( mmio, DP_PIX_WIDTH, mdev->pix_width ); + + if (state->blittingflags & DSBLIT_DST_COLORKEY) + mach64_set_dst_colorkey( mdrv, mdev, state ); + else if (state->blittingflags & DSBLIT_SRC_COLORKEY) + mach64_set_src_colorkey( mdrv, mdev, state ); + else + mach64_disable_colorkey( mdrv, mdev ); + + funcs->Blit = mach64Blit2D; + + state->set = DFXL_BLIT; + break; + default: + D_BUG( "unexpected drawing/blitting function" ); + break; + } + + if (state->mod_hw & SMF_CLIP) { + mach64_set_clip( mdrv, mdev, state ); + mdev->clip = state->clip; + } + + state->mod_hw = 0; +} + +static void mach64GTSetState( void *drv, void *dev, + GraphicsDeviceFuncs *funcs, + CardState *state, DFBAccelerationMask accel ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + volatile u8 *mmio = mdrv->mmio_base; + + bool use_scaler_3d; + + if (state->mod_hw == SMF_ALL) { + mdev->valid = 0; + } else if (state->mod_hw) { + if (state->mod_hw & SMF_SOURCE) + MACH64_INVALIDATE( m_source | m_source_scale | m_srckey | m_srckey_scale | m_blit_blend ); + + if (state->mod_hw & SMF_SRC_COLORKEY) + MACH64_INVALIDATE( m_srckey | m_srckey_scale ); + + if (state->mod_hw & SMF_DESTINATION) + MACH64_INVALIDATE( m_color | m_dstkey ); + + if (state->mod_hw & SMF_COLOR) + MACH64_INVALIDATE( m_color | m_color_3d | m_color_tex ); + + if (state->mod_hw & SMF_DST_COLORKEY) + MACH64_INVALIDATE( m_dstkey ); + + if (state->mod_hw & SMF_BLITTING_FLAGS) + MACH64_INVALIDATE( m_color_tex | m_source_scale | m_srckey | m_srckey_scale | m_dstkey | m_disable_key | m_blit_blend ); + + if (state->mod_hw & SMF_DRAWING_FLAGS) + MACH64_INVALIDATE( m_color | m_color_3d | m_dstkey | m_disable_key | m_draw_blend ); + + if (state->mod_hw & (SMF_SRC_BLEND | SMF_DST_BLEND)) + MACH64_INVALIDATE( m_draw_blend | m_blit_blend ); + } + + use_scaler_3d = mach64_use_scaler_3d( mdev, state, accel ); + + /* At least 3D Rage II+ and IIC chips _will_ lock up without this. */ + if (mdev->chip < CHIP_3D_RAGE_PRO && use_scaler_3d != mdev->use_scaler_3d) + mach64_waitidle( mdrv, mdev ); + + mdev->use_scaler_3d = use_scaler_3d; + + if (state->mod_hw & SMF_DESTINATION) + mach64gt_set_destination( mdrv, mdev, state ); + + switch (accel) { + case DFXL_FILLRECTANGLE: + case DFXL_DRAWRECTANGLE: + case DFXL_DRAWLINE: + case DFXL_FILLTRIANGLE: + if (use_scaler_3d) { + mach64_waitfifo( mdrv, mdev, 3 ); + /* Some 3D registers aren't accessible without this. */ + mach64_out32( mmio, SCALE_3D_CNTL, SCALE_3D_FCN_SHADE ); + + mach64_out32( mmio, DP_SRC, FRGD_SRC_SCALE ); + mach64_out32( mmio, DP_PIX_WIDTH, mdev->pix_width ); + + mach64_set_color_3d( mdrv, mdev, state ); + + mach64_set_draw_blend( mdrv, mdev, state ); + + mach64_waitfifo( mdrv, mdev, 1 ); + mach64_out32( mmio, SCALE_3D_CNTL, SCALE_3D_FCN_SHADE | mdev->draw_blend ); + + funcs->DrawLine = mach64DrawLine3D; + } else { + mach64_waitfifo( mdrv, mdev, 3 ); + mach64_out32( mmio, SCALE_3D_CNTL, 0 ); + + mach64_out32( mmio, DP_SRC, FRGD_SRC_FRGD_CLR ); + mach64_out32( mmio, DP_PIX_WIDTH, mdev->pix_width ); + + mach64_set_color( mdrv, mdev, state ); + + funcs->DrawLine = mach64DrawLine2D; + } + + if (state->drawingflags & DSDRAW_DST_COLORKEY) + mach64_set_dst_colorkey( mdrv, mdev, state ); + else + mach64_disable_colorkey( mdrv, mdev ); + + state->set = DFXL_FILLRECTANGLE | DFXL_DRAWRECTANGLE | DFXL_DRAWLINE | DFXL_FILLTRIANGLE; + break; + case DFXL_BLIT: + case DFXL_STRETCHBLIT: + mdev->blit_deinterlace = state->blittingflags & DSBLIT_DEINTERLACE; + + if (use_scaler_3d) { + mach64_waitfifo( mdrv, mdev, 1 ); + /* Some 3D registers aren't accessible without this. */ + mach64_out32( mmio, SCALE_3D_CNTL, SCALE_3D_FCN_SHADE ); + + mach64gt_set_source_scale( mdrv, mdev, state ); + + mach64_waitfifo( mdrv, mdev, 2 ); + mach64_out32( mmio, DP_SRC, FRGD_SRC_SCALE ); + mach64_out32( mmio, DP_PIX_WIDTH, mdev->pix_width ); + + if (state->blittingflags & (DSBLIT_BLEND_COLORALPHA | + DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR)) + mach64_set_color_tex( mdrv, mdev, state ); + + mach64_set_blit_blend( mdrv, mdev, state ); + + if (state->blittingflags & DSBLIT_DST_COLORKEY) + mach64_set_dst_colorkey( mdrv, mdev, state ); + else if (state->blittingflags & DSBLIT_SRC_COLORKEY) + mach64_set_src_colorkey_scale( mdrv, mdev, state ); + else + mach64_disable_colorkey( mdrv, mdev ); + + if (mdev->chip < CHIP_3D_RAGE_PRO) { + if (mach64_use_tex( mdev, state, accel )) { + funcs->Blit = mach64BlitTexOld; + funcs->StretchBlit = mach64StretchBlitTexOld; + } else { + funcs->Blit = mach64BlitScaleOld; + funcs->StretchBlit = mach64StretchBlitScaleOld; + } + } else { + if (mach64_use_tex( mdev, state, accel )) { + funcs->Blit = mach64BlitTex; + funcs->StretchBlit = mach64StretchBlitTex; + } else { + funcs->Blit = mach64BlitScale; + funcs->StretchBlit = mach64StretchBlitScale; + } + } + + state->set = DFXL_BLIT | DFXL_STRETCHBLIT; + } else { + mach64_waitfifo( mdrv, mdev, 1 ); + mach64_out32( mmio, SCALE_3D_CNTL, 0 ); + + mach64gt_set_source( mdrv, mdev, state ); + + mach64_waitfifo( mdrv, mdev, 2 ); + mach64_out32( mmio, DP_SRC, FRGD_SRC_BLIT ); + mach64_out32( mmio, DP_PIX_WIDTH, mdev->pix_width ); + + if (state->blittingflags & DSBLIT_DST_COLORKEY) + mach64_set_dst_colorkey( mdrv, mdev, state ); + else if (state->blittingflags & DSBLIT_SRC_COLORKEY) + mach64_set_src_colorkey( mdrv, mdev, state ); + else + mach64_disable_colorkey( mdrv, mdev ); + + funcs->Blit = mach64Blit2D; + + state->set = DFXL_BLIT; + } + break; + default: + D_BUG( "unexpected drawing/blitting function" ); + break; + } + + if (state->mod_hw & SMF_CLIP) { + mach64_set_clip( mdrv, mdev, state ); + mdev->clip = state->clip; + } + + state->mod_hw = 0; +} + +/* */ + +static bool mach64FillRectangle( void *drv, void *dev, DFBRectangle *rect ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + volatile u8 *mmio = mdrv->mmio_base; + + mach64_waitfifo( mdrv, mdev, 3 ); + + mach64_out32( mmio, DST_CNTL, DST_X_DIR | DST_Y_DIR ); + mach64_out32( mmio, DST_Y_X, (S13( rect->x ) << 16) | S14( rect->y ) ); + mach64_out32( mmio, DST_HEIGHT_WIDTH, (rect->w << 16) | rect->h ); + + return true; +} + +static bool mach64DrawRectangle( void *drv, void *dev, DFBRectangle *rect ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + volatile u8 *mmio = mdrv->mmio_base; + + int x2 = rect->x + rect->w - 1; + int y2 = rect->y + rect->h - 1; + + mach64_waitfifo( mdrv, mdev, 8 ); + + mach64_out32( mmio, DST_CNTL, DST_X_DIR | DST_Y_DIR ); + mach64_out32( mmio, DST_Y_X, (S13( rect->x ) << 16) | S14( rect->y ) ); + mach64_out32( mmio, DST_HEIGHT_WIDTH, (1 << 16) | rect->h ); + mach64_out32( mmio, DST_HEIGHT_WIDTH, (rect->w << 16) | 1 ); + + mach64_out32( mmio, DST_CNTL, 0 ); + mach64_out32( mmio, DST_Y_X, (S13( x2 ) << 16) | S14( y2 ) ); + mach64_out32( mmio, DST_HEIGHT_WIDTH, (1 << 16) | rect->h ); + mach64_out32( mmio, DST_HEIGHT_WIDTH, (rect->w << 16) | 1 ); + + return true; +} + +static void mach64_draw_line( Mach64DriverData *mdrv, + Mach64DeviceData *mdev, + int x1, int y1, + int x2, int y2, + bool draw_3d ) +{ + volatile u8 *mmio = mdrv->mmio_base; + + u32 dst_cntl = 0; + int dx, dy; + + dx = x2 - x1; + dy = y2 - y1; + + if (dx < 0) + dx = -dx; + else + dst_cntl |= DST_X_DIR; + + if (dy < 0) + dy = -dy; + else + dst_cntl |= DST_Y_DIR; + + if (!dx || !dy) { + /* horizontal / vertical line */ + mach64_waitfifo( mdrv, mdev, 3 ); + + mach64_out32( mmio, DST_CNTL, dst_cntl); + mach64_out32( mmio, DST_Y_X, (S13( x1 ) << 16) | S14( y1 ) ); + mach64_out32( mmio, DST_HEIGHT_WIDTH, ((dx+1) << 16) | (dy+1) ); + + return; + } + + if (dx < dy) { + int tmp = dx; + dx = dy; + dy = tmp; + dst_cntl |= DST_Y_MAJOR; + } + + mach64_waitfifo( mdrv, mdev, 6 ); + + mach64_out32( mmio, DST_CNTL, DST_LAST_PEL | dst_cntl ); + mach64_out32( mmio, DST_Y_X, (S13( x1 ) << 16) | S14( y1 ) ); + + /* Bresenham parameters must be calculated differently + * for the 2D and 3D engines. + */ + if (draw_3d) { + mach64_out32( mmio, DST_BRES_ERR, -dx ); + mach64_out32( mmio, DST_BRES_INC, 2*dy ); + mach64_out32( mmio, DST_BRES_DEC, -2*dx ); + mach64_out32( mmio, DST_BRES_LNTH, dx+1 ); + } else { + mach64_out32( mmio, DST_BRES_ERR, 2*dy-dx ); + mach64_out32( mmio, DST_BRES_INC, 2*dy ); + mach64_out32( mmio, DST_BRES_DEC, 2*dy-2*dx ); + mach64_out32( mmio, DST_BRES_LNTH, dx+1 ); + } +} + +static bool mach64DrawLine2D( void *drv, void *dev, DFBRegion *line ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + mach64_draw_line( mdrv, mdev, + line->x1, line->y1, + line->x2, line->y2, + false ); + + return true; +} + +static bool mach64DrawLine3D( void *drv, void *dev, DFBRegion *line ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + mach64_draw_line( mdrv, mdev, + line->x1, line->y1, + line->x2, line->y2, + true ); + + return true; +} + +static void mach64_fill_trapezoid( Mach64DriverData *mdrv, + Mach64DeviceData *mdev, + int X1l, int X1r, + int X2l, int X2r, + int Y, int dY ) +{ + volatile u8 *mmio = mdrv->mmio_base; + + u32 dst_cntl; + int dXl, dXr; + + X1r++; X2r++; + + dst_cntl = DST_Y_DIR | TRAP_FILL_DIR; + + dXl = X2l - X1l; + if (dXl < 0) + dXl = -dXl; + else + dst_cntl |= DST_X_DIR; + + dXr = X2r - X1r; + if (dXr < 0) + dXr = -dXr; + else + dst_cntl |= TRAIL_X_DIR; + + mach64_waitfifo( mdrv, mdev, 9 ); + + mach64_out32( mmio, DST_CNTL, dst_cntl ); + mach64_out32( mmio, DST_Y_X, (S13( X1l ) << 16) | S14( Y ) ); + + mach64_out32( mmio, LEAD_BRES_ERR, -dY ); + mach64_out32( mmio, LEAD_BRES_INC, 2*dXl ); + mach64_out32( mmio, LEAD_BRES_DEC, -2*dY ); + + mach64_out32( mmio, TRAIL_BRES_ERR, -dY ); + mach64_out32( mmio, TRAIL_BRES_INC, 2*dXr ); + mach64_out32( mmio, TRAIL_BRES_DEC, -2*dY ); + + mach64_out32( mmio, LEAD_BRES_LNTH, (S14( X1r ) << 16) | (dY+1) | DRAW_TRAP | LINE_DIS ); +} + +static bool mach64FillTriangle( void *drv, void *dev, DFBTriangle *tri ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + dfb_sort_triangle( tri ); + + if (tri->y2 == tri->y3) { + mach64_fill_trapezoid( mdrv, mdev, + tri->x1, tri->x1, + MIN( tri->x2, tri->x3), MAX( tri->x2, tri->x3 ), + tri->y1, tri->y3 - tri->y1 ); + } else if (tri->y1 == tri->y2) { + mach64_fill_trapezoid( mdrv, mdev, + MIN( tri->x1, tri->x2), MAX( tri->x1, tri->x2 ), + tri->x3, tri->x3, + tri->y1, tri->y3 - tri->y1 ); + } else { + int majDx = tri->x3 - tri->x1; + int majDy = tri->y3 - tri->y1; + int topDx = tri->x2 - tri->x1; + int topDy = tri->y2 - tri->y1; + int botDy = tri->y3 - tri->y2; + + int topXperY = (topDx << 20) / topDy; + int X2a = tri->x1 + (((topXperY * topDy) + (1<<19)) >> 20); + + int majXperY = (majDx << 20) / majDy; + int majX2 = tri->x1 + (((majXperY * topDy) + (1<<19)) >> 20); + int majX2a = majX2 - ((majXperY + (1<<19)) >> 20); + + mach64_fill_trapezoid( mdrv, mdev, + tri->x1, tri->x1, + MIN( X2a, majX2a ), MAX( X2a, majX2a ), + tri->y1, topDy - 1 ); + mach64_fill_trapezoid( mdrv, mdev, + MIN( tri->x2, majX2 ), MAX( tri->x2, majX2 ), + tri->x3, tri->x3, + tri->y2, botDy ); + } + + return true; +} + +static void mach64DoBlit2D( Mach64DriverData *mdrv, + Mach64DeviceData *mdev, + DFBRectangle *srect, + DFBRectangle *drect ) +{ + volatile u8 *mmio = mdrv->mmio_base; + + u32 dst_cntl = 0; + + if (srect->x <= drect->x) { + srect->x += srect->w - 1; + drect->x += drect->w - 1; + } else + dst_cntl |= DST_X_DIR; + + if (srect->y <= drect->y) { + srect->y += srect->h - 1; + drect->y += drect->h - 1; + } else + dst_cntl |= DST_Y_DIR; + + mach64_waitfifo( mdrv, mdev, 5 ); + + mach64_out32( mmio, SRC_Y_X, (S13( srect->x ) << 16) | S14( srect->y ) ); + mach64_out32( mmio, SRC_HEIGHT1_WIDTH1, (srect->w << 16) | srect->h ); + + mach64_out32( mmio, DST_CNTL, dst_cntl ); + mach64_out32( mmio, DST_Y_X, (S13( drect->x ) << 16) | S14( drect->y ) ); + mach64_out32( mmio, DST_HEIGHT_WIDTH, (drect->w << 16) | drect->h ); +} + +static void mach64DoBlitScaleOld( Mach64DriverData *mdrv, + Mach64DeviceData *mdev, + DFBRectangle *srect, + DFBRectangle *drect, + bool filter ) +{ + volatile u8 *mmio = mdrv->mmio_base; + CoreSurface *source = mdev->source; + + u32 scale_3d_cntl = SCALE_3D_FCN_SCALE | mdev->blit_blend; + int hacc, vacc; + + if (!filter) + scale_3d_cntl |= SCALE_PIX_REP; + + if (mdev->blit_deinterlace) { + srect->y /= 2; + srect->h /= 2; + } + + srect->x <<= 16; + srect->y <<= 16; + srect->w <<= 16; + srect->h <<= 16; + + /* + * SCALE_HACC and SCALE_VACC have limited scale so we need to change + * SCALE_Y_OFF in order to handle the full range of source coordinates. + */ + hacc = srect->x & 0xFFFF0; /* s4.12 */ + vacc = srect->y & 0xFFFF0; /* s4.12 */ + srect->x &= ~0xFFFFF; + srect->y &= ~0xFFFFF; + + mach64_waitfifo( mdrv, mdev, 14 ); + + mach64_out32( mmio, SCALE_3D_CNTL, scale_3d_cntl ); + mach64_out32( mmio, SCALE_Y_OFF, mdev->scale_offset + + (srect->y >> 16) * mdev->scale_pitch + + (srect->x >> 16) * DFB_BYTES_PER_PIXEL( source->config.format ) ); + + + mach64_out32( mmio, SCALE_WIDTH, (srect->w + hacc) >> 16 ); + mach64_out32( mmio, SCALE_HEIGHT, (srect->h + vacc) >> 16 ); + + mach64_out32( mmio, SCALE_Y_PITCH, mdev->scale_pitch / DFB_BYTES_PER_PIXEL( source->config.format ) ); + + mach64_out32( mmio, SCALE_X_INC, srect->w / drect->w ); + mach64_out32( mmio, SCALE_Y_INC, srect->h / drect->h ); + + if (mdev->blit_deinterlace && mdev->field) + vacc += 0x8000; + + mach64_out32( mmio, SCALE_VACC, vacc ); + mach64_out32( mmio, SCALE_HACC, hacc ); + mach64_out32( mmio, SCALE_XUV_INC, (srect->w/2) / (drect->w/2) ); + mach64_out32( mmio, SCALE_UV_HACC, hacc >> 1 ); + + mach64_out32( mmio, DST_CNTL, DST_X_DIR | DST_Y_DIR ); + mach64_out32( mmio, DST_Y_X, (S13( drect->x ) << 16) | S14( drect->y ) ); + mach64_out32( mmio, DST_HEIGHT_WIDTH, (drect->w << 16) | drect->h ); + + /* Some scaler and 3D color registers are shared. */ + MACH64_INVALIDATE( m_color_3d | m_color_tex ); +} + +static void mach64DoBlitScale( Mach64DriverData *mdrv, + Mach64DeviceData *mdev, + DFBRectangle *srect, + DFBRectangle *drect, + bool filter ) +{ + volatile u8 *mmio = mdrv->mmio_base; + CoreSurface *source = mdev->source; + + u32 scale_3d_cntl = SCALE_3D_FCN_SCALE | mdev->blit_blend; + int hacc, vacc; + + if (!filter) + scale_3d_cntl |= SCALE_PIX_REP; + + if (mdev->blit_deinterlace) { + srect->y /= 2; + srect->h /= 2; + } + + srect->x <<= 16; + srect->y <<= 16; + srect->w <<= 16; + srect->h <<= 16; + + /* Hardware bug: Hitting SC_TOP results in incorrect rendering. */ + if (drect->y < mdev->clip.y1) { + int sy, dy; + dy = mdev->clip.y1 - drect->y; + sy = (u64) srect->h * dy / drect->h; + srect->y += sy; + srect->h -= sy; + drect->y += dy; + drect->h -= dy; + } + + /* + * SCALE_HACC and SCALE_VACC have limited scale so we need to change + * SCALE_OFF in order to handle the full range of source coordinates. + */ + hacc = srect->x & 0xFFFFF0; /* s8.12 */ + vacc = srect->y & 0xFFFF0; /* s4.12 */ + srect->x &= ~0xFFFFFF; + srect->y &= ~0xFFFFF; + + mach64_waitfifo( mdrv, mdev, 12 ); + + mach64_out32( mmio, SCALE_3D_CNTL, scale_3d_cntl ); + mach64_out32( mmio, SCALE_OFF, mdev->scale_offset + + (srect->y >> 16) * mdev->scale_pitch + + (srect->x >> 16) * DFB_BYTES_PER_PIXEL( source->config.format ) ); + + mach64_out32( mmio, SCALE_WIDTH, (srect->w + hacc) >> 16 ); + mach64_out32( mmio, SCALE_HEIGHT, (srect->h + vacc) >> 16 ); + + mach64_out32( mmio, SCALE_PITCH, mdev->scale_pitch / DFB_BYTES_PER_PIXEL( source->config.format ) ); + + mach64_out32( mmio, SCALE_X_INC, srect->w / drect->w ); + mach64_out32( mmio, SCALE_Y_INC, srect->h / drect->h ); + + if (mdev->blit_deinterlace && mdev->field) + vacc += 0x8000; + + mach64_out32( mmio, SCALE_VACC, vacc ); + mach64_out32( mmio, SCALE_HACC, hacc ); + + mach64_out32( mmio, DST_CNTL, DST_X_DIR | DST_Y_DIR ); + mach64_out32( mmio, DST_Y_X, (S13( drect->x ) << 16) | S14( drect->y ) ); + mach64_out32( mmio, DST_HEIGHT_WIDTH, (drect->w << 16) | drect->h ); + + /* Some scaler and 3D color registers are shared. */ + MACH64_INVALIDATE( m_color_3d | m_color_tex ); +} + +static void mach64DoBlitTexOld( Mach64DriverData *mdrv, + Mach64DeviceData *mdev, + DFBRectangle *srect, + DFBRectangle *drect, + bool filter ) +{ + volatile u8 *mmio = mdrv->mmio_base; + + u32 scale_3d_cntl = SCALE_3D_FCN_TEXTURE | MIP_MAP_DISABLE | mdev->blit_blend; + + if (mdev->blit_deinterlace) { + srect->y /= 2; + srect->h /= 2; + } + + srect->x <<= 1; + srect->y <<= 1; + srect->w <<= 1; + srect->h <<= 1; + + /* Must add 0.5 to get correct rendering. */ + srect->x += 0x1; + srect->y += 0x1; + + if (filter) { + /* Avoid using texels outside of texture. */ + srect->w -= 0x2; + srect->h -= 0x2; + + scale_3d_cntl |= BILINEAR_TEX_EN | TEX_BLEND_FCN_LINEAR_MIPMAP_NEAREST; + } + + if (mdev->blit_deinterlace && mdev->field) + srect->y += 0x1; + + mach64_waitfifo( mdrv, mdev, 14 ); + + mach64_out32( mmio, SCALE_3D_CNTL, scale_3d_cntl ); + mach64_out32( mmio, TEX_0_OFF + (mdev->tex_size << 2), mdev->tex_offset ); + + mach64_out32( mmio, S_X_INC2, 0 ); + mach64_out32( mmio, S_Y_INC2, 0 ); + mach64_out32( mmio, S_XY_INC2, 0 ); + mach64_out32( mmio, S_X_INC_START, (srect->w << (25 - mdev->tex_size)) / drect->w ); + mach64_out32( mmio, S_Y_INC, 0 ); + mach64_out32( mmio, S_START, (srect->x << (25 - mdev->tex_size)) ); + + mach64_out32( mmio, T_X_INC2, 0 ); + mach64_out32( mmio, T_Y_INC2, 0 ); + mach64_out32( mmio, T_XY_INC2, 0 ); + mach64_out32( mmio, T_X_INC_START, 0 ); + mach64_out32( mmio, T_Y_INC, (srect->h << (25 - mdev->tex_size)) / drect->h ); + mach64_out32( mmio, T_START, (srect->y << (25 - mdev->tex_size)) ); + + mach64_waitfifo( mdrv, mdev, 3 ); + + mach64_out32( mmio, DST_CNTL, DST_X_DIR | DST_Y_DIR ); + mach64_out32( mmio, DST_Y_X, (S13( drect->x ) << 16) | S14( drect->y ) ); + mach64_out32( mmio, DST_HEIGHT_WIDTH, (drect->w << 16) | drect->h ); +} + +static void mach64DoBlitTex( Mach64DriverData *mdrv, + Mach64DeviceData *mdev, + DFBRectangle *srect, + DFBRectangle *drect, + bool filter ) +{ + volatile u8 *mmio = mdrv->mmio_base; + + u32 scale_3d_cntl = SCALE_3D_FCN_TEXTURE | MIP_MAP_DISABLE | mdev->blit_blend; + + if (mdev->blit_deinterlace) { + srect->y /= 2; + srect->h /= 2; + } + + srect->x <<= 1; + srect->y <<= 1; + srect->w <<= 1; + srect->h <<= 1; + + /* Must add 0.5 to get correct rendering. */ + srect->x += 0x1; + srect->y += 0x1; + + if (filter) { + /* Avoid using texels outside of texture. */ + srect->w -= 0x2; + srect->h -= 0x2; + + scale_3d_cntl |= BILINEAR_TEX_EN | TEX_BLEND_FCN_LINEAR_MIPMAP_NEAREST; + } + + if (mdev->blit_deinterlace && mdev->field) + srect->y += 0x1; + + mach64_waitfifo( mdrv, mdev, 13 ); + + mach64_out32( mmio, SCALE_3D_CNTL, scale_3d_cntl ); + mach64_out32( mmio, TEX_0_OFF + (mdev->tex_size << 2), mdev->tex_offset ); + + mach64_out32( mmio, STW_EXP, (1 << 16) | (0 << 8) | (0 << 0) ); + + /* This register doesn't seem to have any effect on the result. */ + mach64_out32( mmio, LOG_MAX_INC, 0 ); + + mach64_out32( mmio, S_X_INC, (srect->w << (23 - mdev->tex_pitch)) / drect->w ); + mach64_out32( mmio, S_Y_INC, 0 ); + mach64_out32( mmio, S_START, (srect->x << (23 - mdev->tex_pitch)) ); + + mach64_out32( mmio, W_X_INC, 0 ); + mach64_out32( mmio, W_Y_INC, 0 ); + mach64_out32( mmio, W_START, 1 << 23 ); + + mach64_out32( mmio, T_X_INC, 0 ); + mach64_out32( mmio, T_Y_INC, (srect->h << (23 - mdev->tex_height)) / drect->h ); + mach64_out32( mmio, T_START, (srect->y << (23 - mdev->tex_height)) ); + + mach64_waitfifo( mdrv, mdev, 3 ); + + mach64_out32( mmio, DST_CNTL, DST_X_DIR | DST_Y_DIR ); + mach64_out32( mmio, DST_Y_X, (S13( drect->x ) << 16) | S14( drect->y ) ); + mach64_out32( mmio, DST_HEIGHT_WIDTH, (drect->w << 16) | drect->h ); +} + +static bool mach64Blit2D( void *drv, void *dev, + DFBRectangle *rect, int dx, int dy ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + DFBRectangle drect = { dx, dy, rect->w, rect->h }; + + mach64DoBlit2D( mdrv, mdev, rect, &drect ); + + return true; +} + +static bool mach64BlitScaleOld( void *drv, void *dev, + DFBRectangle *rect, int dx, int dy ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + DFBRectangle drect = { dx, dy, rect->w, rect->h }; + + mach64DoBlitScaleOld( mdrv, mdev, rect, &drect, mdev->blit_deinterlace ); + + return true; +} + +static bool mach64StretchBlitScaleOld( void *drv, void *dev, + DFBRectangle *srect, DFBRectangle *drect ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + mach64DoBlitScaleOld( mdrv, mdev, srect, drect, true ); + + return true; +} + +static bool mach64BlitScale( void *drv, void *dev, + DFBRectangle *rect, int dx, int dy ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + DFBRectangle drect = { dx, dy, rect->w, rect->h }; + + mach64DoBlitScale( mdrv, mdev, rect, &drect, mdev->blit_deinterlace ); + + return true; +} + +static bool mach64StretchBlitScale( void *drv, void *dev, + DFBRectangle *srect, DFBRectangle *drect ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + mach64DoBlitScale( mdrv, mdev, srect, drect, true ); + + return true; +} + +static bool mach64BlitTexOld( void *drv, void *dev, + DFBRectangle *rect, int dx, int dy ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + DFBRectangle drect = { dx, dy, rect->w, rect->h }; + + mach64DoBlitTexOld( mdrv, mdev, rect, &drect, mdev->blit_deinterlace ); + + return true; +} + +static bool mach64StretchBlitTexOld( void *drv, void *dev, + DFBRectangle *srect, DFBRectangle *drect ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + mach64DoBlitTexOld( mdrv, mdev, srect, drect, true ); + + return true; +} + +static bool mach64BlitTex( void *drv, void *dev, + DFBRectangle *rect, int dx, int dy ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + DFBRectangle drect = { dx, dy, rect->w, rect->h }; + + mach64DoBlitTex( mdrv, mdev, rect, &drect, mdev->blit_deinterlace ); + + return true; +} + +static bool mach64StretchBlitTex( void *drv, void *dev, + DFBRectangle *srect, DFBRectangle *drect ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) drv; + Mach64DeviceData *mdev = (Mach64DeviceData*) dev; + + mach64DoBlitTex( mdrv, mdev, srect, drect, true ); + + return true; +} + +/* */ + +#define MACH64_CFG_CHIP_TYPE( a, b ) (((a) << 8) | (b)) + +static Mach64ChipType +mach64_chip_type_vt( Mach64DriverData *mdrv, + GraphicsDeviceInfo *device_info ) +{ + u32 config_chip_id = mach64_in32( mdrv->mmio_base, CONFIG_CHIP_ID ); + u32 cfg_chip_type = config_chip_id & CFG_CHIP_TYPE; + + switch (cfg_chip_type) { + case MACH64_CFG_CHIP_TYPE( 'V', 'T' ): + switch ((config_chip_id & CFG_CHIP_MAJOR) >> 24) { + case 0: + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, + (config_chip_id & CFG_CHIP_MINOR) ? "ATI-264VT2 (%c%c)" : "ATI-264VT (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_264VT; + case 1: + case 2: + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "ATI-264VT3 (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_264VT3; + } + break; + case MACH64_CFG_CHIP_TYPE( 'V', 'U' ): + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "ATI-264VT3 (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_264VT3; + case MACH64_CFG_CHIP_TYPE( 'V', 'V' ): + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "ATI-264VT4 (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_264VT4; + } + D_WARN( "DirectFB/Mach64: Unknown VT chip type %c%c (0x%08x)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF, config_chip_id ); + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "Mach64 VT" ); + return CHIP_UNKNOWN; +} + +static Mach64ChipType +mach64_chip_type_gt( Mach64DriverData *mdrv, + GraphicsDeviceInfo *device_info ) +{ + u32 config_chip_id = mach64_in32( mdrv->mmio_base, CONFIG_CHIP_ID ); + u32 cfg_chip_type = config_chip_id & CFG_CHIP_TYPE; + + switch (cfg_chip_type) { + case MACH64_CFG_CHIP_TYPE( 'G', 'T' ): + switch ((config_chip_id & CFG_CHIP_MAJOR) >> 24) { + case 0: + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_3D_RAGE; + case 1: + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage II (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_3D_RAGE_II; + case 2: + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage II+ (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_3D_RAGE_IIPLUS; + } + break; + case MACH64_CFG_CHIP_TYPE( 'G', 'U' ): + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage II+ (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_3D_RAGE_IIPLUS; + case MACH64_CFG_CHIP_TYPE( 'L', 'G' ): + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage LT (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_3D_RAGE_LT; + case MACH64_CFG_CHIP_TYPE( 'G', 'V' ): + case MACH64_CFG_CHIP_TYPE( 'G', 'W' ): + case MACH64_CFG_CHIP_TYPE( 'G', 'Y' ): + case MACH64_CFG_CHIP_TYPE( 'G', 'Z' ): + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage IIC (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_3D_RAGE_IIC; + case MACH64_CFG_CHIP_TYPE( 'G', 'B' ): + case MACH64_CFG_CHIP_TYPE( 'G', 'D' ): + case MACH64_CFG_CHIP_TYPE( 'G', 'I' ): + case MACH64_CFG_CHIP_TYPE( 'G', 'P' ): + case MACH64_CFG_CHIP_TYPE( 'G', 'Q' ): + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage Pro (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_3D_RAGE_PRO; + case MACH64_CFG_CHIP_TYPE( 'L', 'B' ): + case MACH64_CFG_CHIP_TYPE( 'L', 'D' ): + case MACH64_CFG_CHIP_TYPE( 'L', 'I' ): + case MACH64_CFG_CHIP_TYPE( 'L', 'P' ): + case MACH64_CFG_CHIP_TYPE( 'L', 'Q' ): + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage LT Pro (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_3D_RAGE_LT_PRO; + case MACH64_CFG_CHIP_TYPE( 'G', 'M' ): + case MACH64_CFG_CHIP_TYPE( 'G', 'O' ): + case MACH64_CFG_CHIP_TYPE( 'G', 'R' ): + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage XL (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_3D_RAGE_XLXC; + case MACH64_CFG_CHIP_TYPE( 'G', 'L' ): + case MACH64_CFG_CHIP_TYPE( 'G', 'N' ): + case MACH64_CFG_CHIP_TYPE( 'G', 'S' ): + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage XC (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_3D_RAGE_XLXC; + case MACH64_CFG_CHIP_TYPE( 'L', 'M' ): + case MACH64_CFG_CHIP_TYPE( 'L', 'N' ): + case MACH64_CFG_CHIP_TYPE( 'L', 'R' ): + case MACH64_CFG_CHIP_TYPE( 'L', 'S' ): + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage Mobility (%c%c)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF ); + return CHIP_3D_RAGE_MOBILITY; + } + D_WARN( "DirectFB/Mach64: Unknown GT chip type %c%c (0x%08x)", + cfg_chip_type >> 8, cfg_chip_type & 0xFF, config_chip_id ); + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "Mach64 GT" ); + return CHIP_UNKNOWN; +} + +/* exported symbols */ + +static int +driver_probe( CoreGraphicsDevice *device ) +{ + switch (dfb_gfxcard_get_accelerator( device )) { + case FB_ACCEL_ATI_MACH64GX: + case FB_ACCEL_ATI_MACH64CT: + case FB_ACCEL_ATI_MACH64VT: + case FB_ACCEL_ATI_MACH64GT: + 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, + "ATI Mach64 Driver" ); + + snprintf( info->vendor, + DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH, + "Ville Syrjala" ); + + info->version.major = 0; + info->version.minor = 13; + + info->driver_data_size = sizeof (Mach64DriverData); + info->device_data_size = sizeof (Mach64DeviceData); +} + +static DFBResult +driver_init_driver( CoreGraphicsDevice *device, + GraphicsDeviceFuncs *funcs, + void *driver_data, + void *device_data, + CoreDFB *core ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) driver_data; + + mdrv->mmio_base = (volatile u8*) dfb_gfxcard_map_mmio( device, 0, -1 ); + if (!mdrv->mmio_base) + return DFB_IO; + + mdrv->device_data = (Mach64DeviceData*) device_data; + + mdrv->accelerator = dfb_gfxcard_get_accelerator( device ); + + funcs->EngineReset = mach64EngineReset; + funcs->EngineSync = mach64EngineSync; + funcs->CheckState = mach64CheckState; + funcs->SetState = mach64SetState; + funcs->FillRectangle = mach64FillRectangle; + funcs->DrawRectangle = mach64DrawRectangle; + + /* Set dynamically: funcs->DrawLine, funcs->Blit, funcs->StretchBlit */ + + switch (mdrv->accelerator) { + case FB_ACCEL_ATI_MACH64GT: + if (!dfb_config->font_format) + dfb_config->font_format = DSPF_ARGB; + funcs->FlushTextureCache = mach64FlushTextureCache; + funcs->CheckState = mach64GTCheckState; + funcs->SetState = mach64GTSetState; + funcs->FillTriangle = mach64FillTriangle; + case FB_ACCEL_ATI_MACH64VT: + mdrv->mmio_base += 0x400; + + dfb_layers_register( dfb_screens_at( DSCID_PRIMARY ), + driver_data, &mach64OverlayFuncs ); + break; + } + + return DFB_OK; +} + +static DFBResult +driver_init_device( CoreGraphicsDevice *device, + GraphicsDeviceInfo *device_info, + void *driver_data, + void *device_data ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) driver_data; + Mach64DeviceData *mdev = (Mach64DeviceData*) device_data; + volatile u8 *mmio = mdrv->mmio_base; + + /* fill device info */ + device_info->caps.flags = CCF_CLIPPING; + + switch (mdrv->accelerator) { + case FB_ACCEL_ATI_MACH64GT: + device_info->caps.drawing = MACH64GT_SUPPORTED_DRAWINGFLAGS; + device_info->caps.blitting = MACH64GT_SUPPORTED_BLITTINGFLAGS; + device_info->caps.accel = MACH64GT_SUPPORTED_DRAWINGFUNCTIONS | + MACH64GT_SUPPORTED_BLITTINGFUNCTIONS; + break; + default: + device_info->caps.drawing = MACH64_SUPPORTED_DRAWINGFLAGS; + device_info->caps.blitting = MACH64_SUPPORTED_BLITTINGFLAGS; + device_info->caps.accel = MACH64_SUPPORTED_DRAWINGFUNCTIONS | + MACH64_SUPPORTED_BLITTINGFUNCTIONS; + break; + } + + switch (mdrv->accelerator) { + case FB_ACCEL_ATI_MACH64GX: + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "Mach64 GX" ); + break; + case FB_ACCEL_ATI_MACH64CT: + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "Mach64 CT" ); + break; + case FB_ACCEL_ATI_MACH64VT: + mdev->chip = mach64_chip_type_vt( mdrv, device_info ); + break; + case FB_ACCEL_ATI_MACH64GT: + mdev->chip = mach64_chip_type_gt( mdrv, device_info ); + + /* Max texture size is 1024x1024 */ + device_info->limits.surface_max_power_of_two_pixelpitch = 1024; + device_info->limits.surface_max_power_of_two_height = 1024; + break; + } + + snprintf( device_info->vendor, + DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "ATI" ); + + device_info->limits.surface_byteoffset_alignment = 8; + device_info->limits.surface_bytepitch_alignment = 16; + device_info->limits.surface_pixelpitch_alignment = 8; + + /* 3D Rage Pro is the first chip that supports auto fast fill/block write. */ + if (mdev->chip >= CHIP_3D_RAGE_PRO) { + mdev->hw_debug = mach64_in32( mmio, HW_DEBUG ); + + /* Save original HW_DEBUG. */ + mdev->hw_debug_orig = mdev->hw_debug; + + /* Enable auto fast fill and fast fill/block write scissoring. */ + mdev->hw_debug &= ~(AUTO_FF_DIS | INTER_PRIM_DIS); + + if ((mach64_in32( mmio, CONFIG_STAT0 ) & CFG_MEM_TYPE) == CFG_MEM_TYPE_SGRAM) { + /* Enable auto block write and auto color register updates. */ + mdev->hw_debug &= ~(AUTO_BLKWRT_DIS | AUTO_BLKWRT_COLOR_DIS); + + device_info->limits.surface_byteoffset_alignment = 64; + device_info->limits.surface_bytepitch_alignment = 64; + } + } + + return DFB_OK; +} + +static void +driver_close_device( CoreGraphicsDevice *device, + void *driver_data, + void *device_data ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) driver_data; + Mach64DeviceData *mdev = (Mach64DeviceData*) device_data; + volatile u8 *mmio = mdrv->mmio_base; + + D_DEBUG( "DirectFB/Mach64: FIFO Performance Monitoring:\n" ); + D_DEBUG( "DirectFB/Mach64: %9d mach64_waitfifo calls\n", + mdev->waitfifo_calls ); + D_DEBUG( "DirectFB/Mach64: %9d register writes (mach64_waitfifo sum)\n", + mdev->waitfifo_sum ); + D_DEBUG( "DirectFB/Mach64: %9d FIFO wait cycles (depends on CPU)\n", + mdev->fifo_waitcycles ); + D_DEBUG( "DirectFB/Mach64: %9d IDLE wait cycles (depends on CPU)\n", + mdev->idle_waitcycles ); + D_DEBUG( "DirectFB/Mach64: %9d FIFO space cache hits(depends on CPU)\n", + mdev->fifo_cache_hits ); + D_DEBUG( "DirectFB/Mach64: Conclusion:\n" ); + D_DEBUG( "DirectFB/Mach64: Average register writes/mach64_waitfifo" + "call:%.2f\n", + mdev->waitfifo_sum/(float)(mdev->waitfifo_calls) ); + D_DEBUG( "DirectFB/Mach64: Average wait cycles/mach64_waitfifo call:" + " %.2f\n", + mdev->fifo_waitcycles/(float)(mdev->waitfifo_calls) ); + D_DEBUG( "DirectFB/Mach64: Average fifo space cache hits: %02d%%\n", + (int)(100 * mdev->fifo_cache_hits/ + (float)(mdev->waitfifo_calls)) ); + + switch (mdrv->accelerator) { + case FB_ACCEL_ATI_MACH64GT: + mach64_waitfifo( mdrv, mdev, 1 ); + mach64_out32( mmio, SCALE_3D_CNTL, 0 ); + case FB_ACCEL_ATI_MACH64VT: + mach64_waitfifo( mdrv, mdev, 1 ); + mach64_out32( mmio, OVERLAY_SCALE_CNTL, 0 ); + break; + } + + if (mdev->chip >= CHIP_3D_RAGE_PRO) { + /* Restore original HW_DEBUG. */ + mach64_out32( mmio, HW_DEBUG, mdev->hw_debug_orig ); + } +} + +static void +driver_close_driver( CoreGraphicsDevice *device, + void *driver_data ) +{ + Mach64DriverData *mdrv = (Mach64DriverData*) driver_data; + + switch (mdrv->accelerator) { + case FB_ACCEL_ATI_MACH64VT: + case FB_ACCEL_ATI_MACH64GT: + mdrv->mmio_base -= 0x400; + break; + } + + dfb_gfxcard_unmap_mmio( device, mdrv->mmio_base, -1 ); +} -- cgit