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/radeon/radeon.c | 1753 ++++++++++++++++++++++++++++ 1 file changed, 1753 insertions(+) create mode 100755 Source/DirectFB/gfxdrivers/radeon/radeon.c (limited to 'Source/DirectFB/gfxdrivers/radeon/radeon.c') diff --git a/Source/DirectFB/gfxdrivers/radeon/radeon.c b/Source/DirectFB/gfxdrivers/radeon/radeon.c new file mode 100755 index 0000000..19f8c49 --- /dev/null +++ b/Source/DirectFB/gfxdrivers/radeon/radeon.c @@ -0,0 +1,1753 @@ +/* + * Copyright (C) 2006 Claudio Ciccani + * + * Graphics driver for ATI Radeon cards written by + * 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 + +#include +#include + +#include + +DFB_GRAPHICS_DRIVER( radeon ) + + +#include "radeon.h" +#include "radeon_chipsets.h" +#include "radeon_regs.h" +#include "radeon_mmio.h" +#include "radeon_state.h" +#include "radeon_2d.h" +#include "radeon_3d.h" + + +/* Enable the following option if you see strange behaviours */ +#define RESET_AFTER_SETVAR 0 + + +/* Driver capability flags */ +#define RADEON_SUPPORTED_2D_DRAWINGFLAGS \ + ( DSDRAW_XOR ) + +#define RADEON_SUPPORTED_2D_DRAWINGFUNCS \ + ( DFXL_FILLRECTANGLE | DFXL_DRAWRECTANGLE | DFXL_DRAWLINE ) + +#define RADEON_SUPPORTED_2D_BLITTINGFLAGS \ + ( DSBLIT_XOR | DSBLIT_SRC_COLORKEY ) + +#define RADEON_SUPPORTED_2D_BLITTINGFUNCS \ + ( DFXL_BLIT ) + + +#define R100_SUPPORTED_DRAWINGFLAGS \ + ( RADEON_SUPPORTED_2D_DRAWINGFLAGS | DSDRAW_BLEND | DSDRAW_SRC_PREMULTIPLY ) + +#define R100_SUPPORTED_DRAWINGFUNCS \ + ( RADEON_SUPPORTED_2D_DRAWINGFUNCS | DFXL_FILLTRIANGLE ) + +#define R100_SUPPORTED_BLITTINGFLAGS \ + ( RADEON_SUPPORTED_2D_BLITTINGFLAGS | \ + DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA | \ + DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR | \ + DSBLIT_DEINTERLACE | DSBLIT_ROTATE180 | \ + DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR | \ + DSBLIT_SRC_PREMULTIPLY ) + +#define R100_SUPPORTED_BLITTINGFUNCS \ + ( RADEON_SUPPORTED_2D_BLITTINGFUNCS | DFXL_STRETCHBLIT | DFXL_TEXTRIANGLES ) + + +#define R200_SUPPORTED_DRAWINGFLAGS \ + ( RADEON_SUPPORTED_2D_DRAWINGFLAGS | DSDRAW_BLEND | DSDRAW_SRC_PREMULTIPLY ) + +#define R200_SUPPORTED_DRAWINGFUNCS \ + ( RADEON_SUPPORTED_2D_DRAWINGFUNCS | DFXL_FILLTRIANGLE ) + +#define R200_SUPPORTED_BLITTINGFLAGS \ + ( RADEON_SUPPORTED_2D_BLITTINGFLAGS | \ + DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA | \ + DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR | \ + DSBLIT_DEINTERLACE | DSBLIT_ROTATE180 | \ + DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR | \ + DSBLIT_SRC_PREMULTIPLY ) + +#define R200_SUPPORTED_BLITTINGFUNCS \ + ( RADEON_SUPPORTED_2D_BLITTINGFUNCS | DFXL_STRETCHBLIT | DFXL_TEXTRIANGLES ) + + +#define R300_SUPPORTED_DRAWINGFLAGS \ + ( RADEON_SUPPORTED_2D_DRAWINGFLAGS | DSDRAW_BLEND | DSDRAW_SRC_PREMULTIPLY ) + +#define R300_SUPPORTED_DRAWINGFUNCS \ + ( RADEON_SUPPORTED_2D_DRAWINGFUNCS | DFXL_FILLTRIANGLE ) + +#define R300_SUPPORTED_BLITTINGFLAGS \ + ( RADEON_SUPPORTED_2D_BLITTINGFLAGS | \ + DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA | \ + DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR | \ + DSBLIT_DEINTERLACE | DSBLIT_ROTATE180 ) + +#define R300_SUPPORTED_BLITTINGFUNCS \ + ( RADEON_SUPPORTED_2D_BLITTINGFUNCS | DFXL_STRETCHBLIT | DFXL_TEXTRIANGLES ) + + +#define DSBLIT_MODULATE_ALPHA ( DSBLIT_BLEND_ALPHACHANNEL | \ + DSBLIT_BLEND_COLORALPHA ) +#define DSBLIT_MODULATE_COLOR ( DSBLIT_BLEND_COLORALPHA | \ + DSBLIT_COLORIZE | \ + DSBLIT_SRC_PREMULTCOLOR ) +#define DSBLIT_MODULATE ( DSBLIT_MODULATE_ALPHA | \ + DSBLIT_MODULATE_COLOR | \ + DSBLIT_SRC_PREMULTIPLY ) +#define DSBLIT_MASK ( DSBLIT_SRC_MASK_ALPHA | \ + DSBLIT_SRC_MASK_COLOR ) + +#define RADEON_DRAW_3D() ( rdev->accel & DFXL_FILLTRIANGLE || \ + rdev->drawingflags & ~DSDRAW_XOR || \ + rdev->matrix != NULL || \ + (rdev->render_options & DSRO_ANTIALIAS && \ + rdev->accel & DFXL_DRAWLINE) ) + +#define RADEON_BLIT_3D() ( rdev->accel & ~DFXL_BLIT ||\ + rdev->blittingflags & ~(DSBLIT_XOR | \ + DSBLIT_SRC_COLORKEY) || \ + rdev->matrix != NULL || \ + (rdev->dst_format != rdev->src_format && \ + !(DFB_PLANAR_PIXELFORMAT(rdev->dst_format) && \ + DFB_PLANAR_PIXELFORMAT(rdev->src_format) ))) + +#define RADEON_FUNC( f ) DFB_PLANAR_PIXELFORMAT(rdev->dst_format) ? f##_420 : f + + +static inline bool +radeon_compatible_format( RadeonDriverData *rdrv, DFBSurfacePixelFormat format ) +{ +#ifdef WORDS_BIGENDIAN + u32 tmp, bpp; + + bpp = DFB_BYTES_PER_PIXEL( format ); + tmp = radeon_in32( rdrv->mmio_base, CRTC_GEN_CNTL ); + switch ((tmp >> 8) & 0xf) { + case DST_8BPP: + case DST_24BPP: + if (bpp == 2 || bpp == 4) + return false; + break; + case DST_15BPP: + case DST_16BPP: + if (bpp != 2) + return false; + break; + default: + if (bpp != 4) + return false; + break; + } +#endif + return true; +} + +static void +radeon_get_monitors( RadeonDriverData *rdrv, + RadeonDeviceData *rdev, + RadeonMonitorType *ret_monitor1, + RadeonMonitorType *ret_monitor2 ) +{ + RadeonMonitorType dvimon = MT_NONE; + RadeonMonitorType vgamon = MT_NONE; +#if D_DEBUG_ENABLED + const char *name[] = { "NONE", "CRT", "DFP", + "LCD", "CTV", "STV" }; +#endif + u32 tmp; + + if (rdev->chipset != CHIP_R100) { + if (rdev->chipset >= CHIP_R300 || + rdev->chipset == CHIP_UNKNOWN) + tmp = radeon_in32( rdrv->mmio_base, BIOS_0_SCRATCH ); + else + tmp = radeon_in32( rdrv->mmio_base, BIOS_4_SCRATCH ); + + /* DVI/TVO port */ + if (tmp & 0x08) + dvimon = MT_DFP; + else if (tmp & 0x4) + dvimon = MT_LCD; + else if (tmp & 0x200) + dvimon = MT_CRT; + else if (tmp & 0x10) + dvimon = MT_CTV; + else if (tmp & 0x20) + dvimon = MT_STV; + + /* VGA port */ + if (tmp & 0x2) + vgamon = MT_CRT; + else if (tmp & 0x800) + vgamon = MT_DFP; + else if (tmp & 0x400) + vgamon = MT_LCD; + else if (tmp & 0x1000) + vgamon = MT_CTV; + else if (tmp & 0x2000) + vgamon = MT_STV; + } + else { + tmp = radeon_in32( rdrv->mmio_base, FP_GEN_CNTL ); + + if (tmp & FP_EN_TMDS) + vgamon = MT_DFP; + else + vgamon = MT_CRT; + } + + D_DEBUG( "DirectFB/Radeon: " + "DVI/TVO Port -> %s, VGA Port -> %s.\n", + name[dvimon], name[vgamon] ); + + if (dvimon) { + /* If DVI port is connected, then + * DVI port is the primary head and + * CRT port is the secondary head. + */ + if (ret_monitor1) + *ret_monitor1 = dvimon; + if (ret_monitor2) + *ret_monitor2 = vgamon; + } + else { + if (ret_monitor1) + *ret_monitor1 = vgamon; + if (ret_monitor2) + *ret_monitor2 = MT_NONE; + } +} + +void +radeon_reset( RadeonDriverData *rdrv, RadeonDeviceData *rdev ) +{ + volatile u8 *mmio = rdrv->mmio_base; + u32 clock_cntl_index; + u32 mclk_cntl; + u32 rbbm_soft_reset; + u32 host_path_cntl; + + clock_cntl_index = radeon_in32( mmio, CLOCK_CNTL_INDEX ); + + mclk_cntl = radeon_inpll( mmio, MCLK_CNTL ); + radeon_outpll( mmio, MCLK_CNTL, mclk_cntl | + FORCEON_MCLKA | + FORCEON_MCLKB | + FORCEON_YCLKA | + FORCEON_YCLKB | + FORCEON_MC | + FORCEON_AIC ); + + host_path_cntl = radeon_in32( mmio, HOST_PATH_CNTL ); + rbbm_soft_reset = radeon_in32( mmio, RBBM_SOFT_RESET ); + + radeon_out32( mmio, RBBM_SOFT_RESET, rbbm_soft_reset | + SOFT_RESET_CP | SOFT_RESET_HI | + SOFT_RESET_SE | SOFT_RESET_RE | + SOFT_RESET_PP | SOFT_RESET_E2 | + SOFT_RESET_RB ); + radeon_in32( mmio, RBBM_SOFT_RESET ); + + radeon_out32( mmio, RBBM_SOFT_RESET, rbbm_soft_reset & + ~(SOFT_RESET_CP | SOFT_RESET_HI | + SOFT_RESET_SE | SOFT_RESET_RE | + SOFT_RESET_PP | SOFT_RESET_E2 | + SOFT_RESET_RB) ); + radeon_in32( mmio, RBBM_SOFT_RESET ); + + radeon_out32( mmio, HOST_PATH_CNTL, host_path_cntl | HDP_SOFT_RESET ); + radeon_in32( mmio, HOST_PATH_CNTL ); + radeon_out32( mmio, HOST_PATH_CNTL, host_path_cntl ); + + radeon_out32( mmio, RBBM_SOFT_RESET, rbbm_soft_reset ); + + radeon_out32( mmio, CLOCK_CNTL_INDEX, clock_cntl_index ); + radeon_outpll( mmio, MCLK_CNTL, mclk_cntl ); + + rdev->set = 0; + rdev->src_format = DSPF_UNKNOWN; + rdev->dst_format = DSPF_UNKNOWN; + rdev->fifo_space = 0; +} + +static void radeonAfterSetVar( void *drv, void *dev ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + volatile u8 *mmio = rdrv->mmio_base; + + rdev->surface_cntl = + rdev->surface_cntl_c = + rdev->surface_cntl_p = radeon_in32( mmio, SURFACE_CNTL ); + + radeon_out32( mmio, CRTC_OFFSET_CNTL, + (radeon_in32( mmio, CRTC_OFFSET_CNTL ) & ~CRTC_TILE_EN) | CRTC_HSYNC_EN ); + +#if RESET_AFTER_SETVAR + radeon_waitidle( rdrv, rdev ); + radeon_reset( rdrv, rdev ); +#endif +} + +static void radeonEngineReset( void *drv, void *dev ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + volatile u8 *mmio = rdrv->mmio_base; + + rdev->fifo_space = 0; + + radeon_out32( mmio, SURFACE_CNTL, rdev->surface_cntl_c ); + + radeon_waitfifo( rdrv, rdev, 3 ); +#ifdef WORDS_BIGENDIAN + radeon_out32( mmio, DP_DATATYPE, + radeon_in32( mmio, DP_DATATYPE ) | HOST_BIG_ENDIAN_EN ); +#else + radeon_out32( mmio, DP_DATATYPE, + radeon_in32( mmio, DP_DATATYPE ) & ~HOST_BIG_ENDIAN_EN ); +#endif + radeon_out32( mmio, DEFAULT_SC_BOTTOM_RIGHT, DEFAULT_SC_RIGHT_MAX | + DEFAULT_SC_BOTTOM_MAX ); + radeon_out32( mmio, AUX_SC_CNTL, 0 ); + + if (rdev->chipset >= CHIP_R300) { + r300_restore( rdrv, rdev ); + } + else if (rdev->chipset >= CHIP_R200) { + r200_restore( rdrv, rdev ); + } + else if (rdev->chipset >= CHIP_R100) { + r100_restore( rdrv, rdev ); + } + + /* sync 2d and 3d engines */ + radeon_waitfifo( rdrv, rdev, 1 ); + radeon_out32( mmio, ISYNC_CNTL, ISYNC_ANY2D_IDLE3D | + ISYNC_ANY3D_IDLE2D ); +} + +static DFBResult radeonEngineSync( void *drv, void *dev ) +{ + if (!radeon_waitidle( (RadeonDriverData*)drv, (RadeonDeviceData*)dev )) + return DFB_IO; /* DFB_TIMEOUT !? */ + + return DFB_OK; +} + +static void radeonInvalidateState( void *drv, void *dev ) +{ + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + + rdev->set = 0; + rdev->dst_format = DSPF_UNKNOWN; + rdev->src_format = DSPF_UNKNOWN; + rdev->msk_format = DSPF_UNKNOWN; +} + +static void radeonFlushTextureCache( void *drv, void *dev ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + volatile u8 *mmio = rdrv->mmio_base; + + if (rdev->chipset >= CHIP_R300) { + if (rdrv->mmio_size > 0x4000) { + radeon_waitfifo( rdrv, rdev, 1 ); + radeon_out32( mmio, R300_TX_CNTL, 0 ); + } + } + else if (rdev->chipset >= CHIP_R200) { + radeon_waitfifo( rdrv, rdev, 2 ); + radeon_out32( mmio, R200_PP_TXOFFSET_0, rdev->src_offset ); + radeon_out32( mmio, R200_PP_TXOFFSET_1, rdev->msk_offset ); + } + else if (rdev->chipset >= CHIP_R100) { + radeon_waitfifo( rdrv, rdev, 2 ); + radeon_out32( mmio, PP_TXOFFSET_0, rdev->src_offset ); + radeon_out32( mmio, PP_TXOFFSET_1, rdev->msk_offset ); + } +} + +#ifdef WORDS_BIGENDIAN +static void radeonSurfaceEnter( void *drv, void *dev, + CoreSurfaceBuffer *buffer, DFBSurfaceLockFlags flags ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + volatile u8 *mmio = rdrv->mmio_base; + u32 tmp; + + if (!(flags & DSLF_WRITE)) + return; + + rdev->surface_cntl_p = radeon_in32( mmio, SURFACE_CNTL ); + + tmp = rdev->surface_cntl_p & ~SURF_TRANSLATION_DIS; + tmp &= ~(NONSURF_AP0_SWP_16BPP | NONSURF_AP1_SWP_16BPP | + NONSURF_AP0_SWP_32BPP | NONSURF_AP1_SWP_32BPP); + + switch (DFB_BITS_PER_PIXEL( buffer->format )) { + case 16: + tmp |= NONSURF_AP0_SWP_16BPP | NONSURF_AP1_SWP_16BPP; + break; + case 32: + tmp |= NONSURF_AP0_SWP_32BPP | NONSURF_AP1_SWP_32BPP; + break; + default: + break; + } + + radeon_out32( mmio, SURFACE_CNTL, tmp ); + rdev->surface_cntl_c = tmp; +} + +static void radeonSurfaceLeave( void *drv, void *dev, CoreSurfaceBuffer *buffer ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + volatile u8 *mmio = rdrv->mmio_base; + + if (rdev->surface_cntl_p != rdev->surface_cntl_c) { + radeon_out32( mmio, SURFACE_CNTL, rdev->surface_cntl_p ); + rdev->surface_cntl_c = rdev->surface_cntl_p; + } +} +#endif + +static void r100CheckState( void *drv, void *dev, + CardState *state, DFBAccelerationMask accel ) +{ + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + CoreSurface *destination = state->destination; + CoreSurface *source = state->source; + + int supported_drawingfuncs = R100_SUPPORTED_DRAWINGFUNCS; + int supported_drawingflags = R100_SUPPORTED_DRAWINGFLAGS; + int supported_blittingfuncs = R100_SUPPORTED_BLITTINGFUNCS; + int supported_blittingflags = R100_SUPPORTED_BLITTINGFLAGS; + + if (!radeon_compatible_format( drv, destination->config.format )) + return; + + switch (destination->config.format) { + case DSPF_A8: + if (state->src_blend == DSBF_SRCALPHASAT) { + supported_drawingflags &= ~DSDRAW_BLEND; + supported_blittingflags &= ~DSBLIT_MODULATE_ALPHA; + } + break; + + case DSPF_RGB332: + case DSPF_RGB444: + case DSPF_ARGB4444: + case DSPF_RGB555: + case DSPF_ARGB1555: + case DSPF_RGB16: + case DSPF_RGB32: + case DSPF_ARGB: + break; + + case DSPF_LUT8: + case DSPF_ALUT44: + if (DFB_BLITTING_FUNCTION( accel ) && + source->config.format != destination->config.format) + return; + supported_drawingflags = DSDRAW_NOFX; + supported_blittingfuncs &= ~DFXL_TEXTRIANGLES; + supported_blittingflags = ~(DSBLIT_MODULATE | DSBLIT_MASK); + break; + + case DSPF_ARGB2554: + if (DFB_BLITTING_FUNCTION( accel ) && + source->config.format != destination->config.format) + return; + supported_drawingfuncs &= ~DFXL_FILLTRIANGLE; + supported_drawingflags = DSDRAW_XOR; + supported_blittingfuncs &= ~DFXL_TEXTRIANGLES; + supported_blittingflags &= ~(DSBLIT_MODULATE | DSBLIT_MASK); + break; + + case DSPF_AiRGB: + supported_drawingflags &= ~DSDRAW_BLEND; + supported_blittingflags &= ~DSBLIT_MODULATE_ALPHA; + break; + + case DSPF_I420: + case DSPF_YV12: + if (DFB_BLITTING_FUNCTION( accel ) && + source->config.format != DSPF_A8 && + source->config.format != DSPF_I420 && + source->config.format != DSPF_YV12) + return; + case DSPF_YUY2: + case DSPF_UYVY: + if (source && source->config.format != DSPF_A8) + supported_blittingflags &= ~(DSBLIT_COLORIZE | DSBLIT_SRC_COLORKEY | DSBLIT_MASK); + break; + + case DSPF_AYUV: + if (DFB_BLITTING_FUNCTION( accel ) && source->config.format != DSPF_A8) { + if (source->config.format != DSPF_AYUV) + return; + supported_blittingflags &= ~(DSBLIT_COLORIZE | DSBLIT_MASK); + } + break; + + default: + return; + } + + if (DFB_BLITTING_FUNCTION( accel )) { + if (state->blittingflags & DSBLIT_MASK || + state->blittingflags & DSBLIT_SRC_PREMULTIPLY) { + if (state->blittingflags & DSBLIT_MASK && + state->blittingflags & DSBLIT_SRC_PREMULTIPLY) + return; + if (state->blittingflags & (DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR)) + return; + } + + if (state->blittingflags & DSBLIT_SRC_COLORKEY) { + if (destination->config.format != source->config.format) + return; + supported_blittingfuncs = DFXL_BLIT; + supported_blittingflags &= DSBLIT_SRC_COLORKEY | DSBLIT_XOR; + } + + if (state->blittingflags & DSBLIT_ROTATE180) + supported_blittingfuncs &= ~DFXL_TEXTRIANGLES; + + if (accel & ~supported_blittingfuncs || + state->blittingflags & ~supported_blittingflags) + return; + + if (source->config.size.w > 2048 || source->config.size.h > 2048) + return; + + if (state->blittingflags & DSBLIT_MODULATE_ALPHA && + state->dst_blend == DSBF_SRCALPHASAT) + return; + + if (!radeon_compatible_format( drv, source->config.format )) + return; + + switch (source->config.format) { + case DSPF_RGB332: + case DSPF_RGB444: + case DSPF_ARGB4444: + case DSPF_RGB555: + case DSPF_ARGB1555: + case DSPF_RGB16: + case DSPF_RGB32: + case DSPF_ARGB: + if (destination->config.format == DSPF_UYVY || + destination->config.format == DSPF_YUY2) + return; + case DSPF_A8: + case DSPF_YUY2: + case DSPF_UYVY: + break; + + case DSPF_AiRGB: + if (destination->config.format != source->config.format && + (DFB_PIXELFORMAT_HAS_ALPHA(destination->config.format) || + destination->config.format == DSPF_UYVY || + destination->config.format == DSPF_YUY2)) + return; + if (state->blittingflags & DSBLIT_SRC_PREMULTIPLY) + return; + break; + + case DSPF_LUT8: + case DSPF_ALUT44: + case DSPF_ARGB2554: + case DSPF_AYUV: + if (destination->config.format != source->config.format) + return; + break; + + case DSPF_I420: + case DSPF_YV12: + if (source->config.size.w < 2 || source->config.size.h < 2) + return; + if (destination->config.format != DSPF_I420 && + destination->config.format != DSPF_YV12) + return; + break; + + default: + return; + } + + if (state->blittingflags & DSBLIT_MASK) { + CoreSurface *mask = state->source_mask; + + if (state->blittingflags & (DSBLIT_BLEND_COLORALPHA | + DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR)) + return; + + if (state->src_mask_flags & DSMF_STENCIL || + state->src_mask_offset.x || state->src_mask_offset.y) + return; + + if (mask->config.size.w > 2048 || mask->config.size.h > 2048) + return; + + if (!radeon_compatible_format( drv, mask->config.format )) + return; + + switch (mask->config.format) { + case DSPF_A8: + case DSPF_RGB332: + case DSPF_RGB444: + case DSPF_ARGB4444: + case DSPF_RGB555: + case DSPF_ARGB1555: + case DSPF_RGB16: + case DSPF_RGB32: + case DSPF_ARGB: + break; + + case DSPF_AiRGB: + if (state->blittingflags & DSBLIT_SRC_MASK_ALPHA && + DFB_PIXELFORMAT_HAS_ALPHA(source->config.format) && + source->config.format != DSPF_AiRGB) + return; + break; + + default: + return; + } + } + + state->accel |= supported_blittingfuncs; + rdev->blitting_mask = supported_blittingfuncs; + } + else { + if (accel & ~supported_drawingfuncs || + state->drawingflags & ~supported_drawingflags) + return; + + if (state->drawingflags & DSDRAW_BLEND && + state->dst_blend == DSBF_SRCALPHASAT) + return; + + state->accel |= supported_drawingfuncs; + rdev->drawing_mask = supported_drawingfuncs; + } +} + +static void r200CheckState( void *drv, void *dev, + CardState *state, DFBAccelerationMask accel ) +{ + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + CoreSurface *destination = state->destination; + CoreSurface *source = state->source; + + int supported_drawingfuncs = R200_SUPPORTED_DRAWINGFUNCS; + int supported_drawingflags = R200_SUPPORTED_DRAWINGFLAGS; + int supported_blittingfuncs = R200_SUPPORTED_BLITTINGFUNCS; + int supported_blittingflags = R200_SUPPORTED_BLITTINGFLAGS; + + if (!radeon_compatible_format( drv, destination->config.format )) + return; + + switch (destination->config.format) { + case DSPF_A8: + if (state->src_blend == DSBF_SRCALPHASAT) { + supported_drawingflags &= ~DSDRAW_BLEND; + supported_blittingflags &= ~DSBLIT_MODULATE_ALPHA; + } + break; + + case DSPF_RGB332: + case DSPF_RGB444: + case DSPF_ARGB4444: + case DSPF_RGB555: + case DSPF_ARGB1555: + case DSPF_RGB16: + case DSPF_RGB32: + case DSPF_ARGB: + break; + + case DSPF_LUT8: + case DSPF_ALUT44: + if (DFB_BLITTING_FUNCTION( accel ) && + source->config.format != destination->config.format) + return; + supported_drawingflags = DSDRAW_NOFX; + supported_blittingfuncs &= ~DFXL_TEXTRIANGLES; + supported_blittingflags &= ~(DSBLIT_MODULATE | DSBLIT_MASK); + break; + + case DSPF_ARGB2554: + if (DFB_BLITTING_FUNCTION( accel ) && + source->config.format != destination->config.format) + return; + supported_drawingfuncs &= ~DFXL_FILLTRIANGLE; + supported_drawingflags = DSDRAW_XOR; + supported_blittingfuncs &= ~DFXL_TEXTRIANGLES; + supported_blittingflags &= ~(DSBLIT_MODULATE | DSBLIT_MASK); + break; + + case DSPF_AiRGB: + supported_drawingflags &= ~DSDRAW_BLEND; + supported_blittingflags &= ~DSBLIT_MODULATE_ALPHA; + break; + + case DSPF_I420: + case DSPF_YV12: + if (DFB_BLITTING_FUNCTION( accel ) && + source->config.format != DSPF_A8 && + source->config.format != DSPF_I420 && + source->config.format != DSPF_YV12) + return; + case DSPF_YUY2: + case DSPF_UYVY: + if (source && source->config.format != DSPF_A8) + supported_blittingflags &= ~(DSBLIT_COLORIZE | DSBLIT_SRC_COLORKEY | DSBLIT_MASK); + break; + + case DSPF_AYUV: + if (DFB_BLITTING_FUNCTION( accel ) && source->config.format != DSPF_A8) { + if (source->config.format != DSPF_AYUV) + return; + supported_blittingflags &= ~(DSBLIT_COLORIZE | DSBLIT_MASK); + } + break; + + default: + return; + } + + if (DFB_BLITTING_FUNCTION( accel )) { + if (state->blittingflags & DSBLIT_MASK || + state->blittingflags & DSBLIT_SRC_PREMULTIPLY) { + if (state->blittingflags & DSBLIT_MASK && + state->blittingflags & DSBLIT_SRC_PREMULTIPLY) + return; + if (state->blittingflags & (DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR)) + return; + } + + if (state->blittingflags & DSBLIT_SRC_COLORKEY) { + if (destination->config.format != source->config.format) + return; + supported_blittingfuncs = DFXL_BLIT; + supported_blittingflags &= DSBLIT_SRC_COLORKEY | DSBLIT_XOR; + } + + if (state->blittingflags & DSBLIT_ROTATE180) + supported_blittingfuncs &= ~DFXL_TEXTRIANGLES; + + if (accel & ~supported_blittingfuncs || + state->blittingflags & ~supported_blittingflags) + return; + + if (source->config.size.w > 2048 || source->config.size.h > 2048) + return; + + if (state->blittingflags & DSBLIT_MODULATE_ALPHA && + state->dst_blend == DSBF_SRCALPHASAT) + return; + + if (!radeon_compatible_format( drv, source->config.format )) + return; + + switch (source->config.format) { + case DSPF_RGB332: + case DSPF_RGB444: + case DSPF_ARGB4444: + case DSPF_RGB555: + case DSPF_ARGB1555: + case DSPF_RGB16: + case DSPF_RGB32: + case DSPF_ARGB: + if (destination->config.format == DSPF_UYVY || + destination->config.format == DSPF_YUY2) + return; + case DSPF_A8: + break; + + case DSPF_AiRGB: + if (destination->config.format != source->config.format && + (DFB_PIXELFORMAT_HAS_ALPHA(destination->config.format) || + destination->config.format == DSPF_UYVY || + destination->config.format == DSPF_YUY2)) + return; + if (state->blittingflags & DSBLIT_SRC_PREMULTIPLY) + return; + break; + + case DSPF_LUT8: + case DSPF_ALUT44: + case DSPF_ARGB2554: + case DSPF_AYUV: + if (destination->config.format != source->config.format) + return; + break; + + case DSPF_YUY2: + case DSPF_UYVY: + if (rdev->chipset == CHIP_RV250 && + destination->config.format != DSPF_YUY2 && + destination->config.format != DSPF_UYVY) + return; + break; + + case DSPF_I420: + case DSPF_YV12: + if (source->config.size.w < 2 || source->config.size.h < 2) + return; + if (destination->config.format != DSPF_I420 && + destination->config.format != DSPF_YV12) + return; + break; + + default: + return; + } + + if (state->blittingflags & DSBLIT_MASK) { + CoreSurface *mask = state->source_mask; + + if (state->blittingflags & (DSBLIT_BLEND_COLORALPHA | + DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR)) + return; + + if (state->src_mask_flags & DSMF_STENCIL || + state->src_mask_offset.x || state->src_mask_offset.y) + return; + + if (mask->config.size.w > 2048 || mask->config.size.h > 2048) + return; + + if (!radeon_compatible_format( drv, mask->config.format )) + return; + + switch (mask->config.format) { + case DSPF_A8: + case DSPF_RGB332: + case DSPF_RGB444: + case DSPF_ARGB4444: + case DSPF_RGB555: + case DSPF_ARGB1555: + case DSPF_RGB16: + case DSPF_RGB32: + case DSPF_ARGB: + break; + + case DSPF_AiRGB: + if (state->blittingflags & DSBLIT_SRC_MASK_ALPHA && + DFB_PIXELFORMAT_HAS_ALPHA(source->config.format) && + source->config.format != DSPF_AiRGB) + return; + break; + + default: + return; + } + } + + state->accel |= supported_blittingfuncs; + rdev->blitting_mask = supported_blittingfuncs; + } + else { + if (accel & ~supported_drawingfuncs || + state->drawingflags & ~supported_drawingflags) + return; + + if (state->drawingflags & DSDRAW_BLEND && + state->dst_blend == DSBF_SRCALPHASAT) + return; + + state->accel |= supported_drawingfuncs; + rdev->drawing_mask = supported_drawingfuncs; + } +} + +static void r300CheckState( void *drv, void *dev, + CardState *state, DFBAccelerationMask accel ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + CoreSurface *destination = state->destination; + CoreSurface *source = state->source; + bool can_convert = true; + + int supported_drawingfuncs = R300_SUPPORTED_DRAWINGFUNCS; + int supported_drawingflags = R300_SUPPORTED_DRAWINGFLAGS; + int supported_blittingfuncs = R300_SUPPORTED_BLITTINGFUNCS; + int supported_blittingflags = R300_SUPPORTED_BLITTINGFLAGS; + if (rdrv->mmio_size <= 0x4000) { + supported_drawingfuncs = RADEON_SUPPORTED_2D_DRAWINGFUNCS; + supported_drawingflags = RADEON_SUPPORTED_2D_DRAWINGFLAGS; + supported_blittingfuncs = RADEON_SUPPORTED_2D_BLITTINGFUNCS; + supported_blittingflags = RADEON_SUPPORTED_2D_BLITTINGFLAGS; + can_convert = false; + } + + if (!radeon_compatible_format( drv, destination->config.format )) + return; + + switch (destination->config.format) { + case DSPF_RGB16: + case DSPF_RGB32: + case DSPF_ARGB: + break; + + case DSPF_LUT8: + case DSPF_ALUT44: + case DSPF_A8: + case DSPF_RGB332: + case DSPF_RGB444: + case DSPF_ARGB4444: + case DSPF_ARGB2554: + case DSPF_RGB555: + case DSPF_ARGB1555: + case DSPF_AiRGB: + case DSPF_AYUV: + case DSPF_YUY2: + case DSPF_UYVY: + if (DFB_BLITTING_FUNCTION( accel )) { + if (source->config.format != destination->config.format) + return; + } + supported_drawingfuncs &= ~DFXL_FILLTRIANGLE; + supported_drawingflags = DSDRAW_NOFX; + supported_blittingfuncs = DFXL_BLIT; + supported_blittingflags = DSBLIT_NOFX; + break; + + case DSPF_I420: + case DSPF_YV12: + if (DFB_BLITTING_FUNCTION( accel )) { + if (source->config.format != DSPF_I420 && + source->config.format != DSPF_YV12) + return; + } + supported_drawingfuncs &= ~DFXL_FILLTRIANGLE; + supported_drawingflags = DSDRAW_XOR; + supported_blittingflags = DSBLIT_DEINTERLACE; + break; + + default: + return; + } + + if (DFB_BLITTING_FUNCTION( accel )) { + if (state->blittingflags & DSBLIT_XOR) { + can_convert = false; + supported_blittingfuncs = DFXL_BLIT; + supported_blittingflags &= DSBLIT_SRC_COLORKEY | DSBLIT_XOR; + } + + if (state->blittingflags & DSBLIT_BLEND_ALPHACHANNEL) { + if (state->blittingflags & DSBLIT_BLEND_COLORALPHA) + return; + if (state->blittingflags & (DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR)) { + if (state->src_blend != DSBF_ONE) + return; + } + } + + if (state->blittingflags & DSBLIT_ROTATE180) + supported_blittingfuncs &= ~DFXL_TEXTRIANGLES; + + if (accel & ~supported_blittingfuncs || + state->blittingflags & ~supported_blittingflags) + return; + + if (source->config.size.w > 2048 || source->config.size.h > 2048) + return; + + if (state->blittingflags & DSBLIT_MODULATE_ALPHA && + state->dst_blend == DSBF_SRCALPHASAT) + return; + + if (!radeon_compatible_format( drv, source->config.format )) + return; + + switch (source->config.format) { + case DSPF_A8: + case DSPF_RGB332: + case DSPF_RGB444: + case DSPF_ARGB4444: + case DSPF_RGB555: + case DSPF_ARGB1555: + case DSPF_RGB16: + case DSPF_RGB32: + case DSPF_ARGB: + if (!can_convert && + destination->config.format != source->config.format) + return; + break; + + case DSPF_LUT8: + case DSPF_ALUT44: + if (destination->config.format != source->config.format) + return; + break; + + case DSPF_ARGB2554: + case DSPF_AiRGB: + case DSPF_AYUV: + case DSPF_YUY2: + case DSPF_UYVY: + if (destination->config.format != source->config.format) + return; + break; + + case DSPF_I420: + case DSPF_YV12: + if (source->config.size.w < 2 || source->config.size.h < 2) + return; + if (destination->config.format != DSPF_I420 && + destination->config.format != DSPF_YV12) + return; + break; + + default: + return; + } + + state->accel |= supported_blittingfuncs; + rdev->blitting_mask = supported_blittingfuncs; + } + else { + if (state->drawingflags & DSDRAW_XOR) { + supported_drawingfuncs &= ~DFXL_FILLTRIANGLE; + supported_drawingflags &= DSDRAW_XOR; + } + + if (accel & ~supported_drawingfuncs || + state->drawingflags & ~supported_drawingflags) + return; + + if (state->drawingflags & DSDRAW_BLEND && + state->dst_blend == DSBF_SRCALPHASAT) + return; + + state->accel |= supported_drawingfuncs; + rdev->drawing_mask = supported_drawingfuncs; + } +} + +static void r100SetState( void *drv, void *dev, + GraphicsDeviceFuncs *funcs, + CardState *state, DFBAccelerationMask accel ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + + rdev->set &= ~state->mod_hw; + if (DFB_BLITTING_FUNCTION( accel )) { + if ((rdev->accel ^ accel) & DFXL_TEXTRIANGLES) + rdev->set &= ~SMF_BLITTING_FLAGS; + } + + rdev->accel = accel; + + r100_set_destination( rdrv, rdev, state ); + r100_set_clip( rdrv, rdev, state ); + r100_set_render_options( rdrv, rdev, state ); + + switch (accel) { + case DFXL_FILLRECTANGLE: + case DFXL_FILLTRIANGLE: + case DFXL_DRAWRECTANGLE: + case DFXL_DRAWLINE: + r100_set_drawing_color( rdrv, rdev, state ); + + if (state->drawingflags & DSDRAW_BLEND) + r100_set_blend_function( rdrv, rdev, state ); + + r100_set_drawingflags( rdrv, rdev, state ); + + if (RADEON_DRAW_3D()) { + funcs->FillRectangle = r100FillRectangle3D; + funcs->FillTriangle = r100FillTriangle; + funcs->DrawRectangle = r100DrawRectangle3D; + funcs->DrawLine = r100DrawLine3D; + funcs->EmitCommands = r100EmitCommands3D; + } else { + funcs->FillRectangle = RADEON_FUNC(radeonFillRectangle2D); + funcs->FillTriangle = NULL; + funcs->DrawRectangle = RADEON_FUNC(radeonDrawRectangle2D); + funcs->DrawLine = RADEON_FUNC(radeonDrawLine2D); + funcs->EmitCommands = NULL; + } + + state->set = rdev->drawing_mask; + break; + + case DFXL_BLIT: + case DFXL_STRETCHBLIT: + case DFXL_TEXTRIANGLES: + r100_set_source( rdrv, rdev, state ); + + if (state->blittingflags & DSBLIT_MASK) + r100_set_source_mask( rdrv, rdev, state ); + + if (state->blittingflags & DSBLIT_MODULATE_ALPHA) + r100_set_blend_function( rdrv, rdev, state ); + + if (state->blittingflags & DSBLIT_MODULATE_COLOR) + r100_set_blitting_color( rdrv, rdev, state ); + + if (state->blittingflags & DSBLIT_SRC_COLORKEY) + r100_set_src_colorkey( rdrv, rdev, state ); + + r100_set_blittingflags( rdrv, rdev, state ); + + if (RADEON_BLIT_3D()) { + funcs->Blit = r100Blit3D; + funcs->StretchBlit = r100StretchBlit; + funcs->TextureTriangles = r100TextureTriangles; + funcs->EmitCommands = r100EmitCommands3D; + } else { + funcs->Blit = RADEON_FUNC(radeonBlit2D); + funcs->StretchBlit = NULL; + funcs->TextureTriangles = NULL; + funcs->EmitCommands = NULL; + } + + state->set = (accel & DFXL_TEXTRIANGLES) + ? : (rdev->blitting_mask & ~DFXL_TEXTRIANGLES); + break; + + default: + D_BUG( "unexpected drawing/blitting function" ); + break; + } + + state->mod_hw = 0; +} + +static void r200SetState( void *drv, void *dev, + GraphicsDeviceFuncs *funcs, + CardState *state, DFBAccelerationMask accel ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + + rdev->set &= ~state->mod_hw; + if (DFB_BLITTING_FUNCTION( accel )) { + if ((rdev->accel ^ accel) & DFXL_TEXTRIANGLES) + rdev->set &= ~SMF_BLITTING_FLAGS; + } + + rdev->accel = accel; + + r200_set_destination( rdrv, rdev, state ); + r200_set_clip( rdrv, rdev, state ); + r200_set_render_options( rdrv, rdev, state ); + + switch (accel) { + case DFXL_FILLRECTANGLE: + case DFXL_FILLTRIANGLE: + case DFXL_DRAWRECTANGLE: + case DFXL_DRAWLINE: + r200_set_drawing_color( rdrv, rdev, state ); + + if (state->drawingflags & DSDRAW_BLEND) + r200_set_blend_function( rdrv, rdev, state ); + + r200_set_drawingflags( rdrv, rdev, state ); + + if (RADEON_DRAW_3D()) { + funcs->FillRectangle = r200FillRectangle3D; + funcs->FillTriangle = r200FillTriangle; + funcs->DrawRectangle = r200DrawRectangle3D; + funcs->DrawLine = r200DrawLine3D; + funcs->EmitCommands = r200EmitCommands3D; + } else { + funcs->FillRectangle = RADEON_FUNC(radeonFillRectangle2D); + funcs->FillTriangle = NULL; + funcs->DrawRectangle = RADEON_FUNC(radeonDrawRectangle2D); + funcs->DrawLine = RADEON_FUNC(radeonDrawLine2D); + funcs->EmitCommands = NULL; + } + + state->set = rdev->drawing_mask; + break; + + case DFXL_BLIT: + case DFXL_STRETCHBLIT: + case DFXL_TEXTRIANGLES: + r200_set_source( rdrv, rdev, state ); + + if (state->blittingflags & DSBLIT_MASK) + r200_set_source_mask( rdrv, rdev, state ); + + if (state->blittingflags & DSBLIT_MODULATE_ALPHA) + r200_set_blend_function( rdrv, rdev, state ); + + if (state->blittingflags & DSBLIT_MODULATE_COLOR) + r200_set_blitting_color( rdrv, rdev, state ); + + if (state->blittingflags & DSBLIT_SRC_COLORKEY) + r200_set_src_colorkey( rdrv, rdev, state ); + + r200_set_blittingflags( rdrv, rdev, state ); + + if (RADEON_BLIT_3D()) { + funcs->Blit = r200Blit3D; + funcs->StretchBlit = r200StretchBlit; + funcs->TextureTriangles = r200TextureTriangles; + funcs->EmitCommands = r200EmitCommands3D; + } else { + funcs->Blit = RADEON_FUNC(radeonBlit2D); + funcs->StretchBlit = NULL; + funcs->TextureTriangles = NULL; + funcs->EmitCommands = NULL; + } + + state->set = (accel & DFXL_TEXTRIANGLES) + ? : (rdev->blitting_mask & ~DFXL_TEXTRIANGLES); + break; + + default: + D_BUG( "unexpected drawing/blitting function" ); + break; + } + + state->mod_hw = 0; +} + +static void r300SetState( void *drv, void *dev, + GraphicsDeviceFuncs *funcs, + CardState *state, DFBAccelerationMask accel ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + + rdev->set &= ~state->mod_hw; + if (DFB_BLITTING_FUNCTION( accel )) { + if ((rdev->accel ^ accel) & DFXL_TEXTRIANGLES) + rdev->set &= ~SMF_BLITTING_FLAGS; + } + + rdev->accel = accel; + + r300_set_destination( rdrv, rdev, state ); + r300_set_clip( rdrv, rdev, state ); + r300_set_render_options( rdrv, rdev, state ); + + switch (accel) { + case DFXL_FILLRECTANGLE: + case DFXL_FILLTRIANGLE: + case DFXL_DRAWRECTANGLE: + case DFXL_DRAWLINE: + r300_set_drawing_color( rdrv, rdev, state ); + + if (state->drawingflags & DSDRAW_BLEND) + r300_set_blend_function( rdrv, rdev, state ); + + r300_set_drawingflags( rdrv, rdev, state ); + + if (RADEON_DRAW_3D()) { + funcs->FillRectangle = r300FillRectangle3D; + funcs->FillTriangle = r300FillTriangle; + funcs->DrawRectangle = r300DrawRectangle3D; + funcs->DrawLine = r300DrawLine3D; + funcs->EmitCommands = r300EmitCommands3D; + } else { + funcs->FillRectangle = RADEON_FUNC(radeonFillRectangle2D); + funcs->FillTriangle = NULL; + funcs->DrawRectangle = RADEON_FUNC(radeonDrawRectangle2D); + funcs->DrawLine = RADEON_FUNC(radeonDrawLine2D); + funcs->EmitCommands = NULL; + } + + state->set = rdev->drawing_mask; + break; + + case DFXL_BLIT: + case DFXL_STRETCHBLIT: + case DFXL_TEXTRIANGLES: + r300_set_source( rdrv, rdev, state ); + + if (state->blittingflags & DSBLIT_MODULATE_ALPHA) + r300_set_blend_function( rdrv, rdev, state ); + + if (state->blittingflags & DSBLIT_MODULATE_COLOR) + r300_set_blitting_color( rdrv, rdev, state ); + + if (state->blittingflags & DSBLIT_SRC_COLORKEY) + r300_set_src_colorkey( rdrv, rdev, state ); + + r300_set_blittingflags( rdrv, rdev, state ); + + if (RADEON_BLIT_3D()) { + funcs->Blit = r300Blit3D; + funcs->StretchBlit = r300StretchBlit; + funcs->TextureTriangles = r300TextureTriangles; + funcs->EmitCommands = r300EmitCommands3D; + } else { + funcs->Blit = RADEON_FUNC(radeonBlit2D); + funcs->StretchBlit = NULL; + funcs->TextureTriangles = NULL; + funcs->EmitCommands = NULL; + } + + state->set = (accel & DFXL_TEXTRIANGLES) + ? : (rdev->blitting_mask & ~DFXL_TEXTRIANGLES); + break; + + default: + D_BUG( "unexpected drawing/blitting function" ); + break; + } + + state->mod_hw = 0; +} + + +/* chipset detection */ + +static int +radeon_find_chipset( RadeonDriverData *rdrv, int *ret_devid, int *ret_index ) +{ + volatile u8 *mmio = rdrv->mmio_base; + unsigned int vendor_id; + unsigned int device_id; + int i; + + vendor_id = radeon_in16( mmio, CONFIG_VENDOR_ID ); + device_id = radeon_in16( mmio, CONFIG_DEVICE_ID ); + if (vendor_id != 0x1002 || !device_id) + dfb_system_get_deviceid( &vendor_id, &device_id ); + + if (vendor_id == 0x1002) { + if (ret_devid) + *ret_devid = device_id; + + for (i = 0; i < D_ARRAY_SIZE( dev_table ); i++) { + if ((unsigned int)dev_table[i].id == device_id) { + if (ret_index) + *ret_index = i; + return 1; + } + } + } + + return 0; +} + +/* exported symbols */ + +static int +driver_probe( CoreGraphicsDevice *device ) +{ + switch (dfb_gfxcard_get_accelerator( device )) { + case FB_ACCEL_ATI_RADEON: + return 1; + default: + break; + } + + 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 Radeon Driver" ); + + snprintf( info->vendor, + DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH, + "Claudio Ciccani" ); + + snprintf( info->license, + DFB_GRAPHICS_DRIVER_INFO_LICENSE_LENGTH, + "LGPL" ); + + snprintf( info->url, + DFB_GRAPHICS_DRIVER_INFO_URL_LENGTH, + "http://www.directfb.org" ); + + info->version.major = 1; + info->version.minor = 2; + + info->driver_data_size = sizeof(RadeonDriverData); + info->device_data_size = sizeof(RadeonDeviceData); +} + +static DFBResult +driver_init_driver( CoreGraphicsDevice *device, + GraphicsDeviceFuncs *funcs, + void *driver_data, + void *device_data, + CoreDFB *core ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) driver_data; + RadeonChipsetFamily chip = CHIP_UNKNOWN; + int idx; + + rdrv->device_data = (RadeonDeviceData*) device_data; + + /* gain access to memory mapped registers */ + rdrv->mmio_base = (volatile u8*) dfb_gfxcard_map_mmio( device, 0, 0x4000 ); + if (!rdrv->mmio_base) + return DFB_IO; + rdrv->mmio_size = 0x4000; + + rdrv->fb_base = dfb_gfxcard_memory_virtual( device, 0 ); + + if (radeon_find_chipset( rdrv, NULL, &idx )) + chip = dev_table[idx].chip; + + if (chip >= CHIP_R300 && !getenv( "R300_DISABLE_3D" )) { + volatile void *base; + /* increase amount of memory mapped registers */ + base = dfb_gfxcard_map_mmio( device, 0, 0x8000 ); + if (!base) { + D_ERROR( "DirectFB/Radeon: You are running a buggy version of radeonfb!\n" + " -> Please, apply the kernel patch named radeonfb-r300fix.\n" ); + D_INFO( "DirectFB/Radeon: 3D Acceleration will be disabled.\n" ); + } + else { + rdrv->mmio_base = base; + rdrv->mmio_size = 0x8000; + } + } + + /* fill function table */ + funcs->AfterSetVar = radeonAfterSetVar; + funcs->EngineReset = radeonEngineReset; + funcs->EngineSync = radeonEngineSync; + funcs->InvalidateState = radeonInvalidateState; + funcs->FlushTextureCache = radeonFlushTextureCache; +#ifdef WORDS_BIGENDIAN + funcs->SurfaceEnter = radeonSurfaceEnter; + funcs->SurfaceLeave = radeonSurfaceLeave; +#endif + + if (chip >= CHIP_R300) { + funcs->CheckState = r300CheckState; + funcs->SetState = r300SetState; + } + else if (chip >= CHIP_R200) { + funcs->CheckState = r200CheckState; + funcs->SetState = r200SetState; + } + else if (chip >= CHIP_R100) { + funcs->CheckState = r100CheckState; + funcs->SetState = r100SetState; + } + + /* primary screen */ + dfb_screens_hook_primary( device, driver_data, + &RadeonCrtc1ScreenFuncs, + &OldPrimaryScreenFuncs, + &OldPrimaryScreenDriverData ); + + /* primary layer */ + dfb_layers_hook_primary( device, driver_data, + &RadeonCrtc1LayerFuncs, + &OldPrimaryLayerFuncs, + &OldPrimaryLayerDriverData ); + + /* overlay support */ + dfb_layers_register( dfb_screens_at( DSCID_PRIMARY ), + driver_data, &RadeonOverlayFuncs ); + + if (chip != CHIP_R100) { + CoreScreen *screen; + + /* secondary screen support */ + screen = dfb_screens_register( device, driver_data, + &RadeonCrtc2ScreenFuncs ); + + /* secondary underlay support */ + dfb_layers_register( screen, driver_data, + &RadeonCrtc2LayerFuncs ); + + /* secondary overlay support */ + dfb_layers_register( screen, driver_data, + &RadeonOverlayFuncs ); + } + + return DFB_OK; +} + +static DFBResult +driver_init_device( CoreGraphicsDevice *device, + GraphicsDeviceInfo *device_info, + void *driver_data, + void *device_data ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) driver_data; + RadeonDeviceData *rdev = (RadeonDeviceData*) device_data; + volatile void *mmio = rdrv->mmio_base; + int dev = 0; + int idx = 0; + const char *name = "Unknown"; + + if (radeon_find_chipset( rdrv, &dev, &idx )) { + rdev->chipset = dev_table[idx].chip; + rdev->igp = dev_table[idx].igp; + name = dev_table[idx].name; + } + else { + if (!dev) { + D_ERROR( "DirectFB/Radeon: Could not detect device id!\n" + " -> Please, specify the bus location of" + " the card by using the 'busid' option.\n" ); + } + D_INFO( "DirectFB/Radeon: " + "Unknown chipset, disabling acceleration!\n" ); + } + + /* fill device info */ + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, + "%s (%04x)", name, dev ); + + snprintf( device_info->vendor, + DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "ATI" ); + + device_info->caps.flags = CCF_CLIPPING | CCF_AUXMEMORY | CCF_RENDEROPTS; + + if (rdev->chipset >= CHIP_R300) { + if (rdrv->mmio_size > 0x4000) { + device_info->caps.accel = R300_SUPPORTED_DRAWINGFUNCS | + R300_SUPPORTED_BLITTINGFUNCS; + device_info->caps.drawing = R300_SUPPORTED_DRAWINGFLAGS; + device_info->caps.blitting = R300_SUPPORTED_BLITTINGFLAGS; + } else { + device_info->caps.accel = RADEON_SUPPORTED_2D_DRAWINGFUNCS | + RADEON_SUPPORTED_2D_BLITTINGFUNCS; + device_info->caps.drawing = RADEON_SUPPORTED_2D_DRAWINGFLAGS; + device_info->caps.blitting = RADEON_SUPPORTED_2D_BLITTINGFLAGS; + } + } + else if (rdev->chipset >= CHIP_R200) { + device_info->caps.accel = R200_SUPPORTED_DRAWINGFUNCS | + R200_SUPPORTED_BLITTINGFUNCS; + device_info->caps.drawing = R200_SUPPORTED_DRAWINGFLAGS; + device_info->caps.blitting = R200_SUPPORTED_BLITTINGFLAGS; + } + else if (rdev->chipset >= CHIP_R100) { + device_info->caps.accel = R100_SUPPORTED_DRAWINGFUNCS | + R100_SUPPORTED_BLITTINGFUNCS; + device_info->caps.drawing = R100_SUPPORTED_DRAWINGFLAGS; + device_info->caps.blitting = R100_SUPPORTED_BLITTINGFLAGS; + } + + device_info->limits.surface_byteoffset_alignment = 32; + device_info->limits.surface_pixelpitch_alignment = 64; + device_info->limits.surface_bytepitch_alignment = 128; + + dfb_config->pollvsync_after = 1; + + /* reserve memory for YUV422 color buffer */ + rdev->yuv422_buffer = dfb_gfxcard_reserve_memory( device, 128 ); + if (rdev->yuv422_buffer == (u32)-1) { + D_ERROR( "DirectFB/Radeon: " + "couldn't reserve 128 bytes of video memory!\n" ); + return DFB_NOVIDEOMEMORY; + } + + rdev->fb_phys = dfb_gfxcard_memory_physical( device, 0 ); + + radeon_waitidle( rdrv, rdev ); + + /* get connected monitors */ + radeon_get_monitors( rdrv, rdev, &rdev->monitor1, &rdev->monitor2 ); + + /* save the following regs */ + rdev->mc_fb_location = radeon_in32( mmio, MC_FB_LOCATION ); + rdev->mc_agp_location = radeon_in32( mmio, MC_AGP_LOCATION ); + rdev->crtc_base_addr = radeon_in32( mmio, CRTC_BASE_ADDR ); + rdev->crtc2_base_addr = radeon_in32( mmio, CRTC2_BASE_ADDR ); + rdev->agp_base = radeon_in32( mmio, AGP_BASE ); + rdev->agp_cntl = radeon_in32( mmio, AGP_CNTL ); + rdev->aic_cntl = radeon_in32( mmio, AIC_CNTL ); + rdev->bus_cntl = radeon_in32( mmio, BUS_CNTL ); + rdev->fcp_cntl = radeon_in32( mmio, FCP_CNTL ); + rdev->cap0_trig_cntl = radeon_in32( mmio, CAP0_TRIG_CNTL ); + rdev->vid_buffer_control = radeon_in32( mmio, VID_BUFFER_CONTROL ); + rdev->display_test_debug_cntl = radeon_in32( mmio, DISPLAY_TEST_DEBUG_CNTL ); + rdev->surface_cntl = radeon_in32( mmio, SURFACE_CNTL ); + rdev->dp_gui_master_cntl = radeon_in32( mmio, DP_GUI_MASTER_CNTL ); + + rdev->surface_cntl_p = + rdev->surface_cntl_c = rdev->surface_cntl; + + if (rdev->igp) { + u32 tom; + /* force MC_FB_LOCATION to NB_TOM */ + tom = radeon_in32( mmio, NB_TOM ); + rdev->fb_offset = tom << 16; + rdev->fb_size = ((tom >> 16) - (tom & 0xffff) + 1) << 16; + } + else { + if (rdev->chipset >= CHIP_R300) { + rdev->fb_offset = 0; + rdev->fb_size = radeon_in32( mmio, CONFIG_MEMSIZE ); + } else { + rdev->fb_offset = radeon_in32( mmio, CONFIG_APER_0_BASE ); + rdev->fb_size = radeon_in32( mmio, CONFIG_APER_SIZE ); + } + } + + radeon_out32( mmio, MC_FB_LOCATION, (rdev->fb_offset>>16) | + ((rdev->fb_offset + rdev->fb_size - 1) & 0xffff0000) ); + + D_DEBUG( "DirectFB/Radeon: " + "Framebuffer located at 0x%08x:0x%08x.\n", + rdev->fb_offset, rdev->fb_offset + rdev->fb_size - 1 ); + + if (dfb_system_auxram_length()) { + rdev->agp_offset = (rdev->fb_offset + rdev->fb_size) & 0xffc00000; + rdev->agp_size = dfb_system_auxram_length(); + + /* enable AGP support */ + radeon_out32( mmio, AIC_CNTL, rdev->aic_cntl & ~PCIGART_TRANSLATE_EN ); + radeon_out32( mmio, AGP_BASE, dfb_system_aux_memory_physical( 0 ) ); + radeon_out32( mmio, AGP_CNTL, rdev->agp_cntl | 0x000e0000 ); + radeon_out32( mmio, BUS_CNTL, rdev->bus_cntl & ~BUS_MASTER_DIS ); + + radeon_out32( mmio, MC_AGP_LOCATION, (rdev->agp_offset>>16) | + ((rdev->agp_offset + rdev->agp_size - 1) & 0xffff0000) ); + + D_DEBUG( "DirectFB/Radeon: " + "AGP Aperture located at 0x%08x:0x%08x.\n", + rdev->agp_offset, rdev->agp_offset + rdev->agp_size - 1 ); + } + + radeon_out32( mmio, CRTC_BASE_ADDR, rdev->fb_offset ); + radeon_out32( mmio, DISP_MERGE_CNTL, 0xffff0000 ); + if (rdev->chipset != CHIP_R100) { + radeon_out32( mmio, CRTC2_BASE_ADDR, rdev->fb_offset ); + radeon_out32( mmio, DISP2_MERGE_CNTL, 0xffff0000 ); + } + + radeon_out32( mmio, FCP_CNTL, FCP0_SRC_GND ); + radeon_out32( mmio, CAP0_TRIG_CNTL, 0 ); + radeon_out32( mmio, VID_BUFFER_CONTROL, 0x00010001 ); + radeon_out32( mmio, DISPLAY_TEST_DEBUG_CNTL, 0 ); + + radeon_reset( rdrv, rdev ); + + return DFB_OK; +} + +static void +driver_close_device( CoreGraphicsDevice *device, + void *driver_data, + void *device_data ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) driver_data; + RadeonDeviceData *rdev = (RadeonDeviceData*) device_data; + volatile u8 *mmio = rdrv->mmio_base; + + D_DEBUG( "DirectFB/Radeon: FIFO Performance Monitoring:\n" ); + D_DEBUG( "DirectFB/Radeon: %9d radeon_waitfifo calls\n", + rdev->waitfifo_calls ); + D_DEBUG( "DirectFB/Radeon: %9d register writes (radeon_waitfifo sum)\n", + rdev->waitfifo_sum ); + D_DEBUG( "DirectFB/Radeon: %9d FIFO wait cycles (depends on CPU)\n", + rdev->fifo_waitcycles ); + D_DEBUG( "DirectFB/Radeon: %9d IDLE wait cycles (depends on CPU)\n", + rdev->idle_waitcycles ); + D_DEBUG( "DirectFB/Radeon: %9d FIFO space cache hits(depends on CPU)\n", + rdev->fifo_cache_hits ); + D_DEBUG( "DirectFB/Radeon: Conclusion:\n" ); + D_DEBUG( "DirectFB/Radeon: Average register writes/radeon_waitfifo call:%.2f\n", + rdev->waitfifo_sum / (float)rdev->waitfifo_calls ); + D_DEBUG( "DirectFB/Radeon: Average wait cycles/radeon_waitfifo call: %.2f\n", + rdev->fifo_waitcycles / (float)rdev->waitfifo_calls ); + D_DEBUG( "DirectFB/Radeon: Average fifo space cache hits: %02d%%\n", + (int)(100 * rdev->fifo_cache_hits / (float)rdev->waitfifo_calls) ); + + radeon_reset( rdrv, rdev ); + + /* restore previously saved regs */ + radeon_out32( mmio, MC_FB_LOCATION, rdev->mc_fb_location ); + radeon_out32( mmio, MC_AGP_LOCATION, rdev->mc_agp_location ); + radeon_out32( mmio, CRTC_BASE_ADDR, rdev->crtc_base_addr ); + radeon_out32( mmio, CRTC2_BASE_ADDR, rdev->crtc2_base_addr ); + radeon_out32( mmio, AGP_CNTL, rdev->agp_cntl ); + radeon_out32( mmio, AGP_BASE, rdev->agp_base ); + radeon_out32( mmio, AIC_CNTL, rdev->aic_cntl ); + radeon_out32( mmio, BUS_CNTL, rdev->bus_cntl ); + radeon_out32( mmio, FCP_CNTL, rdev->fcp_cntl ); + radeon_out32( mmio, CAP0_TRIG_CNTL, rdev->cap0_trig_cntl ); + radeon_out32( mmio, VID_BUFFER_CONTROL, rdev->vid_buffer_control ); + radeon_out32( mmio, DISPLAY_TEST_DEBUG_CNTL, rdev->display_test_debug_cntl ); + radeon_out32( mmio, SURFACE_CNTL, rdev->surface_cntl ); + + radeon_waitfifo( rdrv, rdev, 3 ); + radeon_out32( mmio, SC_TOP_LEFT, 0 ); + radeon_out32( mmio, DEFAULT_SC_BOTTOM_RIGHT, DEFAULT_SC_RIGHT_MAX | + DEFAULT_SC_BOTTOM_MAX ); + radeon_out32( mmio, DP_GUI_MASTER_CNTL, rdev->dp_gui_master_cntl ); +} + +static void +driver_close_driver( CoreGraphicsDevice *device, + void *driver_data ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) driver_data; + + dfb_gfxcard_unmap_mmio( device, rdrv->mmio_base, rdrv->mmio_size ); +} + -- cgit