/***************************************************************************** * VIA Unichrome XvMC extension client lib. * * Copyright (c) 2004 Thomas Hellström. All rights reserved. * Copyright (c) 2003 Andreas Robinson. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* * Low-level functions that deal directly with the hardware. In the future, * these functions might be implemented in a kernel module. Also, some of them * would benefit from DMA. * * Authors: Andreas Robinson 2003. Thomas Hellström 2004. */ #include "viaXvMCPriv.h" #include /* * For Other architectures than i386 these might have to be modified for * bigendian etc. */ #define MPEGIN(ctx,reg) \ *((volatile CARD32 *)(((CARD8 *)(ctx)->mmioAddress) + 0xc00 + (reg))) #define MPEGOUT(ctx,reg,val) \ *((volatile CARD32 *)(((CARD8 *)(ctx)->mmioAddress) + 0xc00 + (reg))) \ = (val); #define VIDIN(ctx,reg) \ *((volatile CARD32 *)(((CARD8 *)(ctx)->mmioAddress) + 0x200 + (reg))) #define VIDOUT(ctx,reg,val) \ *((volatile CARD32 *)(((CARD8 *)(ctx)->mmioAddress) + 0x200 + (reg))) \ = (val); #define REGIN(ctx,reg) \ *((volatile CARD32 *)(((CARD8 *)(ctx)->mmioAddress) + 0x0000 + (reg))) #define REGOUT(ctx,reg,val) \ *((volatile CARD32 *)(((CARD8 *)(ctx)->mmioAddress) + 0x0000 + (reg))) \ = (val); #define HQV_CONTROL 0x1D0 #define HQV_SRC_STARTADDR_Y 0x1D4 #define HQV_SRC_STARTADDR_U 0x1D8 #define HQV_SRC_STARTADDR_V 0x1DC #define HQV_SW_FLIP 0x00000010 #define HQV_FLIP_STATUS 0x00000001 #define HQV_SUBPIC_FLIP 0x00008000 #define HQV_FLIP_ODD 0x00000020 #define HQV_DEINTERLACE 0x00010000 #define HQV_FIELD_2_FRAME 0x00020000 #define HQV_FRAME_2_FIELD 0x00040000 #define HQV_FIELD_UV 0x00100000 #define V_COMPOSE_MODE 0x98 #define V1_COMMAND_FIRE 0x80000000 #define V3_COMMAND_FIRE 0x40000000 /* SUBPICTURE Registers */ #define SUBP_CONTROL_STRIDE 0x1C0 #define SUBP_STARTADDR 0x1C4 #define RAM_TABLE_CONTROL 0x1C8 #define RAM_TABLE_READ 0x1CC /* SUBP_CONTROL_STRIDE 0x3c0 */ #define SUBP_HQV_ENABLE 0x00010000 #define SUBP_IA44 0x00020000 #define SUBP_AI44 0x00000000 #define SUBP_STRIDE_MASK 0x00001fff #define SUBP_CONTROL_MASK 0x00070000 /* RAM_TABLE_CONTROL 0x3c8 */ #define RAM_TABLE_RGB_ENABLE 0x00000007 #define VIA_REG_STATUS 0x400 #define VIA_REG_GEMODE 0x004 #define VIA_REG_SRCBASE 0x030 #define VIA_REG_DSTBASE 0x034 #define VIA_REG_PITCH 0x038 #define VIA_REG_SRCCOLORKEY 0x01C #define VIA_REG_KEYCONTROL 0x02C #define VIA_REG_SRCPOS 0x008 #define VIA_REG_DSTPOS 0x00C #define VIA_REG_GECMD 0x000 #define VIA_REG_DIMENSION 0x010 /* width and height */ #define VIA_REG_FGCOLOR 0x018 #define VIA_VR_QUEUE_BUSY 0x00020000 /* Virtual Queue is busy */ #define VIA_CMD_RGTR_BUSY 0x00000080 /* Command Regulator is busy */ #define VIA_2D_ENG_BUSY 0x00000001 /* 2D Engine is busy */ #define VIA_3D_ENG_BUSY 0x00000002 /* 3D Engine is busy */ #define VIA_GEM_8bpp 0x00000000 #define VIA_GEM_16bpp 0x00000100 #define VIA_GEM_32bpp 0x00000300 #define VIA_GEC_BLT 0x00000001 #define VIA_PITCH_ENABLE 0x80000000 #define VIA_GEC_INCX 0x00000000 #define VIA_GEC_DECY 0x00004000 #define VIA_GEC_INCY 0x00000000 #define VIA_GEC_DECX 0x00008000 #define VIA_GEC_FIXCOLOR_PAT 0x00002000 #define VIA_BLIT_CLEAR 0x00 #define VIA_BLIT_COPY 0xCC #define VIA_BLIT_FILL 0xF0 #define VIA_BLIT_SET 0xFF #define VIA_SYNCWAITTIMEOUT 50000 /* Might be a bit conservative */ /* * Command buffer for sending commands to the CLE266. This structure could * probably be easily changed to a DMA-buffer when there is enough docs on * how to do this. */ typedef struct{ unsigned curPos; CARD32 offsets[VIA_CBUFFERSIZE]; CARD32 values[VIA_CBUFFERSIZE]; }CommandBuffer; #define CLEAR_CBUFFER(buf) (buf)->curPos = 0 #define CBUFFER(buf,offset,value) \ (buf)->offsets[(buf)->curPos] = (offset); \ (buf)->values[((buf)->curPos)++] = (value) #ifndef BEAM_HWMPEG void viaMpegSetSurfaceStrideLocked(ViaXvMCContext * ctx) { CARD32 y_stride = ctx->yStride; CARD32 uv_stride = y_stride >> 1; MPEGOUT(ctx,0x50,(y_stride >> 3) | ((uv_stride >> 3) << 16)); } #endif static void viaVideoWaitSWFlipLocked(ViaXvMCContext *ctx) { while (VIDIN(ctx,HQV_CONTROL) & HQV_SW_FLIP); } static void viaVideoSetSWFLipLocked(ViaXvMCContext *ctx, unsigned yOffs, unsigned uOffs, unsigned vOffs) { VIDOUT(ctx,HQV_SRC_STARTADDR_Y,yOffs); VIDOUT(ctx,HQV_SRC_STARTADDR_U,uOffs); VIDOUT(ctx,HQV_SRC_STARTADDR_V,vOffs); } void viaVideoSWFlipLocked(ViaXvMCContext *ctx, unsigned flags, int progressiveSequence, unsigned yOffs, unsigned uOffs, unsigned vOffs) { CARD32 andWd,orWd; andWd = ~HQV_FLIP_ODD; orWd = HQV_FIELD_UV | HQV_DEINTERLACE | HQV_FIELD_2_FRAME | HQV_FRAME_2_FIELD | HQV_SW_FLIP | HQV_FLIP_STATUS; if ((flags & XVMC_FRAME_PICTURE) == XVMC_TOP_FIELD) { andWd = 0xFFFFFFFFU; orWd |= HQV_FLIP_ODD; } if (progressiveSequence) { orWd &= ~HQV_FIELD_UV; } if ((flags & XVMC_FRAME_PICTURE) == XVMC_FRAME_PICTURE) { orWd = HQV_SW_FLIP | HQV_FLIP_STATUS; } viaVideoWaitSWFlipLocked(ctx); viaVideoSetSWFLipLocked(ctx, yOffs, uOffs, vOffs); VIDOUT(ctx,HQV_CONTROL,(VIDIN(ctx,HQV_CONTROL) & andWd) | orWd ); } #ifndef BEAM_HWMPEG void viaMpegSetFBLocked(ViaXvMCContext *ctx,unsigned i, unsigned yOffs, unsigned uOffs, unsigned vOffs) { i *= 12; printf("BEAMUFB: %d: %x %x %x\n", i / 12, yOffs, uOffs, vOffs); MPEGOUT(ctx, 0x20 + i, yOffs >> 3); MPEGOUT(ctx, 0x24 + i, uOffs >> 3); MPEGOUT(ctx, 0x28 + i, vOffs >> 3); } void viaMpegBeginPictureLocked(ViaXvMCContext *ctx, unsigned width, unsigned height, const XvMCMpegControl *control) { unsigned j, mb_width, mb_height; mb_width = (width + 15) >> 4; mb_height = ((control->mpeg_coding == XVMC_MPEG_2) && (control->flags & XVMC_PROGRESSIVE_SEQUENCE)) ? 2*((height+31) >> 5) : (((height+15) >> 4) & ~1); MPEGOUT(ctx,0x00, ((control->picture_structure & XVMC_FRAME_PICTURE) << 2) | ((control->picture_coding_type & 3) << 4) | ((control->flags & XVMC_ALTERNATE_SCAN) ? (1 << 6) : 0)); if (!(ctx->intraLoaded)) { MPEGOUT(ctx,0x5c, 0); for (j = 0; j < 64; j += 4) { MPEGOUT(ctx,0x60, ctx->intra_quantiser_matrix[j] | (ctx->intra_quantiser_matrix[j+1] << 8) | (ctx->intra_quantiser_matrix[j+2] << 16) | (ctx->intra_quantiser_matrix[j+3] << 24)); } ctx->intraLoaded = 1; } if (!(ctx->nonIntraLoaded)) { MPEGOUT(ctx,0x5c, 1); for (j = 0; j < 64; j += 4) { MPEGOUT(ctx,0x60, ctx->non_intra_quantiser_matrix[j] | (ctx->non_intra_quantiser_matrix[j+1] << 8) | (ctx->non_intra_quantiser_matrix[j+2] << 16) | (ctx->non_intra_quantiser_matrix[j+3] << 24)); } ctx->nonIntraLoaded = 1; } MPEGOUT(ctx,0x90, ((mb_width * mb_height) & 0x3fff) | ((control->flags & XVMC_PRED_DCT_FRAME) ? ( 1 << 14) : 0) | ((control->flags & XVMC_TOP_FIELD_FIRST) ? (1 << 15) : 0 ) | ((control->mpeg_coding == XVMC_MPEG_2) ? (1 << 16) : 0) | ((mb_width & 0xff) << 18)); MPEGOUT(ctx,0x94, ((control->flags & XVMC_CONCEALMENT_MOTION_VECTORS) ? 1 : 0) | ((control->flags & XVMC_Q_SCALE_TYPE) ? 2 : 0) | ((control->intra_dc_precision & 3) << 2) | (((1 + 0x100000 / mb_width) & 0xfffff) << 4) | ((control->flags & XVMC_INTRA_VLC_FORMAT) ? (1 << 24) : 0)); MPEGOUT(ctx,0x98, (((control->FHMV_range) & 0xf) << 0) | (((control->FVMV_range) & 0xf) << 4) | (((control->BHMV_range) & 0xf) << 8) | (((control->BVMV_range) & 0xf) << 12) | ((control->flags & XVMC_SECOND_FIELD) ? (1 << 20) : 0) | (0x0a6 << 16)); } CARD32 viaMpegGetStatusLocked(ViaXvMCContext *ctx) { return MPEGIN(ctx,0x54); } int viaMpegIsBusyLocked(ViaXvMCContext *ctx, CARD32 mask, CARD32 idle) { CARD32 tmp = viaMpegGetStatusLocked(ctx); /* * Error detected. */ if (tmp & 0x70) return 0; return (tmp & mask) != idle; } int viaMpegSliceBusyLocked(ViaXvMCContext *ctx) { return (viaMpegGetStatusLocked(ctx) & (1 << 9)); } void viaMpegResetLocked(ViaXvMCContext *ctx) { int i,j; for (i = 0; i < 14; i++) MPEGOUT(ctx,0x08,0); MPEGOUT(ctx,0x98,0x400000); for (i = 0; i < 6; i++) { MPEGOUT(ctx,0x0c,0x43 | 0x20); for (j = 0x10; j < 0x20; j += 4) MPEGOUT(ctx,j,0); } MPEGOUT(ctx,0x0c, 0xc3 | 0x20); for (j = 0x10; j < 0x20; j += 4) MPEGOUT(ctx,j,0); } void viaMpegWriteSliceLocked(ViaXvMCContext *ctx, CARD8* slice, int nBytes, CARD32 sCode) { int i, n, r; CARD32* buf; n = nBytes >> 2; if (sCode) nBytes += 4; r = nBytes & 3; buf = (CARD32*) slice; if (r) nBytes += 4 - r; nBytes += 8; MPEGOUT(ctx,0x9c,nBytes); if (sCode) MPEGOUT(ctx,0xa0,sCode); for (i = 0; i < n; i++) { MPEGOUT(ctx,0xa0,*buf++); } if (r) { MPEGOUT(ctx,0xa0, *buf & ((1 << (r << 3)) - 1)); } MPEGOUT(ctx,0xa0,0); MPEGOUT(ctx,0xa0,0); } #endif static void viaVideoCBufFlushLocked(ViaXvMCContext *ctx,CommandBuffer *buf) { unsigned i; while( VIDIN(ctx,V_COMPOSE_MODE) & (V1_COMMAND_FIRE | V3_COMMAND_FIRE)); for (i=0; icurPos; ++i) VIDOUT(ctx,buf->offsets[i], buf->values[i]); buf->curPos = 0; } void viaVideoSubPictureOffLocked(ViaXvMCContext *ctx) { CommandBuffer buf; CARD32 stride; CLEAR_CBUFFER(&buf); stride = VIDIN(ctx,SUBP_CONTROL_STRIDE); CBUFFER(&buf, SUBP_CONTROL_STRIDE, stride & ~SUBP_HQV_ENABLE); viaVideoCBufFlushLocked(ctx,&buf); } void viaVideoSubPictureLocked(ViaXvMCSubPicture *pViaSubPic) { CommandBuffer buf; unsigned i; ViaXvMCContext *pViaXvMC; CARD32 cWord; CLEAR_CBUFFER(&buf); for (i=0; ipalette[i]); } CBUFFER(&buf, SUBP_STARTADDR, pViaSubPic->offset); cWord = (pViaSubPic->stride & SUBP_STRIDE_MASK) | SUBP_HQV_ENABLE; cWord |= (pViaSubPic->ia44) ? SUBP_IA44 : SUBP_AI44; CBUFFER(&buf, SUBP_CONTROL_STRIDE,cWord); pViaXvMC = pViaSubPic->privContext; viaVideoCBufFlushLocked(pViaXvMC,&buf); } static unsigned timeDiff(struct timeval *now,struct timeval *then) { return (now->tv_usec >= then->tv_usec) ? now->tv_usec - then->tv_usec : 1000000 - (then->tv_usec - now->tv_usec); } static int viaWaitIdleLocked(ViaXvMCContext *ctx) { struct timeval now,then; struct timezone here; here.tz_minuteswest = 0; here.tz_dsttime = 0; gettimeofday(&then,&here); while(!(REGIN(ctx, VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY)) { gettimeofday(&now,&here); if (timeDiff(&now,&then) > VIA_SYNCWAITTIMEOUT) return 1; } while(REGIN(ctx, VIA_REG_STATUS) & (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY)) { gettimeofday(&now,&here); if (timeDiff(&now,&then) > VIA_SYNCWAITTIMEOUT) return 1; } return 0; } void viaBlit(ViaXvMCContext *ctx,unsigned bpp,unsigned srcBase, unsigned srcPitch,unsigned dstBase,unsigned dstPitch, unsigned w,unsigned h,int xdir,int ydir, unsigned blitMode, unsigned color) { CARD32 dwGEMode = 0, srcY=0, srcX, dstY=0, dstX; CARD32 cmd, saveGEMode,saveSrcBase,saveDstBase,savePitch, saveCKey,saveColor; if (!w || !h) return; switch (bpp) { case 16: dwGEMode |= VIA_GEM_16bpp; break; case 32: dwGEMode |= VIA_GEM_32bpp; break; default: dwGEMode |= VIA_GEM_8bpp; break; } srcX = srcBase & 31; dstX = dstBase & 31; switch (bpp) { case 16: dwGEMode |= VIA_GEM_16bpp; srcX >>= 2; dstX >>= 2; break; case 32: dwGEMode |= VIA_GEM_32bpp; srcX >>= 4; dstX >>= 4; break; default: dwGEMode |= VIA_GEM_8bpp; break; } HW_LOCK(ctx); viaWaitIdleLocked(ctx); saveGEMode = REGIN(ctx,VIA_REG_GEMODE); saveSrcBase = REGIN(ctx,VIA_REG_SRCBASE); saveDstBase = REGIN(ctx,VIA_REG_DSTBASE); savePitch = REGIN(ctx,VIA_REG_PITCH); saveCKey = REGIN(ctx,VIA_REG_KEYCONTROL); saveColor = REGIN(ctx,VIA_REG_SRCCOLORKEY); REGOUT(ctx, VIA_REG_GEMODE, dwGEMode); cmd = 0; if (xdir < 0) { cmd |= VIA_GEC_DECX; srcX += (w - 1); dstX += (w - 1); } if (ydir < 0) { cmd |= VIA_GEC_DECY; srcY += (h - 1); dstY += (h - 1); } switch(blitMode) { case VIABLIT_TRANSCOPY: REGOUT(ctx, VIA_REG_SRCCOLORKEY, color); REGOUT(ctx, VIA_REG_KEYCONTROL, 0x4000); cmd |= VIA_GEC_BLT | (VIA_BLIT_COPY << 24); break; case VIABLIT_FILL: REGOUT(ctx, VIA_REG_FGCOLOR, color); cmd |= VIA_GEC_BLT | VIA_GEC_FIXCOLOR_PAT | (VIA_BLIT_FILL << 24); break; default: REGOUT(ctx, VIA_REG_KEYCONTROL, 0x0); cmd |= VIA_GEC_BLT | (VIA_BLIT_COPY << 24); } REGOUT(ctx, VIA_REG_SRCBASE, (srcBase & ~31) >> 3); REGOUT(ctx, VIA_REG_DSTBASE, (dstBase & ~31) >> 3); REGOUT(ctx, VIA_REG_PITCH, VIA_PITCH_ENABLE | (srcPitch >> 3) | (((dstPitch) >> 3) << 16)); REGOUT(ctx, VIA_REG_SRCPOS, ((srcY << 16) | srcX)); REGOUT(ctx, VIA_REG_DSTPOS, ((dstY << 16) | dstX)); REGOUT(ctx, VIA_REG_DIMENSION, (((h - 1) << 16) | (w - 1))); REGOUT(ctx, VIA_REG_GECMD, cmd); viaWaitIdleLocked(ctx); REGOUT(ctx,VIA_REG_GEMODE,saveGEMode); REGOUT(ctx,VIA_REG_SRCBASE,saveSrcBase); REGOUT(ctx,VIA_REG_DSTBASE,saveDstBase); REGOUT(ctx,VIA_REG_PITCH,savePitch); REGOUT(ctx,VIA_REG_KEYCONTROL,saveCKey); REGOUT(ctx,VIA_REG_SRCCOLORKEY,saveColor); HW_UNLOCK(ctx); }