1 /*
2  * Copyright 2006 Joseph Garvin
3  * Copyright 2012 Connor Behan
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  *
25  * Authors:
26  *    Joseph Garvin <joseph.h.garvin@gmail.com>
27  *    Connor Behan <connor.behan@gmail.com>
28  *
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 
35 #include "r128.h"
36 #include "exa.h"
37 
38 #include "r128_reg.h"
39 #include "r128_rop.h"
40 
41 #include "xf86.h"
42 
43 /* Assumes that depth 15 and 16 can be used as depth 16, which is okay since we
44  * require src and dest datatypes to be equal.
45  */
R128GetDatatypeBpp(int bpp,uint32_t * type)46 Bool R128GetDatatypeBpp(int bpp, uint32_t *type)
47 {
48     switch (bpp) {
49     case 8:
50         *type = R128_DATATYPE_CI8;
51         return TRUE;
52     case 16:
53         *type = R128_DATATYPE_RGB565;
54         return TRUE;
55     case 24:
56         *type = R128_DATATYPE_RGB888;
57         return TRUE;
58     case 32:
59         *type = R128_DATATYPE_ARGB8888;
60         return TRUE;
61     default:
62         return FALSE;
63     }
64 }
65 
R128GetOffsetPitch(PixmapPtr pPix,int bpp,uint32_t * pitch_offset,unsigned int offset,unsigned int pitch)66 static Bool R128GetOffsetPitch(PixmapPtr pPix, int bpp, uint32_t *pitch_offset,
67 				 unsigned int offset, unsigned int pitch)
68 {
69     ScreenPtr     pScreen   = pPix->drawable.pScreen;
70     ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
71     R128InfoPtr   info      = R128PTR(pScrn);
72 
73     if (pitch > 16320 || pitch % info->ExaDriver->pixmapPitchAlign != 0) {
74         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
75                             "Bad pitch 0x%08x\n", pitch));
76 	return FALSE;
77     }
78 
79     if (offset % info->ExaDriver->pixmapOffsetAlign != 0) {
80         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
81                             "Bad offset 0x%08x\n", offset));
82 	return FALSE;
83     }
84 
85     *pitch_offset = ((pitch / bpp) << 21) | (offset >> 5);
86 
87     return TRUE;
88 }
89 
R128GetPixmapOffsetPitch(PixmapPtr pPix,uint32_t * pitch_offset)90 Bool R128GetPixmapOffsetPitch(PixmapPtr pPix, uint32_t *pitch_offset)
91 {
92     uint32_t pitch, offset;
93     int bpp;
94 
95     bpp = pPix->drawable.bitsPerPixel;
96     if (bpp == 24)
97         bpp = 8;
98 
99     offset = exaGetPixmapOffset(pPix);
100     pitch = exaGetPixmapPitch(pPix);
101 
102     return R128GetOffsetPitch(pPix, bpp, pitch_offset, offset, pitch);
103 }
104 
Emit2DState(ScrnInfoPtr pScrn)105 static void Emit2DState(ScrnInfoPtr pScrn)
106 {
107     R128InfoPtr   info      = R128PTR(pScrn);
108     int has_src		    = info->state_2d.src_pitch_offset;
109     unsigned char *R128MMIO = info->MMIO;
110 
111     R128WaitForFifo(pScrn, (has_src ? 10 : 9));
112 
113     OUTREG(R128_DEFAULT_SC_BOTTOM_RIGHT, info->state_2d.default_sc_bottom_right);
114     OUTREG(R128_DP_GUI_MASTER_CNTL, info->state_2d.dp_gui_master_cntl);
115     OUTREG(R128_DP_BRUSH_FRGD_CLR, info->state_2d.dp_brush_frgd_clr);
116     OUTREG(R128_DP_BRUSH_BKGD_CLR, info->state_2d.dp_brush_bkgd_clr);
117     OUTREG(R128_DP_SRC_FRGD_CLR,   info->state_2d.dp_src_frgd_clr);
118     OUTREG(R128_DP_SRC_BKGD_CLR,   info->state_2d.dp_src_bkgd_clr);
119     OUTREG(R128_DP_WRITE_MASK, info->state_2d.dp_write_mask);
120     OUTREG(R128_DP_CNTL, info->state_2d.dp_cntl);
121 
122     OUTREG(R128_DST_PITCH_OFFSET, info->state_2d.dst_pitch_offset);
123     if (has_src) OUTREG(R128_SRC_PITCH_OFFSET, info->state_2d.src_pitch_offset);
124 }
125 
126 #ifdef R128DRI
EmitCCE2DState(ScrnInfoPtr pScrn)127 void EmitCCE2DState(ScrnInfoPtr pScrn)
128 {
129     R128InfoPtr   info      = R128PTR(pScrn);
130     int has_src		    = info->state_2d.src_pitch_offset;
131     RING_LOCALS;
132 
133     R128CCE_REFRESH( pScrn, info );
134 
135     BEGIN_RING( (has_src ? 20 : 18) );
136 
137     OUT_RING_REG( R128_DEFAULT_SC_BOTTOM_RIGHT, info->state_2d.default_sc_bottom_right );
138     OUT_RING_REG( R128_DP_GUI_MASTER_CNTL, info->state_2d.dp_gui_master_cntl );
139     OUT_RING_REG( R128_DP_BRUSH_FRGD_CLR, info->state_2d.dp_brush_frgd_clr );
140     OUT_RING_REG( R128_DP_BRUSH_BKGD_CLR, info->state_2d.dp_brush_bkgd_clr );
141     OUT_RING_REG( R128_DP_SRC_FRGD_CLR,   info->state_2d.dp_src_frgd_clr );
142     OUT_RING_REG( R128_DP_SRC_BKGD_CLR,   info->state_2d.dp_src_bkgd_clr );
143     OUT_RING_REG( R128_DP_WRITE_MASK, info->state_2d.dp_write_mask );
144     OUT_RING_REG( R128_DP_CNTL, info->state_2d.dp_cntl );
145 
146     OUT_RING_REG( R128_DST_PITCH_OFFSET, info->state_2d.dst_pitch_offset );
147     if (has_src) OUT_RING_REG( R128_SRC_PITCH_OFFSET, info->state_2d.src_pitch_offset );
148 
149     ADVANCE_RING();
150 }
151 #endif
152 
153 /* EXA Callbacks */
154 
155 static Bool
R128PrepareSolid(PixmapPtr pPixmap,int alu,Pixel planemask,Pixel fg)156 R128PrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg)
157 {
158     ScreenPtr     pScreen   = pPixmap->drawable.pScreen;
159     ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
160     R128InfoPtr   info      = R128PTR(pScrn);
161 
162     int bpp = pPixmap->drawable.bitsPerPixel;
163     uint32_t datatype, dst_pitch_offset;
164 
165     if (!R128GetDatatypeBpp(bpp, &datatype)) {
166         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
167                             "R128GetDatatypeBpp failed\n"));
168 	return FALSE;
169     }
170     if (!R128GetPixmapOffsetPitch(pPixmap, &dst_pitch_offset)) {
171         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
172                             "R128GetPixmapOffsetPitch failed\n"));
173 	return FALSE;
174     }
175     if (info->state_2d.in_use) return FALSE;
176 
177     info->state_2d.in_use = TRUE;
178     info->state_2d.default_sc_bottom_right = (R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX);
179     info->state_2d.dp_brush_bkgd_clr = 0x00000000;
180     info->state_2d.dp_src_frgd_clr = 0xffffffff;
181     info->state_2d.dp_src_bkgd_clr = 0x00000000;
182     info->state_2d.dp_gui_master_cntl = (R128_GMC_DST_PITCH_OFFSET_CNTL |
183 					  R128_GMC_BRUSH_SOLID_COLOR |
184 					  (datatype >> 8) |
185 					  R128_GMC_SRC_DATATYPE_COLOR |
186 					  R128_ROP[alu].pattern |
187 					  R128_GMC_CLR_CMP_CNTL_DIS);
188     info->state_2d.dp_brush_frgd_clr = fg;
189     info->state_2d.dp_cntl = (R128_DST_X_LEFT_TO_RIGHT | R128_DST_Y_TOP_TO_BOTTOM);
190     info->state_2d.dp_write_mask = planemask;
191     info->state_2d.dst_pitch_offset = dst_pitch_offset;
192     info->state_2d.src_pitch_offset = 0;
193 
194 #ifdef R128DRI
195     if (info->directRenderingEnabled) {
196         EmitCCE2DState(pScrn);
197     } else
198 #endif
199     {
200         Emit2DState(pScrn);
201     }
202     return TRUE;
203 }
204 
205 static void
R128Solid(PixmapPtr pPixmap,int x1,int y1,int x2,int y2)206 R128Solid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
207 {
208     ScreenPtr     pScreen   = pPixmap->drawable.pScreen;
209     ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
210     R128InfoPtr   info      = R128PTR(pScrn);
211     unsigned char *R128MMIO = info->MMIO;
212 
213     R128WaitForFifo(pScrn, 2);
214     OUTREG(R128_DST_Y_X,          (y1 << 16) | x1);
215     OUTREG(R128_DST_WIDTH_HEIGHT, ((x2-x1) << 16) | (y2-y1));
216 }
217 
218 #define R128DoneSolid R128Done
219 
220 void
R128DoPrepareCopy(ScrnInfoPtr pScrn,uint32_t src_pitch_offset,uint32_t dst_pitch_offset,uint32_t datatype,int alu,Pixel planemask)221 R128DoPrepareCopy(ScrnInfoPtr pScrn, uint32_t src_pitch_offset,
222 			uint32_t dst_pitch_offset, uint32_t datatype, int alu, Pixel planemask)
223 {
224     R128InfoPtr   info      = R128PTR(pScrn);
225 
226     info->state_2d.in_use = TRUE;
227     info->state_2d.dp_gui_master_cntl = (R128_GMC_DST_PITCH_OFFSET_CNTL |
228 					  R128_GMC_SRC_PITCH_OFFSET_CNTL |
229 					  R128_GMC_BRUSH_NONE |
230 					  (datatype >> 8) |
231 					  R128_GMC_SRC_DATATYPE_COLOR |
232 					  R128_ROP[alu].rop |
233 					  R128_DP_SRC_SOURCE_MEMORY |
234 					  R128_GMC_CLR_CMP_CNTL_DIS);
235     info->state_2d.dp_cntl = ((info->xdir >= 0 ? R128_DST_X_LEFT_TO_RIGHT : 0) |
236 			       (info->ydir >= 0 ? R128_DST_Y_TOP_TO_BOTTOM : 0));
237     info->state_2d.dp_brush_frgd_clr = 0xffffffff;
238     info->state_2d.dp_brush_bkgd_clr = 0x00000000;
239     info->state_2d.dp_src_frgd_clr = 0xffffffff;
240     info->state_2d.dp_src_bkgd_clr = 0x00000000;
241     info->state_2d.dp_write_mask = planemask;
242     info->state_2d.dst_pitch_offset = dst_pitch_offset;
243     info->state_2d.src_pitch_offset = src_pitch_offset;
244     info->state_2d.default_sc_bottom_right = (R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX);
245 
246 #ifdef R128DRI
247     if (info->directRenderingEnabled) {
248         EmitCCE2DState(pScrn);
249     } else
250 #endif
251     {
252         Emit2DState(pScrn);
253     }
254 }
255 
256 static Bool
R128PrepareCopy(PixmapPtr pSrcPixmap,PixmapPtr pDstPixmap,int xdir,int ydir,int alu,Pixel planemask)257 R128PrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, int ydir, int alu, Pixel planemask)
258 {
259     ScreenPtr     pScreen   = pSrcPixmap->drawable.pScreen;
260     ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
261     R128InfoPtr   info      = R128PTR(pScrn);
262 
263     int bpp = pDstPixmap->drawable.bitsPerPixel;
264     uint32_t datatype, src_pitch_offset, dst_pitch_offset;
265 
266     if (!R128GetDatatypeBpp(bpp, &datatype)) {
267         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
268                             "R128GetDatatypeBpp failed\n"));
269 	return FALSE;
270     }
271     if (!R128GetPixmapOffsetPitch(pSrcPixmap, &src_pitch_offset)) {
272         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
273                             "R128GetPixmapOffsetPitch source "
274                             "failed\n"));
275 	return FALSE;
276     }
277     if (!R128GetPixmapOffsetPitch(pDstPixmap, &dst_pitch_offset)) {
278         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
279                             "R128GetPixmapOffsetPitch dest failed\n"));
280 	return FALSE;
281     }
282     if (info->state_2d.in_use) return FALSE;
283 
284     info->xdir = xdir;
285     info->ydir = ydir;
286 
287     R128DoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset, datatype, alu, planemask);
288 
289     return TRUE;
290 }
291 
292 static void
R128Copy(PixmapPtr pDstPixmap,int srcX,int srcY,int dstX,int dstY,int width,int height)293 R128Copy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY, int width, int height)
294 {
295     ScreenPtr     pScreen   = pDstPixmap->drawable.pScreen;
296     ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
297     R128InfoPtr   info      = R128PTR(pScrn);
298     unsigned char *R128MMIO = info->MMIO;
299 
300     if (info->xdir < 0) srcX += width - 1, dstX += width - 1;
301     if (info->ydir < 0) srcY += height - 1, dstY += height - 1;
302 
303     R128WaitForFifo(pScrn, 3);
304     OUTREG(R128_SRC_Y_X,          (srcY << 16) | srcX);
305     OUTREG(R128_DST_Y_X,          (dstY << 16) | dstX);
306     OUTREG(R128_DST_HEIGHT_WIDTH, (height << 16) | width);
307 }
308 
309 #define R128DoneCopy R128Done
310 
311 static void
R128Sync(ScreenPtr pScreen,int marker)312 R128Sync(ScreenPtr pScreen, int marker)
313 {
314     R128WaitForIdle(xf86ScreenToScrn(pScreen));
315 }
316 
317 void
R128Done(PixmapPtr pPixmap)318 R128Done(PixmapPtr pPixmap)
319 {
320     ScreenPtr     pScreen   = pPixmap->drawable.pScreen;
321     ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
322     R128InfoPtr   info      = R128PTR(pScrn);
323 
324     info->state_2d.in_use = FALSE;
325 #if defined(R128DRI) && defined(RENDER)
326     if (info->state_2d.src_pix) {
327         pScreen->DestroyPixmap(info->state_2d.src_pix);
328 	info->state_2d.src_pix = NULL;
329     }
330     if (info->state_2d.msk_pix) {
331         pScreen->DestroyPixmap(info->state_2d.msk_pix);
332 	info->state_2d.msk_pix = NULL;
333     }
334 #endif
335 }
336 
337 #ifdef R128DRI
338 
339 #define R128CCEPrepareSolid R128PrepareSolid
340 
341 static void
R128CCESolid(PixmapPtr pPixmap,int x1,int y1,int x2,int y2)342 R128CCESolid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
343 {
344     ScreenPtr     pScreen   = pPixmap->drawable.pScreen;
345     ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
346     R128InfoPtr   info      = R128PTR(pScrn);
347     RING_LOCALS;
348 
349     R128CCE_REFRESH( pScrn, info );
350 
351     BEGIN_RING( 4 );
352 
353     OUT_RING_REG( R128_DST_Y_X,          (y1 << 16) | x1 );
354     OUT_RING_REG( R128_DST_WIDTH_HEIGHT, ((x2-x1) << 16) | (y2-y1) );
355 
356     ADVANCE_RING();
357 }
358 
359 #define R128CCEDoneSolid R128Done
360 
361 #define R128CCEPrepareCopy R128PrepareCopy
362 
363 static void
R128CCECopy(PixmapPtr pDstPixmap,int srcX,int srcY,int dstX,int dstY,int width,int height)364 R128CCECopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY,
365 	 int width, int height)
366 {
367     ScreenPtr     pScreen   = pDstPixmap->drawable.pScreen;
368     ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
369     R128InfoPtr   info      = R128PTR(pScrn);
370     RING_LOCALS;
371 
372     R128CCE_REFRESH( pScrn, info );
373 
374     if (info->xdir < 0) srcX += width - 1, dstX += width - 1;
375     if (info->ydir < 0) srcY += height - 1, dstY += height - 1;
376 
377     BEGIN_RING( 6 );
378 
379     OUT_RING_REG( R128_SRC_Y_X,          (srcY << 16) | srcX );
380     OUT_RING_REG( R128_DST_Y_X,          (dstY << 16) | dstX );
381     OUT_RING_REG( R128_DST_HEIGHT_WIDTH, (height << 16) | width );
382 
383     ADVANCE_RING();
384 }
385 
386 #define R128CCEDoneCopy R128Done
387 
388 static void
R128CCESync(ScreenPtr pScreen,int marker)389 R128CCESync(ScreenPtr pScreen, int marker)
390 {
391     R128CCEWaitForIdle(xf86ScreenToScrn(pScreen));
392 }
393 
394 #endif
395 
396 Bool
R128EXAInit(ScreenPtr pScreen,int total)397 R128EXAInit(ScreenPtr pScreen, int total)
398 {
399     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
400     R128InfoPtr info  = R128PTR(pScrn);
401 
402     info->ExaDriver = exaDriverAlloc();
403     if (!info->ExaDriver) {
404         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
405                     "Could not allocate EXA driver...\n");
406         return FALSE;
407     }
408 
409     info->ExaDriver->exa_major = EXA_VERSION_MAJOR;
410     info->ExaDriver->exa_minor = EXA_VERSION_MINOR;
411 
412     info->ExaDriver->memoryBase = info->FB + pScrn->fbOffset;
413     info->ExaDriver->offScreenBase = pScrn->virtualY *
414                                         (pScrn->displayWidth *
415                                         info->CurrentLayout.pixel_bytes);
416     info->ExaDriver->memorySize = total;
417     info->ExaDriver->flags = EXA_OFFSCREEN_PIXMAPS | EXA_OFFSCREEN_ALIGN_POT;
418 
419 #if EXA_VERSION_MAJOR > 2 || (EXA_VERSION_MAJOR == 2 && EXA_VERSION_MINOR >= 3)
420     info->ExaDriver->maxPitchBytes = 16320;
421 #endif
422     /* Pitch alignment is in sets of 8 pixels, and we need to cover 32bpp, so it's 32 bytes */
423     info->ExaDriver->pixmapPitchAlign = 32;
424     info->ExaDriver->pixmapOffsetAlign = 32;
425     info->ExaDriver->maxX = 2048;
426     info->ExaDriver->maxY = 2048;
427 
428     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
429 	       "Setting up EXA callbacks\n");
430 
431 #ifdef R128DRI
432     if (info->directRenderingEnabled) {
433 	info->ExaDriver->PrepareSolid = R128CCEPrepareSolid;
434 	info->ExaDriver->Solid = R128CCESolid;
435 	info->ExaDriver->DoneSolid = R128CCEDoneSolid;
436 
437 	info->ExaDriver->PrepareCopy = R128CCEPrepareCopy;
438 	info->ExaDriver->Copy = R128CCECopy;
439 	info->ExaDriver->DoneCopy = R128CCEDoneCopy;
440 
441 #ifdef RENDER
442 	if (info->RenderAccel) {
443 	    info->ExaDriver->CheckComposite = R128CCECheckComposite;
444 	    info->ExaDriver->PrepareComposite = R128CCEPrepareComposite;
445 	    info->ExaDriver->Composite = R128CCEComposite;
446 	    info->ExaDriver->DoneComposite = R128CCEDoneComposite;
447 	}
448 #endif
449 
450 	info->ExaDriver->WaitMarker = R128CCESync;
451     } else
452 #endif
453     {
454 	info->ExaDriver->PrepareSolid = R128PrepareSolid;
455 	info->ExaDriver->Solid = R128Solid;
456 	info->ExaDriver->DoneSolid = R128DoneSolid;
457 
458 	info->ExaDriver->PrepareCopy = R128PrepareCopy;
459 	info->ExaDriver->Copy = R128Copy;
460 	info->ExaDriver->DoneCopy = R128DoneCopy;
461 
462 	/* The registers used for r128 compositing are CCE specific, just like the
463 	 * registers used for radeon compositing are CP specific. The radeon driver
464 	 * falls back to different registers when there is no DRI. The equivalent
465 	 * registers on the r128 (if they even exist) are not listed in the register
466 	 * file so I can't implement compositing without DRI.
467 	 */
468 
469 	info->ExaDriver->WaitMarker = R128Sync;
470     }
471 
472     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
473 	       "Initializing 2D acceleration engine...\n");
474 
475     R128EngineInit(pScrn);
476 
477     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
478 	       "Initializing EXA driver...\n");
479 
480     if (!exaDriverInit(pScreen, info->ExaDriver)) {
481         free(info->ExaDriver);
482 	return FALSE;
483     }
484 
485     info->state_2d.composite_setup = FALSE;
486     return TRUE;
487 }
488