]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/drm/mga_state.c
This commit was generated by cvs2svn to compensate for changes in r136632,
[FreeBSD/FreeBSD.git] / sys / dev / 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
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
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
50 static 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
76 static __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
102 static __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
133 static __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
164 static /*__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
208 static __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
249 static __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
279 static /*__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
361 static 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
382 static 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  */
416 static 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  */
435 static 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
453 static 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
482 static 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
501 static 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
518 static 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
613 static 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
671 static 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
718 static 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  */
767 static 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
820 static 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
887 int 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
912 int 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
934 int 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
973 int 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
1012 int 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
1054 int 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
1083 int 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 }