r128_cce.c revision 182080
177957Sbenno/* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*-
277957Sbenno * Created: Wed Apr  5 19:24:19 2000 by kevin@precisioninsight.com
377957Sbenno */
4139825Simp/*-
577957Sbenno * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
677957Sbenno * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
777957Sbenno * All Rights Reserved.
877957Sbenno *
977957Sbenno * Permission is hereby granted, free of charge, to any person obtaining a
1077957Sbenno * copy of this software and associated documentation files (the "Software"),
1177957Sbenno * to deal in the Software without restriction, including without limitation
1277957Sbenno * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1377957Sbenno * and/or sell copies of the Software, and to permit persons to whom the
1477957Sbenno * Software is furnished to do so, subject to the following conditions:
1577957Sbenno *
1677957Sbenno * The above copyright notice and this permission notice (including the next
1777957Sbenno * paragraph) shall be included in all copies or substantial portions of the
1877957Sbenno * Software.
1977957Sbenno *
2077957Sbenno * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2177957Sbenno * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2277957Sbenno * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2377957Sbenno * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2477957Sbenno * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2577957Sbenno * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2677957Sbenno * DEALINGS IN THE SOFTWARE.
2777957Sbenno *
28139825Simp * Authors:
2977957Sbenno *    Gareth Hughes <gareth@valinux.com>
3077957Sbenno */
3177957Sbenno
3277957Sbenno#include <sys/cdefs.h>
3377957Sbenno__FBSDID("$FreeBSD: head/sys/dev/drm/r128_cce.c 182080 2008-08-23 20:59:12Z rnoland $");
3477957Sbenno
3577957Sbenno#include "dev/drm/drmP.h"
3677957Sbenno#include "dev/drm/drm.h"
3777957Sbenno#include "dev/drm/r128_drm.h"
3877957Sbenno#include "dev/drm/r128_drv.h"
3977957Sbenno
4077957Sbenno#define R128_FIFO_DEBUG		0
4177957Sbenno
4277957Sbenno/* CCE microcode (from ATI) */
4377957Sbennostatic u32 r128_cce_microcode[] = {
4477957Sbenno	0, 276838400, 0, 268449792, 2, 142, 2, 145, 0, 1076765731, 0,
4577957Sbenno	1617039951, 0, 774592877, 0, 1987540286, 0, 2307490946U, 0,
4677957Sbenno	599558925, 0, 589505315, 0, 596487092, 0, 589505315, 1,
4777957Sbenno	11544576, 1, 206848, 1, 311296, 1, 198656, 2, 912273422, 11,
4877957Sbenno	262144, 0, 0, 1, 33559837, 1, 7438, 1, 14809, 1, 6615, 12, 28,
4977957Sbenno	1, 6614, 12, 28, 2, 23, 11, 18874368, 0, 16790922, 1, 409600, 9,
5077957Sbenno	30, 1, 147854772, 16, 420483072, 3, 8192, 0, 10240, 1, 198656,
5177957Sbenno	1, 15630, 1, 51200, 10, 34858, 9, 42, 1, 33559823, 2, 10276, 1,
5277957Sbenno	15717, 1, 15718, 2, 43, 1, 15936948, 1, 570480831, 1, 14715071,
5377957Sbenno	12, 322123831, 1, 33953125, 12, 55, 1, 33559908, 1, 15718, 2,
5477957Sbenno	46, 4, 2099258, 1, 526336, 1, 442623, 4, 4194365, 1, 509952, 1,
5577957Sbenno	459007, 3, 0, 12, 92, 2, 46, 12, 176, 1, 15734, 1, 206848, 1,
5677957Sbenno	18432, 1, 133120, 1, 100670734, 1, 149504, 1, 165888, 1,
5777957Sbenno	15975928, 1, 1048576, 6, 3145806, 1, 15715, 16, 2150645232U, 2,
5877957Sbenno	268449859, 2, 10307, 12, 176, 1, 15734, 1, 15735, 1, 15630, 1,
5977957Sbenno	15631, 1, 5253120, 6, 3145810, 16, 2150645232U, 1, 15864, 2, 82,
60198723Snwhitehorn	1, 343310, 1, 1064207, 2, 3145813, 1, 15728, 1, 7817, 1, 15729,
6177957Sbenno	3, 15730, 12, 92, 2, 98, 1, 16168, 1, 16167, 1, 16002, 1, 16008,
6277957Sbenno	1, 15974, 1, 15975, 1, 15990, 1, 15976, 1, 15977, 1, 15980, 0,
6377957Sbenno	15981, 1, 10240, 1, 5253120, 1, 15720, 1, 198656, 6, 110, 1,
6477957Sbenno	180224, 1, 103824738, 2, 112, 2, 3145839, 0, 536885440, 1,
6577957Sbenno	114880, 14, 125, 12, 206975, 1, 33559995, 12, 198784, 0,
6677957Sbenno	33570236, 1, 15803, 0, 15804, 3, 294912, 1, 294912, 3, 442370,
6777957Sbenno	1, 11544576, 0, 811612160, 1, 12593152, 1, 11536384, 1,
68291442Snwhitehorn	14024704, 7, 310382726, 0, 10240, 1, 14796, 1, 14797, 1, 14793,
69291442Snwhitehorn	1, 14794, 0, 14795, 1, 268679168, 1, 9437184, 1, 268449792, 1,
70291442Snwhitehorn	198656, 1, 9452827, 1, 1075854602, 1, 1075854603, 1, 557056, 1,
71291442Snwhitehorn	114880, 14, 159, 12, 198784, 1, 1109409213, 12, 198783, 1,
72277335Snwhitehorn	1107312059, 12, 198784, 1, 1109409212, 2, 162, 1, 1075854781, 1,
73277335Snwhitehorn	1073757627, 1, 1075854780, 1, 540672, 1, 10485760, 6, 3145894,
7477957Sbenno	16, 274741248, 9, 168, 3, 4194304, 3, 4209949, 0, 0, 0, 256, 14,
75178628Smarcel	174, 1, 114857, 1, 33560007, 12, 176, 0, 10240, 1, 114858, 1,
76178628Smarcel	33560018, 1, 114857, 3, 33560007, 1, 16008, 1, 114874, 1,
77231019Sandreast	33560360, 1, 114875, 1, 33560154, 0, 15963, 0, 256, 0, 4096, 1,
78223485Snwhitehorn	409611, 9, 188, 0, 10240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79278429Snwhitehorn	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80278429Snwhitehorn	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
81178628Smarcel	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
82178628Smarcel	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83178628Smarcel	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
84172887Sgrehan	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
85172887Sgrehan};
86172887Sgrehan
87118893Sgrehanstatic int R128_READ_PLL(struct drm_device * dev, int addr)
88118893Sgrehan{
8977957Sbenno	drm_r128_private_t *dev_priv = dev->dev_private;
90231019Sandreast
91209975Snwhitehorn	R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f);
92209975Snwhitehorn	return R128_READ(R128_CLOCK_CNTL_DATA);
93118893Sgrehan}
94209975Snwhitehorn
95209975Snwhitehorn#if R128_FIFO_DEBUG
96209975Snwhitehornstatic void r128_status(drm_r128_private_t * dev_priv)
97209975Snwhitehorn{
98209975Snwhitehorn	printk("GUI_STAT           = 0x%08x\n",
99209975Snwhitehorn	       (unsigned int)R128_READ(R128_GUI_STAT));
100209975Snwhitehorn	printk("PM4_STAT           = 0x%08x\n",
101209975Snwhitehorn	       (unsigned int)R128_READ(R128_PM4_STAT));
102209975Snwhitehorn	printk("PM4_BUFFER_DL_WPTR = 0x%08x\n",
103209975Snwhitehorn	       (unsigned int)R128_READ(R128_PM4_BUFFER_DL_WPTR));
104209975Snwhitehorn	printk("PM4_BUFFER_DL_RPTR = 0x%08x\n",
105209975Snwhitehorn	       (unsigned int)R128_READ(R128_PM4_BUFFER_DL_RPTR));
106209975Snwhitehorn	printk("PM4_MICRO_CNTL     = 0x%08x\n",
107209975Snwhitehorn	       (unsigned int)R128_READ(R128_PM4_MICRO_CNTL));
108209975Snwhitehorn	printk("PM4_BUFFER_CNTL    = 0x%08x\n",
109209975Snwhitehorn	       (unsigned int)R128_READ(R128_PM4_BUFFER_CNTL));
110209975Snwhitehorn}
111209975Snwhitehorn#endif
112118893Sgrehan
11391486Sbenno/* ================================================================
114209975Snwhitehorn * Engine, FIFO control
11591486Sbenno */
116209975Snwhitehorn
117209975Snwhitehornstatic int r128_do_pixcache_flush(drm_r128_private_t * dev_priv)
118209975Snwhitehorn{
119209975Snwhitehorn	u32 tmp;
120118893Sgrehan	int i;
121223485Snwhitehorn
122198723Snwhitehorn	tmp = R128_READ(R128_PC_NGUI_CTLSTAT) | R128_PC_FLUSH_ALL;
123198731Snwhitehorn	R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp);
124118893Sgrehan
125209975Snwhitehorn	for (i = 0; i < dev_priv->usec_timeout; i++) {
126209975Snwhitehorn		if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY)) {
127198731Snwhitehorn			return 0;
128178628Smarcel		}
129198731Snwhitehorn		DRM_UDELAY(1);
13086066Smp	}
131218824Snwhitehorn
132209975Snwhitehorn#if R128_FIFO_DEBUG
133188860Snwhitehorn	DRM_ERROR("failed!\n");
134188860Snwhitehorn#endif
135198731Snwhitehorn	return -EBUSY;
136198731Snwhitehorn}
137188860Snwhitehorn
138198731Snwhitehornstatic int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries)
139188860Snwhitehorn{
140218824Snwhitehorn	int i;
141209975Snwhitehorn
142188860Snwhitehorn	for (i = 0; i < dev_priv->usec_timeout; i++) {
143188860Snwhitehorn		int slots = R128_READ(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK;
144118893Sgrehan		if (slots >= entries)
145218824Snwhitehorn			return 0;
146209975Snwhitehorn		DRM_UDELAY(1);
14791486Sbenno	}
148234517Snwhitehorn
149209975Snwhitehorn#if R128_FIFO_DEBUG
150178628Smarcel	DRM_ERROR("failed!\n");
151198723Snwhitehorn#endif
152198723Snwhitehorn	return -EBUSY;
153277335Snwhitehorn}
154198723Snwhitehorn
155223485Snwhitehornstatic int r128_do_wait_for_idle(drm_r128_private_t * dev_priv)
156209975Snwhitehorn{
157235013Snwhitehorn	int i, ret;
158235013Snwhitehorn
159198723Snwhitehorn	ret = r128_do_wait_for_fifo(dev_priv, 64);
160278429Snwhitehorn	if (ret)
161278429Snwhitehorn		return ret;
162278429Snwhitehorn
163198723Snwhitehorn	for (i = 0; i < dev_priv->usec_timeout; i++) {
164278429Snwhitehorn		if (!(R128_READ(R128_GUI_STAT) & R128_GUI_ACTIVE)) {
165278429Snwhitehorn			r128_do_pixcache_flush(dev_priv);
166278429Snwhitehorn			return 0;
167278429Snwhitehorn		}
168278429Snwhitehorn		DRM_UDELAY(1);
169278429Snwhitehorn	}
170223485Snwhitehorn
171223485Snwhitehorn#if R128_FIFO_DEBUG
172209975Snwhitehorn	DRM_ERROR("failed!\n");
17377957Sbenno#endif
174223485Snwhitehorn	return -EBUSY;
175218824Snwhitehorn}
176209975Snwhitehorn
177183088Smarcel/* ================================================================
178178628Smarcel * CCE control, initialization
179178628Smarcel */
180118893Sgrehan
181188860Snwhitehorn/* Load the microcode for the CCE */
182223485Snwhitehornstatic void r128_cce_load_microcode(drm_r128_private_t * dev_priv)
183218824Snwhitehorn{
184209975Snwhitehorn	int i;
18586066Smp
186188860Snwhitehorn	DRM_DEBUG("\n");
187188860Snwhitehorn
188188860Snwhitehorn	r128_do_wait_for_idle(dev_priv);
189188860Snwhitehorn
190188860Snwhitehorn	R128_WRITE(R128_PM4_MICROCODE_ADDR, 0);
191223485Snwhitehorn	for (i = 0; i < 256; i++) {
192218824Snwhitehorn		R128_WRITE(R128_PM4_MICROCODE_DATAH, r128_cce_microcode[i * 2]);
193209975Snwhitehorn		R128_WRITE(R128_PM4_MICROCODE_DATAL,
194188860Snwhitehorn			   r128_cce_microcode[i * 2 + 1]);
19599036Sbenno	}
196188860Snwhitehorn}
197209975Snwhitehorn
198118893Sgrehan/* Flush any pending commands to the CCE.  This should only be used just
199209975Snwhitehorn * prior to a wait for idle, as it informs the engine that the command
200209975Snwhitehorn * stream is ending.
201209975Snwhitehorn */
202209975Snwhitehornstatic void r128_do_cce_flush(drm_r128_private_t * dev_priv)
203209975Snwhitehorn{
204209975Snwhitehorn	u32 tmp;
205209975Snwhitehorn
206209975Snwhitehorn	tmp = R128_READ(R128_PM4_BUFFER_DL_WPTR) | R128_PM4_BUFFER_DL_DONE;
207209975Snwhitehorn	R128_WRITE(R128_PM4_BUFFER_DL_WPTR, tmp);
208209975Snwhitehorn}
209209975Snwhitehorn
210209975Snwhitehorn/* Wait for the CCE to go idle.
211209975Snwhitehorn */
212209975Snwhitehornint r128_do_cce_idle(drm_r128_private_t * dev_priv)
213209975Snwhitehorn{
214209975Snwhitehorn	int i;
215209975Snwhitehorn
216209975Snwhitehorn	for (i = 0; i < dev_priv->usec_timeout; i++) {
217209975Snwhitehorn		if (GET_RING_HEAD(dev_priv) == dev_priv->ring.tail) {
218209975Snwhitehorn			int pm4stat = R128_READ(R128_PM4_STAT);
21984945Smp			if (((pm4stat & R128_PM4_FIFOCNT_MASK) >=
220209975Snwhitehorn			     dev_priv->cce_fifo_size) &&
22191486Sbenno			    !(pm4stat & (R128_PM4_BUSY |
222209975Snwhitehorn					 R128_PM4_GUI_ACTIVE))) {
223209975Snwhitehorn				return r128_do_pixcache_flush(dev_priv);
224209975Snwhitehorn			}
225190704Smarcel		}
226209975Snwhitehorn		DRM_UDELAY(1);
227190704Smarcel	}
228209975Snwhitehorn
229190704Smarcel#if R128_FIFO_DEBUG
230209975Snwhitehorn	DRM_ERROR("failed!\n");
23177957Sbenno	r128_status(dev_priv);
23277957Sbenno#endif
23377957Sbenno	return -EBUSY;
23484945Smp}
23584945Smp
23677957Sbenno/* Start the Concurrent Command Engine.
237231019Sandreast */
238209975Snwhitehornstatic void r128_do_cce_start(drm_r128_private_t * dev_priv)
239209975Snwhitehorn{
240209975Snwhitehorn	r128_do_wait_for_idle(dev_priv);
241209975Snwhitehorn
242209975Snwhitehorn	R128_WRITE(R128_PM4_BUFFER_CNTL,
243209975Snwhitehorn		   dev_priv->cce_mode | dev_priv->ring.size_l2qw
244209975Snwhitehorn		   | R128_PM4_BUFFER_CNTL_NOUPDATE);
245209975Snwhitehorn	R128_READ(R128_PM4_BUFFER_ADDR);	/* as per the sample code */
246209975Snwhitehorn	R128_WRITE(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN);
247209975Snwhitehorn
248209975Snwhitehorn	dev_priv->cce_running = 1;
249209975Snwhitehorn}
250209975Snwhitehorn
251209975Snwhitehorn/* Reset the Concurrent Command Engine.  This will not flush any pending
252209975Snwhitehorn * commands, so you must wait for the CCE command stream to complete
253209975Snwhitehorn * before calling this routine.
254209975Snwhitehorn */
255209975Snwhitehornstatic void r128_do_cce_reset(drm_r128_private_t * dev_priv)
256209975Snwhitehorn{
257209975Snwhitehorn	R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
258209975Snwhitehorn	R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
25984945Smp	dev_priv->ring.tail = 0;
260209975Snwhitehorn}
261209975Snwhitehorn
262288909Sjhibbits/* Stop the Concurrent Command Engine.  This will not flush any pending
263288909Sjhibbits * commands, so you must flush the command stream and wait for the CCE
26477957Sbenno * to go idle before calling this routine.
26591467Sbenno */
26691467Sbennostatic void r128_do_cce_stop(drm_r128_private_t * dev_priv)
26791467Sbenno{
26891467Sbenno	R128_WRITE(R128_PM4_MICRO_CNTL, 0);
26991467Sbenno	R128_WRITE(R128_PM4_BUFFER_CNTL,
270230400Sandreast		   R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE);
271230400Sandreast
272209975Snwhitehorn	dev_priv->cce_running = 0;
273209975Snwhitehorn}
274209975Snwhitehorn
275209975Snwhitehorn/* Reset the engine.  This will stop the CCE if it is running.
276209975Snwhitehorn */
277218824Snwhitehornstatic int r128_do_engine_reset(struct drm_device * dev)
278209975Snwhitehorn{
279209975Snwhitehorn	drm_r128_private_t *dev_priv = dev->dev_private;
280132520Sgrehan	u32 clock_cntl_index, mclk_cntl, gen_reset_cntl;
281132520Sgrehan
282132520Sgrehan	r128_do_pixcache_flush(dev_priv);
28395719Sbenno
284209975Snwhitehorn	clock_cntl_index = R128_READ(R128_CLOCK_CNTL_INDEX);
285	mclk_cntl = R128_READ_PLL(dev, R128_MCLK_CNTL);
286
287	R128_WRITE_PLL(R128_MCLK_CNTL,
288		       mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP);
289
290	gen_reset_cntl = R128_READ(R128_GEN_RESET_CNTL);
291
292	/* Taken from the sample code - do not change */
293	R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI);
294	R128_READ(R128_GEN_RESET_CNTL);
295	R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl & ~R128_SOFT_RESET_GUI);
296	R128_READ(R128_GEN_RESET_CNTL);
297
298	R128_WRITE_PLL(R128_MCLK_CNTL, mclk_cntl);
299	R128_WRITE(R128_CLOCK_CNTL_INDEX, clock_cntl_index);
300	R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl);
301
302	/* Reset the CCE ring */
303	r128_do_cce_reset(dev_priv);
304
305	/* The CCE is no longer running after an engine reset */
306	dev_priv->cce_running = 0;
307
308	/* Reset any pending vertex, indirect buffers */
309	r128_freelist_reset(dev);
310
311	return 0;
312}
313
314static void r128_cce_init_ring_buffer(struct drm_device * dev,
315				      drm_r128_private_t * dev_priv)
316{
317	u32 ring_start;
318	u32 tmp;
319
320	DRM_DEBUG("\n");
321
322	/* The manual (p. 2) says this address is in "VM space".  This
323	 * means it's an offset from the start of AGP space.
324	 */
325#if __OS_HAS_AGP
326	if (!dev_priv->is_pci)
327		ring_start = dev_priv->cce_ring->offset - dev->agp->base;
328	else
329#endif
330		ring_start = dev_priv->cce_ring->offset -
331				(unsigned long)dev->sg->virtual;
332
333	R128_WRITE(R128_PM4_BUFFER_OFFSET, ring_start | R128_AGP_OFFSET);
334
335	R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
336	R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
337
338	/* Set watermark control */
339	R128_WRITE(R128_PM4_BUFFER_WM_CNTL,
340		   ((R128_WATERMARK_L / 4) << R128_WMA_SHIFT)
341		   | ((R128_WATERMARK_M / 4) << R128_WMB_SHIFT)
342		   | ((R128_WATERMARK_N / 4) << R128_WMC_SHIFT)
343		   | ((R128_WATERMARK_K / 64) << R128_WB_WM_SHIFT));
344
345	/* Force read.  Why?  Because it's in the examples... */
346	R128_READ(R128_PM4_BUFFER_ADDR);
347
348	/* Turn on bus mastering */
349	tmp = R128_READ(R128_BUS_CNTL) & ~R128_BUS_MASTER_DIS;
350	R128_WRITE(R128_BUS_CNTL, tmp);
351}
352
353static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
354{
355	drm_r128_private_t *dev_priv;
356
357	DRM_DEBUG("\n");
358
359	dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER);
360	if (dev_priv == NULL)
361		return -ENOMEM;
362
363	memset(dev_priv, 0, sizeof(drm_r128_private_t));
364
365	dev_priv->is_pci = init->is_pci;
366
367	if (dev_priv->is_pci && !dev->sg) {
368		DRM_ERROR("PCI GART memory not allocated!\n");
369		dev->dev_private = (void *)dev_priv;
370		r128_do_cleanup_cce(dev);
371		return -EINVAL;
372	}
373
374	dev_priv->usec_timeout = init->usec_timeout;
375	if (dev_priv->usec_timeout < 1 ||
376	    dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) {
377		DRM_DEBUG("TIMEOUT problem!\n");
378		dev->dev_private = (void *)dev_priv;
379		r128_do_cleanup_cce(dev);
380		return -EINVAL;
381	}
382
383	dev_priv->cce_mode = init->cce_mode;
384
385	/* GH: Simple idle check.
386	 */
387	atomic_set(&dev_priv->idle_count, 0);
388
389	/* We don't support anything other than bus-mastering ring mode,
390	 * but the ring can be in either AGP or PCI space for the ring
391	 * read pointer.
392	 */
393	if ((init->cce_mode != R128_PM4_192BM) &&
394	    (init->cce_mode != R128_PM4_128BM_64INDBM) &&
395	    (init->cce_mode != R128_PM4_64BM_128INDBM) &&
396	    (init->cce_mode != R128_PM4_64BM_64VCBM_64INDBM)) {
397		DRM_DEBUG("Bad cce_mode!\n");
398		dev->dev_private = (void *)dev_priv;
399		r128_do_cleanup_cce(dev);
400		return -EINVAL;
401	}
402
403	switch (init->cce_mode) {
404	case R128_PM4_NONPM4:
405		dev_priv->cce_fifo_size = 0;
406		break;
407	case R128_PM4_192PIO:
408	case R128_PM4_192BM:
409		dev_priv->cce_fifo_size = 192;
410		break;
411	case R128_PM4_128PIO_64INDBM:
412	case R128_PM4_128BM_64INDBM:
413		dev_priv->cce_fifo_size = 128;
414		break;
415	case R128_PM4_64PIO_128INDBM:
416	case R128_PM4_64BM_128INDBM:
417	case R128_PM4_64PIO_64VCBM_64INDBM:
418	case R128_PM4_64BM_64VCBM_64INDBM:
419	case R128_PM4_64PIO_64VCPIO_64INDPIO:
420		dev_priv->cce_fifo_size = 64;
421		break;
422	}
423
424	switch (init->fb_bpp) {
425	case 16:
426		dev_priv->color_fmt = R128_DATATYPE_RGB565;
427		break;
428	case 32:
429	default:
430		dev_priv->color_fmt = R128_DATATYPE_ARGB8888;
431		break;
432	}
433	dev_priv->front_offset = init->front_offset;
434	dev_priv->front_pitch = init->front_pitch;
435	dev_priv->back_offset = init->back_offset;
436	dev_priv->back_pitch = init->back_pitch;
437
438	switch (init->depth_bpp) {
439	case 16:
440		dev_priv->depth_fmt = R128_DATATYPE_RGB565;
441		break;
442	case 24:
443	case 32:
444	default:
445		dev_priv->depth_fmt = R128_DATATYPE_ARGB8888;
446		break;
447	}
448	dev_priv->depth_offset = init->depth_offset;
449	dev_priv->depth_pitch = init->depth_pitch;
450	dev_priv->span_offset = init->span_offset;
451
452	dev_priv->front_pitch_offset_c = (((dev_priv->front_pitch / 8) << 21) |
453					  (dev_priv->front_offset >> 5));
454	dev_priv->back_pitch_offset_c = (((dev_priv->back_pitch / 8) << 21) |
455					 (dev_priv->back_offset >> 5));
456	dev_priv->depth_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
457					  (dev_priv->depth_offset >> 5) |
458					  R128_DST_TILE);
459	dev_priv->span_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
460					 (dev_priv->span_offset >> 5));
461
462	dev_priv->sarea = drm_getsarea(dev);
463	if (!dev_priv->sarea) {
464		DRM_ERROR("could not find sarea!\n");
465		dev->dev_private = (void *)dev_priv;
466		r128_do_cleanup_cce(dev);
467		return -EINVAL;
468	}
469
470	dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
471	if (!dev_priv->mmio) {
472		DRM_ERROR("could not find mmio region!\n");
473		dev->dev_private = (void *)dev_priv;
474		r128_do_cleanup_cce(dev);
475		return -EINVAL;
476	}
477	dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset);
478	if (!dev_priv->cce_ring) {
479		DRM_ERROR("could not find cce ring region!\n");
480		dev->dev_private = (void *)dev_priv;
481		r128_do_cleanup_cce(dev);
482		return -EINVAL;
483	}
484	dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
485	if (!dev_priv->ring_rptr) {
486		DRM_ERROR("could not find ring read pointer!\n");
487		dev->dev_private = (void *)dev_priv;
488		r128_do_cleanup_cce(dev);
489		return -EINVAL;
490	}
491	dev->agp_buffer_token = init->buffers_offset;
492	dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
493	if (!dev->agp_buffer_map) {
494		DRM_ERROR("could not find dma buffer region!\n");
495		dev->dev_private = (void *)dev_priv;
496		r128_do_cleanup_cce(dev);
497		return -EINVAL;
498	}
499
500	if (!dev_priv->is_pci) {
501		dev_priv->agp_textures =
502		    drm_core_findmap(dev, init->agp_textures_offset);
503		if (!dev_priv->agp_textures) {
504			DRM_ERROR("could not find agp texture region!\n");
505			dev->dev_private = (void *)dev_priv;
506			r128_do_cleanup_cce(dev);
507			return -EINVAL;
508		}
509	}
510
511	dev_priv->sarea_priv =
512	    (drm_r128_sarea_t *) ((u8 *) dev_priv->sarea->handle +
513				  init->sarea_priv_offset);
514
515#if __OS_HAS_AGP
516	if (!dev_priv->is_pci) {
517		drm_core_ioremap(dev_priv->cce_ring, dev);
518		drm_core_ioremap(dev_priv->ring_rptr, dev);
519		drm_core_ioremap(dev->agp_buffer_map, dev);
520		if (!dev_priv->cce_ring->handle ||
521		    !dev_priv->ring_rptr->handle ||
522		    !dev->agp_buffer_map->handle) {
523			DRM_ERROR("Could not ioremap agp regions!\n");
524			dev->dev_private = (void *)dev_priv;
525			r128_do_cleanup_cce(dev);
526			return -ENOMEM;
527		}
528	} else
529#endif
530	{
531		dev_priv->cce_ring->handle = (void *)dev_priv->cce_ring->offset;
532		dev_priv->ring_rptr->handle =
533		    (void *)dev_priv->ring_rptr->offset;
534		dev->agp_buffer_map->handle =
535		    (void *)dev->agp_buffer_map->offset;
536	}
537
538#if __OS_HAS_AGP
539	if (!dev_priv->is_pci)
540		dev_priv->cce_buffers_offset = dev->agp->base;
541	else
542#endif
543		dev_priv->cce_buffers_offset = (unsigned long)dev->sg->virtual;
544
545	dev_priv->ring.start = (u32 *) dev_priv->cce_ring->handle;
546	dev_priv->ring.end = ((u32 *) dev_priv->cce_ring->handle
547			      + init->ring_size / sizeof(u32));
548	dev_priv->ring.size = init->ring_size;
549	dev_priv->ring.size_l2qw = drm_order(init->ring_size / 8);
550
551	dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
552
553	dev_priv->ring.high_mark = 128;
554
555	dev_priv->sarea_priv->last_frame = 0;
556	R128_WRITE(R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
557
558	dev_priv->sarea_priv->last_dispatch = 0;
559	R128_WRITE(R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch);
560
561#if __OS_HAS_AGP
562	if (dev_priv->is_pci) {
563#endif
564		dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
565		dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;
566		dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE;
567		dev_priv->gart_info.addr = NULL;
568		dev_priv->gart_info.bus_addr = 0;
569		dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
570		if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
571			DRM_ERROR("failed to init PCI GART!\n");
572			dev->dev_private = (void *)dev_priv;
573			r128_do_cleanup_cce(dev);
574			return -ENOMEM;
575		}
576		R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr);
577#if __OS_HAS_AGP
578	}
579#endif
580
581	r128_cce_init_ring_buffer(dev, dev_priv);
582	r128_cce_load_microcode(dev_priv);
583
584	dev->dev_private = (void *)dev_priv;
585
586	r128_do_engine_reset(dev);
587
588	return 0;
589}
590
591int r128_do_cleanup_cce(struct drm_device * dev)
592{
593
594	/* Make sure interrupts are disabled here because the uninstall ioctl
595	 * may not have been called from userspace and after dev_private
596	 * is freed, it's too late.
597	 */
598	if (dev->irq_enabled)
599		drm_irq_uninstall(dev);
600
601	if (dev->dev_private) {
602		drm_r128_private_t *dev_priv = dev->dev_private;
603
604#if __OS_HAS_AGP
605		if (!dev_priv->is_pci) {
606			if (dev_priv->cce_ring != NULL)
607				drm_core_ioremapfree(dev_priv->cce_ring, dev);
608			if (dev_priv->ring_rptr != NULL)
609				drm_core_ioremapfree(dev_priv->ring_rptr, dev);
610			if (dev->agp_buffer_map != NULL) {
611				drm_core_ioremapfree(dev->agp_buffer_map, dev);
612				dev->agp_buffer_map = NULL;
613			}
614		} else
615#endif
616		{
617			if (dev_priv->gart_info.bus_addr)
618				if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info))
619					DRM_ERROR("failed to cleanup PCI GART!\n");
620		}
621
622		drm_free(dev->dev_private, sizeof(drm_r128_private_t),
623			 DRM_MEM_DRIVER);
624		dev->dev_private = NULL;
625	}
626
627	return 0;
628}
629
630int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
631{
632	drm_r128_init_t *init = data;
633
634	DRM_DEBUG("\n");
635
636	LOCK_TEST_WITH_RETURN(dev, file_priv);
637
638	switch (init->func) {
639	case R128_INIT_CCE:
640		return r128_do_init_cce(dev, init);
641	case R128_CLEANUP_CCE:
642		return r128_do_cleanup_cce(dev);
643	}
644
645	return -EINVAL;
646}
647
648int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
649{
650	drm_r128_private_t *dev_priv = dev->dev_private;
651	DRM_DEBUG("\n");
652
653	LOCK_TEST_WITH_RETURN(dev, file_priv);
654
655	if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) {
656		DRM_DEBUG("while CCE running\n");
657		return 0;
658	}
659
660	r128_do_cce_start(dev_priv);
661
662	return 0;
663}
664
665/* Stop the CCE.  The engine must have been idled before calling this
666 * routine.
667 */
668int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
669{
670	drm_r128_private_t *dev_priv = dev->dev_private;
671	drm_r128_cce_stop_t *stop = data;
672	int ret;
673	DRM_DEBUG("\n");
674
675	LOCK_TEST_WITH_RETURN(dev, file_priv);
676
677	/* Flush any pending CCE commands.  This ensures any outstanding
678	 * commands are exectuted by the engine before we turn it off.
679	 */
680	if (stop->flush) {
681		r128_do_cce_flush(dev_priv);
682	}
683
684	/* If we fail to make the engine go idle, we return an error
685	 * code so that the DRM ioctl wrapper can try again.
686	 */
687	if (stop->idle) {
688		ret = r128_do_cce_idle(dev_priv);
689		if (ret)
690			return ret;
691	}
692
693	/* Finally, we can turn off the CCE.  If the engine isn't idle,
694	 * we will get some dropped triangles as they won't be fully
695	 * rendered before the CCE is shut down.
696	 */
697	r128_do_cce_stop(dev_priv);
698
699	/* Reset the engine */
700	r128_do_engine_reset(dev);
701
702	return 0;
703}
704
705/* Just reset the CCE ring.  Called as part of an X Server engine reset.
706 */
707int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
708{
709	drm_r128_private_t *dev_priv = dev->dev_private;
710	DRM_DEBUG("\n");
711
712	LOCK_TEST_WITH_RETURN(dev, file_priv);
713
714	if (!dev_priv) {
715		DRM_DEBUG("called before init done\n");
716		return -EINVAL;
717	}
718
719	r128_do_cce_reset(dev_priv);
720
721	/* The CCE is no longer running after an engine reset */
722	dev_priv->cce_running = 0;
723
724	return 0;
725}
726
727int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
728{
729	drm_r128_private_t *dev_priv = dev->dev_private;
730	DRM_DEBUG("\n");
731
732	LOCK_TEST_WITH_RETURN(dev, file_priv);
733
734	if (dev_priv->cce_running) {
735		r128_do_cce_flush(dev_priv);
736	}
737
738	return r128_do_cce_idle(dev_priv);
739}
740
741int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
742{
743	DRM_DEBUG("\n");
744
745	LOCK_TEST_WITH_RETURN(dev, file_priv);
746
747	return r128_do_engine_reset(dev);
748}
749
750int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
751{
752	return -EINVAL;
753}
754
755/* ================================================================
756 * Freelist management
757 */
758#define R128_BUFFER_USED	0xffffffff
759#define R128_BUFFER_FREE	0
760
761#if 0
762static int r128_freelist_init(struct drm_device * dev)
763{
764	struct drm_device_dma *dma = dev->dma;
765	drm_r128_private_t *dev_priv = dev->dev_private;
766	struct drm_buf *buf;
767	drm_r128_buf_priv_t *buf_priv;
768	drm_r128_freelist_t *entry;
769	int i;
770
771	dev_priv->head = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);
772	if (dev_priv->head == NULL)
773		return -ENOMEM;
774
775	memset(dev_priv->head, 0, sizeof(drm_r128_freelist_t));
776	dev_priv->head->age = R128_BUFFER_USED;
777
778	for (i = 0; i < dma->buf_count; i++) {
779		buf = dma->buflist[i];
780		buf_priv = buf->dev_private;
781
782		entry = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);
783		if (!entry)
784			return -ENOMEM;
785
786		entry->age = R128_BUFFER_FREE;
787		entry->buf = buf;
788		entry->prev = dev_priv->head;
789		entry->next = dev_priv->head->next;
790		if (!entry->next)
791			dev_priv->tail = entry;
792
793		buf_priv->discard = 0;
794		buf_priv->dispatched = 0;
795		buf_priv->list_entry = entry;
796
797		dev_priv->head->next = entry;
798
799		if (dev_priv->head->next)
800			dev_priv->head->next->prev = entry;
801	}
802
803	return 0;
804
805}
806#endif
807
808static struct drm_buf *r128_freelist_get(struct drm_device * dev)
809{
810	struct drm_device_dma *dma = dev->dma;
811	drm_r128_private_t *dev_priv = dev->dev_private;
812	drm_r128_buf_priv_t *buf_priv;
813	struct drm_buf *buf;
814	int i, t;
815
816	/* FIXME: Optimize -- use freelist code */
817
818	for (i = 0; i < dma->buf_count; i++) {
819		buf = dma->buflist[i];
820		buf_priv = buf->dev_private;
821		if (buf->file_priv == 0)
822			return buf;
823	}
824
825	for (t = 0; t < dev_priv->usec_timeout; t++) {
826		u32 done_age = R128_READ(R128_LAST_DISPATCH_REG);
827
828		for (i = 0; i < dma->buf_count; i++) {
829			buf = dma->buflist[i];
830			buf_priv = buf->dev_private;
831			if (buf->pending && buf_priv->age <= done_age) {
832				/* The buffer has been processed, so it
833				 * can now be used.
834				 */
835				buf->pending = 0;
836				return buf;
837			}
838		}
839		DRM_UDELAY(1);
840	}
841
842	DRM_DEBUG("returning NULL!\n");
843	return NULL;
844}
845
846void r128_freelist_reset(struct drm_device * dev)
847{
848	struct drm_device_dma *dma = dev->dma;
849	int i;
850
851	for (i = 0; i < dma->buf_count; i++) {
852		struct drm_buf *buf = dma->buflist[i];
853		drm_r128_buf_priv_t *buf_priv = buf->dev_private;
854		buf_priv->age = 0;
855	}
856}
857
858/* ================================================================
859 * CCE command submission
860 */
861
862int r128_wait_ring(drm_r128_private_t * dev_priv, int n)
863{
864	drm_r128_ring_buffer_t *ring = &dev_priv->ring;
865	int i;
866
867	for (i = 0; i < dev_priv->usec_timeout; i++) {
868		r128_update_ring_snapshot(dev_priv);
869		if (ring->space >= n)
870			return 0;
871		DRM_UDELAY(1);
872	}
873
874	/* FIXME: This is being ignored... */
875	DRM_ERROR("failed!\n");
876	return -EBUSY;
877}
878
879static int r128_cce_get_buffers(struct drm_device * dev,
880				struct drm_file *file_priv,
881				struct drm_dma * d)
882{
883	int i;
884	struct drm_buf *buf;
885
886	for (i = d->granted_count; i < d->request_count; i++) {
887		buf = r128_freelist_get(dev);
888		if (!buf)
889			return -EAGAIN;
890
891		buf->file_priv = file_priv;
892
893		if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
894				     sizeof(buf->idx)))
895			return -EFAULT;
896		if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
897				     sizeof(buf->total)))
898			return -EFAULT;
899
900		d->granted_count++;
901	}
902	return 0;
903}
904
905int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
906{
907	struct drm_device_dma *dma = dev->dma;
908	int ret = 0;
909	struct drm_dma *d = data;
910
911	LOCK_TEST_WITH_RETURN(dev, file_priv);
912
913	/* Please don't send us buffers.
914	 */
915	if (d->send_count != 0) {
916		DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
917			  DRM_CURRENTPID, d->send_count);
918		return -EINVAL;
919	}
920
921	/* We'll send you buffers.
922	 */
923	if (d->request_count < 0 || d->request_count > dma->buf_count) {
924		DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
925			  DRM_CURRENTPID, d->request_count, dma->buf_count);
926		return -EINVAL;
927	}
928
929	d->granted_count = 0;
930
931	if (d->request_count) {
932		ret = r128_cce_get_buffers(dev, file_priv, d);
933	}
934
935	return ret;
936}
937