r128_video.c revision 0496e070
1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif
5
6#include <string.h>
7
8#include "r128.h"
9#include "r128_reg.h"
10
11#ifdef R128DRI
12#include "r128_common.h"
13#include "r128_sarea.h"
14#endif
15
16#include "xf86.h"
17#include "dixstruct.h"
18
19#include <X11/extensions/Xv.h>
20#include "fourcc.h"
21
22#define OFF_DELAY       250  /* milliseconds */
23#define FREE_DELAY      15000
24
25#define OFF_TIMER       0x01
26#define FREE_TIMER      0x02
27#define CLIENT_VIDEO_ON 0x04
28
29#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
30
31static XF86VideoAdaptorPtr R128SetupImageVideo(ScreenPtr);
32static int  R128SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
33static int  R128GetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
34static void R128StopVideo(ScrnInfoPtr, pointer, Bool);
35static void R128QueryBestSize(ScrnInfoPtr, Bool, short, short, short, short,
36			unsigned int *, unsigned int *, pointer);
37static int  R128PutImage(ScrnInfoPtr, short, short, short, short, short,
38			short, short, short, int, unsigned char*, short,
39			short, Bool, RegionPtr, pointer, DrawablePtr);
40static int  R128QueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
41			unsigned short *,  int *, int *);
42
43
44static void R128ResetVideo(ScrnInfoPtr);
45
46static void R128VideoTimerCallback(ScrnInfoPtr pScrn, Time now);
47
48
49#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
50
51static Atom xvBrightness, xvColorKey, xvSaturation, xvDoubleBuffer;
52
53
54typedef struct {
55   int           brightness;
56   int           saturation;
57   Bool          doubleBuffer;
58   unsigned char currentBuffer;
59   void*         BufferHandle;
60   int		 videoOffset;
61   RegionRec     clip;
62   CARD32        colorKey;
63   CARD32        videoStatus;
64   Time          offTime;
65   Time          freeTime;
66   int           ecp_div;
67} R128PortPrivRec, *R128PortPrivPtr;
68
69static void R128ECP(ScrnInfoPtr pScrn, R128PortPrivPtr pPriv)
70{
71    R128InfoPtr     info      = R128PTR(pScrn);
72    unsigned char   *R128MMIO = info->MMIO;
73    int             dot_clock = info->ModeReg.dot_clock_freq;
74
75    if (dot_clock < 12500)      pPriv->ecp_div = 0;
76    else if (dot_clock < 25000) pPriv->ecp_div = 1;
77    else                        pPriv->ecp_div = 2;
78
79    OUTPLLP(pScrn, R128_VCLK_ECP_CNTL, pPriv->ecp_div<<8, ~R128_ECP_DIV_MASK);
80}
81
82void R128InitVideo(ScreenPtr pScreen)
83{
84    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
85    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
86    XF86VideoAdaptorPtr newAdaptor = NULL;
87    int num_adaptors;
88
89    newAdaptor = R128SetupImageVideo(pScreen);
90
91    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
92
93    if(newAdaptor) {
94	if(!num_adaptors) {
95	    num_adaptors = 1;
96	    adaptors = &newAdaptor;
97	} else {
98	    newAdaptors =  /* need to free this someplace */
99		malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
100	    if(newAdaptors) {
101		memcpy(newAdaptors, adaptors, num_adaptors *
102					sizeof(XF86VideoAdaptorPtr));
103		newAdaptors[num_adaptors] = newAdaptor;
104		adaptors = newAdaptors;
105		num_adaptors++;
106	    }
107	}
108    }
109
110    if(num_adaptors)
111	xf86XVScreenInit(pScreen, adaptors, num_adaptors);
112
113    if(newAdaptors)
114	free(newAdaptors);
115}
116
117#define MAXWIDTH 2048
118#define MAXHEIGHT 2048
119
120/* client libraries expect an encoding */
121static XF86VideoEncodingRec DummyEncoding =
122{
123   0,
124   "XV_IMAGE",
125   MAXWIDTH, MAXHEIGHT,
126   {1, 1}
127};
128
129#define NUM_FORMATS 12
130
131static XF86VideoFormatRec Formats[NUM_FORMATS] =
132{
133   {8, TrueColor}, {8, DirectColor}, {8, PseudoColor},
134   {8, GrayScale}, {8, StaticGray}, {8, StaticColor},
135   {15, TrueColor}, {16, TrueColor}, {24, TrueColor},
136   {15, DirectColor}, {16, DirectColor}, {24, DirectColor}
137};
138
139
140#define NUM_ATTRIBUTES 4
141
142static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
143{
144   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
145   {XvSettable | XvGettable, -64, 63, "XV_BRIGHTNESS"},
146   {XvSettable | XvGettable, 0, 31, "XV_SATURATION"},
147   {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"}
148};
149
150#define NUM_IMAGES 4
151
152static XF86ImageRec Images[NUM_IMAGES] =
153{
154	XVIMAGE_YUY2,
155	XVIMAGE_UYVY,
156	XVIMAGE_YV12,
157	XVIMAGE_I420
158};
159
160static void
161R128ResetVideo(ScrnInfoPtr pScrn)
162{
163    R128InfoPtr   info      = R128PTR(pScrn);
164    unsigned char *R128MMIO = info->MMIO;
165    R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr;
166
167
168    OUTREG(R128_OV0_SCALE_CNTL, 0x80000000);
169    OUTREG(R128_OV0_EXCLUSIVE_HORZ, 0);
170    OUTREG(R128_OV0_AUTO_FLIP_CNTL, 0);   /* maybe */
171    OUTREG(R128_OV0_FILTER_CNTL, 0x0000000f);
172    OUTREG(R128_OV0_COLOUR_CNTL, (pPriv->brightness & 0x7f) |
173				 (pPriv->saturation << 8) |
174				 (pPriv->saturation << 16));
175    OUTREG(R128_OV0_GRAPHICS_KEY_MSK, (1 << pScrn->depth) - 1);
176    OUTREG(R128_OV0_GRAPHICS_KEY_CLR, pPriv->colorKey);
177    OUTREG(R128_OV0_KEY_CNTL, R128_GRAPHIC_KEY_FN_NE);
178    OUTREG(R128_OV0_TEST, 0);
179}
180
181
182static XF86VideoAdaptorPtr
183R128AllocAdaptor(ScrnInfoPtr pScrn)
184{
185    XF86VideoAdaptorPtr adapt;
186    R128InfoPtr info = R128PTR(pScrn);
187    R128PortPrivPtr pPriv;
188
189    if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn)))
190	return NULL;
191
192    if(!(pPriv = calloc(1, sizeof(R128PortPrivRec) + sizeof(DevUnion))))
193    {
194	free(adapt);
195	return NULL;
196    }
197
198    adapt->pPortPrivates = (DevUnion*)(&pPriv[1]);
199    adapt->pPortPrivates[0].ptr = (pointer)pPriv;
200
201    xvBrightness   = MAKE_ATOM("XV_BRIGHTNESS");
202    xvSaturation   = MAKE_ATOM("XV_SATURATION");
203    xvColorKey     = MAKE_ATOM("XV_COLORKEY");
204    xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER");
205
206    pPriv->colorKey = info->videoKey;
207    pPriv->doubleBuffer = TRUE;
208    pPriv->videoStatus = 0;
209    pPriv->brightness = 0;
210    pPriv->saturation = 16;
211    pPriv->currentBuffer = 0;
212    R128ECP(pScrn, pPriv);
213
214    return adapt;
215}
216
217static XF86VideoAdaptorPtr
218R128SetupImageVideo(ScreenPtr pScreen)
219{
220    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
221    R128InfoPtr info = R128PTR(pScrn);
222    R128PortPrivPtr pPriv;
223    XF86VideoAdaptorPtr adapt;
224
225    if(!(adapt = R128AllocAdaptor(pScrn)))
226	return NULL;
227
228    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
229    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
230    adapt->name = "ATI Rage128 Video Overlay";
231    adapt->nEncodings = 1;
232    adapt->pEncodings = &DummyEncoding;
233    adapt->nFormats = NUM_FORMATS;
234    adapt->pFormats = Formats;
235    adapt->nPorts = 1;
236    adapt->nAttributes = NUM_ATTRIBUTES;
237    adapt->pAttributes = Attributes;
238    adapt->nImages = NUM_IMAGES;
239    adapt->pImages = Images;
240    adapt->PutVideo = NULL;
241    adapt->PutStill = NULL;
242    adapt->GetVideo = NULL;
243    adapt->GetStill = NULL;
244    adapt->StopVideo = R128StopVideo;
245    adapt->SetPortAttribute = R128SetPortAttribute;
246    adapt->GetPortAttribute = R128GetPortAttribute;
247    adapt->QueryBestSize = R128QueryBestSize;
248    adapt->PutImage = R128PutImage;
249    adapt->QueryImageAttributes = R128QueryImageAttributes;
250
251    info->adaptor = adapt;
252
253    pPriv = (R128PortPrivPtr)(adapt->pPortPrivates[0].ptr);
254    REGION_NULL(pScreen, &(pPriv->clip));
255
256    R128ResetVideo(pScrn);
257
258    return adapt;
259}
260
261static void
262R128StopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
263{
264  R128InfoPtr info = R128PTR(pScrn);
265  unsigned char *R128MMIO = info->MMIO;
266  R128PortPrivPtr pPriv = (R128PortPrivPtr)data;
267
268  REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
269
270  if(cleanup) {
271     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
272	OUTREG(R128_OV0_SCALE_CNTL, 0);
273     }
274     if(pPriv->BufferHandle) {
275        if (!info->useEXA) {
276	   xf86FreeOffscreenLinear((FBLinearPtr) pPriv->BufferHandle);
277	}
278#ifdef USE_EXA
279	else {
280	   exaOffscreenFree(pScrn->pScreen, (ExaOffscreenArea *) pPriv->BufferHandle);
281	}
282#endif
283	pPriv->BufferHandle = NULL;
284     }
285     pPriv->videoStatus = 0;
286  } else {
287     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
288	pPriv->videoStatus |= OFF_TIMER;
289	pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
290     }
291  }
292}
293
294static int
295R128SetPortAttribute(
296  ScrnInfoPtr pScrn,
297  Atom attribute,
298  INT32 value,
299  pointer data
300){
301  R128InfoPtr info = R128PTR(pScrn);
302  unsigned char *R128MMIO = info->MMIO;
303  R128PortPrivPtr pPriv = (R128PortPrivPtr)data;
304
305  if(attribute == xvBrightness) {
306	if((value < -64) || (value > 63))
307	   return BadValue;
308	pPriv->brightness = value;
309
310	OUTREG(R128_OV0_COLOUR_CNTL, (pPriv->brightness & 0x7f) |
311				     (pPriv->saturation << 8) |
312				     (pPriv->saturation << 16));
313  } else
314  if(attribute == xvSaturation) {
315	if((value < 0) || (value > 31))
316	   return BadValue;
317	pPriv->saturation = value;
318
319	OUTREG(R128_OV0_COLOUR_CNTL, (pPriv->brightness & 0x7f) |
320				     (pPriv->saturation << 8) |
321				     (pPriv->saturation << 16));
322  } else
323  if(attribute == xvDoubleBuffer) {
324	if((value < 0) || (value > 1))
325	   return BadValue;
326	pPriv->doubleBuffer = value;
327  } else
328  if(attribute == xvColorKey) {
329	pPriv->colorKey = value;
330	OUTREG(R128_OV0_GRAPHICS_KEY_CLR, pPriv->colorKey);
331
332	REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
333  } else return BadMatch;
334
335  return Success;
336}
337
338static int
339R128GetPortAttribute(
340  ScrnInfoPtr pScrn,
341  Atom attribute,
342  INT32 *value,
343  pointer data
344){
345  R128PortPrivPtr pPriv = (R128PortPrivPtr)data;
346
347  if(attribute == xvBrightness) {
348	*value = pPriv->brightness;
349  } else
350  if(attribute == xvSaturation) {
351	*value = pPriv->saturation;
352  } else
353  if(attribute == xvDoubleBuffer) {
354	*value = pPriv->doubleBuffer ? 1 : 0;
355  } else
356  if(attribute == xvColorKey) {
357	*value = pPriv->colorKey;
358  } else return BadMatch;
359
360  return Success;
361}
362
363
364static void
365R128QueryBestSize(
366  ScrnInfoPtr pScrn,
367  Bool motion,
368  short vid_w, short vid_h,
369  short drw_w, short drw_h,
370  unsigned int *p_w, unsigned int *p_h,
371  pointer data
372){
373   if(vid_w > (drw_w << 4))
374	drw_w = vid_w >> 4;
375   if(vid_h > (drw_h << 4))
376	drw_h = vid_h >> 4;
377
378  *p_w = drw_w;
379  *p_h = drw_h;
380}
381
382
383/*
384 *
385 * R128DMA - abuse the texture blit ioctl to transfer rectangular blocks
386 *
387 * The block is split into 'passes' pieces of 'hpass' lines which fit entirely
388 * into an indirect buffer
389 *
390 */
391
392Bool
393R128DMA(
394  R128InfoPtr info,
395  unsigned char *src,
396  unsigned char *dst,
397  int srcPitch,
398  int dstPitch,
399  int h,
400  int w
401){
402
403#ifdef R128DRI
404
405#define BUFSIZE (R128_BUFFER_SIZE - R128_HOSTDATA_BLIT_OFFSET)
406#define MAXPASSES (MAXHEIGHT/(BUFSIZE/(MAXWIDTH*2))+1)
407
408    unsigned char *fb = (CARD8*)info->FB;
409    unsigned char *buf;
410    int err=-1, i, idx, offset, hpass, passes, srcpassbytes, dstpassbytes;
411    int sizes[MAXPASSES], list[MAXPASSES];
412    drmDMAReq req;
413    drmR128Blit blit;
414
415    /* Verify conditions and bail out as early as possible */
416    if (!info->directRenderingEnabled || !info->DMAForXv)
417        return FALSE;
418
419    if ((hpass = min(h,(BUFSIZE/w))) == 0)
420	return FALSE;
421
422    if ((passes = (h+hpass-1)/hpass) > MAXPASSES)
423        return FALSE;
424
425    /* Request indirect buffers */
426    srcpassbytes = w*hpass;
427
428    req.context		= info->drmCtx;
429    req.send_count	= 0;
430    req.send_list	= NULL;
431    req.send_sizes	= NULL;
432    req.flags		= DRM_DMA_LARGER_OK;
433    req.request_count	= passes;
434    req.request_size	= srcpassbytes + R128_HOSTDATA_BLIT_OFFSET;
435    req.request_list	= &list[0];
436    req.request_sizes	= &sizes[0];
437    req.granted_count	= 0;
438
439    if (drmDMA(info->drmFD, &req))
440        return FALSE;
441
442    if (req.granted_count < passes) {
443        drmFreeBufs(info->drmFD, req.granted_count, req.request_list);
444	return FALSE;
445    }
446
447    /* Copy parts of the block into buffers and fire them */
448    dstpassbytes = hpass*dstPitch;
449    dstPitch /= 8;
450
451    for (i=0, offset=dst-fb; i<passes; i++, offset+=dstpassbytes) {
452        if (i == (passes-1) && (h % hpass) != 0) {
453	    hpass = h % hpass;
454	    srcpassbytes = w*hpass;
455	}
456
457	idx = req.request_list[i];
458	buf = (unsigned char *) info->buffers->list[idx].address + R128_HOSTDATA_BLIT_OFFSET;
459
460	if (srcPitch == w) {
461            memcpy(buf, src, srcpassbytes);
462	    src += srcpassbytes;
463	} else {
464	    int count = hpass;
465	    while(count--) {
466		memcpy(buf, src, w);
467		src += srcPitch;
468		buf += w;
469	    }
470	}
471
472        blit.idx = idx;
473        blit.offset = offset;
474        blit.pitch = dstPitch;
475        blit.format = (R128_DATATYPE_CI8 >> 16);
476        blit.x = (offset % 32);
477        blit.y = 0;
478        blit.width = w;
479        blit.height = hpass;
480
481	if ((err = drmCommandWrite(info->drmFD, DRM_R128_BLIT,
482                                   &blit, sizeof(drmR128Blit))) < 0)
483	    break;
484    }
485
486    drmFreeBufs(info->drmFD, req.granted_count, req.request_list);
487
488    return (err==0) ? TRUE : FALSE;
489
490#else
491
492    /* This is to avoid cluttering the rest of the code with '#ifdef R128DRI' */
493    return FALSE;
494
495#endif	/* R128DRI */
496
497}
498
499
500static void
501R128CopyData422(
502  R128InfoPtr info,
503  unsigned char *src,
504  unsigned char *dst,
505  int srcPitch,
506  int dstPitch,
507  int h,
508  int w
509){
510    w <<= 1;
511
512    /* Attempt data transfer with DMA and fall back to memcpy */
513
514    if (!R128DMA(info, src, dst, srcPitch, dstPitch, h, w)) {
515        while(h--) {
516	    memcpy(dst, src, w);
517	    src += srcPitch;
518	    dst += dstPitch;
519	}
520    }
521}
522
523static void
524R128CopyData420(
525   R128InfoPtr info,
526   unsigned char *src1,
527   unsigned char *src2,
528   unsigned char *src3,
529   unsigned char *dst1,
530   unsigned char *dst2,
531   unsigned char *dst3,
532   int srcPitch,
533   int srcPitch2,
534   int dstPitch,
535   int h,
536   int w
537){
538   int count;
539
540   /* Attempt data transfer with DMA and fall back to memcpy */
541
542   if (!R128DMA(info, src1, dst1, srcPitch, dstPitch, h, w)) {
543       count = h;
544       while(count--) {
545	   memcpy(dst1, src1, w);
546	   src1 += srcPitch;
547	   dst1 += dstPitch;
548       }
549   }
550
551   w >>= 1;
552   h >>= 1;
553   dstPitch >>= 1;
554
555   if (!R128DMA(info, src2, dst2, srcPitch2, dstPitch, h, w)) {
556       count = h;
557       while(count--) {
558	   memcpy(dst2, src2, w);
559	   src2 += srcPitch2;
560	   dst2 += dstPitch;
561       }
562   }
563
564   if (!R128DMA(info, src3, dst3, srcPitch2, dstPitch, h, w)) {
565       count = h;
566       while(count--) {
567	   memcpy(dst3, src3, w);
568	   src3 += srcPitch2;
569	   dst3 += dstPitch;
570       }
571   }
572}
573
574
575static CARD32
576R128AllocateMemory(
577   ScrnInfoPtr pScrn,
578   void **mem_struct,
579   int size
580){
581   R128InfoPtr info = R128PTR(pScrn);
582   ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
583   int offset = 0;
584
585   if(!info->useEXA) {
586        FBLinearPtr linear = *mem_struct;
587        int cpp = info->CurrentLayout.pixel_bytes;
588
589	/* XAA allocates in units of pixels at the screen bpp, so adjust size appropriately. */
590	size = (size + cpp - 1) / cpp;
591
592        if(linear) {
593	     if(linear->size >= size)
594	        return linear->offset * cpp;
595
596	     if(xf86ResizeOffscreenLinear(linear, size))
597	        return linear->offset * cpp;
598
599	     xf86FreeOffscreenLinear(linear);
600        }
601
602
603        linear = xf86AllocateOffscreenLinear(pScreen, size, 8,
604						NULL, NULL, NULL);
605	*mem_struct = linear;
606
607        if(!linear) {
608	     int max_size;
609
610	     xf86QueryLargestOffscreenLinear(pScreen, &max_size, 8,
611						PRIORITY_EXTREME);
612
613	     if(max_size < size)
614	        return 0;
615
616	     xf86PurgeUnlockedOffscreenAreas(pScreen);
617	     linear = xf86AllocateOffscreenLinear(pScreen, size, 8,
618						NULL, NULL, NULL);
619
620	     if(!linear) return 0;
621        }
622
623	offset = linear->offset * cpp;
624   }
625#ifdef USE_EXA
626   else {
627        /* EXA support based on mga driver */
628	ExaOffscreenArea *area = *mem_struct;
629
630	if(area) {
631	     if(area->size >= size)
632	        return area->offset;
633
634	     exaOffscreenFree(pScrn->pScreen, area);
635	}
636
637	area = exaOffscreenAlloc(pScrn->pScreen, size, 64, TRUE, NULL, NULL);
638	*mem_struct = area;
639
640	if(!area) return 0;
641
642	offset = area->offset;
643   }
644#endif
645
646   return offset;
647}
648
649static void
650R128DisplayVideo422(
651    ScrnInfoPtr pScrn,
652    int id,
653    int offset,
654    short width, short height,
655    int pitch,
656    int left, int right, int top,
657    BoxPtr dstBox,
658    short src_w, short src_h,
659    short drw_w, short drw_h
660){
661    R128InfoPtr info = R128PTR(pScrn);
662    unsigned char *R128MMIO = info->MMIO;
663    R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr;
664    int v_inc, h_inc, step_by, tmp, v_inc_shift;
665    int p1_h_accum_init, p23_h_accum_init;
666    int p1_v_accum_init;
667    Bool rmx_active;
668
669    R128ECP(pScrn, pPriv);
670
671    v_inc_shift = 20;
672    if (pScrn->currentMode->Flags & V_INTERLACE)
673        v_inc_shift++;
674    if (pScrn->currentMode->Flags & V_DBLSCAN)
675        v_inc_shift--;
676
677    rmx_active = INREG(R128_FP_VERT_STRETCH) & R128_VERT_STRETCH_ENABLE;
678    if (rmx_active) {
679        v_inc = ((src_h * pScrn->currentMode->CrtcVDisplay / info->PanelYRes) << v_inc_shift) / drw_h;
680    } else {
681        v_inc = (src_h << v_inc_shift) / drw_h;
682    }
683    h_inc = (src_w << (12 + pPriv->ecp_div)) / drw_w;
684    step_by = 1;
685
686    while(h_inc >= (2 << 12)) {
687	step_by++;
688	h_inc >>= 1;
689    }
690
691    /* keep everything in 16.16 */
692
693    offset += ((left >> 16) & ~7) << 1;
694
695    tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3);
696    p1_h_accum_init = ((tmp <<  4) & 0x000f8000) |
697		      ((tmp << 12) & 0xf0000000);
698
699    tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc << 2);
700    p23_h_accum_init = ((tmp <<  4) & 0x000f8000) |
701		       ((tmp << 12) & 0x70000000);
702
703    tmp = (top & 0x0000ffff) + 0x00018000;
704    p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001;
705
706    left = (left >> 16) & 7;
707
708    OUTREG(R128_OV0_REG_LOAD_CNTL, 1);
709    while(!(INREG(R128_OV0_REG_LOAD_CNTL) & (1 << 3)));
710
711    OUTREG(R128_OV0_H_INC, h_inc | ((h_inc >> 1) << 16));
712    OUTREG(R128_OV0_STEP_BY, step_by | (step_by << 8));
713    OUTREG(R128_OV0_Y_X_START, dstBox->x1 | (dstBox->y1 << 16));
714    OUTREG(R128_OV0_Y_X_END,   dstBox->x2 | (dstBox->y2 << 16));
715    OUTREG(R128_OV0_V_INC, v_inc);
716    OUTREG(R128_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16));
717    OUTREG(R128_OV0_VID_BUF_PITCH0_VALUE, pitch);
718    OUTREG(R128_OV0_P1_X_START_END, (width - 1) | (left << 16));
719    left >>= 1; width >>= 1;
720    OUTREG(R128_OV0_P2_X_START_END, (width - 1) | (left << 16));
721    OUTREG(R128_OV0_P3_X_START_END, (width - 1) | (left << 16));
722    OUTREG(R128_OV0_VID_BUF0_BASE_ADRS, offset & 0xfffffff0);
723    OUTREG(R128_OV0_P1_V_ACCUM_INIT, p1_v_accum_init);
724    OUTREG(R128_OV0_P23_V_ACCUM_INIT, 0);
725    OUTREG(R128_OV0_P1_H_ACCUM_INIT, p1_h_accum_init);
726    OUTREG(R128_OV0_P23_H_ACCUM_INIT, p23_h_accum_init);
727
728    if(id == FOURCC_UYVY)
729       OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8C03);
730    else
731       OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8B03);
732
733    OUTREG(R128_OV0_REG_LOAD_CNTL, 0);
734}
735
736static void
737R128DisplayVideo420(
738    ScrnInfoPtr pScrn,
739    short width, short height,
740    int pitch,
741    int offset1, int offset2, int offset3,
742    int left, int right, int top,
743    BoxPtr dstBox,
744    short src_w, short src_h,
745    short drw_w, short drw_h
746){
747    R128InfoPtr info = R128PTR(pScrn);
748    unsigned char *R128MMIO = info->MMIO;
749    R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr;
750    int v_inc, h_inc, step_by, tmp, leftUV, v_inc_shift;
751    int p1_h_accum_init, p23_h_accum_init;
752    int p1_v_accum_init, p23_v_accum_init;
753    Bool rmx_active;
754
755    v_inc_shift = 20;
756    if (pScrn->currentMode->Flags & V_INTERLACE)
757        v_inc_shift++;
758    if (pScrn->currentMode->Flags & V_DBLSCAN)
759        v_inc_shift--;
760
761    rmx_active = INREG(R128_FP_VERT_STRETCH) & R128_VERT_STRETCH_ENABLE;
762    if (rmx_active) {
763        v_inc = ((src_h * pScrn->currentMode->CrtcVDisplay / info->PanelYRes) << v_inc_shift) / drw_h;
764    } else {
765        v_inc = (src_h << v_inc_shift) / drw_h;
766    }
767    h_inc = (src_w << (12 + pPriv->ecp_div)) / drw_w;
768    step_by = 1;
769
770    while(h_inc >= (2 << 12)) {
771	step_by++;
772	h_inc >>= 1;
773    }
774
775    /* keep everything in 16.16 */
776
777    offset1 += (left >> 16) & ~15;
778    offset2 += (left >> 17) & ~15;
779    offset3 += (left >> 17) & ~15;
780
781    tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3);
782    p1_h_accum_init = ((tmp <<  4) & 0x000f8000) |
783		      ((tmp << 12) & 0xf0000000);
784
785    tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc << 2);
786    p23_h_accum_init = ((tmp <<  4) & 0x000f8000) |
787		       ((tmp << 12) & 0x70000000);
788
789    tmp = (top & 0x0000ffff) + 0x00018000;
790    p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001;
791
792    tmp = ((top >> 1) & 0x0000ffff) + 0x00018000;
793    p23_v_accum_init = ((tmp << 4) & 0x01ff8000) | 0x00000001;
794
795    leftUV = (left >> 17) & 15;
796    left = (left >> 16) & 15;
797
798    OUTREG(R128_OV0_REG_LOAD_CNTL, 1);
799    while(!(INREG(R128_OV0_REG_LOAD_CNTL) & (1 << 3)));
800
801    OUTREG(R128_OV0_H_INC, h_inc | ((h_inc >> 1) << 16));
802    OUTREG(R128_OV0_STEP_BY, step_by | (step_by << 8));
803    OUTREG(R128_OV0_Y_X_START, dstBox->x1 | (dstBox->y1 << 16));
804    OUTREG(R128_OV0_Y_X_END,   dstBox->x2 | (dstBox->y2 << 16));
805    OUTREG(R128_OV0_V_INC, v_inc);
806    OUTREG(R128_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16));
807    src_h = (src_h + 1) >> 1;
808    OUTREG(R128_OV0_P23_BLANK_LINES_AT_TOP, 0x000007ff | ((src_h - 1) << 16));
809    OUTREG(R128_OV0_VID_BUF_PITCH0_VALUE, pitch);
810    OUTREG(R128_OV0_VID_BUF_PITCH1_VALUE, pitch >> 1);
811    OUTREG(R128_OV0_P1_X_START_END, (width - 1) | (left << 16));
812    width >>= 1;
813    OUTREG(R128_OV0_P2_X_START_END, (width - 1) | (leftUV << 16));
814    OUTREG(R128_OV0_P3_X_START_END, (width - 1) | (leftUV << 16));
815    OUTREG(R128_OV0_VID_BUF0_BASE_ADRS, offset1 & 0xfffffff0);
816    OUTREG(R128_OV0_VID_BUF1_BASE_ADRS, (offset2 & 0xfffffff0) | 0x00000001);
817    OUTREG(R128_OV0_VID_BUF2_BASE_ADRS, (offset3 & 0xfffffff0) | 0x00000001);
818    OUTREG(R128_OV0_P1_V_ACCUM_INIT, p1_v_accum_init);
819    OUTREG(R128_OV0_P23_V_ACCUM_INIT, p23_v_accum_init);
820    OUTREG(R128_OV0_P1_H_ACCUM_INIT, p1_h_accum_init);
821    OUTREG(R128_OV0_P23_H_ACCUM_INIT, p23_h_accum_init);
822    OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8A03);
823
824    OUTREG(R128_OV0_REG_LOAD_CNTL, 0);
825}
826
827
828
829static int
830R128PutImage(
831  ScrnInfoPtr pScrn,
832  short src_x, short src_y,
833  short drw_x, short drw_y,
834  short src_w, short src_h,
835  short drw_w, short drw_h,
836  int id, unsigned char* buf,
837  short width, short height,
838  Bool Sync,
839  RegionPtr clipBoxes, pointer data,
840  DrawablePtr pDraw
841){
842   R128InfoPtr info = R128PTR(pScrn);
843   R128PortPrivPtr pPriv = (R128PortPrivPtr)data;
844   unsigned char *fb = (CARD8*)info->FB;
845   INT32 xa, xb, ya, yb;
846   int new_size, offset, s1offset, s2offset, s3offset;
847   int srcPitch, srcPitch2, dstPitch;
848   int d1line, d2line, d3line, d1offset, d2offset, d3offset;
849   int top, left, npixels, nlines;
850   BoxRec dstBox;
851   CARD32 tmp;
852#if X_BYTE_ORDER == X_BIG_ENDIAN
853   unsigned char *R128MMIO = info->MMIO;
854   CARD32 config_cntl = INREG(R128_CONFIG_CNTL);
855
856   /* We need to disable byte swapping, or the data gets mangled */
857   OUTREG(R128_CONFIG_CNTL, config_cntl &
858	  ~(APER_0_BIG_ENDIAN_16BPP_SWAP | APER_0_BIG_ENDIAN_32BPP_SWAP));
859#endif
860
861   /*
862    * s1offset, s2offset, s3offset - byte offsets to the Y, U and V planes
863    *                                of the source.
864    *
865    * d1offset, d2offset, d3offset - byte offsets to the Y, U and V planes
866    *                                of the destination.
867    *
868    * offset - byte offset within the framebuffer to where the destination
869    *          is stored.
870    *
871    * d1line, d2line, d3line - byte offsets within the destination to the
872    *                          first displayed scanline in each plane.
873    *
874    */
875
876   if(src_w > (drw_w << 4))
877	drw_w = src_w >> 4;
878   if(src_h > (drw_h << 4))
879	drw_h = src_h >> 4;
880
881   /* Clip */
882   xa = src_x;
883   xb = src_x + src_w;
884   ya = src_y;
885   yb = src_y + src_h;
886
887   dstBox.x1 = drw_x;
888   dstBox.x2 = drw_x + drw_w;
889   dstBox.y1 = drw_y;
890   dstBox.y2 = drw_y + drw_h;
891
892   if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb,
893			     clipBoxes, width, height))
894	return Success;
895
896   dstBox.x1 -= pScrn->frameX0;
897   dstBox.x2 -= pScrn->frameX0;
898   dstBox.y1 -= pScrn->frameY0;
899   dstBox.y2 -= pScrn->frameY0;
900
901   switch(id) {
902   case FOURCC_YV12:
903   case FOURCC_I420:
904	srcPitch = (width + 3) & ~3;
905	srcPitch2 = ((width >> 1) + 3) & ~3;
906	dstPitch = (width + 31) & ~31;  /* of luma */
907	new_size = dstPitch * (height + (height >> 1));
908	s1offset = 0;
909	s2offset = srcPitch * height;
910	s3offset = (srcPitch2 * (height >> 1)) + s2offset;
911	break;
912   case FOURCC_UYVY:
913   case FOURCC_YUY2:
914   default:
915	srcPitch = width << 1;
916	srcPitch2 = 0;
917	dstPitch = ((width << 1) + 15) & ~15;
918	new_size = dstPitch * height;
919	s1offset = 0;
920	s2offset = 0;
921	s3offset = 0;
922	break;
923   }
924
925   if(!(pPriv->videoOffset = R128AllocateMemory(pScrn, &(pPriv->BufferHandle),
926		pPriv->doubleBuffer ? (new_size << 1) : new_size)))
927   {
928	return BadAlloc;
929   }
930
931   pPriv->currentBuffer ^= 1;
932
933    /* copy data */
934   top = ya >> 16;
935   left = (xa >> 16) & ~1;
936   npixels = ((((xb + 0xffff) >> 16) + 1) & ~1) - left;
937
938   offset = pPriv->videoOffset;
939   if(pPriv->doubleBuffer)
940	offset += pPriv->currentBuffer * new_size;
941
942   switch(id) {
943    case FOURCC_YV12:
944    case FOURCC_I420:
945	d1line = top * dstPitch;
946	d2line = (height * dstPitch) + ((top >> 1) * (dstPitch >> 1));
947	d3line = d2line + ((height >> 1) * (dstPitch >> 1));
948
949	top &= ~1;
950
951	d1offset = (top * dstPitch) + left + offset;
952	d2offset = d2line + (left >> 1) + offset;
953	d3offset = d3line + (left >> 1) + offset;
954
955	s1offset += (top * srcPitch) + left;
956	tmp = ((top >> 1) * srcPitch2) + (left >> 1);
957	s2offset += tmp;
958	s3offset += tmp;
959	if(id == FOURCC_YV12) {
960	   tmp = s2offset;
961	   s2offset = s3offset;
962	   s3offset = tmp;
963	}
964
965	nlines = ((((yb + 0xffff) >> 16) + 1) & ~1) - top;
966	R128CopyData420(info, buf + s1offset, buf + s2offset, buf + s3offset,
967			fb + d1offset, fb + d2offset, fb + d3offset,
968			srcPitch, srcPitch2, dstPitch, nlines, npixels);
969	break;
970    case FOURCC_UYVY:
971    case FOURCC_YUY2:
972    default:
973	left <<= 1;
974	d1line = top * dstPitch;
975	d2line = 0;
976	d3line = 0;
977	d1offset = d1line + left + offset;
978	d2offset = 0;
979	d3offset = 0;
980	s1offset += (top * srcPitch) + left;
981	nlines = ((yb + 0xffff) >> 16) - top;
982	R128CopyData422(info, buf + s1offset, fb + d1offset,
983			srcPitch, dstPitch, nlines, npixels);
984	break;
985    }
986
987#if X_BYTE_ORDER == X_BIG_ENDIAN
988    /* restore byte swapping */
989    OUTREG(R128_CONFIG_CNTL, config_cntl);
990#endif
991
992    /* update cliplist */
993    if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
994	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
995	/* draw these */
996	xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
997    }
998
999
1000    switch(id) {
1001     case FOURCC_YV12:
1002     case FOURCC_I420:
1003	R128DisplayVideo420(pScrn, width, height, dstPitch,
1004		     offset + d1line, offset + d2line, offset + d3line,
1005		     xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h);
1006	break;
1007     case FOURCC_UYVY:
1008     case FOURCC_YUY2:
1009     default:
1010	R128DisplayVideo422(pScrn, id, offset + d1line, width, height, dstPitch,
1011		     xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h);
1012	break;
1013    }
1014
1015    pPriv->videoStatus = CLIENT_VIDEO_ON;
1016
1017    info->VideoTimerCallback = R128VideoTimerCallback;
1018
1019    return Success;
1020}
1021
1022
1023static int
1024R128QueryImageAttributes(
1025    ScrnInfoPtr pScrn,
1026    int id,
1027    unsigned short *w, unsigned short *h,
1028    int *pitches, int *offsets
1029){
1030    int size, tmp;
1031
1032    if(*w > MAXWIDTH) *w = MAXWIDTH;
1033    if(*h > MAXHEIGHT) *h = MAXHEIGHT;
1034
1035    *w = (*w + 1) & ~1;
1036    if(offsets) offsets[0] = 0;
1037
1038    switch(id) {
1039    case FOURCC_YV12:
1040    case FOURCC_I420:
1041	*h = (*h + 1) & ~1;
1042	size = (*w + 3) & ~3;
1043	if(pitches) pitches[0] = size;
1044	size *= *h;
1045	if(offsets) offsets[1] = size;
1046	tmp = ((*w >> 1) + 3) & ~3;
1047	if(pitches) pitches[1] = pitches[2] = tmp;
1048	tmp *= (*h >> 1);
1049	size += tmp;
1050	if(offsets) offsets[2] = size;
1051	size += tmp;
1052	break;
1053    case FOURCC_UYVY:
1054    case FOURCC_YUY2:
1055    default:
1056	size = *w << 1;
1057	if(pitches) pitches[0] = size;
1058	size *= *h;
1059	break;
1060    }
1061
1062    return size;
1063}
1064
1065static void
1066R128VideoTimerCallback(ScrnInfoPtr pScrn, Time now)
1067{
1068    R128InfoPtr info = R128PTR(pScrn);
1069    R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr;
1070
1071    if(pPriv->videoStatus & TIMER_MASK) {
1072	if(pPriv->videoStatus & OFF_TIMER) {
1073	    if(pPriv->offTime < now) {
1074		unsigned char *R128MMIO = info->MMIO;
1075		OUTREG(R128_OV0_SCALE_CNTL, 0);
1076		pPriv->videoStatus = FREE_TIMER;
1077		pPriv->freeTime = now + FREE_DELAY;
1078	    }
1079	} else {  /* FREE_TIMER */
1080	    if(pPriv->freeTime < now) {
1081		if(pPriv->BufferHandle) {
1082		   if (!info->useEXA) {
1083		      xf86FreeOffscreenLinear((FBLinearPtr) pPriv->BufferHandle);
1084		   }
1085#ifdef USE_EXA
1086		   else {
1087		      exaOffscreenFree(pScrn->pScreen, (ExaOffscreenArea *) pPriv->BufferHandle);
1088		   }
1089#endif
1090		   pPriv->BufferHandle = NULL;
1091		}
1092		pPriv->videoStatus = 0;
1093		info->VideoTimerCallback = NULL;
1094	    }
1095	}
1096    } else  /* shouldn't get here */
1097	info->VideoTimerCallback = NULL;
1098}
1099