1/*
2 * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sub license, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Shengquan Yuan  <shengquan.yuan@intel.com>
26 *    Binglin Chen <binglin.chen@intel.com>
27 *    Jason Hu <jason.hu@intel.com>
28 *    Zeng Li <zeng.li@intel.com>
29 */
30
31/*
32 * Most of rendering codes are ported from xf86-video-i810/src/i810_overlay.c
33 */
34
35#include <errno.h>
36#include <stdlib.h>
37#include <unistd.h>
38#include <stdio.h>
39#include <math.h>
40#include <va/va_backend.h>
41#include <wsbm/wsbm_manager.h>
42#include "psb_drv_video.h"
43#include "psb_output.h"
44#include "psb_overlay.h"
45#include "psb_drv_debug.h"
46
47#ifdef ANDROID
48#define psb_xrandr_single_mode() 0
49#else
50int psb_xrandr_single_mode();
51#endif
52
53#define INIT_DRIVER_DATA    psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData
54#define SURFACE(id) ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
55#define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id ))
56//#define GET_SURFACE_INFO_rotate(psb_surface) ((int) (psb_surface)->extra_info[5])
57
58#ifndef VA_FOURCC_I420
59#define VA_FOURCC_I420          0x30323449
60#endif
61
62/**********************************************************************************************
63 * I830ResetVideo
64 *
65 * Description: Use this function to reset the overlay register back buffer to its default
66 * values.  Note that this function does not actually apply these values.  To do so, please
67 * write to OVADD.
68 **********************************************************************************************/
69static void
70I830ResetVideo(VADriverContextP ctx, PsbPortPrivPtr pPriv)
71{
72    INIT_DRIVER_DATA;
73    I830OverlayRegPtr overlayA = (I830OverlayRegPtr)(pPriv->regmap[0]);
74    I830OverlayRegPtr overlayC = (I830OverlayRegPtr)(pPriv->regmap[1]);
75
76    memset(overlayA, 0, sizeof(*overlayA));
77    memset(overlayC, 0, sizeof(*overlayC));
78
79    overlayA->OCLRC0 = (pPriv->contrast.Value << 18) | (pPriv->brightness.Value & 0xff);
80    overlayA->OCLRC1 = pPriv->saturation.Value;
81
82    overlayC->OCLRC0 = (pPriv->contrast.Value << 18) | (pPriv->brightness.Value & 0xff);
83    overlayC->OCLRC1 = pPriv->saturation.Value;
84
85#if USE_DCLRK
86    /* case bit depth 16 */
87    overlayA->DCLRKV = pPriv->colorKey;
88    overlayA->DCLRKM |= DEST_KEY_ENABLE;
89    overlayA->DCLRKM &= ~CONST_ALPHA_ENABLE;
90
91    overlayC->DCLRKV = pPriv->colorKey;
92    overlayC->DCLRKM |= DEST_KEY_ENABLE;
93    overlayC->DCLRKM &= ~CONST_ALPHA_ENABLE;
94#else
95    overlayA->DCLRKM &= ~DEST_KEY_ENABLE;
96    overlayC->DCLRKM &= ~DEST_KEY_ENABLE;
97#endif
98    overlayA->DWINSZ = 0x00000000;
99    overlayA->OCONFIG = CC_OUT_8BIT;
100
101    overlayC->DWINSZ = 0x00000000;
102    overlayC->OCONFIG = CC_OUT_8BIT;
103}
104
105static uint32_t I830BoundGammaElt(uint32_t elt, uint32_t eltPrev)
106{
107    elt &= 0xff;
108    eltPrev &= 0xff;
109    if (elt < eltPrev)
110        elt = eltPrev;
111    else if ((elt - eltPrev) > 0x7e)
112        elt = eltPrev + 0x7e;
113    return elt;
114}
115
116static uint32_t I830BoundGamma(uint32_t gamma, uint32_t gammaPrev)
117{
118    return (I830BoundGammaElt(gamma >> 24, gammaPrev >> 24) << 24 |
119            I830BoundGammaElt(gamma >> 16, gammaPrev >> 16) << 16 |
120            I830BoundGammaElt(gamma >>  8, gammaPrev >>  8) <<  8 |
121            I830BoundGammaElt(gamma      , gammaPrev));
122}
123
124static void
125I830UpdateGamma(VADriverContextP ctx, PsbPortPrivPtr pPriv)
126{
127#ifndef BAYTRAIL
128    INIT_DRIVER_DATA;
129    uint32_t gamma0 = pPriv->gamma0;
130    uint32_t gamma1 = pPriv->gamma1;
131    uint32_t gamma2 = pPriv->gamma2;
132    uint32_t gamma3 = pPriv->gamma3;
133    uint32_t gamma4 = pPriv->gamma4;
134    uint32_t gamma5 = pPriv->gamma5;
135    struct drm_psb_register_rw_arg regs;
136
137    gamma1 = I830BoundGamma(gamma1, gamma0);
138    gamma2 = I830BoundGamma(gamma2, gamma1);
139    gamma3 = I830BoundGamma(gamma3, gamma2);
140    gamma4 = I830BoundGamma(gamma4, gamma3);
141    gamma5 = I830BoundGamma(gamma5, gamma4);
142
143    memset(&regs, 0, sizeof(regs));
144    if (pPriv->is_mfld)
145        regs.overlay_write_mask |= OV_REGRWBITS_OGAM_ALL | OVC_REGRWBITS_OGAM_ALL;
146    else
147        regs.overlay_write_mask |= OV_REGRWBITS_OGAM_ALL;
148    regs.overlay.OGAMC0 = gamma0;
149    regs.overlay.OGAMC1 = gamma1;
150    regs.overlay.OGAMC2 = gamma2;
151    regs.overlay.OGAMC3 = gamma3;
152    regs.overlay.OGAMC4 = gamma4;
153    regs.overlay.OGAMC5 = gamma5;
154    drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
155#endif
156}
157
158static void I830StopVideo(VADriverContextP ctx)
159{
160#ifndef BAYTRAIL
161    INIT_DRIVER_DATA;
162    PsbPortPrivPtr pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
163    I830OverlayRegPtr overlayA, overlayC;
164    struct drm_psb_register_rw_arg regs;
165
166    if (!pPriv->overlayA_enabled && !pPriv->overlayC_enabled) {
167        drv_debug_msg(VIDEO_DEBUG_GENERAL, "I830StopVideo : no overlay has been enabled, do nothing.\n");
168        return;
169    }
170
171    overlayA = (I830OverlayRegPtr)(pPriv->regmap[0]);
172    overlayC = (I830OverlayRegPtr)(pPriv->regmap[1]);
173#if 0
174    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
175#endif
176    memset(&regs, 0, sizeof(regs));
177    if (pPriv->subpicture_enabled) {
178        regs.subpicture_disable_mask = pPriv->subpicture_enable_mask;
179        pPriv->subpicture_enabled = 0;
180        drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
181    }
182
183    memset(&regs, 0, sizeof(regs));
184
185    if (pPriv->is_mfld && psb_xrandr_single_mode() == 0) {
186        if (pPriv->overlayC_enabled) {
187            regs.overlay_read_mask = OVC_REGRWBITS_OVADD;
188            drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
189
190            overlayC->DWINSZ = 0x00000000;
191            overlayC->OCMD &= ~OVERLAY_ENABLE;
192            regs.overlay_read_mask = 0;
193            regs.overlay_write_mask = OVC_REGRWBITS_OVADD;
194            regs.overlay.b_wait_vblank = 1;
195            drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
196
197            memset(&regs, 0, sizeof(regs));
198            pPriv->overlayC_enabled = 0;
199        }
200        if (pPriv->overlayA_enabled) {
201            regs.overlay_read_mask = OV_REGRWBITS_OVADD;
202            drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
203
204            overlayA->DWINSZ = 0x00000000;
205            overlayA->OCMD &= ~OVERLAY_ENABLE;
206            regs.overlay_read_mask = 0;
207            regs.overlay_write_mask = OV_REGRWBITS_OVADD;
208            regs.overlay.b_wait_vblank = 1;
209            drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
210            pPriv->overlayA_enabled = 0;
211        }
212    } else {
213        regs.overlay_read_mask = OV_REGRWBITS_OVADD;
214        drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
215
216        overlayA->DWINSZ = 0x00000000;
217        overlayA->OCMD &= ~OVERLAY_ENABLE;
218        regs.overlay_read_mask = 0;
219        regs.overlay_write_mask = OV_REGRWBITS_OVADD;
220        regs.overlay.b_wait_vblank = 1;
221        drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
222        pPriv->overlayA_enabled = 0;
223    }
224#endif
225}
226
227#if 0
228static void I830SwitchPipe(VADriverContextP ctx , int overlayId, int pipeId)
229{
230    INIT_DRIVER_DATA;
231    PsbPortPrivPtr pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
232    I830OverlayRegPtr overlay = (I830OverlayRegPtr)(pPriv->regmap[overlayId]);
233    struct drm_psb_register_rw_arg regs;
234    uint32_t overlay_mask;
235
236    if ((overlayId == OVERLAY_A) && pPriv->overlayA_enabled)
237        overlay_mask = OV_REGRWBITS_OVADD;
238    else if ((overlayId == OVERLAY_C) && pPriv->overlayC_enabled)
239        overlay_mask = OVC_REGRWBITS_OVADD;
240    else
241        return;  /*No overlay enabled, do nothing.*/
242
243    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Overlay %d switch to pipe %d\n", overlayId, pipeId);
244    memset(&regs, 0, sizeof(regs));
245    memset(overlay, 0, sizeof(*overlay));
246    overlay->OCLRC0 = (pPriv->contrast.Value << 18) | (pPriv->brightness.Value & 0xff);
247    overlay->OCLRC1 = pPriv->saturation.Value;
248
249    /* case bit depth 16 */
250    overlay->DCLRKV = pPriv->colorKey;
251    overlay->DCLRKM |= DEST_KEY_ENABLE;
252    overlay->DCLRKM &= ~CONST_ALPHA_ENABLE;
253    overlay->DWINSZ = 0x00000000;
254    overlay->OCONFIG = CC_OUT_8BIT;
255
256    regs.overlay_read_mask = overlay_mask;
257    drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
258
259    switch (pipeId) {
260    case PIPEA:
261        overlay->OCONFIG |= OVERLAY_C_PIPE_A;
262        break;
263    case PIPEB:
264        overlay->OCONFIG |= OVERLAY_C_PIPE_B;
265        break;
266    case PIPEC:
267        overlay->OCONFIG |= OVERLAY_C_PIPE_C;
268        break;
269    }
270    regs.overlay_read_mask = 0;
271    regs.overlay_write_mask = overlay_mask;
272    regs.overlay.b_wait_vblank = 1;
273    drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
274}
275#endif
276
277static int
278i830_swidth(unsigned int offset, unsigned int width, unsigned int mask, int shift)
279{
280    int swidth = ((offset + width + mask) >> shift) - (offset >> shift);
281    swidth <<= 1;
282    swidth -= 1;
283    return swidth << 2;
284}
285
286static Bool
287SetCoeffRegs(double *coeff, int mantSize, coeffPtr pCoeff, int pos)
288{
289    int maxVal, icoeff, res;
290    int sign;
291    double c;
292
293    sign = 0;
294    maxVal = 1 << mantSize;
295    c = *coeff;
296    if (c < 0.0) {
297        sign = 1;
298        c = -c;
299    }
300
301    res = 12 - mantSize;
302    if ((icoeff = (int)(c * 4 * maxVal + 0.5)) < maxVal) {
303        pCoeff[pos].exponent = 3;
304        pCoeff[pos].mantissa = icoeff << res;
305        *coeff = (double)icoeff / (double)(4 * maxVal);
306    } else if ((icoeff = (int)(c * 2 * maxVal + 0.5)) < maxVal) {
307        pCoeff[pos].exponent = 2;
308        pCoeff[pos].mantissa = icoeff << res;
309        *coeff = (double)icoeff / (double)(2 * maxVal);
310    } else if ((icoeff = (int)(c * maxVal + 0.5)) < maxVal) {
311        pCoeff[pos].exponent = 1;
312        pCoeff[pos].mantissa = icoeff << res;
313        *coeff = (double)icoeff / (double)(maxVal);
314    } else if ((icoeff = (int)(c * maxVal * 0.5 + 0.5)) < maxVal) {
315        pCoeff[pos].exponent = 0;
316        pCoeff[pos].mantissa = icoeff << res;
317        *coeff = (double)icoeff / (double)(maxVal / 2);
318    } else {
319        /* Coeff out of range */
320        return FALSE;
321    }
322
323    pCoeff[pos].sign = sign;
324    if (sign)
325        *coeff = -(*coeff);
326    return TRUE;
327}
328
329static void
330UpdateCoeff(int taps, double fCutoff, Bool isHoriz, Bool isY, coeffPtr pCoeff)
331{
332    int i, j, j1, num, pos, mantSize;
333    double pi = 3.1415926535, val, sinc, window, sum;
334    double rawCoeff[MAX_TAPS * 32], coeffs[N_PHASES][MAX_TAPS];
335    double diff;
336    int tapAdjust[MAX_TAPS], tap2Fix;
337    Bool isVertAndUV;
338
339    if (isHoriz)
340        mantSize = 7;
341    else
342        mantSize = 6;
343
344    isVertAndUV = !isHoriz && !isY;
345    num = taps * 16;
346    for (i = 0; i < num  * 2; i++) {
347        val = (1.0 / fCutoff) * taps * pi * (i - num) / (2 * num);
348        if (val == 0.0)
349            sinc = 1.0;
350        else
351            sinc = sin(val) / val;
352
353        /* Hamming window */
354        window = (0.5 - 0.5 * cos(i * pi / num));
355        rawCoeff[i] = sinc * window;
356    }
357
358    for (i = 0; i < N_PHASES; i++) {
359        /* Normalise the coefficients. */
360        sum = 0.0;
361        for (j = 0; j < taps; j++) {
362            pos = i + j * 32;
363            sum += rawCoeff[pos];
364        }
365        for (j = 0; j < taps; j++) {
366            pos = i + j * 32;
367            coeffs[i][j] = rawCoeff[pos] / sum;
368        }
369
370        /* Set the register values. */
371        for (j = 0; j < taps; j++) {
372            pos = j + i * taps;
373            if ((j == (taps - 1) / 2) && !isVertAndUV)
374                SetCoeffRegs(&coeffs[i][j], mantSize + 2, pCoeff, pos);
375            else
376                SetCoeffRegs(&coeffs[i][j], mantSize, pCoeff, pos);
377        }
378
379        tapAdjust[0] = (taps - 1) / 2;
380        for (j = 1, j1 = 1; j <= tapAdjust[0]; j++, j1++) {
381            tapAdjust[j1] = tapAdjust[0] - j;
382            tapAdjust[++j1] = tapAdjust[0] + j;
383        }
384
385        /* Adjust the coefficients. */
386        sum = 0.0;
387        for (j = 0; j < taps; j++)
388            sum += coeffs[i][j];
389        if (sum != 1.0) {
390            for (j1 = 0; j1 < taps; j1++) {
391                tap2Fix = tapAdjust[j1];
392                diff = 1.0 - sum;
393                coeffs[i][tap2Fix] += diff;
394                pos = tap2Fix + i * taps;
395                if ((tap2Fix == (taps - 1) / 2) && !isVertAndUV)
396                    SetCoeffRegs(&coeffs[i][tap2Fix], mantSize + 2, pCoeff, pos);
397                else
398                    SetCoeffRegs(&coeffs[i][tap2Fix], mantSize, pCoeff, pos);
399
400                sum = 0.0;
401                for (j = 0; j < taps; j++)
402                    sum += coeffs[i][j];
403                if (sum == 1.0)
404                    break;
405            }
406        }
407    }
408}
409
410static void
411i830_display_video(
412    VADriverContextP ctx, PsbPortPrivPtr pPriv, VASurfaceID __maybe_unused surface,
413    int id, short width, short height,
414    int dstPitch, int srcPitch, int __maybe_unused x1, int __maybe_unused y1, int __maybe_unused x2, int __maybe_unused y2, BoxPtr dstBox,
415    short src_w, short src_h, short drw_w, short drw_h,
416    unsigned int flags, int overlayId, int pipeId)
417{
418#ifndef BAYTRAIL
419    INIT_DRIVER_DATA;
420    unsigned int        swidth, swidthy, swidthuv;
421    unsigned int        mask, shift, offsety, offsetu;
422    int                 tmp;
423    uint32_t            OCMD;
424    Bool                scaleChanged = FALSE;
425    unsigned int        offset = wsbmBOOffsetHint(pPriv->wsbo[overlayId]) & 0x0FFFFFFF;
426    I830OverlayRegPtr   overlay = (I830OverlayRegPtr)(pPriv->regmap[overlayId]);
427    struct drm_psb_register_rw_arg regs;
428    int i32EnableIEP = 0;
429    int i32EnableIEPBLE = 0;
430
431    /*before enabling overlay, make sure overlay is disabled first.*/
432    if ((overlayId == OVERLAY_A) && !pPriv->overlayA_enabled) {
433        memset(&regs, 0, sizeof(regs));
434        regs.overlay_read_mask = OV_REGRWBITS_OVADD;
435        drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
436
437        overlay->OCMD &= ~OVERLAY_ENABLE;
438        regs.overlay_read_mask = 0;
439        regs.overlay_write_mask = OV_REGRWBITS_OVADD;
440        drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
441    }
442
443    /* FIXME: don't know who and why add this
444     *        comment it for full screen scale issue
445     *        any concern contact qiang.miao@intel.com
446     */
447#if 0
448    if (drw_w >= 800) {
449        x2 = x2 / 4;
450        y2 = y2 / 4;
451        dstBox->x2 = dstBox->x2 / 4;
452        dstBox->y2 = dstBox->y2 / 4;
453        drw_w = drw_w / 4;
454        drw_h = drw_h / 4;
455    }
456#endif
457
458#if USE_DCLRK
459    overlay->DCLRKM &= ~CONST_ALPHA_ENABLE;
460    if (pPriv->subpicture_enabled)
461        overlay->DCLRKM &= ~DEST_KEY_ENABLE;
462    else
463        overlay->DCLRKM |= DEST_KEY_ENABLE;
464    overlay->DCLRKV = pPriv->colorKey;
465    overlay->DCLRKM |= 0xffffff;
466#else
467    /* disable overlay destination color key didn't work,
468    * it seems z-order of overlay has been bellow display pipe.
469    */
470    overlay->DCLRKM &= ~DEST_KEY_ENABLE;
471#endif
472
473#if USE_ROTATION_FUNC
474    if (((pipeId == PIPEA) && (driver_data->mipi0_rotation != VA_ROTATION_NONE)) ||
475        ((pipeId == PIPEB) && (driver_data->hdmi_rotation != VA_ROTATION_NONE))) {
476        switch (pPriv->rotation) {
477        case VA_ROTATION_NONE:
478            break;
479        case VA_ROTATION_270:
480            tmp = dstBox->x1;
481            dstBox->x1 = dstBox->y1;
482            dstBox->y1 = pPriv->height_save - tmp;
483            tmp = dstBox->x2;
484            dstBox->x2 = dstBox->y2;
485            dstBox->y2 = pPriv->height_save - tmp;
486            tmp = dstBox->y1;
487            dstBox->y1 = dstBox->y2;
488            dstBox->y2 = tmp;
489            tmp = drw_w;
490            drw_w = drw_h;
491            drw_h = tmp;
492            break;
493        case VA_ROTATION_180:
494            tmp = dstBox->x1;
495            dstBox->x1 = pPriv->width_save - dstBox->x2;
496            dstBox->x2 = pPriv->width_save - tmp;
497            tmp = dstBox->y1;
498            dstBox->y1 = pPriv->height_save - dstBox->y2;
499            dstBox->y2 = pPriv->height_save - tmp;
500            break;
501        case VA_ROTATION_90:
502            tmp = dstBox->x1;
503            dstBox->x1 = pPriv->width_save - dstBox->y1;
504            dstBox->y1 = tmp;
505            tmp = dstBox->x2;
506            dstBox->x2 = pPriv->width_save - dstBox->y2;
507            dstBox->y2 = tmp;
508            tmp = dstBox->x1;
509            dstBox->x1 = dstBox->x2;
510            dstBox->x2 = tmp;
511            tmp = drw_w;
512            drw_w = drw_h;
513            drw_h = tmp;
514            break;
515        }
516    }
517#endif
518
519    if (pPriv->oneLineMode) {
520        /* change the coordinates with panel fitting active */
521        dstBox->y1 = (((dstBox->y1 - 1) * pPriv->scaleRatio) >> 16) + 1;
522        dstBox->y2 = ((dstBox->y2 * pPriv->scaleRatio) >> 16) + 1;
523
524        /* Now, alter the height, so we scale to the correct size */
525        drw_h = ((drw_h * pPriv->scaleRatio) >> 16) + 1;
526    }
527
528    shift = 6;
529    mask = 0x3f;
530
531    if (pPriv->curBuf == 0) {
532        offsety = pPriv->YBuf0offset;
533        offsetu = pPriv->UBuf0offset;
534    } else {
535        offsety = pPriv->YBuf1offset;
536        offsetu = pPriv->UBuf1offset;
537    }
538
539    switch (id) {
540    case VA_FOURCC_NV12:
541        overlay->SWIDTH = width | ((width / 2 & 0x7ff) << 16);
542        swidthy = i830_swidth(offsety, width, mask, shift);
543        swidthuv = i830_swidth(offsetu, width / 2, mask, shift);
544        overlay->SWIDTHSW = (swidthy) | (swidthuv << 16);
545        overlay->SHEIGHT = height | ((height / 2) << 16);
546        break;
547    case VA_FOURCC_YV12:
548    case VA_FOURCC_I420:
549        overlay->SWIDTH = width | ((width / 2 & 0x7ff) << 16);
550        swidthy  = i830_swidth(offsety, width, mask, shift);
551        swidthuv = i830_swidth(offsetu, width / 2, mask, shift);
552        overlay->SWIDTHSW = (swidthy) | (swidthuv << 16);
553        overlay->SHEIGHT = height | ((height / 2) << 16);
554        break;
555    case VA_FOURCC_UYVY:
556    case VA_FOURCC_YUY2:
557    default:
558        overlay->SWIDTH = width;
559        swidth = ((offsety + (width << 1) + mask) >> shift) -
560                 (offsety >> shift);
561
562        swidth <<= 1;
563        swidth -= 1;
564        swidth <<= 2;
565
566        overlay->SWIDTHSW = swidth;
567        overlay->SHEIGHT = height;
568        break;
569    }
570
571    overlay->DWINPOS = (dstBox->y1 << 16) | dstBox->x1;
572
573    overlay->DWINSZ = (((dstBox->y2 - dstBox->y1) << 16) |
574                       (dstBox->x2 - dstBox->x1));
575
576    /* buffer locations */
577    overlay->OBUF_0Y = pPriv->YBuf0offset;
578    overlay->OBUF_0U = pPriv->UBuf0offset;
579    overlay->OBUF_0V = pPriv->VBuf0offset;
580    overlay->OBUF_1Y = pPriv->YBuf1offset;
581    overlay->OBUF_1U = pPriv->UBuf1offset;
582    overlay->OBUF_1V = pPriv->VBuf1offset;
583
584    /*
585     * Calculate horizontal and vertical scaling factors and polyphase
586     * coefficients.
587     */
588
589    if (1) {
590        int xscaleInt, xscaleFract, yscaleInt, yscaleFract;
591        int xscaleIntUV, xscaleFractUV;
592        int yscaleIntUV, yscaleFractUV;
593        /* UV is half the size of Y -- YUV420 */
594        int uvratio = 2;
595        uint32_t newval;
596        coeffRec xcoeffY[N_HORIZ_Y_TAPS * N_PHASES];
597        coeffRec xcoeffUV[N_HORIZ_UV_TAPS * N_PHASES];
598        int i, j, pos;
599        int deinterlace_factor;
600
601        /*
602         * Y down-scale factor as a multiple of 4096.
603         */
604        if ((id == VA_FOURCC_NV12) && (0 != (flags & (VA_TOP_FIELD | VA_BOTTOM_FIELD))))
605            deinterlace_factor = 2;
606        else
607            deinterlace_factor = 1;
608
609        /* deinterlace requires twice of VSCALE setting*/
610        if (src_w == drw_w && src_h == drw_h) {
611            xscaleFract = 1 << 12;
612            yscaleFract = (1 << 12) / deinterlace_factor;
613        } else {
614            xscaleFract = ((src_w - 1) << 12) / drw_w;
615            yscaleFract = ((src_h - 1) << 12) / (deinterlace_factor * drw_h);
616        }
617
618        /* Calculate the UV scaling factor. */
619        xscaleFractUV = xscaleFract / uvratio;
620        yscaleFractUV = yscaleFract / uvratio;
621
622        /*
623         * To keep the relative Y and UV ratios exact, round the Y scales
624         * to a multiple of the Y/UV ratio.
625         */
626        xscaleFract = xscaleFractUV * uvratio;
627        yscaleFract = yscaleFractUV * uvratio;
628
629        /* Integer (un-multiplied) values. */
630        xscaleInt = xscaleFract >> 12;
631        yscaleInt = yscaleFract >> 12;
632
633        xscaleIntUV = xscaleFractUV >> 12;
634        yscaleIntUV = yscaleFractUV >> 12;
635
636        /* shouldn't get here */
637        if (xscaleInt > 7) {
638            return;
639        }
640
641        /* shouldn't get here */
642        if (xscaleIntUV > 7) {
643            return;
644        }
645
646        if (pPriv->is_mfld)
647            newval = (xscaleInt << 15) |
648                     ((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20);
649        else
650            newval = (xscaleInt << 16) |
651                     ((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20);
652
653        if (newval != overlay->YRGBSCALE) {
654            scaleChanged = TRUE;
655            overlay->YRGBSCALE = newval;
656        }
657
658        if (pPriv->is_mfld)
659            newval = (xscaleIntUV << 15) | ((xscaleFractUV & 0xFFF) << 3) |
660                     ((yscaleFractUV & 0xFFF) << 20);
661        else
662            newval = (xscaleIntUV << 16) | ((xscaleFractUV & 0xFFF) << 3) |
663                     ((yscaleFractUV & 0xFFF) << 20);
664
665        if (newval != overlay->UVSCALE) {
666            scaleChanged = TRUE;
667            overlay->UVSCALE = newval;
668        }
669
670        newval = yscaleInt << 16 | yscaleIntUV;
671        if (newval != overlay->UVSCALEV) {
672            scaleChanged = TRUE;
673            overlay->UVSCALEV = newval;
674        }
675
676        /* Recalculate coefficients if the scaling changed. */
677
678        /*
679         * Only Horizontal coefficients so far.
680         */
681        if (scaleChanged) {
682            double fCutoffY;
683            double fCutoffUV;
684
685            fCutoffY = xscaleFract / 4096.0;
686            fCutoffUV = xscaleFractUV / 4096.0;
687
688            /* Limit to between 1.0 and 3.0. */
689            if (fCutoffY < MIN_CUTOFF_FREQ)
690                fCutoffY = MIN_CUTOFF_FREQ;
691            if (fCutoffY > MAX_CUTOFF_FREQ)
692                fCutoffY = MAX_CUTOFF_FREQ;
693            if (fCutoffUV < MIN_CUTOFF_FREQ)
694                fCutoffUV = MIN_CUTOFF_FREQ;
695            if (fCutoffUV > MAX_CUTOFF_FREQ)
696                fCutoffUV = MAX_CUTOFF_FREQ;
697
698            UpdateCoeff(N_HORIZ_Y_TAPS, fCutoffY, TRUE, TRUE, xcoeffY);
699            UpdateCoeff(N_HORIZ_UV_TAPS, fCutoffUV, TRUE, FALSE, xcoeffUV);
700
701            for (i = 0; i < N_PHASES; i++) {
702                for (j = 0; j < N_HORIZ_Y_TAPS; j++) {
703                    pos = i * N_HORIZ_Y_TAPS + j;
704                    overlay->Y_HCOEFS[pos] = (xcoeffY[pos].sign << 15 |
705                                              xcoeffY[pos].exponent << 12 |
706                                              xcoeffY[pos].mantissa);
707                }
708            }
709            for (i = 0; i < N_PHASES; i++) {
710                for (j = 0; j < N_HORIZ_UV_TAPS; j++) {
711                    pos = i * N_HORIZ_UV_TAPS + j;
712                    overlay->UV_HCOEFS[pos] = (xcoeffUV[pos].sign << 15 |
713                                               xcoeffUV[pos].exponent << 12 |
714                                               xcoeffUV[pos].mantissa);
715                }
716            }
717        }
718    }
719
720    OCMD = OVERLAY_ENABLE;
721
722    switch (id) {
723    case VA_FOURCC_NV12:
724        overlay->OSTRIDE = dstPitch | (dstPitch << 16);
725        OCMD &= ~SOURCE_FORMAT;
726        OCMD &= ~OV_BYTE_ORDER;
727        OCMD |= NV12;//in the spec, there are two NV12, which to use?
728        break;
729    case VA_FOURCC_YV12:
730    case VA_FOURCC_I420:
731        /* set UV vertical phase to -0.25 */
732        /* overlay->UV_VPH = 0x30003000; */
733        overlay->OSTRIDE = (dstPitch * 2) | (dstPitch << 16);
734        OCMD &= ~SOURCE_FORMAT;
735        OCMD &= ~OV_BYTE_ORDER;
736        OCMD |= YUV_420;
737        break;
738    case VA_FOURCC_UYVY:
739    case VA_FOURCC_YUY2:
740        overlay->OSTRIDE = dstPitch;
741        OCMD &= ~SOURCE_FORMAT;
742        OCMD |= YUV_422;
743        OCMD &= ~OV_BYTE_ORDER;
744        if (id == VA_FOURCC_UYVY)
745            OCMD |= Y_SWAP;
746        break;
747    }
748
749    if (flags & (VA_TOP_FIELD | VA_BOTTOM_FIELD)) {
750        OCMD |= BUF_TYPE_FIELD;
751        OCMD &= ~FIELD_SELECT;
752
753        if (flags & VA_BOTTOM_FIELD) {
754            OCMD |= FIELD1;
755            overlay->OBUF_0Y = pPriv->YBuf0offset - srcPitch;
756            overlay->OBUF_0U = pPriv->UBuf0offset - srcPitch;
757            overlay->OBUF_0V = pPriv->VBuf0offset - srcPitch;
758            overlay->OBUF_1Y = pPriv->YBuf1offset - srcPitch;
759            overlay->OBUF_1U = pPriv->UBuf1offset - srcPitch;
760            overlay->OBUF_1V = pPriv->VBuf1offset - srcPitch;
761        } else
762            OCMD |= FIELD0;
763    } else {
764        OCMD &= ~(FIELD_SELECT);
765        OCMD &= ~BUF_TYPE_FIELD;
766    }
767
768    OCMD &= ~(BUFFER_SELECT);
769
770    if (pPriv->curBuf == 0)
771        OCMD |= BUFFER0;
772    else
773        OCMD |= BUFFER1;
774
775    overlay->OCMD = OCMD;
776
777    memset(&regs, 0, sizeof(regs));
778    switch (overlayId) {
779    case OVERLAY_A:
780        pPriv->overlayA_enabled = 1;
781        regs.overlay_write_mask = OV_REGRWBITS_OVADD;
782        break;
783    case OVERLAY_C:
784        pPriv->overlayC_enabled = 1;
785        regs.overlay_write_mask = OVC_REGRWBITS_OVADD;
786        break;
787    }
788
789    if (pPriv->is_mfld) {
790        i32EnableIEP = 0;
791
792        i32EnableIEPBLE = 0;
793
794        if (i32EnableIEP == 0) {
795            overlay->OCONFIG = CC_OUT_8BIT;
796            overlay->OCONFIG &= OVERLAY_C_PIPE_A | (~OVERLAY_C_PIPE_MASK);
797            overlay->OCONFIG |= IEP_LITE_BYPASS;
798            regs.overlay.OVADD = offset | 1;
799            regs.overlay.IEP_ENABLED = 0;
800            regs.overlay.buffer_handle = wsbmKBufHandle(wsbmKBuf(pPriv->wsbo[overlayId]));
801        }
802    } else {
803        overlay->OCONFIG = CC_OUT_8BIT;
804        overlay->OCONFIG |= IEP_LITE_BYPASS;
805        regs.overlay.OVADD = offset | 1;
806    }
807
808    if (pPriv->is_mfld) {
809        switch (pipeId) {
810        case PIPEA:
811            overlay->OCONFIG |= OVERLAY_C_PIPE_A;
812            overlay->OCONFIG |= ZORDER_TOP;
813            break;
814        case PIPEB:
815            overlay->OCONFIG |= OVERLAY_C_PIPE_B;
816            overlay->OCONFIG |= ZORDER_TOP;
817            regs.overlay.OVADD |= 0x80;
818            break;
819        case PIPEC:
820            overlay->OCONFIG |= OVERLAY_C_PIPE_C;
821            overlay->OCONFIG |= ZORDER_TOP;
822            regs.overlay.OVADD |= 0x40;
823            break;
824        }
825        overlay->OCONFIG |= ZORDER_TOP;
826    } else
827        overlay->OCONFIG |= pipeId << 18; /* mrst */
828
829    if (IS_CTP(driver_data) || IS_MRFL(driver_data) )
830        regs.overlay.b_wms = 1;
831
832    drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
833
834    if (pPriv->is_mfld) {
835        if (regs.overlay.IEP_ENABLED) {
836#if 0
837            printf("regs.overlay BLE minmax 0x%x, BSSCC control 0x%x\n",
838                   regs.overlay.IEP_BLE_MINMAX, regs.overlay.IEP_BSSCC_CONTROL);
839#endif
840            *(unsigned int *)((unsigned int)&(overlay->IEP_SPACE[0]) + 0x804)  = regs.overlay.IEP_BLE_MINMAX;
841        }
842    }
843#endif
844}
845
846
847static void I830PutImageFlipRotateSurface(
848    VADriverContextP ctx,
849    object_surface_p obj_surface,
850    int *src_w_new, int *src_h_new,
851    int *width_new, int *height_new,
852    psb_surface_p *psb_surface_new,
853    int pipeId)
854{
855    int src_w = *src_w_new, src_h =  *src_h_new;
856    int width = *width_new, height = *height_new;
857    int  tmp = 0;
858
859    psb_surface_p psb_surface = NULL;
860    INIT_DRIVER_DATA;
861    PsbPortPrivPtr pPriv;
862
863    /* local/extend display doesn't have render rotation */
864    if (((pipeId == PIPEA) && (driver_data->local_rotation == VA_ROTATION_NONE)) ||
865        ((pipeId == PIPEB) && (driver_data->extend_rotation == VA_ROTATION_NONE)))
866        return;
867
868    pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
869
870    if (pipeId == PIPEA) {
871        if (driver_data->local_rotation != VA_ROTATION_NONE) {
872            psb_surface = obj_surface->out_loop_surface;
873            width = obj_surface->width_r;
874            height = obj_surface->height_r;
875            if (driver_data->local_rotation != VA_ROTATION_180) {
876                tmp = src_w;
877                src_w = src_h;
878                src_h = tmp;
879            }
880        }
881        if ((driver_data->local_rotation == VA_ROTATION_NONE) ||
882            (driver_data->local_rotation == VA_ROTATION_180)) {
883            pPriv->width_save = pPriv->display_width;
884            pPriv->height_save = pPriv->display_height;
885        } else {
886            pPriv->width_save = pPriv->display_height;
887            pPriv->height_save = pPriv->display_width;
888        }
889        if (driver_data->is_android == 0)
890            pPriv->rotation = driver_data->local_rotation;
891        else
892            pPriv->rotation = 0;
893    } else if (pipeId == PIPEB) {
894        if (driver_data->extend_rotation != VA_ROTATION_NONE) {
895            psb_surface = obj_surface->out_loop_surface;
896            width = obj_surface->width_r;
897            height = obj_surface->height_r;
898            if (driver_data->extend_rotation != VA_ROTATION_180) {
899                tmp = src_w;
900                src_w = src_h;
901                src_h = tmp;
902            }
903        }
904        if ((driver_data->extend_rotation == VA_ROTATION_NONE) ||
905            (driver_data->extend_rotation == VA_ROTATION_180)) {
906            pPriv->width_save = pPriv->extend_display_width;
907            pPriv->height_save = pPriv->extend_display_height;
908        } else {
909            pPriv->width_save = pPriv->extend_display_height;
910            pPriv->height_save = pPriv->extend_display_width;
911        }
912        if (driver_data->is_android == 0)
913            pPriv->rotation = driver_data->extend_rotation;
914        else
915            pPriv->rotation = 0;
916    }
917
918    *src_w_new = src_w;
919    *src_h_new = src_h;
920    *width_new = width;
921    *height_new = height;
922    *psb_surface_new = psb_surface;
923}
924
925
926static int I830PutImageFlipRotateDebug(
927    VADriverContextP ctx,
928    VASurfaceID surface,
929    short __maybe_unused src_x, short __maybe_unused src_y,
930    short __maybe_unused src_w, short __maybe_unused src_h,
931    short __maybe_unused drw_x, short __maybe_unused drw_y,
932    short __maybe_unused drw_w, short __maybe_unused drw_h,
933    int __maybe_unused fourcc, int __maybe_unused flags,
934    int __maybe_unused overlayId,
935    int pipeId)
936{
937    INIT_DRIVER_DATA;
938    object_surface_p obj_surface;
939    psb_surface_p psb_surface = NULL;
940    VAStatus vaStatus = VA_STATUS_SUCCESS;
941
942    obj_surface = SURFACE(surface);
943    CHECK_SURFACE(obj_surface);
944
945    if (pipeId != 0)
946        return -1;
947
948    psb_surface = obj_surface->out_loop_surface;
949    psb_buffer_p buf = &psb_surface->buf;
950    unsigned char *data, *chroma, *buffer, *header;
951    static FILE *pf = NULL;
952    int ret, i;
953    if (!psb_surface)
954        goto dump_out;
955    if (pf == NULL)
956        if ((pf = fopen("/home/dump.yuv", "w+")) == NULL) {
957            printf("Open yuv file fails\n");
958            return -1;
959        }
960    ret = psb_buffer_map(buf, &data);
961
962    if (ret) {
963        printf("Map buffer fail\n");
964        return -1;
965    }
966    for (i = 0; i < obj_surface->height_r; i++) {
967        fwrite(data, 1, obj_surface->width_r, pf);
968        data += psb_surface->stride;
969    }
970
971    buffer = malloc(obj_surface->height_r * obj_surface->width_r);
972    if (!buffer) {
973        printf("Alloc chroma buffer fail\n");
974        return -1;
975    }
976    header = buffer;
977    chroma = data;
978    for (i = 0; i < obj_surface->height_r / 2; i++) {
979        int j;
980        for (j = 0; j < obj_surface->width_r / 2; j++) {
981            *buffer++ = data[j*2];
982        }
983        data += psb_surface->stride;
984    }
985
986    data = chroma;
987    for (i = 0; i < obj_surface->height_r / 2; i++) {
988        int j;
989        for (j = 0; j < obj_surface->width_r / 2; j++) {
990            *buffer++ = data[j*2 + 1];
991        }
992        data += psb_surface->stride;
993    }
994
995    fwrite(header, obj_surface->height_r / 2, obj_surface->width_r, pf);
996    free(header);
997    psb_buffer_unmap(buf);
998    return 0;
999
1000dump_out:
1001    return -1;
1002}
1003
1004
1005/*
1006 * The source rectangle of the video is defined by (src_x, src_y, src_w, src_h).
1007 * The dest rectangle of the video is defined by (drw_x, drw_y, drw_w, drw_h).
1008 * id is a fourcc code for the format of the video.
1009 * buf is the pointer to the source data in system memory.
1010 * width and height are the w/h of the source data.
1011 * If "sync" is TRUE, then we must be finished with *buf at the point of return
1012 * (which we always are).
1013 * clipBoxes is the clipping region in screen space.
1014 * data is a pointer to our port private.
1015 * pDraw is a Drawable, which might not be the screen in the case of
1016 * compositing.  It's a new argument to the function in the 1.1 server.
1017 */
1018static int I830PutImage(
1019    VADriverContextP ctx,
1020    VASurfaceID surface,
1021    int src_x, int src_y,
1022    int src_w, int src_h,
1023    int drw_x, int drw_y,
1024    int drw_w, int drw_h,
1025    int fourcc, int flags,
1026    int overlayId,
1027    int pipeId)
1028{
1029    INIT_DRIVER_DATA;
1030    int x1, x2, y1, y2;
1031    int width, height;
1032    int top, left, npixels;
1033    int pitch = 0, pitch2 = 0;
1034    unsigned int pre_add;
1035    unsigned int gtt_ofs;
1036    struct _WsbmBufferObject *drm_buf;
1037    BoxRec dstBox;
1038    PsbPortPrivPtr pPriv;
1039    object_surface_p obj_surface = SURFACE(surface);
1040    psb_surface_p psb_surface = NULL;
1041
1042    /* silent kw */
1043    if (NULL == obj_surface)
1044        return 1;
1045
1046    pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
1047
1048    switch (fourcc) {
1049    case VA_FOURCC_NV12:
1050        width = obj_surface->width;
1051        height = obj_surface->height;
1052        break;
1053    default:
1054        width = obj_surface->width;
1055        height = obj_surface->height;
1056        break;
1057    }
1058
1059    /* rotate support here: more check?
1060     * and for oold also?
1061     */
1062    psb_surface = obj_surface->psb_surface;
1063    I830PutImageFlipRotateSurface(ctx, obj_surface,
1064                                  &src_w, &src_h, &width, &height,
1065                                  &psb_surface, pipeId);
1066
1067    if (NULL == psb_surface) {
1068        /*Rotate surface may not be ready, so we have to discard this frame.*/
1069        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Discard this frame if rotate surface hasn't be ready.\n");
1070
1071        return 1;
1072    }
1073    width = (width <= 1920) ? width : 1920;
1074
1075    /* If dst width and height are less than 1/8th the src size, the
1076     * src/dst scale factor becomes larger than 8 and doesn't fit in
1077     * the scale register.
1078     */
1079    if (src_w >= (drw_w * 8))
1080        drw_w = src_w / 7;
1081
1082    if (src_h >= (drw_h * 8))
1083        drw_h = src_h / 7;
1084
1085    /* Clip */
1086    x1 = src_x;
1087    x2 = src_x + src_w;
1088    y1 = src_y;
1089    y2 = src_y + src_h;
1090
1091    dstBox.x1 = drw_x;
1092    dstBox.x2 = drw_x + drw_w;
1093    dstBox.y1 = drw_y;
1094    dstBox.y2 = drw_y + drw_h;
1095
1096#if USE_CLIP_FUNC
1097    if (!i830_get_crtc(pScrn, &crtc, &dstBox))
1098        return Success;
1099
1100    /*
1101     *Update drw_* and 'clipBoxes' according to current downscale/upscale state
1102     * Make sure the area determined by drw_* is in 'clipBoxes'
1103     */
1104    if (crtc->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
1105        h_ratio = (float)pScrn->pScreen->height / pPriv->width_save;
1106        v_ratio = (float)pScrn->pScreen->width / pPriv->height_save;
1107    } else {
1108        h_ratio = (float)pScrn->pScreen->width / pPriv->width_save;
1109        v_ratio = (float)pScrn->pScreen->height / pPriv->height_save;
1110    }
1111
1112    /* Horizontal downscale/upscale */
1113    if ((int)h_ratio)
1114        clipBoxes->extents.x1 /= h_ratio;
1115    else if (!(int)h_ratio)
1116        clipBoxes->extents.x2 /= h_ratio;
1117
1118    /* Vertical downscale/upscale */
1119    if ((int)v_ratio)
1120        clipBoxes->extents.y1 /= v_ratio;
1121    else if (!(int)v_ratio)
1122        clipBoxes->extents.y2 /= v_ratio;
1123
1124    drw_x /= h_ratio;
1125    drw_y /= v_ratio;
1126    drw_w /= h_ratio;
1127    drw_h /= v_ratio;
1128
1129    dstBox.x1 = drw_x;
1130    dstBox.x2 = drw_x + drw_w;
1131    dstBox.y1 = drw_y;
1132    dstBox.y2 = drw_y + drw_h;
1133
1134    /* Count in client supplied clipboxes */
1135    clipRegion = clipBoxes;
1136    psb_perform_clip(pScrn, vaPtr->clipbox, vaPtr->num_clipbox, clipBoxes, clipRegion, pDraw);
1137
1138    if (!i830_clip_video_helper(pScrn,
1139                                &crtc,
1140                                &dstBox, &x1, &x2, &y1, &y2, clipRegion,
1141                                width, height)) {
1142        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "%s: Fail to clip video to any crtc!\n", __FUNCTION__);
1143        return 0;
1144    }
1145#endif
1146
1147    switch (fourcc) {
1148    case VA_FOURCC_NV12:
1149        pitch = (width + 0x3) & ~0x3;
1150        pitch2 = psb_surface->stride;
1151        break;
1152    case VA_FOURCC_YV12:
1153    case VA_FOURCC_I420:
1154        pitch = (width + 0x3) & ~0x3;
1155        break;
1156#if USE_DISPLAY_C_SPRITE
1157    case FOURCC_RGBA:
1158        pitch = width << 2;
1159        break;
1160#endif
1161    case VA_FOURCC_UYVY:
1162    case VA_FOURCC_YUY2:
1163    default:
1164        pitch = width << 1;
1165        break;
1166    }
1167
1168    top = (y1) & ~1;
1169    left = (x1) & ~1;
1170    npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
1171
1172    if (fourcc == VA_FOURCC_NV12) {
1173        pre_add = psb_surface->buf.buffer_ofs;
1174        drm_buf = psb_surface->buf.drm_buf;
1175        gtt_ofs = wsbmBOOffsetHint(drm_buf) & 0x0FFFFFFF;
1176
1177        /*skip pad bytes.*/
1178        if (driver_data->local_rotation == VA_ROTATION_90) {
1179            left += ((src_w + 0xf) & ~0xf) - src_w;
1180        } else if (driver_data->local_rotation == VA_ROTATION_270) {
1181            top += ((src_h + 0xf) & ~0xf) - src_h;
1182        } else if (driver_data->local_rotation == VA_ROTATION_180) {
1183            left += ((src_w + 0xf) & ~0xf) - src_w;
1184            top += ((src_h + 0xf) & ~0xf) - src_h;
1185        }
1186        pPriv->YBuf0offset = pre_add + gtt_ofs  + top * pitch2 + left;
1187        pPriv->YBuf1offset = pPriv->YBuf0offset;
1188        pPriv->UBuf0offset = pre_add + gtt_ofs + (pitch2  * height) + top * (pitch2 / 2) + left;
1189        pPriv->VBuf0offset = pPriv->UBuf0offset;
1190        pPriv->UBuf1offset = pPriv->UBuf0offset;
1191        pPriv->VBuf1offset = pPriv->UBuf0offset;
1192    } else {
1193        //TBD
1194        //pPriv->YBuf0offset = pPriv->videoBuf0_gtt_offset << PAGE_SHIFT;
1195        //pPriv->YBuf1offset = pPriv->videoBuf1_gtt_offset << PAGE_SHIFT;
1196        if (pPriv->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
1197            pPriv->UBuf0offset = pPriv->YBuf0offset + (pitch2  * width);
1198            pPriv->VBuf0offset = pPriv->UBuf0offset + (pitch2 * width / 2);
1199            pPriv->UBuf1offset = pPriv->YBuf1offset + (pitch2 * width);
1200            pPriv->VBuf1offset = pPriv->UBuf1offset + (pitch2 * width / 2);
1201        } else {
1202            pPriv->UBuf0offset = pPriv->YBuf0offset + (pitch2 * height);
1203            pPriv->VBuf0offset = pPriv->UBuf0offset + (pitch2 * height / 2);
1204            pPriv->UBuf1offset = pPriv->YBuf1offset + (pitch2 * height);
1205            pPriv->VBuf1offset = pPriv->UBuf1offset + (pitch2 * height / 2);
1206        }
1207    }
1208
1209#if USE_DISPLAY_C_SPRITE
1210    if (fourcc == FOURCC_RGBA   \
1211        || (fourcc == FOURCC_XVVA   \
1212            && (pPriv->rotation != RR_Rotate_0) \
1213            && (vaPtr->dst_srf.fourcc == VA_FOURCC_RGBA)))
1214        i830_display_video_sprite(pScrn, crtc, width, height, dstPitch,
1215                                  &dstBox, sprite_offset);
1216    else
1217#endif
1218        i830_display_video(ctx, pPriv, surface, fourcc, src_w, src_h, pitch2, pitch,
1219                           x1, y1, x2, y2, &dstBox, src_w, src_h,
1220                           drw_w, drw_h, flags, overlayId, pipeId);
1221
1222    // FIXME : do I use two buffers here really?
1223    //    pPriv->curBuf = (pPriv->curBuf + 1) & 1;
1224
1225    return Success;
1226}
1227
1228
1229
1230static void psbPortPrivCreate(PsbPortPrivPtr pPriv)
1231{
1232#if 0
1233    REGION_NULL(pScreen, &pPriv->clip);
1234#endif
1235
1236    /* coeffs defaut value */
1237    pPriv->brightness.Value = OV_BRIGHTNESS_DEFAULT_VALUE;
1238    pPriv->brightness.Fraction = 0;
1239
1240    pPriv->contrast.Value = OV_CONTRAST_DEFAULT_VALUE;
1241    pPriv->contrast.Fraction = 0;
1242
1243    pPriv->hue.Value = OV_HUE_DEFAULT_VALUE;
1244    pPriv->hue.Fraction = 0;
1245
1246    pPriv->saturation.Value = OV_SATURATION_DEFAULT_VALUE;
1247    pPriv->saturation.Fraction = 0;
1248    pPriv->subpicture_enabled = 0;
1249    pPriv->subpicture_enable_mask = 0;
1250    pPriv->overlayA_enabled = 0;
1251    pPriv->overlayC_enabled = 0;
1252    pPriv->overlayA_pipeId = PIPEA;
1253    pPriv->overlayC_pipeId = PIPEB;
1254
1255    /* FIXME: is this right? set up to current screen size */
1256#if 1
1257    pPriv->width_save = 1024;
1258    pPriv->height_save = 600;
1259#endif
1260}
1261
1262static void
1263psbPortPrivDestroy(VADriverContextP ctx, PsbPortPrivPtr pPriv)
1264{
1265    I830StopVideo(ctx);
1266
1267    wsbmBOUnmap(pPriv->wsbo[0]);
1268    wsbmBOUnreference(&pPriv->wsbo[0]);
1269    wsbmBOUnmap(pPriv->wsbo[1]);
1270    wsbmBOUnreference(&pPriv->wsbo[1]);
1271    if (pPriv->is_mfld) {
1272        if (pPriv->p_iep_lite_context)
1273            free(pPriv->p_iep_lite_context);
1274    }
1275    pPriv->p_iep_lite_context = NULL;
1276}
1277
1278static int
1279psbSetupImageVideoOverlay(VADriverContextP ctx, PsbPortPrivPtr pPriv)
1280{
1281    INIT_DRIVER_DATA;
1282    I830OverlayRegPtr overlayA = NULL;
1283    I830OverlayRegPtr overlayC = NULL;
1284    int ret;
1285    psbPortPrivCreate(pPriv);
1286
1287
1288    /* use green as color key by default for android media player */
1289    pPriv->colorKey = driver_data->color_key/*0x0440*/;
1290
1291    /*Bypass color correction. Because these color
1292    correction can be done in pipe color correction in future.*/
1293    pPriv->brightness.Value = 0;   /*-19*/
1294    pPriv->contrast.Value = 0x40;  /*75*/
1295    pPriv->saturation.Value = 0x80;  /*146*/
1296
1297    pPriv->gamma5 = 0xc0c0c0;
1298    pPriv->gamma4 = 0x808080;
1299    pPriv->gamma3 = 0x404040;
1300    pPriv->gamma2 = 0x202020;
1301    pPriv->gamma1 = 0x101010;
1302    pPriv->gamma0 = 0x080808;
1303
1304    pPriv->rotation = VA_ROTATION_NONE;
1305    pPriv->subpic_clear_flag = 1;
1306#if 0
1307    /* gotta uninit this someplace */
1308    REGION_NULL(pScreen, &pPriv->clip);
1309#endif
1310
1311    /* With LFP's we need to detect whether we're in One Line Mode, which
1312     * essentially means a resolution greater than 1024x768, and fix up
1313     * the scaler accordingly.
1314     */
1315    pPriv->scaleRatio = 0x10000;
1316    pPriv->oneLineMode = FALSE;
1317
1318    ret = wsbmGenBuffers(driver_data->main_pool, 2,
1319                         &pPriv->wsbo[0], 64 * 1024, /* 64k alignment */
1320                         WSBM_PL_FLAG_TT);
1321    if (ret)
1322        goto out_err;
1323
1324    ret = wsbmBOData(pPriv->wsbo[0],
1325                     5 * 4096,
1326                     NULL, NULL,
1327                     WSBM_PL_FLAG_TT);
1328    if (ret)
1329        goto out_err_bo0;
1330
1331    pPriv->regmap[0] = wsbmBOMap(pPriv->wsbo[0], WSBM_ACCESS_READ | WSBM_ACCESS_WRITE);
1332    if (!pPriv->regmap[0]) {
1333        goto out_err_bo0;
1334    }
1335
1336    ret = wsbmBOData(pPriv->wsbo[1],
1337                     5 * 4096,
1338                     NULL, NULL,
1339                     WSBM_PL_FLAG_TT);
1340    if (ret)
1341        goto out_err_bo1;
1342
1343    pPriv->regmap[1] = wsbmBOMap(pPriv->wsbo[1], WSBM_ACCESS_READ | WSBM_ACCESS_WRITE);
1344    if (!pPriv->regmap[1]) {
1345        goto out_err_bo1;
1346    }
1347
1348    overlayA = (I830OverlayRegPtr)(pPriv->regmap[0]);
1349    overlayC = (I830OverlayRegPtr)(pPriv->regmap[1]);
1350
1351    if (pPriv->is_mfld) {
1352        driver_data->ble_black_mode.value = 1;
1353        driver_data->ble_white_mode.value = 3;
1354        driver_data->blueStretch_gain.value = 200;
1355        driver_data->skinColorCorrection_gain.value = 100;
1356        driver_data->hue.value = (5.25f * (1 << 25));
1357        driver_data->saturation.value = (1.07f * (1 << 25));
1358        driver_data->brightness.value = (-10.1f * (1 << 10));
1359        driver_data->contrast.value = (0.99f * (1 << 25));
1360    }
1361
1362    return 0;
1363
1364out_err_bo1:
1365    wsbmBOUnreference(&pPriv->wsbo[1]);
1366out_err_bo0:
1367    wsbmBOUnreference(&pPriv->wsbo[0]);
1368
1369out_err:
1370    return -1;
1371}
1372
1373int psb_coverlay_init(VADriverContextP ctx)
1374{
1375#ifndef BAYTRAIL
1376    INIT_DRIVER_DATA;
1377    PsbPortPrivPtr pPriv = &driver_data->coverlay_priv;
1378    struct drm_psb_register_rw_arg regs;
1379    int ret;
1380
1381    memset(pPriv, 0, sizeof(PsbPortPrivRec));
1382    pPriv->is_mfld = (IS_MFLD(driver_data) || IS_MRFL(driver_data));
1383
1384    ret = psbSetupImageVideoOverlay(ctx, pPriv);
1385    if (ret != 0) {
1386        drv_debug_msg(VIDEO_DEBUG_ERROR, "psb_coverlay_init : Create overlay cmd buffer failed.\n");
1387        return -1;
1388    }
1389
1390    if (pPriv->is_mfld && driver_data->is_android) {
1391        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Android ExtVideo: set PIPEB(HDMI)display plane on the bottom.\n");
1392
1393        memset(&regs, 0, sizeof(regs));
1394        regs.display_read_mask = REGRWBITS_DSPBCNTR;
1395        drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
1396        regs.display.dspcntr_b |= DISPPLANE_BOTTOM;
1397        regs.display_write_mask = REGRWBITS_DSPBCNTR;
1398        drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
1399    }
1400
1401    I830ResetVideo(ctx, pPriv);
1402    I830UpdateGamma(ctx, pPriv);
1403#endif
1404    return 0;
1405}
1406
1407int psb_coverlay_stop(VADriverContextP ctx)
1408{
1409    I830StopVideo(ctx);
1410    return 0;
1411}
1412
1413int psb_coverlay_deinit(VADriverContextP ctx)
1414{
1415#ifndef BAYTRAIL
1416    INIT_DRIVER_DATA;
1417    PsbPortPrivPtr pPriv = &driver_data->coverlay_priv;
1418    struct drm_psb_register_rw_arg regs;
1419
1420    if (pPriv->is_mfld && driver_data->is_android) {
1421        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Android ExtVideo: set PIPEB(HDMI)display plane normal.\n");
1422
1423        memset(&regs, 0, sizeof(regs));
1424        regs.display_read_mask = REGRWBITS_DSPBCNTR;
1425        drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
1426        regs.display.dspcntr_b &= ~DISPPLANE_BOTTOM;
1427        regs.display_write_mask = REGRWBITS_DSPBCNTR;
1428        drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
1429    }
1430
1431    psbPortPrivDestroy(ctx, pPriv);
1432#endif
1433    return 0;
1434}
1435
1436VAStatus psb_putsurface_overlay(
1437    VADriverContextP ctx,
1438    VASurfaceID surface,
1439    short srcx,
1440    short srcy,
1441    unsigned short srcw,
1442    unsigned short srch,
1443    short destx,
1444    short desty,
1445    unsigned short destw,
1446    unsigned short desth,
1447    unsigned int flags, /* de-interlacing flags */
1448    int overlayId,
1449    int pipeId
1450)
1451{
1452    INIT_DRIVER_DATA;
1453    object_surface_p obj_surface = SURFACE(surface);
1454    PsbPortPrivPtr pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
1455#if 0
1456    if ((overlayId == OVERLAY_A) && (pPriv->overlayA_pipeId != pipeId)) {
1457        pPriv->overlayA_pipeId = pipeId;
1458        I830SwitchPipe(ctx, OVERLAY_A, pipeId);
1459        drv_debug_msg(VIDEO_DEBUG_GENERAL, "OverlayA switch pipe to %d, stop overlayA first.\n", pipeId);
1460    } else if ((overlayId == OVERLAY_C) && (pPriv->overlayC_pipeId != pipeId)) {
1461        pPriv->overlayC_pipeId = pipeId;
1462        I830SwitchPipe(ctx, OVERLAY_C, pipeId);
1463        drv_debug_msg(VIDEO_DEBUG_GENERAL, "OverlayC switch pipe to %d, stop overlayC first.\n", pipeId);
1464    }
1465#endif
1466    I830PutImage(ctx, surface, srcx, srcy, srcw, srch,
1467                 destx, desty, destw, desth,
1468                 VA_FOURCC_NV12, flags, overlayId, pipeId);
1469
1470    /* current surface is being displayed */
1471    if (driver_data->cur_displaying_surface != VA_INVALID_SURFACE)
1472        driver_data->last_displaying_surface = driver_data->cur_displaying_surface;
1473
1474    if (obj_surface == NULL) {
1475        drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid surface ID: 0x%08x\n", surface);
1476        return VA_STATUS_ERROR_INVALID_SURFACE;
1477    }
1478
1479    obj_surface->display_timestamp = GetTickCount();
1480    driver_data->cur_displaying_surface = surface;
1481
1482    return VA_STATUS_SUCCESS;
1483}
1484