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

Commit 856754c3 authored by Christian König's avatar Christian König Committed by Alex Deucher
Browse files

drm/radeon: add UVD support for older asics v4



v2: cleanup R600 support
v3: rebased on current drm-fixes-3.12
v4: rebased on drm-next-3.14

Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 4a956a70
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -3009,6 +3009,17 @@ static int r600_startup(struct radeon_device *rdev)
		return r;
	}

	r = uvd_v1_0_resume(rdev);
	if (!r) {
		r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX);
		if (r) {
			dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r);
		}
	}
	if (r) {
		rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
	}

	/* Enable IRQ */
	if (!rdev->irq.installed) {
		r = radeon_irq_kms_init(rdev);
@@ -3037,6 +3048,16 @@ static int r600_startup(struct radeon_device *rdev)
	if (r)
		return r;

	ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
	if (ring->ring_size) {
		r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
				     RADEON_CP_PACKET2);
		if (!r)
			r = uvd_v1_0_init(rdev);
		if (r)
			DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
	}

	r = radeon_ib_pool_init(rdev);
	if (r) {
		dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
@@ -3096,6 +3117,8 @@ int r600_suspend(struct radeon_device *rdev)
	radeon_pm_suspend(rdev);
	r600_audio_fini(rdev);
	r600_cp_stop(rdev);
	uvd_v1_0_fini(rdev);
	radeon_uvd_suspend(rdev);
	r600_irq_suspend(rdev);
	radeon_wb_disable(rdev);
	r600_pcie_gart_disable(rdev);
@@ -3175,6 +3198,12 @@ int r600_init(struct radeon_device *rdev)
	rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
	r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);

	r = radeon_uvd_init(rdev);
	if (!r) {
		rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL;
		r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096);
	}

	rdev->ih.ring_obj = NULL;
	r600_ih_ring_init(rdev, 64 * 1024);

@@ -3204,6 +3233,8 @@ void r600_fini(struct radeon_device *rdev)
	r600_audio_fini(rdev);
	r600_cp_fini(rdev);
	r600_irq_fini(rdev);
	uvd_v1_0_fini(rdev);
	radeon_uvd_fini(rdev);
	radeon_wb_fini(rdev);
	radeon_ib_pool_fini(rdev);
	radeon_irq_kms_fini(rdev);
+8 −0
Original line number Diff line number Diff line
@@ -1485,6 +1485,7 @@
#define UVD_CGC_GATE					0xf4a8
#define UVD_LMI_CTRL2					0xf4f4
#define UVD_MASTINT_EN					0xf500
#define UVD_FW_START					0xf51C
#define UVD_LMI_ADDR_EXT				0xf594
#define UVD_LMI_CTRL					0xf598
#define UVD_LMI_SWAP_CNTL				0xf5b4
@@ -1497,6 +1498,13 @@
#define UVD_MPC_SET_MUX					0xf5f4
#define UVD_MPC_SET_ALU					0xf5f8

#define UVD_VCPU_CACHE_OFFSET0				0xf608
#define UVD_VCPU_CACHE_SIZE0				0xf60c
#define UVD_VCPU_CACHE_OFFSET1				0xf610
#define UVD_VCPU_CACHE_SIZE1				0xf614
#define UVD_VCPU_CACHE_OFFSET2				0xf618
#define UVD_VCPU_CACHE_SIZE2				0xf61c

#define UVD_VCPU_CNTL					0xf660
#define UVD_SOFT_RESET					0xf680
#define		RBC_SOFT_RESET					(1<<0)
+15 −0
Original line number Diff line number Diff line
@@ -965,6 +965,19 @@ static struct radeon_asic r600_asic = {
	},
};

static struct radeon_asic_ring rv6xx_uvd_ring = {
	.ib_execute = &uvd_v1_0_ib_execute,
	.emit_fence = &uvd_v1_0_fence_emit,
	.emit_semaphore = &uvd_v1_0_semaphore_emit,
	.cs_parse = &radeon_uvd_cs_parse,
	.ring_test = &uvd_v1_0_ring_test,
	.ib_test = &uvd_v1_0_ib_test,
	.is_lockup = &radeon_ring_test_lockup,
	.get_rptr = &uvd_v1_0_get_rptr,
	.get_wptr = &uvd_v1_0_get_wptr,
	.set_wptr = &uvd_v1_0_set_wptr,
};

static struct radeon_asic rv6xx_asic = {
	.init = &r600_init,
	.fini = &r600_fini,
@@ -984,6 +997,7 @@ static struct radeon_asic rv6xx_asic = {
	.ring = {
		[RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring,
		[R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring,
		[R600_RING_TYPE_UVD_INDEX] = &rv6xx_uvd_ring,
	},
	.irq = {
		.set = &r600_irq_set,
@@ -1074,6 +1088,7 @@ static struct radeon_asic rs780_asic = {
	.ring = {
		[RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring,
		[R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring,
		[R600_RING_TYPE_UVD_INDEX] = &rv6xx_uvd_ring,
	},
	.irq = {
		.set = &r600_irq_set,
+3 −0
Original line number Diff line number Diff line
@@ -883,6 +883,7 @@ uint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev,
                           struct radeon_ring *ring);
void uvd_v1_0_set_wptr(struct radeon_device *rdev,
                       struct radeon_ring *ring);
int uvd_v1_0_resume(struct radeon_device *rdev);

int uvd_v1_0_init(struct radeon_device *rdev);
void uvd_v1_0_fini(struct radeon_device *rdev);
@@ -890,6 +891,8 @@ int uvd_v1_0_start(struct radeon_device *rdev);
void uvd_v1_0_stop(struct radeon_device *rdev);

int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);
void uvd_v1_0_fence_emit(struct radeon_device *rdev,
			 struct radeon_fence *fence);
int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev,
			     struct radeon_ring *ring,
+77 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
 * Authors: Christian König <christian.koenig@amd.com>
 */

#include <linux/firmware.h>
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
@@ -69,6 +70,82 @@ void uvd_v1_0_set_wptr(struct radeon_device *rdev,
	WREG32(UVD_RBC_RB_WPTR, ring->wptr);
}

/**
 * uvd_v1_0_fence_emit - emit an fence & trap command
 *
 * @rdev: radeon_device pointer
 * @fence: fence to emit
 *
 * Write a fence and a trap command to the ring.
 */
void uvd_v1_0_fence_emit(struct radeon_device *rdev,
			 struct radeon_fence *fence)
{
	struct radeon_ring *ring = &rdev->ring[fence->ring];
	uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr;

	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0));
	radeon_ring_write(ring, addr & 0xffffffff);
	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0));
	radeon_ring_write(ring, fence->seq);
	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
	radeon_ring_write(ring, 0);

	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0));
	radeon_ring_write(ring, 0);
	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0));
	radeon_ring_write(ring, 0);
	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
	radeon_ring_write(ring, 2);
	return;
}

/**
 * uvd_v1_0_resume - memory controller programming
 *
 * @rdev: radeon_device pointer
 *
 * Let the UVD memory controller know it's offsets
 */
int uvd_v1_0_resume(struct radeon_device *rdev)
{
	uint64_t addr;
	uint32_t size;
	int r;

	r = radeon_uvd_resume(rdev);
	if (r)
		return r;

	/* programm the VCPU memory controller bits 0-27 */
	addr = (rdev->uvd.gpu_addr >> 3) + 16;
	size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size) >> 3;
	WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
	WREG32(UVD_VCPU_CACHE_SIZE0, size);

	addr += size;
	size = RADEON_UVD_STACK_SIZE >> 3;
	WREG32(UVD_VCPU_CACHE_OFFSET1, addr);
	WREG32(UVD_VCPU_CACHE_SIZE1, size);

	addr += size;
	size = RADEON_UVD_HEAP_SIZE >> 3;
	WREG32(UVD_VCPU_CACHE_OFFSET2, addr);
	WREG32(UVD_VCPU_CACHE_SIZE2, size);

	/* bits 28-31 */
	addr = (rdev->uvd.gpu_addr >> 28) & 0xF;
	WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0));

	/* bits 32-39 */
	addr = (rdev->uvd.gpu_addr >> 32) & 0xFF;
	WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31));

	WREG32(UVD_FW_START, *((uint32_t*)rdev->uvd.cpu_addr));

	return 0;
}

/**
 * uvd_v1_0_init - start and test UVD block
 *
Loading