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