/* * 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 OPENCHROMEDRI #include "xf86drm.h" #endif #include "via_driver.h" #include "via_priv.h" #include "via_swov.h" #ifdef OPENCHROMEDRI #include "via_drm.h" #endif #include "via_vgahw.h" #include "via_id.h" #include #include /* * 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) { /* * Uncached PCI reading throughput is about 9 MB/s; so 8 bytes/loop means about * 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->VideoEngine == VIDEO_ENGINE_CME) { // while (*pdwState & (HQV_SUBPIC_FLIP | HQV_SW_FLIP)) ; while (*pdwState & HQV_SUBPIC_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; HWDiff->dwNeedV1Prefetch = 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; HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE; } 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; HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE; 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; HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE; 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; HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE; break; case VIA_VM800: case VIA_P4M900: 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; HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE; break; case VIA_K8M890: 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; HWDiff->dwNeedV1Prefetch = VID_HWDIFF_TRUE; break; case VIA_P4M890: 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; HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE; break; case VIA_CX700: 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; HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE; break; case VIA_VX800: case VIA_VX855: 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; HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE; 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: case PCI_CHIP_VT3336: case PCI_CHIP_VT3364: case PCI_CHIP_VT3324: case PCI_CHIP_VT3327: case PCI_CHIP_VT3353: case PCI_CHIP_VT3409: 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_VT3327: case PCI_CHIP_VT3336: case PCI_CHIP_VT3324: case PCI_CHIP_VT3364: case PCI_CHIP_VT3353: case PCI_CHIP_VT3409: 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_VT3327: case PCI_CHIP_VT3336: case PCI_CHIP_VT3324: case PCI_CHIP_VT3364: case PCI_CHIP_VT3353: case PCI_CHIP_VT3409: return (VIDEO_HQV_INUSE | SW_USE_HQV | VIDEO_1_INUSE | VIDEO_ACTIVE | VIDEO_SHOW); 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_VT3327: case PCI_CHIP_VT3336: case PCI_CHIP_VT3324: case PCI_CHIP_VT3364: case PCI_CHIP_VT3353: return V3_ENABLE | VIDEO_EXPIRE_NUM_VT3336; case PCI_CHIP_VT3409: return V3_ENABLE | VIDEO_EXPIRE_NUM_VT3409; 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 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) { switch (pVia->ChipId) { case PCI_CHIP_VT3314: case PCI_CHIP_VT3324: case PCI_CHIP_VT3327: case PCI_CHIP_VT3353: case PCI_CHIP_VT3409: 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)); break; default : 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)); break; } } 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_VT3327: case PCI_CHIP_VT3336: case PCI_CHIP_VT3324: case PCI_CHIP_VT3364: case PCI_CHIP_VT3353: case PCI_CHIP_VT3409: SetFIFO_V3(pVia, 225, 200, 250); break; 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_VT3327: case PCI_CHIP_VT3336: case PCI_CHIP_VT3324: case PCI_CHIP_VT3364: case PCI_CHIP_VT3353: case PCI_CHIP_VT3409: SetFIFO_V3(pVia, 225, 200, 250); break; 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->VideoEngine == VIDEO_ENGINE_CME) keyLow |= 0x40000000; if (videoFlag & VIDEO_1_INUSE) { SaveVideoRegister(pVia, V_COLOR_KEY, keyLow); } else { if (pVia->HWDiff.dwSupportTwoColorKey) /*CLE_C0 */ SaveVideoRegister(pVia, V3_COLOR_KEY, keyLow); } /*CLE_C0 */ compose = ((compose & ~0x0f) | SELECT_VIDEO_IF_COLOR_KEY | SELECT_VIDEO3_IF_COLOR_KEY); 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->VideoEngine == VIDEO_ENGINE_CME) 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 bytes */ } 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->Panel->NativeMode->Height / pScrn->currentMode->VDisplay); bottom = (pUpdate->DstBottom * pBIOSInfo->Panel->NativeMode->Height / 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); VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo; 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; DBG_DD(ErrorF("videoflag=%p\n", videoFlag)); 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)); dstWidth = pUpdate->DstRight - pUpdate->DstLeft; if (pBIOSInfo->Panel->IsActive && pBIOSInfo->Panel->Scale) { /* FIXME: We need to determine if the panel is using V1 or V3 */ float hfactor = (float)pBIOSInfo->Panel->NativeMode->Width / pScrn->currentMode->HDisplay; dstWidth *= hfactor; } pVia->swov.overlayRecordV1.dwWidth = dstWidth; 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); if (hwDiff->dwNeedV1Prefetch) { DBG_DD(ErrorF("NEEDV1PREFETCH\n")); vidCtl |= V1_PREFETCH_ON_3336; } /* * FIXME: * Enable video on secondary */ if ((pVia->VideoEngine == VIDEO_ENGINE_CME || pVia->Chipset == VIA_VM800) && pVia->pBIOSInfo->Panel->IsActive) { /* V1_ON_SND_DISPLAY */ vidCtl |= 0x80000000; /* SECOND_DISPLAY_COLOR_KEY_ENABLE */ compose |= 0x00010000 | 0x1; } 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->VideoEngine == VIDEO_ENGINE_CME) { 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->VideoEngine == VIDEO_ENGINE_CME) 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; /* Disable X interpolation if the height exceeds * the maximum supported by the hardware */ if (srcHeight >= pVia->swov.maxHInterp) miniCtl &= ~V1_X_INTERPOLY; tmp = zoomCtl & 0xffff0000; } if (haveHQVzoomV) { miniCtl |= V1_Y_INTERPOLY | V1_YCBCR_INTERPOLY; /* Disable Y interpolation if the width exceeds * the maximum supported by the hardware */ if (srcWidth >= pVia->swov.maxWInterp) miniCtl &= ~V1_Y_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); if (pVia->VideoEngine == VIDEO_ENGINE_CME) { VIDOutD(HQV_SRC_DATA_OFFSET_CONTROL1,0); VIDOutD(HQV_SRC_DATA_OFFSET_CONTROL3,((pUpdate->SrcRight - 1 ) << 16) | (pUpdate->SrcBottom - 1)); if (pVia->Chipset == VIA_VX800 || pVia->Chipset == VIA_VX855) { VIDOutD(HQV_SRC_DATA_OFFSET_CONTROL2,0); VIDOutD(HQV_SRC_DATA_OFFSET_CONTROL4,((pUpdate->SrcRight - 1 ) << 16) | (pUpdate->SrcBottom - 1)); } } /* 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->VideoEngine == VIDEO_ENGINE_CME) 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->VideoEngine != VIDEO_ENGINE_CME) { 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; }