3 /* the accelerated functions here are patterned after the
4 * "ACCEL_MMIO" ifdef branches in XFree86
8 #define FLUSH_CACHE_WORKAROUND 1
10 void radeon_fifo_update_and_wait(struct radeonfb_info
*rinfo
, int entries
)
14 for (i
=0; i
<2000000; i
++) {
15 rinfo
->fifo_free
= INREG(RBBM_STATUS
) & 0x7f;
16 if (rinfo
->fifo_free
>= entries
)
20 printk(KERN_ERR
"radeonfb: FIFO Timeout !\n");
21 /* XXX Todo: attempt to reset the engine */
24 static inline void radeon_fifo_wait(struct radeonfb_info
*rinfo
, int entries
)
26 if (entries
<= rinfo
->fifo_free
)
27 rinfo
->fifo_free
-= entries
;
29 radeon_fifo_update_and_wait(rinfo
, entries
);
32 static inline void radeonfb_set_creg(struct radeonfb_info
*rinfo
, u32 reg
,
33 u32
*cache
, u32 new_val
)
35 if (new_val
== *cache
)
38 radeon_fifo_wait(rinfo
, 1);
42 static void radeonfb_prim_fillrect(struct radeonfb_info
*rinfo
,
43 const struct fb_fillrect
*region
)
45 radeonfb_set_creg(rinfo
, DP_GUI_MASTER_CNTL
, &rinfo
->dp_gui_mc_cache
,
46 rinfo
->dp_gui_mc_base
| GMC_BRUSH_SOLID_COLOR
| ROP3_P
);
47 radeonfb_set_creg(rinfo
, DP_CNTL
, &rinfo
->dp_cntl_cache
,
48 DST_X_LEFT_TO_RIGHT
| DST_Y_TOP_TO_BOTTOM
);
49 radeonfb_set_creg(rinfo
, DP_BRUSH_FRGD_CLR
, &rinfo
->dp_brush_fg_cache
,
52 /* Ensure the dst cache is flushed and the engine idle before
53 * issuing the operation.
55 * This works around engine lockups on some cards
57 #if FLUSH_CACHE_WORKAROUND
58 radeon_fifo_wait(rinfo
, 2);
59 OUTREG(DSTCACHE_CTLSTAT
, RB2D_DC_FLUSH_ALL
);
60 OUTREG(WAIT_UNTIL
, (WAIT_2D_IDLECLEAN
| WAIT_DMA_GUI_IDLE
));
62 radeon_fifo_wait(rinfo
, 2);
63 OUTREG(DST_Y_X
, (region
->dy
<< 16) | region
->dx
);
64 OUTREG(DST_WIDTH_HEIGHT
, (region
->width
<< 16) | region
->height
);
67 void radeonfb_fillrect(struct fb_info
*info
, const struct fb_fillrect
*region
)
69 struct radeonfb_info
*rinfo
= info
->par
;
70 struct fb_fillrect modded
;
73 WARN_ON(rinfo
->gfx_mode
);
74 if (info
->state
!= FBINFO_STATE_RUNNING
|| rinfo
->gfx_mode
)
76 if (info
->flags
& FBINFO_HWACCEL_DISABLED
) {
77 cfb_fillrect(info
, region
);
81 vxres
= info
->var
.xres_virtual
;
82 vyres
= info
->var
.yres_virtual
;
84 memcpy(&modded
, region
, sizeof(struct fb_fillrect
));
86 if(!modded
.width
|| !modded
.height
||
87 modded
.dx
>= vxres
|| modded
.dy
>= vyres
)
90 if(modded
.dx
+ modded
.width
> vxres
) modded
.width
= vxres
- modded
.dx
;
91 if(modded
.dy
+ modded
.height
> vyres
) modded
.height
= vyres
- modded
.dy
;
93 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
||
94 info
->fix
.visual
== FB_VISUAL_DIRECTCOLOR
)
95 modded
.color
= ((u32
*) (info
->pseudo_palette
))[region
->color
];
97 radeonfb_prim_fillrect(rinfo
, &modded
);
100 static void radeonfb_prim_copyarea(struct radeonfb_info
*rinfo
,
101 const struct fb_copyarea
*area
)
104 u32 sx
, sy
, dx
, dy
, w
, h
;
106 w
= area
->width
; h
= area
->height
;
107 dx
= area
->dx
; dy
= area
->dy
;
108 sx
= area
->sx
; sy
= area
->sy
;
112 if ( xdir
< 0 ) { sx
+= w
-1; dx
+= w
-1; }
113 if ( ydir
< 0 ) { sy
+= h
-1; dy
+= h
-1; }
115 radeonfb_set_creg(rinfo
, DP_GUI_MASTER_CNTL
, &rinfo
->dp_gui_mc_cache
,
116 rinfo
->dp_gui_mc_base
|
118 GMC_SRC_DATATYPE_COLOR
|
120 DP_SRC_SOURCE_MEMORY
);
121 radeonfb_set_creg(rinfo
, DP_CNTL
, &rinfo
->dp_cntl_cache
,
122 (xdir
>=0 ? DST_X_LEFT_TO_RIGHT
: 0) |
123 (ydir
>=0 ? DST_Y_TOP_TO_BOTTOM
: 0));
125 #if FLUSH_CACHE_WORKAROUND
126 radeon_fifo_wait(rinfo
, 2);
127 OUTREG(DSTCACHE_CTLSTAT
, RB2D_DC_FLUSH_ALL
);
128 OUTREG(WAIT_UNTIL
, (WAIT_2D_IDLECLEAN
| WAIT_DMA_GUI_IDLE
));
130 radeon_fifo_wait(rinfo
, 3);
131 OUTREG(SRC_Y_X
, (sy
<< 16) | sx
);
132 OUTREG(DST_Y_X
, (dy
<< 16) | dx
);
133 OUTREG(DST_HEIGHT_WIDTH
, (h
<< 16) | w
);
137 void radeonfb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
139 struct radeonfb_info
*rinfo
= info
->par
;
140 struct fb_copyarea modded
;
142 modded
.sx
= area
->sx
;
143 modded
.sy
= area
->sy
;
144 modded
.dx
= area
->dx
;
145 modded
.dy
= area
->dy
;
146 modded
.width
= area
->width
;
147 modded
.height
= area
->height
;
149 WARN_ON(rinfo
->gfx_mode
);
150 if (info
->state
!= FBINFO_STATE_RUNNING
|| rinfo
->gfx_mode
)
152 if (info
->flags
& FBINFO_HWACCEL_DISABLED
) {
153 cfb_copyarea(info
, area
);
157 vxres
= info
->var
.xres_virtual
;
158 vyres
= info
->var
.yres_virtual
;
160 if(!modded
.width
|| !modded
.height
||
161 modded
.sx
>= vxres
|| modded
.sy
>= vyres
||
162 modded
.dx
>= vxres
|| modded
.dy
>= vyres
)
165 if(modded
.sx
+ modded
.width
> vxres
) modded
.width
= vxres
- modded
.sx
;
166 if(modded
.dx
+ modded
.width
> vxres
) modded
.width
= vxres
- modded
.dx
;
167 if(modded
.sy
+ modded
.height
> vyres
) modded
.height
= vyres
- modded
.sy
;
168 if(modded
.dy
+ modded
.height
> vyres
) modded
.height
= vyres
- modded
.dy
;
170 radeonfb_prim_copyarea(rinfo
, &modded
);
173 static void radeonfb_prim_imageblit(struct radeonfb_info
*rinfo
,
174 const struct fb_image
*image
,
180 radeonfb_set_creg(rinfo
, DP_GUI_MASTER_CNTL
, &rinfo
->dp_gui_mc_cache
,
181 rinfo
->dp_gui_mc_base
|
182 GMC_BRUSH_NONE
| GMC_DST_CLIP_LEAVE
|
183 GMC_SRC_DATATYPE_MONO_FG_BG
|
185 GMC_BYTE_ORDER_MSB_TO_LSB
|
186 DP_SRC_SOURCE_HOST_DATA
);
187 radeonfb_set_creg(rinfo
, DP_CNTL
, &rinfo
->dp_cntl_cache
,
188 DST_X_LEFT_TO_RIGHT
| DST_Y_TOP_TO_BOTTOM
);
189 radeonfb_set_creg(rinfo
, DP_SRC_FRGD_CLR
, &rinfo
->dp_src_fg_cache
, fg
);
190 radeonfb_set_creg(rinfo
, DP_SRC_BKGD_CLR
, &rinfo
->dp_src_bg_cache
, bg
);
192 /* Ensure the dst cache is flushed and the engine idle before
193 * issuing the operation.
195 * This works around engine lockups on some cards
197 #if FLUSH_CACHE_WORKAROUND
198 radeon_fifo_wait(rinfo
, 2);
199 OUTREG(DSTCACHE_CTLSTAT
, RB2D_DC_FLUSH_ALL
);
200 OUTREG(WAIT_UNTIL
, (WAIT_2D_IDLECLEAN
| WAIT_DMA_GUI_IDLE
));
203 /* X here pads width to a multiple of 32 and uses the clipper to
204 * adjust the result. Is that really necessary ? Things seem to
205 * work ok for me without that and the doco doesn't seem to imply]
206 * there is such a restriction.
208 radeon_fifo_wait(rinfo
, 4);
209 OUTREG(SC_TOP_LEFT
, (image
->dy
<< 16) | image
->dx
);
210 OUTREG(SC_BOTTOM_RIGHT
, ((image
->dy
+ image
->height
) << 16) |
211 (image
->dx
+ image
->width
));
212 OUTREG(DST_Y_X
, (image
->dy
<< 16) | image
->dx
);
214 OUTREG(DST_HEIGHT_WIDTH
, (image
->height
<< 16) | ((image
->width
+ 31) & ~31));
216 dwords
= (image
->width
+ 31) >> 5;
217 dwords
*= image
->height
;
218 bits
= (u32
*)(image
->data
);
221 radeon_fifo_wait(rinfo
, 8);
222 #if BITS_PER_LONG == 64
223 __raw_writeq(*((u64
*)(bits
)), rinfo
->mmio_base
+ HOST_DATA0
);
224 __raw_writeq(*((u64
*)(bits
+2)), rinfo
->mmio_base
+ HOST_DATA2
);
225 __raw_writeq(*((u64
*)(bits
+4)), rinfo
->mmio_base
+ HOST_DATA4
);
226 __raw_writeq(*((u64
*)(bits
+6)), rinfo
->mmio_base
+ HOST_DATA6
);
229 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA0
);
230 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA1
);
231 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA2
);
232 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA3
);
233 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA4
);
234 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA5
);
235 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA6
);
236 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA7
);
241 radeon_fifo_wait(rinfo
, 1);
242 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA0
);
246 void radeonfb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
248 struct radeonfb_info
*rinfo
= info
->par
;
251 WARN_ON(rinfo
->gfx_mode
);
252 if (info
->state
!= FBINFO_STATE_RUNNING
|| rinfo
->gfx_mode
)
255 if (!image
->width
|| !image
->height
)
258 /* We only do 1 bpp color expansion for now */
259 if (info
->flags
& FBINFO_HWACCEL_DISABLED
|| image
->depth
!= 1)
262 /* Fallback if running out of the screen. We may do clipping
264 if ((image
->dx
+ image
->width
) > info
->var
.xres_virtual
||
265 (image
->dy
+ image
->height
) > info
->var
.yres_virtual
)
268 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
||
269 info
->fix
.visual
== FB_VISUAL_DIRECTCOLOR
) {
270 fg
= ((u32
*)(info
->pseudo_palette
))[image
->fg_color
];
271 bg
= ((u32
*)(info
->pseudo_palette
))[image
->bg_color
];
273 fg
= image
->fg_color
;
274 bg
= image
->bg_color
;
277 radeonfb_prim_imageblit(rinfo
, image
, fg
, bg
);
281 radeon_engine_idle(rinfo
);
283 cfb_imageblit(info
, image
);
286 int radeonfb_sync(struct fb_info
*info
)
288 struct radeonfb_info
*rinfo
= info
->par
;
290 if (info
->state
!= FBINFO_STATE_RUNNING
)
293 radeon_engine_idle(rinfo
);
298 void radeonfb_engine_reset(struct radeonfb_info
*rinfo
)
300 u32 clock_cntl_index
, mclk_cntl
, rbbm_soft_reset
;
303 radeon_engine_flush (rinfo
);
305 clock_cntl_index
= INREG(CLOCK_CNTL_INDEX
);
306 mclk_cntl
= INPLL(MCLK_CNTL
);
308 OUTPLL(MCLK_CNTL
, (mclk_cntl
|
316 host_path_cntl
= INREG(HOST_PATH_CNTL
);
317 rbbm_soft_reset
= INREG(RBBM_SOFT_RESET
);
319 if (IS_R300_VARIANT(rinfo
)) {
322 OUTREG(RBBM_SOFT_RESET
, (rbbm_soft_reset
|
326 INREG(RBBM_SOFT_RESET
);
327 OUTREG(RBBM_SOFT_RESET
, 0);
328 tmp
= INREG(RB2D_DSTCACHE_MODE
);
329 OUTREG(RB2D_DSTCACHE_MODE
, tmp
| (1 << 17)); /* FIXME */
331 OUTREG(RBBM_SOFT_RESET
, rbbm_soft_reset
|
339 INREG(RBBM_SOFT_RESET
);
340 OUTREG(RBBM_SOFT_RESET
, rbbm_soft_reset
& (u32
)
348 INREG(RBBM_SOFT_RESET
);
351 OUTREG(HOST_PATH_CNTL
, host_path_cntl
| HDP_SOFT_RESET
);
352 INREG(HOST_PATH_CNTL
);
353 OUTREG(HOST_PATH_CNTL
, host_path_cntl
);
355 if (!IS_R300_VARIANT(rinfo
))
356 OUTREG(RBBM_SOFT_RESET
, rbbm_soft_reset
);
358 OUTREG(CLOCK_CNTL_INDEX
, clock_cntl_index
);
359 OUTPLL(MCLK_CNTL
, mclk_cntl
);
362 void radeonfb_engine_init (struct radeonfb_info
*rinfo
)
366 /* disable 3D engine */
367 OUTREG(RB3D_CNTL
, 0);
369 rinfo
->fifo_free
= 0;
370 radeonfb_engine_reset(rinfo
);
372 radeon_fifo_wait(rinfo
, 1);
373 if (IS_R300_VARIANT(rinfo
)) {
374 OUTREG(RB2D_DSTCACHE_MODE
, INREG(RB2D_DSTCACHE_MODE
) |
375 RB2D_DC_AUTOFLUSH_ENABLE
|
376 RB2D_DC_DC_DISABLE_IGNORE_PE
);
378 /* This needs to be double checked with ATI. Latest X driver
379 * completely "forgets" to set this register on < r3xx, and
380 * we used to just write 0 there... I'll keep the 0 and update
381 * that when we have sorted things out on X side.
383 OUTREG(RB2D_DSTCACHE_MODE
, 0);
386 radeon_fifo_wait(rinfo
, 3);
387 /* We re-read MC_FB_LOCATION from card as it can have been
388 * modified by XFree drivers (ouch !)
390 rinfo
->fb_local_base
= INREG(MC_FB_LOCATION
) << 16;
392 OUTREG(DEFAULT_PITCH_OFFSET
, (rinfo
->pitch
<< 0x16) |
393 (rinfo
->fb_local_base
>> 10));
394 OUTREG(DST_PITCH_OFFSET
, (rinfo
->pitch
<< 0x16) | (rinfo
->fb_local_base
>> 10));
395 OUTREG(SRC_PITCH_OFFSET
, (rinfo
->pitch
<< 0x16) | (rinfo
->fb_local_base
>> 10));
397 radeon_fifo_wait(rinfo
, 1);
399 OUTREGP(DP_DATATYPE
, HOST_BIG_ENDIAN_EN
, ~HOST_BIG_ENDIAN_EN
);
401 OUTREGP(DP_DATATYPE
, 0, ~HOST_BIG_ENDIAN_EN
);
403 radeon_fifo_wait(rinfo
, 2);
404 OUTREG(DEFAULT_SC_TOP_LEFT
, 0);
405 OUTREG(DEFAULT_SC_BOTTOM_RIGHT
, (DEFAULT_SC_RIGHT_MAX
|
406 DEFAULT_SC_BOTTOM_MAX
));
408 /* set default DP_GUI_MASTER_CNTL */
409 temp
= radeon_get_dstbpp(rinfo
->depth
);
410 rinfo
->dp_gui_mc_base
= ((temp
<< 8) | GMC_CLR_CMP_CNTL_DIS
);
412 rinfo
->dp_gui_mc_cache
= rinfo
->dp_gui_mc_base
|
413 GMC_BRUSH_SOLID_COLOR
|
414 GMC_SRC_DATATYPE_COLOR
;
415 radeon_fifo_wait(rinfo
, 1);
416 OUTREG(DP_GUI_MASTER_CNTL
, rinfo
->dp_gui_mc_cache
);
419 /* clear line drawing regs */
420 radeon_fifo_wait(rinfo
, 2);
421 OUTREG(DST_LINE_START
, 0);
422 OUTREG(DST_LINE_END
, 0);
424 /* set brush and source color regs */
425 rinfo
->dp_brush_fg_cache
= 0xffffffff;
426 rinfo
->dp_brush_bg_cache
= 0x00000000;
427 rinfo
->dp_src_fg_cache
= 0xffffffff;
428 rinfo
->dp_src_bg_cache
= 0x00000000;
429 radeon_fifo_wait(rinfo
, 4);
430 OUTREG(DP_BRUSH_FRGD_CLR
, rinfo
->dp_brush_fg_cache
);
431 OUTREG(DP_BRUSH_BKGD_CLR
, rinfo
->dp_brush_bg_cache
);
432 OUTREG(DP_SRC_FRGD_CLR
, rinfo
->dp_src_fg_cache
);
433 OUTREG(DP_SRC_BKGD_CLR
, rinfo
->dp_src_bg_cache
);
435 /* Default direction */
436 rinfo
->dp_cntl_cache
= DST_X_LEFT_TO_RIGHT
| DST_Y_TOP_TO_BOTTOM
;
437 radeon_fifo_wait(rinfo
, 1);
438 OUTREG(DP_CNTL
, rinfo
->dp_cntl_cache
);
440 /* default write mask */
441 radeon_fifo_wait(rinfo
, 1);
442 OUTREG(DP_WRITE_MSK
, 0xffffffff);
444 /* Default to no swapping of host data */
445 radeon_fifo_wait(rinfo
, 1);
446 OUTREG(RBBM_GUICNTL
, RBBM_GUICNTL_HOST_DATA_SWAP_NONE
);
448 /* Make sure it's settled */
449 radeon_engine_idle(rinfo
);