diff options
author | Jon Nettleton <jon.nettleton@gmail.com> | 2007-06-07 13:15:10 +0000 |
---|---|---|
committer | Jon Nettleton <jon.nettleton@gmail.com> | 2007-06-07 13:15:10 +0000 |
commit | 83c4eb79d5d5870a3dde9431b393cb08c175fd0d (patch) | |
tree | 68538648978ea85c7131191d7d97f7802b509b98 /src/via_swov.c | |
parent | 0552096a2831446d7ace66bf88d14bdd2742c65d (diff) |
mv unichrome to src
Diffstat (limited to 'src/via_swov.c')
-rw-r--r-- | src/via_swov.c | 2203 |
1 files changed, 2203 insertions, 0 deletions
diff --git a/src/via_swov.c b/src/via_swov.c new file mode 100644 index 000000000000..b207f3226fc0 --- /dev/null +++ b/src/via_swov.c @@ -0,0 +1,2203 @@ +/* + * Copyright 2004-2005 The Unichrome Project [unichrome.sf.net] + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. 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, sub license, + * 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 (including the + * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86fbman.h" + +#include "via.h" +#ifdef XF86DRI +#include "xf86drm.h" +#endif + +#include "via_driver.h" +#include "via_priv.h" +#include "via_swov.h" +#ifdef XF86DRI +#include "via_drm.h" +#endif +#include "via_vgahw.h" +#include "via_id.h" + +#include <math.h> + +/* + * Warning: this file contains revision checks which are CLE266-specific. + * There seems to be no checking present for KM400 or more recent devices. + * + * TODO: + * - pVia->Chipset checking, of course + * - move content of pVia->HWDiff into pVia->swov + * - merge with CLEXF40040 + */ + +/* + * Old via_regrec code. + */ +#define VIDREG_BUFFER_SIZE 100 /* Number of entries in the VidRegBuffer. */ +#define IN_VIDEO_DISPLAY (*((unsigned long volatile *)(pVia->VidMapBase+V_FLAGS))&VBI_STATUS) +#define VIA_FIRETIMEOUT 40000 + +static void +viaWaitVideoCommandFire(VIAPtr pVia) +{ +/* + * Assume uncached PCI reading throughput is about 9 MB/s. 8 bytes/loop means + * approx 1M loops/second. We want to time out after 50 ms which means 50000 loops. + */ + + unsigned count = 50000; + CARD32 volatile *pdwState = + (CARD32 volatile *)(pVia->VidMapBase + V_COMPOSE_MODE); + + while (--count && ((*pdwState & V1_COMMAND_FIRE) + || (*pdwState & V3_COMMAND_FIRE))) ; + if (!count) { + ErrorF("viaWaitVideoCommandFire: Timeout.\n"); + } +} + +static void +viaWaitHQVFlip(VIAPtr pVia) +{ + unsigned long proReg = 0; + CARD32 volatile *pdwState; + + if ((pVia->ChipId == PCI_CHIP_VT3259) && + !(pVia->swov.gdwVideoFlagSW & VIDEO_1_INUSE)) + proReg = PRO_HQV1_OFFSET; + + pdwState = (CARD32 volatile *)(pVia->VidMapBase + (HQV_CONTROL + proReg)); + + if (pVia->ChipId == PCI_CHIP_VT3259) { + while (*pdwState & (HQV_SUBPIC_FLIP | HQV_SW_FLIP)) ; + } else { + while (!(*pdwState & HQV_FLIP_STATUS)) ; + } +} + +static void +viaWaitHQVFlipClear(VIAPtr pVia, unsigned long dwData) +{ + CARD32 volatile *pdwState = + (CARD32 volatile *)(pVia->VidMapBase + HQV_CONTROL); + *pdwState = dwData; + + while ((*pdwState & HQV_FLIP_STATUS)) { + VIDOutD(HQV_CONTROL, *pdwState | HQV_FLIP_STATUS); + } +} + +static void +viaWaitVBI(VIAPtr pVia) +{ + while (IN_VIDEO_DISPLAY) ; +} + +static void +viaWaitHQVDone(VIAPtr pVia) +{ + CARD32 volatile *pdwState; + unsigned long proReg = 0; + + if ((pVia->ChipId == PCI_CHIP_VT3259) && + !(pVia->swov.gdwVideoFlagSW & VIDEO_1_INUSE)) + proReg = PRO_HQV1_OFFSET; + + pdwState = (CARD32 volatile *)(pVia->VidMapBase + (HQV_CONTROL + proReg)); + if (pVia->swov.MPEG_ON) { + while ((*pdwState & HQV_SW_FLIP)) ; + } +} + +/* + * Send all data in VidRegBuffer to the hardware. + */ +static void +FlushVidRegBuffer(VIAPtr pVia) +{ + unsigned int i; + + viaWaitVideoCommandFire(pVia); + + for (i = 0; i < pVia->VidRegCursor; i += 2) { + VIDOutD(pVia->VidRegBuffer[i], pVia->VidRegBuffer[i + 1]); + DBG_DD(ErrorF("FlushVideoRegs: [%i] %08lx %08lx\n", + i >> 1, pVia->VidRegBuffer[i] + 0x200, + pVia->VidRegBuffer[i + 1])); + } + + /* BUG: (?) VIA never resets the cursor. + * My fix is commented out for now, in case they had a reason for that. /A + */ + /* pVia->VidRegCursor = 0; */ +} + +/* + * Initialize and clear VidRegBuffer. + */ +static void +ResetVidRegBuffer(VIAPtr pVia) +{ + /* BUG: (Memory leak) This allocation may need have a corresponding free somewhere... /A */ + if (!pVia->VidRegBuffer) + pVia->VidRegBuffer = + xnfcalloc(VIDREG_BUFFER_SIZE, sizeof(CARD32) * 2); + pVia->VidRegCursor = 0; +} + +/* + * Save a video register and data in VidRegBuffer. + */ +static void +SaveVideoRegister(VIAPtr pVia, CARD32 index, CARD32 data) +{ + pVia->VidRegBuffer[pVia->VidRegCursor++] = index; + pVia->VidRegBuffer[pVia->VidRegCursor++] = data; + + if (pVia->VidRegCursor > VIDREG_BUFFER_SIZE) { + DBG_DD(ErrorF("SaveVideoRegister: Out of video register space")); + } +} + +/* + * HW Difference Flag (moved here from via_hwdiff.c) + * + * These are the entries of HWDiff used in our code (currently): + * CLE266Ax CLE266Cx KM400 K8M800 PM800 + * ThreeHQVBuffer FALSE TRUE TRUE TRUE TRUE + * HQVFetchByteUnit FALSE TRUE TRUE TRUE TRUE + * SupportTwoColorKey FALSE TRUE FALSE FALSE TRUE + * HQVInitPatch TRUE FALSE FALSE FALSE FALSE + * HQVDisablePatch FALSE TRUE TRUE TRUE FALSE + * + * This is now up to date with CLEXF40040. All unused entries were removed. + * The functions depending on this struct are untouched. + */ +void +VIAVidHWDiffInit(ScrnInfoPtr pScrn) +{ + VIAPtr pVia = VIAPTR(pScrn); + VIAHWDiff *HWDiff = &pVia->HWDiff; + + switch (pVia->Chipset) { + case VIA_CLE266: + if (CLE266_REV_IS_AX(pVia->ChipRev)) { + HWDiff->dwThreeHQVBuffer = VID_HWDIFF_FALSE; + HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_FALSE; + HWDiff->dwSupportTwoColorKey = VID_HWDIFF_FALSE; + HWDiff->dwHQVInitPatch = VID_HWDIFF_TRUE; + HWDiff->dwHQVDisablePatch = VID_HWDIFF_FALSE; + } else { + HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE; + HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE; + HWDiff->dwSupportTwoColorKey = VID_HWDIFF_TRUE; + HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE; + HWDiff->dwHQVDisablePatch = VID_HWDIFF_TRUE; + } + break; + case VIA_KM400: + HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE; + HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE; + HWDiff->dwSupportTwoColorKey = VID_HWDIFF_FALSE; + HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE; + HWDiff->dwHQVDisablePatch = VID_HWDIFF_TRUE; + break; + case VIA_K8M800: + HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE; + HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE; + HWDiff->dwSupportTwoColorKey = VID_HWDIFF_FALSE; + HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE; + HWDiff->dwHQVDisablePatch = VID_HWDIFF_TRUE; + break; + case VIA_PM800: + HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE; + HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE; + HWDiff->dwSupportTwoColorKey = VID_HWDIFF_TRUE; + HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE; + HWDiff->dwHQVDisablePatch = VID_HWDIFF_FALSE; + break; + case VIA_VM800: + HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE; + HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE; + HWDiff->dwSupportTwoColorKey = VID_HWDIFF_FALSE; + HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE; + HWDiff->dwHQVDisablePatch = VID_HWDIFF_TRUE; + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "VIAVidHWDiffInit: Unhandled ChipSet.\n"); + } +} + +/* + * Old via_overlay code. + */ +typedef struct _YCBCRREC +{ + CARD32 dwY; + CARD32 dwCB; + CARD32 dwCR; +} YCBCRREC; + +/* + * Verify that using V1 bit definitions on V3 + * is not broken in OverlayGetV1V3Format(). + */ + +#if V1_COLORSPACE_SIGN != V3_COLORSPACE_SIGN +#error "V1_COLORSPACE_SIGN != V3_COLORSPACE_SIGN" +#endif +#if V1_YUV422 != V3_YUV422 +#error "V1_YUV422 != V3_YUV422" +#endif +#if V1_SWAP_HW_HQV != V3_SWAP_HW_HQV +#error "V1_SWAP_HW_HQV != V3_SWAP_HW_HQV" +#endif +#if V1_RGB15 != V3_RGB15 +#error "V1_RGB15 != V3_RGB15" +#endif +#if V1_RGB16 != V3_RGB16 +#error "V1_RGB16 != V3_RGB16" +#endif +#if V1_RGB32 != V3_RGB32 +#error "V1_RGB32 != V3_RGB32" +#endif + +static BOOL +viaOverlayGetV1V3Format(VIAPtr pVia, int vport, /* 1 or 3, as in V1 or V3 */ + unsigned long videoFlag, unsigned long *pVidCtl, unsigned long *pHQVCtl) +{ + if (videoFlag & VIDEO_HQV_INUSE) { + switch (pVia->swov.SrcFourCC) { + case FOURCC_YV12: + case FOURCC_XVMC: + *pHQVCtl |= HQV_YUV420; + break; + case FOURCC_YUY2: + *pHQVCtl |= HQV_YUV422; + break; + case FOURCC_RV32: + *pVidCtl |= V1_RGB32; + *pHQVCtl |= HQV_RGB32; + break; + case FOURCC_RV15: + *pVidCtl |= V1_RGB15; + *pHQVCtl |= HQV_RGB15; + break; + case FOURCC_RV16: + *pVidCtl |= V1_RGB16; + *pHQVCtl |= HQV_RGB16; + break; + default: + DBG_DD(ErrorF + ("viaOverlayGetV1V3Format: Invalid FOURCC format (0x%lx).\n", + pVia->swov.SrcFourCC)); + return FALSE; + } + *pVidCtl |= V1_SWAP_HW_HQV; + *pHQVCtl |= HQV_SRC_SW | HQV_ENABLE | HQV_SW_FLIP; + } else { + switch (pVia->swov.SrcFourCC) { + case FOURCC_YV12: + case FOURCC_XVMC: + if (vport == 1) { + *pVidCtl |= V1_YCbCr420; + } else { + DBG_DD(ErrorF + ("viaOverlayGetV1V3Format: V3 does not support planar YUV.\n")); + return FALSE; + } + break; + case FOURCC_YUY2: + *pVidCtl |= V1_YUV422; + break; + case FOURCC_RV32: + case FOURCC_RV15: + case FOURCC_RV16: + ErrorF + ("viaOverlayGetV1V3Format: Can't display RGB video in this configuration.\n"); + return FALSE; + default: + DBG_DD(ErrorF + ("viaOverlayGetV1V3Format: Invalid FOURCC format (0x%lx).\n", + pVia->swov.SrcFourCC)); + return FALSE; + } + } + *pVidCtl |= V1_COLORSPACE_SIGN; + return TRUE; +} + +static unsigned long +viaOverlayGetSrcStartAddress(VIAPtr pVia, unsigned long videoFlag, + LPDDUPDATEOVERLAY pUpdate, unsigned long srcPitch, + unsigned long *pHQVoffset) +{ + unsigned long srcWidth = + (unsigned long)(pUpdate->SrcRight - pUpdate->SrcLeft); + unsigned long dstWidth = + (unsigned long)(pUpdate->DstRight - pUpdate->DstLeft); + unsigned long srcHeight = + (unsigned long)(pUpdate->SrcBottom - pUpdate->SrcTop); + unsigned long dstHeight = + (unsigned long)(pUpdate->DstBottom - pUpdate->DstTop); + + unsigned long offset = 0; + unsigned long srcTopOffset = 0; + unsigned long srcLeftOffset = 0; + + int n = 1; + + if ((pUpdate->SrcLeft != 0) || (pUpdate->SrcTop != 0)) { + switch (pVia->swov.SrcFourCC) { + case FOURCC_RV32: + n = 2; + case FOURCC_YUY2: + case FOURCC_UYVY: + case FOURCC_RV15: + case FOURCC_RV16: + + if (videoFlag & VIDEO_HQV_INUSE) { + offset = + (((pUpdate->SrcTop & ~3) * srcPitch) + + ((pUpdate->SrcLeft << n) & ~31)); + + if (srcHeight > dstHeight) + srcTopOffset = + ((pUpdate->SrcTop & ~3) * dstHeight / srcHeight) * + srcPitch; + else + srcTopOffset = (pUpdate->SrcTop & ~3) * srcPitch; + + if (srcWidth > dstWidth) + srcLeftOffset = + ((pUpdate->SrcLeft << n) & ~31) * dstWidth / srcWidth; + else + srcLeftOffset = (pUpdate->SrcLeft << n) & ~31; + *pHQVoffset = srcTopOffset + srcLeftOffset; + } else + offset = + ((pUpdate->SrcTop * srcPitch) + + ((pUpdate->SrcLeft << n) & ~15)); + break; + + case FOURCC_YV12: + case FOURCC_XVMC: + + if (videoFlag & VIDEO_HQV_INUSE) + offset = + (((pUpdate->SrcTop & ~3) * (srcPitch << 1)) + + ((pUpdate->SrcLeft << 1) & ~31)); + else { + offset = + ((((pUpdate->SrcTop & ~3) * srcPitch) + + pUpdate->SrcLeft) & ~31); + if (pUpdate->SrcTop > 0) + pVia->swov.overlayRecordV1.dwUVoffset = + (((((pUpdate->SrcTop & ~3) >> 1) * srcPitch) + + pUpdate->SrcLeft) & ~31) >> 1; + else + pVia->swov.overlayRecordV1.dwUVoffset = offset >> 1; + } + break; + + default: + DBG_DD(ErrorF + ("viaGetSrcStartAddress: Invalid FOURCC format (0x%lx).\n", + pVia->swov.SrcFourCC)); + break; + } + } else { + pVia->swov.overlayRecordV1.dwUVoffset = offset = 0; + } + + return offset; +} + +static YCBCRREC +viaOverlayGetYCbCrStartAddress(unsigned long videoFlag, + unsigned long startAddr, unsigned long offset, unsigned long UVoffset, + unsigned long srcPitch, unsigned long srcHeight) +{ + YCBCRREC YCbCr; + + if (videoFlag & VIDEO_HQV_INUSE) { + YCbCr.dwY = startAddr; + YCbCr.dwCB = startAddr + srcPitch * srcHeight; + YCbCr.dwCR = startAddr + srcPitch * srcHeight + + srcPitch * (srcHeight >> 2); + } else { + YCbCr.dwY = startAddr + offset; + YCbCr.dwCB = startAddr + srcPitch * srcHeight + UVoffset; + YCbCr.dwCR = startAddr + srcPitch * srcHeight + UVoffset + + srcPitch * (srcHeight >> 2); + } + return YCbCr; +} + +static unsigned long +viaOverlayHQVCalcZoomWidth(VIAPtr pVia, unsigned long videoFlag, + unsigned long srcWidth, unsigned long dstWidth, + unsigned long *pZoomCtl, unsigned long *pMiniCtl, + unsigned long *pHQVfilterCtl, unsigned long *pHQVminiCtl, + unsigned long *pHQVzoomflag) +{ + unsigned long tmp, sw1, d, falign, mdiv; + Bool zoom_ok = TRUE; + + CARD32 HQVfilter[5] = { + HQV_H_FILTER_DEFAULT, HQV_H_TAP4_121, HQV_H_TAP4_121, + HQV_H_TAP8_12221, HQV_H_TAP8_12221 + }; + /* CARD HQVmini[5] = { 0, 0xc00, 0xa00, 0x900, 0x8800 }; */ + + falign = 0; + mdiv = 1; + + if (srcWidth == dstWidth) { /* No zoom */ + *pHQVfilterCtl |= HQV_H_FILTER_DEFAULT; + } else if (srcWidth < dstWidth) { /* Zoom in */ + + tmp = srcWidth * 0x800 / dstWidth; + *pZoomCtl = ((tmp & 0x7ff) << 16) | V1_X_ZOOM_ENABLE; + *pMiniCtl |= V1_X_INTERPOLY; + zoom_ok = !(tmp > 0x7ff); + + *pHQVzoomflag = 1; + *pHQVfilterCtl |= HQV_H_FILTER_DEFAULT; + + } else { /* srcWidth > dstWidth - Zoom out */ + + /* HQV rounding patch, instead of: + * //tmp = dstWidth*0x0800 / srcWidth; */ + tmp = dstWidth * 0x800 * 0x400 / srcWidth; + tmp = tmp / 0x400 + ((tmp & 0x3ff) ? 1 : 0); + + *pHQVminiCtl = + (tmp & 0x7ff) | HQV_H_MINIFY_ENABLE | HQV_H_MINIFY_DOWN; + + /* Scale down the picture by a factor mdiv = (1 << d) = {2, 4, 8 or 16} */ + + sw1 = srcWidth; + for (d = 1; d < 5; d++) { + sw1 >>= 1; + if (sw1 <= dstWidth) + break; + } + if (d == 5) { /* Too small. */ + d = 4; + zoom_ok = FALSE; + } + mdiv = 1 << d; /* <= {2,4,8,16} */ + falign = ((mdiv << 1) - 1) & 0xf; /* <= {3,7,15,15} */ + *pMiniCtl |= V1_X_INTERPOLY; + *pMiniCtl |= ((d << 1) - 1) << 24; /* <= {1,3,5,7} << 24 */ + + *pHQVfilterCtl |= HQVfilter[d]; + /* *pHQVminiCtl = HQVmini[d]; */ + *pHQVminiCtl |= HQV_HDEBLOCK_FILTER; + + /* Scale to arbitrary size, on top of previous scaling by (1 << d). */ + + if (sw1 < dstWidth) { + /* CLE bug + *pZoomCtl = sw1 * 0x0800 / dstWidth;*/ + *pZoomCtl = (sw1 - 2) * 0x0800 / dstWidth; + *pZoomCtl = ((*pZoomCtl & 0x7ff) << 16) | V1_X_ZOOM_ENABLE; + } + } + + if (videoFlag & VIDEO_1_INUSE) { + pVia->swov.overlayRecordV1.dwFetchAlignment = falign; + pVia->swov.overlayRecordV1.dwminifyH = mdiv; + } else { + pVia->swov.overlayRecordV3.dwFetchAlignment = falign; + pVia->swov.overlayRecordV3.dwminifyH = mdiv; + } + + return zoom_ok; +} + +static unsigned long +viaOverlayHQVCalcZoomHeight(VIAPtr pVia, unsigned long srcHeight, + unsigned long dstHeight, unsigned long *pZoomCtl, + unsigned long *pMiniCtl, unsigned long *pHQVfilterCtl, + unsigned long *pHQVminiCtl, unsigned long *pHQVzoomflag) +{ + unsigned long tmp, sh1, d; + Bool zoom_ok = TRUE; + + CARD32 HQVfilter[5] = { + HQV_V_TAP4_121, HQV_V_TAP4_121, HQV_V_TAP4_121, + HQV_V_TAP8_12221, HQV_V_TAP8_12221 + }; + /* CARD32 HQVmini[5] = { 0, 0x0c000000, 0x0a000000, 0x09000000, 0x08800000 }; */ + + /*if (pVia->pBIOSInfo->scaleY) + * { + * dstHeight = dstHeight + 1; + * } */ + + if (srcHeight == dstHeight) { /* No zoom */ + *pHQVfilterCtl |= HQV_V_TAP4_121; + } else if (srcHeight < dstHeight) { /* Zoom in */ + + tmp = srcHeight * 0x0400 / dstHeight; + *pZoomCtl |= ((tmp & 0x3ff) | V1_Y_ZOOM_ENABLE); + *pMiniCtl |= (V1_Y_INTERPOLY | V1_YCBCR_INTERPOLY); + + *pHQVzoomflag = 1; + *pHQVfilterCtl |= HQV_V_TAP4_121; + } else { /* srcHeight > dstHeight - Zoom out */ + + /* HQV rounding patch, instead of: + * //tmp = dstHeight*0x0800 / srcHeight; */ + tmp = dstHeight * 0x0800 * 0x400 / srcHeight; + tmp = tmp / 0x400 + ((tmp & 0x3ff) ? 1 : 0); + *pHQVminiCtl |= + ((tmp & 0x7ff) << 16) | HQV_V_MINIFY_ENABLE | HQV_V_MINIFY_DOWN; + + /* Scale down the picture by a factor (1 << d) = {2, 4, 8 or 16} */ + + sh1 = srcHeight; + for (d = 1; d < 5; d++) { + sh1 >>= 1; + if (sh1 <= dstHeight) + break; + } + if (d == 5) { /* Too small. */ + d = 4; + zoom_ok = FALSE; + } + + *pMiniCtl |= ((d << 1) - 1) << 16; /* <= {1,3,5,7} << 16 */ + + *pHQVfilterCtl |= HQVfilter[d]; + /* *pHQVminiCtl |= HQVmini[d]; */ + *pHQVminiCtl |= HQV_VDEBLOCK_FILTER; + + /* Scale to arbitrary size, on top of previous scaling by (1 << d). */ + + if (sh1 < dstHeight) { + tmp = sh1 * 0x0400 / dstHeight; + *pZoomCtl |= ((tmp & 0x3ff) | V1_Y_ZOOM_ENABLE); + *pMiniCtl |= V1_Y_INTERPOLY | V1_YCBCR_INTERPOLY; + } + } + + return zoom_ok; +} + +static unsigned long +viaOverlayGetFetch(VIAPtr pVia, unsigned long videoFlag, + unsigned long srcWidth, unsigned long dstWidth, + unsigned long oriSrcWidth, unsigned long *pHQVsrcFetch) +{ + unsigned long fetch = 0; + int n = 2; /* 2^n bytes per pixel. */ + + switch (pVia->swov.SrcFourCC) { + case FOURCC_YV12: + case FOURCC_XVMC: + n = 0; /* 2^n = 1 byte per pixel (Y channel in planar YUV) */ + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + case FOURCC_RV15: + case FOURCC_RV16: + n = 1; /* 2^n = 2 bytes per pixel (packed YUV) */ + break; + case FOURCC_RV32: + n = 2; + break; + default: + DBG_DD(ErrorF("viaOverlayGetFetch: Invalid FOURCC format (0x%lx).\n", + pVia->swov.SrcFourCC)); + break; + } + + if (videoFlag & VIDEO_HQV_INUSE) { + *pHQVsrcFetch = oriSrcWidth << n; + if (n == 0) { + /* Assume n == 0 <=> Planar YUV. + * The V1/V3 pixelformat is always packed YUV when we use HQV, + * so we switch from 8-bit to 16-bit pixels here. + */ + n = 1; + } + if (dstWidth >= srcWidth) + fetch = (ALIGN_TO(srcWidth << n, 16) >> 4) + 1; + else + fetch = (ALIGN_TO(dstWidth << n, 16) >> 4) + 1; + } else { + if (n == 0) + fetch = (ALIGN_TO(srcWidth, 32) >> 4); + else + fetch = (ALIGN_TO(srcWidth << n, 16) >> 4) + 1; + } + + /* Fix planar mode problem. */ + if (fetch < 4) + fetch = 4; + + return fetch; +} + +/* + * This function uses quadratic mapping to adjust the midpoint of the scaling. + */ +static float +rangeEqualize(float inLow, float inHigh, float outLow, float outHigh, + float outMid, float inValue) +{ + float + inRange = inHigh - inLow, + outRange = outHigh - outLow, + normIn = ((inValue - inLow) / inRange) * 2. - 1., + delta = outMid - outRange * 0.5 - outLow; + return (inValue - inLow) * outRange / inRange + outLow + (1. - + normIn * normIn) * delta; +} + +static unsigned +vPackFloat(float val, float hiLimit, float loLimit, float mult, int shift, + Bool doSign) +{ + unsigned packed, mask, sign; + + val = (val > hiLimit) ? hiLimit : val; + val = (val < loLimit) ? loLimit : val; + sign = (val < 0) ? 1 : 0; + val = (sign) ? -val : val; + packed = ((unsigned)(val * mult + 1.)) >> 1; + mask = (1 << shift) - 1; + return (((packed >= + mask) ? mask : packed) | ((doSign) ? (sign << shift) : 0)); + +} + +typedef float colorCoeff[5]; +static colorCoeff colorCTable[] = { {1.1875, 1.625, 0.875, 0.375, 2.0}, +{1.164, 1.596, 0.54, 0.45, 2.2} +}; + +/* + * This function is a partial rewrite of the overlay.c file of the original VIA + * drivers, which was extremely nasty and difficult to follow. Coefficients for + * new chipset models should be added in the table above and, if needed, + * implemented in the model switch below. + */ +static void +viaCalculateVideoColor(VIAPtr pVia, int hue, int saturation, int brightness, + int contrast, Bool reset, CARD32 * col1, CARD32 * col2) +{ + float fA, fB1, fC1, fD, fB2, fC2, fB3, fC3; + float fPI, fContrast, fSaturation, fHue, fBrightness; + const float *mCoeff; + unsigned long dwA, dwB1, dwC1, dwD, dwB2, dwC2, dwB3, dwC3, dwS; + unsigned long dwD_Int, dwD_Dec; + int intD; + int model; + + fPI = (float)(M_PI / 180.); + + if (reset) { + saturation = 10000; + brightness = 5000; + contrast = 10000; + } + + switch (pVia->ChipId) { + case PCI_CHIP_VT3205: + case PCI_CHIP_VT3204: + case PCI_CHIP_VT3259: + case PCI_CHIP_VT3314: + model = 0; + break; + case PCI_CHIP_CLE3122: + model = (CLE266_REV_IS_CX(pVia->ChipRev) ? 0 : 1); + break; + default: + ErrorF("Unknown Chip ID\n"); + model = 0; + } + + switch (model) { + case 0: + fBrightness = + rangeEqualize(0., 10000., -128., 128., -16., (float)brightness); + fContrast = + rangeEqualize(0., 20000., 0., 1.6645, 1.0, (float)contrast); + fSaturation = rangeEqualize(0., 20000, 0., 2., 1., (float)saturation); + break; + default: + fBrightness = + rangeEqualize(0., 10000., -128., 128., -12., (float)brightness); + fContrast = + rangeEqualize(0., 20000., 0., 1.6645, 1.1, (float)contrast); + fSaturation = + rangeEqualize(0., 20000, 0., 2., 1.15, (float)saturation); + break; + } + fHue = (float)hue; + + mCoeff = colorCTable[model]; + + fA = (float)(mCoeff[0] * fContrast); + fB1 = (float)(-mCoeff[1] * fContrast * fSaturation * sin(fHue * fPI)); + fC1 = (float)(mCoeff[1] * fContrast * fSaturation * cos(fHue * fPI)); + fD = (float)(mCoeff[0] * (fBrightness)); + fB2 = (float)((mCoeff[2] * sin(fHue * fPI) - + mCoeff[3] * cos(fHue * fPI)) * fContrast * fSaturation); + fC2 = (float)(-(mCoeff[2] * cos(fHue * fPI) + + mCoeff[3] * sin(fHue * fPI)) * fContrast * fSaturation); + fB3 = (float)(mCoeff[4] * fContrast * fSaturation * cos(fHue * fPI)); + fC3 = (float)(mCoeff[4] * fContrast * fSaturation * sin(fHue * fPI)); + + switch (model) { + case 0: + dwA = vPackFloat(fA, 1.9375, 0., 32., 5, 0); + dwB1 = vPackFloat(fB1, 2.125, -2.125, 16., 5, 1); + dwC1 = vPackFloat(fC1, 2.125, -2.125, 16., 5, 1); + + if (fD >= 0) { + intD = (int)fD; + if (intD > 127) + intD = 127; + dwD_Int = ((unsigned long)intD) & 0xff; + dwD = ((unsigned long)(fD * 16 + 1)) >> 1; + dwD_Dec = dwD & 0x7; + } else { + intD = (int)fD; + if (intD < -128) + intD = -128; + intD = intD + 256; + dwD_Int = ((unsigned long)intD) & 0xff; + fD = -fD; + dwD = ((unsigned long)(fD * 16 + 1)) >> 1; + dwD_Dec = dwD & 0x7; + } + + dwB2 = vPackFloat(fB2, 1.875, -1.875, 16, 4, 1); + dwC2 = vPackFloat(fC2, 1.875, -1.875, 16, 4, 1); + dwB3 = vPackFloat(fB3, 3.875, -3.875, 16, 5, 1); + dwC3 = vPackFloat(fC3, 3.875, -3.875, 16, 5, 1); + *col1 = (dwA << 24) | (dwB1 << 16) | (dwC1 << 8) | dwD_Int; + *col2 = + (dwD_Dec << 29 | dwB2 << 24) | (dwC2 << 16) | (dwB3 << 8) | + (dwC3); + break; + + default: + dwA = vPackFloat(fA, 1.9375, -0., 32, 5, 0); + dwB1 = vPackFloat(fB1, 0.75, -0.75, 8., 2, 1); + dwC1 = vPackFloat(fC1, 2.875, 1., 16., 5, 0); + + if (fD >= 127) + fD = 127; + + if (fD <= -128) + fD = -128; + + if (fD >= 0) { + dwS = 0; + } else { + dwS = 1; + fD = fD + 128; + } + + dwD = ((unsigned long)(fD * 2 + 1)) >> 1; + if (dwD >= 0x7f) { + dwD = 0x7f | (dwS << 7); + } else { + dwD = (dwD & 0x7f) | (dwS << 7); + } + + dwB2 = vPackFloat(fB2, 0., -0.875, 16., 3, 0); + dwC2 = vPackFloat(fC2, 0., -1.875, 16., 4, 0); + dwB3 = vPackFloat(fB3, 3.75, 0., 8., 4, 0); + dwC3 = vPackFloat(fC3, 1.25, -1.25, 8., 3, 1); + *col1 = (dwA << 24) | (dwB1 << 18) | (dwC1 << 9) | dwD; + *col2 = (dwB2 << 25) | (dwC2 << 17) | (dwB3 << 10) | (dwC3 << 2); + break; + } +} + +/* + * + * + */ +void +viaSetColorSpace(VIAPtr pVia, int hue, int saturation, int brightness, + int contrast, Bool reset) +{ + CARD32 col1, col2; + + viaCalculateVideoColor(pVia, hue, saturation, brightness, contrast, reset, + &col1, &col2); + switch (pVia->ChipId) { + case PCI_CHIP_VT3205: + case PCI_CHIP_VT3204: + case PCI_CHIP_VT3259: + case PCI_CHIP_VT3314: + VIDOutD(V3_ColorSpaceReg_1, col1); + VIDOutD(V3_ColorSpaceReg_2, col2); + DBG_DD(ErrorF("000002C4 %08lx\n", col1)); + DBG_DD(ErrorF("000002C8 %08lx\n", col2)); + break; + case PCI_CHIP_CLE3122: + VIDOutD(V1_ColorSpaceReg_2, col2); + VIDOutD(V1_ColorSpaceReg_1, col1); + VIDOutD(V3_ColorSpaceReg_2, col2); + VIDOutD(V3_ColorSpaceReg_1, col1); + + DBG_DD(ErrorF("00000288 %08lx\n", col2)); + DBG_DD(ErrorF("00000284 %08lx\n", col1)); + break; + default: + DBG_DD(ErrorF("Unknown DeviceID\n")); + break; + } +} + +static unsigned long +ViaInitVideoStatusFlag(VIAPtr pVia) +{ + switch (pVia->ChipId) { + case PCI_CHIP_VT3205: + case PCI_CHIP_VT3204: + case PCI_CHIP_VT3259: + case PCI_CHIP_VT3314: + return VIDEO_HQV_INUSE | SW_USE_HQV | VIDEO_3_INUSE; + case PCI_CHIP_CLE3122: + return VIDEO_HQV_INUSE | SW_USE_HQV | VIDEO_1_INUSE; + default: + DBG_DD(ErrorF("Unknown DeviceID\n")); + break; + } + return 0UL; +} + +static unsigned long +ViaSetVidCtl(VIAPtr pVia, unsigned int videoFlag) +{ + if (videoFlag & VIDEO_1_INUSE) { + /*=* Modify for C1 FIFO *=*/ + /* WARNING: not checking Chipset! */ + if (CLE266_REV_IS_CX(pVia->ChipRev)) + return V1_ENABLE | V1_EXPIRE_NUM_F; + else { + /* Overlay source format for V1 */ + if (pVia->swov.gdwUseExtendedFIFO) + return V1_ENABLE | V1_EXPIRE_NUM_A | V1_FIFO_EXTENDED; + else + return V1_ENABLE | V1_EXPIRE_NUM; + } + } else { + switch (pVia->ChipId) { + case PCI_CHIP_VT3205: + case PCI_CHIP_VT3204: + case PCI_CHIP_VT3259: + case PCI_CHIP_VT3314: + return V3_ENABLE | V3_EXPIRE_NUM_3205; + + case PCI_CHIP_CLE3122: + if (CLE266_REV_IS_CX(pVia->ChipRev)) + return V3_ENABLE | V3_EXPIRE_NUM_F; + else + return V3_ENABLE | V3_EXPIRE_NUM; + break; + + default: + DBG_DD(ErrorF("Unknown DeviceID\n")); + break; + } + } + return 0; +} + +/* + * Fill the buffer with 0x8000 (YUV2 black). + */ +static void +ViaYUVFillBlack(VIAPtr pVia, int offset, int num) +{ + CARD16 *ptr = (CARD16 *) (pVia->FBBase + offset); + + while (num-- > 0) +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + *ptr++ = 0x0080; +#else + *ptr++ = 0x8000; +#endif +} + +/* + * Add an HQV surface to an existing FOURCC surface. + * numbuf: number of buffers, 1, 2 or 3 + * fourcc: FOURCC code of the current (already existing) surface + */ +static long +AddHQVSurface(ScrnInfoPtr pScrn, unsigned int numbuf, CARD32 fourcc) +{ + unsigned int i, width, height, pitch, fbsize, addr; + unsigned long retCode; + BOOL isplanar; + + VIAPtr pVia = VIAPTR(pScrn); + CARD32 AddrReg[3] = + { HQV_DST_STARTADDR0, HQV_DST_STARTADDR1, HQV_DST_STARTADDR2 }; + unsigned long proReg = 0; + + if ((pVia->ChipId == PCI_CHIP_VT3259) && + !(pVia->swov.gdwVideoFlagSW & VIDEO_1_INUSE)) + proReg = PRO_HQV1_OFFSET; + + isplanar = ((fourcc == FOURCC_YV12) || (fourcc == FOURCC_XVMC)); + + width = pVia->swov.SWDevice.gdwSWSrcWidth; + height = pVia->swov.SWDevice.gdwSWSrcHeight; + pitch = pVia->swov.SWDevice.dwPitch; + fbsize = pitch * height * (isplanar ? 2 : 1); + + VIAFreeLinear(&pVia->swov.HQVMem); + retCode = VIAAllocLinear(&pVia->swov.HQVMem, pScrn, fbsize * numbuf); + if (retCode != Success) + return retCode; + addr = pVia->swov.HQVMem.base; + + ViaYUVFillBlack(pVia, addr, fbsize); + + for (i = 0; i < numbuf; i++) { + pVia->swov.overlayRecordV1.dwHQVAddr[i] = addr; + VIDOutD(AddrReg[i] + proReg, addr); + addr += fbsize; + } + + return Success; +} + +/* + * Create a FOURCC surface. + * doalloc: set true to actually allocate memory for the framebuffers + */ +static long +CreateSurface(ScrnInfoPtr pScrn, CARD32 FourCC, CARD16 Width, + CARD16 Height, BOOL doalloc) +{ + VIAPtr pVia = VIAPTR(pScrn); + unsigned long pitch, fbsize, addr; + unsigned long retCode; + BOOL isplanar; + + pVia->swov.SrcFourCC = FourCC; + pVia->swov.gdwVideoFlagSW = ViaInitVideoStatusFlag(pVia); + + isplanar = FALSE; + switch (FourCC) { + case FOURCC_YV12: + case FOURCC_XVMC: + isplanar = TRUE; + pitch = ALIGN_TO(Width, 32); + fbsize = pitch * Height * 1.5; + break; + case FOURCC_RV32: + pitch = ALIGN_TO(Width << 2, 32); + fbsize = pitch * Height; + break; + default: + pitch = ALIGN_TO(Width << 1, 32); + fbsize = pitch * Height; + break; + } + + if (doalloc) { + VIAFreeLinear(&pVia->swov.SWfbMem); + retCode = VIAAllocLinear(&pVia->swov.SWfbMem, pScrn, fbsize * 2); + if (retCode != Success) + return retCode; + addr = pVia->swov.SWfbMem.base; + + ViaYUVFillBlack(pVia, addr, fbsize); + + pVia->swov.SWDevice.dwSWPhysicalAddr[0] = addr; + pVia->swov.SWDevice.dwSWPhysicalAddr[1] = addr + fbsize; + pVia->swov.SWDevice.lpSWOverlaySurface[0] = pVia->FBBase + addr; + pVia->swov.SWDevice.lpSWOverlaySurface[1] = + pVia->swov.SWDevice.lpSWOverlaySurface[0] + fbsize; + + if (isplanar) { + pVia->swov.SWDevice.dwSWCrPhysicalAddr[0] = + pVia->swov.SWDevice.dwSWPhysicalAddr[0] + (pitch * Height); + pVia->swov.SWDevice.dwSWCrPhysicalAddr[1] = + pVia->swov.SWDevice.dwSWPhysicalAddr[1] + (pitch * Height); + pVia->swov.SWDevice.dwSWCbPhysicalAddr[0] = + pVia->swov.SWDevice.dwSWCrPhysicalAddr[0] + + ((pitch >> 1) * (Height >> 1)); + pVia->swov.SWDevice.dwSWCbPhysicalAddr[1] = + pVia->swov.SWDevice.dwSWCrPhysicalAddr[1] + + ((pitch >> 1) * (Height >> 1)); + } + } + + pVia->swov.SWDevice.gdwSWSrcWidth = Width; + pVia->swov.SWDevice.gdwSWSrcHeight = Height; + pVia->swov.SWDevice.dwPitch = pitch; + + pVia->swov.overlayRecordV1.dwV1OriWidth = Width; + pVia->swov.overlayRecordV1.dwV1OriHeight = Height; + pVia->swov.overlayRecordV1.dwV1OriPitch = pitch; + + return Success; +} + +/* + * + */ +int +ViaSwovSurfaceCreate(ScrnInfoPtr pScrn, viaPortPrivPtr pPriv, CARD32 FourCC, + CARD16 Width, CARD16 Height) +{ + VIAPtr pVia = VIAPTR(pScrn); + unsigned long retCode = Success; + int numbuf = pVia->HWDiff.dwThreeHQVBuffer ? 3 : 2; + + DBG_DD(ErrorF("ViaSwovSurfaceCreate: FourCC =0x%08lx\n", FourCC)); + + if ((pVia->VideoStatus & VIDEO_SWOV_SURFACE_CREATED) && + (FourCC == pPriv->FourCC)) + return Success; + + pPriv->FourCC = FourCC; + switch (FourCC) { + case FOURCC_YUY2: + case FOURCC_RV15: + case FOURCC_RV16: + case FOURCC_RV32: + retCode = CreateSurface(pScrn, FourCC, Width, Height, TRUE); + if (retCode != Success) + break; + if ((pVia->swov.gdwVideoFlagSW & SW_USE_HQV)) + retCode = AddHQVSurface(pScrn, numbuf, FourCC); + break; + + case FOURCC_HQVSW: + retCode = AddHQVSurface(pScrn, numbuf, FOURCC_YUY2); + break; + + case FOURCC_YV12: + retCode = CreateSurface(pScrn, FourCC, Width, Height, TRUE); + if (retCode == Success) + retCode = AddHQVSurface(pScrn, numbuf, FOURCC_YV12); + break; + + case FOURCC_XVMC: + retCode = CreateSurface(pScrn, FourCC, Width, Height, FALSE); + if (retCode == Success) + retCode = AddHQVSurface(pScrn, numbuf, FOURCC_XVMC); + break; + + default: + break; + } + + if (retCode == Success) { + pVia->swov.SWDevice.lpSWOverlaySurface[0] = + pVia->FBBase + pVia->swov.SWDevice.dwSWPhysicalAddr[0]; + pVia->swov.SWDevice.lpSWOverlaySurface[1] = + pVia->FBBase + pVia->swov.SWDevice.dwSWPhysicalAddr[1]; + + DBG_DD(ErrorF(" lpSWOverlaySurface[0]: %p\n", + pVia->swov.SWDevice.lpSWOverlaySurface[0])); + DBG_DD(ErrorF(" lpSWOverlaySurface[1]: %p\n", + pVia->swov.SWDevice.lpSWOverlaySurface[1])); + + pVia->VideoStatus |= VIDEO_SWOV_SURFACE_CREATED | VIDEO_SWOV_ON; + } + return retCode; +} + +/* + * Destroy Surface + */ +void +ViaSwovSurfaceDestroy(ScrnInfoPtr pScrn, viaPortPrivPtr pPriv) +{ + VIAPtr pVia = VIAPTR(pScrn); + + DBG_DD(ErrorF("ViaSwovSurfaceDestroy: FourCC =0x%08lx\n", pPriv->FourCC)); + + if (pVia->VideoStatus & VIDEO_SWOV_SURFACE_CREATED) { + DBG_DD(ErrorF("ViaSwovSurfaceDestroy: VideoStatus =0x%08lx\n", + pVia->VideoStatus)); + + switch (pPriv->FourCC) { + case FOURCC_YUY2: + case FOURCC_RV16: + case FOURCC_RV32: + case FOURCC_RV15: + pVia->swov.SrcFourCC = 0; + + VIAFreeLinear(&pVia->swov.SWfbMem); + if ((pVia->swov.gdwVideoFlagSW & SW_USE_HQV)) + VIAFreeLinear(&pVia->swov.HQVMem); + pVia->swov.gdwVideoFlagSW = 0; + break; + + case FOURCC_HQVSW: + VIAFreeLinear(&pVia->swov.HQVMem); + pVia->swov.gdwVideoFlagSW = 0; + break; + + case FOURCC_YV12: + VIAFreeLinear(&pVia->swov.SWfbMem); + case FOURCC_XVMC: + pVia->swov.SrcFourCC = 0; + + VIAFreeLinear(&pVia->swov.HQVMem); + pVia->swov.gdwVideoFlagSW = 0; + break; + } + + pPriv->FourCC = 0; + pVia->VideoStatus &= ~VIDEO_SWOV_SURFACE_CREATED; + + } else + DBG_DD(ErrorF + ("ViaSwovSurfaceDestroy: No SW Overlay Surface Destroyed," + " VideoStatus =0x%08lx\n", pVia->VideoStatus)); +} + +static void +SetFIFO_V1(VIAPtr pVia, CARD8 depth, CARD8 prethreshold, CARD8 threshold) +{ + SaveVideoRegister(pVia, V_FIFO_CONTROL, ((depth - 1) & 0x7f) | + ((prethreshold & 0x7f) << 24) | ((threshold & 0x7f) << 8)); +} + +static void +SetFIFO_V3(VIAPtr pVia, CARD8 depth, CARD8 prethreshold, CARD8 threshold) +{ + if (pVia->ChipId == PCI_CHIP_VT3314) { + SaveVideoRegister(pVia, ALPHA_V3_FIFO_CONTROL, + (VIDInD(ALPHA_V3_FIFO_CONTROL) & ALPHA_FIFO_MASK) | + ((depth - 1) & 0xff) | ((threshold & 0xff) << 8)); + SaveVideoRegister(pVia, ALPHA_V3_PREFIFO_CONTROL, + (VIDInD(ALPHA_V3_PREFIFO_CONTROL) & ~V3_FIFO_MASK_3314) | + (prethreshold & 0xff)); + } else { + SaveVideoRegister(pVia, ALPHA_V3_FIFO_CONTROL, + (VIDInD(ALPHA_V3_FIFO_CONTROL) & ALPHA_FIFO_MASK) | + ((depth - 1) & 0xff) | ((threshold & 0xff) << 8)); + SaveVideoRegister(pVia, ALPHA_V3_PREFIFO_CONTROL, + (VIDInD(ALPHA_V3_PREFIFO_CONTROL) & ~V3_FIFO_MASK) | + (prethreshold & 0x7f)); + } +} + +static void +SetFIFO_64or32(VIAPtr pVia) +{ + /*=* Modify for C1 FIFO *=*/ + /* WARNING: not checking Chipset! */ + if (CLE266_REV_IS_CX(pVia->ChipRev)) + SetFIFO_V1(pVia, 64, 56, 56); + else + SetFIFO_V1(pVia, 32, 29, 16); +} + +static void +SetFIFO_64or16(VIAPtr pVia) +{ + /*=* Modify for C1 FIFO *=*/ + /* WARNING: not checking Chipset! */ + if (CLE266_REV_IS_CX(pVia->ChipRev)) + SetFIFO_V1(pVia, 64, 56, 56); + else + SetFIFO_V1(pVia, 16, 12, 8); +} + +static void +SetFIFO_64or48or32(VIAPtr pVia) +{ + /*=* Modify for C1 FIFO *=*/ + /* WARNING: not checking Chipset! */ + if (CLE266_REV_IS_CX(pVia->ChipRev)) + SetFIFO_V1(pVia, 64, 56, 56); + else { + if (pVia->swov.gdwUseExtendedFIFO) + SetFIFO_V1(pVia, 48, 40, 40); + else + SetFIFO_V1(pVia, 32, 29, 16); + } +} + +static void +SetFIFO_V3_64or32or32(VIAPtr pVia) +{ + switch (pVia->ChipId) { + case PCI_CHIP_VT3204: + SetFIFO_V3(pVia, 100, 89, 89); + break; + case PCI_CHIP_VT3314: + SetFIFO_V3(pVia, 64, 61, 61); + break; + case PCI_CHIP_VT3205: + case PCI_CHIP_VT3259: + SetFIFO_V3(pVia, 32, 29, 29); + break; + + case PCI_CHIP_CLE3122: + if (CLE266_REV_IS_CX(pVia->ChipRev)) + SetFIFO_V3(pVia, 64, 56, 56); + else + SetFIFO_V3(pVia, 32, 16, 16); + break; + + default: + break; + } +} + +static void +SetFIFO_V3_64or32or16(VIAPtr pVia) +{ + switch (pVia->ChipId) { + case PCI_CHIP_VT3204: + SetFIFO_V3(pVia, 100, 89, 89); + break; + case PCI_CHIP_VT3314: + SetFIFO_V3(pVia, 64, 61, 61); + break; + case PCI_CHIP_VT3205: + case PCI_CHIP_VT3259: + SetFIFO_V3(pVia, 32, 29, 29); + break; + + case PCI_CHIP_CLE3122: + if (CLE266_REV_IS_CX(pVia->ChipRev)) + SetFIFO_V3(pVia, 64, 56, 56); + else + SetFIFO_V3(pVia, 16, 16, 8); + break; + + default: + break; + } +} + +static void +SetupFIFOs(VIAPtr pVia, unsigned long videoFlag, unsigned long miniCtl, + unsigned long srcWidth) +{ + if (miniCtl & V1_Y_INTERPOLY) { + if (pVia->swov.SrcFourCC == FOURCC_YV12 || + pVia->swov.SrcFourCC == FOURCC_XVMC) { + if (videoFlag & VIDEO_HQV_INUSE) { + if (videoFlag & VIDEO_1_INUSE) + SetFIFO_64or32(pVia); + else + SetFIFO_V3_64or32or16(pVia); + } else { + /* Minified video will be skewed without this workaround. */ + if (srcWidth <= 80) { /* Fetch count <= 5 */ + if (videoFlag & VIDEO_1_INUSE) + SetFIFO_V1(pVia, 16, 0, 0); + else + SetFIFO_V3(pVia, 16, 16, 0); + } else { + if (videoFlag & VIDEO_1_INUSE) + SetFIFO_64or16(pVia); + else + SetFIFO_V3_64or32or16(pVia); + } + } + } else { + if (videoFlag & VIDEO_1_INUSE) + SetFIFO_64or48or32(pVia); + else { + /* Fix V3 bug. */ + if (srcWidth <= 8) + SetFIFO_V3(pVia, 1, 0, 0); + else + SetFIFO_V3_64or32or32(pVia); + } + } + } else { + if (pVia->swov.SrcFourCC == FOURCC_YV12 || + pVia->swov.SrcFourCC == FOURCC_XVMC) { + if (videoFlag & VIDEO_HQV_INUSE) { + if (videoFlag & VIDEO_1_INUSE) + SetFIFO_64or32(pVia); + else + SetFIFO_V3_64or32or16(pVia); + } else { + /* Minified video will be skewed without this workaround. */ + if (srcWidth <= 80) { /* Fetch count <= 5 */ + if (videoFlag & VIDEO_1_INUSE) + SetFIFO_V1(pVia, 16, 0, 0); + else + SetFIFO_V3(pVia, 16, 16, 0); + } else { + if (videoFlag & VIDEO_1_INUSE) + SetFIFO_64or16(pVia); + else + SetFIFO_V3_64or32or16(pVia); + } + } + } else { + if (videoFlag & VIDEO_1_INUSE) + SetFIFO_64or48or32(pVia); + else { + /* Fix V3 bug. */ + if (srcWidth <= 8) + SetFIFO_V3(pVia, 1, 0, 0); + else + SetFIFO_V3_64or32or32(pVia); + } + } + } +} + +static CARD32 +SetColorKey(VIAPtr pVia, unsigned long videoFlag, + CARD32 keyLow, CARD32 keyHigh, CARD32 compose) +{ + keyLow &= 0x00FFFFFF; + if (pVia->ChipId == PCI_CHIP_VT3259) + keyLow |= 0x40000000; + + /*SaveVideoRegister(pVia, V_COLOR_KEY, keyLow); */ + + if (videoFlag & VIDEO_1_INUSE) { + SaveVideoRegister(pVia, V_COLOR_KEY, keyLow); + } else { + if (pVia->HWDiff.dwSupportTwoColorKey) /*CLE_C0 */ + SaveVideoRegister(pVia, V3_COLOR_KEY, keyLow); + } + + /*compose = (compose & ~0x0f) | SELECT_VIDEO_IF_COLOR_KEY; */ + /*CLE_C0 */ + compose = + (compose & ~0x0f) | SELECT_VIDEO_IF_COLOR_KEY | + SELECT_VIDEO3_IF_COLOR_KEY; + /*compose = (compose & ~0x0f) ; */ + + return compose; +} + +static CARD32 +SetChromaKey(VIAPtr pVia, unsigned long videoFlag, + CARD32 chromaLow, CARD32 chromaHigh, CARD32 miniCtl, CARD32 compose) +{ + chromaLow &= CHROMA_KEY_LOW; + chromaHigh &= CHROMA_KEY_HIGH; + + chromaLow |= (VIDInD(V_CHROMAKEY_LOW) & ~CHROMA_KEY_LOW); + chromaHigh |= (VIDInD(V_CHROMAKEY_HIGH) & ~CHROMA_KEY_HIGH); + + if (pVia->ChipId == PCI_CHIP_VT3259) + chromaLow |= 0x40000000; + + SaveVideoRegister(pVia, V_CHROMAKEY_HIGH, chromaHigh); + if (videoFlag & VIDEO_1_INUSE) { + SaveVideoRegister(pVia, V_CHROMAKEY_LOW, chromaLow & ~V_CHROMAKEY_V3); + /* Temporarily solve the HW interpolation error when using Chroma key */ + SaveVideoRegister(pVia, V1_MINI_CONTROL, miniCtl & 0xFFFFFFF8); + } else { + SaveVideoRegister(pVia, V_CHROMAKEY_LOW, chromaLow | V_CHROMAKEY_V3); + SaveVideoRegister(pVia, V3_MINI_CONTROL, miniCtl & 0xFFFFFFF8); + } + + /* Modified by Scottie[2001.12.5] for select video if (Color key & Chroma key) */ + if (compose == SELECT_VIDEO_IF_COLOR_KEY) + compose = SELECT_VIDEO_IF_COLOR_KEY | SELECT_VIDEO_IF_CHROMA_KEY; + else + compose = (compose & ~0x0f) | SELECT_VIDEO_IF_CHROMA_KEY; + + return compose; +} + +static void +SetVideoStart(VIAPtr pVia, unsigned long videoFlag, + unsigned int numbufs, CARD32 a1, CARD32 a2, CARD32 a3) +{ + CARD32 V1Addr[3] = { V1_STARTADDR_0, V1_STARTADDR_1, V1_STARTADDR_2 }; + CARD32 V3Addr[3] = { V3_STARTADDR_0, V3_STARTADDR_1, V3_STARTADDR_2 }; + CARD32 *VideoAddr = (videoFlag & VIDEO_1_INUSE) ? V1Addr : V3Addr; + + SaveVideoRegister(pVia, VideoAddr[0], a1); + if (numbufs > 1) + SaveVideoRegister(pVia, VideoAddr[1], a2); + if (numbufs > 2) + SaveVideoRegister(pVia, VideoAddr[2], a3); +} + +static void +SetHQVFetch(VIAPtr pVia, CARD32 srcFetch, unsigned long srcHeight) +{ + unsigned long proReg = 0; + + if ((pVia->ChipId == PCI_CHIP_VT3259) && + !(pVia->swov.gdwVideoFlagSW & VIDEO_1_INUSE)) + proReg = PRO_HQV1_OFFSET; + + if (!pVia->HWDiff.dwHQVFetchByteUnit) { /* CLE_C0 */ + srcFetch >>= 3; /* fetch unit is 8-byte */ + } + + SaveVideoRegister(pVia, HQV_SRC_FETCH_LINE + proReg, + ((srcFetch - 1) << 16) | (srcHeight - 1)); +} + +static void +SetFetch(VIAPtr pVia, unsigned long videoFlag, CARD32 fetch) +{ + fetch <<= 20; + if (videoFlag & VIDEO_1_INUSE) { + SaveVideoRegister(pVia, V12_QWORD_PER_LINE, fetch); + } else { + fetch |= VIDInD(V3_ALPHA_QWORD_PER_LINE) & ~V3_FETCH_COUNT; + SaveVideoRegister(pVia, V3_ALPHA_QWORD_PER_LINE, fetch); + } +} + +static void +SetDisplayCount(VIAPtr pVia, unsigned long videoFlag, + unsigned long srcWidth, unsigned long srcHeight) +{ + unsigned long DisplayCount; + + /* Removed VIA's large pixelformat switch/case. + * All formats (YV12, UYVY, YUY2, VIA, RGB16 and RGB32) + * seem to use the same count. /A + */ + + if (videoFlag & VIDEO_HQV_INUSE) + DisplayCount = srcWidth - 1; + else + DisplayCount = srcWidth - pVia->swov.overlayRecordV1.dwminifyH; + + if (videoFlag & VIDEO_1_INUSE) + SaveVideoRegister(pVia, V1_SOURCE_HEIGHT, + (srcHeight << 16) | DisplayCount); + else + SaveVideoRegister(pVia, V3_SOURCE_WIDTH, DisplayCount); +} + +static void +SetMiniAndZoom(VIAPtr pVia, unsigned long videoFlag, + CARD32 miniCtl, CARD32 zoomCtl) +{ + if (videoFlag & VIDEO_1_INUSE) { + SaveVideoRegister(pVia, V1_MINI_CONTROL, miniCtl); + SaveVideoRegister(pVia, V1_ZOOM_CONTROL, zoomCtl); + } else { + SaveVideoRegister(pVia, V3_MINI_CONTROL, miniCtl); + SaveVideoRegister(pVia, V3_ZOOM_CONTROL, zoomCtl); + } +} + +static void +SetVideoControl(VIAPtr pVia, unsigned long videoFlag, CARD32 vidCtl) +{ + if (videoFlag & VIDEO_1_INUSE) + SaveVideoRegister(pVia, V1_CONTROL, vidCtl); + else + SaveVideoRegister(pVia, V3_CONTROL, vidCtl); +} + +static void +FireVideoCommand(VIAPtr pVia, unsigned long videoFlag, CARD32 compose) +{ + if (videoFlag & VIDEO_1_INUSE) + SaveVideoRegister(pVia, V_COMPOSE_MODE, compose | V1_COMMAND_FIRE); + else + SaveVideoRegister(pVia, V_COMPOSE_MODE, compose | V3_COMMAND_FIRE); +} + +static void +SetVideoWindow(ScrnInfoPtr pScrn, unsigned long videoFlag, + LPDDUPDATEOVERLAY pUpdate) +{ + VIAPtr pVia = VIAPTR(pScrn); + VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo; + CARD32 left = pUpdate->DstLeft; + CARD32 top = pUpdate->DstTop; + CARD32 right = pUpdate->DstRight - 1; + CARD32 bottom = pUpdate->DstBottom - 1; + + DBG_DD(ErrorF("SetVideoWindow: X (%ld,%ld) Y (%ld,%ld)\n", + left, right, top, bottom)); + + /* Modify for HW DVI limitation. + * When we enable both the CRT and DVI, then change resolution. + * If the resolution is smaller than the panel's physical size, + * the video display in Y direction will be cut. + * So, we need to adjust the Y top and bottom position. + */ + if (videoFlag & VIDEO_1_INUSE) { + if (pBIOSInfo->SetDVI && pBIOSInfo->scaleY) { + top = + pUpdate->DstTop * pBIOSInfo->panelY / + pScrn->currentMode->VDisplay; + bottom = + pUpdate->DstBottom * pBIOSInfo->panelY / + pScrn->currentMode->VDisplay; + } + } + + if (top < 0) + top = 0; + else if (top > 2047) + top = 2047; + + if (bottom < 0) + bottom = 0; + else if (bottom > 2047) + bottom = 2047; + + if (left < 0) + left = 0; + else if (left > 2047) + left = 2047; + + if (right < 0) + right = 0; + else if (right > 2047) + right = 2047; + + if (videoFlag & VIDEO_1_INUSE) { + SaveVideoRegister(pVia, V1_WIN_END_Y, (right << 16) | bottom); + SaveVideoRegister(pVia, V1_WIN_START_Y, (left << 16) | top); + } else { + SaveVideoRegister(pVia, V3_WIN_END_Y, (right << 16) | bottom); + SaveVideoRegister(pVia, V3_WIN_START_Y, (left << 16) | top); + } +} + +/* + * Upd_Video() + */ +static Bool +Upd_Video(ScrnInfoPtr pScrn, unsigned long videoFlag, + unsigned long startAddr, LPDDUPDATEOVERLAY pUpdate, + unsigned long srcPitch, + unsigned long oriSrcWidth, unsigned long oriSrcHeight, + unsigned long deinterlaceMode, + unsigned long haveColorKey, unsigned long haveChromaKey, + unsigned long colorKeyLow, unsigned long colorKeyHigh, + unsigned long chromaKeyLow, unsigned long chromaKeyHigh) +{ + VIAPtr pVia = VIAPTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + VIAHWDiff *hwDiff = &pVia->HWDiff; + + int i; + unsigned long vidCtl = 0, compose; + unsigned long srcWidth, srcHeight, dstWidth, dstHeight; + unsigned long zoomCtl = 0, miniCtl = 0; + unsigned long hqvCtl = 0; + unsigned long hqvFilterCtl = 0, hqvMiniCtl = 0; + unsigned long haveHQVzoomH = 0, haveHQVzoomV = 0; + unsigned long hqvSrcWidth = 0, hqvDstWidth = 0; + unsigned long hqvSrcFetch = 0, hqvOffset = 0; + unsigned long dwOffset = 0, fetch = 0, tmp = 0; + unsigned long proReg = 0; + + if ((pVia->ChipId == PCI_CHIP_VT3259) && !(videoFlag & VIDEO_1_INUSE)) + proReg = PRO_HQV1_OFFSET; + + compose = (VIDInD(V_COMPOSE_MODE) & + ~(SELECT_VIDEO_IF_COLOR_KEY | V1_COMMAND_FIRE | V3_COMMAND_FIRE)) | + V_COMMAND_LOAD_VBI; + + DBG_DD(ErrorF("// Upd_Video:\n")); + DBG_DD(ErrorF("Modified rSrc X (%ld,%ld) Y (%ld,%ld)\n", + pUpdate->SrcLeft, pUpdate->SrcRight, + pUpdate->SrcTop, pUpdate->SrcBottom)); + DBG_DD(ErrorF("Modified rDest X (%ld,%ld) Y (%ld,%ld)\n", + pUpdate->DstLeft, pUpdate->DstRight, + pUpdate->DstTop, pUpdate->DstBottom)); + + pVia->swov.overlayRecordV1.dwWidth = dstWidth = + pUpdate->DstRight - pUpdate->DstLeft; + pVia->swov.overlayRecordV1.dwHeight = dstHeight = + pUpdate->DstBottom - pUpdate->DstTop; + srcWidth = (unsigned long)pUpdate->SrcRight - pUpdate->SrcLeft; + srcHeight = (unsigned long)pUpdate->SrcBottom - pUpdate->SrcTop; + DBG_DD(ErrorF("===srcWidth= %ld \n", srcWidth)); + DBG_DD(ErrorF("===srcHeight= %ld \n", srcHeight)); + + vidCtl = ViaSetVidCtl(pVia, videoFlag); + viaOverlayGetV1V3Format(pVia, (videoFlag & VIDEO_1_INUSE) ? 1 : 3, + videoFlag, &vidCtl, &hqvCtl); + + if (hwDiff->dwThreeHQVBuffer) { /* CLE_C0: HQV supports triple-buffering */ + hqvCtl &= ~HQV_SW_FLIP; + hqvCtl |= HQV_TRIPLE_BUFF | HQV_FLIP_STATUS; + } + + /* Starting address of source and Source offset */ + dwOffset = + viaOverlayGetSrcStartAddress(pVia, videoFlag, pUpdate, srcPitch, + &hqvOffset); + DBG_DD(ErrorF("===dwOffset= 0x%lx \n", dwOffset)); + + pVia->swov.overlayRecordV1.dwOffset = dwOffset; + + if (pVia->swov.SrcFourCC == FOURCC_YV12 || + pVia->swov.SrcFourCC == FOURCC_XVMC) { + YCBCRREC YCbCr; + + if (videoFlag & VIDEO_HQV_INUSE) { + SetVideoStart(pVia, videoFlag, hwDiff->dwThreeHQVBuffer ? 3 : 2, + pVia->swov.overlayRecordV1.dwHQVAddr[0] + dwOffset, + pVia->swov.overlayRecordV1.dwHQVAddr[1] + dwOffset, + pVia->swov.overlayRecordV1.dwHQVAddr[2] + dwOffset); + + if (pVia->swov.SrcFourCC != FOURCC_XVMC) { + YCbCr = viaOverlayGetYCbCrStartAddress(videoFlag, startAddr, + pVia->swov.overlayRecordV1.dwOffset, + pVia->swov.overlayRecordV1.dwUVoffset, + srcPitch, oriSrcHeight); + if (pVia->ChipId == PCI_CHIP_VT3259) { + SaveVideoRegister(pVia, HQV_SRC_STARTADDR_Y + proReg, + YCbCr.dwY); + SaveVideoRegister(pVia, HQV_SRC_STARTADDR_U + proReg, + YCbCr.dwCB); + } else { + SaveVideoRegister(pVia, HQV_SRC_STARTADDR_Y, YCbCr.dwY); + SaveVideoRegister(pVia, HQV_SRC_STARTADDR_U, YCbCr.dwCR); + SaveVideoRegister(pVia, HQV_SRC_STARTADDR_V, YCbCr.dwCB); + } + } + } else { + YCbCr = viaOverlayGetYCbCrStartAddress(videoFlag, startAddr, + pVia->swov.overlayRecordV1.dwOffset, + pVia->swov.overlayRecordV1.dwUVoffset, + srcPitch, oriSrcHeight); + + if (videoFlag & VIDEO_1_INUSE) { + SaveVideoRegister(pVia, V1_STARTADDR_0, YCbCr.dwY); + SaveVideoRegister(pVia, V1_STARTADDR_CB0, YCbCr.dwCR); + SaveVideoRegister(pVia, V1_STARTADDR_CR0, YCbCr.dwCB); + } else + DBG_DD(ErrorF + ("Upd_Video() : We do not support YV12 with V3!\n")); + } + } else { + if (videoFlag & VIDEO_HQV_INUSE) { + hqvSrcWidth = (unsigned long)pUpdate->SrcRight - pUpdate->SrcLeft; + hqvDstWidth = (unsigned long)pUpdate->DstRight - pUpdate->DstLeft; + + if (hqvSrcWidth > hqvDstWidth) + dwOffset = dwOffset * hqvDstWidth / hqvSrcWidth; + + SetVideoStart(pVia, videoFlag, hwDiff->dwThreeHQVBuffer ? 3 : 2, + pVia->swov.overlayRecordV1.dwHQVAddr[0] + hqvOffset, + pVia->swov.overlayRecordV1.dwHQVAddr[1] + hqvOffset, + pVia->swov.overlayRecordV1.dwHQVAddr[2] + hqvOffset); + + if (pVia->ChipId == PCI_CHIP_VT3259) + SaveVideoRegister(pVia, 0x1cc + proReg, dwOffset); + SaveVideoRegister(pVia, HQV_SRC_STARTADDR_Y + proReg, startAddr); + } else { + startAddr += dwOffset; + SetVideoStart(pVia, videoFlag, 1, startAddr, 0, 0); + } + } + + fetch = viaOverlayGetFetch(pVia, videoFlag, + srcWidth, dstWidth, oriSrcWidth, &hqvSrcFetch); + DBG_DD(ErrorF("===fetch= 0x%lx\n", fetch)); + +#if 0 + /* For DCT450 test-BOB INTERLEAVE */ + if ((deinterlaceMode & DDOVER_INTERLEAVED) + && (deinterlaceMode & DDOVER_BOB)) { + if (videoFlag & VIDEO_HQV_INUSE) + hqvCtl |= HQV_FIELD_2_FRAME | HQV_FRAME_2_FIELD | HQV_DEINTERLACE; + else + vidCtl |= V1_BOB_ENABLE | V1_FRAME_BASE; + } else if (deinterlaceMode & DDOVER_BOB) { + if (videoFlag & VIDEO_HQV_INUSE) + /* The HQV source data line count should be two times of the original line count */ + hqvCtl |= HQV_FIELD_2_FRAME | HQV_DEINTERLACE; + else + vidCtl |= V1_BOB_ENABLE; + } +#endif + + if (videoFlag & VIDEO_HQV_INUSE) { + if (!(deinterlaceMode & DDOVER_INTERLEAVED) + && (deinterlaceMode & DDOVER_BOB)) + SetHQVFetch(pVia, hqvSrcFetch, oriSrcHeight << 1); + else + SetHQVFetch(pVia, hqvSrcFetch, oriSrcHeight); + + if (pVia->swov.SrcFourCC == FOURCC_YV12 || + pVia->swov.SrcFourCC == FOURCC_XVMC) { + if (videoFlag & VIDEO_1_INUSE) + SaveVideoRegister(pVia, V1_STRIDE, srcPitch << 1); + else + SaveVideoRegister(pVia, V3_STRIDE, srcPitch << 1); + + if (pVia->HWDiff.dwHQVFetchByteUnit) + SaveVideoRegister(pVia, HQV_SRC_STRIDE + proReg, + ((srcPitch >> 1) << 16) | srcPitch | HQV_FIFO_DEPTH_1); + else + SaveVideoRegister(pVia, HQV_SRC_STRIDE + proReg, + ((srcPitch >> 1) << 16) | srcPitch); + + SaveVideoRegister(pVia, HQV_DST_STRIDE + proReg, (srcPitch << 1)); + } else { + if (videoFlag & VIDEO_1_INUSE) + SaveVideoRegister(pVia, V1_STRIDE, srcPitch); + else + SaveVideoRegister(pVia, V3_STRIDE, srcPitch); + + SaveVideoRegister(pVia, HQV_SRC_STRIDE + proReg, srcPitch); + SaveVideoRegister(pVia, HQV_DST_STRIDE + proReg, srcPitch); + } + + } else { + if (videoFlag & VIDEO_1_INUSE) + SaveVideoRegister(pVia, V1_STRIDE, srcPitch | (srcPitch << 15)); + else + SaveVideoRegister(pVia, V3_STRIDE, srcPitch | (srcPitch << 15)); + } + + /* Set destination window */ + SetVideoWindow(pScrn, videoFlag, pUpdate); + + compose |= ALWAYS_SELECT_VIDEO; + + /* Set up X zoom factor */ + + pVia->swov.overlayRecordV1.dwFetchAlignment = 0; + + if (!viaOverlayHQVCalcZoomWidth(pVia, videoFlag, srcWidth, dstWidth, + &zoomCtl, &miniCtl, &hqvFilterCtl, &hqvMiniCtl, &haveHQVzoomH)) { + /* Need to scale (minify) too much - can't handle it. */ + SetFetch(pVia, videoFlag, fetch); + FireVideoCommand(pVia, videoFlag, compose); + FlushVidRegBuffer(pVia); + return FALSE; + } + + SetFetch(pVia, videoFlag, fetch); + + /* Set up Y zoom factor */ + + /* For DCT450 test-BOB INTERLEAVE */ + if ((deinterlaceMode & DDOVER_INTERLEAVED) + && (deinterlaceMode & DDOVER_BOB)) { + if (!(videoFlag & VIDEO_HQV_INUSE)) { + srcHeight /= 2; + if (videoFlag & VIDEO_1_INUSE) + vidCtl |= V1_BOB_ENABLE | V1_FRAME_BASE; + else + vidCtl |= V3_BOB_ENABLE | V3_FRAME_BASE; + } else + hqvCtl |= HQV_FIELD_2_FRAME | HQV_FRAME_2_FIELD | HQV_DEINTERLACE; + } else if (deinterlaceMode & DDOVER_BOB) { + if (videoFlag & VIDEO_HQV_INUSE) { + srcHeight <<= 1; + hqvCtl |= HQV_FIELD_2_FRAME | HQV_DEINTERLACE; + } else { + if (videoFlag & VIDEO_1_INUSE) + vidCtl |= V1_BOB_ENABLE; + else + vidCtl |= V3_BOB_ENABLE; + } + } + + SetDisplayCount(pVia, videoFlag, srcWidth, srcHeight); + + if (!viaOverlayHQVCalcZoomHeight(pVia, srcHeight, dstHeight, &zoomCtl, + &miniCtl, &hqvFilterCtl, &hqvMiniCtl, &haveHQVzoomV)) { + /* Need to scale (minify) too much - can't handle it. */ + FireVideoCommand(pVia, videoFlag, compose); + FlushVidRegBuffer(pVia); + return FALSE; + } + + SetupFIFOs(pVia, videoFlag, miniCtl, srcWidth); + + if (videoFlag & VIDEO_HQV_INUSE) { + miniCtl = 0; + + if (haveHQVzoomH || haveHQVzoomV) { + tmp = 0; + + if (haveHQVzoomH) { + miniCtl = V1_X_INTERPOLY; + tmp = zoomCtl & 0xffff0000; + } + + if (haveHQVzoomV) { + miniCtl |= V1_Y_INTERPOLY | V1_YCBCR_INTERPOLY; + tmp |= zoomCtl & 0x0000ffff; + hqvFilterCtl &= 0xfffdffff; + } + + /* Temporary fix for 2D bandwidth problem. 2002/08/01 */ + if (pVia->swov.gdwUseExtendedFIFO) + miniCtl &= ~V1_Y_INTERPOLY; + + SetMiniAndZoom(pVia, videoFlag, miniCtl, tmp); + } else { + if (srcHeight == dstHeight) + hqvFilterCtl &= 0xfffdffff; + + SetMiniAndZoom(pVia, videoFlag, 0, 0); + } + SaveVideoRegister(pVia, HQV_MINIFY_CONTROL + proReg, hqvMiniCtl); + SaveVideoRegister(pVia, HQV_FILTER_CONTROL + proReg, hqvFilterCtl); + } else + SetMiniAndZoom(pVia, videoFlag, miniCtl, zoomCtl); + + if (haveColorKey) + compose = + SetColorKey(pVia, videoFlag, colorKeyLow, colorKeyHigh, compose); + + if (haveChromaKey) + compose = SetChromaKey(pVia, videoFlag, chromaKeyLow, chromaKeyHigh, + miniCtl, compose); + + /* Set up video control */ + if (videoFlag & VIDEO_HQV_INUSE) { + if (!pVia->swov.SWVideo_ON) { + DBG_DD(ErrorF(" First HQV\n")); + + FlushVidRegBuffer(pVia); + + DBG_DD(ErrorF(" Wait flips")); + + if (hwDiff->dwHQVInitPatch) { + DBG_DD(ErrorF(" Initializing HQV twice ...")); + for (i = 0; i < 2; i++) { + viaWaitHQVFlipClear(pVia, + ((hqvCtl & ~HQV_SW_FLIP) | HQV_FLIP_STATUS) & + ~HQV_ENABLE); + VIDOutD(HQV_CONTROL + proReg, hqvCtl); + viaWaitHQVFlip(pVia); + } + DBG_DD(ErrorF(" done.\n")); + } else { /* CLE_C0 */ + CARD32 volatile *HQVCtrl = + (CARD32 volatile *)(pVia->VidMapBase + HQV_CONTROL + + proReg); + + /* Check that HQV is idle */ + DBG_DD(ErrorF("HQV control wf - %08lx\n", *HQVCtrl)); + while (!(*HQVCtrl & HQV_IDLE)) { + DBG_DD(ErrorF("HQV control busy - %08lx\n", *HQVCtrl)); + usleep(1); + } + + if (pVia->ChipId == PCI_CHIP_VT3259) + hqvCtl |= HQV_GEN_IRQ; + + VIDOutD(HQV_CONTROL + proReg, hqvCtl & ~HQV_SW_FLIP); + VIDOutD(HQV_CONTROL + proReg, hqvCtl | HQV_SW_FLIP); + + DBG_DD(ErrorF("HQV control wf5 - %08lx\n", *HQVCtrl)); + DBG_DD(ErrorF(" Wait flips5")); + + if (pVia->ChipId != PCI_CHIP_VT3259) { + for (i = 0; (i < 50) && !(*HQVCtrl & HQV_FLIP_STATUS); + i++) { + DBG_DD(ErrorF(" HQV wait %d %08lx\n", i, *HQVCtrl)); + *HQVCtrl |= HQV_SW_FLIP | HQV_FLIP_STATUS; + usleep(1); + } + } else { + viaWaitHQVFlip(pVia); + } + + DBG_DD(ErrorF(" Wait flips6")); + } + + if (videoFlag & VIDEO_1_INUSE) { + VIDOutD(V1_CONTROL, vidCtl); + VIDOutD(V_COMPOSE_MODE, compose | V1_COMMAND_FIRE); + if (pVia->swov.gdwUseExtendedFIFO) { + /* Set Display FIFO */ + DBG_DD(ErrorF(" Wait flips7")); + viaWaitVBI(pVia); + DBG_DD(ErrorF(" Wait flips 8")); + hwp->writeSeq(hwp, 0x17, 0x2F); + ViaSeqMask(hwp, 0x16, 0x14, 0x1F); + hwp->writeSeq(hwp, 0x18, 0x56); + DBG_DD(ErrorF(" Wait flips 9")); + } + } else { + DBG_DD(ErrorF(" Wait flips 10")); + VIDOutD(V3_CONTROL, vidCtl); + VIDOutD(V_COMPOSE_MODE, compose | V3_COMMAND_FIRE); + } + DBG_DD(ErrorF(" Done flips")); + } else { + DBG_DD(ErrorF(" Normal called\n")); + SaveVideoRegister(pVia, HQV_CONTROL + proReg, + hqvCtl | HQV_FLIP_STATUS); + SetVideoControl(pVia, videoFlag, vidCtl); + FireVideoCommand(pVia, videoFlag, compose); + viaWaitHQVDone(pVia); + FlushVidRegBuffer(pVia); + } + } else { + SetVideoControl(pVia, videoFlag, vidCtl); + FireVideoCommand(pVia, videoFlag, compose); + viaWaitHQVDone(pVia); + FlushVidRegBuffer(pVia); + } + pVia->swov.SWVideo_ON = TRUE; + + DBG_DD(ErrorF(" Done Upd_Video")); + + return TRUE; + +} /* Upd_Video */ + +/* + * VIAVidUpdateOverlay() + * Parameters: src rectangle, dst rectangle, colorkey... + * Return value: unsigned long of state + * Note: updates the overlay image parameter. + */ +Bool +VIAVidUpdateOverlay(ScrnInfoPtr pScrn, LPDDUPDATEOVERLAY pUpdate) +{ + VIAPtr pVia = VIAPTR(pScrn); + OVERLAYRECORD *ovlV1 = &pVia->swov.overlayRecordV1; + + unsigned long flags = pUpdate->dwFlags; + unsigned long videoFlag = 0; + unsigned long startAddr = 0; + unsigned long deinterlaceMode = 0; + + unsigned long haveColorKey = 0, haveChromaKey = 0; + unsigned long colorKeyLow = 0, colorKeyHigh = 0; + unsigned long chromaKeyLow = 0, chromaKeyHigh = 0; + + unsigned long scrnWidth, scrnHeight; + int dstTop, dstBottom, dstLeft, dstRight; + int panDX, panDY; /* Panning delta */ + + unsigned long proReg = 0; + + panDX = pVia->swov.panning_x; + panDY = pVia->swov.panning_y; + pVia->swov.oldPanningX = pVia->swov.panning_x; + pVia->swov.oldPanningY = pVia->swov.panning_y; + + pUpdate->DstLeft -= panDX; + pUpdate->DstTop -= panDY; + pUpdate->DstRight -= panDX; + pUpdate->DstBottom -= panDY; + + DBG_DD(ErrorF("Raw rSrc X (%ld,%ld) Y (%ld,%ld)\n", + pUpdate->SrcLeft, pUpdate->SrcRight, + pUpdate->SrcTop, pUpdate->SrcBottom)); + DBG_DD(ErrorF("Raw rDest X (%ld,%ld) Y (%ld,%ld)\n", + pUpdate->DstLeft, pUpdate->DstRight, + pUpdate->DstTop, pUpdate->DstBottom)); + + if ((pVia->swov.SrcFourCC == FOURCC_YUY2) || + (pVia->swov.SrcFourCC == FOURCC_RV15) || + (pVia->swov.SrcFourCC == FOURCC_RV16) || + (pVia->swov.SrcFourCC == FOURCC_RV32) || + (pVia->swov.SrcFourCC == FOURCC_YV12) || + (pVia->swov.SrcFourCC == FOURCC_XVMC)) { + videoFlag = pVia->swov.gdwVideoFlagSW; + } + + if ((pVia->ChipId == PCI_CHIP_VT3259) && !(videoFlag & VIDEO_1_INUSE)) + proReg = PRO_HQV1_OFFSET; + + flags |= DDOVER_INTERLEAVED; + + /* Disable destination color keying if the alpha window is in use. */ + if (pVia->swov.gdwAlphaEnabled) + flags &= ~DDOVER_KEYDEST; + + ResetVidRegBuffer(pVia); + + /* For SW decode HW overlay use */ + startAddr = VIDInD(HQV_SRC_STARTADDR_Y + proReg); + + if (flags & DDOVER_KEYDEST) { + haveColorKey = 1; + colorKeyLow = pUpdate->dwColorSpaceLowValue; + } + + if (flags & DDOVER_INTERLEAVED) + deinterlaceMode |= DDOVER_INTERLEAVED; + + if (flags & DDOVER_BOB) + deinterlaceMode |= DDOVER_BOB; + + if ((pVia->ChipId == PCI_CHIP_CLE3122) + && (pScrn->currentMode->HDisplay > 1024)) { + DBG_DD(ErrorF("UseExtendedFIFO\n")); + pVia->swov.gdwUseExtendedFIFO = 1; + } else + pVia->swov.gdwUseExtendedFIFO = 0; + + /* Figure out actual rSrc rectangle */ + + dstLeft = pUpdate->DstLeft; + dstTop = pUpdate->DstTop; + dstRight = pUpdate->DstRight; + dstBottom = pUpdate->DstBottom; + + scrnWidth = pScrn->currentMode->HDisplay; + scrnHeight = pScrn->currentMode->VDisplay; + + if (dstLeft < 0) { + pUpdate->SrcLeft = (((-dstLeft) * ovlV1->dwV1OriWidth) + + ((dstRight - dstLeft) >> 1)) / (dstRight - dstLeft); + } + if (dstRight > scrnWidth) { + pUpdate->SrcRight = (((scrnWidth - dstLeft) * ovlV1->dwV1OriWidth) + + ((dstRight - dstLeft) >> 1)) / (dstRight - dstLeft); + } + if (dstTop < 0) { + pUpdate->SrcTop = (((-dstTop) * ovlV1->dwV1OriHeight) + + ((dstBottom - dstTop) >> 1)) / (dstBottom - dstTop); + } + if (dstBottom > scrnHeight) { + pUpdate->SrcBottom = (((scrnHeight - dstTop) * ovlV1->dwV1OriHeight) + + ((dstBottom - dstTop) >> 1)) / (dstBottom - dstTop); + } + + /* Save modified src & original dest rectangle parameters */ + + if ((pVia->swov.SrcFourCC == FOURCC_YUY2) || + (pVia->swov.SrcFourCC == FOURCC_RV15) || + (pVia->swov.SrcFourCC == FOURCC_RV16) || + (pVia->swov.SrcFourCC == FOURCC_RV32) || + (pVia->swov.SrcFourCC == FOURCC_YV12) || + (pVia->swov.SrcFourCC == FOURCC_XVMC)) { + pVia->swov.SWDevice.gdwSWDstLeft = pUpdate->DstLeft + panDX; + pVia->swov.SWDevice.gdwSWDstTop = pUpdate->DstTop + panDY; + pVia->swov.SWDevice.gdwSWDstWidth = + pUpdate->DstRight - pUpdate->DstLeft; + pVia->swov.SWDevice.gdwSWDstHeight = + pUpdate->DstBottom - pUpdate->DstTop; + + pVia->swov.SWDevice.gdwSWSrcWidth = + ovlV1->dwV1SrcWidth = pUpdate->SrcRight - pUpdate->SrcLeft; + pVia->swov.SWDevice.gdwSWSrcHeight = + ovlV1->dwV1SrcHeight = pUpdate->SrcBottom - pUpdate->SrcTop; + } + + ovlV1->dwV1SrcLeft = pUpdate->SrcLeft; + ovlV1->dwV1SrcRight = pUpdate->SrcRight; + ovlV1->dwV1SrcTop = pUpdate->SrcTop; + ovlV1->dwV1SrcBot = pUpdate->SrcBottom; + + /* Figure out actual rDest rectangle */ + + pUpdate->DstLeft = (dstLeft < 0) ? 0 : dstLeft; + pUpdate->DstTop = (dstTop < 0) ? 0 : dstTop; + if (pUpdate->DstTop >= scrnHeight) + pUpdate->DstTop = scrnHeight - 1; + pUpdate->DstRight = (dstRight > scrnWidth) ? scrnWidth : dstRight; + pUpdate->DstBottom = (dstBottom > scrnHeight) ? scrnHeight : dstBottom; + + /* Update the overlay */ + + if (!Upd_Video(pScrn, videoFlag, startAddr, pUpdate, + pVia->swov.SWDevice.dwPitch, ovlV1->dwV1OriWidth, + ovlV1->dwV1OriHeight, deinterlaceMode, haveColorKey, + haveChromaKey, colorKeyLow, colorKeyHigh, chromaKeyLow, + chromaKeyHigh)) + return FALSE; + + pVia->swov.SWVideo_ON = FALSE; + + return TRUE; + +} /* VIAVidUpdateOverlay */ + +/* + * + */ +void +ViaOverlayHide(ScrnInfoPtr pScrn) +{ + VIAPtr pVia = VIAPTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + CARD32 videoFlag = 0; + unsigned long proReg = 0; + + if ((pVia->swov.SrcFourCC == FOURCC_YUY2) || + (pVia->swov.SrcFourCC == FOURCC_RV15) || + (pVia->swov.SrcFourCC == FOURCC_RV16) || + (pVia->swov.SrcFourCC == FOURCC_RV32) || + (pVia->swov.SrcFourCC == FOURCC_YV12) || + (pVia->swov.SrcFourCC == FOURCC_XVMC)) + videoFlag = pVia->swov.gdwVideoFlagSW; + + if ((pVia->ChipId == PCI_CHIP_VT3259) && !(videoFlag & VIDEO_1_INUSE)) + proReg = PRO_HQV1_OFFSET; + + ResetVidRegBuffer(pVia); + + if (pVia->HWDiff.dwHQVDisablePatch) + ViaSeqMask(hwp, 0x2E, 0x00, 0x10); + + SaveVideoRegister(pVia, V_FIFO_CONTROL, V1_FIFO_PRETHRESHOLD12 | + V1_FIFO_THRESHOLD8 | V1_FIFO_DEPTH16); + SaveVideoRegister(pVia, ALPHA_V3_FIFO_CONTROL, ALPHA_FIFO_THRESHOLD4 + | ALPHA_FIFO_DEPTH8 | V3_FIFO_THRESHOLD24 | V3_FIFO_DEPTH32); + + if (videoFlag & VIDEO_HQV_INUSE) + SaveVideoRegister(pVia, HQV_CONTROL + proReg, + VIDInD(HQV_CONTROL + proReg) & ~HQV_ENABLE); + + if (videoFlag & VIDEO_1_INUSE) + SaveVideoRegister(pVia, V1_CONTROL, VIDInD(V1_CONTROL) & ~V1_ENABLE); + else + SaveVideoRegister(pVia, V3_CONTROL, VIDInD(V3_CONTROL) & ~V3_ENABLE); + + FireVideoCommand(pVia, videoFlag, VIDInD(V_COMPOSE_MODE)); + FlushVidRegBuffer(pVia); + + if (pVia->HWDiff.dwHQVDisablePatch) + ViaSeqMask(hwp, 0x2E, 0x10, 0x10); + + pVia->swov.SWVideo_ON = FALSE; + pVia->VideoStatus &= ~VIDEO_SWOV_ON; +} |