mach64_state.c revision 145132
1/* mach64_state.c -- State support for mach64 (Rage Pro) driver -*- linux-c -*-
2 * Created: Sun Dec 03 19:20:26 2000 by gareth@valinux.com
3 *
4 * Copyright 2000 Gareth Hughes
5 * Copyright 2002-2003 Leif Delgass
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 * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 * Authors:
27 *    Gareth Hughes <gareth@valinux.com>
28 *    Leif Delgass <ldelgass@retinalburn.net>
29 *    Jos���Fonseca <j_r_fonseca@yahoo.co.uk>
30 *
31 * $FreeBSD: head/sys/dev/drm/mach64_state.c 145132 2005-04-16 03:44:47Z anholt $
32 */
33
34#include "dev/drm/drmP.h"
35#include "dev/drm/drm.h"
36#include "dev/drm/mach64_drm.h"
37#include "dev/drm/mach64_drv.h"
38
39/* Interface history:
40 *
41 * 1.0 - Initial mach64 DRM
42 *
43 */
44drm_ioctl_desc_t mach64_ioctls[] = {
45	[DRM_IOCTL_NR(DRM_MACH64_INIT)] = {mach64_dma_init, 1, 1},
46	[DRM_IOCTL_NR(DRM_MACH64_CLEAR)] = {mach64_dma_clear, 1, 0},
47	[DRM_IOCTL_NR(DRM_MACH64_SWAP)] = {mach64_dma_swap, 1, 0},
48	[DRM_IOCTL_NR(DRM_MACH64_IDLE)] = {mach64_dma_idle, 1, 0},
49	[DRM_IOCTL_NR(DRM_MACH64_RESET)] = {mach64_engine_reset, 1, 0},
50	[DRM_IOCTL_NR(DRM_MACH64_VERTEX)] = {mach64_dma_vertex, 1, 0},
51	[DRM_IOCTL_NR(DRM_MACH64_BLIT)] = {mach64_dma_blit, 1, 0},
52	[DRM_IOCTL_NR(DRM_MACH64_FLUSH)] = {mach64_dma_flush, 1, 0},
53	[DRM_IOCTL_NR(DRM_MACH64_GETPARAM)] = {mach64_get_param, 1, 0},
54};
55
56int mach64_max_ioctl = DRM_ARRAY_SIZE(mach64_ioctls);
57
58/* ================================================================
59 * DMA hardware state programming functions
60 */
61
62static void mach64_print_dirty(const char *msg, unsigned int flags)
63{
64	DRM_DEBUG("%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s\n",
65		  msg,
66		  flags,
67		  (flags & MACH64_UPLOAD_DST_OFF_PITCH) ? "dst_off_pitch, " :
68		  "",
69		  (flags & MACH64_UPLOAD_Z_ALPHA_CNTL) ? "z_alpha_cntl, " : "",
70		  (flags & MACH64_UPLOAD_SCALE_3D_CNTL) ? "scale_3d_cntl, " :
71		  "", (flags & MACH64_UPLOAD_DP_FOG_CLR) ? "dp_fog_clr, " : "",
72		  (flags & MACH64_UPLOAD_DP_WRITE_MASK) ? "dp_write_mask, " :
73		  "",
74		  (flags & MACH64_UPLOAD_DP_PIX_WIDTH) ? "dp_pix_width, " : "",
75		  (flags & MACH64_UPLOAD_SETUP_CNTL) ? "setup_cntl, " : "",
76		  (flags & MACH64_UPLOAD_MISC) ? "misc, " : "",
77		  (flags & MACH64_UPLOAD_TEXTURE) ? "texture, " : "",
78		  (flags & MACH64_UPLOAD_TEX0IMAGE) ? "tex0 image, " : "",
79		  (flags & MACH64_UPLOAD_TEX1IMAGE) ? "tex1 image, " : "",
80		  (flags & MACH64_UPLOAD_CLIPRECTS) ? "cliprects, " : "");
81}
82
83/* Mach64 doesn't have hardware cliprects, just one hardware scissor,
84 * so the GL scissor is intersected with each cliprect here
85 */
86/* This function returns 0 on success, 1 for no intersection, and
87 * negative for an error
88 */
89static int mach64_emit_cliprect(DRMFILE filp, drm_mach64_private_t * dev_priv,
90				drm_clip_rect_t * box)
91{
92	u32 sc_left_right, sc_top_bottom;
93	drm_clip_rect_t scissor;
94	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
95	drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
96	DMALOCALS;
97
98	DRM_DEBUG("%s: box=%p\n", __FUNCTION__, box);
99
100	/* Get GL scissor */
101	/* FIXME: store scissor in SAREA as a cliprect instead of in
102	 * hardware format, or do intersection client-side
103	 */
104	scissor.x1 = regs->sc_left_right & 0xffff;
105	scissor.x2 = (regs->sc_left_right & 0xffff0000) >> 16;
106	scissor.y1 = regs->sc_top_bottom & 0xffff;
107	scissor.y2 = (regs->sc_top_bottom & 0xffff0000) >> 16;
108
109	/* Intersect GL scissor with cliprect */
110	if (box->x1 > scissor.x1)
111		scissor.x1 = box->x1;
112	if (box->y1 > scissor.y1)
113		scissor.y1 = box->y1;
114	if (box->x2 < scissor.x2)
115		scissor.x2 = box->x2;
116	if (box->y2 < scissor.y2)
117		scissor.y2 = box->y2;
118	/* positive return means skip */
119	if (scissor.x1 >= scissor.x2)
120		return 1;
121	if (scissor.y1 >= scissor.y2)
122		return 1;
123
124	DMAGETPTR(filp, dev_priv, 2);	/* returns on failure to get buffer */
125
126	sc_left_right = ((scissor.x1 << 0) | (scissor.x2 << 16));
127	sc_top_bottom = ((scissor.y1 << 0) | (scissor.y2 << 16));
128
129	DMAOUTREG(MACH64_SC_LEFT_RIGHT, sc_left_right);
130	DMAOUTREG(MACH64_SC_TOP_BOTTOM, sc_top_bottom);
131
132	DMAADVANCE(dev_priv, 1);
133
134	return 0;
135}
136
137static __inline__ int mach64_emit_state(DRMFILE filp,
138					drm_mach64_private_t * dev_priv)
139{
140	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
141	drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
142	unsigned int dirty = sarea_priv->dirty;
143	u32 offset = ((regs->tex_size_pitch & 0xf0) >> 2);
144	DMALOCALS;
145
146	if (MACH64_VERBOSE) {
147		mach64_print_dirty(__FUNCTION__, dirty);
148	} else {
149		DRM_DEBUG("%s: dirty=0x%08x\n", __FUNCTION__, dirty);
150	}
151
152	DMAGETPTR(filp, dev_priv, 17);	/* returns on failure to get buffer */
153
154	if (dirty & MACH64_UPLOAD_MISC) {
155		DMAOUTREG(MACH64_DP_MIX, regs->dp_mix);
156		DMAOUTREG(MACH64_DP_SRC, regs->dp_src);
157		DMAOUTREG(MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl);
158		DMAOUTREG(MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl);
159		sarea_priv->dirty &= ~MACH64_UPLOAD_MISC;
160	}
161
162	if (dirty & MACH64_UPLOAD_DST_OFF_PITCH) {
163		DMAOUTREG(MACH64_DST_OFF_PITCH, regs->dst_off_pitch);
164		sarea_priv->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH;
165	}
166	if (dirty & MACH64_UPLOAD_Z_OFF_PITCH) {
167		DMAOUTREG(MACH64_Z_OFF_PITCH, regs->z_off_pitch);
168		sarea_priv->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH;
169	}
170	if (dirty & MACH64_UPLOAD_Z_ALPHA_CNTL) {
171		DMAOUTREG(MACH64_Z_CNTL, regs->z_cntl);
172		DMAOUTREG(MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl);
173		sarea_priv->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL;
174	}
175	if (dirty & MACH64_UPLOAD_SCALE_3D_CNTL) {
176		DMAOUTREG(MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl);
177		sarea_priv->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL;
178	}
179	if (dirty & MACH64_UPLOAD_DP_FOG_CLR) {
180		DMAOUTREG(MACH64_DP_FOG_CLR, regs->dp_fog_clr);
181		sarea_priv->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR;
182	}
183	if (dirty & MACH64_UPLOAD_DP_WRITE_MASK) {
184		DMAOUTREG(MACH64_DP_WRITE_MASK, regs->dp_write_mask);
185		sarea_priv->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK;
186	}
187	if (dirty & MACH64_UPLOAD_DP_PIX_WIDTH) {
188		DMAOUTREG(MACH64_DP_PIX_WIDTH, regs->dp_pix_width);
189		sarea_priv->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH;
190	}
191	if (dirty & MACH64_UPLOAD_SETUP_CNTL) {
192		DMAOUTREG(MACH64_SETUP_CNTL, regs->setup_cntl);
193		sarea_priv->dirty &= ~MACH64_UPLOAD_SETUP_CNTL;
194	}
195
196	if (dirty & MACH64_UPLOAD_TEXTURE) {
197		DMAOUTREG(MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch);
198		DMAOUTREG(MACH64_TEX_CNTL, regs->tex_cntl);
199		DMAOUTREG(MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off);
200		DMAOUTREG(MACH64_TEX_0_OFF + offset, regs->tex_offset);
201		sarea_priv->dirty &= ~MACH64_UPLOAD_TEXTURE;
202	}
203
204	DMAADVANCE(dev_priv, 1);
205
206	sarea_priv->dirty &= MACH64_UPLOAD_CLIPRECTS;
207
208	return 0;
209
210}
211
212/* ================================================================
213 * DMA command dispatch functions
214 */
215
216static int mach64_dma_dispatch_clear(DRMFILE filp, drm_device_t * dev,
217				     unsigned int flags,
218				     int cx, int cy, int cw, int ch,
219				     unsigned int clear_color,
220				     unsigned int clear_depth)
221{
222	drm_mach64_private_t *dev_priv = dev->dev_private;
223	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
224	drm_mach64_context_regs_t *ctx = &sarea_priv->context_state;
225	int nbox = sarea_priv->nbox;
226	drm_clip_rect_t *pbox = sarea_priv->boxes;
227	u32 fb_bpp, depth_bpp;
228	int i;
229	DMALOCALS;
230
231	DRM_DEBUG("%s\n", __FUNCTION__);
232
233	switch (dev_priv->fb_bpp) {
234	case 16:
235		fb_bpp = MACH64_DATATYPE_RGB565;
236		break;
237	case 32:
238		fb_bpp = MACH64_DATATYPE_ARGB8888;
239		break;
240	default:
241		return DRM_ERR(EINVAL);
242	}
243	switch (dev_priv->depth_bpp) {
244	case 16:
245		depth_bpp = MACH64_DATATYPE_RGB565;
246		break;
247	case 24:
248	case 32:
249		depth_bpp = MACH64_DATATYPE_ARGB8888;
250		break;
251	default:
252		return DRM_ERR(EINVAL);
253	}
254
255	if (!nbox)
256		return 0;
257
258	DMAGETPTR(filp, dev_priv, nbox * 31);	/* returns on failure to get buffer */
259
260	for (i = 0; i < nbox; i++) {
261		int x = pbox[i].x1;
262		int y = pbox[i].y1;
263		int w = pbox[i].x2 - x;
264		int h = pbox[i].y2 - y;
265
266		DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
267			  pbox[i].x1, pbox[i].y1,
268			  pbox[i].x2, pbox[i].y2, flags);
269
270		if (flags & (MACH64_FRONT | MACH64_BACK)) {
271			/* Setup for color buffer clears
272			 */
273
274			DMAOUTREG(MACH64_Z_CNTL, 0);
275			DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
276
277			DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
278			DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
279
280			DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
281			DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
282				  (MACH64_DST_X_LEFT_TO_RIGHT |
283				   MACH64_DST_Y_TOP_TO_BOTTOM));
284
285			DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
286							(fb_bpp << 4) |
287							(fb_bpp << 8) |
288							(fb_bpp << 16) |
289							(fb_bpp << 28)));
290
291			DMAOUTREG(MACH64_DP_FRGD_CLR, clear_color);
292			DMAOUTREG(MACH64_DP_WRITE_MASK, ctx->dp_write_mask);
293			DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
294						  MACH64_FRGD_MIX_S));
295			DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
296						  MACH64_FRGD_SRC_FRGD_CLR |
297						  MACH64_MONO_SRC_ONE));
298
299		}
300
301		if (flags & MACH64_FRONT) {
302
303			DMAOUTREG(MACH64_DST_OFF_PITCH,
304				  dev_priv->front_offset_pitch);
305			DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
306			DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
307
308		}
309
310		if (flags & MACH64_BACK) {
311
312			DMAOUTREG(MACH64_DST_OFF_PITCH,
313				  dev_priv->back_offset_pitch);
314			DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
315			DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
316
317		}
318
319		if (flags & MACH64_DEPTH) {
320			/* Setup for depth buffer clear
321			 */
322			DMAOUTREG(MACH64_Z_CNTL, 0);
323			DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
324
325			DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
326			DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
327
328			DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
329			DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
330				  (MACH64_DST_X_LEFT_TO_RIGHT |
331				   MACH64_DST_Y_TOP_TO_BOTTOM));
332
333			DMAOUTREG(MACH64_DP_PIX_WIDTH, ((depth_bpp << 0) |
334							(depth_bpp << 4) |
335							(depth_bpp << 8) |
336							(depth_bpp << 16) |
337							(depth_bpp << 28)));
338
339			DMAOUTREG(MACH64_DP_FRGD_CLR, clear_depth);
340			DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
341			DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
342						  MACH64_FRGD_MIX_S));
343			DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
344						  MACH64_FRGD_SRC_FRGD_CLR |
345						  MACH64_MONO_SRC_ONE));
346
347			DMAOUTREG(MACH64_DST_OFF_PITCH,
348				  dev_priv->depth_offset_pitch);
349			DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
350			DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
351		}
352	}
353
354	DMAADVANCE(dev_priv, 1);
355
356	return 0;
357}
358
359static int mach64_dma_dispatch_swap(DRMFILE filp, drm_device_t * dev)
360{
361	drm_mach64_private_t *dev_priv = dev->dev_private;
362	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
363	int nbox = sarea_priv->nbox;
364	drm_clip_rect_t *pbox = sarea_priv->boxes;
365	u32 fb_bpp;
366	int i;
367	DMALOCALS;
368
369	DRM_DEBUG("%s\n", __FUNCTION__);
370
371	switch (dev_priv->fb_bpp) {
372	case 16:
373		fb_bpp = MACH64_DATATYPE_RGB565;
374		break;
375	case 32:
376	default:
377		fb_bpp = MACH64_DATATYPE_ARGB8888;
378		break;
379	}
380
381	if (!nbox)
382		return 0;
383
384	DMAGETPTR(filp, dev_priv, 13 + nbox * 4);	/* returns on failure to get buffer */
385
386	DMAOUTREG(MACH64_Z_CNTL, 0);
387	DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
388
389	DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16));	/* no scissor */
390	DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
391
392	DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
393	DMAOUTREG(MACH64_GUI_TRAJ_CNTL, (MACH64_DST_X_LEFT_TO_RIGHT |
394					 MACH64_DST_Y_TOP_TO_BOTTOM));
395
396	DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
397					(fb_bpp << 4) |
398					(fb_bpp << 8) |
399					(fb_bpp << 16) | (fb_bpp << 28)));
400
401	DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
402	DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S));
403	DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_BKGD_CLR |
404				  MACH64_FRGD_SRC_BLIT | MACH64_MONO_SRC_ONE));
405
406	DMAOUTREG(MACH64_SRC_OFF_PITCH, dev_priv->back_offset_pitch);
407	DMAOUTREG(MACH64_DST_OFF_PITCH, dev_priv->front_offset_pitch);
408
409	for (i = 0; i < nbox; i++) {
410		int x = pbox[i].x1;
411		int y = pbox[i].y1;
412		int w = pbox[i].x2 - x;
413		int h = pbox[i].y2 - y;
414
415		DRM_DEBUG("dispatch swap %d,%d-%d,%d\n",
416			  pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2);
417
418		DMAOUTREG(MACH64_SRC_WIDTH1, w);
419		DMAOUTREG(MACH64_SRC_Y_X, (x << 16) | y);
420		DMAOUTREG(MACH64_DST_Y_X, (x << 16) | y);
421		DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
422
423	}
424
425	DMAADVANCE(dev_priv, 1);
426
427	if (dev_priv->driver_mode == MACH64_MODE_DMA_ASYNC) {
428		for (i = 0; i < MACH64_MAX_QUEUED_FRAMES - 1; i++) {
429			dev_priv->frame_ofs[i] = dev_priv->frame_ofs[i + 1];
430		}
431		dev_priv->frame_ofs[i] = GETRINGOFFSET();
432
433		dev_priv->sarea_priv->frames_queued++;
434	}
435
436	return 0;
437}
438
439static int mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv)
440{
441	drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
442	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
443	int i, start;
444	u32 head, tail, ofs;
445
446	DRM_DEBUG("%s\n", __FUNCTION__);
447
448	if (sarea_priv->frames_queued == 0)
449		return 0;
450
451	tail = ring->tail;
452	mach64_ring_tick(dev_priv, ring);
453	head = ring->head;
454
455	start = (MACH64_MAX_QUEUED_FRAMES -
456		 DRM_MIN(MACH64_MAX_QUEUED_FRAMES, sarea_priv->frames_queued));
457
458	if (head == tail) {
459		sarea_priv->frames_queued = 0;
460		for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
461			dev_priv->frame_ofs[i] = ~0;
462		}
463		return 0;
464	}
465
466	for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
467		ofs = dev_priv->frame_ofs[i];
468		DRM_DEBUG("frame_ofs[%d] ofs: %d\n", i, ofs);
469		if (ofs == ~0 ||
470		    (head < tail && (ofs < head || ofs >= tail)) ||
471		    (head > tail && (ofs < head && ofs >= tail))) {
472			sarea_priv->frames_queued =
473			    (MACH64_MAX_QUEUED_FRAMES - 1) - i;
474			dev_priv->frame_ofs[i] = ~0;
475		}
476	}
477
478	return sarea_priv->frames_queued;
479}
480
481/* Copy and verify a client submited buffer.
482 * FIXME: Make an assembly optimized version
483 */
484static __inline__ int copy_and_verify_from_user(u32 * to, const u32 * from,
485						unsigned long bytes)
486{
487	unsigned long n = bytes;	/* dwords remaining in buffer */
488
489	if (DRM_VERIFYAREA_READ(from, n)) {
490		DRM_ERROR("%s: verify_area\n", __FUNCTION__);
491		return DRM_ERR(EFAULT);
492	}
493
494	n >>= 2;
495
496	while (n > 1) {
497		u32 data, reg, count;
498
499		if (DRM_GET_USER_UNCHECKED(data, from++)) {
500			DRM_ERROR("%s: get_user\n", __FUNCTION__);
501			return DRM_ERR(EFAULT);
502		}
503
504		n--;
505
506		reg = le32_to_cpu(data);
507		count = (reg >> 16) + 1;
508		if (count <= n) {
509			n -= count;
510			reg &= 0xffff;
511
512			/* This is an exact match of Mach64's Setup Engine registers,
513			 * excluding SETUP_CNTL (1_C1).
514			 */
515			if ((reg >= 0x0190 && reg < 0x01c1) ||
516			    (reg >= 0x01ca && reg <= 0x01cf)) {
517				*to++ = data;
518				if (DRM_COPY_FROM_USER_UNCHECKED
519				    (to, from, count << 2)) {
520					DRM_ERROR("%s: copy_from_user\n",
521						  __FUNCTION__);
522					return DRM_ERR(EFAULT);
523				}
524				to += count;
525			} else {
526				DRM_ERROR("%s: Got bad command: 0x%04x\n",
527					  __FUNCTION__, reg);
528				return DRM_ERR(EACCES);
529			}
530
531			from += count;
532		} else {
533			DRM_ERROR
534			    ("%s: Got bad command count(=%u) dwords remaining=%lu\n",
535			     __FUNCTION__, count, n);
536			return DRM_ERR(EINVAL);
537		}
538	}
539
540	if (n == 0)
541		return 0;
542	else {
543		DRM_ERROR("%s: Bad buf->used(=%lu)\n", __FUNCTION__, bytes);
544		return DRM_ERR(EINVAL);
545	}
546}
547
548static int mach64_dma_dispatch_vertex(DRMFILE filp, drm_device_t * dev,
549				      int prim, void *buf, unsigned long used,
550				      int discard)
551{
552	drm_mach64_private_t *dev_priv = dev->dev_private;
553	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
554	drm_buf_t *copy_buf;
555	int done = 0;
556	int verify_ret = 0;
557	DMALOCALS;
558
559	DRM_DEBUG("%s: buf=%p used=%lu nbox=%d\n",
560		  __FUNCTION__, buf, used, sarea_priv->nbox);
561
562	if (used) {
563		int ret = 0;
564		int i = 0;
565
566		copy_buf = mach64_freelist_get(dev_priv);
567		if (copy_buf == NULL) {
568			DRM_ERROR("%s: couldn't get buffer in DMAGETPTR\n",
569				  __FUNCTION__);
570			return DRM_ERR(EAGAIN);
571		}
572
573		if ((verify_ret =
574		     copy_and_verify_from_user(GETBUFPTR(copy_buf), buf,
575					       used)) == 0) {
576
577			copy_buf->used = used;
578
579			DMASETPTR(copy_buf);
580
581			if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) {
582				ret = mach64_emit_state(filp, dev_priv);
583				if (ret < 0)
584					return ret;
585			}
586
587			do {
588				/* Emit the next cliprect */
589				if (i < sarea_priv->nbox) {
590					ret =
591					    mach64_emit_cliprect(filp, dev_priv,
592								 &sarea_priv->
593								 boxes[i]);
594					if (ret < 0) {
595						/* failed to get buffer */
596						return ret;
597					} else if (ret != 0) {
598						/* null intersection with scissor */
599						continue;
600					}
601				}
602				if ((i >= sarea_priv->nbox - 1))
603					done = 1;
604
605				/* Add the buffer to the DMA queue */
606				DMAADVANCE(dev_priv, done);
607
608			} while (++i < sarea_priv->nbox);
609		}
610
611		if (copy_buf->pending && !done) {
612			DMADISCARDBUF();
613		} else if (!done) {
614			/* This buffer wasn't used (no cliprects or verify failed), so place it back
615			 * on the free list
616			 */
617			struct list_head *ptr;
618			drm_mach64_freelist_t *entry;
619#if MACH64_EXTRA_CHECKING
620			list_for_each(ptr, &dev_priv->pending) {
621				entry =
622				    list_entry(ptr, drm_mach64_freelist_t,
623					       list);
624				if (copy_buf == entry->buf) {
625					DRM_ERROR
626					    ("%s: Trying to release a pending buf\n",
627					     __FUNCTION__);
628					return DRM_ERR(EFAULT);
629				}
630			}
631#endif
632			ptr = dev_priv->placeholders.next;
633			entry = list_entry(ptr, drm_mach64_freelist_t, list);
634			copy_buf->pending = 0;
635			copy_buf->used = 0;
636			entry->buf = copy_buf;
637			entry->discard = 1;
638			list_del(ptr);
639			list_add_tail(ptr, &dev_priv->free_list);
640		}
641	}
642
643	sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS;
644	sarea_priv->nbox = 0;
645
646	return verify_ret;
647}
648
649static int mach64_dma_dispatch_blit(DRMFILE filp, drm_device_t * dev,
650				    drm_mach64_blit_t * blit)
651{
652	drm_mach64_private_t *dev_priv = dev->dev_private;
653	drm_device_dma_t *dma = dev->dma;
654	int dword_shift, dwords;
655	drm_buf_t *buf;
656	DMALOCALS;
657
658	/* The compiler won't optimize away a division by a variable,
659	 * even if the only legal values are powers of two.  Thus, we'll
660	 * use a shift instead.
661	 */
662	switch (blit->format) {
663	case MACH64_DATATYPE_ARGB8888:
664		dword_shift = 0;
665		break;
666	case MACH64_DATATYPE_ARGB1555:
667	case MACH64_DATATYPE_RGB565:
668	case MACH64_DATATYPE_VYUY422:
669	case MACH64_DATATYPE_YVYU422:
670	case MACH64_DATATYPE_ARGB4444:
671		dword_shift = 1;
672		break;
673	case MACH64_DATATYPE_CI8:
674	case MACH64_DATATYPE_RGB8:
675		dword_shift = 2;
676		break;
677	default:
678		DRM_ERROR("invalid blit format %d\n", blit->format);
679		return DRM_ERR(EINVAL);
680	}
681
682	/* Dispatch the blit buffer.
683	 */
684	buf = dma->buflist[blit->idx];
685
686	if (buf->filp != filp) {
687		DRM_ERROR("process %d (filp %p) using buffer with filp %p\n",
688			  DRM_CURRENTPID, filp, buf->filp);
689		return DRM_ERR(EINVAL);
690	}
691
692	if (buf->pending) {
693		DRM_ERROR("sending pending buffer %d\n", blit->idx);
694		return DRM_ERR(EINVAL);
695	}
696
697	/* Set buf->used to the bytes of blit data based on the blit dimensions
698	 * and verify the size.  When the setup is emitted to the buffer with
699	 * the DMA* macros below, buf->used is incremented to include the bytes
700	 * used for setup as well as the blit data.
701	 */
702	dwords = (blit->width * blit->height) >> dword_shift;
703	buf->used = dwords << 2;
704	if (buf->used <= 0 ||
705	    buf->used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) {
706		DRM_ERROR("Invalid blit size: %d bytes\n", buf->used);
707		return DRM_ERR(EINVAL);
708	}
709
710	/* FIXME: Use a last buffer flag and reduce the state emitted for subsequent,
711	 * continuation buffers?
712	 */
713
714	/* Blit via BM_HOSTDATA (gui-master) - like HOST_DATA[0-15], but doesn't require
715	 * a register command every 16 dwords.  State setup is added at the start of the
716	 * buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET
717	 */
718	DMASETPTR(buf);
719
720	DMAOUTREG(MACH64_Z_CNTL, 0);
721	DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
722
723	DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16));	/* no scissor */
724	DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
725
726	DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);	/* disable */
727	DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
728		  MACH64_DST_X_LEFT_TO_RIGHT | MACH64_DST_Y_TOP_TO_BOTTOM);
729
730	DMAOUTREG(MACH64_DP_PIX_WIDTH, (blit->format << 0)	/* dst pix width */
731		  |(blit->format << 4)	/* composite pix width */
732		  |(blit->format << 8)	/* src pix width */
733		  |(blit->format << 16)	/* host data pix width */
734		  |(blit->format << 28)	/* scaler/3D pix width */
735	    );
736
737	DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);	/* enable all planes */
738	DMAOUTREG(MACH64_DP_MIX, MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S);
739	DMAOUTREG(MACH64_DP_SRC,
740		  MACH64_BKGD_SRC_BKGD_CLR
741		  | MACH64_FRGD_SRC_HOST | MACH64_MONO_SRC_ONE);
742
743	DMAOUTREG(MACH64_DST_OFF_PITCH,
744		  (blit->pitch << 22) | (blit->offset >> 3));
745	DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x);
746	DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width);
747
748	DRM_DEBUG("%s: %d bytes\n", __FUNCTION__, buf->used);
749
750	/* Add the buffer to the queue */
751	DMAADVANCEHOSTDATA(dev_priv);
752
753	return 0;
754}
755
756/* ================================================================
757 * IOCTL functions
758 */
759
760int mach64_dma_clear(DRM_IOCTL_ARGS)
761{
762	DRM_DEVICE;
763	drm_mach64_private_t *dev_priv = dev->dev_private;
764	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
765	drm_mach64_clear_t clear;
766	int ret;
767
768	DRM_DEBUG("%s: pid=%d\n", __FUNCTION__, DRM_CURRENTPID);
769
770	LOCK_TEST_WITH_RETURN(dev, filp);
771
772	DRM_COPY_FROM_USER_IOCTL(clear, (drm_mach64_clear_t *) data,
773				 sizeof(clear));
774
775	if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
776		sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
777
778	ret = mach64_dma_dispatch_clear(filp, dev, clear.flags,
779					clear.x, clear.y, clear.w, clear.h,
780					clear.clear_color, clear.clear_depth);
781
782	/* Make sure we restore the 3D state next time.
783	 */
784	sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
785	return ret;
786}
787
788int mach64_dma_swap(DRM_IOCTL_ARGS)
789{
790	DRM_DEVICE;
791	drm_mach64_private_t *dev_priv = dev->dev_private;
792	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
793	int ret;
794
795	DRM_DEBUG("%s: pid=%d\n", __FUNCTION__, DRM_CURRENTPID);
796
797	LOCK_TEST_WITH_RETURN(dev, filp);
798
799	if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
800		sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
801
802	ret = mach64_dma_dispatch_swap(filp, dev);
803
804	/* Make sure we restore the 3D state next time.
805	 */
806	sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
807	return ret;
808}
809
810int mach64_dma_vertex(DRM_IOCTL_ARGS)
811{
812	DRM_DEVICE;
813	drm_mach64_private_t *dev_priv = dev->dev_private;
814	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
815	drm_mach64_vertex_t vertex;
816
817	LOCK_TEST_WITH_RETURN(dev, filp);
818
819	if (!dev_priv) {
820		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
821		return DRM_ERR(EINVAL);
822	}
823
824	DRM_COPY_FROM_USER_IOCTL(vertex, (drm_mach64_vertex_t *) data,
825				 sizeof(vertex));
826
827	DRM_DEBUG("%s: pid=%d buf=%p used=%lu discard=%d\n",
828		  __FUNCTION__, DRM_CURRENTPID,
829		  vertex.buf, vertex.used, vertex.discard);
830
831	if (vertex.prim < 0 || vertex.prim > MACH64_PRIM_POLYGON) {
832		DRM_ERROR("buffer prim %d\n", vertex.prim);
833		return DRM_ERR(EINVAL);
834	}
835
836	if (vertex.used > MACH64_BUFFER_SIZE || (vertex.used & 3) != 0) {
837		DRM_ERROR("Invalid vertex buffer size: %lu bytes\n",
838			  vertex.used);
839		return DRM_ERR(EINVAL);
840	}
841
842	if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
843		sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
844
845	return mach64_dma_dispatch_vertex(filp, dev, vertex.prim, vertex.buf,
846					  vertex.used, vertex.discard);
847}
848
849int mach64_dma_blit(DRM_IOCTL_ARGS)
850{
851	DRM_DEVICE;
852	drm_device_dma_t *dma = dev->dma;
853	drm_mach64_private_t *dev_priv = dev->dev_private;
854	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
855	drm_mach64_blit_t blit;
856	int ret;
857
858	LOCK_TEST_WITH_RETURN(dev, filp);
859
860	DRM_COPY_FROM_USER_IOCTL(blit, (drm_mach64_blit_t *) data,
861				 sizeof(blit));
862
863	DRM_DEBUG("%s: pid=%d index=%d\n",
864		  __FUNCTION__, DRM_CURRENTPID, blit.idx);
865
866	if (blit.idx < 0 || blit.idx >= dma->buf_count) {
867		DRM_ERROR("buffer index %d (of %d max)\n",
868			  blit.idx, dma->buf_count - 1);
869		return DRM_ERR(EINVAL);
870	}
871
872	ret = mach64_dma_dispatch_blit(filp, dev, &blit);
873
874	/* Make sure we restore the 3D state next time.
875	 */
876	sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT |
877			      MACH64_UPLOAD_MISC | MACH64_UPLOAD_CLIPRECTS);
878
879	return ret;
880}
881
882int mach64_get_param(DRM_IOCTL_ARGS)
883{
884	DRM_DEVICE;
885	drm_mach64_private_t *dev_priv = dev->dev_private;
886	drm_mach64_getparam_t param;
887	int value;
888
889	DRM_DEBUG("%s\n", __FUNCTION__);
890
891	if (!dev_priv) {
892		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
893		return DRM_ERR(EINVAL);
894	}
895
896	DRM_COPY_FROM_USER_IOCTL(param, (drm_mach64_getparam_t *) data,
897				 sizeof(param));
898
899	switch (param.param) {
900	case MACH64_PARAM_FRAMES_QUEUED:
901		/* Needs lock since it calls mach64_ring_tick() */
902		LOCK_TEST_WITH_RETURN(dev, filp);
903		value = mach64_do_get_frames_queued(dev_priv);
904		break;
905	case MACH64_PARAM_IRQ_NR:
906		value = dev->irq;
907		break;
908	default:
909		return DRM_ERR(EINVAL);
910	}
911
912	if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
913		DRM_ERROR("copy_to_user\n");
914		return DRM_ERR(EFAULT);
915	}
916
917	return 0;
918}
919