195584Sanholt/* r128_state.c -- State support for r128 -*- linux-c -*-
2152909Sanholt * Created: Thu Jan 27 02:53:43 2000 by gareth@valinux.com
3152909Sanholt */
4139749Simp/*-
595584Sanholt * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
695584Sanholt * All Rights Reserved.
795584Sanholt *
895584Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
995584Sanholt * copy of this software and associated documentation files (the "Software"),
1095584Sanholt * to deal in the Software without restriction, including without limitation
1195584Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1295584Sanholt * and/or sell copies of the Software, and to permit persons to whom the
1395584Sanholt * Software is furnished to do so, subject to the following conditions:
1495584Sanholt *
1595584Sanholt * The above copyright notice and this permission notice (including the next
1695584Sanholt * paragraph) shall be included in all copies or substantial portions of the
1795584Sanholt * Software.
1895584Sanholt *
1995584Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2095584Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2195584Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2295584Sanholt * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2395584Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2495584Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2595584Sanholt * DEALINGS IN THE SOFTWARE.
2695584Sanholt *
2795584Sanholt * Authors:
2895584Sanholt *    Gareth Hughes <gareth@valinux.com>
2995584Sanholt */
3095584Sanholt
31152909Sanholt#include <sys/cdefs.h>
32152909Sanholt__FBSDID("$FreeBSD$");
33152909Sanholt
3495584Sanholt#include "dev/drm/drmP.h"
35112015Sanholt#include "dev/drm/drm.h"
3695746Sanholt#include "dev/drm/r128_drm.h"
3795584Sanholt#include "dev/drm/r128_drv.h"
3895584Sanholt
3995584Sanholt/* ================================================================
4095584Sanholt * CCE hardware state programming functions
4195584Sanholt */
4295584Sanholt
43145132Sanholtstatic void r128_emit_clip_rects(drm_r128_private_t * dev_priv,
44182080Srnoland				 struct drm_clip_rect * boxes, int count)
4595584Sanholt{
4695584Sanholt	u32 aux_sc_cntl = 0x00000000;
4795584Sanholt	RING_LOCALS;
48182080Srnoland	DRM_DEBUG("\n");
4995584Sanholt
50145132Sanholt	BEGIN_RING((count < 3 ? count : 3) * 5 + 2);
5195584Sanholt
52145132Sanholt	if (count >= 1) {
53145132Sanholt		OUT_RING(CCE_PACKET0(R128_AUX1_SC_LEFT, 3));
54145132Sanholt		OUT_RING(boxes[0].x1);
55145132Sanholt		OUT_RING(boxes[0].x2 - 1);
56145132Sanholt		OUT_RING(boxes[0].y1);
57145132Sanholt		OUT_RING(boxes[0].y2 - 1);
5895584Sanholt
5995584Sanholt		aux_sc_cntl |= (R128_AUX1_SC_EN | R128_AUX1_SC_MODE_OR);
6095584Sanholt	}
61145132Sanholt	if (count >= 2) {
62145132Sanholt		OUT_RING(CCE_PACKET0(R128_AUX2_SC_LEFT, 3));
63145132Sanholt		OUT_RING(boxes[1].x1);
64145132Sanholt		OUT_RING(boxes[1].x2 - 1);
65145132Sanholt		OUT_RING(boxes[1].y1);
66145132Sanholt		OUT_RING(boxes[1].y2 - 1);
6795584Sanholt
6895584Sanholt		aux_sc_cntl |= (R128_AUX2_SC_EN | R128_AUX2_SC_MODE_OR);
6995584Sanholt	}
70145132Sanholt	if (count >= 3) {
71145132Sanholt		OUT_RING(CCE_PACKET0(R128_AUX3_SC_LEFT, 3));
72145132Sanholt		OUT_RING(boxes[2].x1);
73145132Sanholt		OUT_RING(boxes[2].x2 - 1);
74145132Sanholt		OUT_RING(boxes[2].y1);
75145132Sanholt		OUT_RING(boxes[2].y2 - 1);
7695584Sanholt
7795584Sanholt		aux_sc_cntl |= (R128_AUX3_SC_EN | R128_AUX3_SC_MODE_OR);
7895584Sanholt	}
7995584Sanholt
80145132Sanholt	OUT_RING(CCE_PACKET0(R128_AUX_SC_CNTL, 0));
81145132Sanholt	OUT_RING(aux_sc_cntl);
8295584Sanholt
8395584Sanholt	ADVANCE_RING();
8495584Sanholt}
8595584Sanholt
86145132Sanholtstatic __inline__ void r128_emit_core(drm_r128_private_t * dev_priv)
8795584Sanholt{
8895584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
8995584Sanholt	drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
9095584Sanholt	RING_LOCALS;
91182080Srnoland	DRM_DEBUG("\n");
9295584Sanholt
93145132Sanholt	BEGIN_RING(2);
9495584Sanholt
95145132Sanholt	OUT_RING(CCE_PACKET0(R128_SCALE_3D_CNTL, 0));
96145132Sanholt	OUT_RING(ctx->scale_3d_cntl);
9795584Sanholt
9895584Sanholt	ADVANCE_RING();
9995584Sanholt}
10095584Sanholt
101145132Sanholtstatic __inline__ void r128_emit_context(drm_r128_private_t * dev_priv)
10295584Sanholt{
10395584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
10495584Sanholt	drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
10595584Sanholt	RING_LOCALS;
106182080Srnoland	DRM_DEBUG("\n");
10795584Sanholt
108145132Sanholt	BEGIN_RING(13);
10995584Sanholt
110145132Sanholt	OUT_RING(CCE_PACKET0(R128_DST_PITCH_OFFSET_C, 11));
111145132Sanholt	OUT_RING(ctx->dst_pitch_offset_c);
112145132Sanholt	OUT_RING(ctx->dp_gui_master_cntl_c);
113145132Sanholt	OUT_RING(ctx->sc_top_left_c);
114145132Sanholt	OUT_RING(ctx->sc_bottom_right_c);
115145132Sanholt	OUT_RING(ctx->z_offset_c);
116145132Sanholt	OUT_RING(ctx->z_pitch_c);
117145132Sanholt	OUT_RING(ctx->z_sten_cntl_c);
118145132Sanholt	OUT_RING(ctx->tex_cntl_c);
119145132Sanholt	OUT_RING(ctx->misc_3d_state_cntl_reg);
120145132Sanholt	OUT_RING(ctx->texture_clr_cmp_clr_c);
121145132Sanholt	OUT_RING(ctx->texture_clr_cmp_msk_c);
122145132Sanholt	OUT_RING(ctx->fog_color_c);
12395584Sanholt
12495584Sanholt	ADVANCE_RING();
12595584Sanholt}
12695584Sanholt
127145132Sanholtstatic __inline__ void r128_emit_setup(drm_r128_private_t * dev_priv)
12895584Sanholt{
12995584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
13095584Sanholt	drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
13195584Sanholt	RING_LOCALS;
132182080Srnoland	DRM_DEBUG("\n");
13395584Sanholt
134145132Sanholt	BEGIN_RING(3);
13595584Sanholt
136145132Sanholt	OUT_RING(CCE_PACKET1(R128_SETUP_CNTL, R128_PM4_VC_FPU_SETUP));
137145132Sanholt	OUT_RING(ctx->setup_cntl);
138145132Sanholt	OUT_RING(ctx->pm4_vc_fpu_setup);
13995584Sanholt
14095584Sanholt	ADVANCE_RING();
14195584Sanholt}
14295584Sanholt
143145132Sanholtstatic __inline__ void r128_emit_masks(drm_r128_private_t * dev_priv)
14495584Sanholt{
14595584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
14695584Sanholt	drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
14795584Sanholt	RING_LOCALS;
148182080Srnoland	DRM_DEBUG("\n");
14995584Sanholt
150145132Sanholt	BEGIN_RING(5);
15195584Sanholt
152145132Sanholt	OUT_RING(CCE_PACKET0(R128_DP_WRITE_MASK, 0));
153145132Sanholt	OUT_RING(ctx->dp_write_mask);
15495584Sanholt
155145132Sanholt	OUT_RING(CCE_PACKET0(R128_STEN_REF_MASK_C, 1));
156145132Sanholt	OUT_RING(ctx->sten_ref_mask_c);
157145132Sanholt	OUT_RING(ctx->plane_3d_mask_c);
15895584Sanholt
15995584Sanholt	ADVANCE_RING();
16095584Sanholt}
16195584Sanholt
162145132Sanholtstatic __inline__ void r128_emit_window(drm_r128_private_t * dev_priv)
16395584Sanholt{
16495584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
16595584Sanholt	drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
16695584Sanholt	RING_LOCALS;
167182080Srnoland	DRM_DEBUG("\n");
16895584Sanholt
169145132Sanholt	BEGIN_RING(2);
17095584Sanholt
171145132Sanholt	OUT_RING(CCE_PACKET0(R128_WINDOW_XY_OFFSET, 0));
172145132Sanholt	OUT_RING(ctx->window_xy_offset);
17395584Sanholt
17495584Sanholt	ADVANCE_RING();
17595584Sanholt}
17695584Sanholt
177145132Sanholtstatic __inline__ void r128_emit_tex0(drm_r128_private_t * dev_priv)
17895584Sanholt{
17995584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
18095584Sanholt	drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
18195584Sanholt	drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[0];
18295584Sanholt	int i;
18395584Sanholt	RING_LOCALS;
184182080Srnoland	DRM_DEBUG("\n");
18595584Sanholt
186145132Sanholt	BEGIN_RING(7 + R128_MAX_TEXTURE_LEVELS);
18795584Sanholt
188145132Sanholt	OUT_RING(CCE_PACKET0(R128_PRIM_TEX_CNTL_C,
189145132Sanholt			     2 + R128_MAX_TEXTURE_LEVELS));
190145132Sanholt	OUT_RING(tex->tex_cntl);
191145132Sanholt	OUT_RING(tex->tex_combine_cntl);
192145132Sanholt	OUT_RING(ctx->tex_size_pitch_c);
193145132Sanholt	for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++) {
194145132Sanholt		OUT_RING(tex->tex_offset[i]);
19595584Sanholt	}
19695584Sanholt
197145132Sanholt	OUT_RING(CCE_PACKET0(R128_CONSTANT_COLOR_C, 1));
198145132Sanholt	OUT_RING(ctx->constant_color_c);
199145132Sanholt	OUT_RING(tex->tex_border_color);
20095584Sanholt
20195584Sanholt	ADVANCE_RING();
20295584Sanholt}
20395584Sanholt
204145132Sanholtstatic __inline__ void r128_emit_tex1(drm_r128_private_t * dev_priv)
20595584Sanholt{
20695584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
20795584Sanholt	drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[1];
20895584Sanholt	int i;
20995584Sanholt	RING_LOCALS;
210182080Srnoland	DRM_DEBUG("\n");
21195584Sanholt
212145132Sanholt	BEGIN_RING(5 + R128_MAX_TEXTURE_LEVELS);
21395584Sanholt
214145132Sanholt	OUT_RING(CCE_PACKET0(R128_SEC_TEX_CNTL_C, 1 + R128_MAX_TEXTURE_LEVELS));
215145132Sanholt	OUT_RING(tex->tex_cntl);
216145132Sanholt	OUT_RING(tex->tex_combine_cntl);
217145132Sanholt	for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++) {
218145132Sanholt		OUT_RING(tex->tex_offset[i]);
21995584Sanholt	}
22095584Sanholt
221145132Sanholt	OUT_RING(CCE_PACKET0(R128_SEC_TEXTURE_BORDER_COLOR_C, 0));
222145132Sanholt	OUT_RING(tex->tex_border_color);
22395584Sanholt
22495584Sanholt	ADVANCE_RING();
22595584Sanholt}
22695584Sanholt
227182080Srnolandstatic void r128_emit_state(drm_r128_private_t * dev_priv)
22895584Sanholt{
22995584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
23095584Sanholt	unsigned int dirty = sarea_priv->dirty;
23195584Sanholt
232182080Srnoland	DRM_DEBUG("dirty=0x%08x\n", dirty);
23395584Sanholt
234145132Sanholt	if (dirty & R128_UPLOAD_CORE) {
235145132Sanholt		r128_emit_core(dev_priv);
23695584Sanholt		sarea_priv->dirty &= ~R128_UPLOAD_CORE;
23795584Sanholt	}
23895584Sanholt
239145132Sanholt	if (dirty & R128_UPLOAD_CONTEXT) {
240145132Sanholt		r128_emit_context(dev_priv);
24195584Sanholt		sarea_priv->dirty &= ~R128_UPLOAD_CONTEXT;
24295584Sanholt	}
24395584Sanholt
244145132Sanholt	if (dirty & R128_UPLOAD_SETUP) {
245145132Sanholt		r128_emit_setup(dev_priv);
24695584Sanholt		sarea_priv->dirty &= ~R128_UPLOAD_SETUP;
24795584Sanholt	}
24895584Sanholt
249145132Sanholt	if (dirty & R128_UPLOAD_MASKS) {
250145132Sanholt		r128_emit_masks(dev_priv);
25195584Sanholt		sarea_priv->dirty &= ~R128_UPLOAD_MASKS;
25295584Sanholt	}
25395584Sanholt
254145132Sanholt	if (dirty & R128_UPLOAD_WINDOW) {
255145132Sanholt		r128_emit_window(dev_priv);
25695584Sanholt		sarea_priv->dirty &= ~R128_UPLOAD_WINDOW;
25795584Sanholt	}
25895584Sanholt
259145132Sanholt	if (dirty & R128_UPLOAD_TEX0) {
260145132Sanholt		r128_emit_tex0(dev_priv);
26195584Sanholt		sarea_priv->dirty &= ~R128_UPLOAD_TEX0;
26295584Sanholt	}
26395584Sanholt
264145132Sanholt	if (dirty & R128_UPLOAD_TEX1) {
265145132Sanholt		r128_emit_tex1(dev_priv);
26695584Sanholt		sarea_priv->dirty &= ~R128_UPLOAD_TEX1;
26795584Sanholt	}
26895584Sanholt
26995584Sanholt	/* Turn off the texture cache flushing */
27095584Sanholt	sarea_priv->context_state.tex_cntl_c &= ~R128_TEX_CACHE_FLUSH;
27195584Sanholt
27295584Sanholt	sarea_priv->dirty &= ~R128_REQUIRE_QUIESCENCE;
27395584Sanholt}
27495584Sanholt
27595584Sanholt#if R128_PERFORMANCE_BOXES
27695584Sanholt/* ================================================================
27795584Sanholt * Performance monitoring functions
27895584Sanholt */
27995584Sanholt
280145132Sanholtstatic void r128_clear_box(drm_r128_private_t * dev_priv,
281145132Sanholt			   int x, int y, int w, int h, int r, int g, int b)
28295584Sanholt{
28395584Sanholt	u32 pitch, offset;
28495584Sanholt	u32 fb_bpp, color;
28595584Sanholt	RING_LOCALS;
28695584Sanholt
287145132Sanholt	switch (dev_priv->fb_bpp) {
28895584Sanholt	case 16:
28995584Sanholt		fb_bpp = R128_GMC_DST_16BPP;
29095584Sanholt		color = (((r & 0xf8) << 8) |
291145132Sanholt			 ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
29295584Sanholt		break;
29395584Sanholt	case 24:
29495584Sanholt		fb_bpp = R128_GMC_DST_24BPP;
29595584Sanholt		color = ((r << 16) | (g << 8) | b);
29695584Sanholt		break;
29795584Sanholt	case 32:
29895584Sanholt		fb_bpp = R128_GMC_DST_32BPP;
299145132Sanholt		color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
30095584Sanholt		break;
30195584Sanholt	default:
30295584Sanholt		return;
30395584Sanholt	}
30495584Sanholt
30595584Sanholt	offset = dev_priv->back_offset;
30695584Sanholt	pitch = dev_priv->back_pitch >> 3;
30795584Sanholt
308145132Sanholt	BEGIN_RING(6);
30995584Sanholt
310145132Sanholt	OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
311145132Sanholt	OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
312145132Sanholt		 R128_GMC_BRUSH_SOLID_COLOR |
313145132Sanholt		 fb_bpp |
314145132Sanholt		 R128_GMC_SRC_DATATYPE_COLOR |
315145132Sanholt		 R128_ROP3_P |
316145132Sanholt		 R128_GMC_CLR_CMP_CNTL_DIS | R128_GMC_AUX_CLIP_DIS);
31795584Sanholt
318145132Sanholt	OUT_RING((pitch << 21) | (offset >> 5));
319145132Sanholt	OUT_RING(color);
32095584Sanholt
321145132Sanholt	OUT_RING((x << 16) | y);
322145132Sanholt	OUT_RING((w << 16) | h);
32395584Sanholt
32495584Sanholt	ADVANCE_RING();
32595584Sanholt}
32695584Sanholt
327145132Sanholtstatic void r128_cce_performance_boxes(drm_r128_private_t * dev_priv)
32895584Sanholt{
329145132Sanholt	if (atomic_read(&dev_priv->idle_count) == 0) {
330145132Sanholt		r128_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0);
33195584Sanholt	} else {
332145132Sanholt		atomic_set(&dev_priv->idle_count, 0);
33395584Sanholt	}
33495584Sanholt}
33595584Sanholt
33695584Sanholt#endif
33795584Sanholt
33895584Sanholt/* ================================================================
33995584Sanholt * CCE command dispatch functions
34095584Sanholt */
34195584Sanholt
342145132Sanholtstatic void r128_print_dirty(const char *msg, unsigned int flags)
34395584Sanholt{
344145132Sanholt	DRM_INFO("%s: (0x%x) %s%s%s%s%s%s%s%s%s\n",
345145132Sanholt		 msg,
346145132Sanholt		 flags,
347145132Sanholt		 (flags & R128_UPLOAD_CORE) ? "core, " : "",
348145132Sanholt		 (flags & R128_UPLOAD_CONTEXT) ? "context, " : "",
349145132Sanholt		 (flags & R128_UPLOAD_SETUP) ? "setup, " : "",
350145132Sanholt		 (flags & R128_UPLOAD_TEX0) ? "tex0, " : "",
351145132Sanholt		 (flags & R128_UPLOAD_TEX1) ? "tex1, " : "",
352145132Sanholt		 (flags & R128_UPLOAD_MASKS) ? "masks, " : "",
353145132Sanholt		 (flags & R128_UPLOAD_WINDOW) ? "window, " : "",
354145132Sanholt		 (flags & R128_UPLOAD_CLIPRECTS) ? "cliprects, " : "",
355145132Sanholt		 (flags & R128_REQUIRE_QUIESCENCE) ? "quiescence, " : "");
35695584Sanholt}
35795584Sanholt
358182080Srnolandstatic void r128_cce_dispatch_clear(struct drm_device * dev,
359145132Sanholt				    drm_r128_clear_t * clear)
36095584Sanholt{
36195584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
36295584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
36395584Sanholt	int nbox = sarea_priv->nbox;
364182080Srnoland	struct drm_clip_rect *pbox = sarea_priv->boxes;
36595584Sanholt	unsigned int flags = clear->flags;
36695584Sanholt	int i;
36795584Sanholt	RING_LOCALS;
368182080Srnoland	DRM_DEBUG("\n");
36995584Sanholt
370145132Sanholt	if (dev_priv->page_flipping && dev_priv->current_page == 1) {
37195584Sanholt		unsigned int tmp = flags;
37295584Sanholt
37395584Sanholt		flags &= ~(R128_FRONT | R128_BACK);
374145132Sanholt		if (tmp & R128_FRONT)
375145132Sanholt			flags |= R128_BACK;
376145132Sanholt		if (tmp & R128_BACK)
377145132Sanholt			flags |= R128_FRONT;
37895584Sanholt	}
37995584Sanholt
380145132Sanholt	for (i = 0; i < nbox; i++) {
38195584Sanholt		int x = pbox[i].x1;
38295584Sanholt		int y = pbox[i].y1;
38395584Sanholt		int w = pbox[i].x2 - x;
38495584Sanholt		int h = pbox[i].y2 - y;
38595584Sanholt
386145132Sanholt		DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
387145132Sanholt			  pbox[i].x1, pbox[i].y1, pbox[i].x2,
388145132Sanholt			  pbox[i].y2, flags);
38995584Sanholt
390145132Sanholt		if (flags & (R128_FRONT | R128_BACK)) {
391145132Sanholt			BEGIN_RING(2);
39295584Sanholt
393145132Sanholt			OUT_RING(CCE_PACKET0(R128_DP_WRITE_MASK, 0));
394145132Sanholt			OUT_RING(clear->color_mask);
39595584Sanholt
39695584Sanholt			ADVANCE_RING();
39795584Sanholt		}
39895584Sanholt
399145132Sanholt		if (flags & R128_FRONT) {
400145132Sanholt			BEGIN_RING(6);
40195584Sanholt
402145132Sanholt			OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
403145132Sanholt			OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
404145132Sanholt				 R128_GMC_BRUSH_SOLID_COLOR |
405145132Sanholt				 (dev_priv->color_fmt << 8) |
406145132Sanholt				 R128_GMC_SRC_DATATYPE_COLOR |
407145132Sanholt				 R128_ROP3_P |
408145132Sanholt				 R128_GMC_CLR_CMP_CNTL_DIS |
409145132Sanholt				 R128_GMC_AUX_CLIP_DIS);
41095584Sanholt
411145132Sanholt			OUT_RING(dev_priv->front_pitch_offset_c);
412145132Sanholt			OUT_RING(clear->clear_color);
41395584Sanholt
414145132Sanholt			OUT_RING((x << 16) | y);
415145132Sanholt			OUT_RING((w << 16) | h);
41695584Sanholt
41795584Sanholt			ADVANCE_RING();
41895584Sanholt		}
41995584Sanholt
420145132Sanholt		if (flags & R128_BACK) {
421145132Sanholt			BEGIN_RING(6);
42295584Sanholt
423145132Sanholt			OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
424145132Sanholt			OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
425145132Sanholt				 R128_GMC_BRUSH_SOLID_COLOR |
426145132Sanholt				 (dev_priv->color_fmt << 8) |
427145132Sanholt				 R128_GMC_SRC_DATATYPE_COLOR |
428145132Sanholt				 R128_ROP3_P |
429145132Sanholt				 R128_GMC_CLR_CMP_CNTL_DIS |
430145132Sanholt				 R128_GMC_AUX_CLIP_DIS);
43195584Sanholt
432145132Sanholt			OUT_RING(dev_priv->back_pitch_offset_c);
433145132Sanholt			OUT_RING(clear->clear_color);
43495584Sanholt
435145132Sanholt			OUT_RING((x << 16) | y);
436145132Sanholt			OUT_RING((w << 16) | h);
43795584Sanholt
43895584Sanholt			ADVANCE_RING();
43995584Sanholt		}
44095584Sanholt
441145132Sanholt		if (flags & R128_DEPTH) {
442145132Sanholt			BEGIN_RING(6);
44395584Sanholt
444145132Sanholt			OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
445145132Sanholt			OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
446145132Sanholt				 R128_GMC_BRUSH_SOLID_COLOR |
447145132Sanholt				 (dev_priv->depth_fmt << 8) |
448145132Sanholt				 R128_GMC_SRC_DATATYPE_COLOR |
449145132Sanholt				 R128_ROP3_P |
450145132Sanholt				 R128_GMC_CLR_CMP_CNTL_DIS |
451145132Sanholt				 R128_GMC_AUX_CLIP_DIS | R128_GMC_WR_MSK_DIS);
45295584Sanholt
453145132Sanholt			OUT_RING(dev_priv->depth_pitch_offset_c);
454145132Sanholt			OUT_RING(clear->clear_depth);
45595584Sanholt
456145132Sanholt			OUT_RING((x << 16) | y);
457145132Sanholt			OUT_RING((w << 16) | h);
45895584Sanholt
45995584Sanholt			ADVANCE_RING();
46095584Sanholt		}
46195584Sanholt	}
46295584Sanholt}
46395584Sanholt
464182080Srnolandstatic void r128_cce_dispatch_swap(struct drm_device * dev)
46595584Sanholt{
46695584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
46795584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
46895584Sanholt	int nbox = sarea_priv->nbox;
469182080Srnoland	struct drm_clip_rect *pbox = sarea_priv->boxes;
47095584Sanholt	int i;
47195584Sanholt	RING_LOCALS;
472182080Srnoland	DRM_DEBUG("\n");
47395584Sanholt
47495584Sanholt#if R128_PERFORMANCE_BOXES
47595584Sanholt	/* Do some trivial performance monitoring...
47695584Sanholt	 */
477145132Sanholt	r128_cce_performance_boxes(dev_priv);
47895584Sanholt#endif
47995584Sanholt
480145132Sanholt	for (i = 0; i < nbox; i++) {
48195584Sanholt		int x = pbox[i].x1;
48295584Sanholt		int y = pbox[i].y1;
48395584Sanholt		int w = pbox[i].x2 - x;
48495584Sanholt		int h = pbox[i].y2 - y;
48595584Sanholt
486145132Sanholt		BEGIN_RING(7);
48795584Sanholt
488145132Sanholt		OUT_RING(CCE_PACKET3(R128_CNTL_BITBLT_MULTI, 5));
489145132Sanholt		OUT_RING(R128_GMC_SRC_PITCH_OFFSET_CNTL |
490145132Sanholt			 R128_GMC_DST_PITCH_OFFSET_CNTL |
491145132Sanholt			 R128_GMC_BRUSH_NONE |
492145132Sanholt			 (dev_priv->color_fmt << 8) |
493145132Sanholt			 R128_GMC_SRC_DATATYPE_COLOR |
494145132Sanholt			 R128_ROP3_S |
495145132Sanholt			 R128_DP_SRC_SOURCE_MEMORY |
496145132Sanholt			 R128_GMC_CLR_CMP_CNTL_DIS |
497145132Sanholt			 R128_GMC_AUX_CLIP_DIS | R128_GMC_WR_MSK_DIS);
49895584Sanholt
499119098Sanholt		/* Make this work even if front & back are flipped:
500119098Sanholt		 */
501119098Sanholt		if (dev_priv->current_page == 0) {
502145132Sanholt			OUT_RING(dev_priv->back_pitch_offset_c);
503145132Sanholt			OUT_RING(dev_priv->front_pitch_offset_c);
504145132Sanholt		} else {
505145132Sanholt			OUT_RING(dev_priv->front_pitch_offset_c);
506145132Sanholt			OUT_RING(dev_priv->back_pitch_offset_c);
507119098Sanholt		}
50895584Sanholt
509145132Sanholt		OUT_RING((x << 16) | y);
510145132Sanholt		OUT_RING((x << 16) | y);
511145132Sanholt		OUT_RING((w << 16) | h);
51295584Sanholt
51395584Sanholt		ADVANCE_RING();
51495584Sanholt	}
51595584Sanholt
51695584Sanholt	/* Increment the frame counter.  The client-side 3D driver must
51795584Sanholt	 * throttle the framerate by waiting for this value before
51895584Sanholt	 * performing the swapbuffer ioctl.
51995584Sanholt	 */
52095584Sanholt	dev_priv->sarea_priv->last_frame++;
52195584Sanholt
522145132Sanholt	BEGIN_RING(2);
52395584Sanholt
524145132Sanholt	OUT_RING(CCE_PACKET0(R128_LAST_FRAME_REG, 0));
525145132Sanholt	OUT_RING(dev_priv->sarea_priv->last_frame);
52695584Sanholt
52795584Sanholt	ADVANCE_RING();
52895584Sanholt}
52995584Sanholt
530182080Srnolandstatic void r128_cce_dispatch_flip(struct drm_device * dev)
53195584Sanholt{
53295584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
53395584Sanholt	RING_LOCALS;
534182080Srnoland	DRM_DEBUG("page=%d pfCurrentPage=%d\n",
535145132Sanholt		  dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
53695584Sanholt
53795584Sanholt#if R128_PERFORMANCE_BOXES
53895584Sanholt	/* Do some trivial performance monitoring...
53995584Sanholt	 */
540145132Sanholt	r128_cce_performance_boxes(dev_priv);
54195584Sanholt#endif
54295584Sanholt
543145132Sanholt	BEGIN_RING(4);
54495584Sanholt
54595584Sanholt	R128_WAIT_UNTIL_PAGE_FLIPPED();
546145132Sanholt	OUT_RING(CCE_PACKET0(R128_CRTC_OFFSET, 0));
54795584Sanholt
548145132Sanholt	if (dev_priv->current_page == 0) {
549145132Sanholt		OUT_RING(dev_priv->back_offset);
55095584Sanholt	} else {
551145132Sanholt		OUT_RING(dev_priv->front_offset);
55295584Sanholt	}
55395584Sanholt
55495584Sanholt	ADVANCE_RING();
55595584Sanholt
55695584Sanholt	/* Increment the frame counter.  The client-side 3D driver must
55795584Sanholt	 * throttle the framerate by waiting for this value before
55895584Sanholt	 * performing the swapbuffer ioctl.
55995584Sanholt	 */
56095584Sanholt	dev_priv->sarea_priv->last_frame++;
561119098Sanholt	dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
562145132Sanholt	    1 - dev_priv->current_page;
56395584Sanholt
564145132Sanholt	BEGIN_RING(2);
56595584Sanholt
566145132Sanholt	OUT_RING(CCE_PACKET0(R128_LAST_FRAME_REG, 0));
567145132Sanholt	OUT_RING(dev_priv->sarea_priv->last_frame);
56895584Sanholt
56995584Sanholt	ADVANCE_RING();
57095584Sanholt}
57195584Sanholt
572182080Srnolandstatic void r128_cce_dispatch_vertex(struct drm_device * dev, struct drm_buf * buf)
57395584Sanholt{
57495584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
57595584Sanholt	drm_r128_buf_priv_t *buf_priv = buf->dev_private;
57695584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
57795584Sanholt	int format = sarea_priv->vc_format;
57895584Sanholt	int offset = buf->bus_address;
57995584Sanholt	int size = buf->used;
58095584Sanholt	int prim = buf_priv->prim;
58195584Sanholt	int i = 0;
58295584Sanholt	RING_LOCALS;
583145132Sanholt	DRM_DEBUG("buf=%d nbox=%d\n", buf->idx, sarea_priv->nbox);
58495584Sanholt
585145132Sanholt	if (0)
586145132Sanholt		r128_print_dirty("dispatch_vertex", sarea_priv->dirty);
58795584Sanholt
588145132Sanholt	if (buf->used) {
58995584Sanholt		buf_priv->dispatched = 1;
59095584Sanholt
591145132Sanholt		if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS) {
592145132Sanholt			r128_emit_state(dev_priv);
59395584Sanholt		}
59495584Sanholt
59595584Sanholt		do {
59695584Sanholt			/* Emit the next set of up to three cliprects */
597145132Sanholt			if (i < sarea_priv->nbox) {
598145132Sanholt				r128_emit_clip_rects(dev_priv,
599145132Sanholt						     &sarea_priv->boxes[i],
600145132Sanholt						     sarea_priv->nbox - i);
60195584Sanholt			}
60295584Sanholt
60395584Sanholt			/* Emit the vertex buffer rendering commands */
604145132Sanholt			BEGIN_RING(5);
60595584Sanholt
606145132Sanholt			OUT_RING(CCE_PACKET3(R128_3D_RNDR_GEN_INDX_PRIM, 3));
607145132Sanholt			OUT_RING(offset);
608145132Sanholt			OUT_RING(size);
609145132Sanholt			OUT_RING(format);
610145132Sanholt			OUT_RING(prim | R128_CCE_VC_CNTL_PRIM_WALK_LIST |
611145132Sanholt				 (size << R128_CCE_VC_CNTL_NUM_SHIFT));
61295584Sanholt
61395584Sanholt			ADVANCE_RING();
61495584Sanholt
61595584Sanholt			i += 3;
616145132Sanholt		} while (i < sarea_priv->nbox);
61795584Sanholt	}
61895584Sanholt
619145132Sanholt	if (buf_priv->discard) {
62095584Sanholt		buf_priv->age = dev_priv->sarea_priv->last_dispatch;
62195584Sanholt
62295584Sanholt		/* Emit the vertex buffer age */
623145132Sanholt		BEGIN_RING(2);
62495584Sanholt
625145132Sanholt		OUT_RING(CCE_PACKET0(R128_LAST_DISPATCH_REG, 0));
626145132Sanholt		OUT_RING(buf_priv->age);
62795584Sanholt
62895584Sanholt		ADVANCE_RING();
62995584Sanholt
63095584Sanholt		buf->pending = 1;
63195584Sanholt		buf->used = 0;
63295584Sanholt		/* FIXME: Check dispatched field */
63395584Sanholt		buf_priv->dispatched = 0;
63495584Sanholt	}
63595584Sanholt
63695584Sanholt	dev_priv->sarea_priv->last_dispatch++;
63795584Sanholt
63895584Sanholt	sarea_priv->dirty &= ~R128_UPLOAD_CLIPRECTS;
63995584Sanholt	sarea_priv->nbox = 0;
64095584Sanholt}
64195584Sanholt
642182080Srnolandstatic void r128_cce_dispatch_indirect(struct drm_device * dev,
643182080Srnoland				       struct drm_buf * buf, int start, int end)
64495584Sanholt{
64595584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
64695584Sanholt	drm_r128_buf_priv_t *buf_priv = buf->dev_private;
64795584Sanholt	RING_LOCALS;
648145132Sanholt	DRM_DEBUG("indirect: buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
64995584Sanholt
650145132Sanholt	if (start != end) {
65195584Sanholt		int offset = buf->bus_address + start;
65295584Sanholt		int dwords = (end - start + 3) / sizeof(u32);
65395584Sanholt
65495584Sanholt		/* Indirect buffer data must be an even number of
65595584Sanholt		 * dwords, so if we've been given an odd number we must
65695584Sanholt		 * pad the data with a Type-2 CCE packet.
65795584Sanholt		 */
658145132Sanholt		if (dwords & 1) {
65995584Sanholt			u32 *data = (u32 *)
660207066Srnoland			    ((char *)dev->agp_buffer_map->virtual
661145132Sanholt			     + buf->offset + start);
662145132Sanholt			data[dwords++] = cpu_to_le32(R128_CCE_PACKET2);
66395584Sanholt		}
66495584Sanholt
66595584Sanholt		buf_priv->dispatched = 1;
66695584Sanholt
66795584Sanholt		/* Fire off the indirect buffer */
668145132Sanholt		BEGIN_RING(3);
66995584Sanholt
670145132Sanholt		OUT_RING(CCE_PACKET0(R128_PM4_IW_INDOFF, 1));
671145132Sanholt		OUT_RING(offset);
672145132Sanholt		OUT_RING(dwords);
67395584Sanholt
67495584Sanholt		ADVANCE_RING();
67595584Sanholt	}
67695584Sanholt
677145132Sanholt	if (buf_priv->discard) {
67895584Sanholt		buf_priv->age = dev_priv->sarea_priv->last_dispatch;
67995584Sanholt
68095584Sanholt		/* Emit the indirect buffer age */
681145132Sanholt		BEGIN_RING(2);
68295584Sanholt
683145132Sanholt		OUT_RING(CCE_PACKET0(R128_LAST_DISPATCH_REG, 0));
684145132Sanholt		OUT_RING(buf_priv->age);
68595584Sanholt
68695584Sanholt		ADVANCE_RING();
68795584Sanholt
68895584Sanholt		buf->pending = 1;
68995584Sanholt		buf->used = 0;
69095584Sanholt		/* FIXME: Check dispatched field */
69195584Sanholt		buf_priv->dispatched = 0;
69295584Sanholt	}
69395584Sanholt
69495584Sanholt	dev_priv->sarea_priv->last_dispatch++;
69595584Sanholt}
69695584Sanholt
697182080Srnolandstatic void r128_cce_dispatch_indices(struct drm_device * dev,
698182080Srnoland				      struct drm_buf * buf,
699145132Sanholt				      int start, int end, int count)
70095584Sanholt{
70195584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
70295584Sanholt	drm_r128_buf_priv_t *buf_priv = buf->dev_private;
70395584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
70495584Sanholt	int format = sarea_priv->vc_format;
705145132Sanholt	int offset = dev->agp_buffer_map->offset - dev_priv->cce_buffers_offset;
70695584Sanholt	int prim = buf_priv->prim;
70795584Sanholt	u32 *data;
70895584Sanholt	int dwords;
70995584Sanholt	int i = 0;
71095584Sanholt	RING_LOCALS;
711145132Sanholt	DRM_DEBUG("indices: s=%d e=%d c=%d\n", start, end, count);
71295584Sanholt
713145132Sanholt	if (0)
714145132Sanholt		r128_print_dirty("dispatch_indices", sarea_priv->dirty);
71595584Sanholt
716145132Sanholt	if (start != end) {
71795584Sanholt		buf_priv->dispatched = 1;
71895584Sanholt
719145132Sanholt		if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS) {
720145132Sanholt			r128_emit_state(dev_priv);
72195584Sanholt		}
72295584Sanholt
72395584Sanholt		dwords = (end - start + 3) / sizeof(u32);
72495584Sanholt
725207066Srnoland		data = (u32 *) ((char *)dev->agp_buffer_map->virtual
726145132Sanholt				+ buf->offset + start);
72795584Sanholt
728145132Sanholt		data[0] = cpu_to_le32(CCE_PACKET3(R128_3D_RNDR_GEN_INDX_PRIM,
729145132Sanholt						  dwords - 2));
73095584Sanholt
731145132Sanholt		data[1] = cpu_to_le32(offset);
732145132Sanholt		data[2] = cpu_to_le32(R128_MAX_VB_VERTS);
733145132Sanholt		data[3] = cpu_to_le32(format);
734145132Sanholt		data[4] = cpu_to_le32((prim | R128_CCE_VC_CNTL_PRIM_WALK_IND |
735145132Sanholt				       (count << 16)));
73695584Sanholt
737145132Sanholt		if (count & 0x1) {
73895584Sanholt#ifdef __LITTLE_ENDIAN
739145132Sanholt			data[dwords - 1] &= 0x0000ffff;
74095584Sanholt#else
741145132Sanholt			data[dwords - 1] &= 0xffff0000;
74295584Sanholt#endif
74395584Sanholt		}
74495584Sanholt
74595584Sanholt		do {
74695584Sanholt			/* Emit the next set of up to three cliprects */
747145132Sanholt			if (i < sarea_priv->nbox) {
748145132Sanholt				r128_emit_clip_rects(dev_priv,
749145132Sanholt						     &sarea_priv->boxes[i],
750145132Sanholt						     sarea_priv->nbox - i);
75195584Sanholt			}
75295584Sanholt
753145132Sanholt			r128_cce_dispatch_indirect(dev, buf, start, end);
75495584Sanholt
75595584Sanholt			i += 3;
756145132Sanholt		} while (i < sarea_priv->nbox);
75795584Sanholt	}
75895584Sanholt
759145132Sanholt	if (buf_priv->discard) {
76095584Sanholt		buf_priv->age = dev_priv->sarea_priv->last_dispatch;
76195584Sanholt
76295584Sanholt		/* Emit the vertex buffer age */
763145132Sanholt		BEGIN_RING(2);
76495584Sanholt
765145132Sanholt		OUT_RING(CCE_PACKET0(R128_LAST_DISPATCH_REG, 0));
766145132Sanholt		OUT_RING(buf_priv->age);
76795584Sanholt
76895584Sanholt		ADVANCE_RING();
76995584Sanholt
77095584Sanholt		buf->pending = 1;
77195584Sanholt		/* FIXME: Check dispatched field */
77295584Sanholt		buf_priv->dispatched = 0;
77395584Sanholt	}
77495584Sanholt
77595584Sanholt	dev_priv->sarea_priv->last_dispatch++;
77695584Sanholt
77795584Sanholt	sarea_priv->dirty &= ~R128_UPLOAD_CLIPRECTS;
77895584Sanholt	sarea_priv->nbox = 0;
77995584Sanholt}
78095584Sanholt
781182080Srnolandstatic int r128_cce_dispatch_blit(struct drm_device * dev,
782182080Srnoland				  struct drm_file *file_priv,
783182080Srnoland				  drm_r128_blit_t * blit)
78495584Sanholt{
78595584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
786182080Srnoland	struct drm_device_dma *dma = dev->dma;
787182080Srnoland	struct drm_buf *buf;
78895584Sanholt	drm_r128_buf_priv_t *buf_priv;
78995584Sanholt	u32 *data;
79095584Sanholt	int dword_shift, dwords;
79195584Sanholt	RING_LOCALS;
792145132Sanholt	DRM_DEBUG("\n");
79395584Sanholt
79495584Sanholt	/* The compiler won't optimize away a division by a variable,
79595584Sanholt	 * even if the only legal values are powers of two.  Thus, we'll
79695584Sanholt	 * use a shift instead.
79795584Sanholt	 */
798145132Sanholt	switch (blit->format) {
79995584Sanholt	case R128_DATATYPE_ARGB8888:
80095584Sanholt		dword_shift = 0;
80195584Sanholt		break;
80295584Sanholt	case R128_DATATYPE_ARGB1555:
80395584Sanholt	case R128_DATATYPE_RGB565:
80495584Sanholt	case R128_DATATYPE_ARGB4444:
805119098Sanholt	case R128_DATATYPE_YVYU422:
806119098Sanholt	case R128_DATATYPE_VYUY422:
80795584Sanholt		dword_shift = 1;
80895584Sanholt		break;
80995584Sanholt	case R128_DATATYPE_CI8:
81095584Sanholt	case R128_DATATYPE_RGB8:
81195584Sanholt		dword_shift = 2;
81295584Sanholt		break;
81395584Sanholt	default:
814145132Sanholt		DRM_ERROR("invalid blit format %d\n", blit->format);
815182080Srnoland		return -EINVAL;
81695584Sanholt	}
81795584Sanholt
81895584Sanholt	/* Flush the pixel cache, and mark the contents as Read Invalid.
81995584Sanholt	 * This ensures no pixel data gets mixed up with the texture
82095584Sanholt	 * data from the host data blit, otherwise part of the texture
82195584Sanholt	 * image may be corrupted.
82295584Sanholt	 */
823145132Sanholt	BEGIN_RING(2);
82495584Sanholt
825145132Sanholt	OUT_RING(CCE_PACKET0(R128_PC_GUI_CTLSTAT, 0));
826145132Sanholt	OUT_RING(R128_PC_RI_GUI | R128_PC_FLUSH_GUI);
82795584Sanholt
82895584Sanholt	ADVANCE_RING();
82995584Sanholt
83095584Sanholt	/* Dispatch the indirect buffer.
83195584Sanholt	 */
83295584Sanholt	buf = dma->buflist[blit->idx];
83395584Sanholt	buf_priv = buf->dev_private;
83495584Sanholt
835182080Srnoland	if (buf->file_priv != file_priv) {
836145132Sanholt		DRM_ERROR("process %d using buffer owned by %p\n",
837182080Srnoland			  DRM_CURRENTPID, buf->file_priv);
838182080Srnoland		return -EINVAL;
83995584Sanholt	}
840145132Sanholt	if (buf->pending) {
841145132Sanholt		DRM_ERROR("sending pending buffer %d\n", blit->idx);
842182080Srnoland		return -EINVAL;
84395584Sanholt	}
84495584Sanholt
84595584Sanholt	buf_priv->discard = 1;
84695584Sanholt
84795584Sanholt	dwords = (blit->width * blit->height) >> dword_shift;
84895584Sanholt
849145132Sanholt	data = (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
85095584Sanholt
851145132Sanholt	data[0] = cpu_to_le32(CCE_PACKET3(R128_CNTL_HOSTDATA_BLT, dwords + 6));
852145132Sanholt	data[1] = cpu_to_le32((R128_GMC_DST_PITCH_OFFSET_CNTL |
853145132Sanholt			       R128_GMC_BRUSH_NONE |
854145132Sanholt			       (blit->format << 8) |
855145132Sanholt			       R128_GMC_SRC_DATATYPE_COLOR |
856145132Sanholt			       R128_ROP3_S |
857145132Sanholt			       R128_DP_SRC_SOURCE_HOST_DATA |
858145132Sanholt			       R128_GMC_CLR_CMP_CNTL_DIS |
859145132Sanholt			       R128_GMC_AUX_CLIP_DIS | R128_GMC_WR_MSK_DIS));
86095584Sanholt
861145132Sanholt	data[2] = cpu_to_le32((blit->pitch << 21) | (blit->offset >> 5));
862145132Sanholt	data[3] = cpu_to_le32(0xffffffff);
863145132Sanholt	data[4] = cpu_to_le32(0xffffffff);
864145132Sanholt	data[5] = cpu_to_le32((blit->y << 16) | blit->x);
865145132Sanholt	data[6] = cpu_to_le32((blit->height << 16) | blit->width);
866145132Sanholt	data[7] = cpu_to_le32(dwords);
86795584Sanholt
86895584Sanholt	buf->used = (dwords + 8) * sizeof(u32);
86995584Sanholt
870145132Sanholt	r128_cce_dispatch_indirect(dev, buf, 0, buf->used);
87195584Sanholt
87295584Sanholt	/* Flush the pixel cache after the blit completes.  This ensures
87395584Sanholt	 * the texture data is written out to memory before rendering
87495584Sanholt	 * continues.
87595584Sanholt	 */
876145132Sanholt	BEGIN_RING(2);
87795584Sanholt
878145132Sanholt	OUT_RING(CCE_PACKET0(R128_PC_GUI_CTLSTAT, 0));
879145132Sanholt	OUT_RING(R128_PC_FLUSH_GUI);
88095584Sanholt
88195584Sanholt	ADVANCE_RING();
88295584Sanholt
88395584Sanholt	return 0;
88495584Sanholt}
88595584Sanholt
88695584Sanholt/* ================================================================
88795584Sanholt * Tiled depth buffer management
88895584Sanholt *
88995584Sanholt * FIXME: These should all set the destination write mask for when we
89095584Sanholt * have hardware stencil support.
89195584Sanholt */
89295584Sanholt
893182080Srnolandstatic int r128_cce_dispatch_write_span(struct drm_device * dev,
894145132Sanholt					drm_r128_depth_t * depth)
89595584Sanholt{
89695584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
89795584Sanholt	int count, x, y;
89895584Sanholt	u32 *buffer;
89995584Sanholt	u8 *mask;
900112015Sanholt	int i, buffer_size, mask_size;
90195584Sanholt	RING_LOCALS;
902145132Sanholt	DRM_DEBUG("\n");
90395584Sanholt
90495584Sanholt	count = depth->n;
905130331Sanholt	if (count > 4096 || count <= 0)
906182080Srnoland		return -EMSGSIZE;
907130331Sanholt
908145132Sanholt	if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) {
909182080Srnoland		return -EFAULT;
91095584Sanholt	}
911145132Sanholt	if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) {
912182080Srnoland		return -EFAULT;
91395584Sanholt	}
91495584Sanholt
915112015Sanholt	buffer_size = depth->n * sizeof(u32);
916145132Sanholt	buffer = drm_alloc(buffer_size, DRM_MEM_BUFS);
917145132Sanholt	if (buffer == NULL)
918182080Srnoland		return -ENOMEM;
919145132Sanholt	if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) {
920145132Sanholt		drm_free(buffer, buffer_size, DRM_MEM_BUFS);
921182080Srnoland		return -EFAULT;
92295584Sanholt	}
92395584Sanholt
924112015Sanholt	mask_size = depth->n * sizeof(u8);
925145132Sanholt	if (depth->mask) {
926145132Sanholt		mask = drm_alloc(mask_size, DRM_MEM_BUFS);
927145132Sanholt		if (mask == NULL) {
928145132Sanholt			drm_free(buffer, buffer_size, DRM_MEM_BUFS);
929182080Srnoland			return -ENOMEM;
93095584Sanholt		}
931145132Sanholt		if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) {
932145132Sanholt			drm_free(buffer, buffer_size, DRM_MEM_BUFS);
933145132Sanholt			drm_free(mask, mask_size, DRM_MEM_BUFS);
934182080Srnoland			return -EFAULT;
93595584Sanholt		}
93695584Sanholt
937145132Sanholt		for (i = 0; i < count; i++, x++) {
938145132Sanholt			if (mask[i]) {
939145132Sanholt				BEGIN_RING(6);
94095584Sanholt
941145132Sanholt				OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
942145132Sanholt				OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
943145132Sanholt					 R128_GMC_BRUSH_SOLID_COLOR |
944145132Sanholt					 (dev_priv->depth_fmt << 8) |
945145132Sanholt					 R128_GMC_SRC_DATATYPE_COLOR |
946145132Sanholt					 R128_ROP3_P |
947145132Sanholt					 R128_GMC_CLR_CMP_CNTL_DIS |
948145132Sanholt					 R128_GMC_WR_MSK_DIS);
94995584Sanholt
950145132Sanholt				OUT_RING(dev_priv->depth_pitch_offset_c);
951145132Sanholt				OUT_RING(buffer[i]);
95295584Sanholt
953145132Sanholt				OUT_RING((x << 16) | y);
954145132Sanholt				OUT_RING((1 << 16) | 1);
95595584Sanholt
95695584Sanholt				ADVANCE_RING();
95795584Sanholt			}
95895584Sanholt		}
95995584Sanholt
960145132Sanholt		drm_free(mask, mask_size, DRM_MEM_BUFS);
96195584Sanholt	} else {
962145132Sanholt		for (i = 0; i < count; i++, x++) {
963145132Sanholt			BEGIN_RING(6);
96495584Sanholt
965145132Sanholt			OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
966145132Sanholt			OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
967145132Sanholt				 R128_GMC_BRUSH_SOLID_COLOR |
968145132Sanholt				 (dev_priv->depth_fmt << 8) |
969145132Sanholt				 R128_GMC_SRC_DATATYPE_COLOR |
970145132Sanholt				 R128_ROP3_P |
971145132Sanholt				 R128_GMC_CLR_CMP_CNTL_DIS |
972145132Sanholt				 R128_GMC_WR_MSK_DIS);
97395584Sanholt
974145132Sanholt			OUT_RING(dev_priv->depth_pitch_offset_c);
975145132Sanholt			OUT_RING(buffer[i]);
97695584Sanholt
977145132Sanholt			OUT_RING((x << 16) | y);
978145132Sanholt			OUT_RING((1 << 16) | 1);
97995584Sanholt
98095584Sanholt			ADVANCE_RING();
98195584Sanholt		}
98295584Sanholt	}
98395584Sanholt
984145132Sanholt	drm_free(buffer, buffer_size, DRM_MEM_BUFS);
98595584Sanholt
98695584Sanholt	return 0;
98795584Sanholt}
98895584Sanholt
989182080Srnolandstatic int r128_cce_dispatch_write_pixels(struct drm_device * dev,
990145132Sanholt					  drm_r128_depth_t * depth)
99195584Sanholt{
99295584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
99395584Sanholt	int count, *x, *y;
99495584Sanholt	u32 *buffer;
99595584Sanholt	u8 *mask;
996112015Sanholt	int i, xbuf_size, ybuf_size, buffer_size, mask_size;
99795584Sanholt	RING_LOCALS;
998145132Sanholt	DRM_DEBUG("\n");
99995584Sanholt
100095584Sanholt	count = depth->n;
1001130331Sanholt	if (count > 4096 || count <= 0)
1002182080Srnoland		return -EMSGSIZE;
100395584Sanholt
1004112015Sanholt	xbuf_size = count * sizeof(*x);
1005112015Sanholt	ybuf_size = count * sizeof(*y);
1006145132Sanholt	x = drm_alloc(xbuf_size, DRM_MEM_BUFS);
1007145132Sanholt	if (x == NULL) {
1008182080Srnoland		return -ENOMEM;
100995584Sanholt	}
1010145132Sanholt	y = drm_alloc(ybuf_size, DRM_MEM_BUFS);
1011145132Sanholt	if (y == NULL) {
1012145132Sanholt		drm_free(x, xbuf_size, DRM_MEM_BUFS);
1013182080Srnoland		return -ENOMEM;
101495584Sanholt	}
1015145132Sanholt	if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) {
1016145132Sanholt		drm_free(x, xbuf_size, DRM_MEM_BUFS);
1017145132Sanholt		drm_free(y, ybuf_size, DRM_MEM_BUFS);
1018182080Srnoland		return -EFAULT;
101995584Sanholt	}
1020145132Sanholt	if (DRM_COPY_FROM_USER(y, depth->y, xbuf_size)) {
1021145132Sanholt		drm_free(x, xbuf_size, DRM_MEM_BUFS);
1022145132Sanholt		drm_free(y, ybuf_size, DRM_MEM_BUFS);
1023182080Srnoland		return -EFAULT;
102495584Sanholt	}
102595584Sanholt
1026112015Sanholt	buffer_size = depth->n * sizeof(u32);
1027145132Sanholt	buffer = drm_alloc(buffer_size, DRM_MEM_BUFS);
1028145132Sanholt	if (buffer == NULL) {
1029145132Sanholt		drm_free(x, xbuf_size, DRM_MEM_BUFS);
1030145132Sanholt		drm_free(y, ybuf_size, DRM_MEM_BUFS);
1031182080Srnoland		return -ENOMEM;
103295584Sanholt	}
1033145132Sanholt	if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) {
1034145132Sanholt		drm_free(x, xbuf_size, DRM_MEM_BUFS);
1035145132Sanholt		drm_free(y, ybuf_size, DRM_MEM_BUFS);
1036145132Sanholt		drm_free(buffer, buffer_size, DRM_MEM_BUFS);
1037182080Srnoland		return -EFAULT;
103895584Sanholt	}
103995584Sanholt
1040145132Sanholt	if (depth->mask) {
1041112015Sanholt		mask_size = depth->n * sizeof(u8);
1042145132Sanholt		mask = drm_alloc(mask_size, DRM_MEM_BUFS);
1043145132Sanholt		if (mask == NULL) {
1044145132Sanholt			drm_free(x, xbuf_size, DRM_MEM_BUFS);
1045145132Sanholt			drm_free(y, ybuf_size, DRM_MEM_BUFS);
1046145132Sanholt			drm_free(buffer, buffer_size, DRM_MEM_BUFS);
1047182080Srnoland			return -ENOMEM;
104895584Sanholt		}
1049145132Sanholt		if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) {
1050145132Sanholt			drm_free(x, xbuf_size, DRM_MEM_BUFS);
1051145132Sanholt			drm_free(y, ybuf_size, DRM_MEM_BUFS);
1052145132Sanholt			drm_free(buffer, buffer_size, DRM_MEM_BUFS);
1053145132Sanholt			drm_free(mask, mask_size, DRM_MEM_BUFS);
1054182080Srnoland			return -EFAULT;
105595584Sanholt		}
105695584Sanholt
1057145132Sanholt		for (i = 0; i < count; i++) {
1058145132Sanholt			if (mask[i]) {
1059145132Sanholt				BEGIN_RING(6);
106095584Sanholt
1061145132Sanholt				OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
1062145132Sanholt				OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
1063145132Sanholt					 R128_GMC_BRUSH_SOLID_COLOR |
1064145132Sanholt					 (dev_priv->depth_fmt << 8) |
1065145132Sanholt					 R128_GMC_SRC_DATATYPE_COLOR |
1066145132Sanholt					 R128_ROP3_P |
1067145132Sanholt					 R128_GMC_CLR_CMP_CNTL_DIS |
1068145132Sanholt					 R128_GMC_WR_MSK_DIS);
106995584Sanholt
1070145132Sanholt				OUT_RING(dev_priv->depth_pitch_offset_c);
1071145132Sanholt				OUT_RING(buffer[i]);
107295584Sanholt
1073145132Sanholt				OUT_RING((x[i] << 16) | y[i]);
1074145132Sanholt				OUT_RING((1 << 16) | 1);
107595584Sanholt
107695584Sanholt				ADVANCE_RING();
107795584Sanholt			}
107895584Sanholt		}
107995584Sanholt
1080145132Sanholt		drm_free(mask, mask_size, DRM_MEM_BUFS);
108195584Sanholt	} else {
1082145132Sanholt		for (i = 0; i < count; i++) {
1083145132Sanholt			BEGIN_RING(6);
108495584Sanholt
1085145132Sanholt			OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
1086145132Sanholt			OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
1087145132Sanholt				 R128_GMC_BRUSH_SOLID_COLOR |
1088145132Sanholt				 (dev_priv->depth_fmt << 8) |
1089145132Sanholt				 R128_GMC_SRC_DATATYPE_COLOR |
1090145132Sanholt				 R128_ROP3_P |
1091145132Sanholt				 R128_GMC_CLR_CMP_CNTL_DIS |
1092145132Sanholt				 R128_GMC_WR_MSK_DIS);
109395584Sanholt
1094145132Sanholt			OUT_RING(dev_priv->depth_pitch_offset_c);
1095145132Sanholt			OUT_RING(buffer[i]);
109695584Sanholt
1097145132Sanholt			OUT_RING((x[i] << 16) | y[i]);
1098145132Sanholt			OUT_RING((1 << 16) | 1);
109995584Sanholt
110095584Sanholt			ADVANCE_RING();
110195584Sanholt		}
110295584Sanholt	}
110395584Sanholt
1104145132Sanholt	drm_free(x, xbuf_size, DRM_MEM_BUFS);
1105145132Sanholt	drm_free(y, ybuf_size, DRM_MEM_BUFS);
1106145132Sanholt	drm_free(buffer, buffer_size, DRM_MEM_BUFS);
110795584Sanholt
110895584Sanholt	return 0;
110995584Sanholt}
111095584Sanholt
1111182080Srnolandstatic int r128_cce_dispatch_read_span(struct drm_device * dev,
1112145132Sanholt				       drm_r128_depth_t * depth)
111395584Sanholt{
111495584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
111595584Sanholt	int count, x, y;
111695584Sanholt	RING_LOCALS;
1117145132Sanholt	DRM_DEBUG("\n");
111895584Sanholt
111995584Sanholt	count = depth->n;
1120130331Sanholt	if (count > 4096 || count <= 0)
1121182080Srnoland		return -EMSGSIZE;
1122126137Srwatson
1123145132Sanholt	if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) {
1124182080Srnoland		return -EFAULT;
112595584Sanholt	}
1126145132Sanholt	if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) {
1127182080Srnoland		return -EFAULT;
112895584Sanholt	}
112995584Sanholt
1130145132Sanholt	BEGIN_RING(7);
113195584Sanholt
1132145132Sanholt	OUT_RING(CCE_PACKET3(R128_CNTL_BITBLT_MULTI, 5));
1133145132Sanholt	OUT_RING(R128_GMC_SRC_PITCH_OFFSET_CNTL |
1134145132Sanholt		 R128_GMC_DST_PITCH_OFFSET_CNTL |
1135145132Sanholt		 R128_GMC_BRUSH_NONE |
1136145132Sanholt		 (dev_priv->depth_fmt << 8) |
1137145132Sanholt		 R128_GMC_SRC_DATATYPE_COLOR |
1138145132Sanholt		 R128_ROP3_S |
1139145132Sanholt		 R128_DP_SRC_SOURCE_MEMORY |
1140145132Sanholt		 R128_GMC_CLR_CMP_CNTL_DIS | R128_GMC_WR_MSK_DIS);
114195584Sanholt
1142145132Sanholt	OUT_RING(dev_priv->depth_pitch_offset_c);
1143145132Sanholt	OUT_RING(dev_priv->span_pitch_offset_c);
114495584Sanholt
1145145132Sanholt	OUT_RING((x << 16) | y);
1146145132Sanholt	OUT_RING((0 << 16) | 0);
1147145132Sanholt	OUT_RING((count << 16) | 1);
114895584Sanholt
114995584Sanholt	ADVANCE_RING();
115095584Sanholt
115195584Sanholt	return 0;
115295584Sanholt}
115395584Sanholt
1154182080Srnolandstatic int r128_cce_dispatch_read_pixels(struct drm_device * dev,
1155145132Sanholt					 drm_r128_depth_t * depth)
115695584Sanholt{
115795584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
115895584Sanholt	int count, *x, *y;
1159112015Sanholt	int i, xbuf_size, ybuf_size;
116095584Sanholt	RING_LOCALS;
1161182080Srnoland	DRM_DEBUG("\n");
116295584Sanholt
116395584Sanholt	count = depth->n;
1164130331Sanholt	if (count > 4096 || count <= 0)
1165182080Srnoland		return -EMSGSIZE;
1166130331Sanholt
1167145132Sanholt	if (count > dev_priv->depth_pitch) {
116895584Sanholt		count = dev_priv->depth_pitch;
116995584Sanholt	}
117095584Sanholt
1171112015Sanholt	xbuf_size = count * sizeof(*x);
1172112015Sanholt	ybuf_size = count * sizeof(*y);
1173145132Sanholt	x = drm_alloc(xbuf_size, DRM_MEM_BUFS);
1174145132Sanholt	if (x == NULL) {
1175182080Srnoland		return -ENOMEM;
117695584Sanholt	}
1177145132Sanholt	y = drm_alloc(ybuf_size, DRM_MEM_BUFS);
1178145132Sanholt	if (y == NULL) {
1179145132Sanholt		drm_free(x, xbuf_size, DRM_MEM_BUFS);
1180182080Srnoland		return -ENOMEM;
118195584Sanholt	}
1182145132Sanholt	if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) {
1183145132Sanholt		drm_free(x, xbuf_size, DRM_MEM_BUFS);
1184145132Sanholt		drm_free(y, ybuf_size, DRM_MEM_BUFS);
1185182080Srnoland		return -EFAULT;
118695584Sanholt	}
1187145132Sanholt	if (DRM_COPY_FROM_USER(y, depth->y, ybuf_size)) {
1188145132Sanholt		drm_free(x, xbuf_size, DRM_MEM_BUFS);
1189145132Sanholt		drm_free(y, ybuf_size, DRM_MEM_BUFS);
1190182080Srnoland		return -EFAULT;
119195584Sanholt	}
119295584Sanholt
1193145132Sanholt	for (i = 0; i < count; i++) {
1194145132Sanholt		BEGIN_RING(7);
119595584Sanholt
1196145132Sanholt		OUT_RING(CCE_PACKET3(R128_CNTL_BITBLT_MULTI, 5));
1197145132Sanholt		OUT_RING(R128_GMC_SRC_PITCH_OFFSET_CNTL |
1198145132Sanholt			 R128_GMC_DST_PITCH_OFFSET_CNTL |
1199145132Sanholt			 R128_GMC_BRUSH_NONE |
1200145132Sanholt			 (dev_priv->depth_fmt << 8) |
1201145132Sanholt			 R128_GMC_SRC_DATATYPE_COLOR |
1202145132Sanholt			 R128_ROP3_S |
1203145132Sanholt			 R128_DP_SRC_SOURCE_MEMORY |
1204145132Sanholt			 R128_GMC_CLR_CMP_CNTL_DIS | R128_GMC_WR_MSK_DIS);
120595584Sanholt
1206145132Sanholt		OUT_RING(dev_priv->depth_pitch_offset_c);
1207145132Sanholt		OUT_RING(dev_priv->span_pitch_offset_c);
120895584Sanholt
1209145132Sanholt		OUT_RING((x[i] << 16) | y[i]);
1210145132Sanholt		OUT_RING((i << 16) | 0);
1211145132Sanholt		OUT_RING((1 << 16) | 1);
121295584Sanholt
121395584Sanholt		ADVANCE_RING();
121495584Sanholt	}
121595584Sanholt
1216145132Sanholt	drm_free(x, xbuf_size, DRM_MEM_BUFS);
1217145132Sanholt	drm_free(y, ybuf_size, DRM_MEM_BUFS);
121895584Sanholt
121995584Sanholt	return 0;
122095584Sanholt}
122195584Sanholt
122295584Sanholt/* ================================================================
122395584Sanholt * Polygon stipple
122495584Sanholt */
122595584Sanholt
1226182080Srnolandstatic void r128_cce_dispatch_stipple(struct drm_device * dev, u32 * stipple)
122795584Sanholt{
122895584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
122995584Sanholt	int i;
123095584Sanholt	RING_LOCALS;
1231182080Srnoland	DRM_DEBUG("\n");
123295584Sanholt
1233145132Sanholt	BEGIN_RING(33);
123495584Sanholt
1235145132Sanholt	OUT_RING(CCE_PACKET0(R128_BRUSH_DATA0, 31));
1236145132Sanholt	for (i = 0; i < 32; i++) {
1237145132Sanholt		OUT_RING(stipple[i]);
123895584Sanholt	}
123995584Sanholt
124095584Sanholt	ADVANCE_RING();
124195584Sanholt}
124295584Sanholt
124395584Sanholt/* ================================================================
124495584Sanholt * IOCTL functions
124595584Sanholt */
124695584Sanholt
1247182080Srnolandstatic int r128_cce_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
124895584Sanholt{
124995584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
125095584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
1251182080Srnoland	drm_r128_clear_t *clear = data;
1252145132Sanholt	DRM_DEBUG("\n");
125395584Sanholt
1254182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
125595584Sanholt
1256145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
125795584Sanholt
1258145132Sanholt	if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS)
125995584Sanholt		sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS;
126095584Sanholt
1261182080Srnoland	r128_cce_dispatch_clear(dev, clear);
1262121447Sanholt	COMMIT_RING();
126395584Sanholt
126495584Sanholt	/* Make sure we restore the 3D state next time.
126595584Sanholt	 */
126695584Sanholt	dev_priv->sarea_priv->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS;
126795584Sanholt
126895584Sanholt	return 0;
126995584Sanholt}
127095584Sanholt
1271182080Srnolandstatic int r128_do_init_pageflip(struct drm_device * dev)
1272119098Sanholt{
1273119098Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
1274145132Sanholt	DRM_DEBUG("\n");
1275119098Sanholt
1276145132Sanholt	dev_priv->crtc_offset = R128_READ(R128_CRTC_OFFSET);
1277145132Sanholt	dev_priv->crtc_offset_cntl = R128_READ(R128_CRTC_OFFSET_CNTL);
1278119098Sanholt
1279145132Sanholt	R128_WRITE(R128_CRTC_OFFSET, dev_priv->front_offset);
1280145132Sanholt	R128_WRITE(R128_CRTC_OFFSET_CNTL,
1281145132Sanholt		   dev_priv->crtc_offset_cntl | R128_CRTC_OFFSET_FLIP_CNTL);
1282119098Sanholt
1283119098Sanholt	dev_priv->page_flipping = 1;
1284119098Sanholt	dev_priv->current_page = 0;
1285119098Sanholt	dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
1286119098Sanholt
1287119098Sanholt	return 0;
1288119098Sanholt}
1289119098Sanholt
1290182080Srnolandstatic int r128_do_cleanup_pageflip(struct drm_device * dev)
1291119098Sanholt{
1292119098Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
1293145132Sanholt	DRM_DEBUG("\n");
1294119098Sanholt
1295145132Sanholt	R128_WRITE(R128_CRTC_OFFSET, dev_priv->crtc_offset);
1296145132Sanholt	R128_WRITE(R128_CRTC_OFFSET_CNTL, dev_priv->crtc_offset_cntl);
1297119098Sanholt
1298121447Sanholt	if (dev_priv->current_page != 0) {
1299145132Sanholt		r128_cce_dispatch_flip(dev);
1300121447Sanholt		COMMIT_RING();
1301121447Sanholt	}
1302119098Sanholt
1303119098Sanholt	dev_priv->page_flipping = 0;
1304119098Sanholt	return 0;
1305119098Sanholt}
1306119098Sanholt
1307119098Sanholt/* Swapping and flipping are different operations, need different ioctls.
1308145132Sanholt * They can & should be intermixed to support multiple 3d windows.
1309119098Sanholt */
1310119098Sanholt
1311182080Srnolandstatic int r128_cce_flip(struct drm_device *dev, void *data, struct drm_file *file_priv)
1312119098Sanholt{
1313119098Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
1314182080Srnoland	DRM_DEBUG("\n");
1315119098Sanholt
1316182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
1317119098Sanholt
1318145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
1319119098Sanholt
1320145132Sanholt	if (!dev_priv->page_flipping)
1321145132Sanholt		r128_do_init_pageflip(dev);
1322119098Sanholt
1323145132Sanholt	r128_cce_dispatch_flip(dev);
1324119098Sanholt
1325121447Sanholt	COMMIT_RING();
1326119098Sanholt	return 0;
1327119098Sanholt}
1328119098Sanholt
1329182080Srnolandstatic int r128_cce_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
133095584Sanholt{
133195584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
133295584Sanholt	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
1333182080Srnoland	DRM_DEBUG("\n");
133495584Sanholt
1335182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
133695584Sanholt
1337145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
133895584Sanholt
1339145132Sanholt	if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS)
134095584Sanholt		sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS;
134195584Sanholt
1342145132Sanholt	r128_cce_dispatch_swap(dev);
1343119098Sanholt	dev_priv->sarea_priv->dirty |= (R128_UPLOAD_CONTEXT |
1344119098Sanholt					R128_UPLOAD_MASKS);
134595584Sanholt
1346121447Sanholt	COMMIT_RING();
134795584Sanholt	return 0;
134895584Sanholt}
134995584Sanholt
1350182080Srnolandstatic int r128_cce_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
135195584Sanholt{
135295584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
1353182080Srnoland	struct drm_device_dma *dma = dev->dma;
1354182080Srnoland	struct drm_buf *buf;
135595584Sanholt	drm_r128_buf_priv_t *buf_priv;
1356182080Srnoland	drm_r128_vertex_t *vertex = data;
135795584Sanholt
1358182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
135995584Sanholt
1360145132Sanholt	if (!dev_priv) {
1361182080Srnoland		DRM_ERROR("called with no initialization\n");
1362182080Srnoland		return -EINVAL;
136395584Sanholt	}
136495584Sanholt
1365145132Sanholt	DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
1366182080Srnoland		  DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard);
136795584Sanholt
1368182080Srnoland	if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
1369145132Sanholt		DRM_ERROR("buffer index %d (of %d max)\n",
1370182080Srnoland			  vertex->idx, dma->buf_count - 1);
1371182080Srnoland		return -EINVAL;
137295584Sanholt	}
1373182080Srnoland	if (vertex->prim < 0 ||
1374182080Srnoland	    vertex->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
1375182080Srnoland		DRM_ERROR("buffer prim %d\n", vertex->prim);
1376182080Srnoland		return -EINVAL;
137795584Sanholt	}
137895584Sanholt
1379145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
1380145132Sanholt	VB_AGE_TEST_WITH_RETURN(dev_priv);
138195584Sanholt
1382182080Srnoland	buf = dma->buflist[vertex->idx];
138395584Sanholt	buf_priv = buf->dev_private;
138495584Sanholt
1385182080Srnoland	if (buf->file_priv != file_priv) {
1386145132Sanholt		DRM_ERROR("process %d using buffer owned by %p\n",
1387182080Srnoland			  DRM_CURRENTPID, buf->file_priv);
1388182080Srnoland		return -EINVAL;
138995584Sanholt	}
1390145132Sanholt	if (buf->pending) {
1391182080Srnoland		DRM_ERROR("sending pending buffer %d\n", vertex->idx);
1392182080Srnoland		return -EINVAL;
139395584Sanholt	}
139495584Sanholt
1395182080Srnoland	buf->used = vertex->count;
1396182080Srnoland	buf_priv->prim = vertex->prim;
1397182080Srnoland	buf_priv->discard = vertex->discard;
139895584Sanholt
1399145132Sanholt	r128_cce_dispatch_vertex(dev, buf);
140095584Sanholt
1401121447Sanholt	COMMIT_RING();
140295584Sanholt	return 0;
140395584Sanholt}
140495584Sanholt
1405182080Srnolandstatic int r128_cce_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
140695584Sanholt{
140795584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
1408182080Srnoland	struct drm_device_dma *dma = dev->dma;
1409182080Srnoland	struct drm_buf *buf;
141095584Sanholt	drm_r128_buf_priv_t *buf_priv;
1411182080Srnoland	drm_r128_indices_t *elts = data;
141295584Sanholt	int count;
141395584Sanholt
1414182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
141595584Sanholt
1416145132Sanholt	if (!dev_priv) {
1417182080Srnoland		DRM_ERROR("called with no initialization\n");
1418182080Srnoland		return -EINVAL;
141995584Sanholt	}
142095584Sanholt
1421145132Sanholt	DRM_DEBUG("pid=%d buf=%d s=%d e=%d d=%d\n", DRM_CURRENTPID,
1422182080Srnoland		  elts->idx, elts->start, elts->end, elts->discard);
142395584Sanholt
1424182080Srnoland	if (elts->idx < 0 || elts->idx >= dma->buf_count) {
1425145132Sanholt		DRM_ERROR("buffer index %d (of %d max)\n",
1426182080Srnoland			  elts->idx, dma->buf_count - 1);
1427182080Srnoland		return -EINVAL;
142895584Sanholt	}
1429182080Srnoland	if (elts->prim < 0 ||
1430182080Srnoland	    elts->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
1431182080Srnoland		DRM_ERROR("buffer prim %d\n", elts->prim);
1432182080Srnoland		return -EINVAL;
143395584Sanholt	}
143495584Sanholt
1435145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
1436145132Sanholt	VB_AGE_TEST_WITH_RETURN(dev_priv);
143795584Sanholt
1438182080Srnoland	buf = dma->buflist[elts->idx];
143995584Sanholt	buf_priv = buf->dev_private;
144095584Sanholt
1441182080Srnoland	if (buf->file_priv != file_priv) {
1442145132Sanholt		DRM_ERROR("process %d using buffer owned by %p\n",
1443182080Srnoland			  DRM_CURRENTPID, buf->file_priv);
1444182080Srnoland		return -EINVAL;
144595584Sanholt	}
1446145132Sanholt	if (buf->pending) {
1447182080Srnoland		DRM_ERROR("sending pending buffer %d\n", elts->idx);
1448182080Srnoland		return -EINVAL;
144995584Sanholt	}
145095584Sanholt
1451182080Srnoland	count = (elts->end - elts->start) / sizeof(u16);
1452182080Srnoland	elts->start -= R128_INDEX_PRIM_OFFSET;
145395584Sanholt
1454182080Srnoland	if (elts->start & 0x7) {
1455182080Srnoland		DRM_ERROR("misaligned buffer 0x%x\n", elts->start);
1456182080Srnoland		return -EINVAL;
145795584Sanholt	}
1458182080Srnoland	if (elts->start < buf->used) {
1459182080Srnoland		DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used);
1460182080Srnoland		return -EINVAL;
146195584Sanholt	}
146295584Sanholt
1463182080Srnoland	buf->used = elts->end;
1464182080Srnoland	buf_priv->prim = elts->prim;
1465182080Srnoland	buf_priv->discard = elts->discard;
146695584Sanholt
1467182080Srnoland	r128_cce_dispatch_indices(dev, buf, elts->start, elts->end, count);
146895584Sanholt
1469121447Sanholt	COMMIT_RING();
147095584Sanholt	return 0;
147195584Sanholt}
147295584Sanholt
1473182080Srnolandstatic int r128_cce_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
147495584Sanholt{
1475182080Srnoland	struct drm_device_dma *dma = dev->dma;
147695584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
1477182080Srnoland	drm_r128_blit_t *blit = data;
1478121447Sanholt	int ret;
147995584Sanholt
1480182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
148195584Sanholt
1482182080Srnoland	DRM_DEBUG("pid=%d index=%d\n", DRM_CURRENTPID, blit->idx);
148395584Sanholt
1484182080Srnoland	if (blit->idx < 0 || blit->idx >= dma->buf_count) {
1485145132Sanholt		DRM_ERROR("buffer index %d (of %d max)\n",
1486182080Srnoland			  blit->idx, dma->buf_count - 1);
1487182080Srnoland		return -EINVAL;
148895584Sanholt	}
148995584Sanholt
1490145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
1491145132Sanholt	VB_AGE_TEST_WITH_RETURN(dev_priv);
149295584Sanholt
1493182080Srnoland	ret = r128_cce_dispatch_blit(dev, file_priv, blit);
1494121447Sanholt
1495121447Sanholt	COMMIT_RING();
1496121447Sanholt	return ret;
149795584Sanholt}
149895584Sanholt
1499182080Srnolandstatic int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *file_priv)
150095584Sanholt{
150195584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
1502182080Srnoland	drm_r128_depth_t *depth = data;
1503121447Sanholt	int ret;
150495584Sanholt
1505182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
150695584Sanholt
1507145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
150895584Sanholt
1509182080Srnoland	ret = -EINVAL;
1510182080Srnoland	switch (depth->func) {
151195584Sanholt	case R128_WRITE_SPAN:
1512182080Srnoland		ret = r128_cce_dispatch_write_span(dev, depth);
1513152909Sanholt		break;
151495584Sanholt	case R128_WRITE_PIXELS:
1515182080Srnoland		ret = r128_cce_dispatch_write_pixels(dev, depth);
1516152909Sanholt		break;
151795584Sanholt	case R128_READ_SPAN:
1518182080Srnoland		ret = r128_cce_dispatch_read_span(dev, depth);
1519152909Sanholt		break;
152095584Sanholt	case R128_READ_PIXELS:
1521182080Srnoland		ret = r128_cce_dispatch_read_pixels(dev, depth);
1522152909Sanholt		break;
152395584Sanholt	}
152495584Sanholt
1525121447Sanholt	COMMIT_RING();
1526121447Sanholt	return ret;
152795584Sanholt}
152895584Sanholt
1529182080Srnolandstatic int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv)
153095584Sanholt{
153195584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
1532182080Srnoland	drm_r128_stipple_t *stipple = data;
153395584Sanholt	u32 mask[32];
153495584Sanholt
1535182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
153695584Sanholt
1537182080Srnoland	if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32)))
1538182080Srnoland		return -EFAULT;
153995584Sanholt
1540145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
154195584Sanholt
1542145132Sanholt	r128_cce_dispatch_stipple(dev, mask);
154395584Sanholt
1544121447Sanholt	COMMIT_RING();
154595584Sanholt	return 0;
154695584Sanholt}
154795584Sanholt
1548182080Srnolandstatic int r128_cce_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv)
154995584Sanholt{
155095584Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
1551182080Srnoland	struct drm_device_dma *dma = dev->dma;
1552182080Srnoland	struct drm_buf *buf;
155395584Sanholt	drm_r128_buf_priv_t *buf_priv;
1554182080Srnoland	drm_r128_indirect_t *indirect = data;
155595584Sanholt#if 0
155695584Sanholt	RING_LOCALS;
155795584Sanholt#endif
155895584Sanholt
1559182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
156095584Sanholt
1561145132Sanholt	if (!dev_priv) {
1562182080Srnoland		DRM_ERROR("called with no initialization\n");
1563182080Srnoland		return -EINVAL;
156495584Sanholt	}
156595584Sanholt
1566182080Srnoland	DRM_DEBUG("idx=%d s=%d e=%d d=%d\n",
1567182080Srnoland		  indirect->idx, indirect->start, indirect->end,
1568182080Srnoland		  indirect->discard);
156995584Sanholt
1570182080Srnoland	if (indirect->idx < 0 || indirect->idx >= dma->buf_count) {
1571145132Sanholt		DRM_ERROR("buffer index %d (of %d max)\n",
1572182080Srnoland			  indirect->idx, dma->buf_count - 1);
1573182080Srnoland		return -EINVAL;
157495584Sanholt	}
157595584Sanholt
1576182080Srnoland	buf = dma->buflist[indirect->idx];
157795584Sanholt	buf_priv = buf->dev_private;
157895584Sanholt
1579182080Srnoland	if (buf->file_priv != file_priv) {
1580145132Sanholt		DRM_ERROR("process %d using buffer owned by %p\n",
1581182080Srnoland			  DRM_CURRENTPID, buf->file_priv);
1582182080Srnoland		return -EINVAL;
158395584Sanholt	}
1584145132Sanholt	if (buf->pending) {
1585182080Srnoland		DRM_ERROR("sending pending buffer %d\n", indirect->idx);
1586182080Srnoland		return -EINVAL;
158795584Sanholt	}
158895584Sanholt
1589182080Srnoland	if (indirect->start < buf->used) {
1590145132Sanholt		DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
1591182080Srnoland			  indirect->start, buf->used);
1592182080Srnoland		return -EINVAL;
159395584Sanholt	}
159495584Sanholt
1595145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
1596145132Sanholt	VB_AGE_TEST_WITH_RETURN(dev_priv);
159795584Sanholt
1598182080Srnoland	buf->used = indirect->end;
1599182080Srnoland	buf_priv->discard = indirect->discard;
160095584Sanholt
160195584Sanholt#if 0
160295584Sanholt	/* Wait for the 3D stream to idle before the indirect buffer
160395584Sanholt	 * containing 2D acceleration commands is processed.
160495584Sanholt	 */
1605145132Sanholt	BEGIN_RING(2);
160695584Sanholt	RADEON_WAIT_UNTIL_3D_IDLE();
160795584Sanholt	ADVANCE_RING();
160895584Sanholt#endif
160995584Sanholt
161095584Sanholt	/* Dispatch the indirect buffer full of commands from the
161195584Sanholt	 * X server.  This is insecure and is thus only available to
161295584Sanholt	 * privileged clients.
161395584Sanholt	 */
1614182080Srnoland	r128_cce_dispatch_indirect(dev, buf, indirect->start, indirect->end);
161595584Sanholt
1616121447Sanholt	COMMIT_RING();
161795584Sanholt	return 0;
161895584Sanholt}
1619112015Sanholt
1620182080Srnolandstatic int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
1621112015Sanholt{
1622112015Sanholt	drm_r128_private_t *dev_priv = dev->dev_private;
1623182080Srnoland	drm_r128_getparam_t *param = data;
1624112015Sanholt	int value;
1625112015Sanholt
1626145132Sanholt	if (!dev_priv) {
1627182080Srnoland		DRM_ERROR("called with no initialization\n");
1628182080Srnoland		return -EINVAL;
1629112015Sanholt	}
1630112015Sanholt
1631145132Sanholt	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
1632112015Sanholt
1633182080Srnoland	switch (param->param) {
1634112015Sanholt	case R128_PARAM_IRQ_NR:
1635112015Sanholt		value = dev->irq;
1636112015Sanholt		break;
1637112015Sanholt	default:
1638182080Srnoland		return -EINVAL;
1639112015Sanholt	}
1640112015Sanholt
1641182080Srnoland	if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
1642145132Sanholt		DRM_ERROR("copy_to_user\n");
1643182080Srnoland		return -EFAULT;
1644112015Sanholt	}
1645145132Sanholt
1646112015Sanholt	return 0;
1647112015Sanholt}
1648145132Sanholt
1649182080Srnolandvoid r128_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
1650145132Sanholt{
1651145132Sanholt	if (dev->dev_private) {
1652145132Sanholt		drm_r128_private_t *dev_priv = dev->dev_private;
1653145132Sanholt		if (dev_priv->page_flipping) {
1654145132Sanholt			r128_do_cleanup_pageflip(dev);
1655145132Sanholt		}
1656145132Sanholt	}
1657145132Sanholt}
1658145132Sanholt
1659182080Srnolandvoid r128_driver_lastclose(struct drm_device * dev)
1660145132Sanholt{
1661145132Sanholt	r128_do_cleanup_cce(dev);
1662145132Sanholt}
1663145132Sanholt
1664182080Srnolandstruct drm_ioctl_desc r128_ioctls[] = {
1665182080Srnoland	DRM_IOCTL_DEF(DRM_R128_INIT, r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1666182080Srnoland	DRM_IOCTL_DEF(DRM_R128_CCE_START, r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1667182080Srnoland	DRM_IOCTL_DEF(DRM_R128_CCE_STOP, r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1668182080Srnoland	DRM_IOCTL_DEF(DRM_R128_CCE_RESET, r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1669182080Srnoland	DRM_IOCTL_DEF(DRM_R128_CCE_IDLE, r128_cce_idle, DRM_AUTH),
1670182080Srnoland	DRM_IOCTL_DEF(DRM_R128_RESET, r128_engine_reset, DRM_AUTH),
1671182080Srnoland	DRM_IOCTL_DEF(DRM_R128_FULLSCREEN, r128_fullscreen, DRM_AUTH),
1672182080Srnoland	DRM_IOCTL_DEF(DRM_R128_SWAP, r128_cce_swap, DRM_AUTH),
1673182080Srnoland	DRM_IOCTL_DEF(DRM_R128_FLIP, r128_cce_flip, DRM_AUTH),
1674182080Srnoland	DRM_IOCTL_DEF(DRM_R128_CLEAR, r128_cce_clear, DRM_AUTH),
1675182080Srnoland	DRM_IOCTL_DEF(DRM_R128_VERTEX, r128_cce_vertex, DRM_AUTH),
1676182080Srnoland	DRM_IOCTL_DEF(DRM_R128_INDICES, r128_cce_indices, DRM_AUTH),
1677182080Srnoland	DRM_IOCTL_DEF(DRM_R128_BLIT, r128_cce_blit, DRM_AUTH),
1678182080Srnoland	DRM_IOCTL_DEF(DRM_R128_DEPTH, r128_cce_depth, DRM_AUTH),
1679182080Srnoland	DRM_IOCTL_DEF(DRM_R128_STIPPLE, r128_cce_stipple, DRM_AUTH),
1680182080Srnoland	DRM_IOCTL_DEF(DRM_R128_INDIRECT, r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1681182080Srnoland	DRM_IOCTL_DEF(DRM_R128_GETPARAM, r128_getparam, DRM_AUTH),
1682145132Sanholt};
1683145132Sanholt
1684145132Sanholtint r128_max_ioctl = DRM_ARRAY_SIZE(r128_ioctls);
1685