195584Sanholt/* mga_state.c -- State support for MGA G200/G400 -*- linux-c -*-
2152909Sanholt * Created: Thu Jan 27 02:53:43 2000 by jhartmann@precisioninsight.com
3152909Sanholt */
4139749Simp/*-
595584Sanholt * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
695584Sanholt * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
795584Sanholt * All Rights Reserved.
895584Sanholt *
995584Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
1095584Sanholt * copy of this software and associated documentation files (the "Software"),
1195584Sanholt * to deal in the Software without restriction, including without limitation
1295584Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1395584Sanholt * and/or sell copies of the Software, and to permit persons to whom the
1495584Sanholt * Software is furnished to do so, subject to the following conditions:
1595584Sanholt *
1695584Sanholt * The above copyright notice and this permission notice (including the next
1795584Sanholt * paragraph) shall be included in all copies or substantial portions of the
1895584Sanholt * Software.
1995584Sanholt *
2095584Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2195584Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2295584Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2395584Sanholt * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2495584Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2595584Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2695584Sanholt * OTHER DEALINGS IN THE SOFTWARE.
2795584Sanholt *
2895584Sanholt * Authors:
2995584Sanholt *    Jeff Hartmann <jhartmann@valinux.com>
30112015Sanholt *    Keith Whitwell <keith@tungstengraphics.com>
3195584Sanholt *
3295584Sanholt * Rewritten by:
3395584Sanholt *    Gareth Hughes <gareth@valinux.com>
3495584Sanholt */
3595584Sanholt
36152909Sanholt#include <sys/cdefs.h>
37152909Sanholt__FBSDID("$FreeBSD: stable/11/sys/dev/drm/mga_state.c 330446 2018-03-05 06:59:30Z eadler $");
38152909Sanholt
3995584Sanholt#include "dev/drm/drmP.h"
40112015Sanholt#include "dev/drm/drm.h"
4195746Sanholt#include "dev/drm/mga_drm.h"
4295584Sanholt#include "dev/drm/mga_drv.h"
4395584Sanholt
4495584Sanholt/* ================================================================
4595584Sanholt * DMA hardware state programming functions
4695584Sanholt */
4795584Sanholt
48145132Sanholtstatic void mga_emit_clip_rect(drm_mga_private_t * dev_priv,
49182080Srnoland			       struct drm_clip_rect * box)
5095584Sanholt{
5195584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
5295584Sanholt	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
5395584Sanholt	unsigned int pitch = dev_priv->front_pitch;
5495584Sanholt	DMA_LOCALS;
5595584Sanholt
56145132Sanholt	BEGIN_DMA(2);
5795584Sanholt
5895584Sanholt	/* Force reset of DWGCTL on G400 (eliminates clip disable bit).
5995584Sanholt	 */
60152909Sanholt	if (dev_priv->chipset >= MGA_CARD_TYPE_G400) {
61145132Sanholt		DMA_BLOCK(MGA_DWGCTL, ctx->dwgctl,
62145132Sanholt			  MGA_LEN + MGA_EXEC, 0x80000000,
63145132Sanholt			  MGA_DWGCTL, ctx->dwgctl,
64145132Sanholt			  MGA_LEN + MGA_EXEC, 0x80000000);
6595584Sanholt	}
66145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
67145132Sanholt		  MGA_CXBNDRY, ((box->x2 - 1) << 16) | box->x1,
68182080Srnoland		  MGA_YTOP, box->y1 * pitch, MGA_YBOT, (box->y2 - 1) * pitch);
6995584Sanholt
7095584Sanholt	ADVANCE_DMA();
7195584Sanholt}
7295584Sanholt
73145132Sanholtstatic __inline__ void mga_g200_emit_context(drm_mga_private_t * dev_priv)
7495584Sanholt{
7595584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
7695584Sanholt	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
7795584Sanholt	DMA_LOCALS;
7895584Sanholt
79145132Sanholt	BEGIN_DMA(3);
8095584Sanholt
81145132Sanholt	DMA_BLOCK(MGA_DSTORG, ctx->dstorg,
82145132Sanholt		  MGA_MACCESS, ctx->maccess,
83182080Srnoland		  MGA_PLNWT, ctx->plnwt, MGA_DWGCTL, ctx->dwgctl);
8495584Sanholt
85145132Sanholt	DMA_BLOCK(MGA_ALPHACTRL, ctx->alphactrl,
86145132Sanholt		  MGA_FOGCOL, ctx->fogcolor,
87182080Srnoland		  MGA_WFLAG, ctx->wflag, MGA_ZORG, dev_priv->depth_offset);
8895584Sanholt
89145132Sanholt	DMA_BLOCK(MGA_FCOL, ctx->fcol,
90145132Sanholt		  MGA_DMAPAD, 0x00000000,
91182080Srnoland		  MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
9295584Sanholt
9395584Sanholt	ADVANCE_DMA();
9495584Sanholt}
9595584Sanholt
96145132Sanholtstatic __inline__ void mga_g400_emit_context(drm_mga_private_t * dev_priv)
9795584Sanholt{
9895584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
9995584Sanholt	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
10095584Sanholt	DMA_LOCALS;
10195584Sanholt
102145132Sanholt	BEGIN_DMA(4);
10395584Sanholt
104145132Sanholt	DMA_BLOCK(MGA_DSTORG, ctx->dstorg,
105145132Sanholt		  MGA_MACCESS, ctx->maccess,
106145132Sanholt		  MGA_PLNWT, ctx->plnwt,
107145132Sanholt		  MGA_DWGCTL, ctx->dwgctl);
10895584Sanholt
109145132Sanholt	DMA_BLOCK(MGA_ALPHACTRL, ctx->alphactrl,
110145132Sanholt		  MGA_FOGCOL, ctx->fogcolor,
111145132Sanholt		  MGA_WFLAG, ctx->wflag,
112145132Sanholt		  MGA_ZORG, dev_priv->depth_offset);
11395584Sanholt
114145132Sanholt	DMA_BLOCK(MGA_WFLAG1, ctx->wflag,
115145132Sanholt		  MGA_TDUALSTAGE0, ctx->tdualstage0,
116145132Sanholt		  MGA_TDUALSTAGE1, ctx->tdualstage1,
117145132Sanholt		  MGA_FCOL, ctx->fcol);
11895584Sanholt
119145132Sanholt	DMA_BLOCK(MGA_STENCIL, ctx->stencil,
120145132Sanholt		  MGA_STENCILCTL, ctx->stencilctl,
121145132Sanholt		  MGA_DMAPAD, 0x00000000,
122145132Sanholt		  MGA_DMAPAD, 0x00000000);
12395584Sanholt
12495584Sanholt	ADVANCE_DMA();
12595584Sanholt}
12695584Sanholt
127145132Sanholtstatic __inline__ void mga_g200_emit_tex0(drm_mga_private_t * dev_priv)
12895584Sanholt{
12995584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
13095584Sanholt	drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
13195584Sanholt	DMA_LOCALS;
13295584Sanholt
133145132Sanholt	BEGIN_DMA(4);
13495584Sanholt
135145132Sanholt	DMA_BLOCK(MGA_TEXCTL2, tex->texctl2,
136145132Sanholt		  MGA_TEXCTL, tex->texctl,
137145132Sanholt		  MGA_TEXFILTER, tex->texfilter,
138145132Sanholt		  MGA_TEXBORDERCOL, tex->texbordercol);
13995584Sanholt
140145132Sanholt	DMA_BLOCK(MGA_TEXORG, tex->texorg,
141145132Sanholt		  MGA_TEXORG1, tex->texorg1,
142145132Sanholt		  MGA_TEXORG2, tex->texorg2,
143145132Sanholt		  MGA_TEXORG3, tex->texorg3);
14495584Sanholt
145145132Sanholt	DMA_BLOCK(MGA_TEXORG4, tex->texorg4,
146145132Sanholt		  MGA_TEXWIDTH, tex->texwidth,
147145132Sanholt		  MGA_TEXHEIGHT, tex->texheight,
148145132Sanholt		  MGA_WR24, tex->texwidth);
14995584Sanholt
150145132Sanholt	DMA_BLOCK(MGA_WR34, tex->texheight,
151145132Sanholt		  MGA_TEXTRANS, 0x0000ffff,
152145132Sanholt		  MGA_TEXTRANSHIGH, 0x0000ffff,
153145132Sanholt		  MGA_DMAPAD, 0x00000000);
15495584Sanholt
15595584Sanholt	ADVANCE_DMA();
15695584Sanholt}
15795584Sanholt
158145132Sanholtstatic __inline__ void mga_g400_emit_tex0(drm_mga_private_t * dev_priv)
15995584Sanholt{
16095584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
16195584Sanholt	drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
16295584Sanholt	DMA_LOCALS;
16395584Sanholt
164182080Srnoland/*	printk("mga_g400_emit_tex0 %x %x %x\n", tex->texorg, */
165182080Srnoland/*	       tex->texctl, tex->texctl2); */
166112015Sanholt
167145132Sanholt	BEGIN_DMA(6);
16895584Sanholt
169145132Sanholt	DMA_BLOCK(MGA_TEXCTL2, tex->texctl2 | MGA_G400_TC2_MAGIC,
170145132Sanholt		  MGA_TEXCTL, tex->texctl,
171145132Sanholt		  MGA_TEXFILTER, tex->texfilter,
172145132Sanholt		  MGA_TEXBORDERCOL, tex->texbordercol);
17395584Sanholt
174145132Sanholt	DMA_BLOCK(MGA_TEXORG, tex->texorg,
175145132Sanholt		  MGA_TEXORG1, tex->texorg1,
176145132Sanholt		  MGA_TEXORG2, tex->texorg2,
177145132Sanholt		  MGA_TEXORG3, tex->texorg3);
17895584Sanholt
179145132Sanholt	DMA_BLOCK(MGA_TEXORG4, tex->texorg4,
180145132Sanholt		  MGA_TEXWIDTH, tex->texwidth,
181145132Sanholt		  MGA_TEXHEIGHT, tex->texheight,
182145132Sanholt		  MGA_WR49, 0x00000000);
18395584Sanholt
184145132Sanholt	DMA_BLOCK(MGA_WR57, 0x00000000,
185145132Sanholt		  MGA_WR53, 0x00000000,
186145132Sanholt		  MGA_WR61, 0x00000000,
187145132Sanholt		  MGA_WR52, MGA_G400_WR_MAGIC);
18895584Sanholt
189145132Sanholt	DMA_BLOCK(MGA_WR60, MGA_G400_WR_MAGIC,
190145132Sanholt		  MGA_WR54, tex->texwidth | MGA_G400_WR_MAGIC,
191145132Sanholt		  MGA_WR62, tex->texheight | MGA_G400_WR_MAGIC,
192145132Sanholt		  MGA_DMAPAD, 0x00000000);
19395584Sanholt
194145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
195145132Sanholt		  MGA_DMAPAD, 0x00000000,
196145132Sanholt		  MGA_TEXTRANS, 0x0000ffff,
197145132Sanholt		  MGA_TEXTRANSHIGH, 0x0000ffff);
19895584Sanholt
19995584Sanholt	ADVANCE_DMA();
20095584Sanholt}
20195584Sanholt
202145132Sanholtstatic __inline__ void mga_g400_emit_tex1(drm_mga_private_t * dev_priv)
20395584Sanholt{
20495584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
20595584Sanholt	drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[1];
20695584Sanholt	DMA_LOCALS;
20795584Sanholt
208182080Srnoland/*	printk("mga_g400_emit_tex1 %x %x %x\n", tex->texorg,  */
209182080Srnoland/*	       tex->texctl, tex->texctl2); */
210112015Sanholt
211145132Sanholt	BEGIN_DMA(5);
21295584Sanholt
213145132Sanholt	DMA_BLOCK(MGA_TEXCTL2, (tex->texctl2 |
214145132Sanholt				MGA_MAP1_ENABLE |
215145132Sanholt				MGA_G400_TC2_MAGIC),
216145132Sanholt		  MGA_TEXCTL, tex->texctl,
217145132Sanholt		  MGA_TEXFILTER, tex->texfilter,
218145132Sanholt		  MGA_TEXBORDERCOL, tex->texbordercol);
21995584Sanholt
220145132Sanholt	DMA_BLOCK(MGA_TEXORG, tex->texorg,
221145132Sanholt		  MGA_TEXORG1, tex->texorg1,
222145132Sanholt		  MGA_TEXORG2, tex->texorg2,
223145132Sanholt		  MGA_TEXORG3, tex->texorg3);
22495584Sanholt
225145132Sanholt	DMA_BLOCK(MGA_TEXORG4, tex->texorg4,
226145132Sanholt		  MGA_TEXWIDTH, tex->texwidth,
227145132Sanholt		  MGA_TEXHEIGHT, tex->texheight,
228145132Sanholt		  MGA_WR49, 0x00000000);
22995584Sanholt
230145132Sanholt	DMA_BLOCK(MGA_WR57, 0x00000000,
231145132Sanholt		  MGA_WR53, 0x00000000,
232145132Sanholt		  MGA_WR61, 0x00000000,
233145132Sanholt		  MGA_WR52, tex->texwidth | MGA_G400_WR_MAGIC);
23495584Sanholt
235145132Sanholt	DMA_BLOCK(MGA_WR60, tex->texheight | MGA_G400_WR_MAGIC,
236145132Sanholt		  MGA_TEXTRANS, 0x0000ffff,
237145132Sanholt		  MGA_TEXTRANSHIGH, 0x0000ffff,
238145132Sanholt		  MGA_TEXCTL2, tex->texctl2 | MGA_G400_TC2_MAGIC);
23995584Sanholt
24095584Sanholt	ADVANCE_DMA();
24195584Sanholt}
24295584Sanholt
243145132Sanholtstatic __inline__ void mga_g200_emit_pipe(drm_mga_private_t * dev_priv)
24495584Sanholt{
24595584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
24695584Sanholt	unsigned int pipe = sarea_priv->warp_pipe;
24795584Sanholt	DMA_LOCALS;
24895584Sanholt
249145132Sanholt	BEGIN_DMA(3);
25095584Sanholt
251145132Sanholt	DMA_BLOCK(MGA_WIADDR, MGA_WMODE_SUSPEND,
252145132Sanholt		  MGA_WVRTXSZ, 0x00000007,
253145132Sanholt		  MGA_WFLAG, 0x00000000,
254145132Sanholt		  MGA_WR24, 0x00000000);
25595584Sanholt
256145132Sanholt	DMA_BLOCK(MGA_WR25, 0x00000100,
257145132Sanholt		  MGA_WR34, 0x00000000,
258145132Sanholt		  MGA_WR42, 0x0000ffff,
259145132Sanholt		  MGA_WR60, 0x0000ffff);
26095584Sanholt
261330446Seadler	/* Padding required due to hardware bug.
26295584Sanholt	 */
263145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
264145132Sanholt		  MGA_DMAPAD, 0xffffffff,
265145132Sanholt		  MGA_DMAPAD, 0xffffffff,
266145132Sanholt		  MGA_WIADDR, (dev_priv->warp_pipe_phys[pipe] |
267152909Sanholt			       MGA_WMODE_START | dev_priv->wagp_enable));
26895584Sanholt
26995584Sanholt	ADVANCE_DMA();
27095584Sanholt}
27195584Sanholt
272145132Sanholtstatic __inline__ void mga_g400_emit_pipe(drm_mga_private_t * dev_priv)
27395584Sanholt{
27495584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
27595584Sanholt	unsigned int pipe = sarea_priv->warp_pipe;
27695584Sanholt	DMA_LOCALS;
27795584Sanholt
278182080Srnoland/*	printk("mga_g400_emit_pipe %x\n", pipe); */
279112015Sanholt
280145132Sanholt	BEGIN_DMA(10);
28195584Sanholt
282145132Sanholt	DMA_BLOCK(MGA_WIADDR2, MGA_WMODE_SUSPEND,
283145132Sanholt		  MGA_DMAPAD, 0x00000000,
284145132Sanholt		  MGA_DMAPAD, 0x00000000,
285145132Sanholt		  MGA_DMAPAD, 0x00000000);
28695584Sanholt
287145132Sanholt	if (pipe & MGA_T2) {
288145132Sanholt		DMA_BLOCK(MGA_WVRTXSZ, 0x00001e09,
289145132Sanholt			  MGA_DMAPAD, 0x00000000,
290145132Sanholt			  MGA_DMAPAD, 0x00000000,
291145132Sanholt			  MGA_DMAPAD, 0x00000000);
29295584Sanholt
293145132Sanholt		DMA_BLOCK(MGA_WACCEPTSEQ, 0x00000000,
294145132Sanholt			  MGA_WACCEPTSEQ, 0x00000000,
295145132Sanholt			  MGA_WACCEPTSEQ, 0x00000000,
296145132Sanholt			  MGA_WACCEPTSEQ, 0x1e000000);
29795584Sanholt	} else {
298145132Sanholt		if (dev_priv->warp_pipe & MGA_T2) {
29995584Sanholt			/* Flush the WARP pipe */
300145132Sanholt			DMA_BLOCK(MGA_YDST, 0x00000000,
301145132Sanholt				  MGA_FXLEFT, 0x00000000,
302145132Sanholt				  MGA_FXRIGHT, 0x00000001,
303145132Sanholt				  MGA_DWGCTL, MGA_DWGCTL_FLUSH);
30495584Sanholt
305145132Sanholt			DMA_BLOCK(MGA_LEN + MGA_EXEC, 0x00000001,
306145132Sanholt				  MGA_DWGSYNC, 0x00007000,
307145132Sanholt				  MGA_TEXCTL2, MGA_G400_TC2_MAGIC,
308145132Sanholt				  MGA_LEN + MGA_EXEC, 0x00000000);
30995584Sanholt
310145132Sanholt			DMA_BLOCK(MGA_TEXCTL2, (MGA_DUALTEX |
311145132Sanholt						MGA_G400_TC2_MAGIC),
312145132Sanholt				  MGA_LEN + MGA_EXEC, 0x00000000,
313145132Sanholt				  MGA_TEXCTL2, MGA_G400_TC2_MAGIC,
314145132Sanholt				  MGA_DMAPAD, 0x00000000);
31595584Sanholt		}
31695584Sanholt
317145132Sanholt		DMA_BLOCK(MGA_WVRTXSZ, 0x00001807,
318145132Sanholt			  MGA_DMAPAD, 0x00000000,
319145132Sanholt			  MGA_DMAPAD, 0x00000000,
320145132Sanholt			  MGA_DMAPAD, 0x00000000);
32195584Sanholt
322145132Sanholt		DMA_BLOCK(MGA_WACCEPTSEQ, 0x00000000,
323145132Sanholt			  MGA_WACCEPTSEQ, 0x00000000,
324145132Sanholt			  MGA_WACCEPTSEQ, 0x00000000,
325145132Sanholt			  MGA_WACCEPTSEQ, 0x18000000);
32695584Sanholt	}
32795584Sanholt
328145132Sanholt	DMA_BLOCK(MGA_WFLAG, 0x00000000,
329145132Sanholt		  MGA_WFLAG1, 0x00000000,
330145132Sanholt		  MGA_WR56, MGA_G400_WR56_MAGIC,
331145132Sanholt		  MGA_DMAPAD, 0x00000000);
33295584Sanholt
333145132Sanholt	DMA_BLOCK(MGA_WR49, 0x00000000,	/* tex0              */
334145132Sanholt		  MGA_WR57, 0x00000000,	/* tex0              */
335145132Sanholt		  MGA_WR53, 0x00000000,	/* tex1              */
336145132Sanholt		  MGA_WR61, 0x00000000);	/* tex1              */
33795584Sanholt
338145132Sanholt	DMA_BLOCK(MGA_WR54, MGA_G400_WR_MAGIC,	/* tex0 width        */
339145132Sanholt		  MGA_WR62, MGA_G400_WR_MAGIC,	/* tex0 height       */
340145132Sanholt		  MGA_WR52, MGA_G400_WR_MAGIC,	/* tex1 width        */
341145132Sanholt		  MGA_WR60, MGA_G400_WR_MAGIC);	/* tex1 height       */
34295584Sanholt
343330446Seadler	/* Padding required due to hardware bug */
344145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
345145132Sanholt		  MGA_DMAPAD, 0xffffffff,
346145132Sanholt		  MGA_DMAPAD, 0xffffffff,
347145132Sanholt		  MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] |
348152909Sanholt				MGA_WMODE_START | dev_priv->wagp_enable));
34995584Sanholt
35095584Sanholt	ADVANCE_DMA();
35195584Sanholt}
35295584Sanholt
353145132Sanholtstatic void mga_g200_emit_state(drm_mga_private_t * dev_priv)
35495584Sanholt{
35595584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
35695584Sanholt	unsigned int dirty = sarea_priv->dirty;
35795584Sanholt
358145132Sanholt	if (sarea_priv->warp_pipe != dev_priv->warp_pipe) {
359145132Sanholt		mga_g200_emit_pipe(dev_priv);
36095584Sanholt		dev_priv->warp_pipe = sarea_priv->warp_pipe;
36195584Sanholt	}
36295584Sanholt
363145132Sanholt	if (dirty & MGA_UPLOAD_CONTEXT) {
364145132Sanholt		mga_g200_emit_context(dev_priv);
36595584Sanholt		sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT;
36695584Sanholt	}
36795584Sanholt
368145132Sanholt	if (dirty & MGA_UPLOAD_TEX0) {
369145132Sanholt		mga_g200_emit_tex0(dev_priv);
37095584Sanholt		sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
37195584Sanholt	}
37295584Sanholt}
37395584Sanholt
374145132Sanholtstatic void mga_g400_emit_state(drm_mga_private_t * dev_priv)
37595584Sanholt{
37695584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
37795584Sanholt	unsigned int dirty = sarea_priv->dirty;
37895584Sanholt	int multitex = sarea_priv->warp_pipe & MGA_T2;
37995584Sanholt
380145132Sanholt	if (sarea_priv->warp_pipe != dev_priv->warp_pipe) {
381145132Sanholt		mga_g400_emit_pipe(dev_priv);
38295584Sanholt		dev_priv->warp_pipe = sarea_priv->warp_pipe;
38395584Sanholt	}
38495584Sanholt
385145132Sanholt	if (dirty & MGA_UPLOAD_CONTEXT) {
386145132Sanholt		mga_g400_emit_context(dev_priv);
38795584Sanholt		sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT;
38895584Sanholt	}
38995584Sanholt
390145132Sanholt	if (dirty & MGA_UPLOAD_TEX0) {
391145132Sanholt		mga_g400_emit_tex0(dev_priv);
39295584Sanholt		sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
39395584Sanholt	}
39495584Sanholt
395145132Sanholt	if ((dirty & MGA_UPLOAD_TEX1) && multitex) {
396145132Sanholt		mga_g400_emit_tex1(dev_priv);
39795584Sanholt		sarea_priv->dirty &= ~MGA_UPLOAD_TEX1;
39895584Sanholt	}
39995584Sanholt}
40095584Sanholt
40195584Sanholt/* ================================================================
40295584Sanholt * SAREA state verification
40395584Sanholt */
40495584Sanholt
40595584Sanholt/* Disallow all write destinations except the front and backbuffer.
40695584Sanholt */
407145132Sanholtstatic int mga_verify_context(drm_mga_private_t * dev_priv)
40895584Sanholt{
40995584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
41095584Sanholt	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
41195584Sanholt
412145132Sanholt	if (ctx->dstorg != dev_priv->front_offset &&
413145132Sanholt	    ctx->dstorg != dev_priv->back_offset) {
414145132Sanholt		DRM_ERROR("*** bad DSTORG: %x (front %x, back %x)\n\n",
415145132Sanholt			  ctx->dstorg, dev_priv->front_offset,
416145132Sanholt			  dev_priv->back_offset);
41795584Sanholt		ctx->dstorg = 0;
418182080Srnoland		return -EINVAL;
41995584Sanholt	}
42095584Sanholt
42195584Sanholt	return 0;
42295584Sanholt}
42395584Sanholt
42495584Sanholt/* Disallow texture reads from PCI space.
42595584Sanholt */
426145132Sanholtstatic int mga_verify_tex(drm_mga_private_t * dev_priv, int unit)
42795584Sanholt{
42895584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
42995584Sanholt	drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[unit];
43095584Sanholt	unsigned int org;
43195584Sanholt
43295584Sanholt	org = tex->texorg & (MGA_TEXORGMAP_MASK | MGA_TEXORGACC_MASK);
43395584Sanholt
434145132Sanholt	if (org == (MGA_TEXORGMAP_SYSMEM | MGA_TEXORGACC_PCI)) {
435145132Sanholt		DRM_ERROR("*** bad TEXORG: 0x%x, unit %d\n", tex->texorg, unit);
43695584Sanholt		tex->texorg = 0;
437182080Srnoland		return -EINVAL;
43895584Sanholt	}
43995584Sanholt
44095584Sanholt	return 0;
44195584Sanholt}
44295584Sanholt
443145132Sanholtstatic int mga_verify_state(drm_mga_private_t * dev_priv)
44495584Sanholt{
44595584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
44695584Sanholt	unsigned int dirty = sarea_priv->dirty;
44795584Sanholt	int ret = 0;
44895584Sanholt
449145132Sanholt	if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
45095584Sanholt		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
45195584Sanholt
452145132Sanholt	if (dirty & MGA_UPLOAD_CONTEXT)
453145132Sanholt		ret |= mga_verify_context(dev_priv);
45495584Sanholt
455145132Sanholt	if (dirty & MGA_UPLOAD_TEX0)
456145132Sanholt		ret |= mga_verify_tex(dev_priv, 0);
45795584Sanholt
458152909Sanholt	if (dev_priv->chipset >= MGA_CARD_TYPE_G400) {
459145132Sanholt		if (dirty & MGA_UPLOAD_TEX1)
460145132Sanholt			ret |= mga_verify_tex(dev_priv, 1);
46195584Sanholt
462145132Sanholt		if (dirty & MGA_UPLOAD_PIPE)
463145132Sanholt			ret |= (sarea_priv->warp_pipe > MGA_MAX_G400_PIPES);
46495584Sanholt	} else {
465145132Sanholt		if (dirty & MGA_UPLOAD_PIPE)
466145132Sanholt			ret |= (sarea_priv->warp_pipe > MGA_MAX_G200_PIPES);
46795584Sanholt	}
46895584Sanholt
469145132Sanholt	return (ret == 0);
47095584Sanholt}
47195584Sanholt
472145132Sanholtstatic int mga_verify_iload(drm_mga_private_t * dev_priv,
473145132Sanholt			    unsigned int dstorg, unsigned int length)
47495584Sanholt{
475145132Sanholt	if (dstorg < dev_priv->texture_offset ||
476145132Sanholt	    dstorg + length > (dev_priv->texture_offset +
477145132Sanholt			       dev_priv->texture_size)) {
478145132Sanholt		DRM_ERROR("*** bad iload DSTORG: 0x%x\n", dstorg);
479182080Srnoland		return -EINVAL;
48095584Sanholt	}
48195584Sanholt
482145132Sanholt	if (length & MGA_ILOAD_MASK) {
483145132Sanholt		DRM_ERROR("*** bad iload length: 0x%x\n",
484145132Sanholt			  length & MGA_ILOAD_MASK);
485182080Srnoland		return -EINVAL;
48695584Sanholt	}
48795584Sanholt
48895584Sanholt	return 0;
48995584Sanholt}
49095584Sanholt
491145132Sanholtstatic int mga_verify_blit(drm_mga_private_t * dev_priv,
492145132Sanholt			   unsigned int srcorg, unsigned int dstorg)
49395584Sanholt{
494145132Sanholt	if ((srcorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) ||
495145132Sanholt	    (dstorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM)) {
496145132Sanholt		DRM_ERROR("*** bad blit: src=0x%x dst=0x%x\n", srcorg, dstorg);
497182080Srnoland		return -EINVAL;
49895584Sanholt	}
49995584Sanholt	return 0;
50095584Sanholt}
50195584Sanholt
50295584Sanholt/* ================================================================
50395584Sanholt *
50495584Sanholt */
50595584Sanholt
506182080Srnolandstatic void mga_dma_dispatch_clear(struct drm_device * dev, drm_mga_clear_t * clear)
50795584Sanholt{
50895584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
50995584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
51095584Sanholt	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
511182080Srnoland	struct drm_clip_rect *pbox = sarea_priv->boxes;
51295584Sanholt	int nbox = sarea_priv->nbox;
51395584Sanholt	int i;
51495584Sanholt	DMA_LOCALS;
515145132Sanholt	DRM_DEBUG("\n");
51695584Sanholt
517145132Sanholt	BEGIN_DMA(1);
51895584Sanholt
519145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
520145132Sanholt		  MGA_DMAPAD, 0x00000000,
521145132Sanholt		  MGA_DWGSYNC, 0x00007100,
522145132Sanholt		  MGA_DWGSYNC, 0x00007000);
52395584Sanholt
52495584Sanholt	ADVANCE_DMA();
52595584Sanholt
526145132Sanholt	for (i = 0; i < nbox; i++) {
527182080Srnoland		struct drm_clip_rect *box = &pbox[i];
52895584Sanholt		u32 height = box->y2 - box->y1;
52995584Sanholt
530145132Sanholt		DRM_DEBUG("   from=%d,%d to=%d,%d\n",
531145132Sanholt			  box->x1, box->y1, box->x2, box->y2);
53295584Sanholt
533145132Sanholt		if (clear->flags & MGA_FRONT) {
534145132Sanholt			BEGIN_DMA(2);
53595584Sanholt
536145132Sanholt			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
537145132Sanholt				  MGA_PLNWT, clear->color_mask,
538145132Sanholt				  MGA_YDSTLEN, (box->y1 << 16) | height,
539145132Sanholt				  MGA_FXBNDRY, (box->x2 << 16) | box->x1);
54095584Sanholt
541145132Sanholt			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
542145132Sanholt				  MGA_FCOL, clear->clear_color,
543145132Sanholt				  MGA_DSTORG, dev_priv->front_offset,
544145132Sanholt				  MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd);
54595584Sanholt
54695584Sanholt			ADVANCE_DMA();
54795584Sanholt		}
54895584Sanholt
549145132Sanholt		if (clear->flags & MGA_BACK) {
550145132Sanholt			BEGIN_DMA(2);
55195584Sanholt
552145132Sanholt			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
553145132Sanholt				  MGA_PLNWT, clear->color_mask,
554145132Sanholt				  MGA_YDSTLEN, (box->y1 << 16) | height,
555145132Sanholt				  MGA_FXBNDRY, (box->x2 << 16) | box->x1);
55695584Sanholt
557145132Sanholt			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
558145132Sanholt				  MGA_FCOL, clear->clear_color,
559145132Sanholt				  MGA_DSTORG, dev_priv->back_offset,
560145132Sanholt				  MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd);
56195584Sanholt
56295584Sanholt			ADVANCE_DMA();
56395584Sanholt		}
56495584Sanholt
565145132Sanholt		if (clear->flags & MGA_DEPTH) {
566145132Sanholt			BEGIN_DMA(2);
56795584Sanholt
568145132Sanholt			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
569145132Sanholt				  MGA_PLNWT, clear->depth_mask,
570145132Sanholt				  MGA_YDSTLEN, (box->y1 << 16) | height,
571145132Sanholt				  MGA_FXBNDRY, (box->x2 << 16) | box->x1);
57295584Sanholt
573145132Sanholt			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
574145132Sanholt				  MGA_FCOL, clear->clear_depth,
575145132Sanholt				  MGA_DSTORG, dev_priv->depth_offset,
576145132Sanholt				  MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd);
57795584Sanholt
57895584Sanholt			ADVANCE_DMA();
57995584Sanholt		}
58095584Sanholt
58195584Sanholt	}
58295584Sanholt
583145132Sanholt	BEGIN_DMA(1);
58495584Sanholt
58595584Sanholt	/* Force reset of DWGCTL */
586145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
587145132Sanholt		  MGA_DMAPAD, 0x00000000,
588145132Sanholt		  MGA_PLNWT, ctx->plnwt,
589145132Sanholt		  MGA_DWGCTL, ctx->dwgctl);
59095584Sanholt
59195584Sanholt	ADVANCE_DMA();
59295584Sanholt
59395584Sanholt	FLUSH_DMA();
59495584Sanholt}
59595584Sanholt
596182080Srnolandstatic void mga_dma_dispatch_swap(struct drm_device * dev)
59795584Sanholt{
59895584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
59995584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
60095584Sanholt	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
601182080Srnoland	struct drm_clip_rect *pbox = sarea_priv->boxes;
60295584Sanholt	int nbox = sarea_priv->nbox;
60395584Sanholt	int i;
60495584Sanholt	DMA_LOCALS;
605145132Sanholt	DRM_DEBUG("\n");
60695584Sanholt
60795584Sanholt	sarea_priv->last_frame.head = dev_priv->prim.tail;
60895584Sanholt	sarea_priv->last_frame.wrap = dev_priv->prim.last_wrap;
60995584Sanholt
610145132Sanholt	BEGIN_DMA(4 + nbox);
61195584Sanholt
612145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
613145132Sanholt		  MGA_DMAPAD, 0x00000000,
614145132Sanholt		  MGA_DWGSYNC, 0x00007100,
615145132Sanholt		  MGA_DWGSYNC, 0x00007000);
61695584Sanholt
617145132Sanholt	DMA_BLOCK(MGA_DSTORG, dev_priv->front_offset,
618145132Sanholt		  MGA_MACCESS, dev_priv->maccess,
619145132Sanholt		  MGA_SRCORG, dev_priv->back_offset,
620145132Sanholt		  MGA_AR5, dev_priv->front_pitch);
62195584Sanholt
622145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
623145132Sanholt		  MGA_DMAPAD, 0x00000000,
624145132Sanholt		  MGA_PLNWT, 0xffffffff,
625145132Sanholt		  MGA_DWGCTL, MGA_DWGCTL_COPY);
62695584Sanholt
627145132Sanholt	for (i = 0; i < nbox; i++) {
628182080Srnoland		struct drm_clip_rect *box = &pbox[i];
62995584Sanholt		u32 height = box->y2 - box->y1;
63095584Sanholt		u32 start = box->y1 * dev_priv->front_pitch;
63195584Sanholt
632145132Sanholt		DRM_DEBUG("   from=%d,%d to=%d,%d\n",
633145132Sanholt			  box->x1, box->y1, box->x2, box->y2);
63495584Sanholt
635145132Sanholt		DMA_BLOCK(MGA_AR0, start + box->x2 - 1,
636145132Sanholt			  MGA_AR3, start + box->x1,
637145132Sanholt			  MGA_FXBNDRY, ((box->x2 - 1) << 16) | box->x1,
638145132Sanholt			  MGA_YDSTLEN + MGA_EXEC, (box->y1 << 16) | height);
63995584Sanholt	}
64095584Sanholt
641145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
642145132Sanholt		  MGA_PLNWT, ctx->plnwt,
643145132Sanholt		  MGA_SRCORG, dev_priv->front_offset,
644145132Sanholt		  MGA_DWGCTL, ctx->dwgctl);
64595584Sanholt
64695584Sanholt	ADVANCE_DMA();
64795584Sanholt
64895584Sanholt	FLUSH_DMA();
64995584Sanholt
650182080Srnoland	DRM_DEBUG("... done.\n");
65195584Sanholt}
65295584Sanholt
653182080Srnolandstatic void mga_dma_dispatch_vertex(struct drm_device * dev, struct drm_buf * buf)
65495584Sanholt{
65595584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
65695584Sanholt	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
65795584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
65895584Sanholt	u32 address = (u32) buf->bus_address;
65995584Sanholt	u32 length = (u32) buf->used;
66095584Sanholt	int i = 0;
66195584Sanholt	DMA_LOCALS;
662182080Srnoland	DRM_DEBUG("buf=%d used=%d\n", buf->idx, buf->used);
66395584Sanholt
664145132Sanholt	if (buf->used) {
66595584Sanholt		buf_priv->dispatched = 1;
66695584Sanholt
667145132Sanholt		MGA_EMIT_STATE(dev_priv, sarea_priv->dirty);
66895584Sanholt
66995584Sanholt		do {
670145132Sanholt			if (i < sarea_priv->nbox) {
671145132Sanholt				mga_emit_clip_rect(dev_priv,
672145132Sanholt						   &sarea_priv->boxes[i]);
67395584Sanholt			}
67495584Sanholt
675145132Sanholt			BEGIN_DMA(1);
67695584Sanholt
677145132Sanholt			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
678145132Sanholt				  MGA_DMAPAD, 0x00000000,
679145132Sanholt				  MGA_SECADDRESS, (address |
680145132Sanholt						   MGA_DMA_VERTEX),
681145132Sanholt				  MGA_SECEND, ((address + length) |
682152909Sanholt					       dev_priv->dma_access));
68395584Sanholt
68495584Sanholt			ADVANCE_DMA();
685145132Sanholt		} while (++i < sarea_priv->nbox);
68695584Sanholt	}
68795584Sanholt
688145132Sanholt	if (buf_priv->discard) {
689145132Sanholt		AGE_BUFFER(buf_priv);
69095584Sanholt		buf->pending = 0;
69195584Sanholt		buf->used = 0;
69295584Sanholt		buf_priv->dispatched = 0;
69395584Sanholt
694145132Sanholt		mga_freelist_put(dev, buf);
69595584Sanholt	}
69695584Sanholt
69795584Sanholt	FLUSH_DMA();
69895584Sanholt}
69995584Sanholt
700182080Srnolandstatic void mga_dma_dispatch_indices(struct drm_device * dev, struct drm_buf * buf,
701145132Sanholt				     unsigned int start, unsigned int end)
70295584Sanholt{
70395584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
70495584Sanholt	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
70595584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
70695584Sanholt	u32 address = (u32) buf->bus_address;
70795584Sanholt	int i = 0;
70895584Sanholt	DMA_LOCALS;
709182080Srnoland	DRM_DEBUG("buf=%d start=%d end=%d\n", buf->idx, start, end);
71095584Sanholt
711145132Sanholt	if (start != end) {
71295584Sanholt		buf_priv->dispatched = 1;
71395584Sanholt
714145132Sanholt		MGA_EMIT_STATE(dev_priv, sarea_priv->dirty);
71595584Sanholt
71695584Sanholt		do {
717145132Sanholt			if (i < sarea_priv->nbox) {
718145132Sanholt				mga_emit_clip_rect(dev_priv,
719145132Sanholt						   &sarea_priv->boxes[i]);
72095584Sanholt			}
72195584Sanholt
722145132Sanholt			BEGIN_DMA(1);
72395584Sanholt
724145132Sanholt			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
725145132Sanholt				  MGA_DMAPAD, 0x00000000,
726145132Sanholt				  MGA_SETUPADDRESS, address + start,
727145132Sanholt				  MGA_SETUPEND, ((address + end) |
728152909Sanholt						 dev_priv->dma_access));
72995584Sanholt
73095584Sanholt			ADVANCE_DMA();
731145132Sanholt		} while (++i < sarea_priv->nbox);
73295584Sanholt	}
73395584Sanholt
734145132Sanholt	if (buf_priv->discard) {
735145132Sanholt		AGE_BUFFER(buf_priv);
73695584Sanholt		buf->pending = 0;
73795584Sanholt		buf->used = 0;
73895584Sanholt		buf_priv->dispatched = 0;
73995584Sanholt
740145132Sanholt		mga_freelist_put(dev, buf);
74195584Sanholt	}
74295584Sanholt
74395584Sanholt	FLUSH_DMA();
74495584Sanholt}
74595584Sanholt
74695584Sanholt/* This copies a 64 byte aligned agp region to the frambuffer with a
74795584Sanholt * standard blit, the ioctl needs to do checking.
74895584Sanholt */
749182080Srnolandstatic void mga_dma_dispatch_iload(struct drm_device * dev, struct drm_buf * buf,
750145132Sanholt				   unsigned int dstorg, unsigned int length)
75195584Sanholt{
75295584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
75395584Sanholt	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
75495584Sanholt	drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state;
755152909Sanholt	u32 srcorg = buf->bus_address | dev_priv->dma_access | MGA_SRCMAP_SYSMEM;
75695584Sanholt	u32 y2;
75795584Sanholt	DMA_LOCALS;
758145132Sanholt	DRM_DEBUG("buf=%d used=%d\n", buf->idx, buf->used);
75995584Sanholt
76095584Sanholt	y2 = length / 64;
76195584Sanholt
762145132Sanholt	BEGIN_DMA(5);
76395584Sanholt
764145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
765145132Sanholt		  MGA_DMAPAD, 0x00000000,
766145132Sanholt		  MGA_DWGSYNC, 0x00007100,
767145132Sanholt		  MGA_DWGSYNC, 0x00007000);
76895584Sanholt
769145132Sanholt	DMA_BLOCK(MGA_DSTORG, dstorg,
770145132Sanholt		  MGA_MACCESS, 0x00000000,
771145132Sanholt		  MGA_SRCORG, srcorg,
772145132Sanholt		  MGA_AR5, 64);
77395584Sanholt
774145132Sanholt	DMA_BLOCK(MGA_PITCH, 64,
775145132Sanholt		  MGA_PLNWT, 0xffffffff,
776145132Sanholt		  MGA_DMAPAD, 0x00000000,
777145132Sanholt		  MGA_DWGCTL, MGA_DWGCTL_COPY);
77895584Sanholt
779145132Sanholt	DMA_BLOCK(MGA_AR0, 63,
780145132Sanholt		  MGA_AR3, 0,
781145132Sanholt		  MGA_FXBNDRY, (63 << 16) | 0,
782145132Sanholt		  MGA_YDSTLEN + MGA_EXEC, y2);
78395584Sanholt
784145132Sanholt	DMA_BLOCK(MGA_PLNWT, ctx->plnwt,
785145132Sanholt		  MGA_SRCORG, dev_priv->front_offset,
786145132Sanholt		  MGA_PITCH, dev_priv->front_pitch,
787145132Sanholt		  MGA_DWGSYNC, 0x00007000);
78895584Sanholt
78995584Sanholt	ADVANCE_DMA();
79095584Sanholt
791145132Sanholt	AGE_BUFFER(buf_priv);
79295584Sanholt
79395584Sanholt	buf->pending = 0;
79495584Sanholt	buf->used = 0;
79595584Sanholt	buf_priv->dispatched = 0;
79695584Sanholt
797145132Sanholt	mga_freelist_put(dev, buf);
79895584Sanholt
79995584Sanholt	FLUSH_DMA();
80095584Sanholt}
80195584Sanholt
802182080Srnolandstatic void mga_dma_dispatch_blit(struct drm_device * dev, drm_mga_blit_t * blit)
80395584Sanholt{
80495584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
80595584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
80695584Sanholt	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
807182080Srnoland	struct drm_clip_rect *pbox = sarea_priv->boxes;
80895584Sanholt	int nbox = sarea_priv->nbox;
80995584Sanholt	u32 scandir = 0, i;
81095584Sanholt	DMA_LOCALS;
811145132Sanholt	DRM_DEBUG("\n");
81295584Sanholt
813145132Sanholt	BEGIN_DMA(4 + nbox);
81495584Sanholt
815145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
816145132Sanholt		  MGA_DMAPAD, 0x00000000,
817145132Sanholt		  MGA_DWGSYNC, 0x00007100,
818145132Sanholt		  MGA_DWGSYNC, 0x00007000);
81995584Sanholt
820145132Sanholt	DMA_BLOCK(MGA_DWGCTL, MGA_DWGCTL_COPY,
821145132Sanholt		  MGA_PLNWT, blit->planemask,
822145132Sanholt		  MGA_SRCORG, blit->srcorg,
823145132Sanholt		  MGA_DSTORG, blit->dstorg);
82495584Sanholt
825145132Sanholt	DMA_BLOCK(MGA_SGN, scandir,
826145132Sanholt		  MGA_MACCESS, dev_priv->maccess,
827145132Sanholt		  MGA_AR5, blit->ydir * blit->src_pitch,
828145132Sanholt		  MGA_PITCH, blit->dst_pitch);
82995584Sanholt
830145132Sanholt	for (i = 0; i < nbox; i++) {
83195584Sanholt		int srcx = pbox[i].x1 + blit->delta_sx;
83295584Sanholt		int srcy = pbox[i].y1 + blit->delta_sy;
83395584Sanholt		int dstx = pbox[i].x1 + blit->delta_dx;
83495584Sanholt		int dsty = pbox[i].y1 + blit->delta_dy;
83595584Sanholt		int h = pbox[i].y2 - pbox[i].y1;
83695584Sanholt		int w = pbox[i].x2 - pbox[i].x1 - 1;
83795584Sanholt		int start;
83895584Sanholt
839145132Sanholt		if (blit->ydir == -1) {
84095584Sanholt			srcy = blit->height - srcy - 1;
84195584Sanholt		}
84295584Sanholt
84395584Sanholt		start = srcy * blit->src_pitch + srcx;
84495584Sanholt
845145132Sanholt		DMA_BLOCK(MGA_AR0, start + w,
846145132Sanholt			  MGA_AR3, start,
847145132Sanholt			  MGA_FXBNDRY, ((dstx + w) << 16) | (dstx & 0xffff),
848145132Sanholt			  MGA_YDSTLEN + MGA_EXEC, (dsty << 16) | h);
84995584Sanholt	}
85095584Sanholt
85195584Sanholt	/* Do something to flush AGP?
85295584Sanholt	 */
85395584Sanholt
85495584Sanholt	/* Force reset of DWGCTL */
855145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
856145132Sanholt		  MGA_PLNWT, ctx->plnwt,
857145132Sanholt		  MGA_PITCH, dev_priv->front_pitch,
858145132Sanholt		  MGA_DWGCTL, ctx->dwgctl);
85995584Sanholt
86095584Sanholt	ADVANCE_DMA();
86195584Sanholt}
86295584Sanholt
86395584Sanholt/* ================================================================
86495584Sanholt *
86595584Sanholt */
86695584Sanholt
867182080Srnolandstatic int mga_dma_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
86895584Sanholt{
86995584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
87095584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
871182080Srnoland	drm_mga_clear_t *clear = data;
87295584Sanholt
873182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
87495584Sanholt
875145132Sanholt	if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
87695584Sanholt		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
87795584Sanholt
878145132Sanholt	WRAP_TEST_WITH_RETURN(dev_priv);
87995584Sanholt
880182080Srnoland	mga_dma_dispatch_clear(dev, clear);
88195584Sanholt
88295584Sanholt	/* Make sure we restore the 3D state next time.
88395584Sanholt	 */
88495584Sanholt	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
88595584Sanholt
88695584Sanholt	return 0;
88795584Sanholt}
88895584Sanholt
889182080Srnolandstatic int mga_dma_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
89095584Sanholt{
89195584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
89295584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
89395584Sanholt
894182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
89595584Sanholt
896145132Sanholt	if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
89795584Sanholt		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
89895584Sanholt
899145132Sanholt	WRAP_TEST_WITH_RETURN(dev_priv);
90095584Sanholt
901145132Sanholt	mga_dma_dispatch_swap(dev);
90295584Sanholt
90395584Sanholt	/* Make sure we restore the 3D state next time.
90495584Sanholt	 */
90595584Sanholt	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
90695584Sanholt
90795584Sanholt	return 0;
90895584Sanholt}
90995584Sanholt
910182080Srnolandstatic int mga_dma_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
91195584Sanholt{
91295584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
913182080Srnoland	struct drm_device_dma *dma = dev->dma;
914182080Srnoland	struct drm_buf *buf;
91595584Sanholt	drm_mga_buf_priv_t *buf_priv;
916182080Srnoland	drm_mga_vertex_t *vertex = data;
91795584Sanholt
918182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
91995584Sanholt
920182080Srnoland	if (vertex->idx < 0 || vertex->idx > dma->buf_count)
921182080Srnoland		return -EINVAL;
922182080Srnoland	buf = dma->buflist[vertex->idx];
92395584Sanholt	buf_priv = buf->dev_private;
92495584Sanholt
925182080Srnoland	buf->used = vertex->used;
926182080Srnoland	buf_priv->discard = vertex->discard;
92795584Sanholt
928145132Sanholt	if (!mga_verify_state(dev_priv)) {
929182080Srnoland		if (vertex->discard) {
930145132Sanholt			if (buf_priv->dispatched == 1)
931145132Sanholt				AGE_BUFFER(buf_priv);
93295584Sanholt			buf_priv->dispatched = 0;
933145132Sanholt			mga_freelist_put(dev, buf);
93495584Sanholt		}
935182080Srnoland		return -EINVAL;
93695584Sanholt	}
93795584Sanholt
938145132Sanholt	WRAP_TEST_WITH_RETURN(dev_priv);
93995584Sanholt
940145132Sanholt	mga_dma_dispatch_vertex(dev, buf);
94195584Sanholt
94295584Sanholt	return 0;
94395584Sanholt}
94495584Sanholt
945182080Srnolandstatic int mga_dma_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
94695584Sanholt{
94795584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
948182080Srnoland	struct drm_device_dma *dma = dev->dma;
949182080Srnoland	struct drm_buf *buf;
95095584Sanholt	drm_mga_buf_priv_t *buf_priv;
951182080Srnoland	drm_mga_indices_t *indices = data;
95295584Sanholt
953182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
95495584Sanholt
955182080Srnoland	if (indices->idx < 0 || indices->idx > dma->buf_count)
956182080Srnoland		return -EINVAL;
95795584Sanholt
958182080Srnoland	buf = dma->buflist[indices->idx];
95995584Sanholt	buf_priv = buf->dev_private;
96095584Sanholt
961182080Srnoland	buf_priv->discard = indices->discard;
96295584Sanholt
963145132Sanholt	if (!mga_verify_state(dev_priv)) {
964182080Srnoland		if (indices->discard) {
965145132Sanholt			if (buf_priv->dispatched == 1)
966145132Sanholt				AGE_BUFFER(buf_priv);
96795584Sanholt			buf_priv->dispatched = 0;
968145132Sanholt			mga_freelist_put(dev, buf);
96995584Sanholt		}
970182080Srnoland		return -EINVAL;
97195584Sanholt	}
97295584Sanholt
973145132Sanholt	WRAP_TEST_WITH_RETURN(dev_priv);
97495584Sanholt
975182080Srnoland	mga_dma_dispatch_indices(dev, buf, indices->start, indices->end);
97695584Sanholt
97795584Sanholt	return 0;
97895584Sanholt}
97995584Sanholt
980182080Srnolandstatic int mga_dma_iload(struct drm_device *dev, void *data, struct drm_file *file_priv)
98195584Sanholt{
982182080Srnoland	struct drm_device_dma *dma = dev->dma;
98395584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
984182080Srnoland	struct drm_buf *buf;
98595584Sanholt	drm_mga_buf_priv_t *buf_priv;
986182080Srnoland	drm_mga_iload_t *iload = data;
987145132Sanholt	DRM_DEBUG("\n");
98895584Sanholt
989182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
99095584Sanholt
99195584Sanholt#if 0
992145132Sanholt	if (mga_do_wait_for_idle(dev_priv) < 0) {
993145132Sanholt		if (MGA_DMA_DEBUG)
994182080Srnoland			DRM_INFO("-EBUSY\n");
995182080Srnoland		return -EBUSY;
99695584Sanholt	}
99795584Sanholt#endif
998182080Srnoland	if (iload->idx < 0 || iload->idx > dma->buf_count)
999182080Srnoland		return -EINVAL;
100095584Sanholt
1001182080Srnoland	buf = dma->buflist[iload->idx];
100295584Sanholt	buf_priv = buf->dev_private;
100395584Sanholt
1004182080Srnoland	if (mga_verify_iload(dev_priv, iload->dstorg, iload->length)) {
1005145132Sanholt		mga_freelist_put(dev, buf);
1006182080Srnoland		return -EINVAL;
100795584Sanholt	}
100895584Sanholt
1009145132Sanholt	WRAP_TEST_WITH_RETURN(dev_priv);
101095584Sanholt
1011182080Srnoland	mga_dma_dispatch_iload(dev, buf, iload->dstorg, iload->length);
101295584Sanholt
101395584Sanholt	/* Make sure we restore the 3D state next time.
101495584Sanholt	 */
101595584Sanholt	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
101695584Sanholt
101795584Sanholt	return 0;
101895584Sanholt}
101995584Sanholt
1020182080Srnolandstatic int mga_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
102195584Sanholt{
102295584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
102395584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
1024182080Srnoland	drm_mga_blit_t *blit = data;
1025145132Sanholt	DRM_DEBUG("\n");
102695584Sanholt
1027182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
102895584Sanholt
1029145132Sanholt	if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
103095584Sanholt		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
103195584Sanholt
1032182080Srnoland	if (mga_verify_blit(dev_priv, blit->srcorg, blit->dstorg))
1033182080Srnoland		return -EINVAL;
103495584Sanholt
1035145132Sanholt	WRAP_TEST_WITH_RETURN(dev_priv);
103695584Sanholt
1037182080Srnoland	mga_dma_dispatch_blit(dev, blit);
103895584Sanholt
103995584Sanholt	/* Make sure we restore the 3D state next time.
104095584Sanholt	 */
104195584Sanholt	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
104295584Sanholt
104395584Sanholt	return 0;
104495584Sanholt}
1045112015Sanholt
1046182080Srnolandstatic int mga_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
1047112015Sanholt{
1048112015Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
1049182080Srnoland	drm_mga_getparam_t *param = data;
1050112015Sanholt	int value;
1051112015Sanholt
1052145132Sanholt	if (!dev_priv) {
1053182080Srnoland		DRM_ERROR("called with no initialization\n");
1054182080Srnoland		return -EINVAL;
1055112015Sanholt	}
1056112015Sanholt
1057145132Sanholt	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
1058112015Sanholt
1059182080Srnoland	switch (param->param) {
1060112015Sanholt	case MGA_PARAM_IRQ_NR:
1061112015Sanholt		value = dev->irq;
1062112015Sanholt		break;
1063152909Sanholt	case MGA_PARAM_CARD_TYPE:
1064152909Sanholt		value = dev_priv->chipset;
1065152909Sanholt		break;
1066112015Sanholt	default:
1067182080Srnoland		return -EINVAL;
1068112015Sanholt	}
1069112015Sanholt
1070182080Srnoland	if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
1071145132Sanholt		DRM_ERROR("copy_to_user\n");
1072182080Srnoland		return -EFAULT;
1073112015Sanholt	}
1074145132Sanholt
1075112015Sanholt	return 0;
1076112015Sanholt}
1077145132Sanholt
1078182080Srnolandstatic int mga_set_fence(struct drm_device *dev, void *data, struct drm_file *file_priv)
1079152909Sanholt{
1080152909Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
1081182080Srnoland	u32 *fence = data;
1082152909Sanholt	DMA_LOCALS;
1083152909Sanholt
1084152909Sanholt	if (!dev_priv) {
1085182080Srnoland		DRM_ERROR("called with no initialization\n");
1086182080Srnoland		return -EINVAL;
1087152909Sanholt	}
1088152909Sanholt
1089152909Sanholt	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
1090152909Sanholt
1091182080Srnoland	/* I would normal do this assignment in the declaration of fence,
1092152909Sanholt	 * but dev_priv may be NULL.
1093152909Sanholt	 */
1094152909Sanholt
1095182080Srnoland	*fence = dev_priv->next_fence_to_post;
1096152909Sanholt	dev_priv->next_fence_to_post++;
1097152909Sanholt
1098152909Sanholt	BEGIN_DMA(1);
1099152909Sanholt	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
1100152909Sanholt		  MGA_DMAPAD, 0x00000000,
1101152909Sanholt		  MGA_DMAPAD, 0x00000000,
1102152909Sanholt		  MGA_SOFTRAP, 0x00000000);
1103152909Sanholt	ADVANCE_DMA();
1104152909Sanholt
1105152909Sanholt	return 0;
1106152909Sanholt}
1107152909Sanholt
1108182080Srnolandstatic int mga_wait_fence(struct drm_device *dev, void *data, struct drm_file *file_priv)
1109152909Sanholt{
1110152909Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
1111182080Srnoland	u32 *fence = data;
1112152909Sanholt
1113152909Sanholt	if (!dev_priv) {
1114182080Srnoland		DRM_ERROR("called with no initialization\n");
1115182080Srnoland		return -EINVAL;
1116152909Sanholt	}
1117152909Sanholt
1118152909Sanholt	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
1119152909Sanholt
1120182080Srnoland	mga_driver_fence_wait(dev, fence);
1121152909Sanholt
1122152909Sanholt	return 0;
1123152909Sanholt}
1124152909Sanholt
1125182080Srnolandstruct drm_ioctl_desc mga_ioctls[] = {
1126182080Srnoland	DRM_IOCTL_DEF(DRM_MGA_INIT, mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1127182080Srnoland	DRM_IOCTL_DEF(DRM_MGA_FLUSH, mga_dma_flush, DRM_AUTH),
1128182080Srnoland	DRM_IOCTL_DEF(DRM_MGA_RESET, mga_dma_reset, DRM_AUTH),
1129182080Srnoland	DRM_IOCTL_DEF(DRM_MGA_SWAP, mga_dma_swap, DRM_AUTH),
1130182080Srnoland	DRM_IOCTL_DEF(DRM_MGA_CLEAR, mga_dma_clear, DRM_AUTH),
1131182080Srnoland	DRM_IOCTL_DEF(DRM_MGA_VERTEX, mga_dma_vertex, DRM_AUTH),
1132182080Srnoland	DRM_IOCTL_DEF(DRM_MGA_INDICES, mga_dma_indices, DRM_AUTH),
1133182080Srnoland	DRM_IOCTL_DEF(DRM_MGA_ILOAD, mga_dma_iload, DRM_AUTH),
1134182080Srnoland	DRM_IOCTL_DEF(DRM_MGA_BLIT, mga_dma_blit, DRM_AUTH),
1135182080Srnoland	DRM_IOCTL_DEF(DRM_MGA_GETPARAM, mga_getparam, DRM_AUTH),
1136182080Srnoland	DRM_IOCTL_DEF(DRM_MGA_SET_FENCE, mga_set_fence, DRM_AUTH),
1137182080Srnoland	DRM_IOCTL_DEF(DRM_MGA_WAIT_FENCE, mga_wait_fence, DRM_AUTH),
1138182080Srnoland	DRM_IOCTL_DEF(DRM_MGA_DMA_BOOTSTRAP, mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1139152909Sanholt
1140145132Sanholt};
1141145132Sanholt
1142145132Sanholtint mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls);
1143