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