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