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