mach64_state.c revision 145132
1145132Sanholt/* mach64_state.c -- State support for mach64 (Rage Pro) driver -*- linux-c -*-
2145132Sanholt * Created: Sun Dec 03 19:20:26 2000 by gareth@valinux.com
3145132Sanholt *
4145132Sanholt * Copyright 2000 Gareth Hughes
5145132Sanholt * Copyright 2002-2003 Leif Delgass
6145132Sanholt * All Rights Reserved.
7145132Sanholt *
8145132Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
9145132Sanholt * copy of this software and associated documentation files (the "Software"),
10145132Sanholt * to deal in the Software without restriction, including without limitation
11145132Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12145132Sanholt * and/or sell copies of the Software, and to permit persons to whom the
13145132Sanholt * Software is furnished to do so, subject to the following conditions:
14145132Sanholt *
15145132Sanholt * The above copyright notice and this permission notice (including the next
16145132Sanholt * paragraph) shall be included in all copies or substantial portions of the
17145132Sanholt * Software.
18145132Sanholt *
19145132Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20145132Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21145132Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22145132Sanholt * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23145132Sanholt * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24145132Sanholt * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25145132Sanholt *
26145132Sanholt * Authors:
27145132Sanholt *    Gareth Hughes <gareth@valinux.com>
28145132Sanholt *    Leif Delgass <ldelgass@retinalburn.net>
29145132Sanholt *    Jos���Fonseca <j_r_fonseca@yahoo.co.uk>
30145132Sanholt *
31145132Sanholt * $FreeBSD: head/sys/dev/drm/mach64_state.c 145132 2005-04-16 03:44:47Z anholt $
32145132Sanholt */
33145132Sanholt
34145132Sanholt#include "dev/drm/drmP.h"
35145132Sanholt#include "dev/drm/drm.h"
36145132Sanholt#include "dev/drm/mach64_drm.h"
37145132Sanholt#include "dev/drm/mach64_drv.h"
38145132Sanholt
39145132Sanholt/* Interface history:
40145132Sanholt *
41145132Sanholt * 1.0 - Initial mach64 DRM
42145132Sanholt *
43145132Sanholt */
44145132Sanholtdrm_ioctl_desc_t mach64_ioctls[] = {
45145132Sanholt	[DRM_IOCTL_NR(DRM_MACH64_INIT)] = {mach64_dma_init, 1, 1},
46145132Sanholt	[DRM_IOCTL_NR(DRM_MACH64_CLEAR)] = {mach64_dma_clear, 1, 0},
47145132Sanholt	[DRM_IOCTL_NR(DRM_MACH64_SWAP)] = {mach64_dma_swap, 1, 0},
48145132Sanholt	[DRM_IOCTL_NR(DRM_MACH64_IDLE)] = {mach64_dma_idle, 1, 0},
49145132Sanholt	[DRM_IOCTL_NR(DRM_MACH64_RESET)] = {mach64_engine_reset, 1, 0},
50145132Sanholt	[DRM_IOCTL_NR(DRM_MACH64_VERTEX)] = {mach64_dma_vertex, 1, 0},
51145132Sanholt	[DRM_IOCTL_NR(DRM_MACH64_BLIT)] = {mach64_dma_blit, 1, 0},
52145132Sanholt	[DRM_IOCTL_NR(DRM_MACH64_FLUSH)] = {mach64_dma_flush, 1, 0},
53145132Sanholt	[DRM_IOCTL_NR(DRM_MACH64_GETPARAM)] = {mach64_get_param, 1, 0},
54145132Sanholt};
55145132Sanholt
56145132Sanholtint mach64_max_ioctl = DRM_ARRAY_SIZE(mach64_ioctls);
57145132Sanholt
58145132Sanholt/* ================================================================
59145132Sanholt * DMA hardware state programming functions
60145132Sanholt */
61145132Sanholt
62145132Sanholtstatic void mach64_print_dirty(const char *msg, unsigned int flags)
63145132Sanholt{
64145132Sanholt	DRM_DEBUG("%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s\n",
65145132Sanholt		  msg,
66145132Sanholt		  flags,
67145132Sanholt		  (flags & MACH64_UPLOAD_DST_OFF_PITCH) ? "dst_off_pitch, " :
68145132Sanholt		  "",
69145132Sanholt		  (flags & MACH64_UPLOAD_Z_ALPHA_CNTL) ? "z_alpha_cntl, " : "",
70145132Sanholt		  (flags & MACH64_UPLOAD_SCALE_3D_CNTL) ? "scale_3d_cntl, " :
71145132Sanholt		  "", (flags & MACH64_UPLOAD_DP_FOG_CLR) ? "dp_fog_clr, " : "",
72145132Sanholt		  (flags & MACH64_UPLOAD_DP_WRITE_MASK) ? "dp_write_mask, " :
73145132Sanholt		  "",
74145132Sanholt		  (flags & MACH64_UPLOAD_DP_PIX_WIDTH) ? "dp_pix_width, " : "",
75145132Sanholt		  (flags & MACH64_UPLOAD_SETUP_CNTL) ? "setup_cntl, " : "",
76145132Sanholt		  (flags & MACH64_UPLOAD_MISC) ? "misc, " : "",
77145132Sanholt		  (flags & MACH64_UPLOAD_TEXTURE) ? "texture, " : "",
78145132Sanholt		  (flags & MACH64_UPLOAD_TEX0IMAGE) ? "tex0 image, " : "",
79145132Sanholt		  (flags & MACH64_UPLOAD_TEX1IMAGE) ? "tex1 image, " : "",
80145132Sanholt		  (flags & MACH64_UPLOAD_CLIPRECTS) ? "cliprects, " : "");
81145132Sanholt}
82145132Sanholt
83145132Sanholt/* Mach64 doesn't have hardware cliprects, just one hardware scissor,
84145132Sanholt * so the GL scissor is intersected with each cliprect here
85145132Sanholt */
86145132Sanholt/* This function returns 0 on success, 1 for no intersection, and
87145132Sanholt * negative for an error
88145132Sanholt */
89145132Sanholtstatic int mach64_emit_cliprect(DRMFILE filp, drm_mach64_private_t * dev_priv,
90145132Sanholt				drm_clip_rect_t * box)
91145132Sanholt{
92145132Sanholt	u32 sc_left_right, sc_top_bottom;
93145132Sanholt	drm_clip_rect_t scissor;
94145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
95145132Sanholt	drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
96145132Sanholt	DMALOCALS;
97145132Sanholt
98145132Sanholt	DRM_DEBUG("%s: box=%p\n", __FUNCTION__, box);
99145132Sanholt
100145132Sanholt	/* Get GL scissor */
101145132Sanholt	/* FIXME: store scissor in SAREA as a cliprect instead of in
102145132Sanholt	 * hardware format, or do intersection client-side
103145132Sanholt	 */
104145132Sanholt	scissor.x1 = regs->sc_left_right & 0xffff;
105145132Sanholt	scissor.x2 = (regs->sc_left_right & 0xffff0000) >> 16;
106145132Sanholt	scissor.y1 = regs->sc_top_bottom & 0xffff;
107145132Sanholt	scissor.y2 = (regs->sc_top_bottom & 0xffff0000) >> 16;
108145132Sanholt
109145132Sanholt	/* Intersect GL scissor with cliprect */
110145132Sanholt	if (box->x1 > scissor.x1)
111145132Sanholt		scissor.x1 = box->x1;
112145132Sanholt	if (box->y1 > scissor.y1)
113145132Sanholt		scissor.y1 = box->y1;
114145132Sanholt	if (box->x2 < scissor.x2)
115145132Sanholt		scissor.x2 = box->x2;
116145132Sanholt	if (box->y2 < scissor.y2)
117145132Sanholt		scissor.y2 = box->y2;
118145132Sanholt	/* positive return means skip */
119145132Sanholt	if (scissor.x1 >= scissor.x2)
120145132Sanholt		return 1;
121145132Sanholt	if (scissor.y1 >= scissor.y2)
122145132Sanholt		return 1;
123145132Sanholt
124145132Sanholt	DMAGETPTR(filp, dev_priv, 2);	/* returns on failure to get buffer */
125145132Sanholt
126145132Sanholt	sc_left_right = ((scissor.x1 << 0) | (scissor.x2 << 16));
127145132Sanholt	sc_top_bottom = ((scissor.y1 << 0) | (scissor.y2 << 16));
128145132Sanholt
129145132Sanholt	DMAOUTREG(MACH64_SC_LEFT_RIGHT, sc_left_right);
130145132Sanholt	DMAOUTREG(MACH64_SC_TOP_BOTTOM, sc_top_bottom);
131145132Sanholt
132145132Sanholt	DMAADVANCE(dev_priv, 1);
133145132Sanholt
134145132Sanholt	return 0;
135145132Sanholt}
136145132Sanholt
137145132Sanholtstatic __inline__ int mach64_emit_state(DRMFILE filp,
138145132Sanholt					drm_mach64_private_t * dev_priv)
139145132Sanholt{
140145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
141145132Sanholt	drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
142145132Sanholt	unsigned int dirty = sarea_priv->dirty;
143145132Sanholt	u32 offset = ((regs->tex_size_pitch & 0xf0) >> 2);
144145132Sanholt	DMALOCALS;
145145132Sanholt
146145132Sanholt	if (MACH64_VERBOSE) {
147145132Sanholt		mach64_print_dirty(__FUNCTION__, dirty);
148145132Sanholt	} else {
149145132Sanholt		DRM_DEBUG("%s: dirty=0x%08x\n", __FUNCTION__, dirty);
150145132Sanholt	}
151145132Sanholt
152145132Sanholt	DMAGETPTR(filp, dev_priv, 17);	/* returns on failure to get buffer */
153145132Sanholt
154145132Sanholt	if (dirty & MACH64_UPLOAD_MISC) {
155145132Sanholt		DMAOUTREG(MACH64_DP_MIX, regs->dp_mix);
156145132Sanholt		DMAOUTREG(MACH64_DP_SRC, regs->dp_src);
157145132Sanholt		DMAOUTREG(MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl);
158145132Sanholt		DMAOUTREG(MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl);
159145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_MISC;
160145132Sanholt	}
161145132Sanholt
162145132Sanholt	if (dirty & MACH64_UPLOAD_DST_OFF_PITCH) {
163145132Sanholt		DMAOUTREG(MACH64_DST_OFF_PITCH, regs->dst_off_pitch);
164145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH;
165145132Sanholt	}
166145132Sanholt	if (dirty & MACH64_UPLOAD_Z_OFF_PITCH) {
167145132Sanholt		DMAOUTREG(MACH64_Z_OFF_PITCH, regs->z_off_pitch);
168145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH;
169145132Sanholt	}
170145132Sanholt	if (dirty & MACH64_UPLOAD_Z_ALPHA_CNTL) {
171145132Sanholt		DMAOUTREG(MACH64_Z_CNTL, regs->z_cntl);
172145132Sanholt		DMAOUTREG(MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl);
173145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL;
174145132Sanholt	}
175145132Sanholt	if (dirty & MACH64_UPLOAD_SCALE_3D_CNTL) {
176145132Sanholt		DMAOUTREG(MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl);
177145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL;
178145132Sanholt	}
179145132Sanholt	if (dirty & MACH64_UPLOAD_DP_FOG_CLR) {
180145132Sanholt		DMAOUTREG(MACH64_DP_FOG_CLR, regs->dp_fog_clr);
181145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR;
182145132Sanholt	}
183145132Sanholt	if (dirty & MACH64_UPLOAD_DP_WRITE_MASK) {
184145132Sanholt		DMAOUTREG(MACH64_DP_WRITE_MASK, regs->dp_write_mask);
185145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK;
186145132Sanholt	}
187145132Sanholt	if (dirty & MACH64_UPLOAD_DP_PIX_WIDTH) {
188145132Sanholt		DMAOUTREG(MACH64_DP_PIX_WIDTH, regs->dp_pix_width);
189145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH;
190145132Sanholt	}
191145132Sanholt	if (dirty & MACH64_UPLOAD_SETUP_CNTL) {
192145132Sanholt		DMAOUTREG(MACH64_SETUP_CNTL, regs->setup_cntl);
193145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_SETUP_CNTL;
194145132Sanholt	}
195145132Sanholt
196145132Sanholt	if (dirty & MACH64_UPLOAD_TEXTURE) {
197145132Sanholt		DMAOUTREG(MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch);
198145132Sanholt		DMAOUTREG(MACH64_TEX_CNTL, regs->tex_cntl);
199145132Sanholt		DMAOUTREG(MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off);
200145132Sanholt		DMAOUTREG(MACH64_TEX_0_OFF + offset, regs->tex_offset);
201145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_TEXTURE;
202145132Sanholt	}
203145132Sanholt
204145132Sanholt	DMAADVANCE(dev_priv, 1);
205145132Sanholt
206145132Sanholt	sarea_priv->dirty &= MACH64_UPLOAD_CLIPRECTS;
207145132Sanholt
208145132Sanholt	return 0;
209145132Sanholt
210145132Sanholt}
211145132Sanholt
212145132Sanholt/* ================================================================
213145132Sanholt * DMA command dispatch functions
214145132Sanholt */
215145132Sanholt
216145132Sanholtstatic int mach64_dma_dispatch_clear(DRMFILE filp, drm_device_t * dev,
217145132Sanholt				     unsigned int flags,
218145132Sanholt				     int cx, int cy, int cw, int ch,
219145132Sanholt				     unsigned int clear_color,
220145132Sanholt				     unsigned int clear_depth)
221145132Sanholt{
222145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
223145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
224145132Sanholt	drm_mach64_context_regs_t *ctx = &sarea_priv->context_state;
225145132Sanholt	int nbox = sarea_priv->nbox;
226145132Sanholt	drm_clip_rect_t *pbox = sarea_priv->boxes;
227145132Sanholt	u32 fb_bpp, depth_bpp;
228145132Sanholt	int i;
229145132Sanholt	DMALOCALS;
230145132Sanholt
231145132Sanholt	DRM_DEBUG("%s\n", __FUNCTION__);
232145132Sanholt
233145132Sanholt	switch (dev_priv->fb_bpp) {
234145132Sanholt	case 16:
235145132Sanholt		fb_bpp = MACH64_DATATYPE_RGB565;
236145132Sanholt		break;
237145132Sanholt	case 32:
238145132Sanholt		fb_bpp = MACH64_DATATYPE_ARGB8888;
239145132Sanholt		break;
240145132Sanholt	default:
241145132Sanholt		return DRM_ERR(EINVAL);
242145132Sanholt	}
243145132Sanholt	switch (dev_priv->depth_bpp) {
244145132Sanholt	case 16:
245145132Sanholt		depth_bpp = MACH64_DATATYPE_RGB565;
246145132Sanholt		break;
247145132Sanholt	case 24:
248145132Sanholt	case 32:
249145132Sanholt		depth_bpp = MACH64_DATATYPE_ARGB8888;
250145132Sanholt		break;
251145132Sanholt	default:
252145132Sanholt		return DRM_ERR(EINVAL);
253145132Sanholt	}
254145132Sanholt
255145132Sanholt	if (!nbox)
256145132Sanholt		return 0;
257145132Sanholt
258145132Sanholt	DMAGETPTR(filp, dev_priv, nbox * 31);	/* returns on failure to get buffer */
259145132Sanholt
260145132Sanholt	for (i = 0; i < nbox; i++) {
261145132Sanholt		int x = pbox[i].x1;
262145132Sanholt		int y = pbox[i].y1;
263145132Sanholt		int w = pbox[i].x2 - x;
264145132Sanholt		int h = pbox[i].y2 - y;
265145132Sanholt
266145132Sanholt		DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
267145132Sanholt			  pbox[i].x1, pbox[i].y1,
268145132Sanholt			  pbox[i].x2, pbox[i].y2, flags);
269145132Sanholt
270145132Sanholt		if (flags & (MACH64_FRONT | MACH64_BACK)) {
271145132Sanholt			/* Setup for color buffer clears
272145132Sanholt			 */
273145132Sanholt
274145132Sanholt			DMAOUTREG(MACH64_Z_CNTL, 0);
275145132Sanholt			DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
276145132Sanholt
277145132Sanholt			DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
278145132Sanholt			DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
279145132Sanholt
280145132Sanholt			DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
281145132Sanholt			DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
282145132Sanholt				  (MACH64_DST_X_LEFT_TO_RIGHT |
283145132Sanholt				   MACH64_DST_Y_TOP_TO_BOTTOM));
284145132Sanholt
285145132Sanholt			DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
286145132Sanholt							(fb_bpp << 4) |
287145132Sanholt							(fb_bpp << 8) |
288145132Sanholt							(fb_bpp << 16) |
289145132Sanholt							(fb_bpp << 28)));
290145132Sanholt
291145132Sanholt			DMAOUTREG(MACH64_DP_FRGD_CLR, clear_color);
292145132Sanholt			DMAOUTREG(MACH64_DP_WRITE_MASK, ctx->dp_write_mask);
293145132Sanholt			DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
294145132Sanholt						  MACH64_FRGD_MIX_S));
295145132Sanholt			DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
296145132Sanholt						  MACH64_FRGD_SRC_FRGD_CLR |
297145132Sanholt						  MACH64_MONO_SRC_ONE));
298145132Sanholt
299145132Sanholt		}
300145132Sanholt
301145132Sanholt		if (flags & MACH64_FRONT) {
302145132Sanholt
303145132Sanholt			DMAOUTREG(MACH64_DST_OFF_PITCH,
304145132Sanholt				  dev_priv->front_offset_pitch);
305145132Sanholt			DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
306145132Sanholt			DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
307145132Sanholt
308145132Sanholt		}
309145132Sanholt
310145132Sanholt		if (flags & MACH64_BACK) {
311145132Sanholt
312145132Sanholt			DMAOUTREG(MACH64_DST_OFF_PITCH,
313145132Sanholt				  dev_priv->back_offset_pitch);
314145132Sanholt			DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
315145132Sanholt			DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
316145132Sanholt
317145132Sanholt		}
318145132Sanholt
319145132Sanholt		if (flags & MACH64_DEPTH) {
320145132Sanholt			/* Setup for depth buffer clear
321145132Sanholt			 */
322145132Sanholt			DMAOUTREG(MACH64_Z_CNTL, 0);
323145132Sanholt			DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
324145132Sanholt
325145132Sanholt			DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
326145132Sanholt			DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
327145132Sanholt
328145132Sanholt			DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
329145132Sanholt			DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
330145132Sanholt				  (MACH64_DST_X_LEFT_TO_RIGHT |
331145132Sanholt				   MACH64_DST_Y_TOP_TO_BOTTOM));
332145132Sanholt
333145132Sanholt			DMAOUTREG(MACH64_DP_PIX_WIDTH, ((depth_bpp << 0) |
334145132Sanholt							(depth_bpp << 4) |
335145132Sanholt							(depth_bpp << 8) |
336145132Sanholt							(depth_bpp << 16) |
337145132Sanholt							(depth_bpp << 28)));
338145132Sanholt
339145132Sanholt			DMAOUTREG(MACH64_DP_FRGD_CLR, clear_depth);
340145132Sanholt			DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
341145132Sanholt			DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
342145132Sanholt						  MACH64_FRGD_MIX_S));
343145132Sanholt			DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
344145132Sanholt						  MACH64_FRGD_SRC_FRGD_CLR |
345145132Sanholt						  MACH64_MONO_SRC_ONE));
346145132Sanholt
347145132Sanholt			DMAOUTREG(MACH64_DST_OFF_PITCH,
348145132Sanholt				  dev_priv->depth_offset_pitch);
349145132Sanholt			DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
350145132Sanholt			DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
351145132Sanholt		}
352145132Sanholt	}
353145132Sanholt
354145132Sanholt	DMAADVANCE(dev_priv, 1);
355145132Sanholt
356145132Sanholt	return 0;
357145132Sanholt}
358145132Sanholt
359145132Sanholtstatic int mach64_dma_dispatch_swap(DRMFILE filp, drm_device_t * dev)
360145132Sanholt{
361145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
362145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
363145132Sanholt	int nbox = sarea_priv->nbox;
364145132Sanholt	drm_clip_rect_t *pbox = sarea_priv->boxes;
365145132Sanholt	u32 fb_bpp;
366145132Sanholt	int i;
367145132Sanholt	DMALOCALS;
368145132Sanholt
369145132Sanholt	DRM_DEBUG("%s\n", __FUNCTION__);
370145132Sanholt
371145132Sanholt	switch (dev_priv->fb_bpp) {
372145132Sanholt	case 16:
373145132Sanholt		fb_bpp = MACH64_DATATYPE_RGB565;
374145132Sanholt		break;
375145132Sanholt	case 32:
376145132Sanholt	default:
377145132Sanholt		fb_bpp = MACH64_DATATYPE_ARGB8888;
378145132Sanholt		break;
379145132Sanholt	}
380145132Sanholt
381145132Sanholt	if (!nbox)
382145132Sanholt		return 0;
383145132Sanholt
384145132Sanholt	DMAGETPTR(filp, dev_priv, 13 + nbox * 4);	/* returns on failure to get buffer */
385145132Sanholt
386145132Sanholt	DMAOUTREG(MACH64_Z_CNTL, 0);
387145132Sanholt	DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
388145132Sanholt
389145132Sanholt	DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16));	/* no scissor */
390145132Sanholt	DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
391145132Sanholt
392145132Sanholt	DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
393145132Sanholt	DMAOUTREG(MACH64_GUI_TRAJ_CNTL, (MACH64_DST_X_LEFT_TO_RIGHT |
394145132Sanholt					 MACH64_DST_Y_TOP_TO_BOTTOM));
395145132Sanholt
396145132Sanholt	DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
397145132Sanholt					(fb_bpp << 4) |
398145132Sanholt					(fb_bpp << 8) |
399145132Sanholt					(fb_bpp << 16) | (fb_bpp << 28)));
400145132Sanholt
401145132Sanholt	DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
402145132Sanholt	DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S));
403145132Sanholt	DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_BKGD_CLR |
404145132Sanholt				  MACH64_FRGD_SRC_BLIT | MACH64_MONO_SRC_ONE));
405145132Sanholt
406145132Sanholt	DMAOUTREG(MACH64_SRC_OFF_PITCH, dev_priv->back_offset_pitch);
407145132Sanholt	DMAOUTREG(MACH64_DST_OFF_PITCH, dev_priv->front_offset_pitch);
408145132Sanholt
409145132Sanholt	for (i = 0; i < nbox; i++) {
410145132Sanholt		int x = pbox[i].x1;
411145132Sanholt		int y = pbox[i].y1;
412145132Sanholt		int w = pbox[i].x2 - x;
413145132Sanholt		int h = pbox[i].y2 - y;
414145132Sanholt
415145132Sanholt		DRM_DEBUG("dispatch swap %d,%d-%d,%d\n",
416145132Sanholt			  pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2);
417145132Sanholt
418145132Sanholt		DMAOUTREG(MACH64_SRC_WIDTH1, w);
419145132Sanholt		DMAOUTREG(MACH64_SRC_Y_X, (x << 16) | y);
420145132Sanholt		DMAOUTREG(MACH64_DST_Y_X, (x << 16) | y);
421145132Sanholt		DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
422145132Sanholt
423145132Sanholt	}
424145132Sanholt
425145132Sanholt	DMAADVANCE(dev_priv, 1);
426145132Sanholt
427145132Sanholt	if (dev_priv->driver_mode == MACH64_MODE_DMA_ASYNC) {
428145132Sanholt		for (i = 0; i < MACH64_MAX_QUEUED_FRAMES - 1; i++) {
429145132Sanholt			dev_priv->frame_ofs[i] = dev_priv->frame_ofs[i + 1];
430145132Sanholt		}
431145132Sanholt		dev_priv->frame_ofs[i] = GETRINGOFFSET();
432145132Sanholt
433145132Sanholt		dev_priv->sarea_priv->frames_queued++;
434145132Sanholt	}
435145132Sanholt
436145132Sanholt	return 0;
437145132Sanholt}
438145132Sanholt
439145132Sanholtstatic int mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv)
440145132Sanholt{
441145132Sanholt	drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
442145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
443145132Sanholt	int i, start;
444145132Sanholt	u32 head, tail, ofs;
445145132Sanholt
446145132Sanholt	DRM_DEBUG("%s\n", __FUNCTION__);
447145132Sanholt
448145132Sanholt	if (sarea_priv->frames_queued == 0)
449145132Sanholt		return 0;
450145132Sanholt
451145132Sanholt	tail = ring->tail;
452145132Sanholt	mach64_ring_tick(dev_priv, ring);
453145132Sanholt	head = ring->head;
454145132Sanholt
455145132Sanholt	start = (MACH64_MAX_QUEUED_FRAMES -
456145132Sanholt		 DRM_MIN(MACH64_MAX_QUEUED_FRAMES, sarea_priv->frames_queued));
457145132Sanholt
458145132Sanholt	if (head == tail) {
459145132Sanholt		sarea_priv->frames_queued = 0;
460145132Sanholt		for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
461145132Sanholt			dev_priv->frame_ofs[i] = ~0;
462145132Sanholt		}
463145132Sanholt		return 0;
464145132Sanholt	}
465145132Sanholt
466145132Sanholt	for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
467145132Sanholt		ofs = dev_priv->frame_ofs[i];
468145132Sanholt		DRM_DEBUG("frame_ofs[%d] ofs: %d\n", i, ofs);
469145132Sanholt		if (ofs == ~0 ||
470145132Sanholt		    (head < tail && (ofs < head || ofs >= tail)) ||
471145132Sanholt		    (head > tail && (ofs < head && ofs >= tail))) {
472145132Sanholt			sarea_priv->frames_queued =
473145132Sanholt			    (MACH64_MAX_QUEUED_FRAMES - 1) - i;
474145132Sanholt			dev_priv->frame_ofs[i] = ~0;
475145132Sanholt		}
476145132Sanholt	}
477145132Sanholt
478145132Sanholt	return sarea_priv->frames_queued;
479145132Sanholt}
480145132Sanholt
481145132Sanholt/* Copy and verify a client submited buffer.
482145132Sanholt * FIXME: Make an assembly optimized version
483145132Sanholt */
484145132Sanholtstatic __inline__ int copy_and_verify_from_user(u32 * to, const u32 * from,
485145132Sanholt						unsigned long bytes)
486145132Sanholt{
487145132Sanholt	unsigned long n = bytes;	/* dwords remaining in buffer */
488145132Sanholt
489145132Sanholt	if (DRM_VERIFYAREA_READ(from, n)) {
490145132Sanholt		DRM_ERROR("%s: verify_area\n", __FUNCTION__);
491145132Sanholt		return DRM_ERR(EFAULT);
492145132Sanholt	}
493145132Sanholt
494145132Sanholt	n >>= 2;
495145132Sanholt
496145132Sanholt	while (n > 1) {
497145132Sanholt		u32 data, reg, count;
498145132Sanholt
499145132Sanholt		if (DRM_GET_USER_UNCHECKED(data, from++)) {
500145132Sanholt			DRM_ERROR("%s: get_user\n", __FUNCTION__);
501145132Sanholt			return DRM_ERR(EFAULT);
502145132Sanholt		}
503145132Sanholt
504145132Sanholt		n--;
505145132Sanholt
506145132Sanholt		reg = le32_to_cpu(data);
507145132Sanholt		count = (reg >> 16) + 1;
508145132Sanholt		if (count <= n) {
509145132Sanholt			n -= count;
510145132Sanholt			reg &= 0xffff;
511145132Sanholt
512145132Sanholt			/* This is an exact match of Mach64's Setup Engine registers,
513145132Sanholt			 * excluding SETUP_CNTL (1_C1).
514145132Sanholt			 */
515145132Sanholt			if ((reg >= 0x0190 && reg < 0x01c1) ||
516145132Sanholt			    (reg >= 0x01ca && reg <= 0x01cf)) {
517145132Sanholt				*to++ = data;
518145132Sanholt				if (DRM_COPY_FROM_USER_UNCHECKED
519145132Sanholt				    (to, from, count << 2)) {
520145132Sanholt					DRM_ERROR("%s: copy_from_user\n",
521145132Sanholt						  __FUNCTION__);
522145132Sanholt					return DRM_ERR(EFAULT);
523145132Sanholt				}
524145132Sanholt				to += count;
525145132Sanholt			} else {
526145132Sanholt				DRM_ERROR("%s: Got bad command: 0x%04x\n",
527145132Sanholt					  __FUNCTION__, reg);
528145132Sanholt				return DRM_ERR(EACCES);
529145132Sanholt			}
530145132Sanholt
531145132Sanholt			from += count;
532145132Sanholt		} else {
533145132Sanholt			DRM_ERROR
534145132Sanholt			    ("%s: Got bad command count(=%u) dwords remaining=%lu\n",
535145132Sanholt			     __FUNCTION__, count, n);
536145132Sanholt			return DRM_ERR(EINVAL);
537145132Sanholt		}
538145132Sanholt	}
539145132Sanholt
540145132Sanholt	if (n == 0)
541145132Sanholt		return 0;
542145132Sanholt	else {
543145132Sanholt		DRM_ERROR("%s: Bad buf->used(=%lu)\n", __FUNCTION__, bytes);
544145132Sanholt		return DRM_ERR(EINVAL);
545145132Sanholt	}
546145132Sanholt}
547145132Sanholt
548145132Sanholtstatic int mach64_dma_dispatch_vertex(DRMFILE filp, drm_device_t * dev,
549145132Sanholt				      int prim, void *buf, unsigned long used,
550145132Sanholt				      int discard)
551145132Sanholt{
552145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
553145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
554145132Sanholt	drm_buf_t *copy_buf;
555145132Sanholt	int done = 0;
556145132Sanholt	int verify_ret = 0;
557145132Sanholt	DMALOCALS;
558145132Sanholt
559145132Sanholt	DRM_DEBUG("%s: buf=%p used=%lu nbox=%d\n",
560145132Sanholt		  __FUNCTION__, buf, used, sarea_priv->nbox);
561145132Sanholt
562145132Sanholt	if (used) {
563145132Sanholt		int ret = 0;
564145132Sanholt		int i = 0;
565145132Sanholt
566145132Sanholt		copy_buf = mach64_freelist_get(dev_priv);
567145132Sanholt		if (copy_buf == NULL) {
568145132Sanholt			DRM_ERROR("%s: couldn't get buffer in DMAGETPTR\n",
569145132Sanholt				  __FUNCTION__);
570145132Sanholt			return DRM_ERR(EAGAIN);
571145132Sanholt		}
572145132Sanholt
573145132Sanholt		if ((verify_ret =
574145132Sanholt		     copy_and_verify_from_user(GETBUFPTR(copy_buf), buf,
575145132Sanholt					       used)) == 0) {
576145132Sanholt
577145132Sanholt			copy_buf->used = used;
578145132Sanholt
579145132Sanholt			DMASETPTR(copy_buf);
580145132Sanholt
581145132Sanholt			if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) {
582145132Sanholt				ret = mach64_emit_state(filp, dev_priv);
583145132Sanholt				if (ret < 0)
584145132Sanholt					return ret;
585145132Sanholt			}
586145132Sanholt
587145132Sanholt			do {
588145132Sanholt				/* Emit the next cliprect */
589145132Sanholt				if (i < sarea_priv->nbox) {
590145132Sanholt					ret =
591145132Sanholt					    mach64_emit_cliprect(filp, dev_priv,
592145132Sanholt								 &sarea_priv->
593145132Sanholt								 boxes[i]);
594145132Sanholt					if (ret < 0) {
595145132Sanholt						/* failed to get buffer */
596145132Sanholt						return ret;
597145132Sanholt					} else if (ret != 0) {
598145132Sanholt						/* null intersection with scissor */
599145132Sanholt						continue;
600145132Sanholt					}
601145132Sanholt				}
602145132Sanholt				if ((i >= sarea_priv->nbox - 1))
603145132Sanholt					done = 1;
604145132Sanholt
605145132Sanholt				/* Add the buffer to the DMA queue */
606145132Sanholt				DMAADVANCE(dev_priv, done);
607145132Sanholt
608145132Sanholt			} while (++i < sarea_priv->nbox);
609145132Sanholt		}
610145132Sanholt
611145132Sanholt		if (copy_buf->pending && !done) {
612145132Sanholt			DMADISCARDBUF();
613145132Sanholt		} else if (!done) {
614145132Sanholt			/* This buffer wasn't used (no cliprects or verify failed), so place it back
615145132Sanholt			 * on the free list
616145132Sanholt			 */
617145132Sanholt			struct list_head *ptr;
618145132Sanholt			drm_mach64_freelist_t *entry;
619145132Sanholt#if MACH64_EXTRA_CHECKING
620145132Sanholt			list_for_each(ptr, &dev_priv->pending) {
621145132Sanholt				entry =
622145132Sanholt				    list_entry(ptr, drm_mach64_freelist_t,
623145132Sanholt					       list);
624145132Sanholt				if (copy_buf == entry->buf) {
625145132Sanholt					DRM_ERROR
626145132Sanholt					    ("%s: Trying to release a pending buf\n",
627145132Sanholt					     __FUNCTION__);
628145132Sanholt					return DRM_ERR(EFAULT);
629145132Sanholt				}
630145132Sanholt			}
631145132Sanholt#endif
632145132Sanholt			ptr = dev_priv->placeholders.next;
633145132Sanholt			entry = list_entry(ptr, drm_mach64_freelist_t, list);
634145132Sanholt			copy_buf->pending = 0;
635145132Sanholt			copy_buf->used = 0;
636145132Sanholt			entry->buf = copy_buf;
637145132Sanholt			entry->discard = 1;
638145132Sanholt			list_del(ptr);
639145132Sanholt			list_add_tail(ptr, &dev_priv->free_list);
640145132Sanholt		}
641145132Sanholt	}
642145132Sanholt
643145132Sanholt	sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS;
644145132Sanholt	sarea_priv->nbox = 0;
645145132Sanholt
646145132Sanholt	return verify_ret;
647145132Sanholt}
648145132Sanholt
649145132Sanholtstatic int mach64_dma_dispatch_blit(DRMFILE filp, drm_device_t * dev,
650145132Sanholt				    drm_mach64_blit_t * blit)
651145132Sanholt{
652145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
653145132Sanholt	drm_device_dma_t *dma = dev->dma;
654145132Sanholt	int dword_shift, dwords;
655145132Sanholt	drm_buf_t *buf;
656145132Sanholt	DMALOCALS;
657145132Sanholt
658145132Sanholt	/* The compiler won't optimize away a division by a variable,
659145132Sanholt	 * even if the only legal values are powers of two.  Thus, we'll
660145132Sanholt	 * use a shift instead.
661145132Sanholt	 */
662145132Sanholt	switch (blit->format) {
663145132Sanholt	case MACH64_DATATYPE_ARGB8888:
664145132Sanholt		dword_shift = 0;
665145132Sanholt		break;
666145132Sanholt	case MACH64_DATATYPE_ARGB1555:
667145132Sanholt	case MACH64_DATATYPE_RGB565:
668145132Sanholt	case MACH64_DATATYPE_VYUY422:
669145132Sanholt	case MACH64_DATATYPE_YVYU422:
670145132Sanholt	case MACH64_DATATYPE_ARGB4444:
671145132Sanholt		dword_shift = 1;
672145132Sanholt		break;
673145132Sanholt	case MACH64_DATATYPE_CI8:
674145132Sanholt	case MACH64_DATATYPE_RGB8:
675145132Sanholt		dword_shift = 2;
676145132Sanholt		break;
677145132Sanholt	default:
678145132Sanholt		DRM_ERROR("invalid blit format %d\n", blit->format);
679145132Sanholt		return DRM_ERR(EINVAL);
680145132Sanholt	}
681145132Sanholt
682145132Sanholt	/* Dispatch the blit buffer.
683145132Sanholt	 */
684145132Sanholt	buf = dma->buflist[blit->idx];
685145132Sanholt
686145132Sanholt	if (buf->filp != filp) {
687145132Sanholt		DRM_ERROR("process %d (filp %p) using buffer with filp %p\n",
688145132Sanholt			  DRM_CURRENTPID, filp, buf->filp);
689145132Sanholt		return DRM_ERR(EINVAL);
690145132Sanholt	}
691145132Sanholt
692145132Sanholt	if (buf->pending) {
693145132Sanholt		DRM_ERROR("sending pending buffer %d\n", blit->idx);
694145132Sanholt		return DRM_ERR(EINVAL);
695145132Sanholt	}
696145132Sanholt
697145132Sanholt	/* Set buf->used to the bytes of blit data based on the blit dimensions
698145132Sanholt	 * and verify the size.  When the setup is emitted to the buffer with
699145132Sanholt	 * the DMA* macros below, buf->used is incremented to include the bytes
700145132Sanholt	 * used for setup as well as the blit data.
701145132Sanholt	 */
702145132Sanholt	dwords = (blit->width * blit->height) >> dword_shift;
703145132Sanholt	buf->used = dwords << 2;
704145132Sanholt	if (buf->used <= 0 ||
705145132Sanholt	    buf->used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) {
706145132Sanholt		DRM_ERROR("Invalid blit size: %d bytes\n", buf->used);
707145132Sanholt		return DRM_ERR(EINVAL);
708145132Sanholt	}
709145132Sanholt
710145132Sanholt	/* FIXME: Use a last buffer flag and reduce the state emitted for subsequent,
711145132Sanholt	 * continuation buffers?
712145132Sanholt	 */
713145132Sanholt
714145132Sanholt	/* Blit via BM_HOSTDATA (gui-master) - like HOST_DATA[0-15], but doesn't require
715145132Sanholt	 * a register command every 16 dwords.  State setup is added at the start of the
716145132Sanholt	 * buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET
717145132Sanholt	 */
718145132Sanholt	DMASETPTR(buf);
719145132Sanholt
720145132Sanholt	DMAOUTREG(MACH64_Z_CNTL, 0);
721145132Sanholt	DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
722145132Sanholt
723145132Sanholt	DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16));	/* no scissor */
724145132Sanholt	DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
725145132Sanholt
726145132Sanholt	DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);	/* disable */
727145132Sanholt	DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
728145132Sanholt		  MACH64_DST_X_LEFT_TO_RIGHT | MACH64_DST_Y_TOP_TO_BOTTOM);
729145132Sanholt
730145132Sanholt	DMAOUTREG(MACH64_DP_PIX_WIDTH, (blit->format << 0)	/* dst pix width */
731145132Sanholt		  |(blit->format << 4)	/* composite pix width */
732145132Sanholt		  |(blit->format << 8)	/* src pix width */
733145132Sanholt		  |(blit->format << 16)	/* host data pix width */
734145132Sanholt		  |(blit->format << 28)	/* scaler/3D pix width */
735145132Sanholt	    );
736145132Sanholt
737145132Sanholt	DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);	/* enable all planes */
738145132Sanholt	DMAOUTREG(MACH64_DP_MIX, MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S);
739145132Sanholt	DMAOUTREG(MACH64_DP_SRC,
740145132Sanholt		  MACH64_BKGD_SRC_BKGD_CLR
741145132Sanholt		  | MACH64_FRGD_SRC_HOST | MACH64_MONO_SRC_ONE);
742145132Sanholt
743145132Sanholt	DMAOUTREG(MACH64_DST_OFF_PITCH,
744145132Sanholt		  (blit->pitch << 22) | (blit->offset >> 3));
745145132Sanholt	DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x);
746145132Sanholt	DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width);
747145132Sanholt
748145132Sanholt	DRM_DEBUG("%s: %d bytes\n", __FUNCTION__, buf->used);
749145132Sanholt
750145132Sanholt	/* Add the buffer to the queue */
751145132Sanholt	DMAADVANCEHOSTDATA(dev_priv);
752145132Sanholt
753145132Sanholt	return 0;
754145132Sanholt}
755145132Sanholt
756145132Sanholt/* ================================================================
757145132Sanholt * IOCTL functions
758145132Sanholt */
759145132Sanholt
760145132Sanholtint mach64_dma_clear(DRM_IOCTL_ARGS)
761145132Sanholt{
762145132Sanholt	DRM_DEVICE;
763145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
764145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
765145132Sanholt	drm_mach64_clear_t clear;
766145132Sanholt	int ret;
767145132Sanholt
768145132Sanholt	DRM_DEBUG("%s: pid=%d\n", __FUNCTION__, DRM_CURRENTPID);
769145132Sanholt
770145132Sanholt	LOCK_TEST_WITH_RETURN(dev, filp);
771145132Sanholt
772145132Sanholt	DRM_COPY_FROM_USER_IOCTL(clear, (drm_mach64_clear_t *) data,
773145132Sanholt				 sizeof(clear));
774145132Sanholt
775145132Sanholt	if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
776145132Sanholt		sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
777145132Sanholt
778145132Sanholt	ret = mach64_dma_dispatch_clear(filp, dev, clear.flags,
779145132Sanholt					clear.x, clear.y, clear.w, clear.h,
780145132Sanholt					clear.clear_color, clear.clear_depth);
781145132Sanholt
782145132Sanholt	/* Make sure we restore the 3D state next time.
783145132Sanholt	 */
784145132Sanholt	sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
785145132Sanholt	return ret;
786145132Sanholt}
787145132Sanholt
788145132Sanholtint mach64_dma_swap(DRM_IOCTL_ARGS)
789145132Sanholt{
790145132Sanholt	DRM_DEVICE;
791145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
792145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
793145132Sanholt	int ret;
794145132Sanholt
795145132Sanholt	DRM_DEBUG("%s: pid=%d\n", __FUNCTION__, DRM_CURRENTPID);
796145132Sanholt
797145132Sanholt	LOCK_TEST_WITH_RETURN(dev, filp);
798145132Sanholt
799145132Sanholt	if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
800145132Sanholt		sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
801145132Sanholt
802145132Sanholt	ret = mach64_dma_dispatch_swap(filp, dev);
803145132Sanholt
804145132Sanholt	/* Make sure we restore the 3D state next time.
805145132Sanholt	 */
806145132Sanholt	sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
807145132Sanholt	return ret;
808145132Sanholt}
809145132Sanholt
810145132Sanholtint mach64_dma_vertex(DRM_IOCTL_ARGS)
811145132Sanholt{
812145132Sanholt	DRM_DEVICE;
813145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
814145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
815145132Sanholt	drm_mach64_vertex_t vertex;
816145132Sanholt
817145132Sanholt	LOCK_TEST_WITH_RETURN(dev, filp);
818145132Sanholt
819145132Sanholt	if (!dev_priv) {
820145132Sanholt		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
821145132Sanholt		return DRM_ERR(EINVAL);
822145132Sanholt	}
823145132Sanholt
824145132Sanholt	DRM_COPY_FROM_USER_IOCTL(vertex, (drm_mach64_vertex_t *) data,
825145132Sanholt				 sizeof(vertex));
826145132Sanholt
827145132Sanholt	DRM_DEBUG("%s: pid=%d buf=%p used=%lu discard=%d\n",
828145132Sanholt		  __FUNCTION__, DRM_CURRENTPID,
829145132Sanholt		  vertex.buf, vertex.used, vertex.discard);
830145132Sanholt
831145132Sanholt	if (vertex.prim < 0 || vertex.prim > MACH64_PRIM_POLYGON) {
832145132Sanholt		DRM_ERROR("buffer prim %d\n", vertex.prim);
833145132Sanholt		return DRM_ERR(EINVAL);
834145132Sanholt	}
835145132Sanholt
836145132Sanholt	if (vertex.used > MACH64_BUFFER_SIZE || (vertex.used & 3) != 0) {
837145132Sanholt		DRM_ERROR("Invalid vertex buffer size: %lu bytes\n",
838145132Sanholt			  vertex.used);
839145132Sanholt		return DRM_ERR(EINVAL);
840145132Sanholt	}
841145132Sanholt
842145132Sanholt	if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
843145132Sanholt		sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
844145132Sanholt
845145132Sanholt	return mach64_dma_dispatch_vertex(filp, dev, vertex.prim, vertex.buf,
846145132Sanholt					  vertex.used, vertex.discard);
847145132Sanholt}
848145132Sanholt
849145132Sanholtint mach64_dma_blit(DRM_IOCTL_ARGS)
850145132Sanholt{
851145132Sanholt	DRM_DEVICE;
852145132Sanholt	drm_device_dma_t *dma = dev->dma;
853145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
854145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
855145132Sanholt	drm_mach64_blit_t blit;
856145132Sanholt	int ret;
857145132Sanholt
858145132Sanholt	LOCK_TEST_WITH_RETURN(dev, filp);
859145132Sanholt
860145132Sanholt	DRM_COPY_FROM_USER_IOCTL(blit, (drm_mach64_blit_t *) data,
861145132Sanholt				 sizeof(blit));
862145132Sanholt
863145132Sanholt	DRM_DEBUG("%s: pid=%d index=%d\n",
864145132Sanholt		  __FUNCTION__, DRM_CURRENTPID, blit.idx);
865145132Sanholt
866145132Sanholt	if (blit.idx < 0 || blit.idx >= dma->buf_count) {
867145132Sanholt		DRM_ERROR("buffer index %d (of %d max)\n",
868145132Sanholt			  blit.idx, dma->buf_count - 1);
869145132Sanholt		return DRM_ERR(EINVAL);
870145132Sanholt	}
871145132Sanholt
872145132Sanholt	ret = mach64_dma_dispatch_blit(filp, dev, &blit);
873145132Sanholt
874145132Sanholt	/* Make sure we restore the 3D state next time.
875145132Sanholt	 */
876145132Sanholt	sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT |
877145132Sanholt			      MACH64_UPLOAD_MISC | MACH64_UPLOAD_CLIPRECTS);
878145132Sanholt
879145132Sanholt	return ret;
880145132Sanholt}
881145132Sanholt
882145132Sanholtint mach64_get_param(DRM_IOCTL_ARGS)
883145132Sanholt{
884145132Sanholt	DRM_DEVICE;
885145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
886145132Sanholt	drm_mach64_getparam_t param;
887145132Sanholt	int value;
888145132Sanholt
889145132Sanholt	DRM_DEBUG("%s\n", __FUNCTION__);
890145132Sanholt
891145132Sanholt	if (!dev_priv) {
892145132Sanholt		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
893145132Sanholt		return DRM_ERR(EINVAL);
894145132Sanholt	}
895145132Sanholt
896145132Sanholt	DRM_COPY_FROM_USER_IOCTL(param, (drm_mach64_getparam_t *) data,
897145132Sanholt				 sizeof(param));
898145132Sanholt
899145132Sanholt	switch (param.param) {
900145132Sanholt	case MACH64_PARAM_FRAMES_QUEUED:
901145132Sanholt		/* Needs lock since it calls mach64_ring_tick() */
902145132Sanholt		LOCK_TEST_WITH_RETURN(dev, filp);
903145132Sanholt		value = mach64_do_get_frames_queued(dev_priv);
904145132Sanholt		break;
905145132Sanholt	case MACH64_PARAM_IRQ_NR:
906145132Sanholt		value = dev->irq;
907145132Sanholt		break;
908145132Sanholt	default:
909145132Sanholt		return DRM_ERR(EINVAL);
910145132Sanholt	}
911145132Sanholt
912145132Sanholt	if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
913145132Sanholt		DRM_ERROR("copy_to_user\n");
914145132Sanholt		return DRM_ERR(EFAULT);
915145132Sanholt	}
916145132Sanholt
917145132Sanholt	return 0;
918145132Sanholt}
919