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
,
177 unsigned int src_bytes
, dwords
;
180 radeonfb_set_creg(rinfo
, DP_GUI_MASTER_CNTL
, &rinfo
->dp_gui_mc_cache
,
181 rinfo
->dp_gui_mc_base
|
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 radeon_fifo_wait(rinfo
, 1);
193 OUTREG(DST_Y_X
, (image
->dy
<< 16) | image
->dx
);
195 /* Ensure the dst cache is flushed and the engine idle before
196 * issuing the operation.
198 * This works around engine lockups on some cards
200 #if FLUSH_CACHE_WORKAROUND
201 radeon_fifo_wait(rinfo
, 2);
202 OUTREG(DSTCACHE_CTLSTAT
, RB2D_DC_FLUSH_ALL
);
203 OUTREG(WAIT_UNTIL
, (WAIT_2D_IDLECLEAN
| WAIT_DMA_GUI_IDLE
));
206 /* X here pads width to a multiple of 32 and uses the clipper to
207 * adjust the result. Is that really necessary ? Things seem to
208 * work ok for me without that and the doco doesn't seem to imply
209 * there is such a restriction.
211 OUTREG(DST_WIDTH_HEIGHT
, (image
->width
<< 16) | image
->height
);
213 src_bytes
= (((image
->width
* image
->depth
) + 7) / 8) * image
->height
;
214 dwords
= (src_bytes
+ 3) / 4;
215 bits
= (u32
*)(image
->data
);
218 radeon_fifo_wait(rinfo
, 8);
219 #if BITS_PER_LONG == 64
220 __raw_writeq(*((u64
*)(bits
)), rinfo
->mmio_base
+ HOST_DATA0
);
221 __raw_writeq(*((u64
*)(bits
+2)), rinfo
->mmio_base
+ HOST_DATA2
);
222 __raw_writeq(*((u64
*)(bits
+4)), rinfo
->mmio_base
+ HOST_DATA4
);
223 __raw_writeq(*((u64
*)(bits
+6)), rinfo
->mmio_base
+ HOST_DATA6
);
226 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA0
);
227 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA1
);
228 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA2
);
229 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA3
);
230 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA4
);
231 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA5
);
232 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA6
);
233 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA7
);
238 radeon_fifo_wait(rinfo
, 1);
239 __raw_writel(*(bits
++), rinfo
->mmio_base
+ HOST_DATA0
);
243 void radeonfb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
245 struct radeonfb_info
*rinfo
= info
->par
;
248 WARN_ON(rinfo
->gfx_mode
);
249 if (info
->state
!= FBINFO_STATE_RUNNING
|| rinfo
->gfx_mode
)
252 if (!image
->width
|| !image
->height
)
255 /* We only do 1 bpp color expansion for now */
256 if (info
->flags
& FBINFO_HWACCEL_DISABLED
|| image
->depth
!= 1)
259 /* Fallback if running out of the screen. We may do clipping
261 if ((image
->dx
+ image
->width
) > info
->var
.xres_virtual
||
262 (image
->dy
+ image
->height
) > info
->var
.yres_virtual
)
265 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
||
266 info
->fix
.visual
== FB_VISUAL_DIRECTCOLOR
) {
267 fg
= ((u32
*)(info
->pseudo_palette
))[image
->fg_color
];
268 bg
= ((u32
*)(info
->pseudo_palette
))[image
->bg_color
];
270 fg
= image
->fg_color
;
271 bg
= image
->bg_color
;
274 radeonfb_prim_imageblit(rinfo
, image
, fg
, bg
);
278 radeon_engine_idle(rinfo
);
280 cfb_imageblit(info
, image
);
283 int radeonfb_sync(struct fb_info
*info
)
285 struct radeonfb_info
*rinfo
= info
->par
;
287 if (info
->state
!= FBINFO_STATE_RUNNING
)
290 radeon_engine_idle(rinfo
);
295 void radeonfb_engine_reset(struct radeonfb_info
*rinfo
)
297 u32 clock_cntl_index
, mclk_cntl
, rbbm_soft_reset
;
300 radeon_engine_flush (rinfo
);
302 clock_cntl_index
= INREG(CLOCK_CNTL_INDEX
);
303 mclk_cntl
= INPLL(MCLK_CNTL
);
305 OUTPLL(MCLK_CNTL
, (mclk_cntl
|
313 host_path_cntl
= INREG(HOST_PATH_CNTL
);
314 rbbm_soft_reset
= INREG(RBBM_SOFT_RESET
);
316 if (IS_R300_VARIANT(rinfo
)) {
319 OUTREG(RBBM_SOFT_RESET
, (rbbm_soft_reset
|
323 INREG(RBBM_SOFT_RESET
);
324 OUTREG(RBBM_SOFT_RESET
, 0);
325 tmp
= INREG(RB2D_DSTCACHE_MODE
);
326 OUTREG(RB2D_DSTCACHE_MODE
, tmp
| (1 << 17)); /* FIXME */
328 OUTREG(RBBM_SOFT_RESET
, rbbm_soft_reset
|
336 INREG(RBBM_SOFT_RESET
);
337 OUTREG(RBBM_SOFT_RESET
, rbbm_soft_reset
& (u32
)
345 INREG(RBBM_SOFT_RESET
);
348 OUTREG(HOST_PATH_CNTL
, host_path_cntl
| HDP_SOFT_RESET
);
349 INREG(HOST_PATH_CNTL
);
350 OUTREG(HOST_PATH_CNTL
, host_path_cntl
);
352 if (!IS_R300_VARIANT(rinfo
))
353 OUTREG(RBBM_SOFT_RESET
, rbbm_soft_reset
);
355 OUTREG(CLOCK_CNTL_INDEX
, clock_cntl_index
);
356 OUTPLL(MCLK_CNTL
, mclk_cntl
);
359 void radeonfb_engine_init (struct radeonfb_info
*rinfo
)
363 /* disable 3D engine */
364 OUTREG(RB3D_CNTL
, 0);
366 rinfo
->fifo_free
= 0;
367 radeonfb_engine_reset(rinfo
);
369 radeon_fifo_wait(rinfo
, 1);
370 if (IS_R300_VARIANT(rinfo
)) {
371 OUTREG(RB2D_DSTCACHE_MODE
, INREG(RB2D_DSTCACHE_MODE
) |
372 RB2D_DC_AUTOFLUSH_ENABLE
|
373 RB2D_DC_DC_DISABLE_IGNORE_PE
);
375 /* This needs to be double checked with ATI. Latest X driver
376 * completely "forgets" to set this register on < r3xx, and
377 * we used to just write 0 there... I'll keep the 0 and update
378 * that when we have sorted things out on X side.
380 OUTREG(RB2D_DSTCACHE_MODE
, 0);
383 radeon_fifo_wait(rinfo
, 3);
384 /* We re-read MC_FB_LOCATION from card as it can have been
385 * modified by XFree drivers (ouch !)
387 rinfo
->fb_local_base
= INREG(MC_FB_LOCATION
) << 16;
389 OUTREG(DEFAULT_PITCH_OFFSET
, (rinfo
->pitch
<< 0x16) |
390 (rinfo
->fb_local_base
>> 10));
391 OUTREG(DST_PITCH_OFFSET
, (rinfo
->pitch
<< 0x16) | (rinfo
->fb_local_base
>> 10));
392 OUTREG(SRC_PITCH_OFFSET
, (rinfo
->pitch
<< 0x16) | (rinfo
->fb_local_base
>> 10));
394 radeon_fifo_wait(rinfo
, 1);
396 OUTREGP(DP_DATATYPE
, HOST_BIG_ENDIAN_EN
, ~HOST_BIG_ENDIAN_EN
);
398 OUTREGP(DP_DATATYPE
, 0, ~HOST_BIG_ENDIAN_EN
);
400 radeon_fifo_wait(rinfo
, 2);
401 OUTREG(DEFAULT_SC_TOP_LEFT
, 0);
402 OUTREG(DEFAULT_SC_BOTTOM_RIGHT
, (DEFAULT_SC_RIGHT_MAX
|
403 DEFAULT_SC_BOTTOM_MAX
));
405 /* set default DP_GUI_MASTER_CNTL */
406 temp
= radeon_get_dstbpp(rinfo
->depth
);
407 rinfo
->dp_gui_mc_base
= ((temp
<< 8) | GMC_CLR_CMP_CNTL_DIS
);
409 rinfo
->dp_gui_mc_cache
= rinfo
->dp_gui_mc_base
|
410 GMC_BRUSH_SOLID_COLOR
|
411 GMC_SRC_DATATYPE_COLOR
;
412 radeon_fifo_wait(rinfo
, 1);
413 OUTREG(DP_GUI_MASTER_CNTL
, rinfo
->dp_gui_mc_cache
);
416 /* clear line drawing regs */
417 radeon_fifo_wait(rinfo
, 2);
418 OUTREG(DST_LINE_START
, 0);
419 OUTREG(DST_LINE_END
, 0);
421 /* set brush and source color regs */
422 rinfo
->dp_brush_fg_cache
= 0xffffffff;
423 rinfo
->dp_brush_bg_cache
= 0x00000000;
424 rinfo
->dp_src_fg_cache
= 0xffffffff;
425 rinfo
->dp_src_bg_cache
= 0x00000000;
426 radeon_fifo_wait(rinfo
, 4);
427 OUTREG(DP_BRUSH_FRGD_CLR
, rinfo
->dp_brush_fg_cache
);
428 OUTREG(DP_BRUSH_BKGD_CLR
, rinfo
->dp_brush_bg_cache
);
429 OUTREG(DP_SRC_FRGD_CLR
, rinfo
->dp_src_fg_cache
);
430 OUTREG(DP_SRC_BKGD_CLR
, rinfo
->dp_src_bg_cache
);
432 /* Default direction */
433 rinfo
->dp_cntl_cache
= DST_X_LEFT_TO_RIGHT
| DST_Y_TOP_TO_BOTTOM
;
434 radeon_fifo_wait(rinfo
, 1);
435 OUTREG(DP_CNTL
, rinfo
->dp_cntl_cache
);
437 /* default write mask */
438 radeon_fifo_wait(rinfo
, 1);
439 OUTREG(DP_WRITE_MSK
, 0xffffffff);
441 /* Default to no swapping of host data */
442 radeon_fifo_wait(rinfo
, 1);
443 OUTREG(RBBM_GUICNTL
, RBBM_GUICNTL_HOST_DATA_SWAP_NONE
);
445 /* Make sure it's settled */
446 radeon_engine_idle(rinfo
);