1/*
2 * Copyright 2004-2005 The Unichrome Project  [unichrome.sf.net]
3 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
4 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sub license,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include "xf86.h"
31#include "xf86_OSproc.h"
32
33#ifdef HAVE_DRI
34#include "xf86drm.h"
35#include "via_drmclient.h"
36#include "via_drm.h"
37#endif
38#include "via_driver.h"
39
40#include <math.h>
41#include <unistd.h>
42
43/*
44 * Warning: this file contains revision checks which are CLE266-specific.
45 * There seems to be no checking present for KM400 or more recent devices.
46 *
47 * TODO:
48 *   - pVia->Chipset checking, of course
49 *   - move content of pVia->HWDiff into pVia->swov
50 *   - merge with CLEXF40040
51 */
52
53/*
54 * Old via_regrec code.
55 */
56#define VIDREG_BUFFER_SIZE  100  /* Number of entries in the VidRegBuffer. */
57#define IN_VIDEO_DISPLAY (*((unsigned long volatile *)(pVia->MapBase + V_FLAGS)) & VBI_STATUS)
58#define VIA_FIRETIMEOUT 40000
59
60enum HQV_CME_Regs {
61        HQV_SDO_CTRL1,
62        HQV_SDO_CTRL2,
63        HQV_SDO_CTRL3,
64        HQV_SDO_CTRL4
65};
66
67/* register offsets for VT3553/VX800 */
68static const unsigned hqv_cme_regs[] = {
69    [HQV_SDO_CTRL1]  = HQV_SRC_DATA_OFFSET_CONTROL1,
70    [HQV_SDO_CTRL2]  = HQV_SRC_DATA_OFFSET_CONTROL2,
71    [HQV_SDO_CTRL3]  = HQV_SRC_DATA_OFFSET_CONTROL3,
72    [HQV_SDO_CTRL4]  = HQV_SRC_DATA_OFFSET_CONTROL4
73};
74
75/* register hqv offsets for new VT3409/VX855 */
76static const unsigned hqv_cme_regs_409[] = {
77    [HQV_SDO_CTRL1]  = HQV_SRC_DATA_OFFSET_CTRL1_409,
78    [HQV_SDO_CTRL2]  = HQV_SRC_DATA_OFFSET_CTRL2_409,
79    [HQV_SDO_CTRL3]  = HQV_SRC_DATA_OFFSET_CTRL3_409,
80    [HQV_SDO_CTRL4]  = HQV_SRC_DATA_OFFSET_CTRL4_409
81};
82
83#define HQV_CME_REG(HWDiff, name) (HWDiff)->HQVCmeRegs[name]
84
85static void
86viaWaitVideoCommandFire(VIAPtr pVia)
87{
88/*
89 * Uncached PCI reading throughput is about 9 MB/s; so 8 bytes/loop means about
90 * 1M loops/second.  We want to time out after 50 ms, which means 50000 loops.
91 */
92    unsigned count = 50000;
93    CARD32 volatile *pdwState =
94            (CARD32 volatile *)(pVia->MapBase + V_COMPOSE_MODE);
95
96    while (--count && ((*pdwState & V1_COMMAND_FIRE)
97                       || (*pdwState & V3_COMMAND_FIRE))) ;
98    if (!count) {
99        ErrorF("viaWaitVideoCommandFire: Timeout.\n");
100    }
101}
102
103static void
104viaWaitHQVFlip(VIAPtr pVia)
105{
106    unsigned long proReg = 0;
107    CARD32 volatile *pdwState;
108    unsigned count = 50000;
109
110    if (pVia->ChipId == PCI_CHIP_VT3259
111        && !(pVia->swov.gdwVideoFlagSW & VIDEO_1_INUSE))
112        proReg = PRO_HQV1_OFFSET;
113
114    pdwState = (CARD32 volatile *)(pVia->MapBase + (HQV_CONTROL + proReg));
115
116    if (pVia->VideoEngine == VIDEO_ENGINE_CME) {
117		while (--count && (*pdwState & HQV_SUBPIC_FLIP));
118    } else {
119        while (--count && !(*pdwState & HQV_FLIP_STATUS)) ;
120    }
121}
122
123static void
124viaWaitHQVFlipClear(VIAPtr pVia, unsigned long dwData)
125{
126    CARD32 volatile *pdwState =
127            (CARD32 volatile *)(pVia->MapBase + HQV_CONTROL);
128    *pdwState = dwData;
129    unsigned count = 50000;
130
131    while (--count && (*pdwState & HQV_FLIP_STATUS)) {
132        VIASETREG(HQV_CONTROL, *pdwState | HQV_FLIP_STATUS);
133    }
134}
135
136static void
137viaWaitVBI(VIAPtr pVia)
138{
139    while (IN_VIDEO_DISPLAY) ;
140}
141
142static void
143viaWaitHQVDone(VIAPtr pVia)
144{
145    CARD32 volatile *pdwState;
146    unsigned long proReg = 0;
147    unsigned count = 50000;
148
149    if (pVia->ChipId == PCI_CHIP_VT3259
150        && !(pVia->swov.gdwVideoFlagSW & VIDEO_1_INUSE))
151        proReg = PRO_HQV1_OFFSET;
152
153    pdwState = (CARD32 volatile *)(pVia->MapBase + (HQV_CONTROL + proReg));
154    if (pVia->swov.MPEG_ON) {
155        while (--count && (*pdwState & HQV_SW_FLIP)) ;
156    }
157}
158
159/*
160 * Send all data in VidRegBuffer to the hardware.
161 */
162static void
163FlushVidRegBuffer(VIAPtr pVia)
164{
165    unsigned int i;
166
167    viaWaitVideoCommandFire(pVia);
168
169    for (i = 0; i < pVia->VidRegCursor; i += 2) {
170        VIASETREG(pVia->VidRegBuffer[i], pVia->VidRegBuffer[i + 1]);
171        DBG_DD(ErrorF("FlushVideoRegs: [%i] %08lx %08lx\n",
172                      i >> 1, pVia->VidRegBuffer[i] + 0x200,
173                      pVia->VidRegBuffer[i + 1]));
174    }
175
176    /* BUG: (?) VIA never resets the cursor.
177     * My fix is commented out for now, in case they had a reason for that. /A
178     */
179    /* pVia->VidRegCursor = 0; */
180}
181
182/*
183 * Initialize and clear VidRegBuffer.
184 */
185static void
186ResetVidRegBuffer(VIAPtr pVia)
187{
188    /* BUG: (Memory leak) This allocation may need have a corresponding free somewhere... /A */
189    if (!pVia->VidRegBuffer)
190        pVia->VidRegBuffer =
191                xnfcalloc(VIDREG_BUFFER_SIZE, sizeof(CARD32) * 2);
192    pVia->VidRegCursor = 0;
193}
194
195/*
196 * Save a video register and data in VidRegBuffer.
197 */
198static void
199SaveVideoRegister(VIAPtr pVia, CARD32 index, CARD32 data)
200{
201    if (pVia->VidRegCursor >= VIDREG_BUFFER_SIZE) {
202        DBG_DD(ErrorF("SaveVideoRegister: Out of video register space flushing"));
203        FlushVidRegBuffer(pVia);
204        ResetVidRegBuffer(pVia);
205    }
206
207    pVia->VidRegBuffer[pVia->VidRegCursor++] = index;
208    pVia->VidRegBuffer[pVia->VidRegCursor++] = data;
209}
210
211/*
212 * HW Difference Flag (moved here from via_hwdiff.c)
213 *
214 * These are the entries of HWDiff used in our code (currently):
215 *                     CLE266Ax   CLE266Cx   KM400     K8M800    PM800
216 * ThreeHQVBuffer      FALSE      TRUE       TRUE      TRUE      TRUE
217 * HQVFetchByteUnit    FALSE      TRUE       TRUE      TRUE      TRUE
218 * SupportTwoColorKey  FALSE      TRUE       FALSE     FALSE     TRUE
219 * HQVInitPatch        TRUE       FALSE      FALSE     FALSE     FALSE
220 * HQVDisablePatch     FALSE      TRUE       TRUE      TRUE      FALSE
221 *
222 * This is now up to date with CLEXF40040. All unused entries were removed.
223 * The functions depending on this struct are untouched.
224 */
225void
226VIAVidHWDiffInit(ScrnInfoPtr pScrn)
227{
228    VIAPtr pVia = VIAPTR(pScrn);
229    VIAHWDiff *HWDiff = &pVia->HWDiff;
230
231    switch (pVia->Chipset) {
232        case VIA_CLE266:
233            if (CLE266_REV_IS_AX(pVia->ChipRev)) {
234                HWDiff->dwThreeHQVBuffer = VID_HWDIFF_FALSE;
235                HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_FALSE;
236                HWDiff->dwSupportTwoColorKey = VID_HWDIFF_FALSE;
237                HWDiff->dwHQVInitPatch = VID_HWDIFF_TRUE;
238                HWDiff->dwHQVDisablePatch = VID_HWDIFF_FALSE;
239                HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE;
240            } else {
241                HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE;
242                HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE;
243                HWDiff->dwSupportTwoColorKey = VID_HWDIFF_TRUE;
244                HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE;
245                HWDiff->dwHQVDisablePatch = VID_HWDIFF_TRUE;
246                HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE;
247            }
248            HWDiff->dwNewScaleCtl = VID_HWDIFF_FALSE;
249            break;
250        case VIA_KM400:
251            HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE;
252            HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE;
253            HWDiff->dwSupportTwoColorKey = VID_HWDIFF_FALSE;
254            HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE;
255            HWDiff->dwHQVDisablePatch = VID_HWDIFF_TRUE;
256            HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE;
257            HWDiff->dwNewScaleCtl = VID_HWDIFF_FALSE;
258            break;
259        case VIA_K8M800:
260            HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE;
261            HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE;
262            HWDiff->dwSupportTwoColorKey = VID_HWDIFF_FALSE;
263            HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE;
264            HWDiff->dwHQVDisablePatch = VID_HWDIFF_TRUE;
265            HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE;
266            HWDiff->dwNewScaleCtl = VID_HWDIFF_FALSE;
267            break;
268        case VIA_PM800:
269            HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE;
270            HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE;
271            HWDiff->dwSupportTwoColorKey = VID_HWDIFF_TRUE;
272            HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE;
273            HWDiff->dwHQVDisablePatch = VID_HWDIFF_FALSE;
274            HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE;
275            HWDiff->dwNewScaleCtl = VID_HWDIFF_FALSE;
276            HWDiff->HQVCmeRegs = hqv_cme_regs;
277            break;
278        case VIA_P4M800PRO:
279        case VIA_P4M900:
280            HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE;
281            HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE;
282            HWDiff->dwSupportTwoColorKey = VID_HWDIFF_FALSE;
283            HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE;
284            HWDiff->dwHQVDisablePatch = VID_HWDIFF_TRUE;
285            HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE;
286            HWDiff->dwNewScaleCtl = VID_HWDIFF_FALSE;
287            HWDiff->HQVCmeRegs = hqv_cme_regs;
288            break;
289        case VIA_K8M890:
290            HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE;
291            HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE;
292            HWDiff->dwSupportTwoColorKey = VID_HWDIFF_FALSE;
293            HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE;
294            HWDiff->dwHQVDisablePatch = VID_HWDIFF_TRUE;
295            HWDiff->dwNeedV1Prefetch = VID_HWDIFF_TRUE;
296            HWDiff->dwNewScaleCtl = VID_HWDIFF_FALSE;
297            HWDiff->HQVCmeRegs = hqv_cme_regs;
298            break;
299        case VIA_P4M890:
300            HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE;
301            HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE;
302            HWDiff->dwSupportTwoColorKey = VID_HWDIFF_FALSE;
303            HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE;
304            HWDiff->dwHQVDisablePatch = VID_HWDIFF_TRUE;
305            HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE;
306            HWDiff->dwNewScaleCtl = VID_HWDIFF_FALSE;
307            HWDiff->HQVCmeRegs = hqv_cme_regs;
308            break;
309        case VIA_CX700:
310            HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE;
311            HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE;
312            HWDiff->dwSupportTwoColorKey = VID_HWDIFF_TRUE;
313            HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE;
314            HWDiff->dwHQVDisablePatch = VID_HWDIFF_FALSE;
315            HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE;
316            HWDiff->dwNewScaleCtl = VID_HWDIFF_FALSE;
317            HWDiff->HQVCmeRegs = hqv_cme_regs;
318            break;
319        case VIA_VX800:
320            HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE;
321            HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE;
322            HWDiff->dwSupportTwoColorKey = VID_HWDIFF_TRUE;
323            HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE;
324            HWDiff->dwHQVDisablePatch = VID_HWDIFF_FALSE;
325            HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE;
326            HWDiff->dwNewScaleCtl = VID_HWDIFF_TRUE;
327            HWDiff->HQVCmeRegs = hqv_cme_regs;
328            break;
329        case VIA_VX855:
330        case VIA_VX900:
331            HWDiff->dwThreeHQVBuffer = VID_HWDIFF_TRUE;
332            HWDiff->dwHQVFetchByteUnit = VID_HWDIFF_TRUE;
333            HWDiff->dwSupportTwoColorKey = VID_HWDIFF_TRUE;
334            HWDiff->dwHQVInitPatch = VID_HWDIFF_FALSE;
335            HWDiff->dwHQVDisablePatch = VID_HWDIFF_FALSE;
336            HWDiff->dwNeedV1Prefetch = VID_HWDIFF_FALSE;
337            HWDiff->dwNewScaleCtl = VID_HWDIFF_TRUE;
338            HWDiff->HQVCmeRegs = hqv_cme_regs_409;
339            break;
340        default:
341            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
342                       "VIAVidHWDiffInit: Unhandled ChipSet.\n");
343    }
344}
345
346/*
347 * Old via_overlay code.
348 */
349typedef struct _YCBCRREC
350{
351    CARD32 dwY;
352    CARD32 dwCB;
353    CARD32 dwCR;
354} YCBCRREC;
355
356/*
357 * Verify that using V1 bit definitions on V3
358 * is not broken in OverlayGetV1V3Format().
359 */
360
361#if V1_COLORSPACE_SIGN != V3_COLORSPACE_SIGN
362#error "V1_COLORSPACE_SIGN != V3_COLORSPACE_SIGN"
363#endif
364#if V1_YUV422 != V3_YUV422
365#error "V1_YUV422 != V3_YUV422"
366#endif
367#if V1_SWAP_HW_HQV != V3_SWAP_HW_HQV
368#error "V1_SWAP_HW_HQV != V3_SWAP_HW_HQV"
369#endif
370#if V1_RGB15 != V3_RGB15
371#error "V1_RGB15 != V3_RGB15"
372#endif
373#if V1_RGB16 != V3_RGB16
374#error "V1_RGB16 != V3_RGB16"
375#endif
376#if V1_RGB32 != V3_RGB32
377#error "V1_RGB32 != V3_RGB32"
378#endif
379
380static BOOL
381viaOverlayGetV1V3Format(VIAPtr pVia, int vport, /* 1 or 3, as in V1 or V3 */
382                        unsigned long videoFlag, unsigned long *pVidCtl,
383                        unsigned long *pHQVCtl)
384{
385    if (videoFlag & VIDEO_HQV_INUSE) {
386        switch (pVia->swov.SrcFourCC) {
387            case FOURCC_YV12:
388            case FOURCC_I420:
389            case FOURCC_XVMC:
390                *pHQVCtl |= HQV_YUV420;
391                break;
392            case FOURCC_YUY2:
393                *pHQVCtl |= HQV_YUV422;
394                break;
395            case FOURCC_RV32:
396                *pVidCtl |= V1_RGB32;
397                *pHQVCtl |= HQV_RGB32;
398                break;
399            case FOURCC_RV15:
400                *pVidCtl |= V1_RGB15;
401                *pHQVCtl |= HQV_RGB15;
402                break;
403            case FOURCC_RV16:
404                *pVidCtl |= V1_RGB16;
405                *pHQVCtl |= HQV_RGB16;
406                break;
407            default:
408                DBG_DD(ErrorF("viaOverlayGetV1V3Format: "
409                              "Invalid FOURCC format (0x%lx).\n",
410                              pVia->swov.SrcFourCC));
411                return FALSE;
412        }
413        *pVidCtl |= V1_SWAP_HW_HQV;
414        *pHQVCtl |= HQV_SRC_SW | HQV_ENABLE | HQV_SW_FLIP;
415    } else {
416        switch (pVia->swov.SrcFourCC) {
417            case FOURCC_YV12:
418            case FOURCC_I420:
419            case FOURCC_XVMC:
420                if (vport == 1) {
421                    *pVidCtl |= V1_YCbCr420;
422                } else {
423                    DBG_DD(ErrorF("viaOverlayGetV1V3Format: "
424                                  "V3 does not support planar YUV.\n"));
425                    return FALSE;
426                }
427                break;
428            case FOURCC_YUY2:
429                *pVidCtl |= V1_YUV422;
430                break;
431            case FOURCC_RV32:
432            case FOURCC_RV15:
433            case FOURCC_RV16:
434                ErrorF("viaOverlayGetV1V3Format: "
435                       "Can't display RGB video in this configuration.\n");
436                return FALSE;
437            default:
438                DBG_DD(ErrorF("viaOverlayGetV1V3Format: "
439                              "Invalid FOURCC format (0x%lx).\n",
440                              pVia->swov.SrcFourCC));
441                return FALSE;
442        }
443    }
444    *pVidCtl |= V1_COLORSPACE_SIGN;
445    return TRUE;
446}
447
448static unsigned long
449viaOverlayGetSrcStartAddress(VIAPtr pVia,
450                             unsigned long videoFlag,
451                             LPDDUPDATEOVERLAY pUpdate,
452                             unsigned long srcPitch,
453                             unsigned long *pHQVoffset)
454{
455    unsigned long srcWidth =
456            (unsigned long)(pUpdate->SrcRight - pUpdate->SrcLeft);
457    unsigned long dstWidth =
458            (unsigned long)(pUpdate->DstRight - pUpdate->DstLeft);
459    unsigned long srcHeight =
460            (unsigned long)(pUpdate->SrcBottom - pUpdate->SrcTop);
461    unsigned long dstHeight =
462            (unsigned long)(pUpdate->DstBottom - pUpdate->DstTop);
463
464    unsigned long offset = 0;
465    unsigned long srcTopOffset = 0;
466    unsigned long srcLeftOffset = 0;
467
468    int n = 1;
469
470    if ((pUpdate->SrcLeft != 0) || (pUpdate->SrcTop != 0)) {
471        switch (pVia->swov.SrcFourCC) {
472            case FOURCC_RV32:
473                n = 2;
474            case FOURCC_YUY2:
475            case FOURCC_UYVY:
476            case FOURCC_RV15:
477            case FOURCC_RV16:
478
479                if (videoFlag & VIDEO_HQV_INUSE) {
480                    offset = (((pUpdate->SrcTop & ~3) * srcPitch)
481                              + ((pUpdate->SrcLeft << n) & ~31));
482
483                    if (srcHeight > dstHeight)
484                        srcTopOffset = ((pUpdate->SrcTop & ~3)
485                                        * dstHeight / srcHeight) * srcPitch;
486                    else
487                        srcTopOffset = (pUpdate->SrcTop & ~3) * srcPitch;
488
489                    if (srcWidth > dstWidth)
490                        srcLeftOffset = (((pUpdate->SrcLeft << n) & ~31)
491                                         * dstWidth / srcWidth);
492                    else
493                        srcLeftOffset = (pUpdate->SrcLeft << n) & ~31;
494                    *pHQVoffset = srcTopOffset + srcLeftOffset;
495                } else
496                    offset = ((pUpdate->SrcTop * srcPitch)
497                              + ((pUpdate->SrcLeft << n) & ~15));
498                break;
499
500            case FOURCC_YV12:
501            case FOURCC_I420:
502            case FOURCC_XVMC:
503
504                if (videoFlag & VIDEO_HQV_INUSE)
505                    offset = (((pUpdate->SrcTop & ~3) * (srcPitch << 1))
506                              + ((pUpdate->SrcLeft << 1) & ~31));
507                else {
508                    offset = ((((pUpdate->SrcTop & ~3) * srcPitch)
509                               + pUpdate->SrcLeft) & ~31);
510                    if (pUpdate->SrcTop > 0)
511                        pVia->swov.overlayRecordV1.dwUVoffset
512                                = (((((pUpdate->SrcTop & ~3) >> 1) * srcPitch)
513                                    + pUpdate->SrcLeft) & ~31) >> 1;
514                    else
515                        pVia->swov.overlayRecordV1.dwUVoffset = offset >> 1;
516                }
517                break;
518
519            default:
520                DBG_DD(ErrorF("viaGetSrcStartAddress: "
521                              "Invalid FOURCC format (0x%lx).\n",
522                              pVia->swov.SrcFourCC));
523                break;
524        }
525    } else {
526        pVia->swov.overlayRecordV1.dwUVoffset = offset = 0;
527    }
528
529    return offset;
530}
531
532static YCBCRREC
533viaOverlayGetYCbCrStartAddress(unsigned long videoFlag,
534                               unsigned long startAddr, unsigned long offset,
535                               unsigned long UVoffset, unsigned long srcPitch,
536                               unsigned long srcHeight)
537{
538    YCBCRREC YCbCr;
539
540    if (videoFlag & VIDEO_HQV_INUSE) {
541        YCbCr.dwY = startAddr;
542        YCbCr.dwCB = startAddr + srcPitch * srcHeight;
543        YCbCr.dwCR = (startAddr + srcPitch * srcHeight
544                      + srcPitch * (srcHeight >> 2));
545    } else {
546        YCbCr.dwY = startAddr + offset;
547        YCbCr.dwCB = startAddr + srcPitch * srcHeight + UVoffset;
548        YCbCr.dwCR = (startAddr + srcPitch * srcHeight + UVoffset
549                      + srcPitch * (srcHeight >> 2));
550    }
551    return YCbCr;
552}
553
554static unsigned long
555viaOverlayHQVCalcZoomWidth(VIAPtr pVia,
556                           unsigned long videoFlag, unsigned long srcWidth,
557                           unsigned long dstWidth, unsigned long *pZoomCtl,
558                           unsigned long *pMiniCtl,
559                           unsigned long *pHQVfilterCtl,
560                           unsigned long *pHQVminiCtl,
561                           unsigned long *pHQVscaleCtlH,
562                           unsigned long *pHQVzoomflag)
563{
564    unsigned long tmp, sw1, d, falign, mdiv;
565    Bool zoom_ok = TRUE;
566    VIAHWDiff *hwDiff = &pVia->HWDiff;
567
568    CARD32 HQVfilter[5] = { HQV_H_FILTER_DEFAULT, HQV_H_TAP4_121,
569        HQV_H_TAP4_121, HQV_H_TAP8_12221, HQV_H_TAP8_12221
570    };
571    /* CARD HQVmini[5] = { 0, 0xc00, 0xa00, 0x900, 0x8800 }; */
572
573    falign = 0;
574    mdiv = 1;
575
576    if (srcWidth == dstWidth) { /* No zoom */
577        *pHQVfilterCtl |= HQV_H_FILTER_DEFAULT;
578    } else if (srcWidth < dstWidth) { /* Zoom in */
579			*pZoomCtl &= 0x0000FFFF;
580	        tmp = srcWidth * 0x800 / dstWidth;
581	        *pZoomCtl |= ((tmp & 0x7ff) << 16) | V1_X_ZOOM_ENABLE;
582	        *pMiniCtl |= V1_X_INTERPOLY;
583	        zoom_ok = !(tmp > 0x7ff);
584
585	        *pHQVzoomflag = 1;
586	        *pHQVfilterCtl |= HQV_H_FILTER_DEFAULT;
587    } else { /* srcWidth > dstWidth - Zoom out */
588		if (hwDiff->dwNewScaleCtl) {
589            if (srcWidth > (dstWidth << 3)) {
590                /*<1/8*/
591                /*FIXME!*/
592                if (dstWidth <= 32) {
593                    dstWidth = 33;
594                }
595                if (srcWidth > (dstWidth << 5)) {
596                    tmp = 1 * 0x1000 / 31;
597                } else {
598                    tmp = (dstWidth * 0x1000) / srcWidth;
599                }
600
601                *pHQVscaleCtlH = HQV_H_SCALE_DOWN_UNDER_EIGHTH;
602            } else if (srcWidth == (dstWidth << 3)) {
603                /*1/8*/
604                tmp = ((dstWidth - 1) * 0x1000) / srcWidth;
605                *pHQVscaleCtlH = HQV_H_SCALE_DOWN_UNDER_EIGHTH;
606            } else if (srcWidth > (dstWidth << 2)) {
607                /*1/4 -1/8 zoom-out*/
608                tmp = (srcWidth * 0x1000) / dstWidth;
609                *pHQVscaleCtlH = HQV_H_SCALE_DOWN_FOURTH_TO_EIGHTH;
610            } else {
611                /*1-1/4 zoom-out*/
612                /*setting :src/(destination+0.5)*/
613                tmp = (srcWidth * 0x2000) / ((dstWidth << 1) + 1);
614                *pHQVscaleCtlH = HQV_H_SCALE_DOWN_FOURTH_TO_1;
615            }
616
617            /*rounding to nearest interger*/
618            tmp += (((tmp * 0x1000) & 0xfff) > 1) ? 1 : 0;
619            *pHQVscaleCtlH |= (tmp & 0x7fff) | HQV_H_SCALE_ENABLE;
620		} else {
621	        /* HQV rounding patch, instead of:
622	         * //tmp = dstWidth*0x0800 / srcWidth; */
623	        tmp = dstWidth * 0x800 * 0x400 / srcWidth;
624	        tmp = tmp / 0x400 + ((tmp & 0x3ff) ? 1 : 0);
625
626	        *pHQVminiCtl = (tmp & 0x7ff) | HQV_H_MINIFY_ENABLE | HQV_H_MINIFY_DOWN;
627
628	        *pHQVminiCtl |= HQV_HDEBLOCK_FILTER;
629		}
630        /* Scale down the picture by a factor mdiv = (1 << d) = {2, 4, 8 or 16} */
631
632        sw1 = srcWidth;
633        for (d = 1; d < 5; d++) {
634            sw1 >>= 1;
635            if (sw1 <= dstWidth)
636                break;
637        }
638        if (d == 5) { /* Too small. */
639            d = 4;
640            zoom_ok = FALSE;
641        }
642        mdiv = 1 << d; /* <= {2,4,8,16} */
643        falign = ((mdiv << 1) - 1) & 0xf; /* <= {3,7,15,15} */
644        *pMiniCtl |= V1_X_INTERPOLY;
645        *pMiniCtl |= ((d << 1) - 1) << 24; /* <= {1,3,5,7} << 24 */
646
647        *pHQVfilterCtl |= HQVfilter[d];
648
649	/* Scale to arbitrary size, on top of previous scaling by (1 << d). */
650
651	if (sw1 < dstWidth) {
652		/* CLE bug
653		*pZoomCtl = sw1 * 0x0800 / dstWidth;*/
654		*pZoomCtl = (sw1 - 2) * 0x0800 / dstWidth;
655		*pZoomCtl = ((*pZoomCtl & 0x7ff) << 16) | V1_X_ZOOM_ENABLE;
656	}
657
658	if (videoFlag & VIDEO_1_INUSE) {
659		pVia->swov.overlayRecordV1.dwFetchAlignment = falign;
660		pVia->swov.overlayRecordV1.dwminifyH = mdiv;
661	} else {
662		pVia->swov.overlayRecordV3.dwFetchAlignment = falign;
663		pVia->swov.overlayRecordV3.dwminifyH = mdiv;
664	}
665    }
666    return zoom_ok;
667}
668
669static unsigned long
670viaOverlayHQVCalcZoomHeight(VIAPtr pVia,
671                            unsigned long srcHeight, unsigned long dstHeight,
672                            unsigned long *pZoomCtl, unsigned long *pMiniCtl,
673                            unsigned long *pHQVfilterCtl,
674                            unsigned long *pHQVminiCtl,
675                            unsigned long *pHQVscaleCtlV,
676                            unsigned long *pHQVzoomflag)
677{
678    unsigned long tmp, sh1, d;
679    Bool zoom_ok = TRUE;
680    VIAHWDiff *hwDiff = &pVia->HWDiff;
681
682    CARD32 HQVfilter[5] = { HQV_V_TAP4_121, HQV_V_TAP4_121, HQV_V_TAP4_121,
683                            HQV_V_TAP8_12221, HQV_V_TAP8_12221 };
684    /* CARD32 HQVmini[5] = { 0, 0x0c000000, 0x0a000000, 0x09000000, 0x08800000 }; */
685
686    /*if (pVia->pBIOSInfo->scaleY)
687     * {
688     * dstHeight = dstHeight + 1;
689     * } */
690
691    if (srcHeight == dstHeight) { /* No zoom */
692        *pHQVfilterCtl |= HQV_V_TAP4_121;
693    } else if (srcHeight < dstHeight) { /* Zoom in */
694		*pZoomCtl &= 0xFFFF0000;
695	    tmp = srcHeight * 0x400 / dstHeight - 1;
696	    *pZoomCtl |= ((tmp & 0x3ff) | V1_Y_ZOOM_ENABLE);
697	    *pMiniCtl |= (V1_Y_INTERPOLY | V1_YCBCR_INTERPOLY);
698
699	    *pHQVzoomflag = 1;
700	    *pHQVfilterCtl |= HQV_V_TAP4_121;
701    } else { /* srcHeight > dstHeight - Zoom out */
702	if (hwDiff->dwNewScaleCtl) {
703            /*setting :src/(destination+0.5)*/
704            tmp = srcHeight * 0x2000 / ((dstHeight << 1) + 1);
705            tmp += (((tmp * 0x1000) & 0xfff) > 1) ? 1 : 0;
706            if ((tmp & 0x1ffff) == 0) {
707                tmp = 0x1ffff;
708            }
709
710            *pHQVscaleCtlV = (tmp & 0x1ffff) | HQV_V_SCALE_ENABLE| HQV_V_SCALE_DOWN;
711	} else {
712	        /* HQV rounding patch, instead of:
713	         * //tmp = dstHeight*0x0800 / srcHeight; */
714	        tmp = dstHeight * 0x0800 * 0x400 / srcHeight;
715	        tmp = tmp / 0x400 + ((tmp & 0x3ff) ? 1 : 0);
716	        *pHQVminiCtl |= (((tmp & 0x7ff) << 16) | HQV_V_MINIFY_ENABLE
717	                         | HQV_V_MINIFY_DOWN);
718
719	        /* Scale down the picture by a factor (1 << d) = {2, 4, 8 or 16} */
720	        sh1 = srcHeight;
721	        for (d = 1; d < 5; d++) {
722	            sh1 >>= 1;
723	            if (sh1 <= dstHeight)
724	                break;
725	        }
726	        if (d == 5) { /* Too small. */
727	            d = 4;
728	            zoom_ok = FALSE;
729	        }
730
731	        *pMiniCtl |= ((d << 1) - 1) << 16; /* <= {1,3,5,7} << 16 */
732
733	        *pHQVfilterCtl |= HQVfilter[d];
734	        /* *pHQVminiCtl |= HQVmini[d]; */
735	        *pHQVminiCtl |= HQV_VDEBLOCK_FILTER;
736
737	        /* Scale to arbitrary size, on top of previous scaling by (1 << d). */
738
739	        if (sh1 < dstHeight) {
740	            tmp = sh1 * 0x0400 / dstHeight;
741	            *pZoomCtl |= ((tmp & 0x3ff) | V1_Y_ZOOM_ENABLE);
742	            *pMiniCtl |= V1_Y_INTERPOLY | V1_YCBCR_INTERPOLY;
743	        }
744	}
745    }
746    return zoom_ok;
747}
748
749static unsigned long
750viaOverlayGetFetch(VIAPtr pVia, unsigned long videoFlag,
751                   unsigned long srcWidth, unsigned long dstWidth,
752                   unsigned long oriSrcWidth, unsigned long *pHQVsrcFetch)
753{
754    unsigned long fetch = 0;
755    int n = 2; /* 2^n bytes per pixel. */
756
757    switch (pVia->swov.SrcFourCC) {
758        case FOURCC_YV12:
759        case FOURCC_I420:
760        case FOURCC_XVMC:
761            n = 0; /* 2^n = 1 byte per pixel (Y channel in planar YUV) */
762            break;
763        case FOURCC_UYVY:
764        case FOURCC_YUY2:
765        case FOURCC_RV15:
766        case FOURCC_RV16:
767            n = 1; /* 2^n = 2 bytes per pixel (packed YUV) */
768            break;
769        case FOURCC_RV32:
770            n = 2;
771            break;
772        default:
773            DBG_DD(ErrorF("viaOverlayGetFetch: "
774                          "Invalid FOURCC format (0x%lx).\n",
775                          pVia->swov.SrcFourCC));
776            break;
777    }
778
779    if (videoFlag & VIDEO_HQV_INUSE) {
780        *pHQVsrcFetch = oriSrcWidth << n;
781        if (n == 0) {
782            /* Assume n == 0 <=> Planar YUV.
783             * The V1/V3 pixelformat is always packed YUV when we use HQV,
784             * so we switch from 8-bit to 16-bit pixels here.
785             */
786            n = 1;
787        }
788        if (dstWidth >= srcWidth)
789            fetch = (ALIGN_TO(srcWidth << n, 16) >> 4) + 1;
790        else
791            fetch = (ALIGN_TO(dstWidth << n, 16) >> 4) + 1;
792    } else {
793        if (n == 0)
794            fetch = (ALIGN_TO(srcWidth, 32) >> 4);
795        else
796            fetch = (ALIGN_TO(srcWidth << n, 16) >> 4) + 1;
797    }
798
799    /* Fix planar mode problem. */
800    if (fetch < 4)
801        fetch = 4;
802
803    return fetch;
804}
805
806/*
807 * This function uses quadratic mapping to adjust the midpoint of the scaling.
808 */
809static float
810rangeEqualize(float inLow, float inHigh, float outLow, float outHigh,
811              float outMid, float inValue)
812{
813    float inRange = inHigh - inLow,
814          outRange = outHigh - outLow,
815          normIn = ((inValue - inLow) / inRange) * 2. - 1.,
816          delta = outMid - outRange * 0.5 - outLow;
817    return ((inValue - inLow) * outRange / inRange + outLow
818            + (1. - normIn * normIn) * delta);
819}
820
821static unsigned
822vPackFloat(float val, float hiLimit, float loLimit, float mult, int shift,
823           Bool doSign)
824{
825    unsigned packed, mask, sign;
826
827    val = (val > hiLimit) ? hiLimit : val;
828    val = (val < loLimit) ? loLimit : val;
829    sign = (val < 0) ? 1 : 0;
830    val = (sign) ? -val : val;
831    packed = ((unsigned)(val * mult + 1.)) >> 1;
832    mask = (1 << shift) - 1;
833    return (((packed >= mask) ? mask : packed)
834            | ((doSign) ? (sign << shift) : 0));
835
836}
837
838typedef float colorCoeff[5];
839static colorCoeff colorCTable[] = {
840    {1.1875, 1.625, 0.875, 0.375, 2.0},
841    {1.164, 1.596, 0.54, 0.45, 2.2}
842};
843
844/*
845 * This function is a partial rewrite of the overlay.c file of the original VIA
846 * drivers, which was extremely nasty and difficult to follow. Coefficients for
847 * new chipset models should be added in the table above and, if needed,
848 * implemented in the model switch below.
849 */
850static void
851viaCalculateVideoColor(VIAPtr pVia, int hue, int saturation,
852                       int brightness, int contrast, Bool reset,
853                       CARD32 * col1, CARD32 * col2)
854{
855    float fA, fB1, fC1, fD, fB2, fC2, fB3, fC3;
856    float fPI, fContrast, fSaturation, fHue, fBrightness;
857    const float *mCoeff;
858    unsigned long dwA, dwB1, dwC1, dwD, dwB2, dwC2, dwB3, dwC3, dwS;
859    unsigned long dwD_Int, dwD_Dec;
860    int intD;
861    int model;
862
863    fPI = (float)(M_PI / 180.);
864
865    if (reset) {
866        saturation = 10000;
867        brightness = 5000;
868        contrast = 10000;
869    }
870
871    switch (pVia->ChipId) {
872        case PCI_CHIP_VT3205:
873        case PCI_CHIP_VT3204:
874        case PCI_CHIP_VT3259:
875        case PCI_CHIP_VT3314:
876        case PCI_CHIP_VT3336:
877        case PCI_CHIP_VT3364:
878        case PCI_CHIP_VT3324:
879        case PCI_CHIP_VT3327:
880        case PCI_CHIP_VT3353:
881        case PCI_CHIP_VT3409:
882        case PCI_CHIP_VT3410:
883            model = 0;
884            break;
885        case PCI_CHIP_CLE3122:
886            model = (CLE266_REV_IS_CX(pVia->ChipRev) ? 0 : 1);
887            break;
888        default:
889            ErrorF("Unknown Chip ID\n");
890            model = 0;
891    }
892
893    switch (model) {
894        case 0:
895            fBrightness = rangeEqualize(0., 10000., -128., 128., -16.,
896                                        (float)brightness);
897            fContrast = rangeEqualize(0., 20000., 0., 1.6645, 1.0,
898                                      (float)contrast);
899            fSaturation = rangeEqualize(0., 20000, 0., 2., 1.,
900                                        (float)saturation);
901            break;
902        default:
903            fBrightness = rangeEqualize(0., 10000., -128., 128., -12.,
904                                        (float)brightness);
905            fContrast = rangeEqualize(0., 20000., 0., 1.6645, 1.1,
906                                      (float)contrast);
907            fSaturation = rangeEqualize(0., 20000, 0., 2., 1.15,
908                                        (float)saturation);
909            break;
910    }
911    fHue = (float)hue;
912
913    mCoeff = colorCTable[model];
914
915    fA = (float)(mCoeff[0] * fContrast);
916    fB1 = (float)(-mCoeff[1] * fContrast * fSaturation * sin(fHue * fPI));
917    fC1 = (float)(mCoeff[1] * fContrast * fSaturation * cos(fHue * fPI));
918    fD = (float)(mCoeff[0] * (fBrightness));
919    fB2 = (float)((mCoeff[2] * sin(fHue * fPI) - mCoeff[3] * cos(fHue * fPI))
920                  * fContrast * fSaturation);
921    fC2 = (float)(-(mCoeff[2] * cos(fHue * fPI) + mCoeff[3] * sin(fHue * fPI))
922                  * fContrast * fSaturation);
923    fB3 = (float)(mCoeff[4] * fContrast * fSaturation * cos(fHue * fPI));
924    fC3 = (float)(mCoeff[4] * fContrast * fSaturation * sin(fHue * fPI));
925
926    switch (model) {
927        case 0:
928            dwA = vPackFloat(fA, 1.9375, 0., 32., 5, 0);
929            dwB1 = vPackFloat(fB1, 2.125, -2.125, 16., 5, 1);
930            dwC1 = vPackFloat(fC1, 2.125, -2.125, 16., 5, 1);
931
932            if (fD >= 0) {
933                intD = (int)fD;
934                if (intD > 127)
935                    intD = 127;
936                dwD_Int = ((unsigned long)intD) & 0xff;
937                dwD = ((unsigned long)(fD * 16 + 1)) >> 1;
938                dwD_Dec = dwD & 0x7;
939            } else {
940                intD = (int)fD;
941                if (intD < -128)
942                    intD = -128;
943                intD = intD + 256;
944                dwD_Int = ((unsigned long)intD) & 0xff;
945                fD = -fD;
946                dwD = ((unsigned long)(fD * 16 + 1)) >> 1;
947                dwD_Dec = dwD & 0x7;
948            }
949
950            dwB2 = vPackFloat(fB2, 1.875, -1.875, 16, 4, 1);
951            dwC2 = vPackFloat(fC2, 1.875, -1.875, 16, 4, 1);
952            dwB3 = vPackFloat(fB3, 3.875, -3.875, 16, 5, 1);
953            dwC3 = vPackFloat(fC3, 3.875, -3.875, 16, 5, 1);
954            *col1 = (dwA << 24) | (dwB1 << 16) | (dwC1 << 8) | dwD_Int;
955            *col2 = (dwD_Dec << 29 | dwB2 << 24) | (dwC2 << 16) | (dwB3 << 8)
956                    | (dwC3);
957            break;
958
959        default:
960            dwA = vPackFloat(fA, 1.9375, -0., 32, 5, 0);
961            dwB1 = vPackFloat(fB1, 0.75, -0.75, 8., 2, 1);
962            dwC1 = vPackFloat(fC1, 2.875, 1., 16., 5, 0);
963
964            if (fD >= 127)
965                fD = 127;
966
967            if (fD <= -128)
968                fD = -128;
969
970            if (fD >= 0) {
971                dwS = 0;
972            } else {
973                dwS = 1;
974                fD = fD + 128;
975            }
976
977            dwD = ((unsigned long)(fD * 2 + 1)) >> 1;
978            if (dwD >= 0x7f) {
979                dwD = 0x7f | (dwS << 7);
980            } else {
981                dwD = (dwD & 0x7f) | (dwS << 7);
982            }
983
984            dwB2 = vPackFloat(fB2, 0., -0.875, 16., 3, 0);
985            dwC2 = vPackFloat(fC2, 0., -1.875, 16., 4, 0);
986            dwB3 = vPackFloat(fB3, 3.75, 0., 8., 4, 0);
987            dwC3 = vPackFloat(fC3, 1.25, -1.25, 8., 3, 1);
988            *col1 = (dwA << 24) | (dwB1 << 18) | (dwC1 << 9) | dwD;
989            *col2 = (dwB2 << 25) | (dwC2 << 17) | (dwB3 << 10) | (dwC3 << 2);
990            break;
991    }
992}
993
994/*
995 *
996 *
997 */
998void
999viaSetColorSpace(VIAPtr pVia, int hue, int saturation, int brightness,
1000                 int contrast, Bool reset)
1001{
1002    CARD32 col1, col2;
1003
1004    viaCalculateVideoColor(pVia, hue, saturation, brightness, contrast, reset,
1005                           &col1, &col2);
1006    switch (pVia->ChipId) {
1007        case PCI_CHIP_VT3205:
1008        case PCI_CHIP_VT3204:
1009        case PCI_CHIP_VT3314:
1010            VIASETREG(V3_ColorSpaceReg_1, col1);
1011            VIASETREG(V3_ColorSpaceReg_2, col2);
1012            DBG_DD(ErrorF("000002C4 %08lx\n", col1));
1013            DBG_DD(ErrorF("000002C8 %08lx\n", col2));
1014        case PCI_CHIP_VT3259:
1015        case PCI_CHIP_VT3327:
1016        case PCI_CHIP_VT3336:
1017        case PCI_CHIP_VT3324:
1018        case PCI_CHIP_VT3364:
1019        case PCI_CHIP_VT3353:
1020        case PCI_CHIP_VT3409:
1021        case PCI_CHIP_VT3410:
1022        case PCI_CHIP_CLE3122:
1023            VIASETREG(V1_ColorSpaceReg_1, col1);
1024            VIASETREG(V1_ColorSpaceReg_2, col2);
1025            DBG_DD(ErrorF("00000288 %08lx\n", col2));
1026            DBG_DD(ErrorF("00000284 %08lx\n", col1));
1027            break;
1028        default:
1029            DBG_DD(ErrorF("Unknown DeviceID\n"));
1030            break;
1031    }
1032}
1033
1034static unsigned long
1035ViaInitVideoStatusFlag(VIAPtr pVia)
1036{
1037    switch (pVia->ChipId) {
1038        case PCI_CHIP_VT3205:
1039        case PCI_CHIP_VT3204:
1040        case PCI_CHIP_VT3314:
1041            return VIDEO_HQV_INUSE | SW_USE_HQV | VIDEO_3_INUSE;
1042        case PCI_CHIP_VT3259:
1043        case PCI_CHIP_VT3327:
1044        case PCI_CHIP_VT3336:
1045        case PCI_CHIP_VT3324:
1046        case PCI_CHIP_VT3364:
1047        case PCI_CHIP_VT3353:
1048        case PCI_CHIP_VT3409:
1049        case PCI_CHIP_VT3410:
1050            return (VIDEO_HQV_INUSE | SW_USE_HQV | VIDEO_1_INUSE
1051                    | VIDEO_ACTIVE | VIDEO_SHOW);
1052        case PCI_CHIP_CLE3122:
1053            return VIDEO_HQV_INUSE | SW_USE_HQV | VIDEO_1_INUSE;
1054        default:
1055            DBG_DD(ErrorF("Unknown DeviceID\n"));
1056            break;
1057    }
1058    return 0;
1059}
1060
1061static unsigned long
1062ViaSetVidCtl(VIAPtr pVia, unsigned int videoFlag)
1063{
1064    if (videoFlag & VIDEO_1_INUSE) {
1065        /*=* Modify for C1 FIFO *=*/
1066        /* WARNING: not checking Chipset! */
1067        if (CLE266_REV_IS_CX(pVia->ChipRev))
1068            return V1_ENABLE | V1_EXPIRE_NUM_F;
1069        else {
1070            /* Overlay source format for V1 */
1071            if (pVia->swov.gdwUseExtendedFIFO)
1072                return V1_ENABLE | V1_EXPIRE_NUM_A | V1_FIFO_EXTENDED;
1073            else
1074                return V1_ENABLE | V1_EXPIRE_NUM;
1075        }
1076    } else {
1077        switch (pVia->ChipId) {
1078            case PCI_CHIP_VT3205:
1079            case PCI_CHIP_VT3204:
1080            case PCI_CHIP_VT3259:
1081            case PCI_CHIP_VT3314:
1082                return V3_ENABLE | V3_EXPIRE_NUM_3205;
1083            case PCI_CHIP_VT3327:
1084            case PCI_CHIP_VT3336:
1085            case PCI_CHIP_VT3324:
1086            case PCI_CHIP_VT3364:
1087            case PCI_CHIP_VT3353:
1088                return V3_ENABLE | VIDEO_EXPIRE_NUM_VT3336;
1089            case PCI_CHIP_VT3409:
1090            case PCI_CHIP_VT3410:
1091                return V3_ENABLE | VIDEO_EXPIRE_NUM_VT3409;
1092            case PCI_CHIP_CLE3122:
1093                if (CLE266_REV_IS_CX(pVia->ChipRev))
1094                    return V3_ENABLE | V3_EXPIRE_NUM_F;
1095                else
1096                    return V3_ENABLE | V3_EXPIRE_NUM;
1097            default:
1098                DBG_DD(ErrorF("Unknown DeviceID\n"));
1099                break;
1100        }
1101    }
1102    return 0;
1103}
1104
1105/*
1106 * Fill the buffer with 0x8000 (YUV2 black).
1107 */
1108static void
1109ViaYUVFillBlack(VIAPtr pVia, void *buf, int num)
1110{
1111    CARD16 *ptr = (CARD16 *) buf;
1112
1113    while (num-- > 0)
1114#if X_BYTE_ORDER == X_LITTLE_ENDIAN
1115        *ptr++ = 0x0080;
1116#else
1117        *ptr++ = 0x8000;
1118#endif
1119}
1120
1121/*
1122 * Add an HQV surface to an existing FOURCC surface.
1123 * numbuf: number of buffers, 1, 2 or 3
1124 * fourcc: FOURCC code of the current (already existing) surface
1125 */
1126static long
1127AddHQVSurface(ScrnInfoPtr pScrn, unsigned int numbuf, CARD32 fourcc)
1128{
1129    unsigned int i, width, height, pitch, fbsize, addr;
1130    BOOL isplanar;
1131    void *buf;
1132
1133    VIAPtr pVia = VIAPTR(pScrn);
1134    CARD32 AddrReg[3] = { HQV_DST_STARTADDR0, HQV_DST_STARTADDR1,
1135            HQV_DST_STARTADDR2 };
1136    unsigned long proReg = 0;
1137
1138    if (pVia->ChipId == PCI_CHIP_VT3259 &&
1139        !(pVia->swov.gdwVideoFlagSW & VIDEO_1_INUSE))
1140        proReg = PRO_HQV1_OFFSET;
1141
1142    isplanar = ((fourcc == FOURCC_YV12) || (fourcc == FOURCC_I420) ||
1143                (fourcc == FOURCC_XVMC));
1144
1145    width = pVia->swov.SWDevice.gdwSWSrcWidth;
1146    height = pVia->swov.SWDevice.gdwSWSrcHeight;
1147    pitch = pVia->swov.SWDevice.dwPitch;
1148    fbsize = pitch * height * (isplanar ? 2 : 1);
1149
1150    pVia->swov.HQVMem = drm_bo_alloc(pScrn, fbsize * numbuf, 1, TTM_PL_FLAG_VRAM);
1151    if (!pVia->swov.HQVMem)
1152        return BadAlloc;
1153    addr = pVia->swov.HQVMem->offset;
1154    buf = drm_bo_map(pScrn, pVia->swov.HQVMem);
1155
1156    ViaYUVFillBlack(pVia, buf, fbsize);
1157
1158    for (i = 0; i < numbuf; i++) {
1159        pVia->swov.overlayRecordV1.dwHQVAddr[i] = addr;
1160        VIASETREG(AddrReg[i] + proReg, addr);
1161        addr += fbsize;
1162    }
1163    drm_bo_unmap(pScrn, pVia->swov.HQVMem);
1164    return Success;
1165}
1166
1167/*
1168 * Create a FOURCC surface.
1169 * doalloc: set true to actually allocate memory for the framebuffers
1170 */
1171static long
1172CreateSurface(ScrnInfoPtr pScrn, CARD32 FourCC, CARD16 Width,
1173              CARD16 Height, BOOL doalloc)
1174{
1175    VIAPtr pVia = VIAPTR(pScrn);
1176    unsigned long pitch, fbsize, addr;
1177    BOOL isplanar;
1178    void *buf;
1179
1180    pVia->swov.SrcFourCC = FourCC;
1181    pVia->swov.gdwVideoFlagSW = ViaInitVideoStatusFlag(pVia);
1182
1183    isplanar = FALSE;
1184    switch (FourCC) {
1185        case FOURCC_YV12:
1186        case FOURCC_I420:
1187        case FOURCC_XVMC:
1188            isplanar = TRUE;
1189            pitch = ALIGN_TO(Width, 32);
1190            fbsize = pitch * Height * 1.5;
1191            break;
1192        case FOURCC_RV32:
1193            pitch = ALIGN_TO(Width << 2, 32);
1194            fbsize = pitch * Height;
1195            break;
1196        default:
1197            pitch = ALIGN_TO(Width << 1, 32);
1198            fbsize = pitch * Height;
1199            break;
1200    }
1201
1202    if (doalloc) {
1203        pVia->swov.SWfbMem = drm_bo_alloc(pScrn, fbsize * 2, 1, TTM_PL_FLAG_VRAM);
1204        if (!pVia->swov.SWfbMem)
1205            return BadAlloc;
1206        addr = pVia->swov.SWfbMem->offset;
1207        buf = drm_bo_map(pScrn, pVia->swov.SWfbMem);
1208
1209        ViaYUVFillBlack(pVia, buf, fbsize);
1210
1211        pVia->swov.SWDevice.dwSWPhysicalAddr[0] = addr;
1212        pVia->swov.SWDevice.dwSWPhysicalAddr[1] = addr + fbsize;
1213        pVia->swov.SWDevice.lpSWOverlaySurface[0] = buf;
1214        pVia->swov.SWDevice.lpSWOverlaySurface[1] = buf + fbsize;
1215
1216        if (isplanar) {
1217            pVia->swov.SWDevice.dwSWCrPhysicalAddr[0] =
1218                    pVia->swov.SWDevice.dwSWPhysicalAddr[0] +
1219                    (pitch * Height);
1220            pVia->swov.SWDevice.dwSWCrPhysicalAddr[1] =
1221                    pVia->swov.SWDevice.dwSWPhysicalAddr[1] +
1222                    (pitch * Height);
1223            pVia->swov.SWDevice.dwSWCbPhysicalAddr[0] =
1224                    pVia->swov.SWDevice.dwSWCrPhysicalAddr[0] +
1225                    ((pitch >> 1) * (Height >> 1));
1226            pVia->swov.SWDevice.dwSWCbPhysicalAddr[1] =
1227                    pVia->swov.SWDevice.dwSWCrPhysicalAddr[1] +
1228                    ((pitch >> 1) * (Height >> 1));
1229        }
1230    }
1231
1232    pVia->swov.SWDevice.gdwSWSrcWidth = Width;
1233    pVia->swov.SWDevice.gdwSWSrcHeight = Height;
1234    pVia->swov.SWDevice.dwPitch = pitch;
1235
1236    pVia->swov.overlayRecordV1.dwV1OriWidth = Width;
1237    pVia->swov.overlayRecordV1.dwV1OriHeight = Height;
1238    pVia->swov.overlayRecordV1.dwV1OriPitch = pitch;
1239
1240    return Success;
1241}
1242
1243/*
1244 *
1245 */
1246int
1247ViaSwovSurfaceCreate(ScrnInfoPtr pScrn, viaPortPrivPtr pPriv,
1248                     CARD32 FourCC, CARD16 Width, CARD16 Height)
1249{
1250    VIAPtr pVia = VIAPTR(pScrn);
1251    unsigned long retCode = Success;
1252    int numbuf = pVia->HWDiff.dwThreeHQVBuffer ? 3 : 2;
1253
1254    DBG_DD(ErrorF("ViaSwovSurfaceCreate: FourCC =0x%08lx\n", FourCC));
1255
1256    if ((pVia->VideoStatus & VIDEO_SWOV_SURFACE_CREATED)
1257        && (FourCC == pPriv->FourCC))
1258        return Success;
1259
1260    pPriv->FourCC = FourCC;
1261    switch (FourCC) {
1262        case FOURCC_YUY2:
1263        case FOURCC_RV15:
1264        case FOURCC_RV16:
1265        case FOURCC_RV32:
1266            retCode = CreateSurface(pScrn, FourCC, Width, Height, TRUE);
1267            if (retCode != Success)
1268                break;
1269            if ((pVia->swov.gdwVideoFlagSW & SW_USE_HQV))
1270                retCode = AddHQVSurface(pScrn, numbuf, FourCC);
1271            break;
1272
1273        case FOURCC_HQVSW:
1274            retCode = AddHQVSurface(pScrn, numbuf, FOURCC_YUY2);
1275            break;
1276
1277        case FOURCC_YV12:
1278        case FOURCC_I420:
1279            retCode = CreateSurface(pScrn, FourCC, Width, Height, TRUE);
1280            if (retCode == Success)
1281                retCode = AddHQVSurface(pScrn, numbuf, FourCC);
1282            break;
1283
1284        case FOURCC_XVMC:
1285            retCode = CreateSurface(pScrn, FourCC, Width, Height, FALSE);
1286            if (retCode == Success)
1287                retCode = AddHQVSurface(pScrn, numbuf, FOURCC_XVMC);
1288            break;
1289
1290        default:
1291            break;
1292    }
1293
1294    if (retCode == Success) {
1295        DBG_DD(ErrorF(" lpSWOverlaySurface[0]: %p\n",
1296                      pVia->swov.SWDevice.lpSWOverlaySurface[0]));
1297        DBG_DD(ErrorF(" lpSWOverlaySurface[1]: %p\n",
1298                      pVia->swov.SWDevice.lpSWOverlaySurface[1]));
1299
1300        pVia->VideoStatus |= VIDEO_SWOV_SURFACE_CREATED | VIDEO_SWOV_ON;
1301    }
1302    return retCode;
1303}
1304
1305/*
1306 *  Destroy Surface
1307 */
1308void
1309ViaSwovSurfaceDestroy(ScrnInfoPtr pScrn, viaPortPrivPtr pPriv)
1310{
1311    VIAPtr pVia = VIAPTR(pScrn);
1312
1313    DBG_DD(ErrorF("ViaSwovSurfaceDestroy: FourCC =0x%08lx\n", pPriv->FourCC));
1314
1315    if (pVia->VideoStatus & VIDEO_SWOV_SURFACE_CREATED) {
1316        DBG_DD(ErrorF("ViaSwovSurfaceDestroy: VideoStatus =0x%08lx\n",
1317                      pVia->VideoStatus));
1318
1319        switch (pPriv->FourCC) {
1320            case FOURCC_YUY2:
1321            case FOURCC_RV16:
1322            case FOURCC_RV32:
1323            case FOURCC_RV15:
1324                pVia->swov.SrcFourCC = 0;
1325
1326                drm_bo_unmap(pScrn, pVia->swov.SWfbMem);
1327                drm_bo_free(pScrn, pVia->swov.SWfbMem);
1328                if ((pVia->swov.gdwVideoFlagSW & SW_USE_HQV)) {
1329                    drm_bo_unmap(pScrn, pVia->swov.HQVMem);
1330                    drm_bo_free(pScrn, pVia->swov.HQVMem);
1331                }
1332                pVia->swov.gdwVideoFlagSW = 0;
1333                break;
1334
1335            case FOURCC_HQVSW:
1336                drm_bo_free(pScrn, pVia->swov.HQVMem);
1337                pVia->swov.gdwVideoFlagSW = 0;
1338                break;
1339
1340            case FOURCC_YV12:
1341            case FOURCC_I420:
1342                drm_bo_unmap(pScrn, pVia->swov.SWfbMem);
1343                drm_bo_free(pScrn, pVia->swov.SWfbMem);
1344            case FOURCC_XVMC:
1345                pVia->swov.SrcFourCC = 0;
1346
1347                drm_bo_free(pScrn, pVia->swov.HQVMem);
1348                pVia->swov.gdwVideoFlagSW = 0;
1349                break;
1350        }
1351
1352        pPriv->FourCC = 0;
1353        pVia->VideoStatus &= ~VIDEO_SWOV_SURFACE_CREATED;
1354
1355    } else
1356        DBG_DD(ErrorF("ViaSwovSurfaceDestroy: No SW Surface Destroyed, "
1357                      "VideoStatus =0x%08lx\n", pVia->VideoStatus));
1358}
1359
1360static void
1361SetFIFO_V1(VIAPtr pVia, CARD8 depth, CARD8 prethreshold, CARD8 threshold)
1362{
1363    SaveVideoRegister(pVia, V_FIFO_CONTROL,
1364                      ((depth - 1) & 0x7f) |
1365                      ((prethreshold & 0x7f) << 24) |
1366                      ((threshold & 0x7f) << 8));
1367}
1368
1369static void
1370SetFIFO_V3(VIAPtr pVia, CARD8 depth, CARD8 prethreshold, CARD8 threshold)
1371{
1372    switch (pVia->ChipId) {
1373        case PCI_CHIP_VT3314:
1374        case PCI_CHIP_VT3324:
1375        case PCI_CHIP_VT3327:
1376        case PCI_CHIP_VT3353:
1377        case PCI_CHIP_VT3409:
1378        case PCI_CHIP_VT3410:
1379            SaveVideoRegister(pVia, ALPHA_V3_FIFO_CONTROL,
1380                              (VIAGETREG(ALPHA_V3_FIFO_CONTROL) & ALPHA_FIFO_MASK)
1381                               | ((depth - 1) & 0xff) | ((threshold & 0xff) << 8));
1382            SaveVideoRegister(pVia, ALPHA_V3_PREFIFO_CONTROL,
1383                              (VIAGETREG(ALPHA_V3_PREFIFO_CONTROL)
1384                              & ~V3_FIFO_MASK_3314) | (prethreshold & 0xff));
1385            break;
1386        default :
1387            SaveVideoRegister(pVia, ALPHA_V3_FIFO_CONTROL,
1388                              (VIAGETREG(ALPHA_V3_FIFO_CONTROL) & ALPHA_FIFO_MASK)
1389                              | ((depth - 1) & 0xff) | ((threshold & 0xff) << 8));
1390            SaveVideoRegister(pVia, ALPHA_V3_PREFIFO_CONTROL,
1391                              (VIAGETREG(ALPHA_V3_PREFIFO_CONTROL) & ~V3_FIFO_MASK)
1392                              | (prethreshold & 0x7f));
1393            break;
1394    }
1395}
1396
1397static void
1398SetFIFO_64or32(VIAPtr pVia)
1399{
1400    /*=* Modify for C1 FIFO *=*/
1401    /* WARNING: not checking Chipset! */
1402    if (CLE266_REV_IS_CX(pVia->ChipRev))
1403        SetFIFO_V1(pVia, 64, 56, 56);
1404    else
1405        SetFIFO_V1(pVia, 32, 29, 16);
1406}
1407
1408static void
1409SetFIFO_64or16(VIAPtr pVia)
1410{
1411    /*=* Modify for C1 FIFO *=*/
1412    /* WARNING: not checking Chipset! */
1413    if (CLE266_REV_IS_CX(pVia->ChipRev))
1414        SetFIFO_V1(pVia, 64, 56, 56);
1415    else
1416        SetFIFO_V1(pVia, 16, 12, 8);
1417}
1418
1419static void
1420SetFIFO_64or48or32(VIAPtr pVia)
1421{
1422    /*=* Modify for C1 FIFO *=*/
1423    /* WARNING: not checking Chipset! */
1424    if (CLE266_REV_IS_CX(pVia->ChipRev))
1425        SetFIFO_V1(pVia, 64, 56, 56);
1426    else {
1427        if (pVia->swov.gdwUseExtendedFIFO)
1428            SetFIFO_V1(pVia, 48, 40, 40);
1429        else
1430            SetFIFO_V1(pVia, 32, 29, 16);
1431    }
1432}
1433
1434static void
1435SetFIFO_V3_64or32or32(VIAPtr pVia)
1436{
1437    switch (pVia->ChipId) {
1438        case PCI_CHIP_VT3327:
1439        case PCI_CHIP_VT3336:
1440        case PCI_CHIP_VT3324:
1441        case PCI_CHIP_VT3364:
1442        case PCI_CHIP_VT3353:
1443        case PCI_CHIP_VT3409:
1444        case PCI_CHIP_VT3410:
1445            SetFIFO_V3(pVia, 225, 200, 250);
1446            break;
1447        case PCI_CHIP_VT3204:
1448            SetFIFO_V3(pVia, 100, 89, 89);
1449            break;
1450        case PCI_CHIP_VT3314:
1451            SetFIFO_V3(pVia, 64, 61, 61);
1452            break;
1453        case PCI_CHIP_VT3205:
1454        case PCI_CHIP_VT3259:
1455            SetFIFO_V3(pVia, 32, 29, 29);
1456            break;
1457        case PCI_CHIP_CLE3122:
1458            if (CLE266_REV_IS_CX(pVia->ChipRev))
1459                SetFIFO_V3(pVia, 64, 56, 56);
1460            else
1461                SetFIFO_V3(pVia, 32, 16, 16);
1462            break;
1463        default:
1464            break;
1465    }
1466}
1467
1468static void
1469SetFIFO_V3_64or32or16(VIAPtr pVia)
1470{
1471    switch (pVia->ChipId) {
1472        case PCI_CHIP_VT3327:
1473        case PCI_CHIP_VT3336:
1474        case PCI_CHIP_VT3324:
1475        case PCI_CHIP_VT3364:
1476        case PCI_CHIP_VT3353:
1477        case PCI_CHIP_VT3409:
1478        case PCI_CHIP_VT3410:
1479            SetFIFO_V3(pVia, 225, 200, 250);
1480            break;
1481        case PCI_CHIP_VT3204:
1482            SetFIFO_V3(pVia, 100, 89, 89);
1483            break;
1484        case PCI_CHIP_VT3314:
1485            SetFIFO_V3(pVia, 64, 61, 61);
1486            break;
1487        case PCI_CHIP_VT3205:
1488        case PCI_CHIP_VT3259:
1489            SetFIFO_V3(pVia, 32, 29, 29);
1490            break;
1491
1492        case PCI_CHIP_CLE3122:
1493            if (CLE266_REV_IS_CX(pVia->ChipRev))
1494                SetFIFO_V3(pVia, 64, 56, 56);
1495            else
1496                SetFIFO_V3(pVia, 16, 16, 8);
1497            break;
1498
1499        default:
1500            break;
1501    }
1502}
1503
1504static void
1505SetupFIFOs(VIAPtr pVia, unsigned long videoFlag,
1506           unsigned long miniCtl, unsigned long srcWidth)
1507{
1508    if (miniCtl & V1_Y_INTERPOLY) {
1509        if (pVia->swov.SrcFourCC == FOURCC_YV12
1510            || pVia->swov.SrcFourCC == FOURCC_I420
1511            || pVia->swov.SrcFourCC == FOURCC_XVMC) {
1512            if (videoFlag & VIDEO_HQV_INUSE) {
1513                if (videoFlag & VIDEO_1_INUSE)
1514                    SetFIFO_64or32(pVia);
1515                else
1516                    SetFIFO_V3_64or32or16(pVia);
1517            } else {
1518                /* Minified video will be skewed without this workaround. */
1519                if (srcWidth <= 80) { /* Fetch count <= 5 */
1520                    if (videoFlag & VIDEO_1_INUSE)
1521                        SetFIFO_V1(pVia, 16, 0, 0);
1522                    else
1523                        SetFIFO_V3(pVia, 16, 16, 0);
1524                } else {
1525                    if (videoFlag & VIDEO_1_INUSE)
1526                        SetFIFO_64or16(pVia);
1527                    else
1528                        SetFIFO_V3_64or32or16(pVia);
1529                }
1530            }
1531        } else {
1532            if (videoFlag & VIDEO_1_INUSE)
1533                SetFIFO_64or48or32(pVia);
1534            else {
1535                /* Fix V3 bug. */
1536                if (srcWidth <= 8)
1537                    SetFIFO_V3(pVia, 1, 0, 0);
1538                else
1539                    SetFIFO_V3_64or32or32(pVia);
1540            }
1541        }
1542    } else {
1543        if (pVia->swov.SrcFourCC == FOURCC_YV12
1544            || pVia->swov.SrcFourCC == FOURCC_I420
1545            || pVia->swov.SrcFourCC == FOURCC_XVMC) {
1546            if (videoFlag & VIDEO_HQV_INUSE) {
1547                if (videoFlag & VIDEO_1_INUSE)
1548                    SetFIFO_64or32(pVia);
1549                else
1550                    SetFIFO_V3_64or32or16(pVia);
1551            } else {
1552                /* Minified video will be skewed without this workaround. */
1553                if (srcWidth <= 80) { /* Fetch count <= 5 */
1554                    if (videoFlag & VIDEO_1_INUSE)
1555                        SetFIFO_V1(pVia, 16, 0, 0);
1556                    else
1557                        SetFIFO_V3(pVia, 16, 16, 0);
1558                } else {
1559                    if (videoFlag & VIDEO_1_INUSE)
1560                        SetFIFO_64or16(pVia);
1561                    else
1562                        SetFIFO_V3_64or32or16(pVia);
1563                }
1564            }
1565        } else {
1566            if (videoFlag & VIDEO_1_INUSE)
1567                SetFIFO_64or48or32(pVia);
1568            else {
1569                /* Fix V3 bug. */
1570                if (srcWidth <= 8)
1571                    SetFIFO_V3(pVia, 1, 0, 0);
1572                else
1573                    SetFIFO_V3_64or32or32(pVia);
1574            }
1575        }
1576    }
1577}
1578
1579static CARD32
1580SetColorKey(VIAPtr pVia, unsigned long videoFlag,
1581            CARD32 keyLow, CARD32 keyHigh, CARD32 compose)
1582{
1583    keyLow &= 0x00FFFFFF;
1584    if (pVia->VideoEngine == VIDEO_ENGINE_CME)
1585        keyLow |= 0x40000000;
1586
1587    if (videoFlag & VIDEO_1_INUSE) {
1588        SaveVideoRegister(pVia, V_COLOR_KEY, keyLow);
1589        SaveVideoRegister(pVia, SND_COLOR_KEY, keyLow);
1590    } else {
1591        if (pVia->HWDiff.dwSupportTwoColorKey)    /*CLE_C0 */
1592            SaveVideoRegister(pVia, V3_COLOR_KEY, keyLow);
1593    }
1594
1595    /*CLE_C0 */
1596    compose = ((compose & ~0x0f) | SELECT_VIDEO_IF_COLOR_KEY |
1597               SELECT_VIDEO3_IF_COLOR_KEY);
1598
1599    return compose;
1600}
1601
1602static CARD32
1603SetChromaKey(VIAPtr pVia, unsigned long videoFlag,
1604             CARD32 chromaLow, CARD32 chromaHigh,
1605             CARD32 miniCtl, CARD32 compose)
1606{
1607    chromaLow &= CHROMA_KEY_LOW;
1608    chromaHigh &= CHROMA_KEY_HIGH;
1609
1610    chromaLow |= (VIAGETREG(V_CHROMAKEY_LOW) & ~CHROMA_KEY_LOW);
1611    chromaHigh |= (VIAGETREG(V_CHROMAKEY_HIGH) & ~CHROMA_KEY_HIGH);
1612
1613    if (pVia->VideoEngine == VIDEO_ENGINE_CME)
1614        chromaLow |= 0x40000000;
1615
1616    SaveVideoRegister(pVia, V_CHROMAKEY_HIGH, chromaHigh);
1617    if (videoFlag & VIDEO_1_INUSE) {
1618        SaveVideoRegister(pVia, V_CHROMAKEY_LOW, chromaLow & ~V_CHROMAKEY_V3);
1619        /* Temporarily solve the HW interpolation error when using Chroma key */
1620        SaveVideoRegister(pVia, V1_MINI_CONTROL, miniCtl & 0xFFFFFFF8);
1621    } else {
1622        SaveVideoRegister(pVia, V_CHROMAKEY_LOW, chromaLow | V_CHROMAKEY_V3);
1623        SaveVideoRegister(pVia, V3_MINI_CONTROL, miniCtl & 0xFFFFFFF8);
1624    }
1625
1626    /* Modified by Scottie[2001.12.5] for select video if (Color key & Chroma key) */
1627    if (compose == SELECT_VIDEO_IF_COLOR_KEY)
1628        compose = SELECT_VIDEO_IF_COLOR_KEY | SELECT_VIDEO_IF_CHROMA_KEY;
1629    else
1630        compose = (compose & ~0x0f) | SELECT_VIDEO_IF_CHROMA_KEY;
1631
1632    return compose;
1633}
1634
1635static void
1636SetVideoStart(VIAPtr pVia, unsigned long videoFlag,
1637              unsigned int numbufs, CARD32 a1, CARD32 a2, CARD32 a3)
1638{
1639    CARD32 V1Addr[3] = { V1_STARTADDR_0, V1_STARTADDR_1, V1_STARTADDR_2 };
1640    CARD32 V3Addr[3] = { V3_STARTADDR_0, V3_STARTADDR_1, V3_STARTADDR_2 };
1641    CARD32 *VideoAddr = (videoFlag & VIDEO_1_INUSE) ? V1Addr : V3Addr;
1642
1643    SaveVideoRegister(pVia, VideoAddr[0], a1);
1644    if (numbufs > 1)
1645        SaveVideoRegister(pVia, VideoAddr[1], a2);
1646    if (numbufs > 2)
1647        SaveVideoRegister(pVia, VideoAddr[2], a3);
1648}
1649
1650static void
1651SetHQVFetch(VIAPtr pVia, CARD32 srcFetch, unsigned long srcHeight)
1652{
1653    unsigned long proReg = 0;
1654
1655    if (pVia->ChipId == PCI_CHIP_VT3259
1656        && !(pVia->swov.gdwVideoFlagSW & VIDEO_1_INUSE))
1657        proReg = PRO_HQV1_OFFSET;
1658
1659    if (!pVia->HWDiff.dwHQVFetchByteUnit) {    /* CLE_C0 */
1660        srcFetch >>= 3;  /* fetch unit is 8 bytes */
1661    }
1662
1663    if ((pVia->ChipId != PCI_CHIP_VT3409) && (pVia->ChipId != PCI_CHIP_VT3410))
1664        SaveVideoRegister(pVia, HQV_SRC_FETCH_LINE + proReg,
1665                          ((srcFetch - 1) << 16) | (srcHeight - 1));
1666}
1667
1668static void
1669SetFetch(VIAPtr pVia, unsigned long videoFlag, CARD32 fetch)
1670{
1671    fetch <<= 20;
1672    if (videoFlag & VIDEO_1_INUSE) {
1673        SaveVideoRegister(pVia, V12_QWORD_PER_LINE, fetch);
1674    } else {
1675        fetch |= VIAGETREG(V3_ALPHA_QWORD_PER_LINE) & ~V3_FETCH_COUNT;
1676        SaveVideoRegister(pVia, V3_ALPHA_QWORD_PER_LINE, fetch);
1677    }
1678}
1679
1680static void
1681SetDisplayCount(VIAPtr pVia, unsigned long videoFlag,
1682                unsigned long srcWidth, unsigned long srcHeight)
1683{
1684    unsigned long DisplayCount;
1685
1686    /* Removed VIA's large pixelformat switch/case.
1687     * All formats (YV12, UYVY, YUY2, VIA, RGB16 and RGB32)
1688     * seem to use the same count. /A
1689     */
1690
1691    if (videoFlag & VIDEO_HQV_INUSE)
1692        DisplayCount = srcWidth - 1;
1693    else
1694        DisplayCount = srcWidth - pVia->swov.overlayRecordV1.dwminifyH;
1695
1696    if (videoFlag & VIDEO_1_INUSE)
1697        SaveVideoRegister(pVia, V1_SOURCE_HEIGHT,
1698                          (srcHeight << 16) | DisplayCount);
1699    else
1700        SaveVideoRegister(pVia, V3_SOURCE_WIDTH, DisplayCount);
1701}
1702
1703static void
1704SetMiniAndZoom(VIAPtr pVia, unsigned long videoFlag,
1705               CARD32 miniCtl, CARD32 zoomCtl)
1706{
1707    if (videoFlag & VIDEO_1_INUSE) {
1708        SaveVideoRegister(pVia, V1_MINI_CONTROL, miniCtl);
1709        SaveVideoRegister(pVia, V1_ZOOM_CONTROL, zoomCtl);
1710    } else {
1711        SaveVideoRegister(pVia, V3_MINI_CONTROL, miniCtl);
1712        SaveVideoRegister(pVia, V3_ZOOM_CONTROL, zoomCtl);
1713    }
1714}
1715
1716static void
1717SetVideoControl(VIAPtr pVia, unsigned long videoFlag, CARD32 vidCtl)
1718{
1719    if (videoFlag & VIDEO_1_INUSE)
1720        SaveVideoRegister(pVia, V1_CONTROL, vidCtl);
1721    else
1722        SaveVideoRegister(pVia, V3_CONTROL, vidCtl);
1723}
1724
1725static void
1726FireVideoCommand(VIAPtr pVia, unsigned long videoFlag, CARD32 compose)
1727{
1728    if (videoFlag & VIDEO_1_INUSE)
1729        SaveVideoRegister(pVia, V_COMPOSE_MODE, compose | V1_COMMAND_FIRE);
1730    else
1731        SaveVideoRegister(pVia, V_COMPOSE_MODE, compose | V3_COMMAND_FIRE);
1732}
1733
1734static void
1735SetVideoWindow(ScrnInfoPtr pScrn, unsigned long videoFlag,
1736               LPDDUPDATEOVERLAY pUpdate)
1737{
1738    VIAPtr pVia = VIAPTR(pScrn);
1739    CARD32 left = pUpdate->DstLeft;
1740    CARD32 top = pUpdate->DstTop;
1741    CARD32 right = pUpdate->DstRight - 1;
1742    CARD32 bottom = pUpdate->DstBottom - 1;
1743
1744    DBG_DD(ErrorF("SetVideoWindow: X (%ld,%ld) Y (%ld,%ld)\n",
1745                  left, right, top, bottom));
1746
1747    /* Modify for HW DVI limitation.
1748     * When we enable both the CRT and DVI, then change resolution.
1749     * If the resolution is smaller than the panel's physical size,
1750     * the video display in Y direction will be cut.
1751     * So, we need to adjust the Y top and bottom position.
1752     *
1753    if (videoFlag & VIDEO_1_INUSE) {
1754        if (pBIOSInfo->SetDVI && pBIOSInfo->scaleY) {
1755            top = (pUpdate->DstTop * pBIOSInfo->Panel->NativeMode->Height
1756                   / pScrn->currentMode->VDisplay);
1757            bottom = (pUpdate->DstBottom * pBIOSInfo->Panel->NativeMode->Height
1758                      / pScrn->currentMode->VDisplay);
1759        }
1760    }*/
1761
1762    if (top > 2047)
1763        top = 2047;
1764
1765    if (bottom > 2047)
1766        bottom = 2047;
1767
1768    if (left > 2047)
1769        left = 2047;
1770
1771    if (right > 2047)
1772        right = 2047;
1773
1774    if (videoFlag & VIDEO_1_INUSE) {
1775        SaveVideoRegister(pVia, V1_WIN_END_Y, (right << 16) | bottom);
1776        SaveVideoRegister(pVia, V1_WIN_START_Y, (left << 16) | top);
1777    } else {
1778        SaveVideoRegister(pVia, V3_WIN_END_Y, (right << 16) | bottom);
1779        SaveVideoRegister(pVia, V3_WIN_START_Y, (left << 16) | top);
1780    }
1781}
1782
1783/*
1784 * Upd_Video()
1785 */
1786static Bool
1787Upd_Video(xf86CrtcPtr crtc, unsigned long videoFlag,
1788          unsigned long startAddr, LPDDUPDATEOVERLAY pUpdate,
1789          unsigned long srcPitch,
1790          unsigned long oriSrcWidth, unsigned long oriSrcHeight,
1791          unsigned long deinterlaceMode,
1792          unsigned long haveColorKey, unsigned long haveChromaKey,
1793          unsigned long colorKeyLow, unsigned long colorKeyHigh,
1794          unsigned long chromaKeyLow, unsigned long chromaKeyHigh)
1795{
1796    drmmode_crtc_private_ptr iga = crtc->driver_private;
1797    ScrnInfoPtr pScrn = crtc->scrn;
1798    VIAPtr pVia = VIAPTR(pScrn);
1799    vgaHWPtr hwp = VGAHWPTR(pScrn);
1800    VIAHWDiff *hwDiff = &pVia->HWDiff;
1801    unsigned long vidCtl = 0, compose;
1802    unsigned long srcWidth, srcHeight, dstWidth, dstHeight;
1803    unsigned long zoomCtl = 0, miniCtl = 0;
1804    unsigned long hqvCtl = 0;
1805    unsigned long hqvFilterCtl = 0, hqvMiniCtl = 0;
1806    unsigned long hqvScaleCtlH = 0, hqvScaleCtlV = 0;
1807    unsigned long haveHQVzoomH = 0, haveHQVzoomV = 0;
1808    unsigned long hqvSrcWidth = 0, hqvDstWidth = 0;
1809    unsigned long hqvSrcFetch = 0, hqvOffset = 0;
1810    unsigned long dwOffset = 0, fetch = 0, tmp = 0;
1811    unsigned long proReg = 0;
1812    int i;
1813
1814    DBG_DD(ErrorF("videoflag=%ld\n", videoFlag));
1815
1816    if (pVia->ChipId == PCI_CHIP_VT3259 && !(videoFlag & VIDEO_1_INUSE))
1817        proReg = PRO_HQV1_OFFSET;
1818
1819    compose = ((VIAGETREG(V_COMPOSE_MODE)
1820                & ~(SELECT_VIDEO_IF_COLOR_KEY
1821                    | V1_COMMAND_FIRE | V3_COMMAND_FIRE))
1822               | V_COMMAND_LOAD_VBI);
1823
1824    DBG_DD(ErrorF("// Upd_Video:\n"));
1825    DBG_DD(ErrorF("Modified rSrc  X (%ld,%ld) Y (%ld,%ld)\n",
1826                  pUpdate->SrcLeft, pUpdate->SrcRight,
1827                  pUpdate->SrcTop, pUpdate->SrcBottom));
1828    DBG_DD(ErrorF("Modified rDest  X (%ld,%ld) Y (%ld,%ld)\n",
1829                  pUpdate->DstLeft, pUpdate->DstRight,
1830                  pUpdate->DstTop, pUpdate->DstBottom));
1831
1832    dstWidth = pUpdate->DstRight - pUpdate->DstLeft;
1833	/*if (pBIOSInfo->lvds && pBIOSInfo->lvds->status == XF86OutputStatusConnected &&
1834		pBIOSInfo->Panel->Scale) {
1835        * FIXME: We need to determine if the panel is using V1 or V3 *
1836        float hfactor = (float)pBIOSInfo->Panel->NativeMode->Width
1837                        / pScrn->currentMode->HDisplay;
1838        dstWidth *= hfactor;
1839    }*/
1840
1841    pVia->swov.overlayRecordV1.dwWidth = dstWidth;
1842    pVia->swov.overlayRecordV1.dwHeight = dstHeight =
1843            pUpdate->DstBottom - pUpdate->DstTop;
1844    srcWidth = (unsigned long)pUpdate->SrcRight - pUpdate->SrcLeft;
1845    srcHeight = (unsigned long)pUpdate->SrcBottom - pUpdate->SrcTop;
1846    DBG_DD(ErrorF("===srcWidth= %ld \n", srcWidth));
1847    DBG_DD(ErrorF("===srcHeight= %ld \n", srcHeight));
1848
1849    vidCtl = ViaSetVidCtl(pVia, videoFlag);
1850
1851    if (hwDiff->dwNeedV1Prefetch) {
1852        DBG_DD(ErrorF("NEEDV1PREFETCH\n"));
1853        vidCtl |= V1_PREFETCH_ON_3336;
1854    }
1855
1856    /*
1857     * Enable video on secondary
1858     */
1859    if ((pVia->VideoEngine == VIDEO_ENGINE_CME ||
1860         pVia->Chipset == VIA_P4M800PRO) && iga->index) {
1861        /* V1_ON_SND_DISPLAY */
1862        vidCtl |= V1_ON_SND_DISPLAY;
1863        /* SECOND_DISPLAY_COLOR_KEY_ENABLE */
1864        compose |= SECOND_DISPLAY_COLOR_KEY_ENABLE | 0x1;
1865    }
1866
1867    viaOverlayGetV1V3Format(pVia, (videoFlag & VIDEO_1_INUSE) ? 1 : 3,
1868                            videoFlag, &vidCtl, &hqvCtl);
1869
1870    if (hwDiff->dwThreeHQVBuffer) {    /* CLE_C0: HQV supports triple-buffering */
1871        hqvCtl &= ~HQV_SW_FLIP;
1872        hqvCtl |= HQV_TRIPLE_BUFF | HQV_FLIP_STATUS;
1873    }
1874
1875    /* Starting address of source and Source offset */
1876    dwOffset = viaOverlayGetSrcStartAddress(pVia, videoFlag, pUpdate,
1877                                            srcPitch, &hqvOffset);
1878    DBG_DD(ErrorF("===dwOffset= 0x%lx \n", dwOffset));
1879
1880    pVia->swov.overlayRecordV1.dwOffset = dwOffset;
1881
1882    if (pVia->swov.SrcFourCC == FOURCC_YV12
1883        || pVia->swov.SrcFourCC == FOURCC_I420
1884        || pVia->swov.SrcFourCC == FOURCC_XVMC) {
1885
1886        YCBCRREC YCbCr;
1887
1888        if (videoFlag & VIDEO_HQV_INUSE) {
1889            SetVideoStart(pVia, videoFlag, hwDiff->dwThreeHQVBuffer ? 3 : 2,
1890                          pVia->swov.overlayRecordV1.dwHQVAddr[0] + dwOffset,
1891                          pVia->swov.overlayRecordV1.dwHQVAddr[1] + dwOffset,
1892                          pVia->swov.overlayRecordV1.dwHQVAddr[2] + dwOffset);
1893
1894            if (pVia->swov.SrcFourCC != FOURCC_XVMC) {
1895                YCbCr = viaOverlayGetYCbCrStartAddress(videoFlag, startAddr,
1896                                pVia->swov.overlayRecordV1.dwOffset,
1897                                pVia->swov.overlayRecordV1.dwUVoffset,
1898                                srcPitch, oriSrcHeight);
1899                if (pVia->VideoEngine == VIDEO_ENGINE_CME) {
1900                    SaveVideoRegister(pVia, HQV_SRC_STARTADDR_Y + proReg,
1901                                      YCbCr.dwY);
1902                    SaveVideoRegister(pVia, HQV_SRC_STARTADDR_U + proReg,
1903                                      YCbCr.dwCB);
1904                } else {
1905                    SaveVideoRegister(pVia, HQV_SRC_STARTADDR_Y, YCbCr.dwY);
1906                    SaveVideoRegister(pVia, HQV_SRC_STARTADDR_U, YCbCr.dwCR);
1907                    SaveVideoRegister(pVia, HQV_SRC_STARTADDR_V, YCbCr.dwCB);
1908                }
1909            }
1910        } else {
1911            YCbCr = viaOverlayGetYCbCrStartAddress(videoFlag, startAddr,
1912                            pVia->swov.overlayRecordV1.dwOffset,
1913                            pVia->swov.overlayRecordV1.dwUVoffset,
1914                            srcPitch, oriSrcHeight);
1915
1916            if (videoFlag & VIDEO_1_INUSE) {
1917                SaveVideoRegister(pVia, V1_STARTADDR_0, YCbCr.dwY);
1918                SaveVideoRegister(pVia, V1_STARTADDR_CB0, YCbCr.dwCR);
1919                SaveVideoRegister(pVia, V1_STARTADDR_CR0, YCbCr.dwCB);
1920            } else
1921                DBG_DD(ErrorF("Upd_Video(): "
1922                              "We do not support YV12 with V3!\n"));
1923        }
1924    } else {
1925        if (videoFlag & VIDEO_HQV_INUSE) {
1926            hqvSrcWidth = (unsigned long)pUpdate->SrcRight - pUpdate->SrcLeft;
1927            hqvDstWidth = (unsigned long)pUpdate->DstRight - pUpdate->DstLeft;
1928
1929            if (hqvSrcWidth > hqvDstWidth)
1930                dwOffset = dwOffset * hqvDstWidth / hqvSrcWidth;
1931
1932            SetVideoStart(pVia, videoFlag, hwDiff->dwThreeHQVBuffer ? 3 : 2,
1933                          pVia->swov.overlayRecordV1.dwHQVAddr[0] + hqvOffset,
1934                          pVia->swov.overlayRecordV1.dwHQVAddr[1] + hqvOffset,
1935                          pVia->swov.overlayRecordV1.dwHQVAddr[2] + hqvOffset);
1936
1937            if (pVia->VideoEngine == VIDEO_ENGINE_CME)
1938                SaveVideoRegister(pVia, 0x1cc + proReg, dwOffset);
1939
1940            SaveVideoRegister(pVia, HQV_SRC_STARTADDR_Y + proReg, startAddr);
1941        } else {
1942            startAddr += dwOffset;
1943            SetVideoStart(pVia, videoFlag, 1, startAddr, 0, 0);
1944        }
1945    }
1946
1947    fetch = viaOverlayGetFetch(pVia, videoFlag,
1948                               srcWidth, dstWidth, oriSrcWidth, &hqvSrcFetch);
1949    DBG_DD(ErrorF("===fetch= 0x%lx\n", fetch));
1950
1951#if 0
1952    /* For DCT450 test-BOB INTERLEAVE */
1953    if ((deinterlaceMode & DDOVER_INTERLEAVED)
1954        && (deinterlaceMode & DDOVER_BOB)) {
1955        if (videoFlag & VIDEO_HQV_INUSE)
1956            hqvCtl |= HQV_FIELD_2_FRAME | HQV_FRAME_2_FIELD | HQV_DEINTERLACE;
1957        else
1958            vidCtl |= V1_BOB_ENABLE | V1_FRAME_BASE;
1959    } else if (deinterlaceMode & DDOVER_BOB) {
1960        if (videoFlag & VIDEO_HQV_INUSE)
1961            /* The HQV source data line count should be two times of the original line count */
1962            hqvCtl |= HQV_FIELD_2_FRAME | HQV_DEINTERLACE;
1963        else
1964            vidCtl |= V1_BOB_ENABLE;
1965    }
1966#endif
1967
1968    if (videoFlag & VIDEO_HQV_INUSE) {
1969        if (!(deinterlaceMode & DDOVER_INTERLEAVED)
1970            && (deinterlaceMode & DDOVER_BOB))
1971            SetHQVFetch(pVia, hqvSrcFetch, oriSrcHeight << 1);
1972        else
1973            SetHQVFetch(pVia, hqvSrcFetch, oriSrcHeight);
1974
1975        if (pVia->swov.SrcFourCC == FOURCC_YV12
1976            || pVia->swov.SrcFourCC == FOURCC_I420
1977            || pVia->swov.SrcFourCC == FOURCC_XVMC) {
1978            if (videoFlag & VIDEO_1_INUSE)
1979                SaveVideoRegister(pVia, V1_STRIDE, srcPitch << 1);
1980            else
1981                SaveVideoRegister(pVia, V3_STRIDE, srcPitch << 1);
1982
1983            if (pVia->HWDiff.dwHQVFetchByteUnit)
1984                SaveVideoRegister(pVia, HQV_SRC_STRIDE + proReg,
1985                                  ((srcPitch >> 1) << 16) | srcPitch |
1986                                  HQV_FIFO_DEPTH_1);
1987            else
1988                SaveVideoRegister(pVia, HQV_SRC_STRIDE + proReg,
1989                                  ((srcPitch >> 1) << 16) | srcPitch);
1990
1991            SaveVideoRegister(pVia, HQV_DST_STRIDE + proReg, (srcPitch << 1));
1992        } else {
1993            if (videoFlag & VIDEO_1_INUSE)
1994                SaveVideoRegister(pVia, V1_STRIDE, srcPitch);
1995            else
1996                SaveVideoRegister(pVia, V3_STRIDE, srcPitch);
1997
1998            SaveVideoRegister(pVia, HQV_SRC_STRIDE + proReg, srcPitch);
1999            SaveVideoRegister(pVia, HQV_DST_STRIDE + proReg, srcPitch);
2000        }
2001
2002    } else {
2003        if (videoFlag & VIDEO_1_INUSE)
2004            SaveVideoRegister(pVia, V1_STRIDE, srcPitch | (srcPitch << 15));
2005        else
2006            SaveVideoRegister(pVia, V3_STRIDE, srcPitch | (srcPitch << 15));
2007    }
2008
2009    /* Set destination window */
2010    SetVideoWindow(pScrn, videoFlag, pUpdate);
2011
2012    compose |= ALWAYS_SELECT_VIDEO;
2013
2014    /* Set up X zoom factor */
2015
2016    pVia->swov.overlayRecordV1.dwFetchAlignment = 0;
2017
2018    if (!viaOverlayHQVCalcZoomWidth(pVia, videoFlag, srcWidth, dstWidth,
2019                                    &zoomCtl, &miniCtl, &hqvFilterCtl,
2020                                    &hqvMiniCtl, &hqvScaleCtlH, &haveHQVzoomH)) {
2021        /* Need to scale (minify) too much - can't handle it. */
2022        SetFetch(pVia, videoFlag, fetch);
2023        FireVideoCommand(pVia, videoFlag, compose);
2024        FlushVidRegBuffer(pVia);
2025        return FALSE;
2026    }
2027
2028    SetFetch(pVia, videoFlag, fetch);
2029
2030    /* Set up Y zoom factor */
2031
2032    /* For DCT450 test-BOB INTERLEAVE */
2033    if ((deinterlaceMode & DDOVER_INTERLEAVED)
2034        && (deinterlaceMode & DDOVER_BOB)) {
2035        if (!(videoFlag & VIDEO_HQV_INUSE)) {
2036            srcHeight /= 2;
2037            if (videoFlag & VIDEO_1_INUSE)
2038                vidCtl |= V1_BOB_ENABLE | V1_FRAME_BASE;
2039            else
2040                vidCtl |= V3_BOB_ENABLE | V3_FRAME_BASE;
2041        } else
2042            hqvCtl |= HQV_FIELD_2_FRAME | HQV_FRAME_2_FIELD | HQV_DEINTERLACE;
2043    } else if (deinterlaceMode & DDOVER_BOB) {
2044        if (videoFlag & VIDEO_HQV_INUSE) {
2045            srcHeight <<= 1;
2046            hqvCtl |= HQV_FIELD_2_FRAME | HQV_DEINTERLACE;
2047        } else {
2048            if (videoFlag & VIDEO_1_INUSE)
2049                vidCtl |= V1_BOB_ENABLE;
2050            else
2051                vidCtl |= V3_BOB_ENABLE;
2052        }
2053    }
2054
2055    SetDisplayCount(pVia, videoFlag, srcWidth, srcHeight);
2056
2057    if (!viaOverlayHQVCalcZoomHeight(pVia, srcHeight, dstHeight, &zoomCtl,
2058                                     &miniCtl, &hqvFilterCtl, &hqvMiniCtl,
2059                                     &hqvScaleCtlV, &haveHQVzoomV)) {
2060        /* Need to scale (minify) too much - can't handle it. */
2061        FireVideoCommand(pVia, videoFlag, compose);
2062        FlushVidRegBuffer(pVia);
2063        return FALSE;
2064    }
2065
2066    SetupFIFOs(pVia, videoFlag, miniCtl, srcWidth);
2067
2068    if (videoFlag & VIDEO_HQV_INUSE) {
2069        miniCtl = 0;
2070
2071        if (haveHQVzoomH || haveHQVzoomV) {
2072            tmp = 0;
2073
2074            if (haveHQVzoomH) {
2075                miniCtl = V1_X_INTERPOLY;
2076                /* Disable X interpolation if the height exceeds
2077                 * the maximum supported by the hardware */
2078                if (srcHeight >= pVia->swov.maxHInterp)
2079                    miniCtl &= ~V1_X_INTERPOLY;
2080                tmp = zoomCtl & 0xffff0000;
2081            }
2082
2083            if (haveHQVzoomV) {
2084                miniCtl |= V1_Y_INTERPOLY | V1_YCBCR_INTERPOLY;
2085                /* Disable Y interpolation if the width exceeds
2086                 * the maximum supported by the hardware */
2087                if (srcWidth >= pVia->swov.maxWInterp)
2088                    miniCtl &= ~V1_Y_INTERPOLY;
2089                tmp |= zoomCtl & 0x0000ffff;
2090                hqvFilterCtl &= 0xfffdffff;
2091            }
2092
2093            /* Temporary fix for 2D bandwidth problem. 2002/08/01 */
2094            if (pVia->swov.gdwUseExtendedFIFO)
2095                miniCtl &= ~V1_Y_INTERPOLY;
2096
2097            SetMiniAndZoom(pVia, videoFlag, miniCtl, tmp);
2098        } else {
2099            if (srcHeight == dstHeight)
2100                hqvFilterCtl &= 0xfffdffff;
2101            SetMiniAndZoom(pVia, videoFlag, 0, 0);
2102        }
2103	if (hwDiff->dwNewScaleCtl) {
2104		SaveVideoRegister(pVia, HQV_H_SCALE_CONTROL + proReg, hqvScaleCtlH);
2105		SaveVideoRegister(pVia, HQV_V_SCALE_CONTROL + proReg, hqvScaleCtlV);
2106	} else {
2107		SaveVideoRegister(pVia, HQV_MINIFY_CONTROL + proReg, hqvMiniCtl);
2108	}
2109	SaveVideoRegister(pVia, HQV_FILTER_CONTROL + proReg, hqvFilterCtl);
2110    } else
2111        SetMiniAndZoom(pVia, videoFlag, miniCtl, zoomCtl);
2112
2113    if (haveColorKey)
2114        compose = SetColorKey(pVia, videoFlag, colorKeyLow, colorKeyHigh,
2115                              compose);
2116
2117    if (haveChromaKey)
2118        compose = SetChromaKey(pVia, videoFlag, chromaKeyLow, chromaKeyHigh,
2119                               miniCtl, compose);
2120
2121    if (pVia->VideoEngine == VIDEO_ENGINE_CME) {
2122        SaveVideoRegister(pVia, HQV_CME_REG(hwDiff, HQV_SDO_CTRL1),0);
2123        SaveVideoRegister(pVia, HQV_CME_REG(hwDiff, HQV_SDO_CTRL3),((pUpdate->SrcRight - 1 ) << 16) | (pUpdate->SrcBottom - 1));
2124        if ((pVia->Chipset == VIA_VX800) ||
2125            (pVia->Chipset == VIA_VX855) ||
2126            (pVia->Chipset == VIA_VX900)) {
2127            SaveVideoRegister(pVia, HQV_CME_REG(hwDiff, HQV_SDO_CTRL2),0);
2128            SaveVideoRegister(pVia, HQV_CME_REG(hwDiff, HQV_SDO_CTRL4),((pUpdate->SrcRight - 1 ) << 16) | (pUpdate->SrcBottom - 1));
2129            if ((pVia->Chipset == VIA_VX855) ||
2130                (pVia->Chipset == VIA_VX900)) {
2131                SaveVideoRegister(pVia, HQV_DST_DATA_OFFSET_CTRL1,0);
2132                SaveVideoRegister(pVia, HQV_DST_DATA_OFFSET_CTRL3,((pUpdate->SrcRight - 1 ) << 16) | (pUpdate->SrcBottom - 1));
2133                SaveVideoRegister(pVia, HQV_DST_DATA_OFFSET_CTRL2,0);
2134                SaveVideoRegister(pVia, HQV_DST_DATA_OFFSET_CTRL4,((pUpdate->SrcRight - 1 ) << 16) | (pUpdate->SrcBottom - 1));
2135                SaveVideoRegister(pVia, HQV_BACKGROUND_DATA_OFFSET,((pUpdate->SrcRight - 1 ) << 16) | (pUpdate->SrcBottom - 1));
2136                SaveVideoRegister(pVia, HQV_EXTENDED_CONTROL,0);
2137                /*0x3e0*/
2138                SaveVideoRegister(pVia, HQV_SUBP_HSCALE_CTRL,0);
2139                /*0x3e8*/
2140                SaveVideoRegister(pVia, HQV_SUBP_VSCALE_CTRL,0);
2141            }
2142
2143            if (pVia->Chipset == VIA_VX900) {
2144
2145                SaveVideoRegister(pVia, HQV_SHARPNESS_DECODER_HANDSHAKE_CTRL_410, 0);
2146            }
2147
2148            // TODO Need to be tested on VX800
2149            /* 0x3B8 */
2150            SaveVideoRegister(pVia, HQV_DEFAULT_VIDEO_COLOR, HQV_FIX_COLOR);
2151
2152        }
2153    }
2154
2155    /* Set up video control */
2156    if (videoFlag & VIDEO_HQV_INUSE) {
2157
2158        if (!pVia->swov.SWVideo_ON) {
2159            DBG_DD(ErrorF("    First HQV\n"));
2160
2161            FlushVidRegBuffer(pVia);
2162
2163            DBG_DD(ErrorF(" Wait flips"));
2164
2165            if (hwDiff->dwHQVInitPatch) {
2166                DBG_DD(ErrorF(" Initializing HQV twice ..."));
2167                for (i = 0; i < 2; i++) {
2168                    viaWaitHQVFlipClear(pVia,
2169                                        ((hqvCtl & ~HQV_SW_FLIP) |
2170                                         HQV_FLIP_STATUS) & ~HQV_ENABLE);
2171                    VIASETREG(HQV_CONTROL + proReg, hqvCtl);
2172                    viaWaitHQVFlip(pVia);
2173                }
2174                DBG_DD(ErrorF(" done.\n"));
2175            } else {               /* CLE_C0 */
2176                CARD32 volatile *HQVCtrl =
2177                        (CARD32 volatile *)(pVia->MapBase + HQV_CONTROL +
2178                                            proReg);
2179
2180                /* Check that HQV is idle */
2181                DBG_DD(ErrorF("HQV control wf - %08lx\n", *HQVCtrl));
2182                while (!(*HQVCtrl & HQV_IDLE)) {
2183                    DBG_DD(ErrorF("HQV control busy - %08lx\n", *HQVCtrl));
2184                    usleep(1);
2185                }
2186
2187                VIASETREG(HQV_CONTROL + proReg, hqvCtl & ~HQV_SW_FLIP);
2188                VIASETREG(HQV_CONTROL + proReg, hqvCtl | HQV_SW_FLIP);
2189
2190                DBG_DD(ErrorF("HQV control wf5 - %08lx\n", *HQVCtrl));
2191                DBG_DD(ErrorF(" Wait flips5"));
2192
2193                if (pVia->VideoEngine != VIDEO_ENGINE_CME) {
2194                    for (i = 0; (i < 50) && !(*HQVCtrl & HQV_FLIP_STATUS);
2195                         i++) {
2196                        DBG_DD(ErrorF(" HQV wait %d %08lx\n", i, *HQVCtrl));
2197                        *HQVCtrl |= HQV_SW_FLIP | HQV_FLIP_STATUS;
2198                        usleep(1);
2199                    }
2200                } else {
2201                    viaWaitHQVFlip(pVia);
2202                }
2203
2204                DBG_DD(ErrorF(" Wait flips6"));
2205            }
2206
2207            if (videoFlag & VIDEO_1_INUSE) {
2208                VIASETREG(V1_CONTROL, vidCtl);
2209                VIASETREG(V_COMPOSE_MODE, compose | V1_COMMAND_FIRE);
2210                if (pVia->swov.gdwUseExtendedFIFO) {
2211                    /* Set Display FIFO */
2212                    DBG_DD(ErrorF(" Wait flips7"));
2213                    viaWaitVBI(pVia);
2214                    DBG_DD(ErrorF(" Wait flips 8"));
2215                    hwp->writeSeq(hwp, 0x17, 0x2F);
2216                    ViaSeqMask(hwp, 0x16, 0x14, 0x1F);
2217                    hwp->writeSeq(hwp, 0x18, 0x56);
2218                    DBG_DD(ErrorF(" Wait flips 9"));
2219                }
2220            } else {
2221                DBG_DD(ErrorF(" Wait flips 10"));
2222                VIASETREG(V3_CONTROL, vidCtl);
2223                VIASETREG(V_COMPOSE_MODE, compose | V3_COMMAND_FIRE);
2224            }
2225            DBG_DD(ErrorF(" Done flips"));
2226        } else {
2227            DBG_DD(ErrorF("    Normal called\n"));
2228            SaveVideoRegister(pVia, HQV_CONTROL + proReg,
2229                              hqvCtl | HQV_FLIP_STATUS);
2230            SetVideoControl(pVia, videoFlag, vidCtl);
2231            FireVideoCommand(pVia, videoFlag, compose);
2232            viaWaitHQVDone(pVia);
2233            FlushVidRegBuffer(pVia);
2234        }
2235    } else {
2236        SetVideoControl(pVia, videoFlag, vidCtl);
2237        FireVideoCommand(pVia, videoFlag, compose);
2238        viaWaitHQVDone(pVia);
2239        FlushVidRegBuffer(pVia);
2240    }
2241    pVia->swov.SWVideo_ON = TRUE;
2242
2243    DBG_DD(ErrorF(" Done Upd_Video"));
2244
2245    return TRUE;
2246
2247}  /* Upd_Video */
2248
2249/*
2250 *  VIAVidUpdateOverlay()
2251 *  Parameters:   src rectangle, dst rectangle, colorkey...
2252 *  Return value: unsigned long of state
2253 *  Note: updates the overlay image parameter.
2254 */
2255Bool
2256VIAVidUpdateOverlay(xf86CrtcPtr crtc, LPDDUPDATEOVERLAY pUpdate)
2257{
2258    ScrnInfoPtr pScrn = crtc->scrn;
2259    VIAPtr pVia = VIAPTR(pScrn);
2260    OVERLAYRECORD *ovlV1 = &pVia->swov.overlayRecordV1;
2261
2262    unsigned long flags = pUpdate->dwFlags;
2263    unsigned long videoFlag = 0;
2264    unsigned long startAddr = 0;
2265    unsigned long deinterlaceMode = 0;
2266
2267    unsigned long haveColorKey = 0, haveChromaKey = 0;
2268    unsigned long colorKeyLow = 0, colorKeyHigh = 0;
2269    unsigned long chromaKeyLow = 0, chromaKeyHigh = 0;
2270
2271    unsigned long scrnWidth, scrnHeight;
2272    int dstTop, dstBottom, dstLeft, dstRight;
2273    int panDX, panDY;               /* Panning delta */
2274
2275    unsigned long proReg = 0;
2276
2277    panDX = pVia->swov.panning_x;
2278    panDY = pVia->swov.panning_y;
2279    pVia->swov.oldPanningX = pVia->swov.panning_x;
2280    pVia->swov.oldPanningY = pVia->swov.panning_y;
2281
2282    pUpdate->DstLeft -= panDX;
2283    pUpdate->DstTop -= panDY;
2284    pUpdate->DstRight -= panDX;
2285    pUpdate->DstBottom -= panDY;
2286
2287    DBG_DD(ErrorF("Raw rSrc  X (%ld,%ld) Y (%ld,%ld)\n",
2288                  pUpdate->SrcLeft, pUpdate->SrcRight,
2289                  pUpdate->SrcTop, pUpdate->SrcBottom));
2290    DBG_DD(ErrorF("Raw rDest  X (%ld,%ld) Y (%ld,%ld)\n",
2291                  pUpdate->DstLeft, pUpdate->DstRight,
2292                  pUpdate->DstTop, pUpdate->DstBottom));
2293
2294    if ((pVia->swov.SrcFourCC == FOURCC_YUY2) ||
2295        (pVia->swov.SrcFourCC == FOURCC_RV15) ||
2296        (pVia->swov.SrcFourCC == FOURCC_RV16) ||
2297        (pVia->swov.SrcFourCC == FOURCC_RV32) ||
2298        (pVia->swov.SrcFourCC == FOURCC_YV12) ||
2299        (pVia->swov.SrcFourCC == FOURCC_I420) ||
2300        (pVia->swov.SrcFourCC == FOURCC_XVMC)) {
2301        videoFlag = pVia->swov.gdwVideoFlagSW;
2302    }
2303
2304    if (pVia->ChipId == PCI_CHIP_VT3259 && !(videoFlag & VIDEO_1_INUSE))
2305        proReg = PRO_HQV1_OFFSET;
2306
2307    flags |= DDOVER_INTERLEAVED;
2308
2309    /* Disable destination color keying if the alpha window is in use. */
2310    if (pVia->swov.gdwAlphaEnabled)
2311        flags &= ~DDOVER_KEYDEST;
2312
2313    ResetVidRegBuffer(pVia);
2314
2315    /* For SW decode HW overlay use */
2316    startAddr = VIAGETREG(HQV_SRC_STARTADDR_Y + proReg);
2317
2318    if (flags & DDOVER_KEYDEST) {
2319        haveColorKey = 1;
2320        colorKeyLow = pUpdate->dwColorSpaceLowValue;
2321    }
2322
2323    if (flags & DDOVER_INTERLEAVED)
2324        deinterlaceMode |= DDOVER_INTERLEAVED;
2325
2326    if (flags & DDOVER_BOB)
2327        deinterlaceMode |= DDOVER_BOB;
2328
2329    if ((pVia->ChipId == PCI_CHIP_CLE3122)
2330        && (pScrn->currentMode->HDisplay > 1024)) {
2331        DBG_DD(ErrorF("UseExtendedFIFO\n"));
2332        pVia->swov.gdwUseExtendedFIFO = 1;
2333    } else
2334        pVia->swov.gdwUseExtendedFIFO = 0;
2335
2336    /* Figure out actual rSrc rectangle */
2337
2338    dstLeft = pUpdate->DstLeft;
2339    dstTop = pUpdate->DstTop;
2340    dstRight = pUpdate->DstRight;
2341    dstBottom = pUpdate->DstBottom;
2342
2343    scrnWidth = pScrn->currentMode->HDisplay;
2344    scrnHeight = pScrn->currentMode->VDisplay;
2345
2346    if (dstLeft < 0) {
2347        pUpdate->SrcLeft = ((((-dstLeft) * ovlV1->dwV1OriWidth) +
2348                             ((dstRight - dstLeft) >> 1))
2349                            / (dstRight - dstLeft));
2350    }
2351    if (dstRight > scrnWidth) {
2352        pUpdate->SrcRight = ((((scrnWidth - dstLeft) * ovlV1->dwV1OriWidth) +
2353                              ((dstRight - dstLeft) >> 1))
2354                             / (dstRight - dstLeft));
2355    }
2356    if (dstTop < 0) {
2357        pUpdate->SrcTop = ((((-dstTop) * ovlV1->dwV1OriHeight) +
2358                            ((dstBottom - dstTop) >> 1))
2359                           / (dstBottom - dstTop));
2360    }
2361    if (dstBottom > scrnHeight) {
2362        pUpdate->SrcBottom = ((((scrnHeight - dstTop) * ovlV1->dwV1OriHeight) +
2363                               ((dstBottom - dstTop) >> 1))
2364                              / (dstBottom - dstTop));
2365    }
2366
2367    /* Save modified src & original dest rectangle parameters */
2368
2369    if ((pVia->swov.SrcFourCC == FOURCC_YUY2) ||
2370        (pVia->swov.SrcFourCC == FOURCC_RV15) ||
2371        (pVia->swov.SrcFourCC == FOURCC_RV16) ||
2372        (pVia->swov.SrcFourCC == FOURCC_RV32) ||
2373        (pVia->swov.SrcFourCC == FOURCC_YV12) ||
2374        (pVia->swov.SrcFourCC == FOURCC_I420) ||
2375        (pVia->swov.SrcFourCC == FOURCC_XVMC)) {
2376        pVia->swov.SWDevice.gdwSWDstLeft = pUpdate->DstLeft + panDX;
2377        pVia->swov.SWDevice.gdwSWDstTop = pUpdate->DstTop + panDY;
2378        pVia->swov.SWDevice.gdwSWDstWidth =
2379                pUpdate->DstRight - pUpdate->DstLeft;
2380        pVia->swov.SWDevice.gdwSWDstHeight =
2381                pUpdate->DstBottom - pUpdate->DstTop;
2382
2383        pVia->swov.SWDevice.gdwSWSrcWidth = ovlV1->dwV1SrcWidth =
2384                pUpdate->SrcRight - pUpdate->SrcLeft;
2385        pVia->swov.SWDevice.gdwSWSrcHeight = ovlV1->dwV1SrcHeight =
2386                pUpdate->SrcBottom - pUpdate->SrcTop;
2387    }
2388
2389    ovlV1->dwV1SrcLeft = pUpdate->SrcLeft;
2390    ovlV1->dwV1SrcRight = pUpdate->SrcRight;
2391    ovlV1->dwV1SrcTop = pUpdate->SrcTop;
2392    ovlV1->dwV1SrcBot = pUpdate->SrcBottom;
2393
2394    /* Figure out actual rDest rectangle */
2395
2396    pUpdate->DstLeft = (dstLeft < 0) ? 0 : dstLeft;
2397    pUpdate->DstTop = (dstTop < 0) ? 0 : dstTop;
2398    if (pUpdate->DstTop >= scrnHeight)
2399        pUpdate->DstTop = scrnHeight - 1;
2400    pUpdate->DstRight = (dstRight > scrnWidth) ? scrnWidth : dstRight;
2401    pUpdate->DstBottom = (dstBottom > scrnHeight) ? scrnHeight : dstBottom;
2402
2403    /* Update the overlay */
2404
2405    if (!Upd_Video(crtc, videoFlag, startAddr, pUpdate,
2406                   pVia->swov.SWDevice.dwPitch, ovlV1->dwV1OriWidth,
2407                   ovlV1->dwV1OriHeight, deinterlaceMode, haveColorKey,
2408                   haveChromaKey, colorKeyLow, colorKeyHigh, chromaKeyLow,
2409                   chromaKeyHigh))
2410        return FALSE;
2411
2412    pVia->swov.SWVideo_ON = FALSE;
2413
2414    return TRUE;
2415
2416}  /* VIAVidUpdateOverlay */
2417
2418/*
2419 *
2420 */
2421void
2422ViaOverlayHide(ScrnInfoPtr pScrn)
2423{
2424    VIAPtr pVia = VIAPTR(pScrn);
2425    vgaHWPtr hwp = VGAHWPTR(pScrn);
2426    CARD32 videoFlag = 0;
2427    unsigned long proReg = 0;
2428
2429    if ((pVia->swov.SrcFourCC == FOURCC_YUY2) ||
2430        (pVia->swov.SrcFourCC == FOURCC_RV15) ||
2431        (pVia->swov.SrcFourCC == FOURCC_RV16) ||
2432        (pVia->swov.SrcFourCC == FOURCC_RV32) ||
2433        (pVia->swov.SrcFourCC == FOURCC_YV12) ||
2434        (pVia->swov.SrcFourCC == FOURCC_I420) ||
2435        (pVia->swov.SrcFourCC == FOURCC_XVMC))
2436        videoFlag = pVia->swov.gdwVideoFlagSW;
2437
2438    if (pVia->ChipId == PCI_CHIP_VT3259 && !(videoFlag & VIDEO_1_INUSE))
2439        proReg = PRO_HQV1_OFFSET;
2440
2441    ResetVidRegBuffer(pVia);
2442
2443    if (pVia->HWDiff.dwHQVDisablePatch)
2444        ViaSeqMask(hwp, 0x2E, 0x00, 0x10);
2445
2446    SaveVideoRegister(pVia, V_FIFO_CONTROL, V1_FIFO_PRETHRESHOLD12 |
2447                      V1_FIFO_THRESHOLD8 | V1_FIFO_DEPTH16);
2448    SaveVideoRegister(pVia, ALPHA_V3_FIFO_CONTROL,
2449                      ALPHA_FIFO_THRESHOLD4 | ALPHA_FIFO_DEPTH8 |
2450                      V3_FIFO_THRESHOLD24 | V3_FIFO_DEPTH32);
2451
2452    if (videoFlag & VIDEO_HQV_INUSE)
2453        SaveVideoRegister(pVia, HQV_CONTROL + proReg,
2454                          VIAGETREG(HQV_CONTROL + proReg) & ~HQV_ENABLE);
2455
2456    if (videoFlag & VIDEO_1_INUSE)
2457        SaveVideoRegister(pVia, V1_CONTROL, VIAGETREG(V1_CONTROL) & ~V1_ENABLE);
2458    else
2459        SaveVideoRegister(pVia, V3_CONTROL, VIAGETREG(V3_CONTROL) & ~V3_ENABLE);
2460
2461    FireVideoCommand(pVia, videoFlag, VIAGETREG(V_COMPOSE_MODE));
2462    FlushVidRegBuffer(pVia);
2463
2464    if (pVia->HWDiff.dwHQVDisablePatch)
2465        ViaSeqMask(hwp, 0x2E, 0x10, 0x10);
2466
2467    pVia->swov.SWVideo_ON = FALSE;
2468    pVia->VideoStatus &= ~VIDEO_SWOV_ON;
2469}
2470