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