mga_state.c revision 113995
1/* mga_state.c -- State support for MGA G200/G400 -*- linux-c -*-
2 * Created: Thu Jan 27 02:53:43 2000 by jhartmann@precisioninsight.com
3 *
4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * Authors:
28 *    Jeff Hartmann <jhartmann@valinux.com>
29 *    Keith Whitwell <keith@tungstengraphics.com>
30 *
31 * Rewritten by:
32 *    Gareth Hughes <gareth@valinux.com>
33 *
34 * $FreeBSD: head/sys/dev/drm/mga_state.c 113995 2003-04-25 01:18:47Z anholt $
35 */
36
37#include "dev/drm/mga.h"
38#include "dev/drm/drmP.h"
39#include "dev/drm/drm.h"
40#include "dev/drm/mga_drm.h"
41#include "dev/drm/mga_drv.h"
42
43
44/* ================================================================
45 * DMA hardware state programming functions
46 */
47
48static void mga_emit_clip_rect( drm_mga_private_t *dev_priv,
49				drm_clip_rect_t *box )
50{
51	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
52	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
53	unsigned int pitch = dev_priv->front_pitch;
54	DMA_LOCALS;
55
56	BEGIN_DMA( 2 );
57
58	/* Force reset of DWGCTL on G400 (eliminates clip disable bit).
59	 */
60	if ( dev_priv->chipset == MGA_CARD_TYPE_G400 ) {
61		DMA_BLOCK( MGA_DWGCTL,		ctx->dwgctl,
62			   MGA_LEN + MGA_EXEC,	0x80000000,
63			   MGA_DWGCTL,		ctx->dwgctl,
64			   MGA_LEN + MGA_EXEC,	0x80000000 );
65	}
66	DMA_BLOCK( MGA_DMAPAD,	0x00000000,
67		   MGA_CXBNDRY,	(box->x2 << 16) | box->x1,
68		   MGA_YTOP,	box->y1 * pitch,
69		   MGA_YBOT,	box->y2 * pitch );
70
71	ADVANCE_DMA();
72}
73
74static __inline__ void mga_g200_emit_context( drm_mga_private_t *dev_priv )
75{
76	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
77	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
78	DMA_LOCALS;
79
80	BEGIN_DMA( 3 );
81
82	DMA_BLOCK( MGA_DSTORG,		ctx->dstorg,
83		   MGA_MACCESS,		ctx->maccess,
84		   MGA_PLNWT,		ctx->plnwt,
85		   MGA_DWGCTL,		ctx->dwgctl );
86
87	DMA_BLOCK( MGA_ALPHACTRL,	ctx->alphactrl,
88		   MGA_FOGCOL,		ctx->fogcolor,
89		   MGA_WFLAG,		ctx->wflag,
90		   MGA_ZORG,		dev_priv->depth_offset );
91
92	DMA_BLOCK( MGA_FCOL,		ctx->fcol,
93		   MGA_DMAPAD,		0x00000000,
94		   MGA_DMAPAD,		0x00000000,
95		   MGA_DMAPAD,		0x00000000 );
96
97	ADVANCE_DMA();
98}
99
100static __inline__ void mga_g400_emit_context( drm_mga_private_t *dev_priv )
101{
102	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
103	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
104	DMA_LOCALS;
105
106	BEGIN_DMA( 4 );
107
108	DMA_BLOCK( MGA_DSTORG,		ctx->dstorg,
109		   MGA_MACCESS,		ctx->maccess,
110		   MGA_PLNWT,		ctx->plnwt,
111		   MGA_DWGCTL,		ctx->dwgctl );
112
113	DMA_BLOCK( MGA_ALPHACTRL,	ctx->alphactrl,
114		   MGA_FOGCOL,		ctx->fogcolor,
115		   MGA_WFLAG,		ctx->wflag,
116		   MGA_ZORG,		dev_priv->depth_offset );
117
118	DMA_BLOCK( MGA_WFLAG1,		ctx->wflag,
119		   MGA_TDUALSTAGE0,	ctx->tdualstage0,
120		   MGA_TDUALSTAGE1,	ctx->tdualstage1,
121		   MGA_FCOL,		ctx->fcol );
122
123	DMA_BLOCK( MGA_STENCIL,		ctx->stencil,
124		   MGA_STENCILCTL,	ctx->stencilctl,
125		   MGA_DMAPAD,		0x00000000,
126		   MGA_DMAPAD,		0x00000000 );
127
128	ADVANCE_DMA();
129}
130
131static __inline__ void mga_g200_emit_tex0( drm_mga_private_t *dev_priv )
132{
133	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
134	drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
135	DMA_LOCALS;
136
137	BEGIN_DMA( 4 );
138
139	DMA_BLOCK( MGA_TEXCTL2,		tex->texctl2,
140		   MGA_TEXCTL,		tex->texctl,
141		   MGA_TEXFILTER,	tex->texfilter,
142		   MGA_TEXBORDERCOL,	tex->texbordercol );
143
144	DMA_BLOCK( MGA_TEXORG,		tex->texorg,
145		   MGA_TEXORG1,		tex->texorg1,
146		   MGA_TEXORG2,		tex->texorg2,
147		   MGA_TEXORG3,		tex->texorg3 );
148
149	DMA_BLOCK( MGA_TEXORG4,		tex->texorg4,
150		   MGA_TEXWIDTH,	tex->texwidth,
151		   MGA_TEXHEIGHT,	tex->texheight,
152		   MGA_WR24,		tex->texwidth );
153
154	DMA_BLOCK( MGA_WR34,		tex->texheight,
155		   MGA_TEXTRANS,	0x0000ffff,
156		   MGA_TEXTRANSHIGH,	0x0000ffff,
157		   MGA_DMAPAD,		0x00000000 );
158
159	ADVANCE_DMA();
160}
161
162static __inline__ void mga_g400_emit_tex0( drm_mga_private_t *dev_priv )
163{
164	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
165	drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
166	DMA_LOCALS;
167
168/*  	printk("mga_g400_emit_tex0 %x %x %x\n", tex->texorg, */
169/*  	       tex->texctl, tex->texctl2); */
170
171	BEGIN_DMA( 6 );
172
173	DMA_BLOCK( MGA_TEXCTL2,		tex->texctl2 | MGA_G400_TC2_MAGIC,
174		   MGA_TEXCTL,		tex->texctl,
175		   MGA_TEXFILTER,	tex->texfilter,
176		   MGA_TEXBORDERCOL,	tex->texbordercol );
177
178	DMA_BLOCK( MGA_TEXORG,		tex->texorg,
179		   MGA_TEXORG1,		tex->texorg1,
180		   MGA_TEXORG2,		tex->texorg2,
181		   MGA_TEXORG3,		tex->texorg3 );
182
183	DMA_BLOCK( MGA_TEXORG4,		tex->texorg4,
184		   MGA_TEXWIDTH,	tex->texwidth,
185		   MGA_TEXHEIGHT,	tex->texheight,
186		   MGA_WR49,		0x00000000 );
187
188	DMA_BLOCK( MGA_WR57,		0x00000000,
189		   MGA_WR53,		0x00000000,
190		   MGA_WR61,		0x00000000,
191		   MGA_WR52,		MGA_G400_WR_MAGIC );
192
193	DMA_BLOCK( MGA_WR60,		MGA_G400_WR_MAGIC,
194		   MGA_WR54,		tex->texwidth | MGA_G400_WR_MAGIC,
195		   MGA_WR62,		tex->texheight | MGA_G400_WR_MAGIC,
196		   MGA_DMAPAD,		0x00000000 );
197
198	DMA_BLOCK( MGA_DMAPAD,		0x00000000,
199		   MGA_DMAPAD,		0x00000000,
200		   MGA_TEXTRANS,	0x0000ffff,
201		   MGA_TEXTRANSHIGH,	0x0000ffff );
202
203	ADVANCE_DMA();
204}
205
206static __inline__ void mga_g400_emit_tex1( drm_mga_private_t *dev_priv )
207{
208	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
209	drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[1];
210	DMA_LOCALS;
211
212/*  	printk("mga_g400_emit_tex1 %x %x %x\n", tex->texorg,  */
213/*  	       tex->texctl, tex->texctl2); */
214
215	BEGIN_DMA( 5 );
216
217	DMA_BLOCK( MGA_TEXCTL2,		(tex->texctl2 |
218					 MGA_MAP1_ENABLE |
219					 MGA_G400_TC2_MAGIC),
220		   MGA_TEXCTL,		tex->texctl,
221		   MGA_TEXFILTER,	tex->texfilter,
222		   MGA_TEXBORDERCOL,	tex->texbordercol );
223
224	DMA_BLOCK( MGA_TEXORG,		tex->texorg,
225		   MGA_TEXORG1,		tex->texorg1,
226		   MGA_TEXORG2,		tex->texorg2,
227		   MGA_TEXORG3,		tex->texorg3 );
228
229	DMA_BLOCK( MGA_TEXORG4,		tex->texorg4,
230		   MGA_TEXWIDTH,	tex->texwidth,
231		   MGA_TEXHEIGHT,	tex->texheight,
232		   MGA_WR49,		0x00000000 );
233
234	DMA_BLOCK( MGA_WR57,		0x00000000,
235		   MGA_WR53,		0x00000000,
236		   MGA_WR61,		0x00000000,
237		   MGA_WR52,		tex->texwidth | MGA_G400_WR_MAGIC );
238
239	DMA_BLOCK( MGA_WR60,		tex->texheight | MGA_G400_WR_MAGIC,
240		   MGA_TEXTRANS,	0x0000ffff,
241		   MGA_TEXTRANSHIGH,	0x0000ffff,
242		   MGA_TEXCTL2,		tex->texctl2 | MGA_G400_TC2_MAGIC );
243
244	ADVANCE_DMA();
245}
246
247static __inline__ void mga_g200_emit_pipe( drm_mga_private_t *dev_priv )
248{
249	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
250	unsigned int pipe = sarea_priv->warp_pipe;
251	DMA_LOCALS;
252
253	BEGIN_DMA( 3 );
254
255	DMA_BLOCK( MGA_WIADDR,	MGA_WMODE_SUSPEND,
256		   MGA_WVRTXSZ,	0x00000007,
257		   MGA_WFLAG,	0x00000000,
258		   MGA_WR24,	0x00000000 );
259
260	DMA_BLOCK( MGA_WR25,	0x00000100,
261		   MGA_WR34,	0x00000000,
262		   MGA_WR42,	0x0000ffff,
263		   MGA_WR60,	0x0000ffff );
264
265	/* Padding required to to hardware bug.
266	 */
267	DMA_BLOCK( MGA_DMAPAD,	0xffffffff,
268		   MGA_DMAPAD,	0xffffffff,
269		   MGA_DMAPAD,	0xffffffff,
270		   MGA_WIADDR,	(dev_priv->warp_pipe_phys[pipe] |
271				 MGA_WMODE_START |
272				 MGA_WAGP_ENABLE) );
273
274	ADVANCE_DMA();
275}
276
277static __inline__ void mga_g400_emit_pipe( drm_mga_private_t *dev_priv )
278{
279	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
280	unsigned int pipe = sarea_priv->warp_pipe;
281	DMA_LOCALS;
282
283/*  	printk("mga_g400_emit_pipe %x\n", pipe); */
284
285	BEGIN_DMA( 10 );
286
287	DMA_BLOCK( MGA_WIADDR2,	MGA_WMODE_SUSPEND,
288		   MGA_DMAPAD,	0x00000000,
289		   MGA_DMAPAD,	0x00000000,
290		   MGA_DMAPAD,	0x00000000 );
291
292	if ( pipe & MGA_T2 ) {
293		DMA_BLOCK( MGA_WVRTXSZ,		0x00001e09,
294			   MGA_DMAPAD,		0x00000000,
295			   MGA_DMAPAD,		0x00000000,
296			   MGA_DMAPAD,		0x00000000 );
297
298		DMA_BLOCK( MGA_WACCEPTSEQ,	0x00000000,
299			   MGA_WACCEPTSEQ,	0x00000000,
300			   MGA_WACCEPTSEQ,	0x00000000,
301			   MGA_WACCEPTSEQ,	0x1e000000 );
302	} else {
303		if ( dev_priv->warp_pipe & MGA_T2 ) {
304			/* Flush the WARP pipe */
305			DMA_BLOCK( MGA_YDST,		0x00000000,
306				   MGA_FXLEFT,		0x00000000,
307				   MGA_FXRIGHT,		0x00000001,
308				   MGA_DWGCTL,		MGA_DWGCTL_FLUSH );
309
310			DMA_BLOCK( MGA_LEN + MGA_EXEC,	0x00000001,
311				   MGA_DWGSYNC,		0x00007000,
312				   MGA_TEXCTL2,		MGA_G400_TC2_MAGIC,
313				   MGA_LEN + MGA_EXEC,	0x00000000 );
314
315			DMA_BLOCK( MGA_TEXCTL2,		(MGA_DUALTEX |
316							 MGA_G400_TC2_MAGIC),
317				   MGA_LEN + MGA_EXEC,	0x00000000,
318				   MGA_TEXCTL2,		MGA_G400_TC2_MAGIC,
319				   MGA_DMAPAD,		0x00000000 );
320		}
321
322		DMA_BLOCK( MGA_WVRTXSZ,		0x00001807,
323			   MGA_DMAPAD,		0x00000000,
324			   MGA_DMAPAD,		0x00000000,
325			   MGA_DMAPAD,		0x00000000 );
326
327		DMA_BLOCK( MGA_WACCEPTSEQ,	0x00000000,
328			   MGA_WACCEPTSEQ,	0x00000000,
329			   MGA_WACCEPTSEQ,	0x00000000,
330			   MGA_WACCEPTSEQ,	0x18000000 );
331	}
332
333	DMA_BLOCK( MGA_WFLAG,	0x00000000,
334		   MGA_WFLAG1,	0x00000000,
335		   MGA_WR56,	MGA_G400_WR56_MAGIC,
336		   MGA_DMAPAD,	0x00000000 );
337
338	DMA_BLOCK( MGA_WR49,	0x00000000,		/* tex0              */
339		   MGA_WR57,	0x00000000,		/* tex0              */
340		   MGA_WR53,	0x00000000,		/* tex1              */
341		   MGA_WR61,	0x00000000 );		/* tex1              */
342
343	DMA_BLOCK( MGA_WR54,	MGA_G400_WR_MAGIC,	/* tex0 width        */
344		   MGA_WR62,	MGA_G400_WR_MAGIC,	/* tex0 height       */
345		   MGA_WR52,	MGA_G400_WR_MAGIC,	/* tex1 width        */
346		   MGA_WR60,	MGA_G400_WR_MAGIC );	/* tex1 height       */
347
348	/* Padding required to to hardware bug */
349	DMA_BLOCK( MGA_DMAPAD,	0xffffffff,
350		   MGA_DMAPAD,	0xffffffff,
351		   MGA_DMAPAD,	0xffffffff,
352		   MGA_WIADDR2,	(dev_priv->warp_pipe_phys[pipe] |
353				 MGA_WMODE_START |
354				 MGA_WAGP_ENABLE) );
355
356	ADVANCE_DMA();
357}
358
359static void mga_g200_emit_state( drm_mga_private_t *dev_priv )
360{
361	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
362	unsigned int dirty = sarea_priv->dirty;
363
364	if ( sarea_priv->warp_pipe != dev_priv->warp_pipe ) {
365		mga_g200_emit_pipe( dev_priv );
366		dev_priv->warp_pipe = sarea_priv->warp_pipe;
367	}
368
369	if ( dirty & MGA_UPLOAD_CONTEXT ) {
370		mga_g200_emit_context( dev_priv );
371		sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT;
372	}
373
374	if ( dirty & MGA_UPLOAD_TEX0 ) {
375		mga_g200_emit_tex0( dev_priv );
376		sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
377	}
378}
379
380static void mga_g400_emit_state( drm_mga_private_t *dev_priv )
381{
382	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
383	unsigned int dirty = sarea_priv->dirty;
384	int multitex = sarea_priv->warp_pipe & MGA_T2;
385
386	if ( sarea_priv->warp_pipe != dev_priv->warp_pipe ) {
387		mga_g400_emit_pipe( dev_priv );
388		dev_priv->warp_pipe = sarea_priv->warp_pipe;
389	}
390
391	if ( dirty & MGA_UPLOAD_CONTEXT ) {
392		mga_g400_emit_context( dev_priv );
393		sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT;
394	}
395
396	if ( dirty & MGA_UPLOAD_TEX0 ) {
397		mga_g400_emit_tex0( dev_priv );
398		sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
399	}
400
401	if ( (dirty & MGA_UPLOAD_TEX1) && multitex ) {
402		mga_g400_emit_tex1( dev_priv );
403		sarea_priv->dirty &= ~MGA_UPLOAD_TEX1;
404	}
405}
406
407
408/* ================================================================
409 * SAREA state verification
410 */
411
412/* Disallow all write destinations except the front and backbuffer.
413 */
414static int mga_verify_context( drm_mga_private_t *dev_priv )
415{
416	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
417	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
418
419	if ( ctx->dstorg != dev_priv->front_offset &&
420	     ctx->dstorg != dev_priv->back_offset ) {
421		DRM_ERROR( "*** bad DSTORG: %x (front %x, back %x)\n\n",
422			   ctx->dstorg, dev_priv->front_offset,
423			   dev_priv->back_offset );
424		ctx->dstorg = 0;
425		return DRM_ERR(EINVAL);
426	}
427
428	return 0;
429}
430
431/* Disallow texture reads from PCI space.
432 */
433static int mga_verify_tex( drm_mga_private_t *dev_priv, int unit )
434{
435	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
436	drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[unit];
437	unsigned int org;
438
439	org = tex->texorg & (MGA_TEXORGMAP_MASK | MGA_TEXORGACC_MASK);
440
441	if ( org == (MGA_TEXORGMAP_SYSMEM | MGA_TEXORGACC_PCI) ) {
442		DRM_ERROR( "*** bad TEXORG: 0x%x, unit %d\n",
443			   tex->texorg, unit );
444		tex->texorg = 0;
445		return DRM_ERR(EINVAL);
446	}
447
448	return 0;
449}
450
451static int mga_verify_state( drm_mga_private_t *dev_priv )
452{
453	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
454	unsigned int dirty = sarea_priv->dirty;
455	int ret = 0;
456
457	if ( sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS )
458		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
459
460	if ( dirty & MGA_UPLOAD_CONTEXT )
461		ret |= mga_verify_context( dev_priv );
462
463	if ( dirty & MGA_UPLOAD_TEX0 )
464		ret |= mga_verify_tex( dev_priv, 0 );
465
466	if ( dev_priv->chipset == MGA_CARD_TYPE_G400 ) {
467		if ( dirty & MGA_UPLOAD_TEX1 )
468			ret |= mga_verify_tex( dev_priv, 1 );
469
470		if ( dirty & MGA_UPLOAD_PIPE )
471			ret |= ( sarea_priv->warp_pipe > MGA_MAX_G400_PIPES );
472	} else {
473		if ( dirty & MGA_UPLOAD_PIPE )
474			ret |= ( sarea_priv->warp_pipe > MGA_MAX_G200_PIPES );
475	}
476
477	return ( ret == 0 );
478}
479
480static int mga_verify_iload( drm_mga_private_t *dev_priv,
481			     unsigned int dstorg, unsigned int length )
482{
483	if ( dstorg < dev_priv->texture_offset ||
484	     dstorg + length > (dev_priv->texture_offset +
485				dev_priv->texture_size) ) {
486		DRM_ERROR( "*** bad iload DSTORG: 0x%x\n", dstorg );
487		return DRM_ERR(EINVAL);
488	}
489
490	if ( length & MGA_ILOAD_MASK ) {
491		DRM_ERROR( "*** bad iload length: 0x%x\n",
492			   length & MGA_ILOAD_MASK );
493		return DRM_ERR(EINVAL);
494	}
495
496	return 0;
497}
498
499static int mga_verify_blit( drm_mga_private_t *dev_priv,
500			    unsigned int srcorg, unsigned int dstorg )
501{
502	if ( (srcorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) ||
503	     (dstorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) ) {
504		DRM_ERROR( "*** bad blit: src=0x%x dst=0x%x\n",
505			   srcorg, dstorg );
506		return DRM_ERR(EINVAL);
507	}
508	return 0;
509}
510
511
512/* ================================================================
513 *
514 */
515
516static void mga_dma_dispatch_clear( drm_device_t *dev,
517				    drm_mga_clear_t *clear )
518{
519	drm_mga_private_t *dev_priv = dev->dev_private;
520	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
521	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
522	drm_clip_rect_t *pbox = sarea_priv->boxes;
523	int nbox = sarea_priv->nbox;
524	int i;
525	DMA_LOCALS;
526	DRM_DEBUG( "\n" );
527
528	BEGIN_DMA( 1 );
529
530	DMA_BLOCK( MGA_DMAPAD,	0x00000000,
531		   MGA_DMAPAD,	0x00000000,
532		   MGA_DWGSYNC,	0x00007100,
533		   MGA_DWGSYNC,	0x00007000 );
534
535	ADVANCE_DMA();
536
537	for ( i = 0 ; i < nbox ; i++ ) {
538		drm_clip_rect_t *box = &pbox[i];
539		u32 height = box->y2 - box->y1;
540
541		DRM_DEBUG( "   from=%d,%d to=%d,%d\n",
542			   box->x1, box->y1, box->x2, box->y2 );
543
544		if ( clear->flags & MGA_FRONT ) {
545			BEGIN_DMA( 2 );
546
547			DMA_BLOCK( MGA_DMAPAD,	0x00000000,
548				   MGA_PLNWT,	clear->color_mask,
549				   MGA_YDSTLEN, (box->y1 << 16) | height,
550				   MGA_FXBNDRY, (box->x2 << 16) | box->x1 );
551
552			DMA_BLOCK( MGA_DMAPAD,	0x00000000,
553				   MGA_FCOL,	clear->clear_color,
554				   MGA_DSTORG,	dev_priv->front_offset,
555				   MGA_DWGCTL + MGA_EXEC,
556						dev_priv->clear_cmd );
557
558			ADVANCE_DMA();
559		}
560
561
562		if ( clear->flags & MGA_BACK ) {
563			BEGIN_DMA( 2 );
564
565			DMA_BLOCK( MGA_DMAPAD,	0x00000000,
566				   MGA_PLNWT,	clear->color_mask,
567				   MGA_YDSTLEN, (box->y1 << 16) | height,
568				   MGA_FXBNDRY, (box->x2 << 16) | box->x1 );
569
570			DMA_BLOCK( MGA_DMAPAD,	0x00000000,
571				   MGA_FCOL,	clear->clear_color,
572				   MGA_DSTORG,	dev_priv->back_offset,
573				   MGA_DWGCTL + MGA_EXEC,
574						dev_priv->clear_cmd );
575
576			ADVANCE_DMA();
577		}
578
579		if ( clear->flags & MGA_DEPTH ) {
580			BEGIN_DMA( 2 );
581
582			DMA_BLOCK( MGA_DMAPAD,	0x00000000,
583				   MGA_PLNWT,	clear->depth_mask,
584				   MGA_YDSTLEN, (box->y1 << 16) | height,
585				   MGA_FXBNDRY, (box->x2 << 16) | box->x1 );
586
587			DMA_BLOCK( MGA_DMAPAD,	0x00000000,
588				   MGA_FCOL,	clear->clear_depth,
589				   MGA_DSTORG,	dev_priv->depth_offset,
590				   MGA_DWGCTL + MGA_EXEC,
591						dev_priv->clear_cmd );
592
593			ADVANCE_DMA();
594		}
595
596	}
597
598	BEGIN_DMA( 1 );
599
600	/* Force reset of DWGCTL */
601	DMA_BLOCK( MGA_DMAPAD,	0x00000000,
602		   MGA_DMAPAD,	0x00000000,
603		   MGA_PLNWT,	ctx->plnwt,
604		   MGA_DWGCTL,	ctx->dwgctl );
605
606	ADVANCE_DMA();
607
608	FLUSH_DMA();
609}
610
611static void mga_dma_dispatch_swap( drm_device_t *dev )
612{
613	drm_mga_private_t *dev_priv = dev->dev_private;
614	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
615	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
616	drm_clip_rect_t *pbox = sarea_priv->boxes;
617	int nbox = sarea_priv->nbox;
618	int i;
619	DMA_LOCALS;
620	DRM_DEBUG( "\n" );
621
622	sarea_priv->last_frame.head = dev_priv->prim.tail;
623	sarea_priv->last_frame.wrap = dev_priv->prim.last_wrap;
624
625	BEGIN_DMA( 4 + nbox );
626
627	DMA_BLOCK( MGA_DMAPAD,	0x00000000,
628		   MGA_DMAPAD,	0x00000000,
629		   MGA_DWGSYNC,	0x00007100,
630		   MGA_DWGSYNC,	0x00007000 );
631
632	DMA_BLOCK( MGA_DSTORG,	dev_priv->front_offset,
633		   MGA_MACCESS,	dev_priv->maccess,
634		   MGA_SRCORG,	dev_priv->back_offset,
635		   MGA_AR5,	dev_priv->front_pitch );
636
637	DMA_BLOCK( MGA_DMAPAD,	0x00000000,
638		   MGA_DMAPAD,	0x00000000,
639		   MGA_PLNWT,	0xffffffff,
640		   MGA_DWGCTL,	MGA_DWGCTL_COPY );
641
642	for ( i = 0 ; i < nbox ; i++ ) {
643		drm_clip_rect_t *box = &pbox[i];
644		u32 height = box->y2 - box->y1;
645		u32 start = box->y1 * dev_priv->front_pitch;
646
647		DRM_DEBUG( "   from=%d,%d to=%d,%d\n",
648			   box->x1, box->y1, box->x2, box->y2 );
649
650		DMA_BLOCK( MGA_AR0,	start + box->x2 - 1,
651			   MGA_AR3,	start + box->x1,
652			   MGA_FXBNDRY,	((box->x2 - 1) << 16) | box->x1,
653			   MGA_YDSTLEN + MGA_EXEC,
654					(box->y1 << 16) | height );
655	}
656
657	DMA_BLOCK( MGA_DMAPAD,	0x00000000,
658		   MGA_PLNWT,	ctx->plnwt,
659		   MGA_SRCORG,	dev_priv->front_offset,
660		   MGA_DWGCTL,	ctx->dwgctl );
661
662	ADVANCE_DMA();
663
664	FLUSH_DMA();
665
666	DRM_DEBUG( "%s... done.\n", __FUNCTION__ );
667}
668
669static void mga_dma_dispatch_vertex( drm_device_t *dev, drm_buf_t *buf )
670{
671	drm_mga_private_t *dev_priv = dev->dev_private;
672	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
673	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
674	u32 address = (u32) buf->bus_address;
675	u32 length = (u32) buf->used;
676	int i = 0;
677	DMA_LOCALS;
678	DRM_DEBUG( "vertex: buf=%d used=%d\n", buf->idx, buf->used );
679
680	if ( buf->used ) {
681		buf_priv->dispatched = 1;
682
683		MGA_EMIT_STATE( dev_priv, sarea_priv->dirty );
684
685		do {
686			if ( i < sarea_priv->nbox ) {
687				mga_emit_clip_rect( dev_priv,
688						    &sarea_priv->boxes[i] );
689			}
690
691			BEGIN_DMA( 1 );
692
693			DMA_BLOCK( MGA_DMAPAD,		0x00000000,
694				   MGA_DMAPAD,		0x00000000,
695				   MGA_SECADDRESS,	(address |
696							 MGA_DMA_VERTEX),
697				   MGA_SECEND,		((address + length) |
698							 MGA_PAGPXFER) );
699
700			ADVANCE_DMA();
701		} while ( ++i < sarea_priv->nbox );
702	}
703
704	if ( buf_priv->discard ) {
705		AGE_BUFFER( buf_priv );
706		buf->pending = 0;
707		buf->used = 0;
708		buf_priv->dispatched = 0;
709
710		mga_freelist_put( dev, buf );
711	}
712
713	FLUSH_DMA();
714}
715
716static void mga_dma_dispatch_indices( drm_device_t *dev, drm_buf_t *buf,
717				      unsigned int start, unsigned int end )
718{
719	drm_mga_private_t *dev_priv = dev->dev_private;
720	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
721	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
722	u32 address = (u32) buf->bus_address;
723	int i = 0;
724	DMA_LOCALS;
725	DRM_DEBUG( "indices: buf=%d start=%d end=%d\n", buf->idx, start, end );
726
727	if ( start != end ) {
728		buf_priv->dispatched = 1;
729
730		MGA_EMIT_STATE( dev_priv, sarea_priv->dirty );
731
732		do {
733			if ( i < sarea_priv->nbox ) {
734				mga_emit_clip_rect( dev_priv,
735						    &sarea_priv->boxes[i] );
736			}
737
738			BEGIN_DMA( 1 );
739
740			DMA_BLOCK( MGA_DMAPAD,		0x00000000,
741				   MGA_DMAPAD,		0x00000000,
742				   MGA_SETUPADDRESS,	address + start,
743				   MGA_SETUPEND,	((address + end) |
744							 MGA_PAGPXFER) );
745
746			ADVANCE_DMA();
747		} while ( ++i < sarea_priv->nbox );
748	}
749
750	if ( buf_priv->discard ) {
751		AGE_BUFFER( buf_priv );
752		buf->pending = 0;
753		buf->used = 0;
754		buf_priv->dispatched = 0;
755
756		mga_freelist_put( dev, buf );
757	}
758
759	FLUSH_DMA();
760}
761
762/* This copies a 64 byte aligned agp region to the frambuffer with a
763 * standard blit, the ioctl needs to do checking.
764 */
765static void mga_dma_dispatch_iload( drm_device_t *dev, drm_buf_t *buf,
766				    unsigned int dstorg, unsigned int length )
767{
768	drm_mga_private_t *dev_priv = dev->dev_private;
769	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
770	drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state;
771	u32 srcorg = buf->bus_address | MGA_SRCACC_AGP | MGA_SRCMAP_SYSMEM;
772	u32 y2;
773	DMA_LOCALS;
774	DRM_DEBUG( "buf=%d used=%d\n", buf->idx, buf->used );
775
776	y2 = length / 64;
777
778	BEGIN_DMA( 5 );
779
780	DMA_BLOCK( MGA_DMAPAD,	0x00000000,
781		   MGA_DMAPAD,	0x00000000,
782		   MGA_DWGSYNC,	0x00007100,
783		   MGA_DWGSYNC,	0x00007000 );
784
785	DMA_BLOCK( MGA_DSTORG,	dstorg,
786		   MGA_MACCESS,	0x00000000,
787		   MGA_SRCORG,	srcorg,
788		   MGA_AR5,	64 );
789
790	DMA_BLOCK( MGA_PITCH,	64,
791		   MGA_PLNWT,	0xffffffff,
792		   MGA_DMAPAD,	0x00000000,
793		   MGA_DWGCTL,	MGA_DWGCTL_COPY );
794
795	DMA_BLOCK( MGA_AR0,	63,
796		   MGA_AR3,	0,
797		   MGA_FXBNDRY,	(63 << 16) | 0,
798		   MGA_YDSTLEN + MGA_EXEC, y2 );
799
800	DMA_BLOCK( MGA_PLNWT,	ctx->plnwt,
801		   MGA_SRCORG,	dev_priv->front_offset,
802		   MGA_PITCH,	dev_priv->front_pitch,
803		   MGA_DWGSYNC,	0x00007000 );
804
805	ADVANCE_DMA();
806
807	AGE_BUFFER( buf_priv );
808
809	buf->pending = 0;
810	buf->used = 0;
811	buf_priv->dispatched = 0;
812
813	mga_freelist_put( dev, buf );
814
815	FLUSH_DMA();
816}
817
818static void mga_dma_dispatch_blit( drm_device_t *dev,
819				   drm_mga_blit_t *blit )
820{
821	drm_mga_private_t *dev_priv = dev->dev_private;
822	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
823	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
824	drm_clip_rect_t *pbox = sarea_priv->boxes;
825	int nbox = sarea_priv->nbox;
826	u32 scandir = 0, i;
827	DMA_LOCALS;
828	DRM_DEBUG( "\n" );
829
830	BEGIN_DMA( 4 + nbox );
831
832	DMA_BLOCK( MGA_DMAPAD,	0x00000000,
833		   MGA_DMAPAD,	0x00000000,
834		   MGA_DWGSYNC,	0x00007100,
835		   MGA_DWGSYNC,	0x00007000 );
836
837	DMA_BLOCK( MGA_DWGCTL,	MGA_DWGCTL_COPY,
838		   MGA_PLNWT,	blit->planemask,
839		   MGA_SRCORG,	blit->srcorg,
840		   MGA_DSTORG,	blit->dstorg );
841
842	DMA_BLOCK( MGA_SGN,	scandir,
843		   MGA_MACCESS,	dev_priv->maccess,
844		   MGA_AR5,	blit->ydir * blit->src_pitch,
845		   MGA_PITCH,	blit->dst_pitch );
846
847	for ( i = 0 ; i < nbox ; i++ ) {
848		int srcx = pbox[i].x1 + blit->delta_sx;
849		int srcy = pbox[i].y1 + blit->delta_sy;
850		int dstx = pbox[i].x1 + blit->delta_dx;
851		int dsty = pbox[i].y1 + blit->delta_dy;
852		int h = pbox[i].y2 - pbox[i].y1;
853		int w = pbox[i].x2 - pbox[i].x1 - 1;
854		int start;
855
856		if ( blit->ydir == -1 ) {
857			srcy = blit->height - srcy - 1;
858		}
859
860		start = srcy * blit->src_pitch + srcx;
861
862		DMA_BLOCK( MGA_AR0,	start + w,
863			   MGA_AR3,	start,
864			   MGA_FXBNDRY,	((dstx + w) << 16) | (dstx & 0xffff),
865			   MGA_YDSTLEN + MGA_EXEC, (dsty << 16) | h );
866	}
867
868	/* Do something to flush AGP?
869	 */
870
871	/* Force reset of DWGCTL */
872	DMA_BLOCK( MGA_DMAPAD,	0x00000000,
873		   MGA_PLNWT,	ctx->plnwt,
874		   MGA_PITCH,	dev_priv->front_pitch,
875		   MGA_DWGCTL,	ctx->dwgctl );
876
877	ADVANCE_DMA();
878}
879
880
881/* ================================================================
882 *
883 */
884
885int mga_dma_clear( DRM_IOCTL_ARGS )
886{
887	DRM_DEVICE;
888	drm_mga_private_t *dev_priv = dev->dev_private;
889	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
890	drm_mga_clear_t clear;
891
892	LOCK_TEST_WITH_RETURN( dev, filp );
893
894	DRM_COPY_FROM_USER_IOCTL( clear, (drm_mga_clear_t *)data, sizeof(clear) );
895
896	if ( sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS )
897		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
898
899	WRAP_TEST_WITH_RETURN( dev_priv );
900
901	mga_dma_dispatch_clear( dev, &clear );
902
903	/* Make sure we restore the 3D state next time.
904	 */
905	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
906
907	return 0;
908}
909
910int mga_dma_swap( DRM_IOCTL_ARGS )
911{
912	DRM_DEVICE;
913	drm_mga_private_t *dev_priv = dev->dev_private;
914	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
915
916	LOCK_TEST_WITH_RETURN( dev, filp );
917
918	if ( sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS )
919		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
920
921	WRAP_TEST_WITH_RETURN( dev_priv );
922
923	mga_dma_dispatch_swap( dev );
924
925	/* Make sure we restore the 3D state next time.
926	 */
927	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
928
929	return 0;
930}
931
932int mga_dma_vertex( DRM_IOCTL_ARGS )
933{
934	DRM_DEVICE;
935	drm_mga_private_t *dev_priv = dev->dev_private;
936	drm_device_dma_t *dma = dev->dma;
937	drm_buf_t *buf;
938	drm_mga_buf_priv_t *buf_priv;
939	drm_mga_vertex_t vertex;
940
941	LOCK_TEST_WITH_RETURN( dev, filp );
942
943	DRM_COPY_FROM_USER_IOCTL( vertex,
944			     (drm_mga_vertex_t *)data,
945			     sizeof(vertex) );
946
947        if(vertex.idx < 0 || vertex.idx > dma->buf_count) return DRM_ERR(EINVAL);
948	buf = dma->buflist[vertex.idx];
949	buf_priv = buf->dev_private;
950
951	buf->used = vertex.used;
952	buf_priv->discard = vertex.discard;
953
954	if ( !mga_verify_state( dev_priv ) ) {
955		if ( vertex.discard ) {
956			if ( buf_priv->dispatched == 1 )
957				AGE_BUFFER( buf_priv );
958			buf_priv->dispatched = 0;
959			mga_freelist_put( dev, buf );
960		}
961		return DRM_ERR(EINVAL);
962	}
963
964	WRAP_TEST_WITH_RETURN( dev_priv );
965
966	mga_dma_dispatch_vertex( dev, buf );
967
968	return 0;
969}
970
971int mga_dma_indices( DRM_IOCTL_ARGS )
972{
973	DRM_DEVICE;
974	drm_mga_private_t *dev_priv = dev->dev_private;
975	drm_device_dma_t *dma = dev->dma;
976	drm_buf_t *buf;
977	drm_mga_buf_priv_t *buf_priv;
978	drm_mga_indices_t indices;
979
980	LOCK_TEST_WITH_RETURN( dev, filp );
981
982	DRM_COPY_FROM_USER_IOCTL( indices,
983			     (drm_mga_indices_t *)data,
984			     sizeof(indices) );
985
986        if(indices.idx < 0 || indices.idx > dma->buf_count) return DRM_ERR(EINVAL);
987
988	buf = dma->buflist[indices.idx];
989	buf_priv = buf->dev_private;
990
991	buf_priv->discard = indices.discard;
992
993	if ( !mga_verify_state( dev_priv ) ) {
994		if ( indices.discard ) {
995			if ( buf_priv->dispatched == 1 )
996				AGE_BUFFER( buf_priv );
997			buf_priv->dispatched = 0;
998			mga_freelist_put( dev, buf );
999		}
1000		return DRM_ERR(EINVAL);
1001	}
1002
1003	WRAP_TEST_WITH_RETURN( dev_priv );
1004
1005	mga_dma_dispatch_indices( dev, buf, indices.start, indices.end );
1006
1007	return 0;
1008}
1009
1010int mga_dma_iload( DRM_IOCTL_ARGS )
1011{
1012	DRM_DEVICE;
1013	drm_device_dma_t *dma = dev->dma;
1014	drm_mga_private_t *dev_priv = dev->dev_private;
1015	drm_buf_t *buf;
1016	drm_mga_buf_priv_t *buf_priv;
1017	drm_mga_iload_t iload;
1018	DRM_DEBUG( "\n" );
1019
1020	LOCK_TEST_WITH_RETURN( dev, filp );
1021
1022	DRM_COPY_FROM_USER_IOCTL( iload, (drm_mga_iload_t *)data, sizeof(iload) );
1023
1024#if 0
1025	if ( mga_do_wait_for_idle( dev_priv ) < 0 ) {
1026		if ( MGA_DMA_DEBUG )
1027			DRM_INFO( "%s: -EBUSY\n", __FUNCTION__ );
1028		return DRM_ERR(EBUSY);
1029	}
1030#endif
1031        if(iload.idx < 0 || iload.idx > dma->buf_count) return DRM_ERR(EINVAL);
1032
1033	buf = dma->buflist[iload.idx];
1034	buf_priv = buf->dev_private;
1035
1036	if ( mga_verify_iload( dev_priv, iload.dstorg, iload.length ) ) {
1037		mga_freelist_put( dev, buf );
1038		return DRM_ERR(EINVAL);
1039	}
1040
1041	WRAP_TEST_WITH_RETURN( dev_priv );
1042
1043	mga_dma_dispatch_iload( dev, buf, iload.dstorg, iload.length );
1044
1045	/* Make sure we restore the 3D state next time.
1046	 */
1047	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
1048
1049	return 0;
1050}
1051
1052int mga_dma_blit( DRM_IOCTL_ARGS )
1053{
1054	DRM_DEVICE;
1055	drm_mga_private_t *dev_priv = dev->dev_private;
1056	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
1057	drm_mga_blit_t blit;
1058	DRM_DEBUG( "\n" );
1059
1060	LOCK_TEST_WITH_RETURN( dev, filp );
1061
1062	DRM_COPY_FROM_USER_IOCTL( blit, (drm_mga_blit_t *)data, sizeof(blit) );
1063
1064	if ( sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS )
1065		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
1066
1067	if ( mga_verify_blit( dev_priv, blit.srcorg, blit.dstorg ) )
1068		return DRM_ERR(EINVAL);
1069
1070	WRAP_TEST_WITH_RETURN( dev_priv );
1071
1072	mga_dma_dispatch_blit( dev, &blit );
1073
1074	/* Make sure we restore the 3D state next time.
1075	 */
1076	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
1077
1078	return 0;
1079}
1080
1081int mga_getparam( DRM_IOCTL_ARGS )
1082{
1083	DRM_DEVICE;
1084	drm_mga_private_t *dev_priv = dev->dev_private;
1085	drm_mga_getparam_t param;
1086	int value;
1087
1088	if ( !dev_priv ) {
1089		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
1090		return DRM_ERR(EINVAL);
1091	}
1092
1093	DRM_COPY_FROM_USER_IOCTL( param, (drm_mga_getparam_t *)data,
1094			     sizeof(param) );
1095
1096	DRM_DEBUG( "pid=%d\n", DRM_CURRENTPID );
1097
1098	switch( param.param ) {
1099	case MGA_PARAM_IRQ_NR:
1100		value = dev->irq;
1101		break;
1102	default:
1103		return DRM_ERR(EINVAL);
1104	}
1105
1106	if ( DRM_COPY_TO_USER( param.value, &value, sizeof(int) ) ) {
1107		DRM_ERROR( "copy_to_user\n" );
1108		return DRM_ERR(EFAULT);
1109	}
1110
1111	return 0;
1112}
1113