190b17f1bSmrg/***************************************************************************** 290b17f1bSmrg * VIA Unichrome XvMC extension client lib. 390b17f1bSmrg * 490b17f1bSmrg * Copyright (c) 2004 Thomas Hellstr�m. All rights reserved. 590b17f1bSmrg * Copyright (c) 2003 Andreas Robinson. All rights reserved. 690b17f1bSmrg * 790b17f1bSmrg * Permission is hereby granted, free of charge, to any person obtaining a 890b17f1bSmrg * copy of this software and associated documentation files (the "Software"), 990b17f1bSmrg * to deal in the Software without restriction, including without limitation 1090b17f1bSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1190b17f1bSmrg * and/or sell copies of the Software, and to permit persons to whom the 1290b17f1bSmrg * Software is furnished to do so, subject to the following conditions: 1390b17f1bSmrg * 1490b17f1bSmrg * The above copyright notice and this permission notice shall be included in 1590b17f1bSmrg * all copies or substantial portions of the Software. 1690b17f1bSmrg * 1790b17f1bSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1890b17f1bSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1990b17f1bSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2090b17f1bSmrg * AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2190b17f1bSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2290b17f1bSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2390b17f1bSmrg * DEALINGS IN THE SOFTWARE. 2490b17f1bSmrg */ 2590b17f1bSmrg 2690b17f1bSmrg/* 2790b17f1bSmrg * Low-level functions that deal directly with the hardware. In the future, 2890b17f1bSmrg * these functions might be implemented in a kernel module. Also, some of them 2990b17f1bSmrg * would benefit from DMA. 3090b17f1bSmrg * 3190b17f1bSmrg * Authors: Andreas Robinson 2003. Thomas Hellstr�m 2004. 3290b17f1bSmrg */ 3390b17f1bSmrg 3490b17f1bSmrg#include "viaXvMCPriv.h" 3590b17f1bSmrg#include "viaLowLevel.h" 3690b17f1bSmrg#include <time.h> 3790b17f1bSmrg#include <sys/time.h> 3890b17f1bSmrg#include <stdio.h> 3990b17f1bSmrg 4090b17f1bSmrgtypedef struct 4190b17f1bSmrg{ 4290b17f1bSmrg CARD32 agp_buffer[LL_AGP_CMDBUF_SIZE]; 4390b17f1bSmrg CARD32 pci_buffer[LL_PCI_CMDBUF_SIZE]; 4490b17f1bSmrg unsigned agp_pos; 4590b17f1bSmrg unsigned pci_pos; 4690b17f1bSmrg unsigned flip_pos; 4790b17f1bSmrg int use_agp; 4890b17f1bSmrg int agp_mode; 4990b17f1bSmrg int agp_header_start; 5090b17f1bSmrg int agp_index; 5190b17f1bSmrg int fd; 5290b17f1bSmrg drm_context_t *drmcontext; 5390b17f1bSmrg drmLockPtr hwLock; 5490b17f1bSmrg drmAddress mmioAddress; 5590b17f1bSmrg drmAddress fbAddress; 5690b17f1bSmrg unsigned fbStride; 5790b17f1bSmrg unsigned fbDepth; 5890b17f1bSmrg unsigned width; 5990b17f1bSmrg unsigned height; 6090b17f1bSmrg unsigned curWaitFlags; 6190b17f1bSmrg int performLocking; 6290b17f1bSmrg unsigned errors; 6390b17f1bSmrg drm_via_mem_t tsMem; 6490b17f1bSmrg CARD32 tsOffset; 6590b17f1bSmrg volatile CARD32 *tsP; 6690b17f1bSmrg CARD32 curTimeStamp; 6790b17f1bSmrg CARD32 lastReadTimeStamp; 6890b17f1bSmrg int agpSync; 6990b17f1bSmrg CARD32 agpSyncTimeStamp; 7090b17f1bSmrg unsigned chipId; 7190b17f1bSmrg} XvMCLowLevel; 7290b17f1bSmrg 7390b17f1bSmrg/* 7490b17f1bSmrg * For Other architectures than i386 these might have to be modified for 7590b17f1bSmrg * bigendian etc. 7690b17f1bSmrg */ 7790b17f1bSmrg 7890b17f1bSmrg#define MPEGIN(xl,reg) \ 7990b17f1bSmrg *((volatile CARD32 *)(((CARD8 *)(xl)->mmioAddress) + 0xc00 + (reg))) 8090b17f1bSmrg 8190b17f1bSmrg#define VIDIN(ctx,reg) \ 8290b17f1bSmrg *((volatile CARD32 *)(((CARD8 *)(ctx)->mmioAddress) + (reg))) 8390b17f1bSmrg 8490b17f1bSmrg#define REGIN(ctx,reg) \ 8590b17f1bSmrg *((volatile CARD32 *)(((CARD8 *)(ctx)->mmioAddress) + 0x0000 + (reg))) 8690b17f1bSmrg 8790b17f1bSmrg#define HQV_CONTROL 0x3D0 8890b17f1bSmrg#define HQV_SRC_STARTADDR_Y 0x3D4 8990b17f1bSmrg#define HQV_SRC_STARTADDR_U 0x3D8 9090b17f1bSmrg#define HQV_SRC_STARTADDR_V 0x3DC 9190b17f1bSmrg#define HQV_MINIFY_DEBLOCK 0x3E8 9290b17f1bSmrg 9390b17f1bSmrg#define HQV_SW_FLIP 0x00000010 9490b17f1bSmrg#define HQV_FLIP_STATUS 0x00000001 9590b17f1bSmrg#define HQV_SUBPIC_FLIP 0x00008000 9690b17f1bSmrg#define HQV_FLIP_ODD 0x00000020 9790b17f1bSmrg#define HQV_DEINTERLACE 0x00010000 9890b17f1bSmrg#define HQV_FIELD_2_FRAME 0x00020000 9990b17f1bSmrg#define HQV_FRAME_2_FIELD 0x00040000 10090b17f1bSmrg#define HQV_FIELD_UV 0x00100000 10190b17f1bSmrg#define HQV_DEBLOCK_HOR 0x00008000 10290b17f1bSmrg#define HQV_DEBLOCK_VER 0x80000000 10390b17f1bSmrg 10490b17f1bSmrg#define V_COMPOSE_MODE 0x298 10590b17f1bSmrg#define V1_COMMAND_FIRE 0x80000000 10690b17f1bSmrg#define V3_COMMAND_FIRE 0x40000000 10790b17f1bSmrg 10890b17f1bSmrg/* SUBPICTURE Registers */ 10990b17f1bSmrg#define SUBP_CONTROL_STRIDE 0x3C0 11090b17f1bSmrg#define SUBP_STARTADDR 0x3C4 11190b17f1bSmrg#define RAM_TABLE_CONTROL 0x3C8 11290b17f1bSmrg#define RAM_TABLE_READ 0x3CC 11390b17f1bSmrg 11490b17f1bSmrg/* SUBP_CONTROL_STRIDE 0x3c0 */ 11590b17f1bSmrg#define SUBP_HQV_ENABLE 0x00010000 11690b17f1bSmrg#define SUBP_IA44 0x00020000 11790b17f1bSmrg#define SUBP_AI44 0x00000000 11890b17f1bSmrg#define SUBP_STRIDE_MASK 0x00001fff 11990b17f1bSmrg#define SUBP_CONTROL_MASK 0x00070000 12090b17f1bSmrg 12190b17f1bSmrg/* RAM_TABLE_CONTROL 0x3c8 */ 12290b17f1bSmrg#define RAM_TABLE_RGB_ENABLE 0x00000007 12390b17f1bSmrg 12490b17f1bSmrg#define VIA_REG_STATUS 0x400 12590b17f1bSmrg#define VIA_REG_GEMODE 0x004 12690b17f1bSmrg#define VIA_REG_SRCBASE 0x030 12790b17f1bSmrg#define VIA_REG_DSTBASE 0x034 12890b17f1bSmrg#define VIA_REG_PITCH 0x038 12990b17f1bSmrg#define VIA_REG_SRCCOLORKEY 0x01C 13090b17f1bSmrg#define VIA_REG_KEYCONTROL 0x02C 13190b17f1bSmrg#define VIA_REG_SRCPOS 0x008 13290b17f1bSmrg#define VIA_REG_DSTPOS 0x00C 13390b17f1bSmrg#define VIA_REG_GECMD 0x000 13490b17f1bSmrg#define VIA_REG_DIMENSION 0x010 /* width and height */ 13590b17f1bSmrg#define VIA_REG_FGCOLOR 0x018 13690b17f1bSmrg 13790b17f1bSmrg#define VIA_VR_QUEUE_BUSY 0x00020000 /* Virtual Queue is busy */ 13890b17f1bSmrg#define VIA_CMD_RGTR_BUSY 0x00000080 /* Command Regulator is busy */ 13990b17f1bSmrg#define VIA_2D_ENG_BUSY 0x00000002 /* 2D Engine is busy */ 14090b17f1bSmrg#define VIA_3D_ENG_BUSY 0x00000001 /* 3D Engine is busy */ 14190b17f1bSmrg#define VIA_GEM_8bpp 0x00000000 14290b17f1bSmrg#define VIA_GEM_16bpp 0x00000100 14390b17f1bSmrg#define VIA_GEM_32bpp 0x00000300 14490b17f1bSmrg#define VIA_GEC_BLT 0x00000001 14590b17f1bSmrg#define VIA_PITCH_ENABLE 0x80000000 14690b17f1bSmrg#define VIA_GEC_INCX 0x00000000 14790b17f1bSmrg#define VIA_GEC_DECY 0x00004000 14890b17f1bSmrg#define VIA_GEC_INCY 0x00000000 14990b17f1bSmrg#define VIA_GEC_DECX 0x00008000 15090b17f1bSmrg#define VIA_GEC_FIXCOLOR_PAT 0x00002000 15190b17f1bSmrg 15290b17f1bSmrg#define VIA_BLIT_CLEAR 0x00 15390b17f1bSmrg#define VIA_BLIT_COPY 0xCC 15490b17f1bSmrg#define VIA_BLIT_FILL 0xF0 15590b17f1bSmrg#define VIA_BLIT_SET 0xFF 15690b17f1bSmrg 15790b17f1bSmrg#define VIA_SYNCWAITTIMEOUT 50000 /* Might be a bit conservative */ 15890b17f1bSmrg#define VIA_DMAWAITTIMEOUT 150000 15990b17f1bSmrg#define VIA_VIDWAITTIMEOUT 50000 16090b17f1bSmrg#define VIA_XVMC_DECODERTIMEOUT 50000 /*(microseconds) */ 16190b17f1bSmrg 16290b17f1bSmrg#define H1_ADDR(val) (((val) >> 2) | 0xF0000000) 16390b17f1bSmrg#define WAITFLAGS(xl, flags) \ 16490b17f1bSmrg (xl)->curWaitFlags |= (flags) 16590b17f1bSmrg#define BEGIN_RING_AGP(xl,size) \ 16690b17f1bSmrg do { \ 16790b17f1bSmrg if ((xl)->agp_pos > (LL_AGP_CMDBUF_SIZE-(size))) { \ 16890b17f1bSmrg agpFlush(xl); \ 16990b17f1bSmrg } \ 17090b17f1bSmrg } while(0) 17190b17f1bSmrg#define OUT_RING_AGP(xl, val) \ 17290b17f1bSmrg (xl)->agp_buffer[(xl)->agp_pos++] = (val) 17390b17f1bSmrg#define OUT_RING_QW_AGP(xl, val1, val2) \ 17490b17f1bSmrg do { \ 17590b17f1bSmrg (xl)->agp_buffer[(xl)->agp_pos++] = (val1); \ 17690b17f1bSmrg (xl)->agp_buffer[(xl)->agp_pos++] = (val2); \ 17790b17f1bSmrg } while (0) 17890b17f1bSmrg 17990b17f1bSmrg#define LL_HW_LOCK(xl) \ 18090b17f1bSmrg do { \ 18190b17f1bSmrg DRM_LOCK((xl)->fd,(xl)->hwLock,*(xl)->drmcontext,0); \ 18290b17f1bSmrg } while(0); 18390b17f1bSmrg#define LL_HW_UNLOCK(xl) \ 18490b17f1bSmrg do { \ 18590b17f1bSmrg DRM_UNLOCK((xl)->fd,(xl)->hwLock,*(xl)->drmcontext); \ 18690b17f1bSmrg } while(0); 18790b17f1bSmrg 18890b17f1bSmrg/* 18990b17f1bSmrg * We want to have two concurrent types of thread taking the hardware 19090b17f1bSmrg * lock simulataneously. One is the video out thread that needs immediate 19190b17f1bSmrg * access to flip an image. The other is everything else which may have 19290b17f1bSmrg * the lock for quite some time. This is only so the video out thread can 19390b17f1bSmrg * sneak in and display an image while other resources are busy. 19490b17f1bSmrg */ 19590b17f1bSmrg 19690b17f1bSmrgvoid 19790b17f1bSmrghwlLock(void *xlp, int videoLock) 19890b17f1bSmrg{ 19990b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 20090b17f1bSmrg 20190b17f1bSmrg LL_HW_LOCK(xl); 20290b17f1bSmrg} 20390b17f1bSmrg 20490b17f1bSmrgvoid 20590b17f1bSmrghwlUnlock(void *xlp, int videoLock) 20690b17f1bSmrg{ 20790b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 20890b17f1bSmrg 20990b17f1bSmrg LL_HW_UNLOCK(xl); 21090b17f1bSmrg} 21190b17f1bSmrg 21290b17f1bSmrgstatic unsigned 21390b17f1bSmrgtimeDiff(struct timeval *now, struct timeval *then) 21490b17f1bSmrg{ 21590b17f1bSmrg return (now->tv_usec >= then->tv_usec) ? 21690b17f1bSmrg now->tv_usec - then->tv_usec : 21790b17f1bSmrg 1000000 - (then->tv_usec - now->tv_usec); 21890b17f1bSmrg} 21990b17f1bSmrg 22090b17f1bSmrgvoid 22190b17f1bSmrgsetAGPSyncLowLevel(void *xlp, int val, CARD32 timeStamp) 22290b17f1bSmrg{ 22390b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 22490b17f1bSmrg 22590b17f1bSmrg xl->agpSync = val; 22690b17f1bSmrg xl->agpSyncTimeStamp = timeStamp; 22790b17f1bSmrg} 22890b17f1bSmrg 22990b17f1bSmrgCARD32 23090b17f1bSmrgviaDMATimeStampLowLevel(void *xlp) 23190b17f1bSmrg{ 23290b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 23390b17f1bSmrg 23490b17f1bSmrg if (xl->use_agp) { 23590b17f1bSmrg viaBlit(xl, 32, xl->tsOffset, 1, xl->tsOffset, 1, 1, 1, 0, 0, 23690b17f1bSmrg VIABLIT_FILL, xl->curTimeStamp); 23790b17f1bSmrg return xl->curTimeStamp++; 23890b17f1bSmrg } 23990b17f1bSmrg return 0; 24090b17f1bSmrg} 24190b17f1bSmrg 24290b17f1bSmrgstatic void 24390b17f1bSmrgviaDMAWaitTimeStamp(XvMCLowLevel * xl, CARD32 timeStamp, int doSleep) 24490b17f1bSmrg{ 24590b17f1bSmrg struct timeval now, then; 24690b17f1bSmrg struct timezone here; 24790b17f1bSmrg struct timespec sleep, rem; 24890b17f1bSmrg 24990b17f1bSmrg if (xl->use_agp && (timeStamp > xl->lastReadTimeStamp)) { 25090b17f1bSmrg sleep.tv_nsec = 1; 25190b17f1bSmrg sleep.tv_sec = 0; 25290b17f1bSmrg here.tz_minuteswest = 0; 25390b17f1bSmrg here.tz_dsttime = 0; 25490b17f1bSmrg gettimeofday(&then, &here); 25590b17f1bSmrg 25690b17f1bSmrg while (timeStamp > (xl->lastReadTimeStamp = *xl->tsP)) { 25790b17f1bSmrg gettimeofday(&now, &here); 25890b17f1bSmrg if (timeDiff(&now, &then) > VIA_DMAWAITTIMEOUT) { 25990b17f1bSmrg if ((timeStamp > (xl->lastReadTimeStamp = *xl->tsP))) { 26090b17f1bSmrg xl->errors |= LL_DMA_TIMEDOUT; 26190b17f1bSmrg break; 26290b17f1bSmrg } 26390b17f1bSmrg } 26490b17f1bSmrg if (doSleep) 26590b17f1bSmrg nanosleep(&sleep, &rem); 26690b17f1bSmrg } 26790b17f1bSmrg } 26890b17f1bSmrg} 26990b17f1bSmrg 27090b17f1bSmrgstatic int 27190b17f1bSmrgviaDMAInitTimeStamp(XvMCLowLevel * xl) 27290b17f1bSmrg{ 27390b17f1bSmrg int ret = 0; 27490b17f1bSmrg 27590b17f1bSmrg if (xl->use_agp) { 27690b17f1bSmrg xl->tsMem.context = *(xl->drmcontext); 27790b17f1bSmrg xl->tsMem.size = 64; 27890b17f1bSmrg xl->tsMem.type = VIA_MEM_VIDEO; 27990b17f1bSmrg if ((ret = drmCommandWriteRead(xl->fd, DRM_VIA_ALLOCMEM, &xl->tsMem, 28090b17f1bSmrg sizeof(xl->tsMem))) < 0) 28190b17f1bSmrg return ret; 28290b17f1bSmrg if (xl->tsMem.size != 64) 28390b17f1bSmrg return -1; 28490b17f1bSmrg xl->tsOffset = (xl->tsMem.offset + 31) & ~31; 28590b17f1bSmrg xl->tsP = (CARD32 *) xl->fbAddress + (xl->tsOffset >> 2); 28690b17f1bSmrg xl->curTimeStamp = 1; 28790b17f1bSmrg *xl->tsP = 0; 28890b17f1bSmrg } 28990b17f1bSmrg return 0; 29090b17f1bSmrg} 29190b17f1bSmrg 29290b17f1bSmrgstatic int 29390b17f1bSmrgviaDMACleanupTimeStamp(XvMCLowLevel * xl) 29490b17f1bSmrg{ 29590b17f1bSmrg 29690b17f1bSmrg if (!(xl->tsMem.size) || !xl->use_agp) 29790b17f1bSmrg return 0; 29890b17f1bSmrg return drmCommandWrite(xl->fd, DRM_VIA_FREEMEM, &xl->tsMem, 29990b17f1bSmrg sizeof(xl->tsMem)); 30090b17f1bSmrg} 30190b17f1bSmrg 30290b17f1bSmrgstatic CARD32 30390b17f1bSmrgviaMpegGetStatus(XvMCLowLevel * xl) 30490b17f1bSmrg{ 30590b17f1bSmrg return MPEGIN(xl, 0x54); 30690b17f1bSmrg} 30790b17f1bSmrg 30890b17f1bSmrgstatic int 30990b17f1bSmrgviaMpegIsBusy(XvMCLowLevel * xl, CARD32 mask, CARD32 idle) 31090b17f1bSmrg{ 31190b17f1bSmrg CARD32 tmp = viaMpegGetStatus(xl); 31290b17f1bSmrg 31390b17f1bSmrg /* 31490b17f1bSmrg * Error detected. 31590b17f1bSmrg * FIXME: Are errors really shown when error concealment is on? 31690b17f1bSmrg */ 31790b17f1bSmrg 31890b17f1bSmrg if (tmp & 0x70) 31990b17f1bSmrg return 0; 32090b17f1bSmrg 32190b17f1bSmrg return (tmp & mask) != idle; 32290b17f1bSmrg} 32390b17f1bSmrg 32490b17f1bSmrgstatic void 32590b17f1bSmrgsyncDMA(XvMCLowLevel * xl, unsigned int doSleep) 32690b17f1bSmrg{ 32790b17f1bSmrg 32890b17f1bSmrg /* 32990b17f1bSmrg * Ideally, we'd like to have an interrupt wait here, but, according to second hand 33090b17f1bSmrg * information, the hardware does not support this, although earlier S3 chips do that. 33190b17f1bSmrg * It is therefore not implemented into the DRM, and we'll do a user space wait here. 33290b17f1bSmrg */ 33390b17f1bSmrg 33490b17f1bSmrg struct timeval now, then; 33590b17f1bSmrg struct timezone here; 33690b17f1bSmrg struct timespec sleep, rem; 33790b17f1bSmrg 33890b17f1bSmrg sleep.tv_nsec = 1; 33990b17f1bSmrg sleep.tv_sec = 0; 34090b17f1bSmrg here.tz_minuteswest = 0; 34190b17f1bSmrg here.tz_dsttime = 0; 34290b17f1bSmrg gettimeofday(&then, &here); 34390b17f1bSmrg while (!(REGIN(xl, VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY)) { 34490b17f1bSmrg gettimeofday(&now, &here); 34590b17f1bSmrg if (timeDiff(&now, &then) > VIA_DMAWAITTIMEOUT) { 34690b17f1bSmrg if (!(REGIN(xl, VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY)) { 34790b17f1bSmrg xl->errors |= LL_DMA_TIMEDOUT; 34890b17f1bSmrg break; 34990b17f1bSmrg } 35090b17f1bSmrg } 35190b17f1bSmrg if (doSleep) 35290b17f1bSmrg nanosleep(&sleep, &rem); 35390b17f1bSmrg } 35490b17f1bSmrg while (REGIN(xl, VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) { 35590b17f1bSmrg gettimeofday(&now, &here); 35690b17f1bSmrg if (timeDiff(&now, &then) > VIA_DMAWAITTIMEOUT) { 35790b17f1bSmrg if (REGIN(xl, VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) { 35890b17f1bSmrg xl->errors |= LL_DMA_TIMEDOUT; 35990b17f1bSmrg break; 36090b17f1bSmrg } 36190b17f1bSmrg } 36290b17f1bSmrg if (doSleep) 36390b17f1bSmrg nanosleep(&sleep, &rem); 36490b17f1bSmrg } 36590b17f1bSmrg} 36690b17f1bSmrg 36790b17f1bSmrgstatic void 36890b17f1bSmrgsyncVideo(XvMCLowLevel * xl, unsigned int doSleep) 36990b17f1bSmrg{ 37090b17f1bSmrg /* 37190b17f1bSmrg * Wait for HQV completion. Nothing strange here. We assume that the HQV 37290b17f1bSmrg * Handles syncing to the V1 / V3 engines by itself. It should be safe to 37390b17f1bSmrg * always wait for SUBPIC_FLIP completion although subpictures are not 37490b17f1bSmrg * always used. 37590b17f1bSmrg */ 37690b17f1bSmrg 37790b17f1bSmrg struct timeval now, then; 37890b17f1bSmrg struct timezone here; 37990b17f1bSmrg struct timespec sleep, rem; 38090b17f1bSmrg 38190b17f1bSmrg sleep.tv_nsec = 1; 38290b17f1bSmrg sleep.tv_sec = 0; 38390b17f1bSmrg here.tz_minuteswest = 0; 38490b17f1bSmrg here.tz_dsttime = 0; 38590b17f1bSmrg gettimeofday(&then, &here); 38690b17f1bSmrg while (VIDIN(xl, HQV_CONTROL) & (HQV_SW_FLIP | HQV_SUBPIC_FLIP)) { 38790b17f1bSmrg gettimeofday(&now, &here); 38890b17f1bSmrg if (timeDiff(&now, &then) > VIA_SYNCWAITTIMEOUT) { 38990b17f1bSmrg if (VIDIN(xl, HQV_CONTROL) & (HQV_SW_FLIP | HQV_SUBPIC_FLIP)) { 39090b17f1bSmrg xl->errors |= LL_VIDEO_TIMEDOUT; 39190b17f1bSmrg break; 39290b17f1bSmrg } 39390b17f1bSmrg } 39490b17f1bSmrg if (doSleep) 39590b17f1bSmrg nanosleep(&sleep, &rem); 39690b17f1bSmrg } 39790b17f1bSmrg} 39890b17f1bSmrg 39990b17f1bSmrgstatic void 40090b17f1bSmrgsyncAccel(XvMCLowLevel * xl, unsigned int mode, unsigned int doSleep) 40190b17f1bSmrg{ 40290b17f1bSmrg struct timeval now, then; 40390b17f1bSmrg struct timezone here; 40490b17f1bSmrg struct timespec sleep, rem; 40590b17f1bSmrg CARD32 mask = ((mode & LL_MODE_2D) ? VIA_2D_ENG_BUSY : 0) | 40690b17f1bSmrg ((mode & LL_MODE_3D) ? VIA_3D_ENG_BUSY : 0); 40790b17f1bSmrg 40890b17f1bSmrg sleep.tv_nsec = 1; 40990b17f1bSmrg sleep.tv_sec = 0; 41090b17f1bSmrg here.tz_minuteswest = 0; 41190b17f1bSmrg here.tz_dsttime = 0; 41290b17f1bSmrg gettimeofday(&then, &here); 41390b17f1bSmrg while (REGIN(xl, VIA_REG_STATUS) & mask) { 41490b17f1bSmrg gettimeofday(&now, &here); 41590b17f1bSmrg if (timeDiff(&now, &then) > VIA_SYNCWAITTIMEOUT) { 41690b17f1bSmrg if (REGIN(xl, VIA_REG_STATUS) & mask) { 41790b17f1bSmrg xl->errors |= LL_ACCEL_TIMEDOUT; 41890b17f1bSmrg break; 41990b17f1bSmrg } 42090b17f1bSmrg } 42190b17f1bSmrg if (doSleep) 42290b17f1bSmrg nanosleep(&sleep, &rem); 42390b17f1bSmrg } 42490b17f1bSmrg} 42590b17f1bSmrg 42690b17f1bSmrgstatic void 42790b17f1bSmrgsyncMpeg(XvMCLowLevel * xl, unsigned int mode, unsigned int doSleep) 42890b17f1bSmrg{ 42990b17f1bSmrg /* 43090b17f1bSmrg * Ideally, we'd like to have an interrupt wait here, but from information from VIA 43190b17f1bSmrg * at least the MPEG completion interrupt is broken on the CLE266, which was 43290b17f1bSmrg * discovered during validation of the chip. 43390b17f1bSmrg */ 43490b17f1bSmrg 43590b17f1bSmrg struct timeval now, then; 43690b17f1bSmrg struct timezone here; 43790b17f1bSmrg struct timespec sleep, rem; 43890b17f1bSmrg CARD32 busyMask = 0; 43990b17f1bSmrg CARD32 idleVal = 0; 44090b17f1bSmrg CARD32 ret; 44190b17f1bSmrg 44290b17f1bSmrg sleep.tv_nsec = 1; 44390b17f1bSmrg sleep.tv_sec = 0; 44490b17f1bSmrg here.tz_minuteswest = 0; 44590b17f1bSmrg here.tz_dsttime = 0; 44690b17f1bSmrg gettimeofday(&then, &here); 44790b17f1bSmrg if (mode & LL_MODE_DECODER_SLICE) { 44890b17f1bSmrg busyMask = VIA_SLICEBUSYMASK; 44990b17f1bSmrg idleVal = VIA_SLICEIDLEVAL; 45090b17f1bSmrg } 45190b17f1bSmrg if (mode & LL_MODE_DECODER_IDLE) { 45290b17f1bSmrg busyMask |= VIA_BUSYMASK; 45390b17f1bSmrg idleVal = VIA_IDLEVAL; 45490b17f1bSmrg } 45590b17f1bSmrg while (viaMpegIsBusy(xl, busyMask, idleVal)) { 45690b17f1bSmrg gettimeofday(&now, &here); 45790b17f1bSmrg if (timeDiff(&now, &then) > VIA_XVMC_DECODERTIMEOUT) { 45890b17f1bSmrg if (viaMpegIsBusy(xl, busyMask, idleVal)) { 45990b17f1bSmrg xl->errors |= LL_DECODER_TIMEDOUT; 46090b17f1bSmrg } 46190b17f1bSmrg break; 46290b17f1bSmrg } 46390b17f1bSmrg if (doSleep) 46490b17f1bSmrg nanosleep(&sleep, &rem); 46590b17f1bSmrg } 46690b17f1bSmrg 46790b17f1bSmrg ret = viaMpegGetStatus(xl); 46890b17f1bSmrg if (ret & 0x70) { 46990b17f1bSmrg xl->errors |= ((ret & 0x70) >> 3); 47090b17f1bSmrg } 47190b17f1bSmrg return; 47290b17f1bSmrg} 47390b17f1bSmrg 47490b17f1bSmrgstatic void 47590b17f1bSmrgpciFlush(XvMCLowLevel * xl) 47690b17f1bSmrg{ 47790b17f1bSmrg int ret; 47890b17f1bSmrg drm_via_cmdbuffer_t b; 47990b17f1bSmrg unsigned mode = xl->curWaitFlags; 48090b17f1bSmrg 48190b17f1bSmrg b.buf = (char *)xl->pci_buffer; 48290b17f1bSmrg b.size = xl->pci_pos * sizeof(CARD32); 48390b17f1bSmrg if (xl->performLocking) 48490b17f1bSmrg hwlLock(xl, 0); 48590b17f1bSmrg if ((mode != LL_MODE_VIDEO) && (mode != 0)) 48690b17f1bSmrg syncDMA(xl, 0); 48790b17f1bSmrg if ((mode & LL_MODE_2D) || (mode & LL_MODE_3D)) 48890b17f1bSmrg syncAccel(xl, mode, 0); 48990b17f1bSmrg if (mode & LL_MODE_VIDEO) 49090b17f1bSmrg syncVideo(xl, 0); 49190b17f1bSmrg if (mode & (LL_MODE_DECODER_SLICE | LL_MODE_DECODER_IDLE)) 49290b17f1bSmrg syncMpeg(xl, mode, 0); 49390b17f1bSmrg ret = drmCommandWrite(xl->fd, DRM_VIA_PCICMD, &b, sizeof(b)); 49490b17f1bSmrg if (xl->performLocking) 49590b17f1bSmrg hwlUnlock(xl, 0); 49690b17f1bSmrg if (ret) { 49790b17f1bSmrg xl->errors |= LL_PCI_COMMAND_ERR; 49890b17f1bSmrg } 49990b17f1bSmrg xl->pci_pos = 0; 50090b17f1bSmrg xl->curWaitFlags = 0; 50190b17f1bSmrg} 50290b17f1bSmrg 50390b17f1bSmrgstatic void 50490b17f1bSmrgagpFlush(XvMCLowLevel * xl) 50590b17f1bSmrg{ 50690b17f1bSmrg drm_via_cmdbuffer_t b; 50790b17f1bSmrg int ret; 50890b17f1bSmrg 50990b17f1bSmrg if (xl->use_agp) { 51090b17f1bSmrg b.buf = (char *)xl->agp_buffer; 51190b17f1bSmrg b.size = xl->agp_pos * sizeof(CARD32); 51290b17f1bSmrg if (xl->agpSync) { 51390b17f1bSmrg syncXvMCLowLevel(xl, LL_MODE_DECODER_IDLE, 1, 51490b17f1bSmrg xl->agpSyncTimeStamp); 51590b17f1bSmrg xl->agpSync = 0; 51690b17f1bSmrg } 51790b17f1bSmrg if (xl->performLocking) 51890b17f1bSmrg hwlLock(xl, 0); 51990b17f1bSmrg do { 52090b17f1bSmrg ret = drmCommandWrite(xl->fd, DRM_VIA_CMDBUFFER, &b, sizeof(b)); 52190b17f1bSmrg } while (-EAGAIN == ret); 52290b17f1bSmrg if (xl->performLocking) 52390b17f1bSmrg hwlUnlock(xl, 0); 52490b17f1bSmrg 52590b17f1bSmrg if (ret) { 52690b17f1bSmrg xl->errors |= LL_AGP_COMMAND_ERR; 52790b17f1bSmrg } else { 52890b17f1bSmrg xl->agp_pos = 0; 52990b17f1bSmrg } 53090b17f1bSmrg xl->curWaitFlags &= LL_MODE_VIDEO; 53190b17f1bSmrg } else { 53290b17f1bSmrg unsigned mode = xl->curWaitFlags; 53390b17f1bSmrg 53490b17f1bSmrg b.buf = (char *)xl->agp_buffer; 53590b17f1bSmrg b.size = xl->agp_pos * sizeof(CARD32); 53690b17f1bSmrg if (xl->performLocking) 53790b17f1bSmrg hwlLock(xl, 0); 53890b17f1bSmrg if ((mode != LL_MODE_VIDEO) && (mode != 0)) 53990b17f1bSmrg syncDMA(xl, 0); 54090b17f1bSmrg if ((mode & LL_MODE_2D) || (mode & LL_MODE_3D)) 54190b17f1bSmrg syncAccel(xl, mode, 0); 54290b17f1bSmrg if (mode & LL_MODE_VIDEO) 54390b17f1bSmrg syncVideo(xl, 0); 54490b17f1bSmrg if (mode & (LL_MODE_DECODER_SLICE | LL_MODE_DECODER_IDLE)) 54590b17f1bSmrg syncMpeg(xl, mode, 0); 54690b17f1bSmrg ret = drmCommandWrite(xl->fd, DRM_VIA_PCICMD, &b, sizeof(b)); 54790b17f1bSmrg if (xl->performLocking) 54890b17f1bSmrg hwlUnlock(xl, 0); 54990b17f1bSmrg if (ret) { 55090b17f1bSmrg xl->errors |= LL_PCI_COMMAND_ERR; 55190b17f1bSmrg } 55290b17f1bSmrg xl->agp_pos = 0; 55390b17f1bSmrg xl->curWaitFlags = 0; 55490b17f1bSmrg } 55590b17f1bSmrg} 55690b17f1bSmrg 55790b17f1bSmrgunsigned 55890b17f1bSmrgflushXvMCLowLevel(void *xlp) 55990b17f1bSmrg{ 56090b17f1bSmrg unsigned errors; 56190b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 56290b17f1bSmrg 56390b17f1bSmrg if (xl->pci_pos) 56490b17f1bSmrg pciFlush(xl); 56590b17f1bSmrg if (xl->agp_pos) 56690b17f1bSmrg agpFlush(xl); 56790b17f1bSmrg errors = xl->errors; 56890b17f1bSmrg xl->errors = 0; 56990b17f1bSmrg return errors; 57090b17f1bSmrg} 57190b17f1bSmrg 57290b17f1bSmrgvoid 57390b17f1bSmrgflushPCIXvMCLowLevel(void *xlp) 57490b17f1bSmrg{ 57590b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 57690b17f1bSmrg 57790b17f1bSmrg if (xl->pci_pos) 57890b17f1bSmrg pciFlush(xl); 57990b17f1bSmrg if (!xl->use_agp && xl->agp_pos) 58090b17f1bSmrg agpFlush(xl); 58190b17f1bSmrg} 58290b17f1bSmrg 58390b17f1bSmrg__inline static void 58490b17f1bSmrgpciCommand(XvMCLowLevel * xl, unsigned offset, unsigned value, unsigned flags) 58590b17f1bSmrg{ 58690b17f1bSmrg if (xl->pci_pos > (LL_PCI_CMDBUF_SIZE - 2)) 58790b17f1bSmrg pciFlush(xl); 58890b17f1bSmrg if (flags) 58990b17f1bSmrg xl->curWaitFlags |= flags; 59090b17f1bSmrg xl->pci_buffer[xl->pci_pos++] = (offset >> 2) | 0xF0000000; 59190b17f1bSmrg xl->pci_buffer[xl->pci_pos++] = value; 59290b17f1bSmrg} 59390b17f1bSmrg 59490b17f1bSmrgvoid 59590b17f1bSmrgviaMpegSetSurfaceStride(void *xlp, ViaXvMCContext * ctx) 59690b17f1bSmrg{ 59790b17f1bSmrg CARD32 y_stride = ctx->yStride; 59890b17f1bSmrg CARD32 uv_stride = y_stride >> 1; 59990b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 60090b17f1bSmrg 60190b17f1bSmrg BEGIN_RING_AGP(xl, 2); 60290b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc50), 60390b17f1bSmrg (y_stride >> 3) | ((uv_stride >> 3) << 16)); 60490b17f1bSmrg WAITFLAGS(xl, LL_MODE_DECODER_IDLE); 60590b17f1bSmrg} 60690b17f1bSmrg 60790b17f1bSmrgvoid 60890b17f1bSmrgviaVideoSetSWFLipLocked(void *xlp, unsigned yOffs, unsigned uOffs, 60990b17f1bSmrg unsigned vOffs, unsigned yStride, unsigned uvStride) 61090b17f1bSmrg{ 61190b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 61290b17f1bSmrg 61390b17f1bSmrg pciCommand(xl, HQV_SRC_STARTADDR_Y, yOffs, LL_MODE_VIDEO); 61490b17f1bSmrg pciCommand(xl, HQV_SRC_STARTADDR_U, uOffs, 0); 61590b17f1bSmrg pciCommand(xl, HQV_SRC_STARTADDR_V, vOffs, 0); 61690b17f1bSmrg} 61790b17f1bSmrg 61890b17f1bSmrgvoid 61990b17f1bSmrgviaVideoSWFlipLocked(void *xlp, unsigned flags, int progressiveSequence) 62090b17f1bSmrg{ 62190b17f1bSmrg CARD32 andWd, orWd; 62290b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 62390b17f1bSmrg 62490b17f1bSmrg andWd = 0; 62590b17f1bSmrg orWd = 0; 62690b17f1bSmrg 62790b17f1bSmrg if ((flags & XVMC_FRAME_PICTURE) == XVMC_BOTTOM_FIELD) { 62890b17f1bSmrg andWd = 0xFFFFFFFFU; 62990b17f1bSmrg orWd = HQV_FIELD_UV | 63090b17f1bSmrg HQV_DEINTERLACE | 63190b17f1bSmrg HQV_FIELD_2_FRAME | 63290b17f1bSmrg HQV_FRAME_2_FIELD | 63390b17f1bSmrg HQV_SW_FLIP | HQV_FLIP_ODD | HQV_FLIP_STATUS | HQV_SUBPIC_FLIP; 63490b17f1bSmrg } else if ((flags & XVMC_FRAME_PICTURE) == XVMC_TOP_FIELD) { 63590b17f1bSmrg andWd = ~HQV_FLIP_ODD; 63690b17f1bSmrg orWd = HQV_FIELD_UV | 63790b17f1bSmrg HQV_DEINTERLACE | 63890b17f1bSmrg HQV_FIELD_2_FRAME | 63990b17f1bSmrg HQV_FRAME_2_FIELD | 64090b17f1bSmrg HQV_SW_FLIP | HQV_FLIP_STATUS | HQV_SUBPIC_FLIP; 64190b17f1bSmrg } else if ((flags & XVMC_FRAME_PICTURE) == XVMC_FRAME_PICTURE) { 64290b17f1bSmrg andWd = ~(HQV_DEINTERLACE | 64390b17f1bSmrg HQV_FRAME_2_FIELD | HQV_FIELD_2_FRAME | HQV_FIELD_UV); 64490b17f1bSmrg orWd = HQV_SW_FLIP | HQV_FLIP_STATUS | HQV_SUBPIC_FLIP; 64590b17f1bSmrg } 64690b17f1bSmrg if (progressiveSequence) { 64790b17f1bSmrg andWd &= ~HQV_FIELD_UV; 64890b17f1bSmrg orWd &= ~HQV_FIELD_UV; 64990b17f1bSmrg } 65090b17f1bSmrg 65190b17f1bSmrg pciCommand(xl, HQV_CONTROL, (VIDIN(xl, 65290b17f1bSmrg HQV_CONTROL) & andWd) | orWd, 0); 65390b17f1bSmrg} 65490b17f1bSmrg 65590b17f1bSmrgvoid 65690b17f1bSmrgviaMpegSetFB(void *xlp, unsigned i, 65790b17f1bSmrg unsigned yOffs, unsigned uOffs, unsigned vOffs) 65890b17f1bSmrg{ 65990b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 66090b17f1bSmrg 66190b17f1bSmrg i *= 12; 66290b17f1bSmrg BEGIN_RING_AGP(xl, 6); 66390b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc20 + i), yOffs >> 3); 66490b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc24 + i), uOffs >> 3); 66590b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc28 + i), vOffs >> 3); 66690b17f1bSmrg WAITFLAGS(xl, LL_MODE_DECODER_IDLE); 66790b17f1bSmrg} 66890b17f1bSmrg 66990b17f1bSmrgvoid 67090b17f1bSmrgviaMpegBeginPicture(void *xlp, ViaXvMCContext * ctx, 67190b17f1bSmrg unsigned width, unsigned height, const XvMCMpegControl * control) 67290b17f1bSmrg{ 67390b17f1bSmrg 67490b17f1bSmrg unsigned j, mb_width, mb_height; 67590b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 67690b17f1bSmrg 67790b17f1bSmrg mb_width = (width + 15) >> 4; 67890b17f1bSmrg 67990b17f1bSmrg mb_height = 68090b17f1bSmrg ((control->mpeg_coding == XVMC_MPEG_2) && 68190b17f1bSmrg (control->flags & XVMC_PROGRESSIVE_SEQUENCE)) ? 68290b17f1bSmrg 2 * ((height + 31) >> 5) : (((height + 15) >> 4)); 68390b17f1bSmrg 68490b17f1bSmrg BEGIN_RING_AGP(xl, 144); 68590b17f1bSmrg WAITFLAGS(xl, LL_MODE_DECODER_IDLE); 68690b17f1bSmrg 68790b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc00), 68890b17f1bSmrg ((control->picture_structure & XVMC_FRAME_PICTURE) << 2) | 68990b17f1bSmrg ((control->picture_coding_type & 3) << 4) | 69090b17f1bSmrg ((control->flags & XVMC_ALTERNATE_SCAN) ? (1 << 6) : 0)); 69190b17f1bSmrg 69290b17f1bSmrg if (!(ctx->intraLoaded)) { 69390b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc5c), 0); 69490b17f1bSmrg for (j = 0; j < 64; j += 4) { 69590b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc60), 69690b17f1bSmrg ctx->intra_quantiser_matrix[j] | 69790b17f1bSmrg (ctx->intra_quantiser_matrix[j + 1] << 8) | 69890b17f1bSmrg (ctx->intra_quantiser_matrix[j + 2] << 16) | 69990b17f1bSmrg (ctx->intra_quantiser_matrix[j + 3] << 24)); 70090b17f1bSmrg } 70190b17f1bSmrg ctx->intraLoaded = 1; 70290b17f1bSmrg } 70390b17f1bSmrg 70490b17f1bSmrg if (!(ctx->nonIntraLoaded)) { 70590b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc5c), 1); 70690b17f1bSmrg for (j = 0; j < 64; j += 4) { 70790b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc60), 70890b17f1bSmrg ctx->non_intra_quantiser_matrix[j] | 70990b17f1bSmrg (ctx->non_intra_quantiser_matrix[j + 1] << 8) | 71090b17f1bSmrg (ctx->non_intra_quantiser_matrix[j + 2] << 16) | 71190b17f1bSmrg (ctx->non_intra_quantiser_matrix[j + 3] << 24)); 71290b17f1bSmrg } 71390b17f1bSmrg ctx->nonIntraLoaded = 1; 71490b17f1bSmrg } 71590b17f1bSmrg 71690b17f1bSmrg if (!(ctx->chromaIntraLoaded)) { 71790b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc5c), 2); 71890b17f1bSmrg for (j = 0; j < 64; j += 4) { 71990b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc60), 72090b17f1bSmrg ctx->chroma_intra_quantiser_matrix[j] | 72190b17f1bSmrg (ctx->chroma_intra_quantiser_matrix[j + 1] << 8) | 72290b17f1bSmrg (ctx->chroma_intra_quantiser_matrix[j + 2] << 16) | 72390b17f1bSmrg (ctx->chroma_intra_quantiser_matrix[j + 3] << 24)); 72490b17f1bSmrg } 72590b17f1bSmrg ctx->chromaIntraLoaded = 1; 72690b17f1bSmrg } 72790b17f1bSmrg 72890b17f1bSmrg if (!(ctx->chromaNonIntraLoaded)) { 72990b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc5c), 3); 73090b17f1bSmrg for (j = 0; j < 64; j += 4) { 73190b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc60), 73290b17f1bSmrg ctx->chroma_non_intra_quantiser_matrix[j] | 73390b17f1bSmrg (ctx->chroma_non_intra_quantiser_matrix[j + 1] << 8) | 73490b17f1bSmrg (ctx->chroma_non_intra_quantiser_matrix[j + 2] << 16) | 73590b17f1bSmrg (ctx->chroma_non_intra_quantiser_matrix[j + 3] << 24)); 73690b17f1bSmrg } 73790b17f1bSmrg ctx->chromaNonIntraLoaded = 1; 73890b17f1bSmrg } 73990b17f1bSmrg 74090b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc90), 74190b17f1bSmrg ((mb_width * mb_height) & 0x3fff) | 74290b17f1bSmrg ((control->flags & XVMC_PRED_DCT_FRAME) ? (1 << 14) : 0) | 74390b17f1bSmrg ((control->flags & XVMC_TOP_FIELD_FIRST) ? (1 << 15) : 0) | 74490b17f1bSmrg ((control->mpeg_coding == XVMC_MPEG_2) ? (1 << 16) : 0) | 74590b17f1bSmrg ((mb_width & 0xff) << 18)); 74690b17f1bSmrg 74790b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc94), 74890b17f1bSmrg ((control->flags & XVMC_CONCEALMENT_MOTION_VECTORS) ? 1 : 0) | 74990b17f1bSmrg ((control->flags & XVMC_Q_SCALE_TYPE) ? 2 : 0) | 75090b17f1bSmrg ((control->intra_dc_precision & 3) << 2) | 75190b17f1bSmrg (((1 + 0x100000 / mb_width) & 0xfffff) << 4) | 75290b17f1bSmrg ((control->flags & XVMC_INTRA_VLC_FORMAT) ? (1 << 24) : 0)); 75390b17f1bSmrg 75490b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc98), 75590b17f1bSmrg (((control->FHMV_range) & 0xf) << 0) | 75690b17f1bSmrg (((control->FVMV_range) & 0xf) << 4) | 75790b17f1bSmrg (((control->BHMV_range) & 0xf) << 8) | 75890b17f1bSmrg (((control->BVMV_range) & 0xf) << 12) | 75990b17f1bSmrg ((control->flags & XVMC_SECOND_FIELD) ? (1 << 20) : 0) | 76090b17f1bSmrg (0x0a6 << 16)); 76190b17f1bSmrg 76290b17f1bSmrg} 76390b17f1bSmrg 76490b17f1bSmrgvoid 76590b17f1bSmrgviaMpegReset(void *xlp) 76690b17f1bSmrg{ 76790b17f1bSmrg int i, j; 76890b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 76990b17f1bSmrg 77090b17f1bSmrg BEGIN_RING_AGP(xl, 100); 77190b17f1bSmrg WAITFLAGS(xl, LL_MODE_DECODER_IDLE); 77290b17f1bSmrg 77390b17f1bSmrg for (i = 0; i < 14; i++) 77490b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc08), 0); 77590b17f1bSmrg 77690b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc98), 0x400000); 77790b17f1bSmrg 77890b17f1bSmrg for (i = 0; i < 6; i++) { 77990b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc0c), 0x43 | 0x20); 78090b17f1bSmrg for (j = 0xc10; j < 0xc20; j += 4) 78190b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(j), 0); 78290b17f1bSmrg } 78390b17f1bSmrg 78490b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc0c), 0xc3 | 0x20); 78590b17f1bSmrg for (j = 0xc10; j < 0xc20; j += 4) 78690b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(j), 0); 78790b17f1bSmrg 78890b17f1bSmrg} 78990b17f1bSmrg 79090b17f1bSmrgvoid 79190b17f1bSmrgviaMpegWriteSlice(void *xlp, CARD8 * slice, int nBytes, CARD32 sCode) 79290b17f1bSmrg{ 79390b17f1bSmrg int i, n, r; 79490b17f1bSmrg CARD32 *buf; 79590b17f1bSmrg int count; 79690b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 79790b17f1bSmrg 79890b17f1bSmrg if (xl->errors & (LL_DECODER_TIMEDOUT | 79990b17f1bSmrg LL_IDCT_FIFO_ERROR | LL_SLICE_FIFO_ERROR | LL_SLICE_FAULT)) 80090b17f1bSmrg return; 80190b17f1bSmrg 80290b17f1bSmrg n = nBytes >> 2; 80390b17f1bSmrg if (sCode) 80490b17f1bSmrg nBytes += 4; 80590b17f1bSmrg r = nBytes & 3; 80690b17f1bSmrg buf = (CARD32 *) slice; 80790b17f1bSmrg 80890b17f1bSmrg if (r) 80990b17f1bSmrg nBytes += 4 - r; 81090b17f1bSmrg 81190b17f1bSmrg nBytes += 8; 81290b17f1bSmrg 81390b17f1bSmrg BEGIN_RING_AGP(xl, 4); 81490b17f1bSmrg WAITFLAGS(xl, LL_MODE_DECODER_IDLE); 81590b17f1bSmrg 81690b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xc9c), nBytes); 81790b17f1bSmrg 81890b17f1bSmrg if (sCode) 81990b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xca0), sCode); 82090b17f1bSmrg 82190b17f1bSmrg i = 0; 82290b17f1bSmrg count = 0; 82390b17f1bSmrg 82490b17f1bSmrg do { 82590b17f1bSmrg count += (LL_AGP_CMDBUF_SIZE - 20) >> 1; 82690b17f1bSmrg count = (count > n) ? n : count; 82790b17f1bSmrg BEGIN_RING_AGP(xl, (count - i) << 1); 82890b17f1bSmrg 82990b17f1bSmrg for (; i < count; i++) { 83090b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xca0), *buf++); 83190b17f1bSmrg } 83290b17f1bSmrg } while (i < n); 83390b17f1bSmrg 83490b17f1bSmrg BEGIN_RING_AGP(xl, 6); 83590b17f1bSmrg 83690b17f1bSmrg if (r) { 83790b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xca0), *buf & ((1 << (r << 3)) - 1)); 83890b17f1bSmrg } 83990b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xca0), 0); 84090b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(0xca0), 0); 84190b17f1bSmrg 84290b17f1bSmrg} 84390b17f1bSmrg 84490b17f1bSmrgvoid 84590b17f1bSmrgviaVideoSubPictureOffLocked(void *xlp) 84690b17f1bSmrg{ 84790b17f1bSmrg 84890b17f1bSmrg CARD32 stride; 84990b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 85090b17f1bSmrg 85190b17f1bSmrg stride = VIDIN(xl, SUBP_CONTROL_STRIDE); 85290b17f1bSmrg 85390b17f1bSmrg pciCommand(xl, SUBP_CONTROL_STRIDE, stride & ~SUBP_HQV_ENABLE, 85490b17f1bSmrg LL_MODE_VIDEO); 85590b17f1bSmrg} 85690b17f1bSmrg 85790b17f1bSmrgvoid 85890b17f1bSmrgviaVideoSubPictureLocked(void *xlp, ViaXvMCSubPicture * pViaSubPic) 85990b17f1bSmrg{ 86090b17f1bSmrg 86190b17f1bSmrg unsigned i; 86290b17f1bSmrg CARD32 cWord; 86390b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 86490b17f1bSmrg 86590b17f1bSmrg for (i = 0; i < VIA_SUBPIC_PALETTE_SIZE; ++i) { 86690b17f1bSmrg pciCommand(xl, RAM_TABLE_CONTROL, pViaSubPic->palette[i], 86790b17f1bSmrg LL_MODE_VIDEO); 86890b17f1bSmrg } 86990b17f1bSmrg 87090b17f1bSmrg pciCommand(xl, SUBP_STARTADDR, pViaSubPic->offset, 0); 87190b17f1bSmrg cWord = (pViaSubPic->stride & SUBP_STRIDE_MASK) | SUBP_HQV_ENABLE; 87290b17f1bSmrg cWord |= (pViaSubPic->ia44) ? SUBP_IA44 : SUBP_AI44; 87390b17f1bSmrg pciCommand(xl, SUBP_CONTROL_STRIDE, cWord, 0); 87490b17f1bSmrg} 87590b17f1bSmrg 87690b17f1bSmrgvoid 87790b17f1bSmrgviaBlit(void *xlp, unsigned bpp, unsigned srcBase, 87890b17f1bSmrg unsigned srcPitch, unsigned dstBase, unsigned dstPitch, 87990b17f1bSmrg unsigned w, unsigned h, int xdir, int ydir, unsigned blitMode, 88090b17f1bSmrg unsigned color) 88190b17f1bSmrg{ 88290b17f1bSmrg 88390b17f1bSmrg CARD32 dwGEMode = 0, srcY = 0, srcX, dstY = 0, dstX; 88490b17f1bSmrg CARD32 cmd; 88590b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 88690b17f1bSmrg 88790b17f1bSmrg if (!w || !h) 88890b17f1bSmrg return; 88990b17f1bSmrg 89090b17f1bSmrg switch (bpp) { 89190b17f1bSmrg case 16: 89290b17f1bSmrg dwGEMode |= VIA_GEM_16bpp; 89390b17f1bSmrg break; 89490b17f1bSmrg case 32: 89590b17f1bSmrg dwGEMode |= VIA_GEM_32bpp; 89690b17f1bSmrg break; 89790b17f1bSmrg default: 89890b17f1bSmrg dwGEMode |= VIA_GEM_8bpp; 89990b17f1bSmrg break; 90090b17f1bSmrg } 90190b17f1bSmrg 90290b17f1bSmrg srcX = srcBase & 31; 90390b17f1bSmrg dstX = dstBase & 31; 90490b17f1bSmrg switch (bpp) { 90590b17f1bSmrg case 16: 90690b17f1bSmrg dwGEMode |= VIA_GEM_16bpp; 90790b17f1bSmrg srcX >>= 2; 90890b17f1bSmrg dstX >>= 2; 90990b17f1bSmrg break; 91090b17f1bSmrg case 32: 91190b17f1bSmrg dwGEMode |= VIA_GEM_32bpp; 91290b17f1bSmrg srcX >>= 4; 91390b17f1bSmrg dstX >>= 4; 91490b17f1bSmrg break; 91590b17f1bSmrg default: 91690b17f1bSmrg dwGEMode |= VIA_GEM_8bpp; 91790b17f1bSmrg break; 91890b17f1bSmrg } 91990b17f1bSmrg 92090b17f1bSmrg BEGIN_RING_AGP(xl, 20); 92190b17f1bSmrg WAITFLAGS(xl, LL_MODE_2D); 92290b17f1bSmrg 92390b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_GEMODE), dwGEMode); 92490b17f1bSmrg cmd = 0; 92590b17f1bSmrg 92690b17f1bSmrg if (xdir < 0) { 92790b17f1bSmrg cmd |= VIA_GEC_DECX; 92890b17f1bSmrg srcX += (w - 1); 92990b17f1bSmrg dstX += (w - 1); 93090b17f1bSmrg } 93190b17f1bSmrg if (ydir < 0) { 93290b17f1bSmrg cmd |= VIA_GEC_DECY; 93390b17f1bSmrg srcY += (h - 1); 93490b17f1bSmrg dstY += (h - 1); 93590b17f1bSmrg } 93690b17f1bSmrg 93790b17f1bSmrg switch (blitMode) { 93890b17f1bSmrg case VIABLIT_TRANSCOPY: 93990b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_SRCCOLORKEY), color); 94090b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_KEYCONTROL), 0x4000); 94190b17f1bSmrg cmd |= VIA_GEC_BLT | (VIA_BLIT_COPY << 24); 94290b17f1bSmrg break; 94390b17f1bSmrg case VIABLIT_FILL: 94490b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_FGCOLOR), color); 94590b17f1bSmrg cmd |= VIA_GEC_BLT | VIA_GEC_FIXCOLOR_PAT | (VIA_BLIT_FILL << 24); 94690b17f1bSmrg break; 94790b17f1bSmrg default: 94890b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_KEYCONTROL), 0x0); 94990b17f1bSmrg cmd |= VIA_GEC_BLT | (VIA_BLIT_COPY << 24); 95090b17f1bSmrg } 95190b17f1bSmrg 95290b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_SRCBASE), (srcBase & ~31) >> 3); 95390b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_DSTBASE), (dstBase & ~31) >> 3); 95490b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_PITCH), VIA_PITCH_ENABLE | 95590b17f1bSmrg (srcPitch >> 3) | (((dstPitch) >> 3) << 16)); 95690b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_SRCPOS), ((srcY << 16) | srcX)); 95790b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_DSTPOS), ((dstY << 16) | dstX)); 95890b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_DIMENSION), 95990b17f1bSmrg (((h - 1) << 16) | (w - 1))); 96090b17f1bSmrg OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_GECMD), cmd); 96190b17f1bSmrg} 96290b17f1bSmrg 96390b17f1bSmrgunsigned 96490b17f1bSmrgsyncXvMCLowLevel(void *xlp, unsigned int mode, unsigned int doSleep, 96590b17f1bSmrg CARD32 timeStamp) 96690b17f1bSmrg{ 96790b17f1bSmrg unsigned errors; 96890b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 96990b17f1bSmrg 97090b17f1bSmrg if (mode == 0) { 97190b17f1bSmrg errors = xl->errors; 97290b17f1bSmrg xl->errors = 0; 97390b17f1bSmrg return errors; 97490b17f1bSmrg } 97590b17f1bSmrg 97690b17f1bSmrg if ((mode & (LL_MODE_VIDEO | LL_MODE_3D)) || !xl->use_agp) { 97790b17f1bSmrg if (xl->performLocking) 97890b17f1bSmrg hwlLock(xl, 0); 97990b17f1bSmrg if ((mode != LL_MODE_VIDEO)) 98090b17f1bSmrg syncDMA(xl, doSleep); 98190b17f1bSmrg if (mode & LL_MODE_3D) 98290b17f1bSmrg syncAccel(xl, mode, doSleep); 98390b17f1bSmrg if (mode & LL_MODE_VIDEO) 98490b17f1bSmrg syncVideo(xl, doSleep); 98590b17f1bSmrg if (xl->performLocking) 98690b17f1bSmrg hwlUnlock(xl, 0); 98790b17f1bSmrg } else { 98890b17f1bSmrg viaDMAWaitTimeStamp(xl, timeStamp, doSleep); 98990b17f1bSmrg } 99090b17f1bSmrg 99190b17f1bSmrg if (mode & (LL_MODE_DECODER_SLICE | LL_MODE_DECODER_IDLE)) 99290b17f1bSmrg syncMpeg(xl, mode, doSleep); 99390b17f1bSmrg 99490b17f1bSmrg errors = xl->errors; 99590b17f1bSmrg xl->errors = 0; 99690b17f1bSmrg 99790b17f1bSmrg return errors; 99890b17f1bSmrg} 99990b17f1bSmrg 100090b17f1bSmrgextern void * 100190b17f1bSmrginitXvMCLowLevel(int fd, drm_context_t * ctx, 100290b17f1bSmrg drmLockPtr hwLock, drmAddress mmioAddress, 100390b17f1bSmrg drmAddress fbAddress, unsigned fbStride, unsigned fbDepth, 100490b17f1bSmrg unsigned width, unsigned height, int useAgp, unsigned chipId) 100590b17f1bSmrg{ 100690b17f1bSmrg int ret; 100790b17f1bSmrg XvMCLowLevel *xl; 100890b17f1bSmrg 100990b17f1bSmrg if (chipId == PCI_CHIP_VT3259 || chipId == PCI_CHIP_VT3364) { 101090b17f1bSmrg fprintf(stderr, "You are using an XvMC driver for the wrong chip.\n"); 101190b17f1bSmrg fprintf(stderr, "Chipid is 0x%04x.\n", chipId); 101290b17f1bSmrg return NULL; 101390b17f1bSmrg } 101490b17f1bSmrg 101590b17f1bSmrg xl = (XvMCLowLevel *) malloc(sizeof(XvMCLowLevel)); 101690b17f1bSmrg 101790b17f1bSmrg if (!xl) 101890b17f1bSmrg return NULL; 101990b17f1bSmrg 102090b17f1bSmrg xl->agp_pos = 0; 102190b17f1bSmrg xl->pci_pos = 0; 102290b17f1bSmrg xl->use_agp = useAgp; 102390b17f1bSmrg xl->fd = fd; 102490b17f1bSmrg xl->drmcontext = ctx; 102590b17f1bSmrg xl->hwLock = hwLock; 102690b17f1bSmrg xl->mmioAddress = mmioAddress; 102790b17f1bSmrg xl->fbAddress = fbAddress; 102890b17f1bSmrg xl->curWaitFlags = 0; 102990b17f1bSmrg xl->performLocking = 1; 103090b17f1bSmrg xl->errors = 0; 103190b17f1bSmrg xl->agpSync = 0; 103290b17f1bSmrg ret = viaDMAInitTimeStamp(xl); 103390b17f1bSmrg if (ret) { 103490b17f1bSmrg free(xl); 103590b17f1bSmrg return NULL; 103690b17f1bSmrg } 103790b17f1bSmrg return xl; 103890b17f1bSmrg} 103990b17f1bSmrg 104090b17f1bSmrgvoid 104190b17f1bSmrgsetLowLevelLocking(void *xlp, int performLocking) 104290b17f1bSmrg{ 104390b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 104490b17f1bSmrg 104590b17f1bSmrg xl->performLocking = performLocking; 104690b17f1bSmrg} 104790b17f1bSmrg 104890b17f1bSmrgvoid 104990b17f1bSmrgcloseXvMCLowLevel(void *xlp) 105090b17f1bSmrg{ 105190b17f1bSmrg XvMCLowLevel *xl = (XvMCLowLevel *) xlp; 105290b17f1bSmrg 105390b17f1bSmrg viaDMACleanupTimeStamp(xl); 105490b17f1bSmrg free(xl); 105590b17f1bSmrg} 1056