radeon_cp.c 46.7 KB
Newer Older
1 2
/* radeon_cp.c -- CP support for Radeon -*- linux-c -*- */
/*
L
Linus Torvalds 已提交
3 4
 * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
 * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
5
 * Copyright 2007 Advanced Micro Devices, Inc.
L
Linus Torvalds 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Authors:
 *    Kevin E. Martin <martin@valinux.com>
 *    Gareth Hughes <gareth@valinux.com>
 */

#include "drmP.h"
#include "drm.h"
#include "radeon_drm.h"
#include "radeon_drv.h"
D
Dave Airlie 已提交
36
#include "r300_reg.h"
L
Linus Torvalds 已提交
37

38 39
#include "radeon_microcode.h"

L
Linus Torvalds 已提交
40 41
#define RADEON_FIFO_DEBUG	0

42
static int radeon_do_cleanup_cp(struct drm_device * dev);
L
Linus Torvalds 已提交
43

44
static u32 R500_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
D
Dave Airlie 已提交
45 46 47 48 49 50 51 52
{
	u32 ret;
	RADEON_WRITE(R520_MC_IND_INDEX, 0x7f0000 | (addr & 0xff));
	ret = RADEON_READ(R520_MC_IND_DATA);
	RADEON_WRITE(R520_MC_IND_INDEX, 0);
	return ret;
}

53 54 55 56 57 58 59 60 61
static u32 RS480_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
{
	u32 ret;
	RADEON_WRITE(RS480_NB_MC_INDEX, addr & 0xff);
	ret = RADEON_READ(RS480_NB_MC_DATA);
	RADEON_WRITE(RS480_NB_MC_INDEX, 0xff);
	return ret;
}

62 63
static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
{
64
	u32 ret;
65
	RADEON_WRITE(RS690_MC_INDEX, (addr & RS690_MC_INDEX_MASK));
66 67 68 69 70 71 72 73 74 75 76
	ret = RADEON_READ(RS690_MC_DATA);
	RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_MASK);
	return ret;
}

static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
{
	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
		return RS690_READ_MCIND(dev_priv, addr);
	else
		return RS480_READ_MCIND(dev_priv, addr);
77 78
}

D
Dave Airlie 已提交
79 80 81 82
u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
{

	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
83
		return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
84 85
	else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
		return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION);
D
Dave Airlie 已提交
86
	else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
87
		return R500_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
D
Dave Airlie 已提交
88 89 90 91 92 93 94
	else
		return RADEON_READ(RADEON_MC_FB_LOCATION);
}

static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
{
	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
95
		R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
96 97
	else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
		RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc);
D
Dave Airlie 已提交
98
	else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
99
		R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
D
Dave Airlie 已提交
100 101 102 103 104 105 106
	else
		RADEON_WRITE(RADEON_MC_FB_LOCATION, fb_loc);
}

static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc)
{
	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
107
		R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
108 109
	else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
		RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc);
D
Dave Airlie 已提交
110
	else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
111
		R500_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
D
Dave Airlie 已提交
112 113 114 115
	else
		RADEON_WRITE(RADEON_MC_AGP_LOCATION, agp_loc);
}

116
static int RADEON_READ_PLL(struct drm_device * dev, int addr)
L
Linus Torvalds 已提交
117 118 119 120 121 122 123
{
	drm_radeon_private_t *dev_priv = dev->dev_private;

	RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, addr & 0x1f);
	return RADEON_READ(RADEON_CLOCK_CNTL_DATA);
}

D
Dave Airlie 已提交
124
static u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr)
125 126 127 128 129
{
	RADEON_WRITE8(RADEON_PCIE_INDEX, addr & 0xff);
	return RADEON_READ(RADEON_PCIE_DATA);
}

L
Linus Torvalds 已提交
130
#if RADEON_FIFO_DEBUG
D
Dave Airlie 已提交
131
static void radeon_status(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
132
{
133
	printk("%s:\n", __func__);
D
Dave Airlie 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
	printk("RBBM_STATUS = 0x%08x\n",
	       (unsigned int)RADEON_READ(RADEON_RBBM_STATUS));
	printk("CP_RB_RTPR = 0x%08x\n",
	       (unsigned int)RADEON_READ(RADEON_CP_RB_RPTR));
	printk("CP_RB_WTPR = 0x%08x\n",
	       (unsigned int)RADEON_READ(RADEON_CP_RB_WPTR));
	printk("AIC_CNTL = 0x%08x\n",
	       (unsigned int)RADEON_READ(RADEON_AIC_CNTL));
	printk("AIC_STAT = 0x%08x\n",
	       (unsigned int)RADEON_READ(RADEON_AIC_STAT));
	printk("AIC_PT_BASE = 0x%08x\n",
	       (unsigned int)RADEON_READ(RADEON_AIC_PT_BASE));
	printk("TLB_ADDR = 0x%08x\n",
	       (unsigned int)RADEON_READ(RADEON_AIC_TLB_ADDR));
	printk("TLB_DATA = 0x%08x\n",
	       (unsigned int)RADEON_READ(RADEON_AIC_TLB_DATA));
L
Linus Torvalds 已提交
150 151 152 153 154 155 156
}
#endif

/* ================================================================
 * Engine, FIFO control
 */

D
Dave Airlie 已提交
157
static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
158 159 160 161 162 163
{
	u32 tmp;
	int i;

	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;

164 165 166
	tmp = RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT);
	tmp |= RADEON_RB3D_DC_FLUSH_ALL;
	RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp);
L
Linus Torvalds 已提交
167

D
Dave Airlie 已提交
168
	for (i = 0; i < dev_priv->usec_timeout; i++) {
169 170
		if (!(RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT)
		      & RADEON_RB3D_DC_BUSY)) {
L
Linus Torvalds 已提交
171 172
			return 0;
		}
D
Dave Airlie 已提交
173
		DRM_UDELAY(1);
L
Linus Torvalds 已提交
174 175 176
	}

#if RADEON_FIFO_DEBUG
D
Dave Airlie 已提交
177 178
	DRM_ERROR("failed!\n");
	radeon_status(dev_priv);
L
Linus Torvalds 已提交
179
#endif
E
Eric Anholt 已提交
180
	return -EBUSY;
L
Linus Torvalds 已提交
181 182
}

D
Dave Airlie 已提交
183
static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries)
L
Linus Torvalds 已提交
184 185 186 187 188
{
	int i;

	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;

D
Dave Airlie 已提交
189 190 191 192 193 194
	for (i = 0; i < dev_priv->usec_timeout; i++) {
		int slots = (RADEON_READ(RADEON_RBBM_STATUS)
			     & RADEON_RBBM_FIFOCNT_MASK);
		if (slots >= entries)
			return 0;
		DRM_UDELAY(1);
L
Linus Torvalds 已提交
195 196 197
	}

#if RADEON_FIFO_DEBUG
D
Dave Airlie 已提交
198 199
	DRM_ERROR("failed!\n");
	radeon_status(dev_priv);
L
Linus Torvalds 已提交
200
#endif
E
Eric Anholt 已提交
201
	return -EBUSY;
L
Linus Torvalds 已提交
202 203
}

D
Dave Airlie 已提交
204
static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
205 206 207 208 209
{
	int i, ret;

	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;

D
Dave Airlie 已提交
210 211 212
	ret = radeon_do_wait_for_fifo(dev_priv, 64);
	if (ret)
		return ret;
L
Linus Torvalds 已提交
213

D
Dave Airlie 已提交
214 215 216 217
	for (i = 0; i < dev_priv->usec_timeout; i++) {
		if (!(RADEON_READ(RADEON_RBBM_STATUS)
		      & RADEON_RBBM_ACTIVE)) {
			radeon_do_pixcache_flush(dev_priv);
L
Linus Torvalds 已提交
218 219
			return 0;
		}
D
Dave Airlie 已提交
220
		DRM_UDELAY(1);
L
Linus Torvalds 已提交
221 222 223
	}

#if RADEON_FIFO_DEBUG
D
Dave Airlie 已提交
224 225
	DRM_ERROR("failed!\n");
	radeon_status(dev_priv);
L
Linus Torvalds 已提交
226
#endif
E
Eric Anholt 已提交
227
	return -EBUSY;
L
Linus Torvalds 已提交
228 229 230 231 232 233 234
}

/* ================================================================
 * CP control, initialization
 */

/* Load the microcode for the CP */
D
Dave Airlie 已提交
235
static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
236 237
{
	int i;
D
Dave Airlie 已提交
238
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
239

D
Dave Airlie 已提交
240
	radeon_do_wait_for_idle(dev_priv);
L
Linus Torvalds 已提交
241

D
Dave Airlie 已提交
242
	RADEON_WRITE(RADEON_CP_ME_RAM_ADDR, 0);
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
	if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R100) ||
	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV100) ||
	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV200) ||
	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS100) ||
	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS200)) {
		DRM_INFO("Loading R100 Microcode\n");
		for (i = 0; i < 256; i++) {
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
				     R100_cp_microcode[i][1]);
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
				     R100_cp_microcode[i][0]);
		}
	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R200) ||
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV250) ||
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV280) ||
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS300)) {
L
Linus Torvalds 已提交
259
		DRM_INFO("Loading R200 Microcode\n");
D
Dave Airlie 已提交
260 261 262 263 264
		for (i = 0; i < 256; i++) {
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
				     R200_cp_microcode[i][1]);
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
				     R200_cp_microcode[i][0]);
L
Linus Torvalds 已提交
265
		}
266 267 268 269
	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R300) ||
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350) ||
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV350) ||
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) ||
270
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
L
Linus Torvalds 已提交
271
		DRM_INFO("Loading R300 Microcode\n");
D
Dave Airlie 已提交
272 273 274 275 276
		for (i = 0; i < 256; i++) {
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
				     R300_cp_microcode[i][1]);
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
				     R300_cp_microcode[i][0]);
L
Linus Torvalds 已提交
277
		}
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV410)) {
		DRM_INFO("Loading R400 Microcode\n");
		for (i = 0; i < 256; i++) {
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
				     R420_cp_microcode[i][1]);
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
				     R420_cp_microcode[i][0]);
		}
	} else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
		DRM_INFO("Loading RS690 Microcode\n");
		for (i = 0; i < 256; i++) {
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
				     RS690_cp_microcode[i][1]);
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
				     RS690_cp_microcode[i][0]);
		}
	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) ||
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R520) ||
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530) ||
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R580) ||
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV560) ||
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV570)) {
		DRM_INFO("Loading R500 Microcode\n");
D
Dave Airlie 已提交
302 303
		for (i = 0; i < 256; i++) {
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
304
				     R520_cp_microcode[i][1]);
D
Dave Airlie 已提交
305
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
306
				     R520_cp_microcode[i][0]);
L
Linus Torvalds 已提交
307 308 309 310 311 312 313 314
		}
	}
}

/* Flush any pending commands to the CP.  This should only be used just
 * prior to a wait for idle, as it informs the engine that the command
 * stream is ending.
 */
D
Dave Airlie 已提交
315
static void radeon_do_cp_flush(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
316
{
D
Dave Airlie 已提交
317
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
318 319 320
#if 0
	u32 tmp;

D
Dave Airlie 已提交
321 322
	tmp = RADEON_READ(RADEON_CP_RB_WPTR) | (1 << 31);
	RADEON_WRITE(RADEON_CP_RB_WPTR, tmp);
L
Linus Torvalds 已提交
323 324 325 326 327
#endif
}

/* Wait for the CP to go idle.
 */
D
Dave Airlie 已提交
328
int radeon_do_cp_idle(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
329 330
{
	RING_LOCALS;
D
Dave Airlie 已提交
331
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
332

D
Dave Airlie 已提交
333
	BEGIN_RING(6);
L
Linus Torvalds 已提交
334 335 336 337 338 339 340 341

	RADEON_PURGE_CACHE();
	RADEON_PURGE_ZCACHE();
	RADEON_WAIT_UNTIL_IDLE();

	ADVANCE_RING();
	COMMIT_RING();

D
Dave Airlie 已提交
342
	return radeon_do_wait_for_idle(dev_priv);
L
Linus Torvalds 已提交
343 344 345 346
}

/* Start the Command Processor.
 */
D
Dave Airlie 已提交
347
static void radeon_do_cp_start(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
348 349
{
	RING_LOCALS;
D
Dave Airlie 已提交
350
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
351

D
Dave Airlie 已提交
352
	radeon_do_wait_for_idle(dev_priv);
L
Linus Torvalds 已提交
353

D
Dave Airlie 已提交
354
	RADEON_WRITE(RADEON_CP_CSQ_CNTL, dev_priv->cp_mode);
L
Linus Torvalds 已提交
355 356 357

	dev_priv->cp_running = 1;

D
Dave Airlie 已提交
358
	BEGIN_RING(6);
L
Linus Torvalds 已提交
359 360 361 362 363 364 365 366 367 368 369 370 371

	RADEON_PURGE_CACHE();
	RADEON_PURGE_ZCACHE();
	RADEON_WAIT_UNTIL_IDLE();

	ADVANCE_RING();
	COMMIT_RING();
}

/* Reset the Command Processor.  This will not flush any pending
 * commands, so you must wait for the CP command stream to complete
 * before calling this routine.
 */
D
Dave Airlie 已提交
372
static void radeon_do_cp_reset(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
373 374
{
	u32 cur_read_ptr;
D
Dave Airlie 已提交
375
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
376

D
Dave Airlie 已提交
377 378 379
	cur_read_ptr = RADEON_READ(RADEON_CP_RB_RPTR);
	RADEON_WRITE(RADEON_CP_RB_WPTR, cur_read_ptr);
	SET_RING_HEAD(dev_priv, cur_read_ptr);
L
Linus Torvalds 已提交
380 381 382 383 384 385 386
	dev_priv->ring.tail = cur_read_ptr;
}

/* Stop the Command Processor.  This will not flush any pending
 * commands, so you must flush the command stream and wait for the CP
 * to go idle before calling this routine.
 */
D
Dave Airlie 已提交
387
static void radeon_do_cp_stop(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
388
{
D
Dave Airlie 已提交
389
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
390

D
Dave Airlie 已提交
391
	RADEON_WRITE(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS);
L
Linus Torvalds 已提交
392 393 394 395 396 397

	dev_priv->cp_running = 0;
}

/* Reset the engine.  This will stop the CP if it is running.
 */
398
static int radeon_do_engine_reset(struct drm_device * dev)
L
Linus Torvalds 已提交
399 400 401
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
	u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset;
D
Dave Airlie 已提交
402
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
403

D
Dave Airlie 已提交
404 405
	radeon_do_pixcache_flush(dev_priv);

D
Dave Airlie 已提交
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
	if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_RV515) {
		clock_cntl_index = RADEON_READ(RADEON_CLOCK_CNTL_INDEX);
		mclk_cntl = RADEON_READ_PLL(dev, RADEON_MCLK_CNTL);

		RADEON_WRITE_PLL(RADEON_MCLK_CNTL, (mclk_cntl |
						    RADEON_FORCEON_MCLKA |
						    RADEON_FORCEON_MCLKB |
						    RADEON_FORCEON_YCLKA |
						    RADEON_FORCEON_YCLKB |
						    RADEON_FORCEON_MC |
						    RADEON_FORCEON_AIC));

		rbbm_soft_reset = RADEON_READ(RADEON_RBBM_SOFT_RESET);

		RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset |
						      RADEON_SOFT_RESET_CP |
						      RADEON_SOFT_RESET_HI |
						      RADEON_SOFT_RESET_SE |
						      RADEON_SOFT_RESET_RE |
						      RADEON_SOFT_RESET_PP |
						      RADEON_SOFT_RESET_E2 |
						      RADEON_SOFT_RESET_RB));
		RADEON_READ(RADEON_RBBM_SOFT_RESET);
		RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset &
						      ~(RADEON_SOFT_RESET_CP |
							RADEON_SOFT_RESET_HI |
							RADEON_SOFT_RESET_SE |
							RADEON_SOFT_RESET_RE |
							RADEON_SOFT_RESET_PP |
							RADEON_SOFT_RESET_E2 |
							RADEON_SOFT_RESET_RB)));
		RADEON_READ(RADEON_RBBM_SOFT_RESET);

		RADEON_WRITE_PLL(RADEON_MCLK_CNTL, mclk_cntl);
		RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, clock_cntl_index);
		RADEON_WRITE(RADEON_RBBM_SOFT_RESET, rbbm_soft_reset);
	}
L
Linus Torvalds 已提交
443 444

	/* Reset the CP ring */
D
Dave Airlie 已提交
445
	radeon_do_cp_reset(dev_priv);
L
Linus Torvalds 已提交
446 447 448 449 450

	/* The CP is no longer running after an engine reset */
	dev_priv->cp_running = 0;

	/* Reset any pending vertex, indirect buffers */
D
Dave Airlie 已提交
451
	radeon_freelist_reset(dev);
L
Linus Torvalds 已提交
452 453 454 455

	return 0;
}

456
static void radeon_cp_init_ring_buffer(struct drm_device * dev,
D
Dave Airlie 已提交
457
				       drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
458 459 460
{
	u32 ring_start, cur_read_ptr;
	u32 tmp;
D
Dave Airlie 已提交
461

462 463 464 465 466 467
	/* Initialize the memory controller. With new memory map, the fb location
	 * is not changed, it should have been properly initialized already. Part
	 * of the problem is that the code below is bogus, assuming the GART is
	 * always appended to the fb which is not necessarily the case
	 */
	if (!dev_priv->new_memmap)
D
Dave Airlie 已提交
468
		radeon_write_fb_location(dev_priv,
469 470
			     ((dev_priv->gart_vm_start - 1) & 0xffff0000)
			     | (dev_priv->fb_location >> 16));
L
Linus Torvalds 已提交
471 472

#if __OS_HAS_AGP
473
	if (dev_priv->flags & RADEON_IS_AGP) {
474
		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
475 476
		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R200)
			RADEON_WRITE(RADEON_AGP_BASE_2, 0);
D
Dave Airlie 已提交
477
		radeon_write_agp_location(dev_priv,
D
Dave Airlie 已提交
478 479 480
			     (((dev_priv->gart_vm_start - 1 +
				dev_priv->gart_size) & 0xffff0000) |
			      (dev_priv->gart_vm_start >> 16)));
L
Linus Torvalds 已提交
481 482 483 484

		ring_start = (dev_priv->cp_ring->offset
			      - dev->agp->base
			      + dev_priv->gart_vm_start);
485
	} else
L
Linus Torvalds 已提交
486 487
#endif
		ring_start = (dev_priv->cp_ring->offset
488
			      - (unsigned long)dev->sg->virtual
L
Linus Torvalds 已提交
489 490
			      + dev_priv->gart_vm_start);

D
Dave Airlie 已提交
491
	RADEON_WRITE(RADEON_CP_RB_BASE, ring_start);
L
Linus Torvalds 已提交
492 493

	/* Set the write pointer delay */
D
Dave Airlie 已提交
494
	RADEON_WRITE(RADEON_CP_RB_WPTR_DELAY, 0);
L
Linus Torvalds 已提交
495 496

	/* Initialize the ring buffer's read and write pointers */
D
Dave Airlie 已提交
497 498 499
	cur_read_ptr = RADEON_READ(RADEON_CP_RB_RPTR);
	RADEON_WRITE(RADEON_CP_RB_WPTR, cur_read_ptr);
	SET_RING_HEAD(dev_priv, cur_read_ptr);
L
Linus Torvalds 已提交
500 501 502
	dev_priv->ring.tail = cur_read_ptr;

#if __OS_HAS_AGP
503
	if (dev_priv->flags & RADEON_IS_AGP) {
D
Dave Airlie 已提交
504 505 506
		RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
			     dev_priv->ring_rptr->offset
			     - dev->agp->base + dev_priv->gart_vm_start);
L
Linus Torvalds 已提交
507 508 509
	} else
#endif
	{
D
Dave Airlie 已提交
510
		struct drm_sg_mem *entry = dev->sg;
L
Linus Torvalds 已提交
511 512
		unsigned long tmp_ofs, page_ofs;

513 514
		tmp_ofs = dev_priv->ring_rptr->offset -
				(unsigned long)dev->sg->virtual;
L
Linus Torvalds 已提交
515 516
		page_ofs = tmp_ofs >> PAGE_SHIFT;

D
Dave Airlie 已提交
517 518 519 520
		RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, entry->busaddr[page_ofs]);
		DRM_DEBUG("ring rptr: offset=0x%08lx handle=0x%08lx\n",
			  (unsigned long)entry->busaddr[page_ofs],
			  entry->handle + tmp_ofs);
L
Linus Torvalds 已提交
521 522
	}

523 524 525
	/* Set ring buffer size */
#ifdef __BIG_ENDIAN
	RADEON_WRITE(RADEON_CP_RB_CNTL,
526 527 528 529
		     RADEON_BUF_SWAP_32BIT |
		     (dev_priv->ring.fetch_size_l2ow << 18) |
		     (dev_priv->ring.rptr_update_l2qw << 8) |
		     dev_priv->ring.size_l2qw);
530
#else
531 532 533 534
	RADEON_WRITE(RADEON_CP_RB_CNTL,
		     (dev_priv->ring.fetch_size_l2ow << 18) |
		     (dev_priv->ring.rptr_update_l2qw << 8) |
		     dev_priv->ring.size_l2qw);
535 536 537 538 539
#endif

	/* Start with assuming that writeback doesn't work */
	dev_priv->writeback_works = 0;

L
Linus Torvalds 已提交
540 541 542 543 544 545 546
	/* Initialize the scratch register pointer.  This will cause
	 * the scratch register values to be written out to memory
	 * whenever they are updated.
	 *
	 * We simply put this behind the ring read pointer, this works
	 * with PCI GART as well as (whatever kind of) AGP GART
	 */
D
Dave Airlie 已提交
547 548
	RADEON_WRITE(RADEON_SCRATCH_ADDR, RADEON_READ(RADEON_CP_RB_RPTR_ADDR)
		     + RADEON_SCRATCH_REG_OFFSET);
L
Linus Torvalds 已提交
549 550 551 552 553

	dev_priv->scratch = ((__volatile__ u32 *)
			     dev_priv->ring_rptr->handle +
			     (RADEON_SCRATCH_REG_OFFSET / sizeof(u32)));

D
Dave Airlie 已提交
554
	RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7);
L
Linus Torvalds 已提交
555

556 557 558
	/* Turn on bus mastering */
	tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
	RADEON_WRITE(RADEON_BUS_CNTL, tmp);
L
Linus Torvalds 已提交
559 560

	dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0;
D
Dave Airlie 已提交
561
	RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
L
Linus Torvalds 已提交
562 563

	dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0;
D
Dave Airlie 已提交
564 565
	RADEON_WRITE(RADEON_LAST_DISPATCH_REG,
		     dev_priv->sarea_priv->last_dispatch);
L
Linus Torvalds 已提交
566 567

	dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0;
D
Dave Airlie 已提交
568
	RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear);
L
Linus Torvalds 已提交
569

D
Dave Airlie 已提交
570
	radeon_do_wait_for_idle(dev_priv);
L
Linus Torvalds 已提交
571 572

	/* Sync everything up */
D
Dave Airlie 已提交
573 574 575 576 577
	RADEON_WRITE(RADEON_ISYNC_CNTL,
		     (RADEON_ISYNC_ANY2D_IDLE3D |
		      RADEON_ISYNC_ANY3D_IDLE2D |
		      RADEON_ISYNC_WAIT_IDLEGUI |
		      RADEON_ISYNC_CPSCRATCH_IDLEGUI));
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608

}

static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
{
	u32 tmp;

	/* Writeback doesn't seem to work everywhere, test it here and possibly
	 * enable it if it appears to work
	 */
	DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0);
	RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef);

	for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) {
		if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) ==
		    0xdeadbeef)
			break;
		DRM_UDELAY(1);
	}

	if (tmp < dev_priv->usec_timeout) {
		dev_priv->writeback_works = 1;
		DRM_INFO("writeback test succeeded in %d usecs\n", tmp);
	} else {
		dev_priv->writeback_works = 0;
		DRM_INFO("writeback test failed\n");
	}
	if (radeon_no_wb == 1) {
		dev_priv->writeback_works = 0;
		DRM_INFO("writeback forced off\n");
	}
609 610 611 612 613 614 615

	if (!dev_priv->writeback_works) {
		/* Disable writeback to avoid unnecessary bus master transfer */
		RADEON_WRITE(RADEON_CP_RB_CNTL, RADEON_READ(RADEON_CP_RB_CNTL) |
			     RADEON_RB_NO_UPDATE);
		RADEON_WRITE(RADEON_SCRATCH_UMSK, 0);
	}
L
Linus Torvalds 已提交
616 617
}

618 619
/* Enable or disable IGP GART on the chip */
static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
620 621 622 623
{
	u32 temp;

	if (on) {
624
		DRM_DEBUG("programming igp gart %08X %08lX %08X\n",
625 626 627 628
			  dev_priv->gart_vm_start,
			  (long)dev_priv->gart_info.bus_addr,
			  dev_priv->gart_size);

629 630 631 632 633 634
		temp = IGP_READ_MCIND(dev_priv, RS480_MC_MISC_CNTL);
		if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
			IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, (RS480_GART_INDEX_REG_EN |
							     RS690_BLOCK_GFX_D3_EN));
		else
			IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, RS480_GART_INDEX_REG_EN);
635

636 637
		IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN |
							       RS480_VA_SIZE_32MB));
638

639 640 641 642 643
		temp = IGP_READ_MCIND(dev_priv, RS480_GART_FEATURE_ID);
		IGP_WRITE_MCIND(RS480_GART_FEATURE_ID, (RS480_HANG_EN |
							RS480_TLB_ENABLE |
							RS480_GTW_LAC_EN |
							RS480_1LEVEL_GART));
644

645 646
		temp = dev_priv->gart_info.bus_addr & 0xfffff000;
		temp |= (upper_32_bits(dev_priv->gart_info.bus_addr) & 0xff) << 4;
647 648 649 650 651 652 653 654 655 656 657 658 659 660
		IGP_WRITE_MCIND(RS480_GART_BASE, temp);

		temp = IGP_READ_MCIND(dev_priv, RS480_AGP_MODE_CNTL);
		IGP_WRITE_MCIND(RS480_AGP_MODE_CNTL, ((1 << RS480_REQ_TYPE_SNOOP_SHIFT) |
						      RS480_REQ_TYPE_SNOOP_DIS));

		if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
			IGP_WRITE_MCIND(RS690_MC_AGP_BASE,
					(unsigned int)dev_priv->gart_vm_start);
			IGP_WRITE_MCIND(RS690_MC_AGP_BASE_2, 0);
		} else {
			RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev_priv->gart_vm_start);
			RADEON_WRITE(RS480_AGP_BASE_2, 0);
		}
D
Dave Airlie 已提交
661

662 663 664 665
		dev_priv->gart_size = 32*1024*1024;
		temp = (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) &
			 0xffff0000) | (dev_priv->gart_vm_start >> 16));

666
		radeon_write_agp_location(dev_priv, temp);
667

668 669 670
		temp = IGP_READ_MCIND(dev_priv, RS480_AGP_ADDRESS_SPACE_SIZE);
		IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN |
							       RS480_VA_SIZE_32MB));
671 672

		do {
673 674
			temp = IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL);
			if ((temp & RS480_GART_CACHE_INVALIDATE) == 0)
675 676 677 678
				break;
			DRM_UDELAY(1);
		} while (1);

679 680
		IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL,
				RS480_GART_CACHE_INVALIDATE);
681

682
		do {
683 684
			temp = IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL);
			if ((temp & RS480_GART_CACHE_INVALIDATE) == 0)
685 686 687 688
				break;
			DRM_UDELAY(1);
		} while (1);

689
		IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL, 0);
690
	} else {
691
		IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, 0);
692 693 694
	}
}

695 696 697 698 699 700
static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on)
{
	u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL);
	if (on) {

		DRM_DEBUG("programming pcie %08X %08lX %08X\n",
D
Dave Airlie 已提交
701 702
			  dev_priv->gart_vm_start,
			  (long)dev_priv->gart_info.bus_addr,
703
			  dev_priv->gart_size);
D
Dave Airlie 已提交
704 705 706 707 708 709 710 711 712 713
		RADEON_WRITE_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO,
				  dev_priv->gart_vm_start);
		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_BASE,
				  dev_priv->gart_info.bus_addr);
		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_START_LO,
				  dev_priv->gart_vm_start);
		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_END_LO,
				  dev_priv->gart_vm_start +
				  dev_priv->gart_size - 1);

D
Dave Airlie 已提交
714
		radeon_write_agp_location(dev_priv, 0xffffffc0); /* ?? */
D
Dave Airlie 已提交
715 716 717

		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL,
				  RADEON_PCIE_TX_GART_EN);
718
	} else {
D
Dave Airlie 已提交
719 720
		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL,
				  tmp & ~RADEON_PCIE_TX_GART_EN);
721
	}
L
Linus Torvalds 已提交
722 723 724
}

/* Enable or disable PCI GART on the chip */
D
Dave Airlie 已提交
725
static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
L
Linus Torvalds 已提交
726
{
727
	u32 tmp;
L
Linus Torvalds 已提交
728

729 730
	if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
	    (dev_priv->flags & RADEON_IS_IGPGART)) {
731 732 733 734
		radeon_set_igpgart(dev_priv, on);
		return;
	}

735
	if (dev_priv->flags & RADEON_IS_PCIE) {
736 737 738
		radeon_set_pciegart(dev_priv, on);
		return;
	}
L
Linus Torvalds 已提交
739

D
Dave Airlie 已提交
740
	tmp = RADEON_READ(RADEON_AIC_CNTL);
741

D
Dave Airlie 已提交
742 743 744
	if (on) {
		RADEON_WRITE(RADEON_AIC_CNTL,
			     tmp | RADEON_PCIGART_TRANSLATE_EN);
L
Linus Torvalds 已提交
745 746 747

		/* set PCI GART page-table base address
		 */
748
		RADEON_WRITE(RADEON_AIC_PT_BASE, dev_priv->gart_info.bus_addr);
L
Linus Torvalds 已提交
749 750 751

		/* set address range for PCI address translate
		 */
D
Dave Airlie 已提交
752 753 754
		RADEON_WRITE(RADEON_AIC_LO_ADDR, dev_priv->gart_vm_start);
		RADEON_WRITE(RADEON_AIC_HI_ADDR, dev_priv->gart_vm_start
			     + dev_priv->gart_size - 1);
L
Linus Torvalds 已提交
755 756 757

		/* Turn off AGP aperture -- is this required for PCI GART?
		 */
D
Dave Airlie 已提交
758
		radeon_write_agp_location(dev_priv, 0xffffffc0);
D
Dave Airlie 已提交
759
		RADEON_WRITE(RADEON_AGP_COMMAND, 0);	/* clear AGP_COMMAND */
L
Linus Torvalds 已提交
760
	} else {
D
Dave Airlie 已提交
761 762
		RADEON_WRITE(RADEON_AIC_CNTL,
			     tmp & ~RADEON_PCIGART_TRANSLATE_EN);
L
Linus Torvalds 已提交
763 764 765
	}
}

766
static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
L
Linus Torvalds 已提交
767
{
768 769
	drm_radeon_private_t *dev_priv = dev->dev_private;

D
Dave Airlie 已提交
770
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
771

D
Dave Airlie 已提交
772
	/* if we require new memory map but we don't have it fail */
773
	if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) {
774
		DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n");
D
Dave Airlie 已提交
775
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
776
		return -EINVAL;
D
Dave Airlie 已提交
777 778
	}

779
	if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) {
780
		DRM_DEBUG("Forcing AGP card to PCI mode\n");
781 782
		dev_priv->flags &= ~RADEON_IS_AGP;
	} else if (!(dev_priv->flags & (RADEON_IS_AGP | RADEON_IS_PCI | RADEON_IS_PCIE))
783 784
		   && !init->is_pci) {
		DRM_DEBUG("Restoring AGP flag\n");
785
		dev_priv->flags |= RADEON_IS_AGP;
786
	}
L
Linus Torvalds 已提交
787

788
	if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) {
D
Dave Airlie 已提交
789
		DRM_ERROR("PCI GART memory not allocated!\n");
L
Linus Torvalds 已提交
790
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
791
		return -EINVAL;
L
Linus Torvalds 已提交
792 793 794
	}

	dev_priv->usec_timeout = init->usec_timeout;
D
Dave Airlie 已提交
795 796 797
	if (dev_priv->usec_timeout < 1 ||
	    dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT) {
		DRM_DEBUG("TIMEOUT problem!\n");
L
Linus Torvalds 已提交
798
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
799
		return -EINVAL;
L
Linus Torvalds 已提交
800 801
	}

802 803 804 805
	/* Enable vblank on CRTC1 for older X servers
	 */
	dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1;

806
	switch(init->func) {
L
Linus Torvalds 已提交
807
	case RADEON_INIT_R200_CP:
D
Dave Airlie 已提交
808
		dev_priv->microcode_version = UCODE_R200;
L
Linus Torvalds 已提交
809 810
		break;
	case RADEON_INIT_R300_CP:
D
Dave Airlie 已提交
811
		dev_priv->microcode_version = UCODE_R300;
L
Linus Torvalds 已提交
812 813
		break;
	default:
D
Dave Airlie 已提交
814
		dev_priv->microcode_version = UCODE_R100;
L
Linus Torvalds 已提交
815
	}
D
Dave Airlie 已提交
816

L
Linus Torvalds 已提交
817 818 819 820 821 822 823
	dev_priv->do_boxes = 0;
	dev_priv->cp_mode = init->cp_mode;

	/* We don't support anything other than bus-mastering ring mode,
	 * but the ring can be in either AGP or PCI space for the ring
	 * read pointer.
	 */
D
Dave Airlie 已提交
824 825 826
	if ((init->cp_mode != RADEON_CSQ_PRIBM_INDDIS) &&
	    (init->cp_mode != RADEON_CSQ_PRIBM_INDBM)) {
		DRM_DEBUG("BAD cp_mode (%x)!\n", init->cp_mode);
L
Linus Torvalds 已提交
827
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
828
		return -EINVAL;
L
Linus Torvalds 已提交
829 830
	}

D
Dave Airlie 已提交
831
	switch (init->fb_bpp) {
L
Linus Torvalds 已提交
832 833 834 835 836 837 838 839
	case 16:
		dev_priv->color_fmt = RADEON_COLOR_FORMAT_RGB565;
		break;
	case 32:
	default:
		dev_priv->color_fmt = RADEON_COLOR_FORMAT_ARGB8888;
		break;
	}
D
Dave Airlie 已提交
840 841 842 843
	dev_priv->front_offset = init->front_offset;
	dev_priv->front_pitch = init->front_pitch;
	dev_priv->back_offset = init->back_offset;
	dev_priv->back_pitch = init->back_pitch;
L
Linus Torvalds 已提交
844

D
Dave Airlie 已提交
845
	switch (init->depth_bpp) {
L
Linus Torvalds 已提交
846 847 848 849 850 851 852 853
	case 16:
		dev_priv->depth_fmt = RADEON_DEPTH_FORMAT_16BIT_INT_Z;
		break;
	case 32:
	default:
		dev_priv->depth_fmt = RADEON_DEPTH_FORMAT_24BIT_INT_Z;
		break;
	}
D
Dave Airlie 已提交
854 855
	dev_priv->depth_offset = init->depth_offset;
	dev_priv->depth_pitch = init->depth_pitch;
L
Linus Torvalds 已提交
856 857 858 859 860 861 862 863

	/* Hardware state for depth clears.  Remove this if/when we no
	 * longer clear the depth buffer with a 3D rectangle.  Hard-code
	 * all values to prevent unwanted 3D state from slipping through
	 * and screwing with the clear operation.
	 */
	dev_priv->depth_clear.rb3d_cntl = (RADEON_PLANE_MASK_ENABLE |
					   (dev_priv->color_fmt << 10) |
D
Dave Airlie 已提交
864 865
					   (dev_priv->microcode_version ==
					    UCODE_R100 ? RADEON_ZBLOCK16 : 0));
L
Linus Torvalds 已提交
866

D
Dave Airlie 已提交
867 868 869 870 871 872 873
	dev_priv->depth_clear.rb3d_zstencilcntl =
	    (dev_priv->depth_fmt |
	     RADEON_Z_TEST_ALWAYS |
	     RADEON_STENCIL_TEST_ALWAYS |
	     RADEON_STENCIL_S_FAIL_REPLACE |
	     RADEON_STENCIL_ZPASS_REPLACE |
	     RADEON_STENCIL_ZFAIL_REPLACE | RADEON_Z_WRITE_ENABLE);
L
Linus Torvalds 已提交
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891

	dev_priv->depth_clear.se_cntl = (RADEON_FFACE_CULL_CW |
					 RADEON_BFACE_SOLID |
					 RADEON_FFACE_SOLID |
					 RADEON_FLAT_SHADE_VTX_LAST |
					 RADEON_DIFFUSE_SHADE_FLAT |
					 RADEON_ALPHA_SHADE_FLAT |
					 RADEON_SPECULAR_SHADE_FLAT |
					 RADEON_FOG_SHADE_FLAT |
					 RADEON_VTX_PIX_CENTER_OGL |
					 RADEON_ROUND_MODE_TRUNC |
					 RADEON_ROUND_PREC_8TH_PIX);


	dev_priv->ring_offset = init->ring_offset;
	dev_priv->ring_rptr_offset = init->ring_rptr_offset;
	dev_priv->buffers_offset = init->buffers_offset;
	dev_priv->gart_textures_offset = init->gart_textures_offset;
D
Dave Airlie 已提交
892

893
	dev_priv->sarea = drm_getsarea(dev);
D
Dave Airlie 已提交
894
	if (!dev_priv->sarea) {
L
Linus Torvalds 已提交
895 896
		DRM_ERROR("could not find sarea!\n");
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
897
		return -EINVAL;
L
Linus Torvalds 已提交
898 899 900
	}

	dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset);
D
Dave Airlie 已提交
901
	if (!dev_priv->cp_ring) {
L
Linus Torvalds 已提交
902 903
		DRM_ERROR("could not find cp ring region!\n");
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
904
		return -EINVAL;
L
Linus Torvalds 已提交
905 906
	}
	dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
D
Dave Airlie 已提交
907
	if (!dev_priv->ring_rptr) {
L
Linus Torvalds 已提交
908 909
		DRM_ERROR("could not find ring read pointer!\n");
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
910
		return -EINVAL;
L
Linus Torvalds 已提交
911
	}
912
	dev->agp_buffer_token = init->buffers_offset;
L
Linus Torvalds 已提交
913
	dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
D
Dave Airlie 已提交
914
	if (!dev->agp_buffer_map) {
L
Linus Torvalds 已提交
915 916
		DRM_ERROR("could not find dma buffer region!\n");
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
917
		return -EINVAL;
L
Linus Torvalds 已提交
918 919
	}

D
Dave Airlie 已提交
920 921 922 923
	if (init->gart_textures_offset) {
		dev_priv->gart_textures =
		    drm_core_findmap(dev, init->gart_textures_offset);
		if (!dev_priv->gart_textures) {
L
Linus Torvalds 已提交
924 925
			DRM_ERROR("could not find GART texture region!\n");
			radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
926
			return -EINVAL;
L
Linus Torvalds 已提交
927 928 929 930
		}
	}

	dev_priv->sarea_priv =
D
Dave Airlie 已提交
931 932
	    (drm_radeon_sarea_t *) ((u8 *) dev_priv->sarea->handle +
				    init->sarea_priv_offset);
L
Linus Torvalds 已提交
933 934

#if __OS_HAS_AGP
935
	if (dev_priv->flags & RADEON_IS_AGP) {
D
Dave Airlie 已提交
936 937 938 939 940 941
		drm_core_ioremap(dev_priv->cp_ring, dev);
		drm_core_ioremap(dev_priv->ring_rptr, dev);
		drm_core_ioremap(dev->agp_buffer_map, dev);
		if (!dev_priv->cp_ring->handle ||
		    !dev_priv->ring_rptr->handle ||
		    !dev->agp_buffer_map->handle) {
L
Linus Torvalds 已提交
942 943
			DRM_ERROR("could not find ioremap agp regions!\n");
			radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
944
			return -EINVAL;
L
Linus Torvalds 已提交
945 946 947 948
		}
	} else
#endif
	{
D
Dave Airlie 已提交
949
		dev_priv->cp_ring->handle = (void *)dev_priv->cp_ring->offset;
L
Linus Torvalds 已提交
950
		dev_priv->ring_rptr->handle =
D
Dave Airlie 已提交
951 952 953 954 955 956 957 958 959 960
		    (void *)dev_priv->ring_rptr->offset;
		dev->agp_buffer_map->handle =
		    (void *)dev->agp_buffer_map->offset;

		DRM_DEBUG("dev_priv->cp_ring->handle %p\n",
			  dev_priv->cp_ring->handle);
		DRM_DEBUG("dev_priv->ring_rptr->handle %p\n",
			  dev_priv->ring_rptr->handle);
		DRM_DEBUG("dev->agp_buffer_map->handle %p\n",
			  dev->agp_buffer_map->handle);
L
Linus Torvalds 已提交
961 962
	}

D
Dave Airlie 已提交
963
	dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 16;
D
Dave Airlie 已提交
964
	dev_priv->fb_size =
D
Dave Airlie 已提交
965
		((radeon_read_fb_location(dev_priv) & 0xffff0000u) + 0x10000)
966
		- dev_priv->fb_location;
L
Linus Torvalds 已提交
967

D
Dave Airlie 已提交
968 969 970
	dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) |
					((dev_priv->front_offset
					  + dev_priv->fb_location) >> 10));
L
Linus Torvalds 已提交
971

D
Dave Airlie 已提交
972 973 974
	dev_priv->back_pitch_offset = (((dev_priv->back_pitch / 64) << 22) |
				       ((dev_priv->back_offset
					 + dev_priv->fb_location) >> 10));
L
Linus Torvalds 已提交
975

D
Dave Airlie 已提交
976 977 978
	dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch / 64) << 22) |
					((dev_priv->depth_offset
					  + dev_priv->fb_location) >> 10));
L
Linus Torvalds 已提交
979 980

	dev_priv->gart_size = init->gart_size;
981 982 983 984 985 986 987 988 989 990 991 992

	/* New let's set the memory map ... */
	if (dev_priv->new_memmap) {
		u32 base = 0;

		DRM_INFO("Setting GART location based on new memory map\n");

		/* If using AGP, try to locate the AGP aperture at the same
		 * location in the card and on the bus, though we have to
		 * align it down.
		 */
#if __OS_HAS_AGP
993
		if (dev_priv->flags & RADEON_IS_AGP) {
994 995
			base = dev->agp->base;
			/* Check if valid */
996 997
			if ((base + dev_priv->gart_size - 1) >= dev_priv->fb_location &&
			    base < (dev_priv->fb_location + dev_priv->fb_size - 1)) {
998 999 1000 1001 1002 1003 1004 1005 1006
				DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n",
					 dev->agp->base);
				base = 0;
			}
		}
#endif
		/* If not or if AGP is at 0 (Macs), try to put it elsewhere */
		if (base == 0) {
			base = dev_priv->fb_location + dev_priv->fb_size;
1007 1008
			if (base < dev_priv->fb_location ||
			    ((base + dev_priv->gart_size) & 0xfffffffful) < base)
1009 1010
				base = dev_priv->fb_location
					- dev_priv->gart_size;
D
Dave Airlie 已提交
1011
		}
1012 1013 1014 1015 1016 1017 1018 1019 1020
		dev_priv->gart_vm_start = base & 0xffc00000u;
		if (dev_priv->gart_vm_start != base)
			DRM_INFO("GART aligned down from 0x%08x to 0x%08x\n",
				 base, dev_priv->gart_vm_start);
	} else {
		DRM_INFO("Setting GART location based on old memory map\n");
		dev_priv->gart_vm_start = dev_priv->fb_location +
			RADEON_READ(RADEON_CONFIG_APER_SIZE);
	}
L
Linus Torvalds 已提交
1021 1022

#if __OS_HAS_AGP
1023
	if (dev_priv->flags & RADEON_IS_AGP)
L
Linus Torvalds 已提交
1024
		dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
D
Dave Airlie 已提交
1025 1026
						 - dev->agp->base
						 + dev_priv->gart_vm_start);
L
Linus Torvalds 已提交
1027 1028 1029
	else
#endif
		dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
1030 1031
					- (unsigned long)dev->sg->virtual
					+ dev_priv->gart_vm_start);
L
Linus Torvalds 已提交
1032

D
Dave Airlie 已提交
1033 1034 1035 1036
	DRM_DEBUG("dev_priv->gart_size %d\n", dev_priv->gart_size);
	DRM_DEBUG("dev_priv->gart_vm_start 0x%x\n", dev_priv->gart_vm_start);
	DRM_DEBUG("dev_priv->gart_buffers_offset 0x%lx\n",
		  dev_priv->gart_buffers_offset);
L
Linus Torvalds 已提交
1037

D
Dave Airlie 已提交
1038 1039
	dev_priv->ring.start = (u32 *) dev_priv->cp_ring->handle;
	dev_priv->ring.end = ((u32 *) dev_priv->cp_ring->handle
L
Linus Torvalds 已提交
1040 1041
			      + init->ring_size / sizeof(u32));
	dev_priv->ring.size = init->ring_size;
D
Dave Airlie 已提交
1042
	dev_priv->ring.size_l2qw = drm_order(init->ring_size / 8);
L
Linus Torvalds 已提交
1043

1044 1045 1046 1047 1048
	dev_priv->ring.rptr_update = /* init->rptr_update */ 4096;
	dev_priv->ring.rptr_update_l2qw = drm_order( /* init->rptr_update */ 4096 / 8);

	dev_priv->ring.fetch_size = /* init->fetch_size */ 32;
	dev_priv->ring.fetch_size_l2ow = drm_order( /* init->fetch_size */ 32 / 16);
D
Dave Airlie 已提交
1049
	dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
L
Linus Torvalds 已提交
1050 1051 1052 1053

	dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;

#if __OS_HAS_AGP
1054
	if (dev_priv->flags & RADEON_IS_AGP) {
L
Linus Torvalds 已提交
1055
		/* Turn off PCI GART */
D
Dave Airlie 已提交
1056
		radeon_set_pcigart(dev_priv, 0);
L
Linus Torvalds 已提交
1057 1058 1059
	} else
#endif
	{
1060
		dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
1061
		/* if we have an offset set from userspace */
1062
		if (dev_priv->pcigart_offset_set) {
D
Dave Airlie 已提交
1063 1064
			dev_priv->gart_info.bus_addr =
			    dev_priv->pcigart_offset + dev_priv->fb_location;
1065
			dev_priv->gart_info.mapping.offset =
1066
			    dev_priv->pcigart_offset + dev_priv->fb_aper_offset;
1067
			dev_priv->gart_info.mapping.size =
1068
			    dev_priv->gart_info.table_size;
1069 1070

			drm_core_ioremap(&dev_priv->gart_info.mapping, dev);
D
Dave Airlie 已提交
1071
			dev_priv->gart_info.addr =
1072
			    dev_priv->gart_info.mapping.handle;
D
Dave Airlie 已提交
1073

1074 1075 1076 1077
			if (dev_priv->flags & RADEON_IS_PCIE)
				dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE;
			else
				dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
D
Dave Airlie 已提交
1078 1079 1080
			dev_priv->gart_info.gart_table_location =
			    DRM_ATI_GART_FB;

1081
			DRM_DEBUG("Setting phys_pci_gart to %p %08lX\n",
D
Dave Airlie 已提交
1082 1083 1084
				  dev_priv->gart_info.addr,
				  dev_priv->pcigart_offset);
		} else {
1085 1086 1087 1088
			if (dev_priv->flags & RADEON_IS_IGPGART)
				dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP;
			else
				dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
D
Dave Airlie 已提交
1089 1090
			dev_priv->gart_info.gart_table_location =
			    DRM_ATI_GART_MAIN;
1091 1092
			dev_priv->gart_info.addr = NULL;
			dev_priv->gart_info.bus_addr = 0;
1093
			if (dev_priv->flags & RADEON_IS_PCIE) {
D
Dave Airlie 已提交
1094 1095
				DRM_ERROR
				    ("Cannot use PCI Express without GART in FB memory\n");
1096
				radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
1097
				return -EINVAL;
1098 1099 1100 1101
			}
		}

		if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
D
Dave Airlie 已提交
1102
			DRM_ERROR("failed to init PCI GART!\n");
L
Linus Torvalds 已提交
1103
			radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
1104
			return -ENOMEM;
L
Linus Torvalds 已提交
1105 1106 1107
		}

		/* Turn on PCI GART */
D
Dave Airlie 已提交
1108
		radeon_set_pcigart(dev_priv, 1);
L
Linus Torvalds 已提交
1109 1110
	}

D
Dave Airlie 已提交
1111 1112
	radeon_cp_load_microcode(dev_priv);
	radeon_cp_init_ring_buffer(dev, dev_priv);
L
Linus Torvalds 已提交
1113 1114 1115

	dev_priv->last_buf = 0;

D
Dave Airlie 已提交
1116
	radeon_do_engine_reset(dev);
1117
	radeon_test_writeback(dev_priv);
L
Linus Torvalds 已提交
1118 1119 1120 1121

	return 0;
}

1122
static int radeon_do_cleanup_cp(struct drm_device * dev)
L
Linus Torvalds 已提交
1123 1124
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
D
Dave Airlie 已提交
1125
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
1126 1127 1128 1129 1130

	/* Make sure interrupts are disabled here because the uninstall ioctl
	 * may not have been called from userspace and after dev_private
	 * is freed, it's too late.
	 */
D
Dave Airlie 已提交
1131 1132
	if (dev->irq_enabled)
		drm_irq_uninstall(dev);
L
Linus Torvalds 已提交
1133 1134

#if __OS_HAS_AGP
1135
	if (dev_priv->flags & RADEON_IS_AGP) {
1136
		if (dev_priv->cp_ring != NULL) {
D
Dave Airlie 已提交
1137
			drm_core_ioremapfree(dev_priv->cp_ring, dev);
1138 1139 1140
			dev_priv->cp_ring = NULL;
		}
		if (dev_priv->ring_rptr != NULL) {
D
Dave Airlie 已提交
1141
			drm_core_ioremapfree(dev_priv->ring_rptr, dev);
1142 1143
			dev_priv->ring_rptr = NULL;
		}
D
Dave Airlie 已提交
1144 1145
		if (dev->agp_buffer_map != NULL) {
			drm_core_ioremapfree(dev->agp_buffer_map, dev);
L
Linus Torvalds 已提交
1146 1147 1148 1149 1150
			dev->agp_buffer_map = NULL;
		}
	} else
#endif
	{
1151 1152 1153 1154

		if (dev_priv->gart_info.bus_addr) {
			/* Turn off PCI GART */
			radeon_set_pcigart(dev_priv, 0);
1155 1156
			if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info))
				DRM_ERROR("failed to cleanup PCI GART!\n");
1157
		}
D
Dave Airlie 已提交
1158

1159 1160
		if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB)
		{
1161
			drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev);
1162
			dev_priv->gart_info.addr = 0;
1163
		}
L
Linus Torvalds 已提交
1164 1165 1166 1167 1168 1169 1170
	}
	/* only clear to the start of flags */
	memset(dev_priv, 0, offsetof(drm_radeon_private_t, flags));

	return 0;
}

D
Dave Airlie 已提交
1171 1172
/* This code will reinit the Radeon CP hardware after a resume from disc.
 * AFAIK, it would be very difficult to pickle the state at suspend time, so
L
Linus Torvalds 已提交
1173 1174 1175 1176 1177
 * here we make sure that all Radeon hardware initialisation is re-done without
 * affecting running applications.
 *
 * Charl P. Botha <http://cpbotha.net>
 */
1178
static int radeon_do_resume_cp(struct drm_device * dev)
L
Linus Torvalds 已提交
1179 1180 1181
{
	drm_radeon_private_t *dev_priv = dev->dev_private;

D
Dave Airlie 已提交
1182 1183
	if (!dev_priv) {
		DRM_ERROR("Called with no initialization\n");
E
Eric Anholt 已提交
1184
		return -EINVAL;
L
Linus Torvalds 已提交
1185 1186 1187 1188 1189
	}

	DRM_DEBUG("Starting radeon_do_resume_cp()\n");

#if __OS_HAS_AGP
1190
	if (dev_priv->flags & RADEON_IS_AGP) {
L
Linus Torvalds 已提交
1191
		/* Turn off PCI GART */
D
Dave Airlie 已提交
1192
		radeon_set_pcigart(dev_priv, 0);
L
Linus Torvalds 已提交
1193 1194 1195 1196
	} else
#endif
	{
		/* Turn on PCI GART */
D
Dave Airlie 已提交
1197
		radeon_set_pcigart(dev_priv, 1);
L
Linus Torvalds 已提交
1198 1199
	}

D
Dave Airlie 已提交
1200 1201
	radeon_cp_load_microcode(dev_priv);
	radeon_cp_init_ring_buffer(dev, dev_priv);
L
Linus Torvalds 已提交
1202

D
Dave Airlie 已提交
1203
	radeon_do_engine_reset(dev);
L
Linus Torvalds 已提交
1204 1205 1206 1207 1208 1209

	DRM_DEBUG("radeon_do_resume_cp() complete\n");

	return 0;
}

1210
int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1211
{
1212
	drm_radeon_init_t *init = data;
L
Linus Torvalds 已提交
1213

1214
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1215

1216
	if (init->func == RADEON_INIT_R300_CP)
D
Dave Airlie 已提交
1217
		r300_init_reg_flags(dev);
D
Dave Airlie 已提交
1218

1219
	switch (init->func) {
L
Linus Torvalds 已提交
1220 1221 1222
	case RADEON_INIT_CP:
	case RADEON_INIT_R200_CP:
	case RADEON_INIT_R300_CP:
1223
		return radeon_do_init_cp(dev, init);
L
Linus Torvalds 已提交
1224
	case RADEON_CLEANUP_CP:
D
Dave Airlie 已提交
1225
		return radeon_do_cleanup_cp(dev);
L
Linus Torvalds 已提交
1226 1227
	}

E
Eric Anholt 已提交
1228
	return -EINVAL;
L
Linus Torvalds 已提交
1229 1230
}

1231
int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1232 1233
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
D
Dave Airlie 已提交
1234
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
1235

1236
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1237

D
Dave Airlie 已提交
1238
	if (dev_priv->cp_running) {
1239
		DRM_DEBUG("while CP running\n");
L
Linus Torvalds 已提交
1240 1241
		return 0;
	}
D
Dave Airlie 已提交
1242
	if (dev_priv->cp_mode == RADEON_CSQ_PRIDIS_INDDIS) {
1243 1244
		DRM_DEBUG("called with bogus CP mode (%d)\n",
			  dev_priv->cp_mode);
L
Linus Torvalds 已提交
1245 1246 1247
		return 0;
	}

D
Dave Airlie 已提交
1248
	radeon_do_cp_start(dev_priv);
L
Linus Torvalds 已提交
1249 1250 1251 1252 1253 1254 1255

	return 0;
}

/* Stop the CP.  The engine must have been idled before calling this
 * routine.
 */
1256
int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1257 1258
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
1259
	drm_radeon_cp_stop_t *stop = data;
L
Linus Torvalds 已提交
1260
	int ret;
D
Dave Airlie 已提交
1261
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
1262

1263
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1264 1265 1266 1267 1268 1269 1270

	if (!dev_priv->cp_running)
		return 0;

	/* Flush any pending CP commands.  This ensures any outstanding
	 * commands are exectuted by the engine before we turn it off.
	 */
1271
	if (stop->flush) {
D
Dave Airlie 已提交
1272
		radeon_do_cp_flush(dev_priv);
L
Linus Torvalds 已提交
1273 1274 1275 1276 1277
	}

	/* If we fail to make the engine go idle, we return an error
	 * code so that the DRM ioctl wrapper can try again.
	 */
1278
	if (stop->idle) {
D
Dave Airlie 已提交
1279 1280 1281
		ret = radeon_do_cp_idle(dev_priv);
		if (ret)
			return ret;
L
Linus Torvalds 已提交
1282 1283 1284 1285 1286 1287
	}

	/* Finally, we can turn off the CP.  If the engine isn't idle,
	 * we will get some dropped triangles as they won't be fully
	 * rendered before the CP is shut down.
	 */
D
Dave Airlie 已提交
1288
	radeon_do_cp_stop(dev_priv);
L
Linus Torvalds 已提交
1289 1290

	/* Reset the engine */
D
Dave Airlie 已提交
1291
	radeon_do_engine_reset(dev);
L
Linus Torvalds 已提交
1292 1293 1294 1295

	return 0;
}

1296
void radeon_do_release(struct drm_device * dev)
L
Linus Torvalds 已提交
1297 1298 1299 1300 1301 1302 1303
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
	int i, ret;

	if (dev_priv) {
		if (dev_priv->cp_running) {
			/* Stop the cp */
D
Dave Airlie 已提交
1304
			while ((ret = radeon_do_cp_idle(dev_priv)) != 0) {
L
Linus Torvalds 已提交
1305 1306 1307 1308 1309 1310 1311
				DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
#ifdef __linux__
				schedule();
#else
				tsleep(&ret, PZERO, "rdnrel", 1);
#endif
			}
D
Dave Airlie 已提交
1312 1313
			radeon_do_cp_stop(dev_priv);
			radeon_do_engine_reset(dev);
L
Linus Torvalds 已提交
1314 1315 1316 1317
		}

		/* Disable *all* interrupts */
		if (dev_priv->mmio)	/* remove this after permanent addmaps */
D
Dave Airlie 已提交
1318
			RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
L
Linus Torvalds 已提交
1319

D
Dave Airlie 已提交
1320
		if (dev_priv->mmio) {	/* remove all surfaces */
L
Linus Torvalds 已提交
1321
			for (i = 0; i < RADEON_MAX_SURFACES; i++) {
D
Dave Airlie 已提交
1322 1323 1324 1325 1326
				RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * i, 0);
				RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND +
					     16 * i, 0);
				RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND +
					     16 * i, 0);
L
Linus Torvalds 已提交
1327 1328 1329 1330
			}
		}

		/* Free memory heap structures */
D
Dave Airlie 已提交
1331 1332
		radeon_mem_takedown(&(dev_priv->gart_heap));
		radeon_mem_takedown(&(dev_priv->fb_heap));
L
Linus Torvalds 已提交
1333 1334

		/* deallocate kernel resources */
D
Dave Airlie 已提交
1335
		radeon_do_cleanup_cp(dev);
L
Linus Torvalds 已提交
1336 1337 1338 1339 1340
	}
}

/* Just reset the CP ring.  Called as part of an X Server engine reset.
 */
1341
int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1342 1343
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
D
Dave Airlie 已提交
1344
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
1345

1346
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1347

D
Dave Airlie 已提交
1348
	if (!dev_priv) {
1349
		DRM_DEBUG("called before init done\n");
E
Eric Anholt 已提交
1350
		return -EINVAL;
L
Linus Torvalds 已提交
1351 1352
	}

D
Dave Airlie 已提交
1353
	radeon_do_cp_reset(dev_priv);
L
Linus Torvalds 已提交
1354 1355 1356 1357 1358 1359 1360

	/* The CP is no longer running after an engine reset */
	dev_priv->cp_running = 0;

	return 0;
}

1361
int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1362 1363
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
D
Dave Airlie 已提交
1364
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
1365

1366
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1367

D
Dave Airlie 已提交
1368
	return radeon_do_cp_idle(dev_priv);
L
Linus Torvalds 已提交
1369 1370 1371 1372
}

/* Added by Charl P. Botha to call radeon_do_resume_cp().
 */
1373
int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1374 1375 1376 1377 1378
{

	return radeon_do_resume_cp(dev);
}

1379
int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1380
{
D
Dave Airlie 已提交
1381
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
1382

1383
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1384

D
Dave Airlie 已提交
1385
	return radeon_do_engine_reset(dev);
L
Linus Torvalds 已提交
1386 1387 1388 1389 1390 1391 1392 1393
}

/* ================================================================
 * Fullscreen mode
 */

/* KW: Deprecated to say the least:
 */
1394
int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406
{
	return 0;
}

/* ================================================================
 * Freelist management
 */

/* Original comment: FIXME: ROTATE_BUFS is a hack to cycle through
 *   bufs until freelist code is used.  Note this hides a problem with
 *   the scratch register * (used to keep track of last buffer
 *   completed) being written to before * the last buffer has actually
D
Dave Airlie 已提交
1407
 *   completed rendering.
L
Linus Torvalds 已提交
1408 1409 1410 1411 1412 1413
 *
 * KW:  It's also a good way to find free buffers quickly.
 *
 * KW: Ideally this loop wouldn't exist, and freelist_get wouldn't
 * sleep.  However, bugs in older versions of radeon_accel.c mean that
 * we essentially have to do this, else old clients will break.
D
Dave Airlie 已提交
1414
 *
L
Linus Torvalds 已提交
1415 1416
 * However, it does leave open a potential deadlock where all the
 * buffers are held by other clients, which can't release them because
D
Dave Airlie 已提交
1417
 * they can't get the lock.
L
Linus Torvalds 已提交
1418 1419
 */

D
Dave Airlie 已提交
1420
struct drm_buf *radeon_freelist_get(struct drm_device * dev)
L
Linus Torvalds 已提交
1421
{
1422
	struct drm_device_dma *dma = dev->dma;
L
Linus Torvalds 已提交
1423 1424
	drm_radeon_private_t *dev_priv = dev->dev_private;
	drm_radeon_buf_priv_t *buf_priv;
D
Dave Airlie 已提交
1425
	struct drm_buf *buf;
L
Linus Torvalds 已提交
1426 1427 1428
	int i, t;
	int start;

D
Dave Airlie 已提交
1429
	if (++dev_priv->last_buf >= dma->buf_count)
L
Linus Torvalds 已提交
1430 1431 1432 1433
		dev_priv->last_buf = 0;

	start = dev_priv->last_buf;

D
Dave Airlie 已提交
1434 1435 1436 1437
	for (t = 0; t < dev_priv->usec_timeout; t++) {
		u32 done_age = GET_SCRATCH(1);
		DRM_DEBUG("done_age = %d\n", done_age);
		for (i = start; i < dma->buf_count; i++) {
L
Linus Torvalds 已提交
1438 1439
			buf = dma->buflist[i];
			buf_priv = buf->dev_private;
1440 1441 1442
			if (buf->file_priv == NULL || (buf->pending &&
						       buf_priv->age <=
						       done_age)) {
L
Linus Torvalds 已提交
1443 1444 1445 1446 1447 1448 1449 1450
				dev_priv->stats.requested_bufs++;
				buf->pending = 0;
				return buf;
			}
			start = 0;
		}

		if (t) {
D
Dave Airlie 已提交
1451
			DRM_UDELAY(1);
L
Linus Torvalds 已提交
1452 1453 1454 1455
			dev_priv->stats.freelist_loops++;
		}
	}

D
Dave Airlie 已提交
1456
	DRM_DEBUG("returning NULL!\n");
L
Linus Torvalds 已提交
1457 1458
	return NULL;
}
D
Dave Airlie 已提交
1459

L
Linus Torvalds 已提交
1460
#if 0
D
Dave Airlie 已提交
1461
struct drm_buf *radeon_freelist_get(struct drm_device * dev)
L
Linus Torvalds 已提交
1462
{
1463
	struct drm_device_dma *dma = dev->dma;
L
Linus Torvalds 已提交
1464 1465
	drm_radeon_private_t *dev_priv = dev->dev_private;
	drm_radeon_buf_priv_t *buf_priv;
D
Dave Airlie 已提交
1466
	struct drm_buf *buf;
L
Linus Torvalds 已提交
1467 1468 1469 1470
	int i, t;
	int start;
	u32 done_age = DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1));

D
Dave Airlie 已提交
1471
	if (++dev_priv->last_buf >= dma->buf_count)
L
Linus Torvalds 已提交
1472 1473 1474 1475
		dev_priv->last_buf = 0;

	start = dev_priv->last_buf;
	dev_priv->stats.freelist_loops++;
D
Dave Airlie 已提交
1476 1477 1478

	for (t = 0; t < 2; t++) {
		for (i = start; i < dma->buf_count; i++) {
L
Linus Torvalds 已提交
1479 1480
			buf = dma->buflist[i];
			buf_priv = buf->dev_private;
1481 1482 1483
			if (buf->file_priv == 0 || (buf->pending &&
						    buf_priv->age <=
						    done_age)) {
L
Linus Torvalds 已提交
1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495
				dev_priv->stats.requested_bufs++;
				buf->pending = 0;
				return buf;
			}
		}
		start = 0;
	}

	return NULL;
}
#endif

1496
void radeon_freelist_reset(struct drm_device * dev)
L
Linus Torvalds 已提交
1497
{
1498
	struct drm_device_dma *dma = dev->dma;
L
Linus Torvalds 已提交
1499 1500 1501 1502
	drm_radeon_private_t *dev_priv = dev->dev_private;
	int i;

	dev_priv->last_buf = 0;
D
Dave Airlie 已提交
1503
	for (i = 0; i < dma->buf_count; i++) {
D
Dave Airlie 已提交
1504
		struct drm_buf *buf = dma->buflist[i];
L
Linus Torvalds 已提交
1505 1506 1507 1508 1509 1510 1511 1512 1513
		drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
		buf_priv->age = 0;
	}
}

/* ================================================================
 * CP command submission
 */

D
Dave Airlie 已提交
1514
int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n)
L
Linus Torvalds 已提交
1515 1516 1517
{
	drm_radeon_ring_buffer_t *ring = &dev_priv->ring;
	int i;
D
Dave Airlie 已提交
1518
	u32 last_head = GET_RING_HEAD(dev_priv);
L
Linus Torvalds 已提交
1519

D
Dave Airlie 已提交
1520 1521
	for (i = 0; i < dev_priv->usec_timeout; i++) {
		u32 head = GET_RING_HEAD(dev_priv);
L
Linus Torvalds 已提交
1522 1523

		ring->space = (head - ring->tail) * sizeof(u32);
D
Dave Airlie 已提交
1524
		if (ring->space <= 0)
L
Linus Torvalds 已提交
1525
			ring->space += ring->size;
D
Dave Airlie 已提交
1526
		if (ring->space > n)
L
Linus Torvalds 已提交
1527
			return 0;
D
Dave Airlie 已提交
1528

L
Linus Torvalds 已提交
1529 1530 1531 1532 1533 1534
		dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;

		if (head != last_head)
			i = 0;
		last_head = head;

D
Dave Airlie 已提交
1535
		DRM_UDELAY(1);
L
Linus Torvalds 已提交
1536 1537 1538 1539
	}

	/* FIXME: This return value is ignored in the BEGIN_RING macro! */
#if RADEON_FIFO_DEBUG
D
Dave Airlie 已提交
1540 1541
	radeon_status(dev_priv);
	DRM_ERROR("failed!\n");
L
Linus Torvalds 已提交
1542
#endif
E
Eric Anholt 已提交
1543
	return -EBUSY;
L
Linus Torvalds 已提交
1544 1545
}

1546 1547
static int radeon_cp_get_buffers(struct drm_device *dev,
				 struct drm_file *file_priv,
1548
				 struct drm_dma * d)
L
Linus Torvalds 已提交
1549 1550
{
	int i;
D
Dave Airlie 已提交
1551
	struct drm_buf *buf;
L
Linus Torvalds 已提交
1552

D
Dave Airlie 已提交
1553 1554 1555
	for (i = d->granted_count; i < d->request_count; i++) {
		buf = radeon_freelist_get(dev);
		if (!buf)
E
Eric Anholt 已提交
1556
			return -EBUSY;	/* NOTE: broken client */
L
Linus Torvalds 已提交
1557

1558
		buf->file_priv = file_priv;
L
Linus Torvalds 已提交
1559

D
Dave Airlie 已提交
1560 1561
		if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
				     sizeof(buf->idx)))
E
Eric Anholt 已提交
1562
			return -EFAULT;
D
Dave Airlie 已提交
1563 1564
		if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
				     sizeof(buf->total)))
E
Eric Anholt 已提交
1565
			return -EFAULT;
L
Linus Torvalds 已提交
1566 1567 1568 1569 1570 1571

		d->granted_count++;
	}
	return 0;
}

1572
int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1573
{
1574
	struct drm_device_dma *dma = dev->dma;
L
Linus Torvalds 已提交
1575
	int ret = 0;
1576
	struct drm_dma *d = data;
L
Linus Torvalds 已提交
1577

1578
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1579 1580 1581

	/* Please don't send us buffers.
	 */
1582
	if (d->send_count != 0) {
D
Dave Airlie 已提交
1583
		DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
1584
			  DRM_CURRENTPID, d->send_count);
E
Eric Anholt 已提交
1585
		return -EINVAL;
L
Linus Torvalds 已提交
1586 1587 1588 1589
	}

	/* We'll send you buffers.
	 */
1590
	if (d->request_count < 0 || d->request_count > dma->buf_count) {
D
Dave Airlie 已提交
1591
		DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
1592
			  DRM_CURRENTPID, d->request_count, dma->buf_count);
E
Eric Anholt 已提交
1593
		return -EINVAL;
L
Linus Torvalds 已提交
1594 1595
	}

1596
	d->granted_count = 0;
L
Linus Torvalds 已提交
1597

1598 1599
	if (d->request_count) {
		ret = radeon_cp_get_buffers(dev, file_priv, d);
L
Linus Torvalds 已提交
1600 1601 1602 1603 1604
	}

	return ret;
}

1605
int radeon_driver_load(struct drm_device *dev, unsigned long flags)
L
Linus Torvalds 已提交
1606 1607 1608 1609 1610 1611
{
	drm_radeon_private_t *dev_priv;
	int ret = 0;

	dev_priv = drm_alloc(sizeof(drm_radeon_private_t), DRM_MEM_DRIVER);
	if (dev_priv == NULL)
E
Eric Anholt 已提交
1612
		return -ENOMEM;
L
Linus Torvalds 已提交
1613 1614 1615 1616 1617

	memset(dev_priv, 0, sizeof(drm_radeon_private_t));
	dev->dev_private = (void *)dev_priv;
	dev_priv->flags = flags;

1618
	switch (flags & RADEON_FAMILY_MASK) {
L
Linus Torvalds 已提交
1619 1620 1621 1622
	case CHIP_R100:
	case CHIP_RV200:
	case CHIP_R200:
	case CHIP_R300:
1623
	case CHIP_R350:
D
Dave Airlie 已提交
1624
	case CHIP_R420:
1625
	case CHIP_RV410:
D
Dave Airlie 已提交
1626 1627 1628 1629
	case CHIP_RV515:
	case CHIP_R520:
	case CHIP_RV570:
	case CHIP_R580:
1630
		dev_priv->flags |= RADEON_HAS_HIERZ;
L
Linus Torvalds 已提交
1631 1632
		break;
	default:
D
Dave Airlie 已提交
1633
		/* all other chips have no hierarchical z buffer */
L
Linus Torvalds 已提交
1634 1635
		break;
	}
D
Dave Airlie 已提交
1636 1637

	if (drm_device_is_agp(dev))
1638
		dev_priv->flags |= RADEON_IS_AGP;
1639
	else if (drm_device_is_pcie(dev))
1640
		dev_priv->flags |= RADEON_IS_PCIE;
1641
	else
1642
		dev_priv->flags |= RADEON_IS_PCI;
1643

D
Dave Airlie 已提交
1644
	DRM_DEBUG("%s card detected\n",
1645
		  ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI"))));
L
Linus Torvalds 已提交
1646 1647 1648
	return ret;
}

1649 1650 1651 1652
/* Create mappings for registers and framebuffer so userland doesn't necessarily
 * have to find them.
 */
int radeon_driver_firstopen(struct drm_device *dev)
D
Dave Airlie 已提交
1653 1654 1655 1656 1657
{
	int ret;
	drm_local_map_t *map;
	drm_radeon_private_t *dev_priv = dev->dev_private;

1658 1659
	dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;

D
Dave Airlie 已提交
1660 1661 1662 1663 1664 1665
	ret = drm_addmap(dev, drm_get_resource_start(dev, 2),
			 drm_get_resource_len(dev, 2), _DRM_REGISTERS,
			 _DRM_READ_ONLY, &dev_priv->mmio);
	if (ret != 0)
		return ret;

1666 1667
	dev_priv->fb_aper_offset = drm_get_resource_start(dev, 0);
	ret = drm_addmap(dev, dev_priv->fb_aper_offset,
D
Dave Airlie 已提交
1668 1669 1670 1671 1672 1673 1674 1675
			 drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER,
			 _DRM_WRITE_COMBINING, &map);
	if (ret != 0)
		return ret;

	return 0;
}

1676
int radeon_driver_unload(struct drm_device *dev)
L
Linus Torvalds 已提交
1677 1678 1679 1680 1681 1682 1683 1684 1685
{
	drm_radeon_private_t *dev_priv = dev->dev_private;

	DRM_DEBUG("\n");
	drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);

	dev->dev_private = NULL;
	return 0;
}