Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* r128_state.c -- State support for r128 -*- linux-c -*- |
2 | * Created: Thu Jan 27 02:53:43 2000 by gareth@valinux.com | |
3 | * | |
4 | * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. | |
5 | * All Rights Reserved. | |
6 | * | |
7 | * Permission is hereby granted, free of charge, to any person obtaining a | |
8 | * copy of this software and associated documentation files (the "Software"), | |
9 | * to deal in the Software without restriction, including without limitation | |
10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
11 | * and/or sell copies of the Software, and to permit persons to whom the | |
12 | * Software is furnished to do so, subject to the following conditions: | |
13 | * | |
14 | * The above copyright notice and this permission notice (including the next | |
15 | * paragraph) shall be included in all copies or substantial portions of the | |
16 | * Software. | |
17 | * | |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
21 | * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
22 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
23 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
24 | * DEALINGS IN THE SOFTWARE. | |
25 | * | |
26 | * Authors: | |
27 | * Gareth Hughes <gareth@valinux.com> | |
28 | */ | |
29 | ||
30 | #include "drmP.h" | |
31 | #include "drm.h" | |
32 | #include "r128_drm.h" | |
33 | #include "r128_drv.h" | |
34 | ||
35 | ||
36 | /* ================================================================ | |
37 | * CCE hardware state programming functions | |
38 | */ | |
39 | ||
40 | static void r128_emit_clip_rects( drm_r128_private_t *dev_priv, | |
41 | drm_clip_rect_t *boxes, int count ) | |
42 | { | |
43 | u32 aux_sc_cntl = 0x00000000; | |
44 | RING_LOCALS; | |
45 | DRM_DEBUG( " %s\n", __FUNCTION__ ); | |
46 | ||
47 | BEGIN_RING( (count < 3? count: 3) * 5 + 2 ); | |
48 | ||
49 | if ( count >= 1 ) { | |
50 | OUT_RING( CCE_PACKET0( R128_AUX1_SC_LEFT, 3 ) ); | |
51 | OUT_RING( boxes[0].x1 ); | |
52 | OUT_RING( boxes[0].x2 - 1 ); | |
53 | OUT_RING( boxes[0].y1 ); | |
54 | OUT_RING( boxes[0].y2 - 1 ); | |
55 | ||
56 | aux_sc_cntl |= (R128_AUX1_SC_EN | R128_AUX1_SC_MODE_OR); | |
57 | } | |
58 | if ( count >= 2 ) { | |
59 | OUT_RING( CCE_PACKET0( R128_AUX2_SC_LEFT, 3 ) ); | |
60 | OUT_RING( boxes[1].x1 ); | |
61 | OUT_RING( boxes[1].x2 - 1 ); | |
62 | OUT_RING( boxes[1].y1 ); | |
63 | OUT_RING( boxes[1].y2 - 1 ); | |
64 | ||
65 | aux_sc_cntl |= (R128_AUX2_SC_EN | R128_AUX2_SC_MODE_OR); | |
66 | } | |
67 | if ( count >= 3 ) { | |
68 | OUT_RING( CCE_PACKET0( R128_AUX3_SC_LEFT, 3 ) ); | |
69 | OUT_RING( boxes[2].x1 ); | |
70 | OUT_RING( boxes[2].x2 - 1 ); | |
71 | OUT_RING( boxes[2].y1 ); | |
72 | OUT_RING( boxes[2].y2 - 1 ); | |
73 | ||
74 | aux_sc_cntl |= (R128_AUX3_SC_EN | R128_AUX3_SC_MODE_OR); | |
75 | } | |
76 | ||
77 | OUT_RING( CCE_PACKET0( R128_AUX_SC_CNTL, 0 ) ); | |
78 | OUT_RING( aux_sc_cntl ); | |
79 | ||
80 | ADVANCE_RING(); | |
81 | } | |
82 | ||
83 | static __inline__ void r128_emit_core( drm_r128_private_t *dev_priv ) | |
84 | { | |
85 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
86 | drm_r128_context_regs_t *ctx = &sarea_priv->context_state; | |
87 | RING_LOCALS; | |
88 | DRM_DEBUG( " %s\n", __FUNCTION__ ); | |
89 | ||
90 | BEGIN_RING( 2 ); | |
91 | ||
92 | OUT_RING( CCE_PACKET0( R128_SCALE_3D_CNTL, 0 ) ); | |
93 | OUT_RING( ctx->scale_3d_cntl ); | |
94 | ||
95 | ADVANCE_RING(); | |
96 | } | |
97 | ||
98 | static __inline__ void r128_emit_context( drm_r128_private_t *dev_priv ) | |
99 | { | |
100 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
101 | drm_r128_context_regs_t *ctx = &sarea_priv->context_state; | |
102 | RING_LOCALS; | |
103 | DRM_DEBUG( " %s\n", __FUNCTION__ ); | |
104 | ||
105 | BEGIN_RING( 13 ); | |
106 | ||
107 | OUT_RING( CCE_PACKET0( R128_DST_PITCH_OFFSET_C, 11 ) ); | |
108 | OUT_RING( ctx->dst_pitch_offset_c ); | |
109 | OUT_RING( ctx->dp_gui_master_cntl_c ); | |
110 | OUT_RING( ctx->sc_top_left_c ); | |
111 | OUT_RING( ctx->sc_bottom_right_c ); | |
112 | OUT_RING( ctx->z_offset_c ); | |
113 | OUT_RING( ctx->z_pitch_c ); | |
114 | OUT_RING( ctx->z_sten_cntl_c ); | |
115 | OUT_RING( ctx->tex_cntl_c ); | |
116 | OUT_RING( ctx->misc_3d_state_cntl_reg ); | |
117 | OUT_RING( ctx->texture_clr_cmp_clr_c ); | |
118 | OUT_RING( ctx->texture_clr_cmp_msk_c ); | |
119 | OUT_RING( ctx->fog_color_c ); | |
120 | ||
121 | ADVANCE_RING(); | |
122 | } | |
123 | ||
124 | static __inline__ void r128_emit_setup( drm_r128_private_t *dev_priv ) | |
125 | { | |
126 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
127 | drm_r128_context_regs_t *ctx = &sarea_priv->context_state; | |
128 | RING_LOCALS; | |
129 | DRM_DEBUG( " %s\n", __FUNCTION__ ); | |
130 | ||
131 | BEGIN_RING( 3 ); | |
132 | ||
133 | OUT_RING( CCE_PACKET1( R128_SETUP_CNTL, R128_PM4_VC_FPU_SETUP ) ); | |
134 | OUT_RING( ctx->setup_cntl ); | |
135 | OUT_RING( ctx->pm4_vc_fpu_setup ); | |
136 | ||
137 | ADVANCE_RING(); | |
138 | } | |
139 | ||
140 | static __inline__ void r128_emit_masks( drm_r128_private_t *dev_priv ) | |
141 | { | |
142 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
143 | drm_r128_context_regs_t *ctx = &sarea_priv->context_state; | |
144 | RING_LOCALS; | |
145 | DRM_DEBUG( " %s\n", __FUNCTION__ ); | |
146 | ||
147 | BEGIN_RING( 5 ); | |
148 | ||
149 | OUT_RING( CCE_PACKET0( R128_DP_WRITE_MASK, 0 ) ); | |
150 | OUT_RING( ctx->dp_write_mask ); | |
151 | ||
152 | OUT_RING( CCE_PACKET0( R128_STEN_REF_MASK_C, 1 ) ); | |
153 | OUT_RING( ctx->sten_ref_mask_c ); | |
154 | OUT_RING( ctx->plane_3d_mask_c ); | |
155 | ||
156 | ADVANCE_RING(); | |
157 | } | |
158 | ||
159 | static __inline__ void r128_emit_window( drm_r128_private_t *dev_priv ) | |
160 | { | |
161 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
162 | drm_r128_context_regs_t *ctx = &sarea_priv->context_state; | |
163 | RING_LOCALS; | |
164 | DRM_DEBUG( " %s\n", __FUNCTION__ ); | |
165 | ||
166 | BEGIN_RING( 2 ); | |
167 | ||
168 | OUT_RING( CCE_PACKET0( R128_WINDOW_XY_OFFSET, 0 ) ); | |
169 | OUT_RING( ctx->window_xy_offset ); | |
170 | ||
171 | ADVANCE_RING(); | |
172 | } | |
173 | ||
174 | static __inline__ void r128_emit_tex0( drm_r128_private_t *dev_priv ) | |
175 | { | |
176 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
177 | drm_r128_context_regs_t *ctx = &sarea_priv->context_state; | |
178 | drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[0]; | |
179 | int i; | |
180 | RING_LOCALS; | |
181 | DRM_DEBUG( " %s\n", __FUNCTION__ ); | |
182 | ||
183 | BEGIN_RING( 7 + R128_MAX_TEXTURE_LEVELS ); | |
184 | ||
185 | OUT_RING( CCE_PACKET0( R128_PRIM_TEX_CNTL_C, | |
186 | 2 + R128_MAX_TEXTURE_LEVELS ) ); | |
187 | OUT_RING( tex->tex_cntl ); | |
188 | OUT_RING( tex->tex_combine_cntl ); | |
189 | OUT_RING( ctx->tex_size_pitch_c ); | |
190 | for ( i = 0 ; i < R128_MAX_TEXTURE_LEVELS ; i++ ) { | |
191 | OUT_RING( tex->tex_offset[i] ); | |
192 | } | |
193 | ||
194 | OUT_RING( CCE_PACKET0( R128_CONSTANT_COLOR_C, 1 ) ); | |
195 | OUT_RING( ctx->constant_color_c ); | |
196 | OUT_RING( tex->tex_border_color ); | |
197 | ||
198 | ADVANCE_RING(); | |
199 | } | |
200 | ||
201 | static __inline__ void r128_emit_tex1( drm_r128_private_t *dev_priv ) | |
202 | { | |
203 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
204 | drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[1]; | |
205 | int i; | |
206 | RING_LOCALS; | |
207 | DRM_DEBUG( " %s\n", __FUNCTION__ ); | |
208 | ||
209 | BEGIN_RING( 5 + R128_MAX_TEXTURE_LEVELS ); | |
210 | ||
211 | OUT_RING( CCE_PACKET0( R128_SEC_TEX_CNTL_C, | |
212 | 1 + R128_MAX_TEXTURE_LEVELS ) ); | |
213 | OUT_RING( tex->tex_cntl ); | |
214 | OUT_RING( tex->tex_combine_cntl ); | |
215 | for ( i = 0 ; i < R128_MAX_TEXTURE_LEVELS ; i++ ) { | |
216 | OUT_RING( tex->tex_offset[i] ); | |
217 | } | |
218 | ||
219 | OUT_RING( CCE_PACKET0( R128_SEC_TEXTURE_BORDER_COLOR_C, 0 ) ); | |
220 | OUT_RING( tex->tex_border_color ); | |
221 | ||
222 | ADVANCE_RING(); | |
223 | } | |
224 | ||
225 | static __inline__ void r128_emit_state( drm_r128_private_t *dev_priv ) | |
226 | { | |
227 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
228 | unsigned int dirty = sarea_priv->dirty; | |
229 | ||
230 | DRM_DEBUG( "%s: dirty=0x%08x\n", __FUNCTION__, dirty ); | |
231 | ||
232 | if ( dirty & R128_UPLOAD_CORE ) { | |
233 | r128_emit_core( dev_priv ); | |
234 | sarea_priv->dirty &= ~R128_UPLOAD_CORE; | |
235 | } | |
236 | ||
237 | if ( dirty & R128_UPLOAD_CONTEXT ) { | |
238 | r128_emit_context( dev_priv ); | |
239 | sarea_priv->dirty &= ~R128_UPLOAD_CONTEXT; | |
240 | } | |
241 | ||
242 | if ( dirty & R128_UPLOAD_SETUP ) { | |
243 | r128_emit_setup( dev_priv ); | |
244 | sarea_priv->dirty &= ~R128_UPLOAD_SETUP; | |
245 | } | |
246 | ||
247 | if ( dirty & R128_UPLOAD_MASKS ) { | |
248 | r128_emit_masks( dev_priv ); | |
249 | sarea_priv->dirty &= ~R128_UPLOAD_MASKS; | |
250 | } | |
251 | ||
252 | if ( dirty & R128_UPLOAD_WINDOW ) { | |
253 | r128_emit_window( dev_priv ); | |
254 | sarea_priv->dirty &= ~R128_UPLOAD_WINDOW; | |
255 | } | |
256 | ||
257 | if ( dirty & R128_UPLOAD_TEX0 ) { | |
258 | r128_emit_tex0( dev_priv ); | |
259 | sarea_priv->dirty &= ~R128_UPLOAD_TEX0; | |
260 | } | |
261 | ||
262 | if ( dirty & R128_UPLOAD_TEX1 ) { | |
263 | r128_emit_tex1( dev_priv ); | |
264 | sarea_priv->dirty &= ~R128_UPLOAD_TEX1; | |
265 | } | |
266 | ||
267 | /* Turn off the texture cache flushing */ | |
268 | sarea_priv->context_state.tex_cntl_c &= ~R128_TEX_CACHE_FLUSH; | |
269 | ||
270 | sarea_priv->dirty &= ~R128_REQUIRE_QUIESCENCE; | |
271 | } | |
272 | ||
273 | ||
274 | #if R128_PERFORMANCE_BOXES | |
275 | /* ================================================================ | |
276 | * Performance monitoring functions | |
277 | */ | |
278 | ||
279 | static void r128_clear_box( drm_r128_private_t *dev_priv, | |
280 | int x, int y, int w, int h, | |
281 | int r, int g, int b ) | |
282 | { | |
283 | u32 pitch, offset; | |
284 | u32 fb_bpp, color; | |
285 | RING_LOCALS; | |
286 | ||
287 | switch ( dev_priv->fb_bpp ) { | |
288 | case 16: | |
289 | fb_bpp = R128_GMC_DST_16BPP; | |
290 | color = (((r & 0xf8) << 8) | | |
291 | ((g & 0xfc) << 3) | | |
292 | ((b & 0xf8) >> 3)); | |
293 | break; | |
294 | case 24: | |
295 | fb_bpp = R128_GMC_DST_24BPP; | |
296 | color = ((r << 16) | (g << 8) | b); | |
297 | break; | |
298 | case 32: | |
299 | fb_bpp = R128_GMC_DST_32BPP; | |
300 | color = (((0xff) << 24) | (r << 16) | (g << 8) | b); | |
301 | break; | |
302 | default: | |
303 | return; | |
304 | } | |
305 | ||
306 | offset = dev_priv->back_offset; | |
307 | pitch = dev_priv->back_pitch >> 3; | |
308 | ||
309 | BEGIN_RING( 6 ); | |
310 | ||
311 | OUT_RING( CCE_PACKET3( R128_CNTL_PAINT_MULTI, 4 ) ); | |
312 | OUT_RING( R128_GMC_DST_PITCH_OFFSET_CNTL | | |
313 | R128_GMC_BRUSH_SOLID_COLOR | | |
314 | fb_bpp | | |
315 | R128_GMC_SRC_DATATYPE_COLOR | | |
316 | R128_ROP3_P | | |
317 | R128_GMC_CLR_CMP_CNTL_DIS | | |
318 | R128_GMC_AUX_CLIP_DIS ); | |
319 | ||
320 | OUT_RING( (pitch << 21) | (offset >> 5) ); | |
321 | OUT_RING( color ); | |
322 | ||
323 | OUT_RING( (x << 16) | y ); | |
324 | OUT_RING( (w << 16) | h ); | |
325 | ||
326 | ADVANCE_RING(); | |
327 | } | |
328 | ||
329 | static void r128_cce_performance_boxes( drm_r128_private_t *dev_priv ) | |
330 | { | |
331 | if ( atomic_read( &dev_priv->idle_count ) == 0 ) { | |
332 | r128_clear_box( dev_priv, 64, 4, 8, 8, 0, 255, 0 ); | |
333 | } else { | |
334 | atomic_set( &dev_priv->idle_count, 0 ); | |
335 | } | |
336 | } | |
337 | ||
338 | #endif | |
339 | ||
340 | ||
341 | /* ================================================================ | |
342 | * CCE command dispatch functions | |
343 | */ | |
344 | ||
345 | static void r128_print_dirty( const char *msg, unsigned int flags ) | |
346 | { | |
347 | DRM_INFO( "%s: (0x%x) %s%s%s%s%s%s%s%s%s\n", | |
348 | msg, | |
349 | flags, | |
350 | (flags & R128_UPLOAD_CORE) ? "core, " : "", | |
351 | (flags & R128_UPLOAD_CONTEXT) ? "context, " : "", | |
352 | (flags & R128_UPLOAD_SETUP) ? "setup, " : "", | |
353 | (flags & R128_UPLOAD_TEX0) ? "tex0, " : "", | |
354 | (flags & R128_UPLOAD_TEX1) ? "tex1, " : "", | |
355 | (flags & R128_UPLOAD_MASKS) ? "masks, " : "", | |
356 | (flags & R128_UPLOAD_WINDOW) ? "window, " : "", | |
357 | (flags & R128_UPLOAD_CLIPRECTS) ? "cliprects, " : "", | |
358 | (flags & R128_REQUIRE_QUIESCENCE) ? "quiescence, " : "" ); | |
359 | } | |
360 | ||
361 | static void r128_cce_dispatch_clear( drm_device_t *dev, | |
362 | drm_r128_clear_t *clear ) | |
363 | { | |
364 | drm_r128_private_t *dev_priv = dev->dev_private; | |
365 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
366 | int nbox = sarea_priv->nbox; | |
367 | drm_clip_rect_t *pbox = sarea_priv->boxes; | |
368 | unsigned int flags = clear->flags; | |
369 | int i; | |
370 | RING_LOCALS; | |
371 | DRM_DEBUG( "%s\n", __FUNCTION__ ); | |
372 | ||
373 | if ( dev_priv->page_flipping && dev_priv->current_page == 1 ) { | |
374 | unsigned int tmp = flags; | |
375 | ||
376 | flags &= ~(R128_FRONT | R128_BACK); | |
377 | if ( tmp & R128_FRONT ) flags |= R128_BACK; | |
378 | if ( tmp & R128_BACK ) flags |= R128_FRONT; | |
379 | } | |
380 | ||
381 | for ( i = 0 ; i < nbox ; i++ ) { | |
382 | int x = pbox[i].x1; | |
383 | int y = pbox[i].y1; | |
384 | int w = pbox[i].x2 - x; | |
385 | int h = pbox[i].y2 - y; | |
386 | ||
387 | DRM_DEBUG( "dispatch clear %d,%d-%d,%d flags 0x%x\n", | |
388 | pbox[i].x1, pbox[i].y1, pbox[i].x2, | |
389 | pbox[i].y2, flags ); | |
390 | ||
391 | if ( flags & (R128_FRONT | R128_BACK) ) { | |
392 | BEGIN_RING( 2 ); | |
393 | ||
394 | OUT_RING( CCE_PACKET0( R128_DP_WRITE_MASK, 0 ) ); | |
395 | OUT_RING( clear->color_mask ); | |
396 | ||
397 | ADVANCE_RING(); | |
398 | } | |
399 | ||
400 | if ( flags & R128_FRONT ) { | |
401 | BEGIN_RING( 6 ); | |
402 | ||
403 | OUT_RING( CCE_PACKET3( R128_CNTL_PAINT_MULTI, 4 ) ); | |
404 | OUT_RING( R128_GMC_DST_PITCH_OFFSET_CNTL | | |
405 | R128_GMC_BRUSH_SOLID_COLOR | | |
406 | (dev_priv->color_fmt << 8) | | |
407 | R128_GMC_SRC_DATATYPE_COLOR | | |
408 | R128_ROP3_P | | |
409 | R128_GMC_CLR_CMP_CNTL_DIS | | |
410 | R128_GMC_AUX_CLIP_DIS ); | |
411 | ||
412 | OUT_RING( dev_priv->front_pitch_offset_c ); | |
413 | OUT_RING( clear->clear_color ); | |
414 | ||
415 | OUT_RING( (x << 16) | y ); | |
416 | OUT_RING( (w << 16) | h ); | |
417 | ||
418 | ADVANCE_RING(); | |
419 | } | |
420 | ||
421 | if ( flags & R128_BACK ) { | |
422 | BEGIN_RING( 6 ); | |
423 | ||
424 | OUT_RING( CCE_PACKET3( R128_CNTL_PAINT_MULTI, 4 ) ); | |
425 | OUT_RING( R128_GMC_DST_PITCH_OFFSET_CNTL | | |
426 | R128_GMC_BRUSH_SOLID_COLOR | | |
427 | (dev_priv->color_fmt << 8) | | |
428 | R128_GMC_SRC_DATATYPE_COLOR | | |
429 | R128_ROP3_P | | |
430 | R128_GMC_CLR_CMP_CNTL_DIS | | |
431 | R128_GMC_AUX_CLIP_DIS ); | |
432 | ||
433 | OUT_RING( dev_priv->back_pitch_offset_c ); | |
434 | OUT_RING( clear->clear_color ); | |
435 | ||
436 | OUT_RING( (x << 16) | y ); | |
437 | OUT_RING( (w << 16) | h ); | |
438 | ||
439 | ADVANCE_RING(); | |
440 | } | |
441 | ||
442 | if ( flags & R128_DEPTH ) { | |
443 | BEGIN_RING( 6 ); | |
444 | ||
445 | OUT_RING( CCE_PACKET3( R128_CNTL_PAINT_MULTI, 4 ) ); | |
446 | OUT_RING( R128_GMC_DST_PITCH_OFFSET_CNTL | | |
447 | R128_GMC_BRUSH_SOLID_COLOR | | |
448 | (dev_priv->depth_fmt << 8) | | |
449 | R128_GMC_SRC_DATATYPE_COLOR | | |
450 | R128_ROP3_P | | |
451 | R128_GMC_CLR_CMP_CNTL_DIS | | |
452 | R128_GMC_AUX_CLIP_DIS | | |
453 | R128_GMC_WR_MSK_DIS ); | |
454 | ||
455 | OUT_RING( dev_priv->depth_pitch_offset_c ); | |
456 | OUT_RING( clear->clear_depth ); | |
457 | ||
458 | OUT_RING( (x << 16) | y ); | |
459 | OUT_RING( (w << 16) | h ); | |
460 | ||
461 | ADVANCE_RING(); | |
462 | } | |
463 | } | |
464 | } | |
465 | ||
466 | static void r128_cce_dispatch_swap( drm_device_t *dev ) | |
467 | { | |
468 | drm_r128_private_t *dev_priv = dev->dev_private; | |
469 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
470 | int nbox = sarea_priv->nbox; | |
471 | drm_clip_rect_t *pbox = sarea_priv->boxes; | |
472 | int i; | |
473 | RING_LOCALS; | |
474 | DRM_DEBUG( "%s\n", __FUNCTION__ ); | |
475 | ||
476 | #if R128_PERFORMANCE_BOXES | |
477 | /* Do some trivial performance monitoring... | |
478 | */ | |
479 | r128_cce_performance_boxes( dev_priv ); | |
480 | #endif | |
481 | ||
482 | for ( i = 0 ; i < nbox ; i++ ) { | |
483 | int x = pbox[i].x1; | |
484 | int y = pbox[i].y1; | |
485 | int w = pbox[i].x2 - x; | |
486 | int h = pbox[i].y2 - y; | |
487 | ||
488 | BEGIN_RING( 7 ); | |
489 | ||
490 | OUT_RING( CCE_PACKET3( R128_CNTL_BITBLT_MULTI, 5 ) ); | |
491 | OUT_RING( R128_GMC_SRC_PITCH_OFFSET_CNTL | | |
492 | R128_GMC_DST_PITCH_OFFSET_CNTL | | |
493 | R128_GMC_BRUSH_NONE | | |
494 | (dev_priv->color_fmt << 8) | | |
495 | R128_GMC_SRC_DATATYPE_COLOR | | |
496 | R128_ROP3_S | | |
497 | R128_DP_SRC_SOURCE_MEMORY | | |
498 | R128_GMC_CLR_CMP_CNTL_DIS | | |
499 | R128_GMC_AUX_CLIP_DIS | | |
500 | R128_GMC_WR_MSK_DIS ); | |
501 | ||
502 | /* Make this work even if front & back are flipped: | |
503 | */ | |
504 | if (dev_priv->current_page == 0) { | |
505 | OUT_RING( dev_priv->back_pitch_offset_c ); | |
506 | OUT_RING( dev_priv->front_pitch_offset_c ); | |
507 | } | |
508 | else { | |
509 | OUT_RING( dev_priv->front_pitch_offset_c ); | |
510 | OUT_RING( dev_priv->back_pitch_offset_c ); | |
511 | } | |
512 | ||
513 | OUT_RING( (x << 16) | y ); | |
514 | OUT_RING( (x << 16) | y ); | |
515 | OUT_RING( (w << 16) | h ); | |
516 | ||
517 | ADVANCE_RING(); | |
518 | } | |
519 | ||
520 | /* Increment the frame counter. The client-side 3D driver must | |
521 | * throttle the framerate by waiting for this value before | |
522 | * performing the swapbuffer ioctl. | |
523 | */ | |
524 | dev_priv->sarea_priv->last_frame++; | |
525 | ||
526 | BEGIN_RING( 2 ); | |
527 | ||
528 | OUT_RING( CCE_PACKET0( R128_LAST_FRAME_REG, 0 ) ); | |
529 | OUT_RING( dev_priv->sarea_priv->last_frame ); | |
530 | ||
531 | ADVANCE_RING(); | |
532 | } | |
533 | ||
534 | static void r128_cce_dispatch_flip( drm_device_t *dev ) | |
535 | { | |
536 | drm_r128_private_t *dev_priv = dev->dev_private; | |
537 | RING_LOCALS; | |
538 | DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", | |
539 | __FUNCTION__, | |
540 | dev_priv->current_page, | |
541 | dev_priv->sarea_priv->pfCurrentPage); | |
542 | ||
543 | #if R128_PERFORMANCE_BOXES | |
544 | /* Do some trivial performance monitoring... | |
545 | */ | |
546 | r128_cce_performance_boxes( dev_priv ); | |
547 | #endif | |
548 | ||
549 | BEGIN_RING( 4 ); | |
550 | ||
551 | R128_WAIT_UNTIL_PAGE_FLIPPED(); | |
552 | OUT_RING( CCE_PACKET0( R128_CRTC_OFFSET, 0 ) ); | |
553 | ||
554 | if ( dev_priv->current_page == 0 ) { | |
555 | OUT_RING( dev_priv->back_offset ); | |
556 | } else { | |
557 | OUT_RING( dev_priv->front_offset ); | |
558 | } | |
559 | ||
560 | ADVANCE_RING(); | |
561 | ||
562 | /* Increment the frame counter. The client-side 3D driver must | |
563 | * throttle the framerate by waiting for this value before | |
564 | * performing the swapbuffer ioctl. | |
565 | */ | |
566 | dev_priv->sarea_priv->last_frame++; | |
567 | dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page = | |
568 | 1 - dev_priv->current_page; | |
569 | ||
570 | BEGIN_RING( 2 ); | |
571 | ||
572 | OUT_RING( CCE_PACKET0( R128_LAST_FRAME_REG, 0 ) ); | |
573 | OUT_RING( dev_priv->sarea_priv->last_frame ); | |
574 | ||
575 | ADVANCE_RING(); | |
576 | } | |
577 | ||
578 | static void r128_cce_dispatch_vertex( drm_device_t *dev, | |
579 | drm_buf_t *buf ) | |
580 | { | |
581 | drm_r128_private_t *dev_priv = dev->dev_private; | |
582 | drm_r128_buf_priv_t *buf_priv = buf->dev_private; | |
583 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
584 | int format = sarea_priv->vc_format; | |
585 | int offset = buf->bus_address; | |
586 | int size = buf->used; | |
587 | int prim = buf_priv->prim; | |
588 | int i = 0; | |
589 | RING_LOCALS; | |
590 | DRM_DEBUG( "buf=%d nbox=%d\n", buf->idx, sarea_priv->nbox ); | |
591 | ||
592 | if ( 0 ) | |
593 | r128_print_dirty( "dispatch_vertex", sarea_priv->dirty ); | |
594 | ||
595 | if ( buf->used ) { | |
596 | buf_priv->dispatched = 1; | |
597 | ||
598 | if ( sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS ) { | |
599 | r128_emit_state( dev_priv ); | |
600 | } | |
601 | ||
602 | do { | |
603 | /* Emit the next set of up to three cliprects */ | |
604 | if ( i < sarea_priv->nbox ) { | |
605 | r128_emit_clip_rects( dev_priv, | |
606 | &sarea_priv->boxes[i], | |
607 | sarea_priv->nbox - i ); | |
608 | } | |
609 | ||
610 | /* Emit the vertex buffer rendering commands */ | |
611 | BEGIN_RING( 5 ); | |
612 | ||
613 | OUT_RING( CCE_PACKET3( R128_3D_RNDR_GEN_INDX_PRIM, 3 ) ); | |
614 | OUT_RING( offset ); | |
615 | OUT_RING( size ); | |
616 | OUT_RING( format ); | |
617 | OUT_RING( prim | R128_CCE_VC_CNTL_PRIM_WALK_LIST | | |
618 | (size << R128_CCE_VC_CNTL_NUM_SHIFT) ); | |
619 | ||
620 | ADVANCE_RING(); | |
621 | ||
622 | i += 3; | |
623 | } while ( i < sarea_priv->nbox ); | |
624 | } | |
625 | ||
626 | if ( buf_priv->discard ) { | |
627 | buf_priv->age = dev_priv->sarea_priv->last_dispatch; | |
628 | ||
629 | /* Emit the vertex buffer age */ | |
630 | BEGIN_RING( 2 ); | |
631 | ||
632 | OUT_RING( CCE_PACKET0( R128_LAST_DISPATCH_REG, 0 ) ); | |
633 | OUT_RING( buf_priv->age ); | |
634 | ||
635 | ADVANCE_RING(); | |
636 | ||
637 | buf->pending = 1; | |
638 | buf->used = 0; | |
639 | /* FIXME: Check dispatched field */ | |
640 | buf_priv->dispatched = 0; | |
641 | } | |
642 | ||
643 | dev_priv->sarea_priv->last_dispatch++; | |
644 | ||
645 | sarea_priv->dirty &= ~R128_UPLOAD_CLIPRECTS; | |
646 | sarea_priv->nbox = 0; | |
647 | } | |
648 | ||
649 | static void r128_cce_dispatch_indirect( drm_device_t *dev, | |
650 | drm_buf_t *buf, | |
651 | int start, int end ) | |
652 | { | |
653 | drm_r128_private_t *dev_priv = dev->dev_private; | |
654 | drm_r128_buf_priv_t *buf_priv = buf->dev_private; | |
655 | RING_LOCALS; | |
656 | DRM_DEBUG( "indirect: buf=%d s=0x%x e=0x%x\n", | |
657 | buf->idx, start, end ); | |
658 | ||
659 | if ( start != end ) { | |
660 | int offset = buf->bus_address + start; | |
661 | int dwords = (end - start + 3) / sizeof(u32); | |
662 | ||
663 | /* Indirect buffer data must be an even number of | |
664 | * dwords, so if we've been given an odd number we must | |
665 | * pad the data with a Type-2 CCE packet. | |
666 | */ | |
667 | if ( dwords & 1 ) { | |
668 | u32 *data = (u32 *) | |
669 | ((char *)dev->agp_buffer_map->handle | |
670 | + buf->offset + start); | |
671 | data[dwords++] = cpu_to_le32( R128_CCE_PACKET2 ); | |
672 | } | |
673 | ||
674 | buf_priv->dispatched = 1; | |
675 | ||
676 | /* Fire off the indirect buffer */ | |
677 | BEGIN_RING( 3 ); | |
678 | ||
679 | OUT_RING( CCE_PACKET0( R128_PM4_IW_INDOFF, 1 ) ); | |
680 | OUT_RING( offset ); | |
681 | OUT_RING( dwords ); | |
682 | ||
683 | ADVANCE_RING(); | |
684 | } | |
685 | ||
686 | if ( buf_priv->discard ) { | |
687 | buf_priv->age = dev_priv->sarea_priv->last_dispatch; | |
688 | ||
689 | /* Emit the indirect buffer age */ | |
690 | BEGIN_RING( 2 ); | |
691 | ||
692 | OUT_RING( CCE_PACKET0( R128_LAST_DISPATCH_REG, 0 ) ); | |
693 | OUT_RING( buf_priv->age ); | |
694 | ||
695 | ADVANCE_RING(); | |
696 | ||
697 | buf->pending = 1; | |
698 | buf->used = 0; | |
699 | /* FIXME: Check dispatched field */ | |
700 | buf_priv->dispatched = 0; | |
701 | } | |
702 | ||
703 | dev_priv->sarea_priv->last_dispatch++; | |
704 | } | |
705 | ||
706 | static void r128_cce_dispatch_indices( drm_device_t *dev, | |
707 | drm_buf_t *buf, | |
708 | int start, int end, | |
709 | int count ) | |
710 | { | |
711 | drm_r128_private_t *dev_priv = dev->dev_private; | |
712 | drm_r128_buf_priv_t *buf_priv = buf->dev_private; | |
713 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
714 | int format = sarea_priv->vc_format; | |
715 | int offset = dev->agp_buffer_map->offset - dev_priv->cce_buffers_offset; | |
716 | int prim = buf_priv->prim; | |
717 | u32 *data; | |
718 | int dwords; | |
719 | int i = 0; | |
720 | RING_LOCALS; | |
721 | DRM_DEBUG( "indices: s=%d e=%d c=%d\n", start, end, count ); | |
722 | ||
723 | if ( 0 ) | |
724 | r128_print_dirty( "dispatch_indices", sarea_priv->dirty ); | |
725 | ||
726 | if ( start != end ) { | |
727 | buf_priv->dispatched = 1; | |
728 | ||
729 | if ( sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS ) { | |
730 | r128_emit_state( dev_priv ); | |
731 | } | |
732 | ||
733 | dwords = (end - start + 3) / sizeof(u32); | |
734 | ||
735 | data = (u32 *)((char *)dev->agp_buffer_map->handle | |
736 | + buf->offset + start); | |
737 | ||
738 | data[0] = cpu_to_le32( CCE_PACKET3( R128_3D_RNDR_GEN_INDX_PRIM, | |
739 | dwords-2 ) ); | |
740 | ||
741 | data[1] = cpu_to_le32( offset ); | |
742 | data[2] = cpu_to_le32( R128_MAX_VB_VERTS ); | |
743 | data[3] = cpu_to_le32( format ); | |
744 | data[4] = cpu_to_le32( (prim | R128_CCE_VC_CNTL_PRIM_WALK_IND | | |
745 | (count << 16)) ); | |
746 | ||
747 | if ( count & 0x1 ) { | |
748 | #ifdef __LITTLE_ENDIAN | |
749 | data[dwords-1] &= 0x0000ffff; | |
750 | #else | |
751 | data[dwords-1] &= 0xffff0000; | |
752 | #endif | |
753 | } | |
754 | ||
755 | do { | |
756 | /* Emit the next set of up to three cliprects */ | |
757 | if ( i < sarea_priv->nbox ) { | |
758 | r128_emit_clip_rects( dev_priv, | |
759 | &sarea_priv->boxes[i], | |
760 | sarea_priv->nbox - i ); | |
761 | } | |
762 | ||
763 | r128_cce_dispatch_indirect( dev, buf, start, end ); | |
764 | ||
765 | i += 3; | |
766 | } while ( i < sarea_priv->nbox ); | |
767 | } | |
768 | ||
769 | if ( buf_priv->discard ) { | |
770 | buf_priv->age = dev_priv->sarea_priv->last_dispatch; | |
771 | ||
772 | /* Emit the vertex buffer age */ | |
773 | BEGIN_RING( 2 ); | |
774 | ||
775 | OUT_RING( CCE_PACKET0( R128_LAST_DISPATCH_REG, 0 ) ); | |
776 | OUT_RING( buf_priv->age ); | |
777 | ||
778 | ADVANCE_RING(); | |
779 | ||
780 | buf->pending = 1; | |
781 | /* FIXME: Check dispatched field */ | |
782 | buf_priv->dispatched = 0; | |
783 | } | |
784 | ||
785 | dev_priv->sarea_priv->last_dispatch++; | |
786 | ||
787 | sarea_priv->dirty &= ~R128_UPLOAD_CLIPRECTS; | |
788 | sarea_priv->nbox = 0; | |
789 | } | |
790 | ||
791 | static int r128_cce_dispatch_blit( DRMFILE filp, | |
792 | drm_device_t *dev, | |
793 | drm_r128_blit_t *blit ) | |
794 | { | |
795 | drm_r128_private_t *dev_priv = dev->dev_private; | |
796 | drm_device_dma_t *dma = dev->dma; | |
797 | drm_buf_t *buf; | |
798 | drm_r128_buf_priv_t *buf_priv; | |
799 | u32 *data; | |
800 | int dword_shift, dwords; | |
801 | RING_LOCALS; | |
802 | DRM_DEBUG( "\n" ); | |
803 | ||
804 | /* The compiler won't optimize away a division by a variable, | |
805 | * even if the only legal values are powers of two. Thus, we'll | |
806 | * use a shift instead. | |
807 | */ | |
808 | switch ( blit->format ) { | |
809 | case R128_DATATYPE_ARGB8888: | |
810 | dword_shift = 0; | |
811 | break; | |
812 | case R128_DATATYPE_ARGB1555: | |
813 | case R128_DATATYPE_RGB565: | |
814 | case R128_DATATYPE_ARGB4444: | |
815 | case R128_DATATYPE_YVYU422: | |
816 | case R128_DATATYPE_VYUY422: | |
817 | dword_shift = 1; | |
818 | break; | |
819 | case R128_DATATYPE_CI8: | |
820 | case R128_DATATYPE_RGB8: | |
821 | dword_shift = 2; | |
822 | break; | |
823 | default: | |
824 | DRM_ERROR( "invalid blit format %d\n", blit->format ); | |
825 | return DRM_ERR(EINVAL); | |
826 | } | |
827 | ||
828 | /* Flush the pixel cache, and mark the contents as Read Invalid. | |
829 | * This ensures no pixel data gets mixed up with the texture | |
830 | * data from the host data blit, otherwise part of the texture | |
831 | * image may be corrupted. | |
832 | */ | |
833 | BEGIN_RING( 2 ); | |
834 | ||
835 | OUT_RING( CCE_PACKET0( R128_PC_GUI_CTLSTAT, 0 ) ); | |
836 | OUT_RING( R128_PC_RI_GUI | R128_PC_FLUSH_GUI ); | |
837 | ||
838 | ADVANCE_RING(); | |
839 | ||
840 | /* Dispatch the indirect buffer. | |
841 | */ | |
842 | buf = dma->buflist[blit->idx]; | |
843 | buf_priv = buf->dev_private; | |
844 | ||
845 | if ( buf->filp != filp ) { | |
846 | DRM_ERROR( "process %d using buffer owned by %p\n", | |
847 | DRM_CURRENTPID, buf->filp ); | |
848 | return DRM_ERR(EINVAL); | |
849 | } | |
850 | if ( buf->pending ) { | |
851 | DRM_ERROR( "sending pending buffer %d\n", blit->idx ); | |
852 | return DRM_ERR(EINVAL); | |
853 | } | |
854 | ||
855 | buf_priv->discard = 1; | |
856 | ||
857 | dwords = (blit->width * blit->height) >> dword_shift; | |
858 | ||
859 | data = (u32 *)((char *)dev->agp_buffer_map->handle + buf->offset); | |
860 | ||
861 | data[0] = cpu_to_le32( CCE_PACKET3( R128_CNTL_HOSTDATA_BLT, dwords + 6 ) ); | |
862 | data[1] = cpu_to_le32( (R128_GMC_DST_PITCH_OFFSET_CNTL | | |
863 | R128_GMC_BRUSH_NONE | | |
864 | (blit->format << 8) | | |
865 | R128_GMC_SRC_DATATYPE_COLOR | | |
866 | R128_ROP3_S | | |
867 | R128_DP_SRC_SOURCE_HOST_DATA | | |
868 | R128_GMC_CLR_CMP_CNTL_DIS | | |
869 | R128_GMC_AUX_CLIP_DIS | | |
870 | R128_GMC_WR_MSK_DIS) ); | |
871 | ||
872 | data[2] = cpu_to_le32( (blit->pitch << 21) | (blit->offset >> 5) ); | |
873 | data[3] = cpu_to_le32( 0xffffffff ); | |
874 | data[4] = cpu_to_le32( 0xffffffff ); | |
875 | data[5] = cpu_to_le32( (blit->y << 16) | blit->x ); | |
876 | data[6] = cpu_to_le32( (blit->height << 16) | blit->width ); | |
877 | data[7] = cpu_to_le32( dwords ); | |
878 | ||
879 | buf->used = (dwords + 8) * sizeof(u32); | |
880 | ||
881 | r128_cce_dispatch_indirect( dev, buf, 0, buf->used ); | |
882 | ||
883 | /* Flush the pixel cache after the blit completes. This ensures | |
884 | * the texture data is written out to memory before rendering | |
885 | * continues. | |
886 | */ | |
887 | BEGIN_RING( 2 ); | |
888 | ||
889 | OUT_RING( CCE_PACKET0( R128_PC_GUI_CTLSTAT, 0 ) ); | |
890 | OUT_RING( R128_PC_FLUSH_GUI ); | |
891 | ||
892 | ADVANCE_RING(); | |
893 | ||
894 | return 0; | |
895 | } | |
896 | ||
897 | ||
898 | /* ================================================================ | |
899 | * Tiled depth buffer management | |
900 | * | |
901 | * FIXME: These should all set the destination write mask for when we | |
902 | * have hardware stencil support. | |
903 | */ | |
904 | ||
905 | static int r128_cce_dispatch_write_span( drm_device_t *dev, | |
906 | drm_r128_depth_t *depth ) | |
907 | { | |
908 | drm_r128_private_t *dev_priv = dev->dev_private; | |
909 | int count, x, y; | |
910 | u32 *buffer; | |
911 | u8 *mask; | |
912 | int i, buffer_size, mask_size; | |
913 | RING_LOCALS; | |
914 | DRM_DEBUG( "\n" ); | |
915 | ||
916 | count = depth->n; | |
917 | if (count > 4096 || count <= 0) | |
918 | return DRM_ERR(EMSGSIZE); | |
919 | ||
920 | if ( DRM_COPY_FROM_USER( &x, depth->x, sizeof(x) ) ) { | |
921 | return DRM_ERR(EFAULT); | |
922 | } | |
923 | if ( DRM_COPY_FROM_USER( &y, depth->y, sizeof(y) ) ) { | |
924 | return DRM_ERR(EFAULT); | |
925 | } | |
926 | ||
927 | buffer_size = depth->n * sizeof(u32); | |
928 | buffer = drm_alloc( buffer_size, DRM_MEM_BUFS ); | |
929 | if ( buffer == NULL ) | |
930 | return DRM_ERR(ENOMEM); | |
931 | if ( DRM_COPY_FROM_USER( buffer, depth->buffer, buffer_size ) ) { | |
932 | drm_free( buffer, buffer_size, DRM_MEM_BUFS); | |
933 | return DRM_ERR(EFAULT); | |
934 | } | |
935 | ||
936 | mask_size = depth->n * sizeof(u8); | |
937 | if ( depth->mask ) { | |
938 | mask = drm_alloc( mask_size, DRM_MEM_BUFS ); | |
939 | if ( mask == NULL ) { | |
940 | drm_free( buffer, buffer_size, DRM_MEM_BUFS ); | |
941 | return DRM_ERR(ENOMEM); | |
942 | } | |
943 | if ( DRM_COPY_FROM_USER( mask, depth->mask, mask_size ) ) { | |
944 | drm_free( buffer, buffer_size, DRM_MEM_BUFS ); | |
945 | drm_free( mask, mask_size, DRM_MEM_BUFS ); | |
946 | return DRM_ERR(EFAULT); | |
947 | } | |
948 | ||
949 | for ( i = 0 ; i < count ; i++, x++ ) { | |
950 | if ( mask[i] ) { | |
951 | BEGIN_RING( 6 ); | |
952 | ||
953 | OUT_RING( CCE_PACKET3( R128_CNTL_PAINT_MULTI, 4 ) ); | |
954 | OUT_RING( R128_GMC_DST_PITCH_OFFSET_CNTL | | |
955 | R128_GMC_BRUSH_SOLID_COLOR | | |
956 | (dev_priv->depth_fmt << 8) | | |
957 | R128_GMC_SRC_DATATYPE_COLOR | | |
958 | R128_ROP3_P | | |
959 | R128_GMC_CLR_CMP_CNTL_DIS | | |
960 | R128_GMC_WR_MSK_DIS ); | |
961 | ||
962 | OUT_RING( dev_priv->depth_pitch_offset_c ); | |
963 | OUT_RING( buffer[i] ); | |
964 | ||
965 | OUT_RING( (x << 16) | y ); | |
966 | OUT_RING( (1 << 16) | 1 ); | |
967 | ||
968 | ADVANCE_RING(); | |
969 | } | |
970 | } | |
971 | ||
972 | drm_free( mask, mask_size, DRM_MEM_BUFS ); | |
973 | } else { | |
974 | for ( i = 0 ; i < count ; i++, x++ ) { | |
975 | BEGIN_RING( 6 ); | |
976 | ||
977 | OUT_RING( CCE_PACKET3( R128_CNTL_PAINT_MULTI, 4 ) ); | |
978 | OUT_RING( R128_GMC_DST_PITCH_OFFSET_CNTL | | |
979 | R128_GMC_BRUSH_SOLID_COLOR | | |
980 | (dev_priv->depth_fmt << 8) | | |
981 | R128_GMC_SRC_DATATYPE_COLOR | | |
982 | R128_ROP3_P | | |
983 | R128_GMC_CLR_CMP_CNTL_DIS | | |
984 | R128_GMC_WR_MSK_DIS ); | |
985 | ||
986 | OUT_RING( dev_priv->depth_pitch_offset_c ); | |
987 | OUT_RING( buffer[i] ); | |
988 | ||
989 | OUT_RING( (x << 16) | y ); | |
990 | OUT_RING( (1 << 16) | 1 ); | |
991 | ||
992 | ADVANCE_RING(); | |
993 | } | |
994 | } | |
995 | ||
996 | drm_free( buffer, buffer_size, DRM_MEM_BUFS ); | |
997 | ||
998 | return 0; | |
999 | } | |
1000 | ||
1001 | static int r128_cce_dispatch_write_pixels( drm_device_t *dev, | |
1002 | drm_r128_depth_t *depth ) | |
1003 | { | |
1004 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1005 | int count, *x, *y; | |
1006 | u32 *buffer; | |
1007 | u8 *mask; | |
1008 | int i, xbuf_size, ybuf_size, buffer_size, mask_size; | |
1009 | RING_LOCALS; | |
1010 | DRM_DEBUG( "\n" ); | |
1011 | ||
1012 | count = depth->n; | |
1013 | if (count > 4096 || count <= 0) | |
1014 | return DRM_ERR(EMSGSIZE); | |
1015 | ||
1016 | xbuf_size = count * sizeof(*x); | |
1017 | ybuf_size = count * sizeof(*y); | |
1018 | x = drm_alloc( xbuf_size, DRM_MEM_BUFS ); | |
1019 | if ( x == NULL ) { | |
1020 | return DRM_ERR(ENOMEM); | |
1021 | } | |
1022 | y = drm_alloc( ybuf_size, DRM_MEM_BUFS ); | |
1023 | if ( y == NULL ) { | |
1024 | drm_free( x, xbuf_size, DRM_MEM_BUFS ); | |
1025 | return DRM_ERR(ENOMEM); | |
1026 | } | |
1027 | if ( DRM_COPY_FROM_USER( x, depth->x, xbuf_size ) ) { | |
1028 | drm_free( x, xbuf_size, DRM_MEM_BUFS ); | |
1029 | drm_free( y, ybuf_size, DRM_MEM_BUFS ); | |
1030 | return DRM_ERR(EFAULT); | |
1031 | } | |
1032 | if ( DRM_COPY_FROM_USER( y, depth->y, xbuf_size ) ) { | |
1033 | drm_free( x, xbuf_size, DRM_MEM_BUFS ); | |
1034 | drm_free( y, ybuf_size, DRM_MEM_BUFS ); | |
1035 | return DRM_ERR(EFAULT); | |
1036 | } | |
1037 | ||
1038 | buffer_size = depth->n * sizeof(u32); | |
1039 | buffer = drm_alloc( buffer_size, DRM_MEM_BUFS ); | |
1040 | if ( buffer == NULL ) { | |
1041 | drm_free( x, xbuf_size, DRM_MEM_BUFS ); | |
1042 | drm_free( y, ybuf_size, DRM_MEM_BUFS ); | |
1043 | return DRM_ERR(ENOMEM); | |
1044 | } | |
1045 | if ( DRM_COPY_FROM_USER( buffer, depth->buffer, buffer_size ) ) { | |
1046 | drm_free( x, xbuf_size, DRM_MEM_BUFS ); | |
1047 | drm_free( y, ybuf_size, DRM_MEM_BUFS ); | |
1048 | drm_free( buffer, buffer_size, DRM_MEM_BUFS ); | |
1049 | return DRM_ERR(EFAULT); | |
1050 | } | |
1051 | ||
1052 | if ( depth->mask ) { | |
1053 | mask_size = depth->n * sizeof(u8); | |
1054 | mask = drm_alloc( mask_size, DRM_MEM_BUFS ); | |
1055 | if ( mask == NULL ) { | |
1056 | drm_free( x, xbuf_size, DRM_MEM_BUFS ); | |
1057 | drm_free( y, ybuf_size, DRM_MEM_BUFS ); | |
1058 | drm_free( buffer, buffer_size, DRM_MEM_BUFS ); | |
1059 | return DRM_ERR(ENOMEM); | |
1060 | } | |
1061 | if ( DRM_COPY_FROM_USER( mask, depth->mask, mask_size ) ) { | |
1062 | drm_free( x, xbuf_size, DRM_MEM_BUFS ); | |
1063 | drm_free( y, ybuf_size, DRM_MEM_BUFS ); | |
1064 | drm_free( buffer, buffer_size, DRM_MEM_BUFS ); | |
1065 | drm_free( mask, mask_size, DRM_MEM_BUFS ); | |
1066 | return DRM_ERR(EFAULT); | |
1067 | } | |
1068 | ||
1069 | for ( i = 0 ; i < count ; i++ ) { | |
1070 | if ( mask[i] ) { | |
1071 | BEGIN_RING( 6 ); | |
1072 | ||
1073 | OUT_RING( CCE_PACKET3( R128_CNTL_PAINT_MULTI, 4 ) ); | |
1074 | OUT_RING( R128_GMC_DST_PITCH_OFFSET_CNTL | | |
1075 | R128_GMC_BRUSH_SOLID_COLOR | | |
1076 | (dev_priv->depth_fmt << 8) | | |
1077 | R128_GMC_SRC_DATATYPE_COLOR | | |
1078 | R128_ROP3_P | | |
1079 | R128_GMC_CLR_CMP_CNTL_DIS | | |
1080 | R128_GMC_WR_MSK_DIS ); | |
1081 | ||
1082 | OUT_RING( dev_priv->depth_pitch_offset_c ); | |
1083 | OUT_RING( buffer[i] ); | |
1084 | ||
1085 | OUT_RING( (x[i] << 16) | y[i] ); | |
1086 | OUT_RING( (1 << 16) | 1 ); | |
1087 | ||
1088 | ADVANCE_RING(); | |
1089 | } | |
1090 | } | |
1091 | ||
1092 | drm_free( mask, mask_size, DRM_MEM_BUFS ); | |
1093 | } else { | |
1094 | for ( i = 0 ; i < count ; i++ ) { | |
1095 | BEGIN_RING( 6 ); | |
1096 | ||
1097 | OUT_RING( CCE_PACKET3( R128_CNTL_PAINT_MULTI, 4 ) ); | |
1098 | OUT_RING( R128_GMC_DST_PITCH_OFFSET_CNTL | | |
1099 | R128_GMC_BRUSH_SOLID_COLOR | | |
1100 | (dev_priv->depth_fmt << 8) | | |
1101 | R128_GMC_SRC_DATATYPE_COLOR | | |
1102 | R128_ROP3_P | | |
1103 | R128_GMC_CLR_CMP_CNTL_DIS | | |
1104 | R128_GMC_WR_MSK_DIS ); | |
1105 | ||
1106 | OUT_RING( dev_priv->depth_pitch_offset_c ); | |
1107 | OUT_RING( buffer[i] ); | |
1108 | ||
1109 | OUT_RING( (x[i] << 16) | y[i] ); | |
1110 | OUT_RING( (1 << 16) | 1 ); | |
1111 | ||
1112 | ADVANCE_RING(); | |
1113 | } | |
1114 | } | |
1115 | ||
1116 | drm_free( x, xbuf_size, DRM_MEM_BUFS ); | |
1117 | drm_free( y, ybuf_size, DRM_MEM_BUFS ); | |
1118 | drm_free( buffer, buffer_size, DRM_MEM_BUFS ); | |
1119 | ||
1120 | return 0; | |
1121 | } | |
1122 | ||
1123 | static int r128_cce_dispatch_read_span( drm_device_t *dev, | |
1124 | drm_r128_depth_t *depth ) | |
1125 | { | |
1126 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1127 | int count, x, y; | |
1128 | RING_LOCALS; | |
1129 | DRM_DEBUG( "\n" ); | |
1130 | ||
1131 | count = depth->n; | |
1132 | if (count > 4096 || count <= 0) | |
1133 | return DRM_ERR(EMSGSIZE); | |
1134 | ||
1135 | if ( DRM_COPY_FROM_USER( &x, depth->x, sizeof(x) ) ) { | |
1136 | return DRM_ERR(EFAULT); | |
1137 | } | |
1138 | if ( DRM_COPY_FROM_USER( &y, depth->y, sizeof(y) ) ) { | |
1139 | return DRM_ERR(EFAULT); | |
1140 | } | |
1141 | ||
1142 | BEGIN_RING( 7 ); | |
1143 | ||
1144 | OUT_RING( CCE_PACKET3( R128_CNTL_BITBLT_MULTI, 5 ) ); | |
1145 | OUT_RING( R128_GMC_SRC_PITCH_OFFSET_CNTL | | |
1146 | R128_GMC_DST_PITCH_OFFSET_CNTL | | |
1147 | R128_GMC_BRUSH_NONE | | |
1148 | (dev_priv->depth_fmt << 8) | | |
1149 | R128_GMC_SRC_DATATYPE_COLOR | | |
1150 | R128_ROP3_S | | |
1151 | R128_DP_SRC_SOURCE_MEMORY | | |
1152 | R128_GMC_CLR_CMP_CNTL_DIS | | |
1153 | R128_GMC_WR_MSK_DIS ); | |
1154 | ||
1155 | OUT_RING( dev_priv->depth_pitch_offset_c ); | |
1156 | OUT_RING( dev_priv->span_pitch_offset_c ); | |
1157 | ||
1158 | OUT_RING( (x << 16) | y ); | |
1159 | OUT_RING( (0 << 16) | 0 ); | |
1160 | OUT_RING( (count << 16) | 1 ); | |
1161 | ||
1162 | ADVANCE_RING(); | |
1163 | ||
1164 | return 0; | |
1165 | } | |
1166 | ||
1167 | static int r128_cce_dispatch_read_pixels( drm_device_t *dev, | |
1168 | drm_r128_depth_t *depth ) | |
1169 | { | |
1170 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1171 | int count, *x, *y; | |
1172 | int i, xbuf_size, ybuf_size; | |
1173 | RING_LOCALS; | |
1174 | DRM_DEBUG( "%s\n", __FUNCTION__ ); | |
1175 | ||
1176 | count = depth->n; | |
1177 | if (count > 4096 || count <= 0) | |
1178 | return DRM_ERR(EMSGSIZE); | |
1179 | ||
1180 | if ( count > dev_priv->depth_pitch ) { | |
1181 | count = dev_priv->depth_pitch; | |
1182 | } | |
1183 | ||
1184 | xbuf_size = count * sizeof(*x); | |
1185 | ybuf_size = count * sizeof(*y); | |
1186 | x = drm_alloc( xbuf_size, DRM_MEM_BUFS ); | |
1187 | if ( x == NULL ) { | |
1188 | return DRM_ERR(ENOMEM); | |
1189 | } | |
1190 | y = drm_alloc( ybuf_size, DRM_MEM_BUFS ); | |
1191 | if ( y == NULL ) { | |
1192 | drm_free( x, xbuf_size, DRM_MEM_BUFS ); | |
1193 | return DRM_ERR(ENOMEM); | |
1194 | } | |
1195 | if ( DRM_COPY_FROM_USER( x, depth->x, xbuf_size ) ) { | |
1196 | drm_free( x, xbuf_size, DRM_MEM_BUFS ); | |
1197 | drm_free( y, ybuf_size, DRM_MEM_BUFS ); | |
1198 | return DRM_ERR(EFAULT); | |
1199 | } | |
1200 | if ( DRM_COPY_FROM_USER( y, depth->y, ybuf_size ) ) { | |
1201 | drm_free( x, xbuf_size, DRM_MEM_BUFS ); | |
1202 | drm_free( y, ybuf_size, DRM_MEM_BUFS ); | |
1203 | return DRM_ERR(EFAULT); | |
1204 | } | |
1205 | ||
1206 | for ( i = 0 ; i < count ; i++ ) { | |
1207 | BEGIN_RING( 7 ); | |
1208 | ||
1209 | OUT_RING( CCE_PACKET3( R128_CNTL_BITBLT_MULTI, 5 ) ); | |
1210 | OUT_RING( R128_GMC_SRC_PITCH_OFFSET_CNTL | | |
1211 | R128_GMC_DST_PITCH_OFFSET_CNTL | | |
1212 | R128_GMC_BRUSH_NONE | | |
1213 | (dev_priv->depth_fmt << 8) | | |
1214 | R128_GMC_SRC_DATATYPE_COLOR | | |
1215 | R128_ROP3_S | | |
1216 | R128_DP_SRC_SOURCE_MEMORY | | |
1217 | R128_GMC_CLR_CMP_CNTL_DIS | | |
1218 | R128_GMC_WR_MSK_DIS ); | |
1219 | ||
1220 | OUT_RING( dev_priv->depth_pitch_offset_c ); | |
1221 | OUT_RING( dev_priv->span_pitch_offset_c ); | |
1222 | ||
1223 | OUT_RING( (x[i] << 16) | y[i] ); | |
1224 | OUT_RING( (i << 16) | 0 ); | |
1225 | OUT_RING( (1 << 16) | 1 ); | |
1226 | ||
1227 | ADVANCE_RING(); | |
1228 | } | |
1229 | ||
1230 | drm_free( x, xbuf_size, DRM_MEM_BUFS ); | |
1231 | drm_free( y, ybuf_size, DRM_MEM_BUFS ); | |
1232 | ||
1233 | return 0; | |
1234 | } | |
1235 | ||
1236 | ||
1237 | /* ================================================================ | |
1238 | * Polygon stipple | |
1239 | */ | |
1240 | ||
1241 | static void r128_cce_dispatch_stipple( drm_device_t *dev, u32 *stipple ) | |
1242 | { | |
1243 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1244 | int i; | |
1245 | RING_LOCALS; | |
1246 | DRM_DEBUG( "%s\n", __FUNCTION__ ); | |
1247 | ||
1248 | BEGIN_RING( 33 ); | |
1249 | ||
1250 | OUT_RING( CCE_PACKET0( R128_BRUSH_DATA0, 31 ) ); | |
1251 | for ( i = 0 ; i < 32 ; i++ ) { | |
1252 | OUT_RING( stipple[i] ); | |
1253 | } | |
1254 | ||
1255 | ADVANCE_RING(); | |
1256 | } | |
1257 | ||
1258 | ||
1259 | /* ================================================================ | |
1260 | * IOCTL functions | |
1261 | */ | |
1262 | ||
1263 | static int r128_cce_clear( DRM_IOCTL_ARGS ) | |
1264 | { | |
1265 | DRM_DEVICE; | |
1266 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1267 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
1268 | drm_r128_clear_t clear; | |
1269 | DRM_DEBUG( "\n" ); | |
1270 | ||
1271 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
1272 | ||
1273 | DRM_COPY_FROM_USER_IOCTL( clear, (drm_r128_clear_t __user *) data, | |
1274 | sizeof(clear) ); | |
1275 | ||
1276 | RING_SPACE_TEST_WITH_RETURN( dev_priv ); | |
1277 | ||
1278 | if ( sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS ) | |
1279 | sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS; | |
1280 | ||
1281 | r128_cce_dispatch_clear( dev, &clear ); | |
1282 | COMMIT_RING(); | |
1283 | ||
1284 | /* Make sure we restore the 3D state next time. | |
1285 | */ | |
1286 | dev_priv->sarea_priv->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS; | |
1287 | ||
1288 | return 0; | |
1289 | } | |
1290 | ||
1291 | static int r128_do_init_pageflip( drm_device_t *dev ) | |
1292 | { | |
1293 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1294 | DRM_DEBUG( "\n" ); | |
1295 | ||
1296 | dev_priv->crtc_offset = R128_READ( R128_CRTC_OFFSET ); | |
1297 | dev_priv->crtc_offset_cntl = R128_READ( R128_CRTC_OFFSET_CNTL ); | |
1298 | ||
1299 | R128_WRITE( R128_CRTC_OFFSET, dev_priv->front_offset ); | |
1300 | R128_WRITE( R128_CRTC_OFFSET_CNTL, | |
1301 | dev_priv->crtc_offset_cntl | R128_CRTC_OFFSET_FLIP_CNTL ); | |
1302 | ||
1303 | dev_priv->page_flipping = 1; | |
1304 | dev_priv->current_page = 0; | |
1305 | dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page; | |
1306 | ||
1307 | return 0; | |
1308 | } | |
1309 | ||
c94f7029 | 1310 | static int r128_do_cleanup_pageflip( drm_device_t *dev ) |
1da177e4 LT |
1311 | { |
1312 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1313 | DRM_DEBUG( "\n" ); | |
1314 | ||
1315 | R128_WRITE( R128_CRTC_OFFSET, dev_priv->crtc_offset ); | |
1316 | R128_WRITE( R128_CRTC_OFFSET_CNTL, dev_priv->crtc_offset_cntl ); | |
1317 | ||
1318 | if (dev_priv->current_page != 0) { | |
1319 | r128_cce_dispatch_flip( dev ); | |
1320 | COMMIT_RING(); | |
1321 | } | |
1322 | ||
1323 | dev_priv->page_flipping = 0; | |
1324 | return 0; | |
1325 | } | |
1326 | ||
1327 | /* Swapping and flipping are different operations, need different ioctls. | |
1328 | * They can & should be intermixed to support multiple 3d windows. | |
1329 | */ | |
1330 | ||
1331 | static int r128_cce_flip( DRM_IOCTL_ARGS ) | |
1332 | { | |
1333 | DRM_DEVICE; | |
1334 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1335 | DRM_DEBUG( "%s\n", __FUNCTION__ ); | |
1336 | ||
1337 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
1338 | ||
1339 | RING_SPACE_TEST_WITH_RETURN( dev_priv ); | |
1340 | ||
1341 | if (!dev_priv->page_flipping) | |
1342 | r128_do_init_pageflip( dev ); | |
1343 | ||
1344 | r128_cce_dispatch_flip( dev ); | |
1345 | ||
1346 | COMMIT_RING(); | |
1347 | return 0; | |
1348 | } | |
1349 | ||
1350 | static int r128_cce_swap( DRM_IOCTL_ARGS ) | |
1351 | { | |
1352 | DRM_DEVICE; | |
1353 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1354 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | |
1355 | DRM_DEBUG( "%s\n", __FUNCTION__ ); | |
1356 | ||
1357 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
1358 | ||
1359 | RING_SPACE_TEST_WITH_RETURN( dev_priv ); | |
1360 | ||
1361 | if ( sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS ) | |
1362 | sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS; | |
1363 | ||
1364 | r128_cce_dispatch_swap( dev ); | |
1365 | dev_priv->sarea_priv->dirty |= (R128_UPLOAD_CONTEXT | | |
1366 | R128_UPLOAD_MASKS); | |
1367 | ||
1368 | COMMIT_RING(); | |
1369 | return 0; | |
1370 | } | |
1371 | ||
1372 | static int r128_cce_vertex( DRM_IOCTL_ARGS ) | |
1373 | { | |
1374 | DRM_DEVICE; | |
1375 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1376 | drm_device_dma_t *dma = dev->dma; | |
1377 | drm_buf_t *buf; | |
1378 | drm_r128_buf_priv_t *buf_priv; | |
1379 | drm_r128_vertex_t vertex; | |
1380 | ||
1381 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
1382 | ||
1383 | if ( !dev_priv ) { | |
1384 | DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); | |
1385 | return DRM_ERR(EINVAL); | |
1386 | } | |
1387 | ||
1388 | DRM_COPY_FROM_USER_IOCTL( vertex, (drm_r128_vertex_t __user *) data, | |
1389 | sizeof(vertex) ); | |
1390 | ||
1391 | DRM_DEBUG( "pid=%d index=%d count=%d discard=%d\n", | |
1392 | DRM_CURRENTPID, | |
1393 | vertex.idx, vertex.count, vertex.discard ); | |
1394 | ||
1395 | if ( vertex.idx < 0 || vertex.idx >= dma->buf_count ) { | |
1396 | DRM_ERROR( "buffer index %d (of %d max)\n", | |
1397 | vertex.idx, dma->buf_count - 1 ); | |
1398 | return DRM_ERR(EINVAL); | |
1399 | } | |
1400 | if ( vertex.prim < 0 || | |
1401 | vertex.prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2 ) { | |
1402 | DRM_ERROR( "buffer prim %d\n", vertex.prim ); | |
1403 | return DRM_ERR(EINVAL); | |
1404 | } | |
1405 | ||
1406 | RING_SPACE_TEST_WITH_RETURN( dev_priv ); | |
1407 | VB_AGE_TEST_WITH_RETURN( dev_priv ); | |
1408 | ||
1409 | buf = dma->buflist[vertex.idx]; | |
1410 | buf_priv = buf->dev_private; | |
1411 | ||
1412 | if ( buf->filp != filp ) { | |
1413 | DRM_ERROR( "process %d using buffer owned by %p\n", | |
1414 | DRM_CURRENTPID, buf->filp ); | |
1415 | return DRM_ERR(EINVAL); | |
1416 | } | |
1417 | if ( buf->pending ) { | |
1418 | DRM_ERROR( "sending pending buffer %d\n", vertex.idx ); | |
1419 | return DRM_ERR(EINVAL); | |
1420 | } | |
1421 | ||
1422 | buf->used = vertex.count; | |
1423 | buf_priv->prim = vertex.prim; | |
1424 | buf_priv->discard = vertex.discard; | |
1425 | ||
1426 | r128_cce_dispatch_vertex( dev, buf ); | |
1427 | ||
1428 | COMMIT_RING(); | |
1429 | return 0; | |
1430 | } | |
1431 | ||
1432 | static int r128_cce_indices( DRM_IOCTL_ARGS ) | |
1433 | { | |
1434 | DRM_DEVICE; | |
1435 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1436 | drm_device_dma_t *dma = dev->dma; | |
1437 | drm_buf_t *buf; | |
1438 | drm_r128_buf_priv_t *buf_priv; | |
1439 | drm_r128_indices_t elts; | |
1440 | int count; | |
1441 | ||
1442 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
1443 | ||
1444 | if ( !dev_priv ) { | |
1445 | DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); | |
1446 | return DRM_ERR(EINVAL); | |
1447 | } | |
1448 | ||
1449 | DRM_COPY_FROM_USER_IOCTL( elts, (drm_r128_indices_t __user *) data, | |
1450 | sizeof(elts) ); | |
1451 | ||
1452 | DRM_DEBUG( "pid=%d buf=%d s=%d e=%d d=%d\n", DRM_CURRENTPID, | |
1453 | elts.idx, elts.start, elts.end, elts.discard ); | |
1454 | ||
1455 | if ( elts.idx < 0 || elts.idx >= dma->buf_count ) { | |
1456 | DRM_ERROR( "buffer index %d (of %d max)\n", | |
1457 | elts.idx, dma->buf_count - 1 ); | |
1458 | return DRM_ERR(EINVAL); | |
1459 | } | |
1460 | if ( elts.prim < 0 || | |
1461 | elts.prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2 ) { | |
1462 | DRM_ERROR( "buffer prim %d\n", elts.prim ); | |
1463 | return DRM_ERR(EINVAL); | |
1464 | } | |
1465 | ||
1466 | RING_SPACE_TEST_WITH_RETURN( dev_priv ); | |
1467 | VB_AGE_TEST_WITH_RETURN( dev_priv ); | |
1468 | ||
1469 | buf = dma->buflist[elts.idx]; | |
1470 | buf_priv = buf->dev_private; | |
1471 | ||
1472 | if ( buf->filp != filp ) { | |
1473 | DRM_ERROR( "process %d using buffer owned by %p\n", | |
1474 | DRM_CURRENTPID, buf->filp ); | |
1475 | return DRM_ERR(EINVAL); | |
1476 | } | |
1477 | if ( buf->pending ) { | |
1478 | DRM_ERROR( "sending pending buffer %d\n", elts.idx ); | |
1479 | return DRM_ERR(EINVAL); | |
1480 | } | |
1481 | ||
1482 | count = (elts.end - elts.start) / sizeof(u16); | |
1483 | elts.start -= R128_INDEX_PRIM_OFFSET; | |
1484 | ||
1485 | if ( elts.start & 0x7 ) { | |
1486 | DRM_ERROR( "misaligned buffer 0x%x\n", elts.start ); | |
1487 | return DRM_ERR(EINVAL); | |
1488 | } | |
1489 | if ( elts.start < buf->used ) { | |
1490 | DRM_ERROR( "no header 0x%x - 0x%x\n", elts.start, buf->used ); | |
1491 | return DRM_ERR(EINVAL); | |
1492 | } | |
1493 | ||
1494 | buf->used = elts.end; | |
1495 | buf_priv->prim = elts.prim; | |
1496 | buf_priv->discard = elts.discard; | |
1497 | ||
1498 | r128_cce_dispatch_indices( dev, buf, elts.start, elts.end, count ); | |
1499 | ||
1500 | COMMIT_RING(); | |
1501 | return 0; | |
1502 | } | |
1503 | ||
1504 | static int r128_cce_blit( DRM_IOCTL_ARGS ) | |
1505 | { | |
1506 | DRM_DEVICE; | |
1507 | drm_device_dma_t *dma = dev->dma; | |
1508 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1509 | drm_r128_blit_t blit; | |
1510 | int ret; | |
1511 | ||
1512 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
1513 | ||
1514 | DRM_COPY_FROM_USER_IOCTL( blit, (drm_r128_blit_t __user *) data, | |
1515 | sizeof(blit) ); | |
1516 | ||
1517 | DRM_DEBUG( "pid=%d index=%d\n", DRM_CURRENTPID, blit.idx ); | |
1518 | ||
1519 | if ( blit.idx < 0 || blit.idx >= dma->buf_count ) { | |
1520 | DRM_ERROR( "buffer index %d (of %d max)\n", | |
1521 | blit.idx, dma->buf_count - 1 ); | |
1522 | return DRM_ERR(EINVAL); | |
1523 | } | |
1524 | ||
1525 | RING_SPACE_TEST_WITH_RETURN( dev_priv ); | |
1526 | VB_AGE_TEST_WITH_RETURN( dev_priv ); | |
1527 | ||
1528 | ret = r128_cce_dispatch_blit( filp, dev, &blit ); | |
1529 | ||
1530 | COMMIT_RING(); | |
1531 | return ret; | |
1532 | } | |
1533 | ||
1534 | static int r128_cce_depth( DRM_IOCTL_ARGS ) | |
1535 | { | |
1536 | DRM_DEVICE; | |
1537 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1538 | drm_r128_depth_t depth; | |
1539 | int ret; | |
1540 | ||
1541 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
1542 | ||
1543 | DRM_COPY_FROM_USER_IOCTL( depth, (drm_r128_depth_t __user *) data, | |
1544 | sizeof(depth) ); | |
1545 | ||
1546 | RING_SPACE_TEST_WITH_RETURN( dev_priv ); | |
1547 | ||
1548 | ret = DRM_ERR(EINVAL); | |
1549 | switch ( depth.func ) { | |
1550 | case R128_WRITE_SPAN: | |
1551 | ret = r128_cce_dispatch_write_span( dev, &depth ); | |
41aac24f | 1552 | break; |
1da177e4 LT |
1553 | case R128_WRITE_PIXELS: |
1554 | ret = r128_cce_dispatch_write_pixels( dev, &depth ); | |
41aac24f | 1555 | break; |
1da177e4 LT |
1556 | case R128_READ_SPAN: |
1557 | ret = r128_cce_dispatch_read_span( dev, &depth ); | |
41aac24f | 1558 | break; |
1da177e4 LT |
1559 | case R128_READ_PIXELS: |
1560 | ret = r128_cce_dispatch_read_pixels( dev, &depth ); | |
41aac24f | 1561 | break; |
1da177e4 LT |
1562 | } |
1563 | ||
1564 | COMMIT_RING(); | |
1565 | return ret; | |
1566 | } | |
1567 | ||
1568 | static int r128_cce_stipple( DRM_IOCTL_ARGS ) | |
1569 | { | |
1570 | DRM_DEVICE; | |
1571 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1572 | drm_r128_stipple_t stipple; | |
1573 | u32 mask[32]; | |
1574 | ||
1575 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
1576 | ||
1577 | DRM_COPY_FROM_USER_IOCTL( stipple, (drm_r128_stipple_t __user *) data, | |
1578 | sizeof(stipple) ); | |
1579 | ||
1580 | if ( DRM_COPY_FROM_USER( &mask, stipple.mask, | |
1581 | 32 * sizeof(u32) ) ) | |
1582 | return DRM_ERR( EFAULT ); | |
1583 | ||
1584 | RING_SPACE_TEST_WITH_RETURN( dev_priv ); | |
1585 | ||
1586 | r128_cce_dispatch_stipple( dev, mask ); | |
1587 | ||
1588 | COMMIT_RING(); | |
1589 | return 0; | |
1590 | } | |
1591 | ||
1592 | static int r128_cce_indirect( DRM_IOCTL_ARGS ) | |
1593 | { | |
1594 | DRM_DEVICE; | |
1595 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1596 | drm_device_dma_t *dma = dev->dma; | |
1597 | drm_buf_t *buf; | |
1598 | drm_r128_buf_priv_t *buf_priv; | |
1599 | drm_r128_indirect_t indirect; | |
1600 | #if 0 | |
1601 | RING_LOCALS; | |
1602 | #endif | |
1603 | ||
1604 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
1605 | ||
1606 | if ( !dev_priv ) { | |
1607 | DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); | |
1608 | return DRM_ERR(EINVAL); | |
1609 | } | |
1610 | ||
1611 | DRM_COPY_FROM_USER_IOCTL( indirect, (drm_r128_indirect_t __user *) data, | |
1612 | sizeof(indirect) ); | |
1613 | ||
1614 | DRM_DEBUG( "indirect: idx=%d s=%d e=%d d=%d\n", | |
1615 | indirect.idx, indirect.start, | |
1616 | indirect.end, indirect.discard ); | |
1617 | ||
1618 | if ( indirect.idx < 0 || indirect.idx >= dma->buf_count ) { | |
1619 | DRM_ERROR( "buffer index %d (of %d max)\n", | |
1620 | indirect.idx, dma->buf_count - 1 ); | |
1621 | return DRM_ERR(EINVAL); | |
1622 | } | |
1623 | ||
1624 | buf = dma->buflist[indirect.idx]; | |
1625 | buf_priv = buf->dev_private; | |
1626 | ||
1627 | if ( buf->filp != filp ) { | |
1628 | DRM_ERROR( "process %d using buffer owned by %p\n", | |
1629 | DRM_CURRENTPID, buf->filp ); | |
1630 | return DRM_ERR(EINVAL); | |
1631 | } | |
1632 | if ( buf->pending ) { | |
1633 | DRM_ERROR( "sending pending buffer %d\n", indirect.idx ); | |
1634 | return DRM_ERR(EINVAL); | |
1635 | } | |
1636 | ||
1637 | if ( indirect.start < buf->used ) { | |
1638 | DRM_ERROR( "reusing indirect: start=0x%x actual=0x%x\n", | |
1639 | indirect.start, buf->used ); | |
1640 | return DRM_ERR(EINVAL); | |
1641 | } | |
1642 | ||
1643 | RING_SPACE_TEST_WITH_RETURN( dev_priv ); | |
1644 | VB_AGE_TEST_WITH_RETURN( dev_priv ); | |
1645 | ||
1646 | buf->used = indirect.end; | |
1647 | buf_priv->discard = indirect.discard; | |
1648 | ||
1649 | #if 0 | |
1650 | /* Wait for the 3D stream to idle before the indirect buffer | |
1651 | * containing 2D acceleration commands is processed. | |
1652 | */ | |
1653 | BEGIN_RING( 2 ); | |
1654 | RADEON_WAIT_UNTIL_3D_IDLE(); | |
1655 | ADVANCE_RING(); | |
1656 | #endif | |
1657 | ||
1658 | /* Dispatch the indirect buffer full of commands from the | |
1659 | * X server. This is insecure and is thus only available to | |
1660 | * privileged clients. | |
1661 | */ | |
1662 | r128_cce_dispatch_indirect( dev, buf, indirect.start, indirect.end ); | |
1663 | ||
1664 | COMMIT_RING(); | |
1665 | return 0; | |
1666 | } | |
1667 | ||
1668 | static int r128_getparam( DRM_IOCTL_ARGS ) | |
1669 | { | |
1670 | DRM_DEVICE; | |
1671 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1672 | drm_r128_getparam_t param; | |
1673 | int value; | |
1674 | ||
1675 | if ( !dev_priv ) { | |
1676 | DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); | |
1677 | return DRM_ERR(EINVAL); | |
1678 | } | |
1679 | ||
1680 | DRM_COPY_FROM_USER_IOCTL( param, (drm_r128_getparam_t __user *)data, | |
1681 | sizeof(param) ); | |
1682 | ||
1683 | DRM_DEBUG( "pid=%d\n", DRM_CURRENTPID ); | |
1684 | ||
1685 | switch( param.param ) { | |
1686 | case R128_PARAM_IRQ_NR: | |
1687 | value = dev->irq; | |
1688 | break; | |
1689 | default: | |
1690 | return DRM_ERR(EINVAL); | |
1691 | } | |
1692 | ||
1693 | if ( DRM_COPY_TO_USER( param.value, &value, sizeof(int) ) ) { | |
1694 | DRM_ERROR( "copy_to_user\n" ); | |
1695 | return DRM_ERR(EFAULT); | |
1696 | } | |
1697 | ||
1698 | return 0; | |
1699 | } | |
1700 | ||
1701 | void r128_driver_prerelease(drm_device_t *dev, DRMFILE filp) | |
1702 | { | |
1703 | if ( dev->dev_private ) { | |
1704 | drm_r128_private_t *dev_priv = dev->dev_private; | |
1705 | if ( dev_priv->page_flipping ) { | |
1706 | r128_do_cleanup_pageflip( dev ); | |
1707 | } | |
1708 | } | |
1709 | } | |
1710 | ||
1711 | void r128_driver_pretakedown(drm_device_t *dev) | |
1712 | { | |
1713 | r128_do_cleanup_cce( dev ); | |
1714 | } | |
1715 | ||
1716 | drm_ioctl_desc_t r128_ioctls[] = { | |
1717 | [DRM_IOCTL_NR(DRM_R128_INIT)] = { r128_cce_init, 1, 1 }, | |
1718 | [DRM_IOCTL_NR(DRM_R128_CCE_START)] = { r128_cce_start, 1, 1 }, | |
1719 | [DRM_IOCTL_NR(DRM_R128_CCE_STOP)] = { r128_cce_stop, 1, 1 }, | |
1720 | [DRM_IOCTL_NR(DRM_R128_CCE_RESET)] = { r128_cce_reset, 1, 1 }, | |
1721 | [DRM_IOCTL_NR(DRM_R128_CCE_IDLE)] = { r128_cce_idle, 1, 0 }, | |
1722 | [DRM_IOCTL_NR(DRM_R128_RESET)] = { r128_engine_reset, 1, 0 }, | |
1723 | [DRM_IOCTL_NR(DRM_R128_FULLSCREEN)] = { r128_fullscreen, 1, 0 }, | |
1724 | [DRM_IOCTL_NR(DRM_R128_SWAP)] = { r128_cce_swap, 1, 0 }, | |
1725 | [DRM_IOCTL_NR(DRM_R128_FLIP)] = { r128_cce_flip, 1, 0 }, | |
1726 | [DRM_IOCTL_NR(DRM_R128_CLEAR)] = { r128_cce_clear, 1, 0 }, | |
1727 | [DRM_IOCTL_NR(DRM_R128_VERTEX)] = { r128_cce_vertex, 1, 0 }, | |
1728 | [DRM_IOCTL_NR(DRM_R128_INDICES)] = { r128_cce_indices, 1, 0 }, | |
1729 | [DRM_IOCTL_NR(DRM_R128_BLIT)] = { r128_cce_blit, 1, 0 }, | |
1730 | [DRM_IOCTL_NR(DRM_R128_DEPTH)] = { r128_cce_depth, 1, 0 }, | |
1731 | [DRM_IOCTL_NR(DRM_R128_STIPPLE)] = { r128_cce_stipple, 1, 0 }, | |
1732 | [DRM_IOCTL_NR(DRM_R128_INDIRECT)] = { r128_cce_indirect, 1, 1 }, | |
1733 | [DRM_IOCTL_NR(DRM_R128_GETPARAM)] = { r128_getparam, 1, 0 }, | |
1734 | }; | |
1735 | ||
1736 | int r128_max_ioctl = DRM_ARRAY_SIZE(r128_ioctls); |