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

Commit 3ce0a23d authored by Jerome Glisse's avatar Jerome Glisse Committed by Dave Airlie
Browse files

drm/radeon/kms: add r600 KMS support



This adds the r600 KMS + CS support to the Linux kernel.

The r600 TTM support is quite basic and still needs more
work esp around using interrupts, but the polled fencing
should work okay for now.

Also currently TTM is using memcpy to do VRAM moves,
the code is here to use a 3D blit to do this, but
isn't fully debugged yet.

Authors:
Alex Deucher <alexdeucher@gmail.com>
Dave Airlie <airlied@redhat.com>
Jerome Glisse <jglisse@redhat.com>

Signed-off-by: default avatarJerome Glisse <jglisse@redhat.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 4ce001ab
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -46,8 +46,9 @@ radeon-$(CONFIG_DRM_RADEON_KMS) += radeon_device.o radeon_kms.o \
	radeon_encoders.o radeon_display.o radeon_cursor.o radeon_i2c.o \
	radeon_clocks.o radeon_fb.o radeon_gem.o radeon_ring.o radeon_irq_kms.o \
	radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \
	rs400.o rs600.o rs690.o rv515.o r520.o r600.o rs780.o rv770.o \
	radeon_test.o r200.o radeon_legacy_tv.o
	rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \
	r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \
	r600_blit_kms.o

radeon-$(CONFIG_COMPAT) += radeon_ioc32.o

+1 −0
Original line number Diff line number Diff line
@@ -389,6 +389,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
					pll_flags |= RADEON_PLL_USE_REF_DIV;
			}
			radeon_encoder = to_radeon_encoder(encoder);
			break;
		}
	}

+33 −9
Original line number Diff line number Diff line
/*
 * Copyright 2008 Advanced Micro Devices, Inc.
 * Copyright 2008 Red Hat Inc.
 * Copyright 2009 Jerome Glisse.
 * Copyright 2009 Advanced Micro Devices, Inc.
 * Copyright 2009 Red Hat Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
@@ -25,12 +24,37 @@
 *          Alex Deucher
 *          Jerome Glisse
 */
#ifndef R300_H
#define R300_H
#ifndef AVIVOD_H
#define AVIVOD_H

struct r300_asic {
	const unsigned	*reg_safe_bm;
	unsigned	reg_safe_bm_size;
};

#define	D1CRTC_CONTROL					0x6080
#define		CRTC_EN						(1 << 0)
#define	D1CRTC_UPDATE_LOCK				0x60E8
#define	D1GRPH_PRIMARY_SURFACE_ADDRESS			0x6110
#define	D1GRPH_SECONDARY_SURFACE_ADDRESS		0x6118

#define	D2CRTC_CONTROL					0x6880
#define	D2CRTC_UPDATE_LOCK				0x68E8
#define	D2GRPH_PRIMARY_SURFACE_ADDRESS			0x6910
#define	D2GRPH_SECONDARY_SURFACE_ADDRESS		0x6918

#define	D1VGA_CONTROL					0x0330
#define		DVGA_CONTROL_MODE_ENABLE			(1 << 0)
#define		DVGA_CONTROL_TIMING_SELECT			(1 << 8)
#define		DVGA_CONTROL_SYNC_POLARITY_SELECT		(1 << 9)
#define		DVGA_CONTROL_OVERSCAN_TIMING_SELECT		(1 << 10)
#define		DVGA_CONTROL_OVERSCAN_COLOR_EN			(1 << 16)
#define		DVGA_CONTROL_ROTATE				(1 << 24)
#define D2VGA_CONTROL					0x0338

#define	VGA_HDP_CONTROL					0x328
#define		VGA_MEM_PAGE_SELECT_EN				(1 << 0)
#define		VGA_MEMORY_DISABLE				(1 << 4)
#define		VGA_RBBM_LOCK_DISABLE				(1 << 8)
#define		VGA_SOFT_RESET					(1 << 16)
#define	VGA_MEMORY_BASE_ADDRESS				0x0310
#define	VGA_RENDER_CONTROL				0x0300
#define		VGA_VSTATUS_CNTL_MASK				0x00030000

#endif
+123 −12
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@
#include "radeon_drm.h"
#include "radeon_reg.h"
#include "radeon.h"
#include "r100d.h"

#include <linux/firmware.h>
#include <linux/platform_device.h>

@@ -391,9 +393,9 @@ int r100_wb_init(struct radeon_device *rdev)
			return r;
		}
	}
	WREG32(0x774, rdev->wb.gpu_addr);
	WREG32(0x70C, rdev->wb.gpu_addr + 1024);
	WREG32(0x770, 0xff);
	WREG32(RADEON_SCRATCH_ADDR, rdev->wb.gpu_addr);
	WREG32(RADEON_CP_RB_RPTR_ADDR, rdev->wb.gpu_addr + 1024);
	WREG32(RADEON_SCRATCH_UMSK, 0xff);
	return 0;
}

@@ -559,18 +561,18 @@ static int r100_cp_init_microcode(struct radeon_device *rdev)
		fw_name = FIRMWARE_R520;
	}

	err = request_firmware(&rdev->fw, fw_name, &pdev->dev);
	err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev);
	platform_device_unregister(pdev);
	if (err) {
		printk(KERN_ERR "radeon_cp: Failed to load firmware \"%s\"\n",
		       fw_name);
	} else if (rdev->fw->size % 8) {
	} else if (rdev->me_fw->size % 8) {
		printk(KERN_ERR
		       "radeon_cp: Bogus length %zu in firmware \"%s\"\n",
		       rdev->fw->size, fw_name);
		       rdev->me_fw->size, fw_name);
		err = -EINVAL;
		release_firmware(rdev->fw);
		rdev->fw = NULL;
		release_firmware(rdev->me_fw);
		rdev->me_fw = NULL;
	}
	return err;
}
@@ -584,9 +586,9 @@ static void r100_cp_load_microcode(struct radeon_device *rdev)
		       "programming pipes. Bad things might happen.\n");
	}

	if (rdev->fw) {
		size = rdev->fw->size / 4;
		fw_data = (const __be32 *)&rdev->fw->data[0];
	if (rdev->me_fw) {
		size = rdev->me_fw->size / 4;
		fw_data = (const __be32 *)&rdev->me_fw->data[0];
		WREG32(RADEON_CP_ME_RAM_ADDR, 0);
		for (i = 0; i < size; i += 2) {
			WREG32(RADEON_CP_ME_RAM_DATAH,
@@ -632,7 +634,7 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
		DRM_INFO("radeon: cp idle (0x%08X)\n", tmp);
	}

	if (!rdev->fw) {
	if (!rdev->me_fw) {
		r = r100_cp_init_microcode(rdev);
		if (r) {
			DRM_ERROR("Failed to load firmware!\n");
@@ -765,6 +767,12 @@ int r100_cp_reset(struct radeon_device *rdev)
	return -1;
}

void r100_cp_commit(struct radeon_device *rdev)
{
	WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr);
	(void)RREG32(RADEON_CP_RB_WPTR);
}


/*
 * CS functions
@@ -2954,3 +2962,106 @@ void r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track
			}
	}
}

int r100_ring_test(struct radeon_device *rdev)
{
	uint32_t scratch;
	uint32_t tmp = 0;
	unsigned i;
	int r;

	r = radeon_scratch_get(rdev, &scratch);
	if (r) {
		DRM_ERROR("radeon: cp failed to get scratch reg (%d).\n", r);
		return r;
	}
	WREG32(scratch, 0xCAFEDEAD);
	r = radeon_ring_lock(rdev, 2);
	if (r) {
		DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
		radeon_scratch_free(rdev, scratch);
		return r;
	}
	radeon_ring_write(rdev, PACKET0(scratch, 0));
	radeon_ring_write(rdev, 0xDEADBEEF);
	radeon_ring_unlock_commit(rdev);
	for (i = 0; i < rdev->usec_timeout; i++) {
		tmp = RREG32(scratch);
		if (tmp == 0xDEADBEEF) {
			break;
		}
		DRM_UDELAY(1);
	}
	if (i < rdev->usec_timeout) {
		DRM_INFO("ring test succeeded in %d usecs\n", i);
	} else {
		DRM_ERROR("radeon: ring test failed (sracth(0x%04X)=0x%08X)\n",
			  scratch, tmp);
		r = -EINVAL;
	}
	radeon_scratch_free(rdev, scratch);
	return r;
}

void r100_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
{
	radeon_ring_write(rdev, PACKET0(RADEON_CP_IB_BASE, 1));
	radeon_ring_write(rdev, ib->gpu_addr);
	radeon_ring_write(rdev, ib->length_dw);
}

int r100_ib_test(struct radeon_device *rdev)
{
	struct radeon_ib *ib;
	uint32_t scratch;
	uint32_t tmp = 0;
	unsigned i;
	int r;

	r = radeon_scratch_get(rdev, &scratch);
	if (r) {
		DRM_ERROR("radeon: failed to get scratch reg (%d).\n", r);
		return r;
	}
	WREG32(scratch, 0xCAFEDEAD);
	r = radeon_ib_get(rdev, &ib);
	if (r) {
		return r;
	}
	ib->ptr[0] = PACKET0(scratch, 0);
	ib->ptr[1] = 0xDEADBEEF;
	ib->ptr[2] = PACKET2(0);
	ib->ptr[3] = PACKET2(0);
	ib->ptr[4] = PACKET2(0);
	ib->ptr[5] = PACKET2(0);
	ib->ptr[6] = PACKET2(0);
	ib->ptr[7] = PACKET2(0);
	ib->length_dw = 8;
	r = radeon_ib_schedule(rdev, ib);
	if (r) {
		radeon_scratch_free(rdev, scratch);
		radeon_ib_free(rdev, &ib);
		return r;
	}
	r = radeon_fence_wait(ib->fence, false);
	if (r) {
		return r;
	}
	for (i = 0; i < rdev->usec_timeout; i++) {
		tmp = RREG32(scratch);
		if (tmp == 0xDEADBEEF) {
			break;
		}
		DRM_UDELAY(1);
	}
	if (i < rdev->usec_timeout) {
		DRM_INFO("ib test succeeded in %u usecs\n", i);
	} else {
		DRM_ERROR("radeon: ib test failed (sracth(0x%04X)=0x%08X)\n",
			  scratch, tmp);
		r = -EINVAL;
	}
	radeon_scratch_free(rdev, scratch);
	radeon_ib_free(rdev, &ib);
	return r;
}
+76 −0
Original line number Diff line number Diff line
@@ -25,78 +25,52 @@
 *          Alex Deucher
 *          Jerome Glisse
 */
#include "drmP.h"
#include "radeon_reg.h"
#include "radeon.h"
#ifndef __R100D_H__
#define __R100D_H__

/* rs780  depends on : */
void rs600_mc_disable_clients(struct radeon_device *rdev);

/* This files gather functions specifics to:
 * rs780
 *
 * Some of these functions might be used by newer ASICs.
 */
int rs780_mc_wait_for_idle(struct radeon_device *rdev);
void rs780_gpu_init(struct radeon_device *rdev);


/*
 * MC
 */
int rs780_mc_init(struct radeon_device *rdev)
{
	rs780_gpu_init(rdev);
	/* FIXME: implement */

	rs600_mc_disable_clients(rdev);
	if (rs780_mc_wait_for_idle(rdev)) {
		printk(KERN_WARNING "Failed to wait MC idle while "
		       "programming pipes. Bad things might happen.\n");
	}
	return 0;
}

void rs780_mc_fini(struct radeon_device *rdev)
{
	/* FIXME: implement */
}
#define CP_PACKET0			0x00000000
#define		PACKET0_BASE_INDEX_SHIFT	0
#define		PACKET0_BASE_INDEX_MASK		(0x1ffff << 0)
#define		PACKET0_COUNT_SHIFT		16
#define		PACKET0_COUNT_MASK		(0x3fff << 16)
#define CP_PACKET1			0x40000000
#define CP_PACKET2			0x80000000
#define		PACKET2_PAD_SHIFT		0
#define		PACKET2_PAD_MASK		(0x3fffffff << 0)
#define CP_PACKET3			0xC0000000
#define		PACKET3_IT_OPCODE_SHIFT		8
#define		PACKET3_IT_OPCODE_MASK		(0xff << 8)
#define		PACKET3_COUNT_SHIFT		16
#define		PACKET3_COUNT_MASK		(0x3fff << 16)
/* PACKET3 op code */
#define		PACKET3_NOP			0x10
#define		PACKET3_3D_DRAW_VBUF		0x28
#define		PACKET3_3D_DRAW_IMMD		0x29
#define		PACKET3_3D_DRAW_INDX		0x2A
#define		PACKET3_3D_LOAD_VBPNTR		0x2F
#define		PACKET3_INDX_BUFFER		0x33
#define		PACKET3_3D_DRAW_VBUF_2		0x34
#define		PACKET3_3D_DRAW_IMMD_2		0x35
#define		PACKET3_3D_DRAW_INDX_2		0x36
#define		PACKET3_BITBLT_MULTI		0x9B

#define PACKET0(reg, n)	(CP_PACKET0 |					\
			 REG_SET(PACKET0_BASE_INDEX, (reg) >> 2) |	\
			 REG_SET(PACKET0_COUNT, (n)))
#define PACKET2(v)	(CP_PACKET2 | REG_SET(PACKET2_PAD, (v)))
#define PACKET3(op, n)	(CP_PACKET3 |					\
			 REG_SET(PACKET3_IT_OPCODE, (op)) |		\
			 REG_SET(PACKET3_COUNT, (n)))

/*
 * Global GPU functions
 */
void rs780_errata(struct radeon_device *rdev)
{
	rdev->pll_errata = 0;
}

int rs780_mc_wait_for_idle(struct radeon_device *rdev)
{
	/* FIXME: implement */
	return 0;
}

void rs780_gpu_init(struct radeon_device *rdev)
{
	/* FIXME: implement */
}


/*
 * VRAM info
 */
void rs780_vram_get_type(struct radeon_device *rdev)
{
	/* FIXME: implement */
}
#define	PACKET_TYPE0	0
#define	PACKET_TYPE1	1
#define	PACKET_TYPE2	2
#define	PACKET_TYPE3	3

void rs780_vram_info(struct radeon_device *rdev)
{
	rs780_vram_get_type(rdev);
#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3)
#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF)
#define CP_PACKET0_GET_REG(h) (((h) & 0x1FFF) << 2)
#define CP_PACKET0_GET_ONE_REG_WR(h) (((h) >> 15) & 1)
#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF)

	/* FIXME: implement */
	/* Could aper size report 0 ? */
	rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
	rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
}
#endif
Loading