radeon_cp.c 48.9 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 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
	if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) {
		tmp = RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT);
		tmp |= RADEON_RB3D_DC_FLUSH_ALL;
		RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp);

		for (i = 0; i < dev_priv->usec_timeout; i++) {
			if (!(RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT)
			      & RADEON_RB3D_DC_BUSY)) {
				return 0;
			}
			DRM_UDELAY(1);
		}
	} else {
		/* 3D */
		tmp = RADEON_READ(R300_RB3D_DSTCACHE_CTLSTAT);
		tmp |= RADEON_RB3D_DC_FLUSH_ALL;
		RADEON_WRITE(R300_RB3D_DSTCACHE_CTLSTAT, tmp);

		/* 2D */
		tmp = RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT);
		tmp |= RADEON_RB3D_DC_FLUSH_ALL;
		RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp);

		for (i = 0; i < dev_priv->usec_timeout; i++) {
			if (!(RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT)
			  & RADEON_RB3D_DC_BUSY)) {
				return 0;
			}
			DRM_UDELAY(1);
L
Linus Torvalds 已提交
193 194 195 196
		}
	}

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

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

	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;

D
Dave Airlie 已提交
209 210 211 212 213 214
	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 已提交
215 216 217
	}

#if RADEON_FIFO_DEBUG
D
Dave Airlie 已提交
218 219
	DRM_ERROR("failed!\n");
	radeon_status(dev_priv);
L
Linus Torvalds 已提交
220
#endif
E
Eric Anholt 已提交
221
	return -EBUSY;
L
Linus Torvalds 已提交
222 223
}

D
Dave Airlie 已提交
224
static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
225 226 227 228 229
{
	int i, ret;

	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;

D
Dave Airlie 已提交
230 231 232
	ret = radeon_do_wait_for_fifo(dev_priv, 64);
	if (ret)
		return ret;
L
Linus Torvalds 已提交
233

D
Dave Airlie 已提交
234 235 236 237
	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 已提交
238 239
			return 0;
		}
D
Dave Airlie 已提交
240
		DRM_UDELAY(1);
L
Linus Torvalds 已提交
241 242 243
	}

#if RADEON_FIFO_DEBUG
D
Dave Airlie 已提交
244 245
	DRM_ERROR("failed!\n");
	radeon_status(dev_priv);
L
Linus Torvalds 已提交
246
#endif
E
Eric Anholt 已提交
247
	return -EBUSY;
L
Linus Torvalds 已提交
248 249
}

250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
static void radeon_init_pipes(drm_radeon_private_t *dev_priv)
{
	uint32_t gb_tile_config, gb_pipe_sel = 0;

	/* RS4xx/RS6xx/R4xx/R5xx */
	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R420) {
		gb_pipe_sel = RADEON_READ(R400_GB_PIPE_SELECT);
		dev_priv->num_gb_pipes = ((gb_pipe_sel >> 12) & 0x3) + 1;
	} else {
		/* R3xx */
		if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R300) ||
		    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350)) {
			dev_priv->num_gb_pipes = 2;
		} else {
			/* R3Vxx */
			dev_priv->num_gb_pipes = 1;
		}
	}
	DRM_INFO("Num pipes: %d\n", dev_priv->num_gb_pipes);

	gb_tile_config = (R300_ENABLE_TILING | R300_TILE_SIZE_16 /*| R300_SUBPIXEL_1_16*/);

	switch (dev_priv->num_gb_pipes) {
	case 2: gb_tile_config |= R300_PIPE_COUNT_R300; break;
	case 3: gb_tile_config |= R300_PIPE_COUNT_R420_3P; break;
	case 4: gb_tile_config |= R300_PIPE_COUNT_R420; break;
	default:
	case 1: gb_tile_config |= R300_PIPE_COUNT_RV350; break;
	}

	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
		RADEON_WRITE_PLL(R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4));
		RADEON_WRITE(R500_SU_REG_DEST, ((1 << dev_priv->num_gb_pipes) - 1));
	}
	RADEON_WRITE(R300_GB_TILE_CONFIG, gb_tile_config);
	radeon_do_wait_for_idle(dev_priv);
	RADEON_WRITE(R300_DST_PIPE_CONFIG, RADEON_READ(R300_DST_PIPE_CONFIG) | R300_PIPE_AUTO_CONFIG);
	RADEON_WRITE(R300_RB2D_DSTCACHE_MODE, (RADEON_READ(R300_RB2D_DSTCACHE_MODE) |
					       R300_DC_AUTOFLUSH_ENABLE |
					       R300_DC_DC_DISABLE_IGNORE_PE));


}

L
Linus Torvalds 已提交
294 295 296 297 298
/* ================================================================
 * CP control, initialization
 */

/* Load the microcode for the CP */
D
Dave Airlie 已提交
299
static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
300 301
{
	int i;
D
Dave Airlie 已提交
302
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
303

D
Dave Airlie 已提交
304
	radeon_do_wait_for_idle(dev_priv);
L
Linus Torvalds 已提交
305

D
Dave Airlie 已提交
306
	RADEON_WRITE(RADEON_CP_ME_RAM_ADDR, 0);
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
	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 已提交
323
		DRM_INFO("Loading R200 Microcode\n");
D
Dave Airlie 已提交
324 325 326 327 328
		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 已提交
329
		}
330 331 332 333
	} 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) ||
334
		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
L
Linus Torvalds 已提交
335
		DRM_INFO("Loading R300 Microcode\n");
D
Dave Airlie 已提交
336 337 338 339 340
		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 已提交
341
		}
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
	} 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 已提交
366 367
		for (i = 0; i < 256; i++) {
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
368
				     R520_cp_microcode[i][1]);
D
Dave Airlie 已提交
369
			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
370
				     R520_cp_microcode[i][0]);
L
Linus Torvalds 已提交
371 372 373 374 375 376 377 378
		}
	}
}

/* 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 已提交
379
static void radeon_do_cp_flush(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
380
{
D
Dave Airlie 已提交
381
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
382 383 384
#if 0
	u32 tmp;

D
Dave Airlie 已提交
385 386
	tmp = RADEON_READ(RADEON_CP_RB_WPTR) | (1 << 31);
	RADEON_WRITE(RADEON_CP_RB_WPTR, tmp);
L
Linus Torvalds 已提交
387 388 389 390 391
#endif
}

/* Wait for the CP to go idle.
 */
D
Dave Airlie 已提交
392
int radeon_do_cp_idle(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
393 394
{
	RING_LOCALS;
D
Dave Airlie 已提交
395
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
396

D
Dave Airlie 已提交
397
	BEGIN_RING(6);
L
Linus Torvalds 已提交
398 399 400 401 402 403 404 405

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

	ADVANCE_RING();
	COMMIT_RING();

D
Dave Airlie 已提交
406
	return radeon_do_wait_for_idle(dev_priv);
L
Linus Torvalds 已提交
407 408 409 410
}

/* Start the Command Processor.
 */
D
Dave Airlie 已提交
411
static void radeon_do_cp_start(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
412 413
{
	RING_LOCALS;
D
Dave Airlie 已提交
414
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
415

D
Dave Airlie 已提交
416
	radeon_do_wait_for_idle(dev_priv);
L
Linus Torvalds 已提交
417

D
Dave Airlie 已提交
418
	RADEON_WRITE(RADEON_CP_CSQ_CNTL, dev_priv->cp_mode);
L
Linus Torvalds 已提交
419 420 421

	dev_priv->cp_running = 1;

D
Dave Airlie 已提交
422
	BEGIN_RING(6);
L
Linus Torvalds 已提交
423 424 425 426 427 428 429 430 431 432 433 434 435

	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 已提交
436
static void radeon_do_cp_reset(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
437 438
{
	u32 cur_read_ptr;
D
Dave Airlie 已提交
439
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
440

D
Dave Airlie 已提交
441 442 443
	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 已提交
444 445 446 447 448 449 450
	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 已提交
451
static void radeon_do_cp_stop(drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
452
{
D
Dave Airlie 已提交
453
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
454

D
Dave Airlie 已提交
455
	RADEON_WRITE(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS);
L
Linus Torvalds 已提交
456 457 458 459 460 461

	dev_priv->cp_running = 0;
}

/* Reset the engine.  This will stop the CP if it is running.
 */
462
static int radeon_do_engine_reset(struct drm_device * dev)
L
Linus Torvalds 已提交
463 464
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
465
	u32 clock_cntl_index = 0, mclk_cntl = 0, rbbm_soft_reset;
D
Dave Airlie 已提交
466
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
467

D
Dave Airlie 已提交
468 469
	radeon_do_pixcache_flush(dev_priv);

470 471
	if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) {
		/* may need something similar for newer chips */
D
Dave Airlie 已提交
472 473 474 475 476 477 478 479 480 481
		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));
482
	}
D
Dave Airlie 已提交
483

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
	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);

	if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) {
D
Dave Airlie 已提交
506 507 508 509
		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 已提交
510

511 512 513 514
	/* setup the raster pipes */
	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R300)
	    radeon_init_pipes(dev_priv);

L
Linus Torvalds 已提交
515
	/* Reset the CP ring */
D
Dave Airlie 已提交
516
	radeon_do_cp_reset(dev_priv);
L
Linus Torvalds 已提交
517 518 519 520 521

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

	/* Reset any pending vertex, indirect buffers */
D
Dave Airlie 已提交
522
	radeon_freelist_reset(dev);
L
Linus Torvalds 已提交
523 524 525 526

	return 0;
}

527
static void radeon_cp_init_ring_buffer(struct drm_device * dev,
D
Dave Airlie 已提交
528
				       drm_radeon_private_t * dev_priv)
L
Linus Torvalds 已提交
529 530 531
{
	u32 ring_start, cur_read_ptr;
	u32 tmp;
D
Dave Airlie 已提交
532

533 534 535 536 537 538
	/* 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 已提交
539
		radeon_write_fb_location(dev_priv,
540 541
			     ((dev_priv->gart_vm_start - 1) & 0xffff0000)
			     | (dev_priv->fb_location >> 16));
L
Linus Torvalds 已提交
542 543

#if __OS_HAS_AGP
544
	if (dev_priv->flags & RADEON_IS_AGP) {
545
		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
546 547
		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R200)
			RADEON_WRITE(RADEON_AGP_BASE_2, 0);
D
Dave Airlie 已提交
548
		radeon_write_agp_location(dev_priv,
D
Dave Airlie 已提交
549 550 551
			     (((dev_priv->gart_vm_start - 1 +
				dev_priv->gart_size) & 0xffff0000) |
			      (dev_priv->gart_vm_start >> 16)));
L
Linus Torvalds 已提交
552 553 554 555

		ring_start = (dev_priv->cp_ring->offset
			      - dev->agp->base
			      + dev_priv->gart_vm_start);
556
	} else
L
Linus Torvalds 已提交
557 558
#endif
		ring_start = (dev_priv->cp_ring->offset
559
			      - (unsigned long)dev->sg->virtual
L
Linus Torvalds 已提交
560 561
			      + dev_priv->gart_vm_start);

D
Dave Airlie 已提交
562
	RADEON_WRITE(RADEON_CP_RB_BASE, ring_start);
L
Linus Torvalds 已提交
563 564

	/* Set the write pointer delay */
D
Dave Airlie 已提交
565
	RADEON_WRITE(RADEON_CP_RB_WPTR_DELAY, 0);
L
Linus Torvalds 已提交
566 567

	/* Initialize the ring buffer's read and write pointers */
D
Dave Airlie 已提交
568 569 570
	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 已提交
571 572 573
	dev_priv->ring.tail = cur_read_ptr;

#if __OS_HAS_AGP
574
	if (dev_priv->flags & RADEON_IS_AGP) {
D
Dave Airlie 已提交
575 576 577
		RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
			     dev_priv->ring_rptr->offset
			     - dev->agp->base + dev_priv->gart_vm_start);
L
Linus Torvalds 已提交
578 579 580
	} else
#endif
	{
D
Dave Airlie 已提交
581
		struct drm_sg_mem *entry = dev->sg;
L
Linus Torvalds 已提交
582 583
		unsigned long tmp_ofs, page_ofs;

584 585
		tmp_ofs = dev_priv->ring_rptr->offset -
				(unsigned long)dev->sg->virtual;
L
Linus Torvalds 已提交
586 587
		page_ofs = tmp_ofs >> PAGE_SHIFT;

D
Dave Airlie 已提交
588 589 590 591
		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 已提交
592 593
	}

594 595 596
	/* Set ring buffer size */
#ifdef __BIG_ENDIAN
	RADEON_WRITE(RADEON_CP_RB_CNTL,
597 598 599 600
		     RADEON_BUF_SWAP_32BIT |
		     (dev_priv->ring.fetch_size_l2ow << 18) |
		     (dev_priv->ring.rptr_update_l2qw << 8) |
		     dev_priv->ring.size_l2qw);
601
#else
602 603 604 605
	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);
606 607 608 609 610
#endif

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

L
Linus Torvalds 已提交
611 612 613 614 615 616 617
	/* 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 已提交
618 619
	RADEON_WRITE(RADEON_SCRATCH_ADDR, RADEON_READ(RADEON_CP_RB_RPTR_ADDR)
		     + RADEON_SCRATCH_REG_OFFSET);
L
Linus Torvalds 已提交
620 621 622 623 624

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

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

627 628 629
	/* Turn on bus mastering */
	tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
	RADEON_WRITE(RADEON_BUS_CNTL, tmp);
L
Linus Torvalds 已提交
630 631

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

	dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0;
D
Dave Airlie 已提交
635 636
	RADEON_WRITE(RADEON_LAST_DISPATCH_REG,
		     dev_priv->sarea_priv->last_dispatch);
L
Linus Torvalds 已提交
637 638

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

D
Dave Airlie 已提交
641
	radeon_do_wait_for_idle(dev_priv);
L
Linus Torvalds 已提交
642 643

	/* Sync everything up */
D
Dave Airlie 已提交
644 645 646 647 648
	RADEON_WRITE(RADEON_ISYNC_CNTL,
		     (RADEON_ISYNC_ANY2D_IDLE3D |
		      RADEON_ISYNC_ANY3D_IDLE2D |
		      RADEON_ISYNC_WAIT_IDLEGUI |
		      RADEON_ISYNC_CPSCRATCH_IDLEGUI));
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679

}

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");
	}
680 681 682 683 684 685 686

	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 已提交
687 688
}

689 690
/* Enable or disable IGP GART on the chip */
static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
691 692 693 694
{
	u32 temp;

	if (on) {
695
		DRM_DEBUG("programming igp gart %08X %08lX %08X\n",
696 697 698 699
			  dev_priv->gart_vm_start,
			  (long)dev_priv->gart_info.bus_addr,
			  dev_priv->gart_size);

700 701 702 703 704 705
		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);
706

707 708
		IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN |
							       RS480_VA_SIZE_32MB));
709

710 711 712 713 714
		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));
715

716 717
		temp = dev_priv->gart_info.bus_addr & 0xfffff000;
		temp |= (upper_32_bits(dev_priv->gart_info.bus_addr) & 0xff) << 4;
718 719 720 721 722 723 724 725 726 727 728 729 730 731
		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 已提交
732

733 734 735 736
		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));

737
		radeon_write_agp_location(dev_priv, temp);
738

739 740 741
		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));
742 743

		do {
744 745
			temp = IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL);
			if ((temp & RS480_GART_CACHE_INVALIDATE) == 0)
746 747 748 749
				break;
			DRM_UDELAY(1);
		} while (1);

750 751
		IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL,
				RS480_GART_CACHE_INVALIDATE);
752

753
		do {
754 755
			temp = IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL);
			if ((temp & RS480_GART_CACHE_INVALIDATE) == 0)
756 757 758 759
				break;
			DRM_UDELAY(1);
		} while (1);

760
		IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL, 0);
761
	} else {
762
		IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, 0);
763 764 765
	}
}

766 767 768 769 770 771
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 已提交
772 773
			  dev_priv->gart_vm_start,
			  (long)dev_priv->gart_info.bus_addr,
774
			  dev_priv->gart_size);
D
Dave Airlie 已提交
775 776 777 778 779 780 781 782 783 784
		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 已提交
785
		radeon_write_agp_location(dev_priv, 0xffffffc0); /* ?? */
D
Dave Airlie 已提交
786 787 788

		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL,
				  RADEON_PCIE_TX_GART_EN);
789
	} else {
D
Dave Airlie 已提交
790 791
		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL,
				  tmp & ~RADEON_PCIE_TX_GART_EN);
792
	}
L
Linus Torvalds 已提交
793 794 795
}

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

800 801
	if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
	    (dev_priv->flags & RADEON_IS_IGPGART)) {
802 803 804 805
		radeon_set_igpgart(dev_priv, on);
		return;
	}

806
	if (dev_priv->flags & RADEON_IS_PCIE) {
807 808 809
		radeon_set_pciegart(dev_priv, on);
		return;
	}
L
Linus Torvalds 已提交
810

D
Dave Airlie 已提交
811
	tmp = RADEON_READ(RADEON_AIC_CNTL);
812

D
Dave Airlie 已提交
813 814 815
	if (on) {
		RADEON_WRITE(RADEON_AIC_CNTL,
			     tmp | RADEON_PCIGART_TRANSLATE_EN);
L
Linus Torvalds 已提交
816 817 818

		/* set PCI GART page-table base address
		 */
819
		RADEON_WRITE(RADEON_AIC_PT_BASE, dev_priv->gart_info.bus_addr);
L
Linus Torvalds 已提交
820 821 822

		/* set address range for PCI address translate
		 */
D
Dave Airlie 已提交
823 824 825
		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 已提交
826 827 828

		/* Turn off AGP aperture -- is this required for PCI GART?
		 */
D
Dave Airlie 已提交
829
		radeon_write_agp_location(dev_priv, 0xffffffc0);
D
Dave Airlie 已提交
830
		RADEON_WRITE(RADEON_AGP_COMMAND, 0);	/* clear AGP_COMMAND */
L
Linus Torvalds 已提交
831
	} else {
D
Dave Airlie 已提交
832 833
		RADEON_WRITE(RADEON_AIC_CNTL,
			     tmp & ~RADEON_PCIGART_TRANSLATE_EN);
L
Linus Torvalds 已提交
834 835 836
	}
}

837
static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
L
Linus Torvalds 已提交
838
{
839 840
	drm_radeon_private_t *dev_priv = dev->dev_private;

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

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

850
	if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) {
851
		DRM_DEBUG("Forcing AGP card to PCI mode\n");
852 853
		dev_priv->flags &= ~RADEON_IS_AGP;
	} else if (!(dev_priv->flags & (RADEON_IS_AGP | RADEON_IS_PCI | RADEON_IS_PCIE))
854 855
		   && !init->is_pci) {
		DRM_DEBUG("Restoring AGP flag\n");
856
		dev_priv->flags |= RADEON_IS_AGP;
857
	}
L
Linus Torvalds 已提交
858

859
	if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) {
D
Dave Airlie 已提交
860
		DRM_ERROR("PCI GART memory not allocated!\n");
L
Linus Torvalds 已提交
861
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
862
		return -EINVAL;
L
Linus Torvalds 已提交
863 864 865
	}

	dev_priv->usec_timeout = init->usec_timeout;
D
Dave Airlie 已提交
866 867 868
	if (dev_priv->usec_timeout < 1 ||
	    dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT) {
		DRM_DEBUG("TIMEOUT problem!\n");
L
Linus Torvalds 已提交
869
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
870
		return -EINVAL;
L
Linus Torvalds 已提交
871 872
	}

873 874 875 876
	/* Enable vblank on CRTC1 for older X servers
	 */
	dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1;

877
	switch(init->func) {
L
Linus Torvalds 已提交
878
	case RADEON_INIT_R200_CP:
D
Dave Airlie 已提交
879
		dev_priv->microcode_version = UCODE_R200;
L
Linus Torvalds 已提交
880 881
		break;
	case RADEON_INIT_R300_CP:
D
Dave Airlie 已提交
882
		dev_priv->microcode_version = UCODE_R300;
L
Linus Torvalds 已提交
883 884
		break;
	default:
D
Dave Airlie 已提交
885
		dev_priv->microcode_version = UCODE_R100;
L
Linus Torvalds 已提交
886
	}
D
Dave Airlie 已提交
887

L
Linus Torvalds 已提交
888 889 890 891 892 893 894
	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 已提交
895 896 897
	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 已提交
898
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
899
		return -EINVAL;
L
Linus Torvalds 已提交
900 901
	}

D
Dave Airlie 已提交
902
	switch (init->fb_bpp) {
L
Linus Torvalds 已提交
903 904 905 906 907 908 909 910
	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 已提交
911 912 913 914
	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 已提交
915

D
Dave Airlie 已提交
916
	switch (init->depth_bpp) {
L
Linus Torvalds 已提交
917 918 919 920 921 922 923 924
	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 已提交
925 926
	dev_priv->depth_offset = init->depth_offset;
	dev_priv->depth_pitch = init->depth_pitch;
L
Linus Torvalds 已提交
927 928 929 930 931 932 933 934

	/* 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 已提交
935 936
					   (dev_priv->microcode_version ==
					    UCODE_R100 ? RADEON_ZBLOCK16 : 0));
L
Linus Torvalds 已提交
937

D
Dave Airlie 已提交
938 939 940 941 942 943 944
	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 已提交
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962

	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 已提交
963

964
	dev_priv->sarea = drm_getsarea(dev);
D
Dave Airlie 已提交
965
	if (!dev_priv->sarea) {
L
Linus Torvalds 已提交
966 967
		DRM_ERROR("could not find sarea!\n");
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
968
		return -EINVAL;
L
Linus Torvalds 已提交
969 970 971
	}

	dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset);
D
Dave Airlie 已提交
972
	if (!dev_priv->cp_ring) {
L
Linus Torvalds 已提交
973 974
		DRM_ERROR("could not find cp ring region!\n");
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
975
		return -EINVAL;
L
Linus Torvalds 已提交
976 977
	}
	dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
D
Dave Airlie 已提交
978
	if (!dev_priv->ring_rptr) {
L
Linus Torvalds 已提交
979 980
		DRM_ERROR("could not find ring read pointer!\n");
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
981
		return -EINVAL;
L
Linus Torvalds 已提交
982
	}
983
	dev->agp_buffer_token = init->buffers_offset;
L
Linus Torvalds 已提交
984
	dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
D
Dave Airlie 已提交
985
	if (!dev->agp_buffer_map) {
L
Linus Torvalds 已提交
986 987
		DRM_ERROR("could not find dma buffer region!\n");
		radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
988
		return -EINVAL;
L
Linus Torvalds 已提交
989 990
	}

D
Dave Airlie 已提交
991 992 993 994
	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 已提交
995 996
			DRM_ERROR("could not find GART texture region!\n");
			radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
997
			return -EINVAL;
L
Linus Torvalds 已提交
998 999 1000 1001
		}
	}

	dev_priv->sarea_priv =
D
Dave Airlie 已提交
1002 1003
	    (drm_radeon_sarea_t *) ((u8 *) dev_priv->sarea->handle +
				    init->sarea_priv_offset);
L
Linus Torvalds 已提交
1004 1005

#if __OS_HAS_AGP
1006
	if (dev_priv->flags & RADEON_IS_AGP) {
D
Dave Airlie 已提交
1007 1008 1009 1010 1011 1012
		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 已提交
1013 1014
			DRM_ERROR("could not find ioremap agp regions!\n");
			radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
1015
			return -EINVAL;
L
Linus Torvalds 已提交
1016 1017 1018 1019
		}
	} else
#endif
	{
D
Dave Airlie 已提交
1020
		dev_priv->cp_ring->handle = (void *)dev_priv->cp_ring->offset;
L
Linus Torvalds 已提交
1021
		dev_priv->ring_rptr->handle =
D
Dave Airlie 已提交
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
		    (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 已提交
1032 1033
	}

D
Dave Airlie 已提交
1034
	dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 16;
D
Dave Airlie 已提交
1035
	dev_priv->fb_size =
D
Dave Airlie 已提交
1036
		((radeon_read_fb_location(dev_priv) & 0xffff0000u) + 0x10000)
1037
		- dev_priv->fb_location;
L
Linus Torvalds 已提交
1038

D
Dave Airlie 已提交
1039 1040 1041
	dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) |
					((dev_priv->front_offset
					  + dev_priv->fb_location) >> 10));
L
Linus Torvalds 已提交
1042

D
Dave Airlie 已提交
1043 1044 1045
	dev_priv->back_pitch_offset = (((dev_priv->back_pitch / 64) << 22) |
				       ((dev_priv->back_offset
					 + dev_priv->fb_location) >> 10));
L
Linus Torvalds 已提交
1046

D
Dave Airlie 已提交
1047 1048 1049
	dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch / 64) << 22) |
					((dev_priv->depth_offset
					  + dev_priv->fb_location) >> 10));
L
Linus Torvalds 已提交
1050 1051

	dev_priv->gart_size = init->gart_size;
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063

	/* 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
1064
		if (dev_priv->flags & RADEON_IS_AGP) {
1065 1066
			base = dev->agp->base;
			/* Check if valid */
1067 1068
			if ((base + dev_priv->gart_size - 1) >= dev_priv->fb_location &&
			    base < (dev_priv->fb_location + dev_priv->fb_size - 1)) {
1069 1070 1071 1072 1073 1074 1075 1076 1077
				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;
1078 1079
			if (base < dev_priv->fb_location ||
			    ((base + dev_priv->gart_size) & 0xfffffffful) < base)
1080 1081
				base = dev_priv->fb_location
					- dev_priv->gart_size;
D
Dave Airlie 已提交
1082
		}
1083 1084 1085 1086 1087 1088 1089 1090 1091
		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 已提交
1092 1093

#if __OS_HAS_AGP
1094
	if (dev_priv->flags & RADEON_IS_AGP)
L
Linus Torvalds 已提交
1095
		dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
D
Dave Airlie 已提交
1096 1097
						 - dev->agp->base
						 + dev_priv->gart_vm_start);
L
Linus Torvalds 已提交
1098 1099 1100
	else
#endif
		dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
1101 1102
					- (unsigned long)dev->sg->virtual
					+ dev_priv->gart_vm_start);
L
Linus Torvalds 已提交
1103

D
Dave Airlie 已提交
1104 1105 1106 1107
	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 已提交
1108

D
Dave Airlie 已提交
1109 1110
	dev_priv->ring.start = (u32 *) dev_priv->cp_ring->handle;
	dev_priv->ring.end = ((u32 *) dev_priv->cp_ring->handle
L
Linus Torvalds 已提交
1111 1112
			      + init->ring_size / sizeof(u32));
	dev_priv->ring.size = init->ring_size;
D
Dave Airlie 已提交
1113
	dev_priv->ring.size_l2qw = drm_order(init->ring_size / 8);
L
Linus Torvalds 已提交
1114

1115 1116 1117 1118 1119
	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 已提交
1120
	dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
L
Linus Torvalds 已提交
1121 1122 1123 1124

	dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;

#if __OS_HAS_AGP
1125
	if (dev_priv->flags & RADEON_IS_AGP) {
L
Linus Torvalds 已提交
1126
		/* Turn off PCI GART */
D
Dave Airlie 已提交
1127
		radeon_set_pcigart(dev_priv, 0);
L
Linus Torvalds 已提交
1128 1129 1130
	} else
#endif
	{
1131
		dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
1132
		/* if we have an offset set from userspace */
1133
		if (dev_priv->pcigart_offset_set) {
D
Dave Airlie 已提交
1134 1135
			dev_priv->gart_info.bus_addr =
			    dev_priv->pcigart_offset + dev_priv->fb_location;
1136
			dev_priv->gart_info.mapping.offset =
1137
			    dev_priv->pcigart_offset + dev_priv->fb_aper_offset;
1138
			dev_priv->gart_info.mapping.size =
1139
			    dev_priv->gart_info.table_size;
1140 1141

			drm_core_ioremap(&dev_priv->gart_info.mapping, dev);
D
Dave Airlie 已提交
1142
			dev_priv->gart_info.addr =
1143
			    dev_priv->gart_info.mapping.handle;
D
Dave Airlie 已提交
1144

1145 1146 1147 1148
			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 已提交
1149 1150 1151
			dev_priv->gart_info.gart_table_location =
			    DRM_ATI_GART_FB;

1152
			DRM_DEBUG("Setting phys_pci_gart to %p %08lX\n",
D
Dave Airlie 已提交
1153 1154 1155
				  dev_priv->gart_info.addr,
				  dev_priv->pcigart_offset);
		} else {
1156 1157 1158 1159
			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 已提交
1160 1161
			dev_priv->gart_info.gart_table_location =
			    DRM_ATI_GART_MAIN;
1162 1163
			dev_priv->gart_info.addr = NULL;
			dev_priv->gart_info.bus_addr = 0;
1164
			if (dev_priv->flags & RADEON_IS_PCIE) {
D
Dave Airlie 已提交
1165 1166
				DRM_ERROR
				    ("Cannot use PCI Express without GART in FB memory\n");
1167
				radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
1168
				return -EINVAL;
1169 1170 1171 1172
			}
		}

		if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
D
Dave Airlie 已提交
1173
			DRM_ERROR("failed to init PCI GART!\n");
L
Linus Torvalds 已提交
1174
			radeon_do_cleanup_cp(dev);
E
Eric Anholt 已提交
1175
			return -ENOMEM;
L
Linus Torvalds 已提交
1176 1177 1178
		}

		/* Turn on PCI GART */
D
Dave Airlie 已提交
1179
		radeon_set_pcigart(dev_priv, 1);
L
Linus Torvalds 已提交
1180 1181
	}

D
Dave Airlie 已提交
1182 1183
	radeon_cp_load_microcode(dev_priv);
	radeon_cp_init_ring_buffer(dev, dev_priv);
L
Linus Torvalds 已提交
1184 1185 1186

	dev_priv->last_buf = 0;

D
Dave Airlie 已提交
1187
	radeon_do_engine_reset(dev);
1188
	radeon_test_writeback(dev_priv);
L
Linus Torvalds 已提交
1189 1190 1191 1192

	return 0;
}

1193
static int radeon_do_cleanup_cp(struct drm_device * dev)
L
Linus Torvalds 已提交
1194 1195
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
D
Dave Airlie 已提交
1196
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
1197 1198 1199 1200 1201

	/* 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 已提交
1202 1203
	if (dev->irq_enabled)
		drm_irq_uninstall(dev);
L
Linus Torvalds 已提交
1204 1205

#if __OS_HAS_AGP
1206
	if (dev_priv->flags & RADEON_IS_AGP) {
1207
		if (dev_priv->cp_ring != NULL) {
D
Dave Airlie 已提交
1208
			drm_core_ioremapfree(dev_priv->cp_ring, dev);
1209 1210 1211
			dev_priv->cp_ring = NULL;
		}
		if (dev_priv->ring_rptr != NULL) {
D
Dave Airlie 已提交
1212
			drm_core_ioremapfree(dev_priv->ring_rptr, dev);
1213 1214
			dev_priv->ring_rptr = NULL;
		}
D
Dave Airlie 已提交
1215 1216
		if (dev->agp_buffer_map != NULL) {
			drm_core_ioremapfree(dev->agp_buffer_map, dev);
L
Linus Torvalds 已提交
1217 1218 1219 1220 1221
			dev->agp_buffer_map = NULL;
		}
	} else
#endif
	{
1222 1223 1224 1225

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

1230 1231
		if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB)
		{
1232
			drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev);
1233
			dev_priv->gart_info.addr = 0;
1234
		}
L
Linus Torvalds 已提交
1235 1236 1237 1238 1239 1240 1241
	}
	/* only clear to the start of flags */
	memset(dev_priv, 0, offsetof(drm_radeon_private_t, flags));

	return 0;
}

D
Dave Airlie 已提交
1242 1243
/* 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 已提交
1244 1245 1246 1247 1248
 * here we make sure that all Radeon hardware initialisation is re-done without
 * affecting running applications.
 *
 * Charl P. Botha <http://cpbotha.net>
 */
1249
static int radeon_do_resume_cp(struct drm_device * dev)
L
Linus Torvalds 已提交
1250 1251 1252
{
	drm_radeon_private_t *dev_priv = dev->dev_private;

D
Dave Airlie 已提交
1253 1254
	if (!dev_priv) {
		DRM_ERROR("Called with no initialization\n");
E
Eric Anholt 已提交
1255
		return -EINVAL;
L
Linus Torvalds 已提交
1256 1257 1258 1259 1260
	}

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

#if __OS_HAS_AGP
1261
	if (dev_priv->flags & RADEON_IS_AGP) {
L
Linus Torvalds 已提交
1262
		/* Turn off PCI GART */
D
Dave Airlie 已提交
1263
		radeon_set_pcigart(dev_priv, 0);
L
Linus Torvalds 已提交
1264 1265 1266 1267
	} else
#endif
	{
		/* Turn on PCI GART */
D
Dave Airlie 已提交
1268
		radeon_set_pcigart(dev_priv, 1);
L
Linus Torvalds 已提交
1269 1270
	}

D
Dave Airlie 已提交
1271 1272
	radeon_cp_load_microcode(dev_priv);
	radeon_cp_init_ring_buffer(dev, dev_priv);
L
Linus Torvalds 已提交
1273

D
Dave Airlie 已提交
1274
	radeon_do_engine_reset(dev);
L
Linus Torvalds 已提交
1275 1276 1277 1278 1279 1280

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

	return 0;
}

1281
int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1282
{
1283
	drm_radeon_init_t *init = data;
L
Linus Torvalds 已提交
1284

1285
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1286

1287
	if (init->func == RADEON_INIT_R300_CP)
D
Dave Airlie 已提交
1288
		r300_init_reg_flags(dev);
D
Dave Airlie 已提交
1289

1290
	switch (init->func) {
L
Linus Torvalds 已提交
1291 1292 1293
	case RADEON_INIT_CP:
	case RADEON_INIT_R200_CP:
	case RADEON_INIT_R300_CP:
1294
		return radeon_do_init_cp(dev, init);
L
Linus Torvalds 已提交
1295
	case RADEON_CLEANUP_CP:
D
Dave Airlie 已提交
1296
		return radeon_do_cleanup_cp(dev);
L
Linus Torvalds 已提交
1297 1298
	}

E
Eric Anholt 已提交
1299
	return -EINVAL;
L
Linus Torvalds 已提交
1300 1301
}

1302
int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1303 1304
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
D
Dave Airlie 已提交
1305
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
1306

1307
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1308

D
Dave Airlie 已提交
1309
	if (dev_priv->cp_running) {
1310
		DRM_DEBUG("while CP running\n");
L
Linus Torvalds 已提交
1311 1312
		return 0;
	}
D
Dave Airlie 已提交
1313
	if (dev_priv->cp_mode == RADEON_CSQ_PRIDIS_INDDIS) {
1314 1315
		DRM_DEBUG("called with bogus CP mode (%d)\n",
			  dev_priv->cp_mode);
L
Linus Torvalds 已提交
1316 1317 1318
		return 0;
	}

D
Dave Airlie 已提交
1319
	radeon_do_cp_start(dev_priv);
L
Linus Torvalds 已提交
1320 1321 1322 1323 1324 1325 1326

	return 0;
}

/* Stop the CP.  The engine must have been idled before calling this
 * routine.
 */
1327
int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1328 1329
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
1330
	drm_radeon_cp_stop_t *stop = data;
L
Linus Torvalds 已提交
1331
	int ret;
D
Dave Airlie 已提交
1332
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
1333

1334
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1335 1336 1337 1338 1339 1340 1341

	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.
	 */
1342
	if (stop->flush) {
D
Dave Airlie 已提交
1343
		radeon_do_cp_flush(dev_priv);
L
Linus Torvalds 已提交
1344 1345 1346 1347 1348
	}

	/* If we fail to make the engine go idle, we return an error
	 * code so that the DRM ioctl wrapper can try again.
	 */
1349
	if (stop->idle) {
D
Dave Airlie 已提交
1350 1351 1352
		ret = radeon_do_cp_idle(dev_priv);
		if (ret)
			return ret;
L
Linus Torvalds 已提交
1353 1354 1355 1356 1357 1358
	}

	/* 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 已提交
1359
	radeon_do_cp_stop(dev_priv);
L
Linus Torvalds 已提交
1360 1361

	/* Reset the engine */
D
Dave Airlie 已提交
1362
	radeon_do_engine_reset(dev);
L
Linus Torvalds 已提交
1363 1364 1365 1366

	return 0;
}

1367
void radeon_do_release(struct drm_device * dev)
L
Linus Torvalds 已提交
1368 1369 1370 1371 1372 1373 1374
{
	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 已提交
1375
			while ((ret = radeon_do_cp_idle(dev_priv)) != 0) {
L
Linus Torvalds 已提交
1376 1377 1378 1379 1380 1381 1382
				DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
#ifdef __linux__
				schedule();
#else
				tsleep(&ret, PZERO, "rdnrel", 1);
#endif
			}
D
Dave Airlie 已提交
1383 1384
			radeon_do_cp_stop(dev_priv);
			radeon_do_engine_reset(dev);
L
Linus Torvalds 已提交
1385 1386 1387 1388
		}

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

D
Dave Airlie 已提交
1391
		if (dev_priv->mmio) {	/* remove all surfaces */
L
Linus Torvalds 已提交
1392
			for (i = 0; i < RADEON_MAX_SURFACES; i++) {
D
Dave Airlie 已提交
1393 1394 1395 1396 1397
				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 已提交
1398 1399 1400 1401
			}
		}

		/* Free memory heap structures */
D
Dave Airlie 已提交
1402 1403
		radeon_mem_takedown(&(dev_priv->gart_heap));
		radeon_mem_takedown(&(dev_priv->fb_heap));
L
Linus Torvalds 已提交
1404 1405

		/* deallocate kernel resources */
D
Dave Airlie 已提交
1406
		radeon_do_cleanup_cp(dev);
L
Linus Torvalds 已提交
1407 1408 1409 1410 1411
	}
}

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

1417
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1418

D
Dave Airlie 已提交
1419
	if (!dev_priv) {
1420
		DRM_DEBUG("called before init done\n");
E
Eric Anholt 已提交
1421
		return -EINVAL;
L
Linus Torvalds 已提交
1422 1423
	}

D
Dave Airlie 已提交
1424
	radeon_do_cp_reset(dev_priv);
L
Linus Torvalds 已提交
1425 1426 1427 1428 1429 1430 1431

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

	return 0;
}

1432
int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1433 1434
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
D
Dave Airlie 已提交
1435
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
1436

1437
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1438

D
Dave Airlie 已提交
1439
	return radeon_do_cp_idle(dev_priv);
L
Linus Torvalds 已提交
1440 1441 1442 1443
}

/* Added by Charl P. Botha to call radeon_do_resume_cp().
 */
1444
int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1445 1446 1447 1448 1449
{

	return radeon_do_resume_cp(dev);
}

1450
int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1451
{
D
Dave Airlie 已提交
1452
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
1453

1454
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1455

D
Dave Airlie 已提交
1456
	return radeon_do_engine_reset(dev);
L
Linus Torvalds 已提交
1457 1458 1459 1460 1461 1462 1463 1464
}

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

/* KW: Deprecated to say the least:
 */
1465
int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477
{
	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 已提交
1478
 *   completed rendering.
L
Linus Torvalds 已提交
1479 1480 1481 1482 1483 1484
 *
 * 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 已提交
1485
 *
L
Linus Torvalds 已提交
1486 1487
 * 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 已提交
1488
 * they can't get the lock.
L
Linus Torvalds 已提交
1489 1490
 */

D
Dave Airlie 已提交
1491
struct drm_buf *radeon_freelist_get(struct drm_device * dev)
L
Linus Torvalds 已提交
1492
{
1493
	struct drm_device_dma *dma = dev->dma;
L
Linus Torvalds 已提交
1494 1495
	drm_radeon_private_t *dev_priv = dev->dev_private;
	drm_radeon_buf_priv_t *buf_priv;
D
Dave Airlie 已提交
1496
	struct drm_buf *buf;
L
Linus Torvalds 已提交
1497 1498 1499
	int i, t;
	int start;

D
Dave Airlie 已提交
1500
	if (++dev_priv->last_buf >= dma->buf_count)
L
Linus Torvalds 已提交
1501 1502 1503 1504
		dev_priv->last_buf = 0;

	start = dev_priv->last_buf;

D
Dave Airlie 已提交
1505 1506 1507 1508
	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 已提交
1509 1510
			buf = dma->buflist[i];
			buf_priv = buf->dev_private;
1511 1512 1513
			if (buf->file_priv == NULL || (buf->pending &&
						       buf_priv->age <=
						       done_age)) {
L
Linus Torvalds 已提交
1514 1515 1516 1517 1518 1519 1520 1521
				dev_priv->stats.requested_bufs++;
				buf->pending = 0;
				return buf;
			}
			start = 0;
		}

		if (t) {
D
Dave Airlie 已提交
1522
			DRM_UDELAY(1);
L
Linus Torvalds 已提交
1523 1524 1525 1526
			dev_priv->stats.freelist_loops++;
		}
	}

D
Dave Airlie 已提交
1527
	DRM_DEBUG("returning NULL!\n");
L
Linus Torvalds 已提交
1528 1529
	return NULL;
}
D
Dave Airlie 已提交
1530

L
Linus Torvalds 已提交
1531
#if 0
D
Dave Airlie 已提交
1532
struct drm_buf *radeon_freelist_get(struct drm_device * dev)
L
Linus Torvalds 已提交
1533
{
1534
	struct drm_device_dma *dma = dev->dma;
L
Linus Torvalds 已提交
1535 1536
	drm_radeon_private_t *dev_priv = dev->dev_private;
	drm_radeon_buf_priv_t *buf_priv;
D
Dave Airlie 已提交
1537
	struct drm_buf *buf;
L
Linus Torvalds 已提交
1538 1539 1540 1541
	int i, t;
	int start;
	u32 done_age = DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1));

D
Dave Airlie 已提交
1542
	if (++dev_priv->last_buf >= dma->buf_count)
L
Linus Torvalds 已提交
1543 1544 1545 1546
		dev_priv->last_buf = 0;

	start = dev_priv->last_buf;
	dev_priv->stats.freelist_loops++;
D
Dave Airlie 已提交
1547 1548 1549

	for (t = 0; t < 2; t++) {
		for (i = start; i < dma->buf_count; i++) {
L
Linus Torvalds 已提交
1550 1551
			buf = dma->buflist[i];
			buf_priv = buf->dev_private;
1552 1553 1554
			if (buf->file_priv == 0 || (buf->pending &&
						    buf_priv->age <=
						    done_age)) {
L
Linus Torvalds 已提交
1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566
				dev_priv->stats.requested_bufs++;
				buf->pending = 0;
				return buf;
			}
		}
		start = 0;
	}

	return NULL;
}
#endif

1567
void radeon_freelist_reset(struct drm_device * dev)
L
Linus Torvalds 已提交
1568
{
1569
	struct drm_device_dma *dma = dev->dma;
L
Linus Torvalds 已提交
1570 1571 1572 1573
	drm_radeon_private_t *dev_priv = dev->dev_private;
	int i;

	dev_priv->last_buf = 0;
D
Dave Airlie 已提交
1574
	for (i = 0; i < dma->buf_count; i++) {
D
Dave Airlie 已提交
1575
		struct drm_buf *buf = dma->buflist[i];
L
Linus Torvalds 已提交
1576 1577 1578 1579 1580 1581 1582 1583 1584
		drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
		buf_priv->age = 0;
	}
}

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

D
Dave Airlie 已提交
1585
int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n)
L
Linus Torvalds 已提交
1586 1587 1588
{
	drm_radeon_ring_buffer_t *ring = &dev_priv->ring;
	int i;
D
Dave Airlie 已提交
1589
	u32 last_head = GET_RING_HEAD(dev_priv);
L
Linus Torvalds 已提交
1590

D
Dave Airlie 已提交
1591 1592
	for (i = 0; i < dev_priv->usec_timeout; i++) {
		u32 head = GET_RING_HEAD(dev_priv);
L
Linus Torvalds 已提交
1593 1594

		ring->space = (head - ring->tail) * sizeof(u32);
D
Dave Airlie 已提交
1595
		if (ring->space <= 0)
L
Linus Torvalds 已提交
1596
			ring->space += ring->size;
D
Dave Airlie 已提交
1597
		if (ring->space > n)
L
Linus Torvalds 已提交
1598
			return 0;
D
Dave Airlie 已提交
1599

L
Linus Torvalds 已提交
1600 1601 1602 1603 1604 1605
		dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;

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

D
Dave Airlie 已提交
1606
		DRM_UDELAY(1);
L
Linus Torvalds 已提交
1607 1608 1609 1610
	}

	/* FIXME: This return value is ignored in the BEGIN_RING macro! */
#if RADEON_FIFO_DEBUG
D
Dave Airlie 已提交
1611 1612
	radeon_status(dev_priv);
	DRM_ERROR("failed!\n");
L
Linus Torvalds 已提交
1613
#endif
E
Eric Anholt 已提交
1614
	return -EBUSY;
L
Linus Torvalds 已提交
1615 1616
}

1617 1618
static int radeon_cp_get_buffers(struct drm_device *dev,
				 struct drm_file *file_priv,
1619
				 struct drm_dma * d)
L
Linus Torvalds 已提交
1620 1621
{
	int i;
D
Dave Airlie 已提交
1622
	struct drm_buf *buf;
L
Linus Torvalds 已提交
1623

D
Dave Airlie 已提交
1624 1625 1626
	for (i = d->granted_count; i < d->request_count; i++) {
		buf = radeon_freelist_get(dev);
		if (!buf)
E
Eric Anholt 已提交
1627
			return -EBUSY;	/* NOTE: broken client */
L
Linus Torvalds 已提交
1628

1629
		buf->file_priv = file_priv;
L
Linus Torvalds 已提交
1630

D
Dave Airlie 已提交
1631 1632
		if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
				     sizeof(buf->idx)))
E
Eric Anholt 已提交
1633
			return -EFAULT;
D
Dave Airlie 已提交
1634 1635
		if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
				     sizeof(buf->total)))
E
Eric Anholt 已提交
1636
			return -EFAULT;
L
Linus Torvalds 已提交
1637 1638 1639 1640 1641 1642

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

1643
int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1644
{
1645
	struct drm_device_dma *dma = dev->dma;
L
Linus Torvalds 已提交
1646
	int ret = 0;
1647
	struct drm_dma *d = data;
L
Linus Torvalds 已提交
1648

1649
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1650 1651 1652

	/* Please don't send us buffers.
	 */
1653
	if (d->send_count != 0) {
D
Dave Airlie 已提交
1654
		DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
1655
			  DRM_CURRENTPID, d->send_count);
E
Eric Anholt 已提交
1656
		return -EINVAL;
L
Linus Torvalds 已提交
1657 1658 1659 1660
	}

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

1667
	d->granted_count = 0;
L
Linus Torvalds 已提交
1668

1669 1670
	if (d->request_count) {
		ret = radeon_cp_get_buffers(dev, file_priv, d);
L
Linus Torvalds 已提交
1671 1672 1673 1674 1675
	}

	return ret;
}

1676
int radeon_driver_load(struct drm_device *dev, unsigned long flags)
L
Linus Torvalds 已提交
1677 1678 1679 1680 1681 1682
{
	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 已提交
1683
		return -ENOMEM;
L
Linus Torvalds 已提交
1684 1685 1686 1687 1688

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

1689
	switch (flags & RADEON_FAMILY_MASK) {
L
Linus Torvalds 已提交
1690 1691 1692 1693
	case CHIP_R100:
	case CHIP_RV200:
	case CHIP_R200:
	case CHIP_R300:
1694
	case CHIP_R350:
D
Dave Airlie 已提交
1695
	case CHIP_R420:
1696
	case CHIP_RV410:
D
Dave Airlie 已提交
1697 1698 1699 1700
	case CHIP_RV515:
	case CHIP_R520:
	case CHIP_RV570:
	case CHIP_R580:
1701
		dev_priv->flags |= RADEON_HAS_HIERZ;
L
Linus Torvalds 已提交
1702 1703
		break;
	default:
D
Dave Airlie 已提交
1704
		/* all other chips have no hierarchical z buffer */
L
Linus Torvalds 已提交
1705 1706
		break;
	}
D
Dave Airlie 已提交
1707 1708

	if (drm_device_is_agp(dev))
1709
		dev_priv->flags |= RADEON_IS_AGP;
1710
	else if (drm_device_is_pcie(dev))
1711
		dev_priv->flags |= RADEON_IS_PCIE;
1712
	else
1713
		dev_priv->flags |= RADEON_IS_PCI;
1714

D
Dave Airlie 已提交
1715
	DRM_DEBUG("%s card detected\n",
1716
		  ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI"))));
L
Linus Torvalds 已提交
1717 1718 1719
	return ret;
}

1720 1721 1722 1723
/* 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 已提交
1724 1725 1726 1727 1728
{
	int ret;
	drm_local_map_t *map;
	drm_radeon_private_t *dev_priv = dev->dev_private;

1729 1730
	dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;

D
Dave Airlie 已提交
1731 1732 1733 1734 1735 1736
	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;

1737 1738
	dev_priv->fb_aper_offset = drm_get_resource_start(dev, 0);
	ret = drm_addmap(dev, dev_priv->fb_aper_offset,
D
Dave Airlie 已提交
1739 1740 1741 1742 1743 1744 1745 1746
			 drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER,
			 _DRM_WRITE_COMBINING, &map);
	if (ret != 0)
		return ret;

	return 0;
}

1747
int radeon_driver_unload(struct drm_device *dev)
L
Linus Torvalds 已提交
1748 1749 1750 1751 1752 1753 1754 1755 1756
{
	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;
}