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