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