r128_video.c revision 0496e070
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;
62c582b7e3Smrg   CARD32        colorKey;
63c582b7e3Smrg   CARD32        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;
229c582b7e3Smrg    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
408c582b7e3Smrg    unsigned char *fb = (CARD8*)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
57542a55b46Smrgstatic CARD32
576c582b7e3SmrgR128AllocateMemory(
577c582b7e3Smrg   ScrnInfoPtr pScrn,
57842a55b46Smrg   void **mem_struct,
579c582b7e3Smrg   int size
580c582b7e3Smrg){
58142a55b46Smrg   R128InfoPtr info = R128PTR(pScrn);
58242a55b46Smrg   ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
58342a55b46Smrg   int offset = 0;
584c582b7e3Smrg
58542a55b46Smrg   if(!info->useEXA) {
58642a55b46Smrg        FBLinearPtr linear = *mem_struct;
58742a55b46Smrg        int cpp = info->CurrentLayout.pixel_bytes;
588c582b7e3Smrg
58942a55b46Smrg	/* XAA allocates in units of pixels at the screen bpp, so adjust size appropriately. */
59042a55b46Smrg	size = (size + cpp - 1) / cpp;
591c582b7e3Smrg
59242a55b46Smrg        if(linear) {
59342a55b46Smrg	     if(linear->size >= size)
59442a55b46Smrg	        return linear->offset * cpp;
59542a55b46Smrg
59642a55b46Smrg	     if(xf86ResizeOffscreenLinear(linear, size))
59742a55b46Smrg	        return linear->offset * cpp;
598c582b7e3Smrg
59942a55b46Smrg	     xf86FreeOffscreenLinear(linear);
60042a55b46Smrg        }
601c582b7e3Smrg
60242a55b46Smrg
60342a55b46Smrg        linear = xf86AllocateOffscreenLinear(pScreen, size, 8,
604c582b7e3Smrg						NULL, NULL, NULL);
60542a55b46Smrg	*mem_struct = linear;
606c582b7e3Smrg
60742a55b46Smrg        if(!linear) {
60842a55b46Smrg	     int max_size;
609c582b7e3Smrg
61042a55b46Smrg	     xf86QueryLargestOffscreenLinear(pScreen, &max_size, 8,
611c582b7e3Smrg						PRIORITY_EXTREME);
612c582b7e3Smrg
61342a55b46Smrg	     if(max_size < size)
61442a55b46Smrg	        return 0;
615c582b7e3Smrg
61642a55b46Smrg	     xf86PurgeUnlockedOffscreenAreas(pScreen);
61742a55b46Smrg	     linear = xf86AllocateOffscreenLinear(pScreen, size, 8,
618c582b7e3Smrg						NULL, NULL, NULL);
61942a55b46Smrg
62042a55b46Smrg	     if(!linear) return 0;
62142a55b46Smrg        }
62242a55b46Smrg
62342a55b46Smrg	offset = linear->offset * cpp;
62442a55b46Smrg   }
62542a55b46Smrg#ifdef USE_EXA
62642a55b46Smrg   else {
62742a55b46Smrg        /* EXA support based on mga driver */
62842a55b46Smrg	ExaOffscreenArea *area = *mem_struct;
62942a55b46Smrg
63042a55b46Smrg	if(area) {
63142a55b46Smrg	     if(area->size >= size)
63242a55b46Smrg	        return area->offset;
63342a55b46Smrg
63442a55b46Smrg	     exaOffscreenFree(pScrn->pScreen, area);
63542a55b46Smrg	}
63642a55b46Smrg
63742a55b46Smrg	area = exaOffscreenAlloc(pScrn->pScreen, size, 64, TRUE, NULL, NULL);
63842a55b46Smrg	*mem_struct = area;
63942a55b46Smrg
64042a55b46Smrg	if(!area) return 0;
64142a55b46Smrg
64242a55b46Smrg	offset = area->offset;
643c582b7e3Smrg   }
64442a55b46Smrg#endif
645c582b7e3Smrg
64642a55b46Smrg   return offset;
647c582b7e3Smrg}
648c582b7e3Smrg
649c582b7e3Smrgstatic void
650c582b7e3SmrgR128DisplayVideo422(
651c582b7e3Smrg    ScrnInfoPtr pScrn,
652c582b7e3Smrg    int id,
653c582b7e3Smrg    int offset,
654c582b7e3Smrg    short width, short height,
655c582b7e3Smrg    int pitch,
656c582b7e3Smrg    int left, int right, int top,
657c582b7e3Smrg    BoxPtr dstBox,
658c582b7e3Smrg    short src_w, short src_h,
659c582b7e3Smrg    short drw_w, short drw_h
660c582b7e3Smrg){
661c582b7e3Smrg    R128InfoPtr info = R128PTR(pScrn);
662c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
663c582b7e3Smrg    R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr;
66442a55b46Smrg    int v_inc, h_inc, step_by, tmp, v_inc_shift;
665c582b7e3Smrg    int p1_h_accum_init, p23_h_accum_init;
666c582b7e3Smrg    int p1_v_accum_init;
66742a55b46Smrg    Bool rmx_active;
668c582b7e3Smrg
669c582b7e3Smrg    R128ECP(pScrn, pPriv);
670c582b7e3Smrg
67142a55b46Smrg    v_inc_shift = 20;
67242a55b46Smrg    if (pScrn->currentMode->Flags & V_INTERLACE)
67342a55b46Smrg        v_inc_shift++;
67442a55b46Smrg    if (pScrn->currentMode->Flags & V_DBLSCAN)
67542a55b46Smrg        v_inc_shift--;
6760496e070Smrg
67742a55b46Smrg    rmx_active = INREG(R128_FP_VERT_STRETCH) & R128_VERT_STRETCH_ENABLE;
67842a55b46Smrg    if (rmx_active) {
67942a55b46Smrg        v_inc = ((src_h * pScrn->currentMode->CrtcVDisplay / info->PanelYRes) << v_inc_shift) / drw_h;
68042a55b46Smrg    } else {
68142a55b46Smrg        v_inc = (src_h << v_inc_shift) / drw_h;
68242a55b46Smrg    }
683c582b7e3Smrg    h_inc = (src_w << (12 + pPriv->ecp_div)) / drw_w;
684c582b7e3Smrg    step_by = 1;
685c582b7e3Smrg
686c582b7e3Smrg    while(h_inc >= (2 << 12)) {
687c582b7e3Smrg	step_by++;
688c582b7e3Smrg	h_inc >>= 1;
689c582b7e3Smrg    }
690c582b7e3Smrg
691c582b7e3Smrg    /* keep everything in 16.16 */
692c582b7e3Smrg
693c582b7e3Smrg    offset += ((left >> 16) & ~7) << 1;
694c582b7e3Smrg
695c582b7e3Smrg    tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3);
696c582b7e3Smrg    p1_h_accum_init = ((tmp <<  4) & 0x000f8000) |
697c582b7e3Smrg		      ((tmp << 12) & 0xf0000000);
698c582b7e3Smrg
699c582b7e3Smrg    tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc << 2);
700c582b7e3Smrg    p23_h_accum_init = ((tmp <<  4) & 0x000f8000) |
701c582b7e3Smrg		       ((tmp << 12) & 0x70000000);
702c582b7e3Smrg
703c582b7e3Smrg    tmp = (top & 0x0000ffff) + 0x00018000;
704c582b7e3Smrg    p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001;
705c582b7e3Smrg
706c582b7e3Smrg    left = (left >> 16) & 7;
707c582b7e3Smrg
708c582b7e3Smrg    OUTREG(R128_OV0_REG_LOAD_CNTL, 1);
709c582b7e3Smrg    while(!(INREG(R128_OV0_REG_LOAD_CNTL) & (1 << 3)));
710c582b7e3Smrg
711c582b7e3Smrg    OUTREG(R128_OV0_H_INC, h_inc | ((h_inc >> 1) << 16));
712c582b7e3Smrg    OUTREG(R128_OV0_STEP_BY, step_by | (step_by << 8));
713c582b7e3Smrg    OUTREG(R128_OV0_Y_X_START, dstBox->x1 | (dstBox->y1 << 16));
714c582b7e3Smrg    OUTREG(R128_OV0_Y_X_END,   dstBox->x2 | (dstBox->y2 << 16));
715c582b7e3Smrg    OUTREG(R128_OV0_V_INC, v_inc);
716c582b7e3Smrg    OUTREG(R128_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16));
717c582b7e3Smrg    OUTREG(R128_OV0_VID_BUF_PITCH0_VALUE, pitch);
718c582b7e3Smrg    OUTREG(R128_OV0_P1_X_START_END, (width - 1) | (left << 16));
719c582b7e3Smrg    left >>= 1; width >>= 1;
720c582b7e3Smrg    OUTREG(R128_OV0_P2_X_START_END, (width - 1) | (left << 16));
721c582b7e3Smrg    OUTREG(R128_OV0_P3_X_START_END, (width - 1) | (left << 16));
722c582b7e3Smrg    OUTREG(R128_OV0_VID_BUF0_BASE_ADRS, offset & 0xfffffff0);
723c582b7e3Smrg    OUTREG(R128_OV0_P1_V_ACCUM_INIT, p1_v_accum_init);
724c582b7e3Smrg    OUTREG(R128_OV0_P23_V_ACCUM_INIT, 0);
725c582b7e3Smrg    OUTREG(R128_OV0_P1_H_ACCUM_INIT, p1_h_accum_init);
726c582b7e3Smrg    OUTREG(R128_OV0_P23_H_ACCUM_INIT, p23_h_accum_init);
727c582b7e3Smrg
728c582b7e3Smrg    if(id == FOURCC_UYVY)
729c582b7e3Smrg       OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8C03);
730c582b7e3Smrg    else
731c582b7e3Smrg       OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8B03);
732c582b7e3Smrg
733c582b7e3Smrg    OUTREG(R128_OV0_REG_LOAD_CNTL, 0);
734c582b7e3Smrg}
735c582b7e3Smrg
736c582b7e3Smrgstatic void
737c582b7e3SmrgR128DisplayVideo420(
738c582b7e3Smrg    ScrnInfoPtr pScrn,
739c582b7e3Smrg    short width, short height,
740c582b7e3Smrg    int pitch,
741c582b7e3Smrg    int offset1, int offset2, int offset3,
742c582b7e3Smrg    int left, int right, int top,
743c582b7e3Smrg    BoxPtr dstBox,
744c582b7e3Smrg    short src_w, short src_h,
745c582b7e3Smrg    short drw_w, short drw_h
746c582b7e3Smrg){
747c582b7e3Smrg    R128InfoPtr info = R128PTR(pScrn);
748c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
749c582b7e3Smrg    R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr;
75042a55b46Smrg    int v_inc, h_inc, step_by, tmp, leftUV, v_inc_shift;
751c582b7e3Smrg    int p1_h_accum_init, p23_h_accum_init;
752c582b7e3Smrg    int p1_v_accum_init, p23_v_accum_init;
75342a55b46Smrg    Bool rmx_active;
75442a55b46Smrg
75542a55b46Smrg    v_inc_shift = 20;
75642a55b46Smrg    if (pScrn->currentMode->Flags & V_INTERLACE)
75742a55b46Smrg        v_inc_shift++;
75842a55b46Smrg    if (pScrn->currentMode->Flags & V_DBLSCAN)
75942a55b46Smrg        v_inc_shift--;
7600496e070Smrg
76142a55b46Smrg    rmx_active = INREG(R128_FP_VERT_STRETCH) & R128_VERT_STRETCH_ENABLE;
76242a55b46Smrg    if (rmx_active) {
76342a55b46Smrg        v_inc = ((src_h * pScrn->currentMode->CrtcVDisplay / info->PanelYRes) << v_inc_shift) / drw_h;
76442a55b46Smrg    } else {
76542a55b46Smrg        v_inc = (src_h << v_inc_shift) / drw_h;
76642a55b46Smrg    }
767c582b7e3Smrg    h_inc = (src_w << (12 + pPriv->ecp_div)) / drw_w;
768c582b7e3Smrg    step_by = 1;
769c582b7e3Smrg
770c582b7e3Smrg    while(h_inc >= (2 << 12)) {
771c582b7e3Smrg	step_by++;
772c582b7e3Smrg	h_inc >>= 1;
773c582b7e3Smrg    }
774c582b7e3Smrg
775c582b7e3Smrg    /* keep everything in 16.16 */
776c582b7e3Smrg
777c582b7e3Smrg    offset1 += (left >> 16) & ~15;
778c582b7e3Smrg    offset2 += (left >> 17) & ~15;
779c582b7e3Smrg    offset3 += (left >> 17) & ~15;
780c582b7e3Smrg
781c582b7e3Smrg    tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3);
782c582b7e3Smrg    p1_h_accum_init = ((tmp <<  4) & 0x000f8000) |
783c582b7e3Smrg		      ((tmp << 12) & 0xf0000000);
784c582b7e3Smrg
785c582b7e3Smrg    tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc << 2);
786c582b7e3Smrg    p23_h_accum_init = ((tmp <<  4) & 0x000f8000) |
787c582b7e3Smrg		       ((tmp << 12) & 0x70000000);
788c582b7e3Smrg
789c582b7e3Smrg    tmp = (top & 0x0000ffff) + 0x00018000;
790c582b7e3Smrg    p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001;
791c582b7e3Smrg
792c582b7e3Smrg    tmp = ((top >> 1) & 0x0000ffff) + 0x00018000;
793c582b7e3Smrg    p23_v_accum_init = ((tmp << 4) & 0x01ff8000) | 0x00000001;
794c582b7e3Smrg
795c582b7e3Smrg    leftUV = (left >> 17) & 15;
796c582b7e3Smrg    left = (left >> 16) & 15;
797c582b7e3Smrg
798c582b7e3Smrg    OUTREG(R128_OV0_REG_LOAD_CNTL, 1);
799c582b7e3Smrg    while(!(INREG(R128_OV0_REG_LOAD_CNTL) & (1 << 3)));
800c582b7e3Smrg
801c582b7e3Smrg    OUTREG(R128_OV0_H_INC, h_inc | ((h_inc >> 1) << 16));
802c582b7e3Smrg    OUTREG(R128_OV0_STEP_BY, step_by | (step_by << 8));
803c582b7e3Smrg    OUTREG(R128_OV0_Y_X_START, dstBox->x1 | (dstBox->y1 << 16));
804c582b7e3Smrg    OUTREG(R128_OV0_Y_X_END,   dstBox->x2 | (dstBox->y2 << 16));
805c582b7e3Smrg    OUTREG(R128_OV0_V_INC, v_inc);
806c582b7e3Smrg    OUTREG(R128_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16));
807c582b7e3Smrg    src_h = (src_h + 1) >> 1;
808c582b7e3Smrg    OUTREG(R128_OV0_P23_BLANK_LINES_AT_TOP, 0x000007ff | ((src_h - 1) << 16));
809c582b7e3Smrg    OUTREG(R128_OV0_VID_BUF_PITCH0_VALUE, pitch);
810c582b7e3Smrg    OUTREG(R128_OV0_VID_BUF_PITCH1_VALUE, pitch >> 1);
811c582b7e3Smrg    OUTREG(R128_OV0_P1_X_START_END, (width - 1) | (left << 16));
812c582b7e3Smrg    width >>= 1;
813c582b7e3Smrg    OUTREG(R128_OV0_P2_X_START_END, (width - 1) | (leftUV << 16));
814c582b7e3Smrg    OUTREG(R128_OV0_P3_X_START_END, (width - 1) | (leftUV << 16));
815c582b7e3Smrg    OUTREG(R128_OV0_VID_BUF0_BASE_ADRS, offset1 & 0xfffffff0);
816c582b7e3Smrg    OUTREG(R128_OV0_VID_BUF1_BASE_ADRS, (offset2 & 0xfffffff0) | 0x00000001);
817c582b7e3Smrg    OUTREG(R128_OV0_VID_BUF2_BASE_ADRS, (offset3 & 0xfffffff0) | 0x00000001);
818c582b7e3Smrg    OUTREG(R128_OV0_P1_V_ACCUM_INIT, p1_v_accum_init);
819c582b7e3Smrg    OUTREG(R128_OV0_P23_V_ACCUM_INIT, p23_v_accum_init);
820c582b7e3Smrg    OUTREG(R128_OV0_P1_H_ACCUM_INIT, p1_h_accum_init);
821c582b7e3Smrg    OUTREG(R128_OV0_P23_H_ACCUM_INIT, p23_h_accum_init);
822c582b7e3Smrg    OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8A03);
823c582b7e3Smrg
824c582b7e3Smrg    OUTREG(R128_OV0_REG_LOAD_CNTL, 0);
825c582b7e3Smrg}
826c582b7e3Smrg
827c582b7e3Smrg
828c582b7e3Smrg
829c582b7e3Smrgstatic int
830c582b7e3SmrgR128PutImage(
831c582b7e3Smrg  ScrnInfoPtr pScrn,
832c582b7e3Smrg  short src_x, short src_y,
833c582b7e3Smrg  short drw_x, short drw_y,
834c582b7e3Smrg  short src_w, short src_h,
835c582b7e3Smrg  short drw_w, short drw_h,
836c582b7e3Smrg  int id, unsigned char* buf,
837c582b7e3Smrg  short width, short height,
838c582b7e3Smrg  Bool Sync,
839c582b7e3Smrg  RegionPtr clipBoxes, pointer data,
840c582b7e3Smrg  DrawablePtr pDraw
841c582b7e3Smrg){
842c582b7e3Smrg   R128InfoPtr info = R128PTR(pScrn);
843c582b7e3Smrg   R128PortPrivPtr pPriv = (R128PortPrivPtr)data;
844c582b7e3Smrg   unsigned char *fb = (CARD8*)info->FB;
845c582b7e3Smrg   INT32 xa, xb, ya, yb;
846c582b7e3Smrg   int new_size, offset, s1offset, s2offset, s3offset;
847c582b7e3Smrg   int srcPitch, srcPitch2, dstPitch;
848c582b7e3Smrg   int d1line, d2line, d3line, d1offset, d2offset, d3offset;
84942a55b46Smrg   int top, left, npixels, nlines;
850c582b7e3Smrg   BoxRec dstBox;
851c582b7e3Smrg   CARD32 tmp;
852c582b7e3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
853c582b7e3Smrg   unsigned char *R128MMIO = info->MMIO;
854c582b7e3Smrg   CARD32 config_cntl = INREG(R128_CONFIG_CNTL);
855c582b7e3Smrg
856c582b7e3Smrg   /* We need to disable byte swapping, or the data gets mangled */
857c582b7e3Smrg   OUTREG(R128_CONFIG_CNTL, config_cntl &
858c582b7e3Smrg	  ~(APER_0_BIG_ENDIAN_16BPP_SWAP | APER_0_BIG_ENDIAN_32BPP_SWAP));
859c582b7e3Smrg#endif
860c582b7e3Smrg
861c582b7e3Smrg   /*
862c582b7e3Smrg    * s1offset, s2offset, s3offset - byte offsets to the Y, U and V planes
863c582b7e3Smrg    *                                of the source.
864c582b7e3Smrg    *
865c582b7e3Smrg    * d1offset, d2offset, d3offset - byte offsets to the Y, U and V planes
866c582b7e3Smrg    *                                of the destination.
867c582b7e3Smrg    *
868c582b7e3Smrg    * offset - byte offset within the framebuffer to where the destination
869c582b7e3Smrg    *          is stored.
870c582b7e3Smrg    *
871c582b7e3Smrg    * d1line, d2line, d3line - byte offsets within the destination to the
872c582b7e3Smrg    *                          first displayed scanline in each plane.
873c582b7e3Smrg    *
874c582b7e3Smrg    */
875c582b7e3Smrg
876c582b7e3Smrg   if(src_w > (drw_w << 4))
877c582b7e3Smrg	drw_w = src_w >> 4;
878c582b7e3Smrg   if(src_h > (drw_h << 4))
879c582b7e3Smrg	drw_h = src_h >> 4;
880c582b7e3Smrg
881c582b7e3Smrg   /* Clip */
882c582b7e3Smrg   xa = src_x;
883c582b7e3Smrg   xb = src_x + src_w;
884c582b7e3Smrg   ya = src_y;
885c582b7e3Smrg   yb = src_y + src_h;
886c582b7e3Smrg
887c582b7e3Smrg   dstBox.x1 = drw_x;
888c582b7e3Smrg   dstBox.x2 = drw_x + drw_w;
889c582b7e3Smrg   dstBox.y1 = drw_y;
890c582b7e3Smrg   dstBox.y2 = drw_y + drw_h;
891c582b7e3Smrg
892c582b7e3Smrg   if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb,
893c582b7e3Smrg			     clipBoxes, width, height))
894c582b7e3Smrg	return Success;
895c582b7e3Smrg
896c582b7e3Smrg   dstBox.x1 -= pScrn->frameX0;
897c582b7e3Smrg   dstBox.x2 -= pScrn->frameX0;
898c582b7e3Smrg   dstBox.y1 -= pScrn->frameY0;
899c582b7e3Smrg   dstBox.y2 -= pScrn->frameY0;
900c582b7e3Smrg
901c582b7e3Smrg   switch(id) {
902c582b7e3Smrg   case FOURCC_YV12:
903c582b7e3Smrg   case FOURCC_I420:
904c582b7e3Smrg	srcPitch = (width + 3) & ~3;
905c582b7e3Smrg	srcPitch2 = ((width >> 1) + 3) & ~3;
906c582b7e3Smrg	dstPitch = (width + 31) & ~31;  /* of luma */
90742a55b46Smrg	new_size = dstPitch * (height + (height >> 1));
908c582b7e3Smrg	s1offset = 0;
909c582b7e3Smrg	s2offset = srcPitch * height;
910c582b7e3Smrg	s3offset = (srcPitch2 * (height >> 1)) + s2offset;
911c582b7e3Smrg	break;
912c582b7e3Smrg   case FOURCC_UYVY:
913c582b7e3Smrg   case FOURCC_YUY2:
914c582b7e3Smrg   default:
915c582b7e3Smrg	srcPitch = width << 1;
916c582b7e3Smrg	srcPitch2 = 0;
917c582b7e3Smrg	dstPitch = ((width << 1) + 15) & ~15;
91842a55b46Smrg	new_size = dstPitch * height;
919c582b7e3Smrg	s1offset = 0;
920c582b7e3Smrg	s2offset = 0;
921c582b7e3Smrg	s3offset = 0;
922c582b7e3Smrg	break;
923c582b7e3Smrg   }
924c582b7e3Smrg
92542a55b46Smrg   if(!(pPriv->videoOffset = R128AllocateMemory(pScrn, &(pPriv->BufferHandle),
926c582b7e3Smrg		pPriv->doubleBuffer ? (new_size << 1) : new_size)))
927c582b7e3Smrg   {
928c582b7e3Smrg	return BadAlloc;
929c582b7e3Smrg   }
930c582b7e3Smrg
931c582b7e3Smrg   pPriv->currentBuffer ^= 1;
932c582b7e3Smrg
933c582b7e3Smrg    /* copy data */
934c582b7e3Smrg   top = ya >> 16;
935c582b7e3Smrg   left = (xa >> 16) & ~1;
936c582b7e3Smrg   npixels = ((((xb + 0xffff) >> 16) + 1) & ~1) - left;
937c582b7e3Smrg
93842a55b46Smrg   offset = pPriv->videoOffset;
939c582b7e3Smrg   if(pPriv->doubleBuffer)
94042a55b46Smrg	offset += pPriv->currentBuffer * new_size;
941c582b7e3Smrg
942c582b7e3Smrg   switch(id) {
943c582b7e3Smrg    case FOURCC_YV12:
944c582b7e3Smrg    case FOURCC_I420:
945c582b7e3Smrg	d1line = top * dstPitch;
946c582b7e3Smrg	d2line = (height * dstPitch) + ((top >> 1) * (dstPitch >> 1));
947c582b7e3Smrg	d3line = d2line + ((height >> 1) * (dstPitch >> 1));
948c582b7e3Smrg
949c582b7e3Smrg	top &= ~1;
950c582b7e3Smrg
951c582b7e3Smrg	d1offset = (top * dstPitch) + left + offset;
952c582b7e3Smrg	d2offset = d2line + (left >> 1) + offset;
953c582b7e3Smrg	d3offset = d3line + (left >> 1) + offset;
954c582b7e3Smrg
955c582b7e3Smrg	s1offset += (top * srcPitch) + left;
956c582b7e3Smrg	tmp = ((top >> 1) * srcPitch2) + (left >> 1);
957c582b7e3Smrg	s2offset += tmp;
958c582b7e3Smrg	s3offset += tmp;
959c582b7e3Smrg	if(id == FOURCC_YV12) {
960c582b7e3Smrg	   tmp = s2offset;
961c582b7e3Smrg	   s2offset = s3offset;
962c582b7e3Smrg	   s3offset = tmp;
963c582b7e3Smrg	}
964c582b7e3Smrg
965c582b7e3Smrg	nlines = ((((yb + 0xffff) >> 16) + 1) & ~1) - top;
966c582b7e3Smrg	R128CopyData420(info, buf + s1offset, buf + s2offset, buf + s3offset,
967c582b7e3Smrg			fb + d1offset, fb + d2offset, fb + d3offset,
968c582b7e3Smrg			srcPitch, srcPitch2, dstPitch, nlines, npixels);
969c582b7e3Smrg	break;
970c582b7e3Smrg    case FOURCC_UYVY:
971c582b7e3Smrg    case FOURCC_YUY2:
972c582b7e3Smrg    default:
973c582b7e3Smrg	left <<= 1;
974c582b7e3Smrg	d1line = top * dstPitch;
975c582b7e3Smrg	d2line = 0;
976c582b7e3Smrg	d3line = 0;
977c582b7e3Smrg	d1offset = d1line + left + offset;
978c582b7e3Smrg	d2offset = 0;
979c582b7e3Smrg	d3offset = 0;
980c582b7e3Smrg	s1offset += (top * srcPitch) + left;
981c582b7e3Smrg	nlines = ((yb + 0xffff) >> 16) - top;
982c582b7e3Smrg	R128CopyData422(info, buf + s1offset, fb + d1offset,
983c582b7e3Smrg			srcPitch, dstPitch, nlines, npixels);
984c582b7e3Smrg	break;
985c582b7e3Smrg    }
986c582b7e3Smrg
987c582b7e3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
988c582b7e3Smrg    /* restore byte swapping */
989c582b7e3Smrg    OUTREG(R128_CONFIG_CNTL, config_cntl);
990c582b7e3Smrg#endif
991c582b7e3Smrg
992c582b7e3Smrg    /* update cliplist */
993c582b7e3Smrg    if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
994c582b7e3Smrg	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
995c582b7e3Smrg	/* draw these */
996c582b7e3Smrg	xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
997c582b7e3Smrg    }
998c582b7e3Smrg
999c582b7e3Smrg
1000c582b7e3Smrg    switch(id) {
1001c582b7e3Smrg     case FOURCC_YV12:
1002c582b7e3Smrg     case FOURCC_I420:
1003c582b7e3Smrg	R128DisplayVideo420(pScrn, width, height, dstPitch,
1004c582b7e3Smrg		     offset + d1line, offset + d2line, offset + d3line,
1005c582b7e3Smrg		     xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h);
1006c582b7e3Smrg	break;
1007c582b7e3Smrg     case FOURCC_UYVY:
1008c582b7e3Smrg     case FOURCC_YUY2:
1009c582b7e3Smrg     default:
1010c582b7e3Smrg	R128DisplayVideo422(pScrn, id, offset + d1line, width, height, dstPitch,
1011c582b7e3Smrg		     xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h);
1012c582b7e3Smrg	break;
1013c582b7e3Smrg    }
1014c582b7e3Smrg
1015c582b7e3Smrg    pPriv->videoStatus = CLIENT_VIDEO_ON;
1016c582b7e3Smrg
1017c582b7e3Smrg    info->VideoTimerCallback = R128VideoTimerCallback;
1018c582b7e3Smrg
1019c582b7e3Smrg    return Success;
1020c582b7e3Smrg}
1021c582b7e3Smrg
1022c582b7e3Smrg
1023c582b7e3Smrgstatic int
1024c582b7e3SmrgR128QueryImageAttributes(
1025c582b7e3Smrg    ScrnInfoPtr pScrn,
1026c582b7e3Smrg    int id,
1027c582b7e3Smrg    unsigned short *w, unsigned short *h,
1028c582b7e3Smrg    int *pitches, int *offsets
1029c582b7e3Smrg){
1030c582b7e3Smrg    int size, tmp;
1031c582b7e3Smrg
1032c582b7e3Smrg    if(*w > MAXWIDTH) *w = MAXWIDTH;
1033c582b7e3Smrg    if(*h > MAXHEIGHT) *h = MAXHEIGHT;
1034c582b7e3Smrg
1035c582b7e3Smrg    *w = (*w + 1) & ~1;
1036c582b7e3Smrg    if(offsets) offsets[0] = 0;
1037c582b7e3Smrg
1038c582b7e3Smrg    switch(id) {
1039c582b7e3Smrg    case FOURCC_YV12:
1040c582b7e3Smrg    case FOURCC_I420:
1041c582b7e3Smrg	*h = (*h + 1) & ~1;
1042c582b7e3Smrg	size = (*w + 3) & ~3;
1043c582b7e3Smrg	if(pitches) pitches[0] = size;
1044c582b7e3Smrg	size *= *h;
1045c582b7e3Smrg	if(offsets) offsets[1] = size;
1046c582b7e3Smrg	tmp = ((*w >> 1) + 3) & ~3;
1047c582b7e3Smrg	if(pitches) pitches[1] = pitches[2] = tmp;
1048c582b7e3Smrg	tmp *= (*h >> 1);
1049c582b7e3Smrg	size += tmp;
1050c582b7e3Smrg	if(offsets) offsets[2] = size;
1051c582b7e3Smrg	size += tmp;
1052c582b7e3Smrg	break;
1053c582b7e3Smrg    case FOURCC_UYVY:
1054c582b7e3Smrg    case FOURCC_YUY2:
1055c582b7e3Smrg    default:
1056c582b7e3Smrg	size = *w << 1;
1057c582b7e3Smrg	if(pitches) pitches[0] = size;
1058c582b7e3Smrg	size *= *h;
1059c582b7e3Smrg	break;
1060c582b7e3Smrg    }
1061c582b7e3Smrg
1062c582b7e3Smrg    return size;
1063c582b7e3Smrg}
1064c582b7e3Smrg
1065c582b7e3Smrgstatic void
1066c582b7e3SmrgR128VideoTimerCallback(ScrnInfoPtr pScrn, Time now)
1067c582b7e3Smrg{
1068c582b7e3Smrg    R128InfoPtr info = R128PTR(pScrn);
1069c582b7e3Smrg    R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr;
1070c582b7e3Smrg
1071c582b7e3Smrg    if(pPriv->videoStatus & TIMER_MASK) {
1072c582b7e3Smrg	if(pPriv->videoStatus & OFF_TIMER) {
1073c582b7e3Smrg	    if(pPriv->offTime < now) {
1074c582b7e3Smrg		unsigned char *R128MMIO = info->MMIO;
1075c582b7e3Smrg		OUTREG(R128_OV0_SCALE_CNTL, 0);
1076c582b7e3Smrg		pPriv->videoStatus = FREE_TIMER;
1077c582b7e3Smrg		pPriv->freeTime = now + FREE_DELAY;
1078c582b7e3Smrg	    }
1079c582b7e3Smrg	} else {  /* FREE_TIMER */
1080c582b7e3Smrg	    if(pPriv->freeTime < now) {
108142a55b46Smrg		if(pPriv->BufferHandle) {
108242a55b46Smrg		   if (!info->useEXA) {
108342a55b46Smrg		      xf86FreeOffscreenLinear((FBLinearPtr) pPriv->BufferHandle);
108442a55b46Smrg		   }
108542a55b46Smrg#ifdef USE_EXA
108642a55b46Smrg		   else {
108742a55b46Smrg		      exaOffscreenFree(pScrn->pScreen, (ExaOffscreenArea *) pPriv->BufferHandle);
108842a55b46Smrg		   }
108942a55b46Smrg#endif
109042a55b46Smrg		   pPriv->BufferHandle = NULL;
1091c582b7e3Smrg		}
1092c582b7e3Smrg		pPriv->videoStatus = 0;
1093c582b7e3Smrg		info->VideoTimerCallback = NULL;
1094c582b7e3Smrg	    }
1095c582b7e3Smrg	}
1096c582b7e3Smrg    } else  /* shouldn't get here */
1097c582b7e3Smrg	info->VideoTimerCallback = NULL;
1098c582b7e3Smrg}
1099