/* * 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 ); }