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