diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-amd/0027-drm-radeon-initial-VCE-support-v4.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-amd/0027-drm-radeon-initial-VCE-support-v4.patch | 1434 |
1 files changed, 1434 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-amd/0027-drm-radeon-initial-VCE-support-v4.patch b/common/recipes-kernel/linux/linux-amd/0027-drm-radeon-initial-VCE-support-v4.patch new file mode 100644 index 00000000..00996021 --- /dev/null +++ b/common/recipes-kernel/linux/linux-amd/0027-drm-radeon-initial-VCE-support-v4.patch @@ -0,0 +1,1434 @@ +From 769bdc09213b2d223c39eb5f8df2c741fca88321 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> +Date: Thu, 23 May 2013 12:10:04 +0200 +Subject: [PATCH 27/60] drm/radeon: initial VCE support v4 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Only VCE 2.0 support so far. + +v2: squashing multiple patches into this one +v3: add IRQ support for CIK, major cleanups, + basic code documentation +v4: remove HAINAN from chipset list + +Signed-off-by: Christian König <christian.koenig@amd.com> +--- + drivers/gpu/drm/radeon/Makefile | 6 + + drivers/gpu/drm/radeon/cik.c | 60 ++++ + drivers/gpu/drm/radeon/cikd.h | 33 ++ + drivers/gpu/drm/radeon/radeon.h | 56 +++- + drivers/gpu/drm/radeon/radeon_asic.c | 17 + + drivers/gpu/drm/radeon/radeon_asic.h | 13 + + drivers/gpu/drm/radeon/radeon_cs.c | 4 + + drivers/gpu/drm/radeon/radeon_kms.c | 1 + + drivers/gpu/drm/radeon/radeon_ring.c | 4 + + drivers/gpu/drm/radeon/radeon_test.c | 39 ++- + drivers/gpu/drm/radeon/radeon_vce.c | 588 +++++++++++++++++++++++++++++++++++ + drivers/gpu/drm/radeon/sid.h | 47 +++ + drivers/gpu/drm/radeon/vce_v1_0.c | 187 +++++++++++ + drivers/gpu/drm/radeon/vce_v2_0.c | 70 +++++ + include/uapi/drm/radeon_drm.h | 1 + + 15 files changed, 1117 insertions(+), 9 deletions(-) + create mode 100644 drivers/gpu/drm/radeon/radeon_vce.c + create mode 100644 drivers/gpu/drm/radeon/vce_v1_0.c + create mode 100644 drivers/gpu/drm/radeon/vce_v2_0.c + +diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile +index 306364a..ed60caa 100644 +--- a/drivers/gpu/drm/radeon/Makefile ++++ b/drivers/gpu/drm/radeon/Makefile +@@ -99,6 +99,12 @@ radeon-y += \ + uvd_v3_1.o \ + uvd_v4_2.o + ++# add VCE block ++radeon-y += \ ++ radeon_vce.o \ ++ vce_v1_0.o \ ++ vce_v2_0.o \ ++ + radeon-$(CONFIG_COMPAT) += radeon_ioc32.o + radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o + radeon-$(CONFIG_ACPI) += radeon_acpi.o +diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c +index cef0bbe..e256340 100644 +--- a/drivers/gpu/drm/radeon/cik.c ++++ b/drivers/gpu/drm/radeon/cik.c +@@ -6835,6 +6835,20 @@ restart_ih: + /* reset addr and status */ + WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); + break; ++ case 167: /* VCE */ ++ DRM_DEBUG("IH: VCE int: 0x%08x\n", src_data); ++ switch (src_data) { ++ case 0: ++ radeon_fence_process(rdev, TN_RING_TYPE_VCE1_INDEX); ++ break; ++ case 1: ++ radeon_fence_process(rdev, TN_RING_TYPE_VCE2_INDEX); ++ break; ++ default: ++ DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); ++ break; ++ } ++ break; + case 176: /* GFX RB CP_INT */ + case 177: /* GFX IB CP_INT */ + radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); +@@ -7134,6 +7148,22 @@ static int cik_startup(struct radeon_device *rdev) + if (r) + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; + ++ r = radeon_vce_resume(rdev); ++ if (!r) { ++ r = vce_v2_0_resume(rdev); ++ if (!r) ++ r = radeon_fence_driver_start_ring(rdev, ++ TN_RING_TYPE_VCE1_INDEX); ++ if (!r) ++ r = radeon_fence_driver_start_ring(rdev, ++ TN_RING_TYPE_VCE2_INDEX); ++ } ++ if (r) { ++ dev_err(rdev->dev, "VCE init error (%d).\n", r); ++ rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0; ++ rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0; ++ } ++ + /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); +@@ -7209,6 +7239,23 @@ static int cik_startup(struct radeon_device *rdev) + DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); + } + ++ r = -ENOENT; ++ ++ ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; ++ if (ring->ring_size) ++ r = radeon_ring_init(rdev, ring, ring->ring_size, 0, ++ VCE_CMD_NO_OP); ++ ++ ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; ++ if (ring->ring_size) ++ r = radeon_ring_init(rdev, ring, ring->ring_size, 0, ++ VCE_CMD_NO_OP); ++ ++ if (!r) ++ r = vce_v1_0_init(rdev); ++ else if (r != -ENOENT) ++ DRM_ERROR("radeon: failed initializing VCE (%d).\n", r); ++ + r = radeon_ib_pool_init(rdev); + if (r) { + dev_err(rdev->dev, "IB initialization failed (%d).\n", r); +@@ -7276,6 +7323,7 @@ int cik_suspend(struct radeon_device *rdev) + cik_sdma_enable(rdev, false); + uvd_v1_0_fini(rdev); + radeon_uvd_suspend(rdev); ++ radeon_vce_suspend(rdev); + cik_fini_pg(rdev); + cik_fini_cg(rdev); + cik_irq_suspend(rdev); +@@ -7405,6 +7453,17 @@ int cik_init(struct radeon_device *rdev) + r600_ring_init(rdev, ring, 4096); + } + ++ r = radeon_vce_init(rdev); ++ if (!r) { ++ ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; ++ ring->ring_obj = NULL; ++ r600_ring_init(rdev, ring, 4096); ++ ++ ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; ++ ring->ring_obj = NULL; ++ r600_ring_init(rdev, ring, 4096); ++ } ++ + rdev->ih.ring_obj = NULL; + r600_ih_ring_init(rdev, 64 * 1024); + +@@ -7465,6 +7524,7 @@ void cik_fini(struct radeon_device *rdev) + radeon_irq_kms_fini(rdev); + uvd_v1_0_fini(rdev); + radeon_uvd_fini(rdev); ++ radeon_vce_fini(rdev); + cik_pcie_gart_fini(rdev); + r600_vram_scratch_fini(rdev); + radeon_gem_fini(rdev); +diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h +index c4738bc..54eb8be 100644 +--- a/drivers/gpu/drm/radeon/cikd.h ++++ b/drivers/gpu/drm/radeon/cikd.h +@@ -1908,4 +1908,37 @@ + /* UVD CTX indirect */ + #define UVD_CGC_MEM_CTRL 0xC0 + ++/* VCE */ ++ ++#define VCE_VCPU_CACHE_OFFSET0 0x20024 ++#define VCE_VCPU_CACHE_SIZE0 0x20028 ++#define VCE_VCPU_CACHE_OFFSET1 0x2002c ++#define VCE_VCPU_CACHE_SIZE1 0x20030 ++#define VCE_VCPU_CACHE_OFFSET2 0x20034 ++#define VCE_VCPU_CACHE_SIZE2 0x20038 ++#define VCE_RB_RPTR2 0x20178 ++#define VCE_RB_WPTR2 0x2017c ++#define VCE_RB_RPTR 0x2018c ++#define VCE_RB_WPTR 0x20190 ++#define VCE_CLOCK_GATING_A 0x202f8 ++#define VCE_CLOCK_GATING_B 0x202fc ++#define VCE_UENC_CLOCK_GATING 0x207bc ++#define VCE_UENC_REG_CLOCK_GATING 0x207c0 ++#define VCE_SYS_INT_EN 0x21300 ++# define VCE_SYS_INT_TRAP_INTERRUPT_EN (1 << 3) ++#define VCE_LMI_CTRL2 0x21474 ++#define VCE_LMI_CTRL 0x21498 ++#define VCE_LMI_VM_CTRL 0x214a0 ++#define VCE_LMI_SWAP_CNTL 0x214b4 ++#define VCE_LMI_SWAP_CNTL1 0x214b8 ++#define VCE_LMI_CACHE_CTRL 0x214f4 ++ ++#define VCE_CMD_NO_OP 0x00000000 ++#define VCE_CMD_END 0x00000001 ++#define VCE_CMD_IB 0x00000002 ++#define VCE_CMD_FENCE 0x00000003 ++#define VCE_CMD_TRAP 0x00000004 ++#define VCE_CMD_IB_AUTO 0x00000005 ++#define VCE_CMD_SEMAPHORE 0x00000006 ++ + #endif +diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h +index aa1ffa9..0abbe5e 100644 +--- a/drivers/gpu/drm/radeon/radeon.h ++++ b/drivers/gpu/drm/radeon/radeon.h +@@ -111,19 +111,16 @@ extern int radeon_aspm; + #define RADEONFB_CONN_LIMIT 4 + #define RADEON_BIOS_NUM_SCRATCH 8 + +-/* max number of rings */ +-#define RADEON_NUM_RINGS 6 +- + /* fence seq are set to this number when signaled */ + #define RADEON_FENCE_SIGNALED_SEQ 0LL + + /* internal ring indices */ + /* r1xx+ has gfx CP ring */ +-#define RADEON_RING_TYPE_GFX_INDEX 0 ++#define RADEON_RING_TYPE_GFX_INDEX 0 + + /* cayman has 2 compute CP rings */ +-#define CAYMAN_RING_TYPE_CP1_INDEX 1 +-#define CAYMAN_RING_TYPE_CP2_INDEX 2 ++#define CAYMAN_RING_TYPE_CP1_INDEX 1 ++#define CAYMAN_RING_TYPE_CP2_INDEX 2 + + /* R600+ has an async dma ring */ + #define R600_RING_TYPE_DMA_INDEX 3 +@@ -131,7 +128,14 @@ extern int radeon_aspm; + #define CAYMAN_RING_TYPE_DMA1_INDEX 4 + + /* R600+ */ +-#define R600_RING_TYPE_UVD_INDEX 5 ++#define R600_RING_TYPE_UVD_INDEX 5 ++ ++/* TN+ */ ++#define TN_RING_TYPE_VCE1_INDEX 6 ++#define TN_RING_TYPE_VCE2_INDEX 7 ++ ++/* max number of rings */ ++#define RADEON_NUM_RINGS 8 + + /* hardcode those limit for now */ + #define RADEON_VA_IB_OFFSET (1 << 20) +@@ -1592,6 +1596,42 @@ int radeon_uvd_calc_upll_dividers(struct radeon_device *rdev, + int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev, + unsigned cg_upll_func_cntl); + ++/* ++ * VCE ++ */ ++#define RADEON_MAX_VCE_HANDLES 16 ++#define RADEON_VCE_STACK_SIZE (1024*1024) ++#define RADEON_VCE_HEAP_SIZE (4*1024*1024) ++ ++struct radeon_vce { ++ struct radeon_bo *vcpu_bo; ++ void *cpu_addr; ++ uint64_t gpu_addr; ++ atomic_t handles[RADEON_MAX_VCE_HANDLES]; ++ struct drm_file *filp[RADEON_MAX_VCE_HANDLES]; ++}; ++ ++int radeon_vce_init(struct radeon_device *rdev); ++void radeon_vce_fini(struct radeon_device *rdev); ++int radeon_vce_suspend(struct radeon_device *rdev); ++int radeon_vce_resume(struct radeon_device *rdev); ++int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, ++ uint32_t handle, struct radeon_fence **fence); ++int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, ++ uint32_t handle, struct radeon_fence **fence); ++void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp); ++int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi); ++int radeon_vce_cs_parse(struct radeon_cs_parser *p); ++bool radeon_vce_semaphore_emit(struct radeon_device *rdev, ++ struct radeon_ring *ring, ++ struct radeon_semaphore *semaphore, ++ bool emit_wait); ++void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); ++void radeon_vce_fence_emit(struct radeon_device *rdev, ++ struct radeon_fence *fence); ++int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring); ++int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); ++ + struct r600_audio_pin { + int channels; + int rate; +@@ -2186,6 +2226,7 @@ struct radeon_device { + struct radeon_gem gem; + struct radeon_pm pm; + struct radeon_uvd uvd; ++ struct radeon_vce vce; + uint32_t bios_scratch[RADEON_BIOS_NUM_SCRATCH]; + struct radeon_wb wb; + struct radeon_dummy_page dummy_page; +@@ -2204,6 +2245,7 @@ struct radeon_device { + const struct firmware *sdma_fw; /* CIK SDMA firmware */ + const struct firmware *smc_fw; /* SMC firmware */ + const struct firmware *uvd_fw; /* UVD firmware */ ++ const struct firmware *vce_fw; /* VCE firmware */ + struct r600_vram_scratch vram_scratch; + int msi_enabled; /* msi enabled */ + struct r600_ih ih; /* r6/700 interrupt ring */ +diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c +index a539869..763280b 100644 +--- a/drivers/gpu/drm/radeon/radeon_asic.c ++++ b/drivers/gpu/drm/radeon/radeon_asic.c +@@ -1978,6 +1978,19 @@ static struct radeon_asic_ring ci_dma_ring = { + .set_wptr = &cik_sdma_set_wptr, + }; + ++static struct radeon_asic_ring ci_vce_ring = { ++ .ib_execute = &radeon_vce_ib_execute, ++ .emit_fence = &radeon_vce_fence_emit, ++ .emit_semaphore = &radeon_vce_semaphore_emit, ++ .cs_parse = &radeon_vce_cs_parse, ++ .ring_test = &radeon_vce_ring_test, ++ .ib_test = &radeon_vce_ib_test, ++ .is_lockup = &radeon_ring_test_lockup, ++ .get_rptr = &vce_v1_0_get_rptr, ++ .get_wptr = &vce_v1_0_get_wptr, ++ .set_wptr = &vce_v1_0_set_wptr, ++}; ++ + static struct radeon_asic ci_asic = { + .init = &cik_init, + .fini = &cik_fini, +@@ -2006,6 +2019,8 @@ static struct radeon_asic ci_asic = { + [R600_RING_TYPE_DMA_INDEX] = &ci_dma_ring, + [CAYMAN_RING_TYPE_DMA1_INDEX] = &ci_dma_ring, + [R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring, ++ [TN_RING_TYPE_VCE1_INDEX] = &ci_vce_ring, ++ [TN_RING_TYPE_VCE2_INDEX] = &ci_vce_ring, + }, + .irq = { + .set = &cik_irq_set, +@@ -2107,6 +2122,8 @@ static struct radeon_asic kv_asic = { + [R600_RING_TYPE_DMA_INDEX] = &ci_dma_ring, + [CAYMAN_RING_TYPE_DMA1_INDEX] = &ci_dma_ring, + [R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring, ++ [TN_RING_TYPE_VCE1_INDEX] = &ci_vce_ring, ++ [TN_RING_TYPE_VCE2_INDEX] = &ci_vce_ring, + }, + .irq = { + .set = &cik_irq_set, +diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h +index 998042e..a6c3eeb 100644 +--- a/drivers/gpu/drm/radeon/radeon_asic.h ++++ b/drivers/gpu/drm/radeon/radeon_asic.h +@@ -850,4 +850,17 @@ bool uvd_v3_1_semaphore_emit(struct radeon_device *rdev, + /* uvd v4.2 */ + int uvd_v4_2_resume(struct radeon_device *rdev); + ++/* vce v1.0 */ ++uint32_t vce_v1_0_get_rptr(struct radeon_device *rdev, ++ struct radeon_ring *ring); ++uint32_t vce_v1_0_get_wptr(struct radeon_device *rdev, ++ struct radeon_ring *ring); ++void vce_v1_0_set_wptr(struct radeon_device *rdev, ++ struct radeon_ring *ring); ++int vce_v1_0_init(struct radeon_device *rdev); ++int vce_v1_0_start(struct radeon_device *rdev); ++ ++/* vce v2.0 */ ++int vce_v2_0_resume(struct radeon_device *rdev); ++ + #endif +diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c +index eec1ad3..9d4e25d 100644 +--- a/drivers/gpu/drm/radeon/radeon_cs.c ++++ b/drivers/gpu/drm/radeon/radeon_cs.c +@@ -153,6 +153,10 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority + case RADEON_CS_RING_UVD: + p->ring = R600_RING_TYPE_UVD_INDEX; + break; ++ case RADEON_CS_RING_VCE: ++ /* TODO: only use the low priority ring for now */ ++ p->ring = TN_RING_TYPE_VCE1_INDEX; ++ break; + } + return 0; + } +diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c +index e90c42b..b35967a 100644 +--- a/drivers/gpu/drm/radeon/radeon_kms.c ++++ b/drivers/gpu/drm/radeon/radeon_kms.c +@@ -588,6 +588,7 @@ void radeon_driver_preclose_kms(struct drm_device *dev, + if (rdev->cmask_filp == file_priv) + rdev->cmask_filp = NULL; + radeon_uvd_free_handles(rdev, file_priv); ++ radeon_vce_free_handles(rdev, file_priv); + } + + /* +diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c +index 65f1cea..91457f8 100644 +--- a/drivers/gpu/drm/radeon/radeon_ring.c ++++ b/drivers/gpu/drm/radeon/radeon_ring.c +@@ -814,6 +814,8 @@ static int cayman_cp2_index = CAYMAN_RING_TYPE_CP2_INDEX; + static int radeon_dma1_index = R600_RING_TYPE_DMA_INDEX; + static int radeon_dma2_index = CAYMAN_RING_TYPE_DMA1_INDEX; + static int r600_uvd_index = R600_RING_TYPE_UVD_INDEX; ++static int si_vce1_index = TN_RING_TYPE_VCE1_INDEX; ++static int si_vce2_index = TN_RING_TYPE_VCE2_INDEX; + + static struct drm_info_list radeon_debugfs_ring_info_list[] = { + {"radeon_ring_gfx", radeon_debugfs_ring_info, 0, &radeon_gfx_index}, +@@ -822,6 +824,8 @@ static struct drm_info_list radeon_debugfs_ring_info_list[] = { + {"radeon_ring_dma1", radeon_debugfs_ring_info, 0, &radeon_dma1_index}, + {"radeon_ring_dma2", radeon_debugfs_ring_info, 0, &radeon_dma2_index}, + {"radeon_ring_uvd", radeon_debugfs_ring_info, 0, &r600_uvd_index}, ++ {"radeon_ring_vce1", radeon_debugfs_ring_info, 0, &si_vce1_index}, ++ {"radeon_ring_vce2", radeon_debugfs_ring_info, 0, &si_vce2_index}, + }; + + static int radeon_debugfs_sa_info(struct seq_file *m, void *data) +diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c +index 12e8099..3a13e0d 100644 +--- a/drivers/gpu/drm/radeon/radeon_test.c ++++ b/drivers/gpu/drm/radeon/radeon_test.c +@@ -257,20 +257,36 @@ static int radeon_test_create_and_emit_fence(struct radeon_device *rdev, + struct radeon_ring *ring, + struct radeon_fence **fence) + { ++ uint32_t handle = ring->idx ^ 0xdeafbeef; + int r; + + if (ring->idx == R600_RING_TYPE_UVD_INDEX) { +- r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL); ++ r = radeon_uvd_get_create_msg(rdev, ring->idx, handle, NULL); + if (r) { + DRM_ERROR("Failed to get dummy create msg\n"); + return r; + } + +- r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, fence); ++ r = radeon_uvd_get_destroy_msg(rdev, ring->idx, handle, fence); + if (r) { + DRM_ERROR("Failed to get dummy destroy msg\n"); + return r; + } ++ ++ } else if (ring->idx == TN_RING_TYPE_VCE1_INDEX || ++ ring->idx == TN_RING_TYPE_VCE2_INDEX) { ++ r = radeon_vce_get_create_msg(rdev, ring->idx, handle, NULL); ++ if (r) { ++ DRM_ERROR("Failed to get dummy create msg\n"); ++ return r; ++ } ++ ++ r = radeon_vce_get_destroy_msg(rdev, ring->idx, handle, fence); ++ if (r) { ++ DRM_ERROR("Failed to get dummy destroy msg\n"); ++ return r; ++ } ++ + } else { + r = radeon_ring_lock(rdev, ring, 64); + if (r) { +@@ -486,6 +502,16 @@ out_cleanup: + printk(KERN_WARNING "Error while testing ring sync (%d).\n", r); + } + ++static bool radeon_test_sync_possible(struct radeon_ring *ringA, ++ struct radeon_ring *ringB) ++{ ++ if (ringA->idx == TN_RING_TYPE_VCE2_INDEX && ++ ringB->idx == TN_RING_TYPE_VCE1_INDEX) ++ return false; ++ ++ return true; ++} ++ + void radeon_test_syncing(struct radeon_device *rdev) + { + int i, j, k; +@@ -500,6 +526,9 @@ void radeon_test_syncing(struct radeon_device *rdev) + if (!ringB->ready) + continue; + ++ if (!radeon_test_sync_possible(ringA, ringB)) ++ continue; ++ + DRM_INFO("Testing syncing between rings %d and %d...\n", i, j); + radeon_test_ring_sync(rdev, ringA, ringB); + +@@ -511,6 +540,12 @@ void radeon_test_syncing(struct radeon_device *rdev) + if (!ringC->ready) + continue; + ++ if (!radeon_test_sync_possible(ringA, ringC)) ++ continue; ++ ++ if (!radeon_test_sync_possible(ringB, ringC)) ++ continue; ++ + DRM_INFO("Testing syncing between rings %d, %d and %d...\n", i, j, k); + radeon_test_ring_sync2(rdev, ringA, ringB, ringC); + +diff --git a/drivers/gpu/drm/radeon/radeon_vce.c b/drivers/gpu/drm/radeon/radeon_vce.c +new file mode 100644 +index 0000000..2547d8e +--- /dev/null ++++ b/drivers/gpu/drm/radeon/radeon_vce.c +@@ -0,0 +1,588 @@ ++/* ++ * Copyright 2013 Advanced Micro Devices, Inc. ++ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS, AUTHORS 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. ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * Authors: Christian König <christian.koenig@amd.com> ++ */ ++ ++#include <linux/firmware.h> ++#include <linux/module.h> ++#include <drm/drmP.h> ++#include <drm/drm.h> ++ ++#include "radeon.h" ++#include "radeon_asic.h" ++#include "sid.h" ++ ++/* Firmware Names */ ++#define FIRMWARE_BONAIRE "radeon/BONAIRE_vce.bin" ++ ++MODULE_FIRMWARE(FIRMWARE_BONAIRE); ++ ++/** ++ * radeon_vce_init - allocate memory, load vce firmware ++ * ++ * @rdev: radeon_device pointer ++ * ++ * First step to get VCE online, allocate memory and load the firmware ++ */ ++int radeon_vce_init(struct radeon_device *rdev) ++{ ++ unsigned long bo_size; ++ const char *fw_name; ++ int i, r; ++ ++ switch (rdev->family) { ++ case CHIP_BONAIRE: ++ case CHIP_KAVERI: ++ case CHIP_KABINI: ++ fw_name = FIRMWARE_BONAIRE; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ r = request_firmware(&rdev->vce_fw, fw_name, rdev->dev); ++ if (r) { ++ dev_err(rdev->dev, "radeon_vce: Can't load firmware \"%s\"\n", ++ fw_name); ++ return r; ++ } ++ ++ bo_size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size) + ++ RADEON_VCE_STACK_SIZE + RADEON_VCE_HEAP_SIZE; ++ r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, ++ RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->vce.vcpu_bo); ++ if (r) { ++ dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r); ++ return r; ++ } ++ ++ r = radeon_vce_resume(rdev); ++ if (r) ++ return r; ++ ++ memset(rdev->vce.cpu_addr, 0, bo_size); ++ memcpy(rdev->vce.cpu_addr, rdev->vce_fw->data, rdev->vce_fw->size); ++ ++ r = radeon_vce_suspend(rdev); ++ if (r) ++ return r; ++ ++ for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { ++ atomic_set(&rdev->vce.handles[i], 0); ++ rdev->vce.filp[i] = NULL; ++ } ++ ++ return 0; ++} ++ ++/** ++ * radeon_vce_fini - free memory ++ * ++ * @rdev: radeon_device pointer ++ * ++ * Last step on VCE teardown, free firmware memory ++ */ ++void radeon_vce_fini(struct radeon_device *rdev) ++{ ++ radeon_vce_suspend(rdev); ++ radeon_bo_unref(&rdev->vce.vcpu_bo); ++} ++ ++/** ++ * radeon_vce_suspend - unpin VCE fw memory ++ * ++ * @rdev: radeon_device pointer ++ * ++ * TODO: Test VCE suspend/resume ++ */ ++int radeon_vce_suspend(struct radeon_device *rdev) ++{ ++ int r; ++ ++ if (rdev->vce.vcpu_bo == NULL) ++ return 0; ++ ++ r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); ++ if (!r) { ++ radeon_bo_kunmap(rdev->vce.vcpu_bo); ++ radeon_bo_unpin(rdev->vce.vcpu_bo); ++ radeon_bo_unreserve(rdev->vce.vcpu_bo); ++ } ++ return r; ++} ++ ++/** ++ * radeon_vce_resume - pin VCE fw memory ++ * ++ * @rdev: radeon_device pointer ++ * ++ * TODO: Test VCE suspend/resume ++ */ ++int radeon_vce_resume(struct radeon_device *rdev) ++{ ++ int r; ++ ++ if (rdev->vce.vcpu_bo == NULL) ++ return -EINVAL; ++ ++ r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); ++ if (r) { ++ radeon_bo_unref(&rdev->vce.vcpu_bo); ++ dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r); ++ return r; ++ } ++ ++ r = radeon_bo_pin(rdev->vce.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, ++ &rdev->vce.gpu_addr); ++ if (r) { ++ radeon_bo_unreserve(rdev->vce.vcpu_bo); ++ radeon_bo_unref(&rdev->vce.vcpu_bo); ++ dev_err(rdev->dev, "(%d) VCE bo pin failed\n", r); ++ return r; ++ } ++ ++ r = radeon_bo_kmap(rdev->vce.vcpu_bo, &rdev->vce.cpu_addr); ++ if (r) { ++ dev_err(rdev->dev, "(%d) VCE map failed\n", r); ++ return r; ++ } ++ ++ radeon_bo_unreserve(rdev->vce.vcpu_bo); ++ ++ return 0; ++} ++ ++/** ++ * radeon_vce_free_handles - free still open VCE handles ++ * ++ * @rdev: radeon_device pointer ++ * @filp: drm file pointer ++ * ++ * Close all VCE handles still open by this file pointer ++ */ ++void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp) ++{ ++ int i, r; ++ for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { ++ uint32_t handle = atomic_read(&rdev->vce.handles[i]); ++ if (!handle || rdev->vce.filp[i] != filp) ++ continue; ++ ++ r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX, ++ handle, NULL); ++ if (r) ++ DRM_ERROR("Error destroying VCE handle (%d)!\n", r); ++ ++ rdev->vce.filp[i] = NULL; ++ atomic_set(&rdev->vce.handles[i], 0); ++ } ++} ++ ++/** ++ * radeon_vce_get_create_msg - generate a VCE create msg ++ * ++ * @rdev: radeon_device pointer ++ * @ring: ring we should submit the msg to ++ * @handle: VCE session handle to use ++ * @fence: optional fence to return ++ * ++ * Open up a stream for HW test ++ */ ++int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, ++ uint32_t handle, struct radeon_fence **fence) ++{ ++ const unsigned ib_size_dw = 1024; ++ struct radeon_ib ib; ++ uint64_t dummy; ++ int i, r; ++ ++ r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); ++ if (r) { ++ DRM_ERROR("radeon: failed to get ib (%d).\n", r); ++ return r; ++ } ++ ++ dummy = ib.gpu_addr + 1024; ++ ++ /* stitch together an VCE create msg */ ++ ib.length_dw = 0; ++ ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ ++ ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ ++ ib.ptr[ib.length_dw++] = handle; ++ ++ ib.ptr[ib.length_dw++] = 0x00000030; /* len */ ++ ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */ ++ ib.ptr[ib.length_dw++] = 0x00000000; ++ ib.ptr[ib.length_dw++] = 0x00000042; ++ ib.ptr[ib.length_dw++] = 0x0000000a; ++ ib.ptr[ib.length_dw++] = 0x00000001; ++ ib.ptr[ib.length_dw++] = 0x00000080; ++ ib.ptr[ib.length_dw++] = 0x00000060; ++ ib.ptr[ib.length_dw++] = 0x00000100; ++ ib.ptr[ib.length_dw++] = 0x00000100; ++ ib.ptr[ib.length_dw++] = 0x0000000c; ++ ib.ptr[ib.length_dw++] = 0x00000000; ++ ++ ib.ptr[ib.length_dw++] = 0x00000014; /* len */ ++ ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ ++ ib.ptr[ib.length_dw++] = upper_32_bits(dummy); ++ ib.ptr[ib.length_dw++] = dummy; ++ ib.ptr[ib.length_dw++] = 0x00000001; ++ ++ for (i = ib.length_dw; i < ib_size_dw; ++i) ++ ib.ptr[i] = 0x0; ++ ++ r = radeon_ib_schedule(rdev, &ib, NULL); ++ if (r) { ++ DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); ++ } ++ ++ if (fence) ++ *fence = radeon_fence_ref(ib.fence); ++ ++ radeon_ib_free(rdev, &ib); ++ ++ return r; ++} ++ ++/** ++ * radeon_vce_get_destroy_msg - generate a VCE destroy msg ++ * ++ * @rdev: radeon_device pointer ++ * @ring: ring we should submit the msg to ++ * @handle: VCE session handle to use ++ * @fence: optional fence to return ++ * ++ * Close up a stream for HW test or if userspace failed to do so ++ */ ++int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, ++ uint32_t handle, struct radeon_fence **fence) ++{ ++ const unsigned ib_size_dw = 1024; ++ struct radeon_ib ib; ++ uint64_t dummy; ++ int i, r; ++ ++ r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); ++ if (r) { ++ DRM_ERROR("radeon: failed to get ib (%d).\n", r); ++ return r; ++ } ++ ++ dummy = ib.gpu_addr + 1024; ++ ++ /* stitch together an VCE destroy msg */ ++ ib.length_dw = 0; ++ ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ ++ ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ ++ ib.ptr[ib.length_dw++] = handle; ++ ++ ib.ptr[ib.length_dw++] = 0x00000014; /* len */ ++ ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ ++ ib.ptr[ib.length_dw++] = upper_32_bits(dummy); ++ ib.ptr[ib.length_dw++] = dummy; ++ ib.ptr[ib.length_dw++] = 0x00000001; ++ ++ ib.ptr[ib.length_dw++] = 0x00000008; /* len */ ++ ib.ptr[ib.length_dw++] = 0x02000001; /* destroy cmd */ ++ ++ for (i = ib.length_dw; i < ib_size_dw; ++i) ++ ib.ptr[i] = 0x0; ++ ++ r = radeon_ib_schedule(rdev, &ib, NULL); ++ if (r) { ++ DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); ++ } ++ ++ if (fence) ++ *fence = radeon_fence_ref(ib.fence); ++ ++ radeon_ib_free(rdev, &ib); ++ ++ return r; ++} ++ ++/** ++ * radeon_vce_cs_reloc - command submission relocation ++ * ++ * @p: parser context ++ * @lo: address of lower dword ++ * @hi: address of higher dword ++ * ++ * Patch relocation inside command stream with real buffer address ++ */ ++int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi) ++{ ++ struct radeon_cs_chunk *relocs_chunk; ++ uint64_t offset; ++ unsigned idx; ++ ++ relocs_chunk = &p->chunks[p->chunk_relocs_idx]; ++ offset = radeon_get_ib_value(p, lo); ++ idx = radeon_get_ib_value(p, hi); ++ ++ if (idx >= relocs_chunk->length_dw) { ++ DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", ++ idx, relocs_chunk->length_dw); ++ return -EINVAL; ++ } ++ ++ offset += p->relocs_ptr[(idx / 4)]->lobj.gpu_offset; ++ ++ p->ib.ptr[lo] = offset & 0xFFFFFFFF; ++ p->ib.ptr[hi] = offset >> 32; ++ ++ return 0; ++} ++ ++/** ++ * radeon_vce_cs_parse - parse and validate the command stream ++ * ++ * @p: parser context ++ * ++ */ ++int radeon_vce_cs_parse(struct radeon_cs_parser *p) ++{ ++ uint32_t handle = 0; ++ bool destroy = false; ++ int i, r; ++ ++ while (p->idx < p->chunks[p->chunk_ib_idx].length_dw) { ++ uint32_t len = radeon_get_ib_value(p, p->idx); ++ uint32_t cmd = radeon_get_ib_value(p, p->idx + 1); ++ ++ if ((len < 8) || (len & 3)) { ++ DRM_ERROR("invalid VCE command length (%d)!\n", len); ++ return -EINVAL; ++ } ++ ++ switch (cmd) { ++ case 0x00000001: // session ++ handle = radeon_get_ib_value(p, p->idx + 2); ++ break; ++ ++ case 0x00000002: // task info ++ case 0x01000001: // create ++ case 0x04000001: // config extension ++ case 0x04000002: // pic control ++ case 0x04000005: // rate control ++ case 0x04000007: // motion estimation ++ case 0x04000008: // rdo ++ break; ++ ++ case 0x03000001: // encode ++ r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9); ++ if (r) ++ return r; ++ ++ r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11); ++ if (r) ++ return r; ++ break; ++ ++ case 0x02000001: // destroy ++ destroy = true; ++ break; ++ ++ case 0x05000001: // context buffer ++ case 0x05000004: // video bitstream buffer ++ case 0x05000005: // feedback buffer ++ r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2); ++ if (r) ++ return r; ++ break; ++ ++ default: ++ DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); ++ return -EINVAL; ++ } ++ ++ p->idx += len / 4; ++ } ++ ++ if (destroy) { ++ /* IB contains a destroy msg, free the handle */ ++ for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) ++ atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0); ++ ++ return 0; ++ } ++ ++ /* create or encode, validate the handle */ ++ for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { ++ if (atomic_read(&p->rdev->vce.handles[i]) == handle) ++ return 0; ++ } ++ ++ /* handle not found try to alloc a new one */ ++ for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { ++ if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) { ++ p->rdev->vce.filp[i] = p->filp; ++ return 0; ++ } ++ } ++ ++ DRM_ERROR("No more free VCE handles!\n"); ++ return -EINVAL; ++} ++ ++/** ++ * radeon_vce_semaphore_emit - emit a semaphore command ++ * ++ * @rdev: radeon_device pointer ++ * @ring: engine to use ++ * @semaphore: address of semaphore ++ * @emit_wait: true=emit wait, false=emit signal ++ * ++ */ ++bool radeon_vce_semaphore_emit(struct radeon_device *rdev, ++ struct radeon_ring *ring, ++ struct radeon_semaphore *semaphore, ++ bool emit_wait) ++{ ++ uint64_t addr = semaphore->gpu_addr; ++ ++ radeon_ring_write(ring, VCE_CMD_SEMAPHORE); ++ radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); ++ radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); ++ radeon_ring_write(ring, 0x01003000 | (emit_wait ? 1 : 0)); ++ if (!emit_wait) ++ radeon_ring_write(ring, VCE_CMD_END); ++ ++ return true; ++} ++ ++/** ++ * radeon_vce_ib_execute - execute indirect buffer ++ * ++ * @rdev: radeon_device pointer ++ * @ib: the IB to execute ++ * ++ */ ++void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) ++{ ++ struct radeon_ring *ring = &rdev->ring[ib->ring]; ++ radeon_ring_write(ring, VCE_CMD_IB); ++ radeon_ring_write(ring, ib->gpu_addr); ++ radeon_ring_write(ring, upper_32_bits(ib->gpu_addr)); ++ radeon_ring_write(ring, ib->length_dw); ++} ++ ++/** ++ * radeon_vce_fence_emit - add a fence command to the ring ++ * ++ * @rdev: radeon_device pointer ++ * @fence: the fence ++ * ++ */ ++void radeon_vce_fence_emit(struct radeon_device *rdev, ++ struct radeon_fence *fence) ++{ ++ struct radeon_ring *ring = &rdev->ring[fence->ring]; ++ uint32_t addr = rdev->fence_drv[fence->ring].gpu_addr; ++ ++ radeon_ring_write(ring, VCE_CMD_FENCE); ++ radeon_ring_write(ring, addr); ++ radeon_ring_write(ring, upper_32_bits(addr)); ++ radeon_ring_write(ring, fence->seq); ++ radeon_ring_write(ring, VCE_CMD_TRAP); ++ radeon_ring_write(ring, VCE_CMD_END); ++} ++ ++/** ++ * radeon_vce_ring_test - test if VCE ring is working ++ * ++ * @rdev: radeon_device pointer ++ * @ring: the engine to test on ++ * ++ */ ++int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) ++{ ++ uint32_t rptr = vce_v1_0_get_rptr(rdev, ring); ++ unsigned i; ++ int r; ++ ++ r = radeon_ring_lock(rdev, ring, 16); ++ if (r) { ++ DRM_ERROR("radeon: vce failed to lock ring %d (%d).\n", ++ ring->idx, r); ++ return r; ++ } ++ radeon_ring_write(ring, VCE_CMD_END); ++ radeon_ring_unlock_commit(rdev, ring); ++ ++ for (i = 0; i < rdev->usec_timeout; i++) { ++ if (vce_v1_0_get_rptr(rdev, ring) != rptr) ++ break; ++ DRM_UDELAY(1); ++ } ++ ++ if (i < rdev->usec_timeout) { ++ DRM_INFO("ring test on %d succeeded in %d usecs\n", ++ ring->idx, i); ++ } else { ++ DRM_ERROR("radeon: ring %d test failed\n", ++ ring->idx); ++ r = -ETIMEDOUT; ++ } ++ ++ return r; ++} ++ ++/** ++ * radeon_vce_ib_test - test if VCE IBs are working ++ * ++ * @rdev: radeon_device pointer ++ * @ring: the engine to test on ++ * ++ */ ++int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) ++{ ++ struct radeon_fence *fence = NULL; ++ int r; ++ ++ r = radeon_vce_get_create_msg(rdev, ring->idx, 1, NULL); ++ if (r) { ++ DRM_ERROR("radeon: failed to get create msg (%d).\n", r); ++ goto error; ++ } ++ ++ r = radeon_vce_get_destroy_msg(rdev, ring->idx, 1, &fence); ++ if (r) { ++ DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r); ++ goto error; ++ } ++ ++ r = radeon_fence_wait(fence, false); ++ if (r) { ++ DRM_ERROR("radeon: fence wait failed (%d).\n", r); ++ } else { ++ DRM_INFO("ib test on ring %d succeeded\n", ring->idx); ++ } ++error: ++ radeon_fence_unref(&fence); ++ return r; ++} +diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h +index 940e36b..2b71e67 100644 +--- a/drivers/gpu/drm/radeon/sid.h ++++ b/drivers/gpu/drm/radeon/sid.h +@@ -1747,4 +1747,51 @@ + #define DMA_PACKET_CONSTANT_FILL 0xd + #define DMA_PACKET_NOP 0xf + ++#define VCE_STATUS 0x20004 ++#define VCE_VCPU_CNTL 0x20014 ++#define VCE_CLK_EN (1 << 0) ++#define VCE_VCPU_CACHE_OFFSET0 0x20024 ++#define VCE_VCPU_CACHE_SIZE0 0x20028 ++#define VCE_VCPU_CACHE_OFFSET1 0x2002c ++#define VCE_VCPU_CACHE_SIZE1 0x20030 ++#define VCE_VCPU_CACHE_OFFSET2 0x20034 ++#define VCE_VCPU_CACHE_SIZE2 0x20038 ++#define VCE_SOFT_RESET 0x20120 ++#define VCE_ECPU_SOFT_RESET (1 << 0) ++#define VCE_FME_SOFT_RESET (1 << 2) ++#define VCE_RB_BASE_LO2 0x2016c ++#define VCE_RB_BASE_HI2 0x20170 ++#define VCE_RB_SIZE2 0x20174 ++#define VCE_RB_RPTR2 0x20178 ++#define VCE_RB_WPTR2 0x2017c ++#define VCE_RB_BASE_LO 0x20180 ++#define VCE_RB_BASE_HI 0x20184 ++#define VCE_RB_SIZE 0x20188 ++#define VCE_RB_RPTR 0x2018c ++#define VCE_RB_WPTR 0x20190 ++#define VCE_CLOCK_GATING_A 0x202f8 ++#define VCE_CLOCK_GATING_B 0x202fc ++#define VCE_UENC_CLOCK_GATING 0x205bc ++#define VCE_UENC_REG_CLOCK_GATING 0x205c0 ++#define VCE_FW_REG_STATUS 0x20e10 ++# define VCE_FW_REG_STATUS_BUSY (1 << 0) ++# define VCE_FW_REG_STATUS_PASS (1 << 3) ++# define VCE_FW_REG_STATUS_DONE (1 << 11) ++#define VCE_LMI_FW_START_KEYSEL 0x20e18 ++#define VCE_LMI_FW_PERIODIC_CTRL 0x20e20 ++#define VCE_LMI_CTRL2 0x20e74 ++#define VCE_LMI_CTRL 0x20e98 ++#define VCE_LMI_VM_CTRL 0x20ea0 ++#define VCE_LMI_SWAP_CNTL 0x20eb4 ++#define VCE_LMI_SWAP_CNTL1 0x20eb8 ++#define VCE_LMI_CACHE_CTRL 0x20ef4 ++ ++#define VCE_CMD_NO_OP 0x00000000 ++#define VCE_CMD_END 0x00000001 ++#define VCE_CMD_IB 0x00000002 ++#define VCE_CMD_FENCE 0x00000003 ++#define VCE_CMD_TRAP 0x00000004 ++#define VCE_CMD_IB_AUTO 0x00000005 ++#define VCE_CMD_SEMAPHORE 0x00000006 ++ + #endif +diff --git a/drivers/gpu/drm/radeon/vce_v1_0.c b/drivers/gpu/drm/radeon/vce_v1_0.c +new file mode 100644 +index 0000000..e0c3534 +--- /dev/null ++++ b/drivers/gpu/drm/radeon/vce_v1_0.c +@@ -0,0 +1,187 @@ ++/* ++ * Copyright 2013 Advanced Micro Devices, Inc. ++ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS, AUTHORS 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. ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * Authors: Christian König <christian.koenig@amd.com> ++ */ ++ ++#include <linux/firmware.h> ++#include <drm/drmP.h> ++#include "radeon.h" ++#include "radeon_asic.h" ++#include "sid.h" ++ ++/** ++ * vce_v1_0_get_rptr - get read pointer ++ * ++ * @rdev: radeon_device pointer ++ * @ring: radeon_ring pointer ++ * ++ * Returns the current hardware read pointer ++ */ ++uint32_t vce_v1_0_get_rptr(struct radeon_device *rdev, ++ struct radeon_ring *ring) ++{ ++ if (ring->idx == TN_RING_TYPE_VCE1_INDEX) ++ return RREG32(VCE_RB_RPTR); ++ else ++ return RREG32(VCE_RB_RPTR2); ++} ++ ++/** ++ * vce_v1_0_get_wptr - get write pointer ++ * ++ * @rdev: radeon_device pointer ++ * @ring: radeon_ring pointer ++ * ++ * Returns the current hardware write pointer ++ */ ++uint32_t vce_v1_0_get_wptr(struct radeon_device *rdev, ++ struct radeon_ring *ring) ++{ ++ if (ring->idx == TN_RING_TYPE_VCE1_INDEX) ++ return RREG32(VCE_RB_WPTR); ++ else ++ return RREG32(VCE_RB_WPTR2); ++} ++ ++/** ++ * vce_v1_0_set_wptr - set write pointer ++ * ++ * @rdev: radeon_device pointer ++ * @ring: radeon_ring pointer ++ * ++ * Commits the write pointer to the hardware ++ */ ++void vce_v1_0_set_wptr(struct radeon_device *rdev, ++ struct radeon_ring *ring) ++{ ++ if (ring->idx == TN_RING_TYPE_VCE1_INDEX) ++ WREG32(VCE_RB_WPTR, ring->wptr); ++ else ++ WREG32(VCE_RB_WPTR2, ring->wptr); ++} ++ ++/** ++ * vce_v1_0_start - start VCE block ++ * ++ * @rdev: radeon_device pointer ++ * ++ * Setup and start the VCE block ++ */ ++int vce_v1_0_start(struct radeon_device *rdev) ++{ ++ struct radeon_ring *ring; ++ int i, j, r; ++ ++ /* set BUSY flag */ ++ WREG32_P(VCE_STATUS, 1, ~1); ++ ++ ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; ++ WREG32(VCE_RB_RPTR, ring->rptr); ++ WREG32(VCE_RB_WPTR, ring->wptr); ++ WREG32(VCE_RB_BASE_LO, ring->gpu_addr); ++ WREG32(VCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); ++ WREG32(VCE_RB_SIZE, ring->ring_size / 4); ++ ++ ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; ++ WREG32(VCE_RB_RPTR2, ring->rptr); ++ WREG32(VCE_RB_WPTR2, ring->wptr); ++ WREG32(VCE_RB_BASE_LO2, ring->gpu_addr); ++ WREG32(VCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); ++ WREG32(VCE_RB_SIZE2, ring->ring_size / 4); ++ ++ WREG32_P(VCE_VCPU_CNTL, VCE_CLK_EN, ~VCE_CLK_EN); ++ ++ WREG32_P(VCE_SOFT_RESET, ++ VCE_ECPU_SOFT_RESET | ++ VCE_FME_SOFT_RESET, ~( ++ VCE_ECPU_SOFT_RESET | ++ VCE_FME_SOFT_RESET)); ++ ++ mdelay(100); ++ ++ WREG32_P(VCE_SOFT_RESET, 0, ~( ++ VCE_ECPU_SOFT_RESET | ++ VCE_FME_SOFT_RESET)); ++ ++ for (i = 0; i < 10; ++i) { ++ uint32_t status; ++ for (j = 0; j < 100; ++j) { ++ status = RREG32(VCE_STATUS); ++ if (status & 2) ++ break; ++ mdelay(10); ++ } ++ r = 0; ++ if (status & 2) ++ break; ++ ++ DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); ++ WREG32_P(VCE_SOFT_RESET, VCE_ECPU_SOFT_RESET, ~VCE_ECPU_SOFT_RESET); ++ mdelay(10); ++ WREG32_P(VCE_SOFT_RESET, 0, ~VCE_ECPU_SOFT_RESET); ++ mdelay(10); ++ r = -1; ++ } ++ ++ /* clear BUSY flag */ ++ WREG32_P(VCE_STATUS, 0, ~1); ++ ++ if (r) { ++ DRM_ERROR("VCE not responding, giving up!!!\n"); ++ return r; ++ } ++ ++ return 0; ++} ++ ++int vce_v1_0_init(struct radeon_device *rdev) ++{ ++ struct radeon_ring *ring; ++ int r; ++ ++ r = vce_v1_0_start(rdev); ++ if (r) ++ return r; ++ ++ ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; ++ ring->ready = true; ++ r = radeon_ring_test(rdev, TN_RING_TYPE_VCE1_INDEX, ring); ++ if (r) { ++ ring->ready = false; ++ return r; ++ } ++ ++ ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; ++ ring->ready = true; ++ r = radeon_ring_test(rdev, TN_RING_TYPE_VCE2_INDEX, ring); ++ if (r) { ++ ring->ready = false; ++ return r; ++ } ++ ++ DRM_INFO("VCE initialized successfully.\n"); ++ ++ return 0; ++} +diff --git a/drivers/gpu/drm/radeon/vce_v2_0.c b/drivers/gpu/drm/radeon/vce_v2_0.c +new file mode 100644 +index 0000000..4911d1b +--- /dev/null ++++ b/drivers/gpu/drm/radeon/vce_v2_0.c +@@ -0,0 +1,70 @@ ++/* ++ * Copyright 2013 Advanced Micro Devices, Inc. ++ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS, AUTHORS 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. ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * Authors: Christian König <christian.koenig@amd.com> ++ */ ++ ++#include <linux/firmware.h> ++#include <drm/drmP.h> ++#include "radeon.h" ++#include "radeon_asic.h" ++#include "cikd.h" ++ ++int vce_v2_0_resume(struct radeon_device *rdev) ++{ ++ uint64_t addr = rdev->vce.gpu_addr; ++ uint32_t size; ++ ++ WREG32_P(VCE_CLOCK_GATING_A, 0, ~(1 << 16)); ++ WREG32_P(VCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); ++ WREG32_P(VCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); ++ WREG32(VCE_CLOCK_GATING_B, 0xf7); ++ ++ WREG32(VCE_LMI_CTRL, 0x00398000); ++ WREG32_P(VCE_LMI_CACHE_CTRL, 0x0, ~0x1); ++ WREG32(VCE_LMI_SWAP_CNTL, 0); ++ WREG32(VCE_LMI_SWAP_CNTL1, 0); ++ WREG32(VCE_LMI_VM_CTRL, 0); ++ ++ size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size); ++ WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff); ++ WREG32(VCE_VCPU_CACHE_SIZE0, size); ++ ++ addr += size; ++ size = RADEON_VCE_STACK_SIZE; ++ WREG32(VCE_VCPU_CACHE_OFFSET1, addr & 0x7fffffff); ++ WREG32(VCE_VCPU_CACHE_SIZE1, size); ++ ++ addr += size; ++ size = RADEON_VCE_HEAP_SIZE; ++ WREG32(VCE_VCPU_CACHE_OFFSET2, addr & 0x7fffffff); ++ WREG32(VCE_VCPU_CACHE_SIZE2, size); ++ ++ WREG32_P(VCE_LMI_CTRL2, 0x0, ~0x100); ++ ++ WREG32_P(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, ++ ~VCE_SYS_INT_TRAP_INTERRUPT_EN); ++ ++ return 0; ++} +diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h +index fe421e8a..b93c92a 100644 +--- a/include/uapi/drm/radeon_drm.h ++++ b/include/uapi/drm/radeon_drm.h +@@ -919,6 +919,7 @@ struct drm_radeon_gem_va { + #define RADEON_CS_RING_COMPUTE 1 + #define RADEON_CS_RING_DMA 2 + #define RADEON_CS_RING_UVD 3 ++#define RADEON_CS_RING_VCE 4 + /* The third dword of RADEON_CHUNK_ID_FLAGS is a sint32 that sets the priority */ + /* 0 = normal, + = higher priority, - = lower priority */ + +-- +1.9.1 + |