Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c05ce083 authored by Alex Deucher's avatar Alex Deucher Committed by Dave Airlie
Browse files

drm/radeon: add initial support for R6xx/R7xx GPUs



This adds support for 2D/Xv acceleration in the X.org 2D driver,
to the drm. It doesn't yet provide any 3D support hooks.

Signed-off-by: default avatarAlex Deucher <alexdeucher@gmail.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 80b3334a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.

ccflags-y := -Iinclude/drm
radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o r600_cp.o

radeon-$(CONFIG_COMPAT) += radeon_ioc32.o

+2247 −0

File added.

Preview size limit exceeded, changes collapsed.

+141 −47
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@
static int radeon_do_cleanup_cp(struct drm_device * dev);
static void radeon_do_cp_start(drm_radeon_private_t * dev_priv);

static u32 radeon_read_ring_rptr(drm_radeon_private_t *dev_priv, u32 off)
u32 radeon_read_ring_rptr(drm_radeon_private_t *dev_priv, u32 off)
{
	u32 val;

@@ -62,11 +62,15 @@ u32 radeon_get_ring_head(drm_radeon_private_t *dev_priv)
{
	if (dev_priv->writeback_works)
		return radeon_read_ring_rptr(dev_priv, 0);
	else {
		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
			return RADEON_READ(R600_CP_RB_RPTR);
		else
			return RADEON_READ(RADEON_CP_RB_RPTR);
	}
}

static void radeon_write_ring_rptr(drm_radeon_private_t *dev_priv, u32 off, u32 val)
void radeon_write_ring_rptr(drm_radeon_private_t *dev_priv, u32 off, u32 val)
{
	if (dev_priv->flags & RADEON_IS_AGP)
		DRM_WRITE32(dev_priv->ring_rptr, off, val);
@@ -82,12 +86,20 @@ void radeon_set_ring_head(drm_radeon_private_t *dev_priv, u32 val)

u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index)
{
	if (dev_priv->writeback_works)
	if (dev_priv->writeback_works) {
		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
			return radeon_read_ring_rptr(dev_priv,
						     R600_SCRATCHOFF(index));
		else
			return radeon_read_ring_rptr(dev_priv,
						     RADEON_SCRATCHOFF(index));
	} else {
		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
			return RADEON_READ(R600_SCRATCH_REG0 + 4*index);
		else
			return RADEON_READ(RADEON_SCRATCH_REG0 + 4*index);
	}
}

u32 RADEON_READ_MM(drm_radeon_private_t *dev_priv, int addr)
{
@@ -142,7 +154,11 @@ static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
{

	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
		return RADEON_READ(R700_MC_VM_FB_LOCATION);
	else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
		return RADEON_READ(R600_MC_VM_FB_LOCATION);
	else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
		return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
	else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
		 ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
@@ -155,7 +171,11 @@ u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)

static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
{
	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
		RADEON_WRITE(R700_MC_VM_FB_LOCATION, fb_loc);
	else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
		RADEON_WRITE(R600_MC_VM_FB_LOCATION, fb_loc);
	else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
		R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
	else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
		 ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
@@ -166,9 +186,16 @@ static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
		RADEON_WRITE(RADEON_MC_FB_LOCATION, fb_loc);
}

static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc)
void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc)
{
	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
	/*R6xx/R7xx: AGP_TOP and BOT are actually 18 bits each */
	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) {
		RADEON_WRITE(R700_MC_VM_AGP_BOT, agp_loc & 0xffff); /* FIX ME */
		RADEON_WRITE(R700_MC_VM_AGP_TOP, (agp_loc >> 16) & 0xffff);
	} else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
		RADEON_WRITE(R600_MC_VM_AGP_BOT, agp_loc & 0xffff); /* FIX ME */
		RADEON_WRITE(R600_MC_VM_AGP_TOP, (agp_loc >> 16) & 0xffff);
	} else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
		R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
	else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
		 ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
@@ -179,12 +206,18 @@ static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_lo
		RADEON_WRITE(RADEON_MC_AGP_LOCATION, agp_loc);
}

static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
{
	u32 agp_base_hi = upper_32_bits(agp_base);
	u32 agp_base_lo = agp_base & 0xffffffff;

	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) {
	u32 r6xx_agp_base = (agp_base >> 22) & 0x3ffff;

	/* R6xx/R7xx must be aligned to a 4MB boundry */
	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
		RADEON_WRITE(R700_MC_VM_AGP_BASE, r6xx_agp_base);
	else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
		RADEON_WRITE(R600_MC_VM_AGP_BASE, r6xx_agp_base);
	else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) {
		R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo);
		R500_WRITE_MCIND(RV515_MC_AGP_BASE_2, agp_base_hi);
	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
@@ -205,7 +238,7 @@ static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
	}
}

static void radeon_enable_bm(struct drm_radeon_private *dev_priv)
void radeon_enable_bm(struct drm_radeon_private *dev_priv)
{
	u32 tmp;
	/* Turn on bus mastering */
@@ -1440,6 +1473,7 @@ static int radeon_do_resume_cp(struct drm_device *dev, struct drm_file *file_pri

int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
	drm_radeon_init_t *init = data;

	LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -1452,7 +1486,12 @@ int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_pri
	case RADEON_INIT_R200_CP:
	case RADEON_INIT_R300_CP:
		return radeon_do_init_cp(dev, init, file_priv);
	case RADEON_INIT_R600_CP:
		return r600_do_init_cp(dev, init, file_priv);
	case RADEON_CLEANUP_CP:
		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
			return r600_do_cleanup_cp(dev);
		else
			return radeon_do_cleanup_cp(dev);
	}

@@ -1476,6 +1515,9 @@ int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_pr
		return 0;
	}

	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
		r600_do_cp_start(dev_priv);
	else
		radeon_do_cp_start(dev_priv);

	return 0;
@@ -1507,6 +1549,9 @@ int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_pri
	 * code so that the DRM ioctl wrapper can try again.
	 */
	if (stop->idle) {
		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
			ret = r600_do_cp_idle(dev_priv);
		else
			ret = radeon_do_cp_idle(dev_priv);
		if (ret)
			return ret;
@@ -1516,9 +1561,15 @@ int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_pri
	 * we will get some dropped triangles as they won't be fully
	 * rendered before the CP is shut down.
	 */
	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
		r600_do_cp_stop(dev_priv);
	else
		radeon_do_cp_stop(dev_priv);

	/* Reset the engine */
	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
		r600_do_engine_reset(dev);
	else
		radeon_do_engine_reset(dev);

	return 0;
@@ -1532,6 +1583,16 @@ void radeon_do_release(struct drm_device * dev)
	if (dev_priv) {
		if (dev_priv->cp_running) {
			/* Stop the cp */
			if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_R600) {
				while ((ret = r600_do_cp_idle(dev_priv)) != 0) {
					DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
#ifdef __linux__
					schedule();
#else
					tsleep(&ret, PZERO, "rdnrel", 1);
#endif
				}
			} else {
				while ((ret = radeon_do_cp_idle(dev_priv)) != 0) {
					DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
#ifdef __linux__
@@ -1540,10 +1601,17 @@ void radeon_do_release(struct drm_device * dev)
					tsleep(&ret, PZERO, "rdnrel", 1);
#endif
				}
			}
			if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
				r600_do_cp_stop(dev_priv);
				r600_do_engine_reset(dev);
			} else {
				radeon_do_cp_stop(dev_priv);
				radeon_do_engine_reset(dev);
			}
		}

		if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_R600) {
			/* Disable *all* interrupts */
			if (dev_priv->mmio)	/* remove this after permanent addmaps */
				RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
@@ -1557,12 +1625,16 @@ void radeon_do_release(struct drm_device * dev)
						     16 * i, 0);
				}
			}
		}

		/* Free memory heap structures */
		radeon_mem_takedown(&(dev_priv->gart_heap));
		radeon_mem_takedown(&(dev_priv->fb_heap));

		/* deallocate kernel resources */
		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
			r600_do_cleanup_cp(dev);
		else
			radeon_do_cleanup_cp(dev);
	}
}
@@ -1581,6 +1653,9 @@ int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_pr
		return -EINVAL;
	}

	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
		r600_do_cp_reset(dev_priv);
	else
		radeon_do_cp_reset(dev_priv);

	/* The CP is no longer running after an engine reset */
@@ -1596,6 +1671,9 @@ int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_pri

	LOCK_TEST_WITH_RETURN(dev, file_priv);

	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
		return r600_do_cp_idle(dev_priv);
	else
		return radeon_do_cp_idle(dev_priv);
}

@@ -1603,15 +1681,25 @@ int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_pri
 */
int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
	DRM_DEBUG("\n");

	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
		return r600_do_resume_cp(dev, file_priv);
	else
		return radeon_do_resume_cp(dev, file_priv);
}

int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
	drm_radeon_private_t *dev_priv = dev->dev_private;
	DRM_DEBUG("\n");

	LOCK_TEST_WITH_RETURN(dev, file_priv);

	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
		return r600_do_engine_reset(dev);
	else
		return radeon_do_engine_reset(dev);
}

@@ -1997,7 +2085,13 @@ void radeon_commit_ring(drm_radeon_private_t *dev_priv)
	DRM_MEMORYBARRIER();
	GET_RING_HEAD( dev_priv );

	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
		RADEON_WRITE(R600_CP_RB_WPTR, dev_priv->ring.tail);
		/* read from PCI bus to ensure correct posting */
		RADEON_READ(R600_CP_RB_RPTR);
	} else {
		RADEON_WRITE(RADEON_CP_RB_WPTR, dev_priv->ring.tail);
		/* read from PCI bus to ensure correct posting */
		RADEON_READ(RADEON_CP_RB_RPTR);
	}
}
+24 −1
Original line number Diff line number Diff line
@@ -396,6 +396,8 @@ extern int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_fi
extern int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv);
extern void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc);
extern void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base);
extern u32 RADEON_READ_MM(drm_radeon_private_t *dev_priv, int addr);

extern void radeon_freelist_reset(struct drm_device * dev);
@@ -416,6 +418,10 @@ extern void radeon_mem_takedown(struct mem_block **heap);
extern void radeon_mem_release(struct drm_file *file_priv,
			       struct mem_block *heap);

extern void radeon_enable_bm(struct drm_radeon_private *dev_priv);
extern u32 radeon_read_ring_rptr(drm_radeon_private_t *dev_priv, u32 off);
extern void radeon_write_ring_rptr(drm_radeon_private_t *dev_priv, u32 off, u32 val);

				/* radeon_irq.c */
extern void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state);
extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);
@@ -456,6 +462,19 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
			     struct drm_file *file_priv,
			     drm_radeon_kcmd_buffer_t *cmdbuf);

/* r600_cp.c */
extern int r600_do_engine_reset(struct drm_device *dev);
extern int r600_do_cleanup_cp(struct drm_device *dev);
extern int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
			   struct drm_file *file_priv);
extern int r600_do_resume_cp(struct drm_device *dev, struct drm_file *file_priv);
extern int r600_do_cp_idle(drm_radeon_private_t *dev_priv);
extern void r600_do_cp_start(drm_radeon_private_t *dev_priv);
extern void r600_do_cp_reset(drm_radeon_private_t *dev_priv);
extern void r600_do_cp_stop(drm_radeon_private_t *dev_priv);
extern int r600_cp_dispatch_indirect(struct drm_device *dev,
				     struct drm_buf *buf, int start, int end);

/* Flags for stats.boxes
 */
#define RADEON_BOX_DMA_IDLE      0x1
@@ -1832,7 +1851,11 @@ do { \
	struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;	\
	drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;	\
	if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) {		\
		int __ret = radeon_do_cp_idle( dev_priv );		\
		int __ret;						\
		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) \
			__ret = r600_do_cp_idle(dev_priv);		\
		else							\
			__ret = radeon_do_cp_idle(dev_priv);		\
		if ( __ret ) return __ret;				\
		sarea_priv->last_dispatch = 0;				\
		radeon_freelist_reset( dev );				\
+26 −16
Original line number Diff line number Diff line
@@ -1556,9 +1556,15 @@ static void radeon_cp_discard_buffer(struct drm_device *dev, struct drm_master *
	buf_priv->age = ++master_priv->sarea_priv->last_dispatch;

	/* Emit the vertex buffer age */
	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
		BEGIN_RING(3);
		R600_DISPATCH_AGE(buf_priv->age);
		ADVANCE_RING();
	} else {
		BEGIN_RING(2);
		RADEON_DISPATCH_AGE(buf_priv->age);
		ADVANCE_RING();
	}

	buf->pending = 1;
	buf->used = 0;
@@ -2473,24 +2479,25 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil

	buf->used = indirect->end;

	/* Dispatch the indirect buffer full of commands from the
	 * X server.  This is insecure and is thus only available to
	 * privileged clients.
	 */
	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
		r600_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
	else {
		/* Wait for the 3D stream to idle before the indirect buffer
		 * containing 2D acceleration commands is processed.
		 */
		BEGIN_RING(2);

		RADEON_WAIT_UNTIL_3D_IDLE();

		ADVANCE_RING();

	/* Dispatch the indirect buffer full of commands from the
	 * X server.  This is insecure and is thus only available to
	 * privileged clients.
	 */
		radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
	if (indirect->discard) {
		radeon_cp_discard_buffer(dev, file_priv->master, buf);
	}

	if (indirect->discard)
		radeon_cp_discard_buffer(dev, file_priv->master, buf);

	COMMIT_RING();
	return 0;
}
@@ -3052,6 +3059,9 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
	case RADEON_PARAM_SCRATCH_OFFSET:
		if (!dev_priv->writeback_works)
			return -EINVAL;
		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
			value = R600_SCRATCH_REG_OFFSET;
		else
			value = RADEON_SCRATCH_REG_OFFSET;
		break;
	case RADEON_PARAM_CARD_TYPE: