]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/commitdiff
drm/radeon: separate UVD code v3
authorChristian König <christian.koenig@amd.com>
Tue, 13 Aug 2013 09:56:53 +0000 (11:56 +0200)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 30 Aug 2013 20:30:42 +0000 (16:30 -0400)
Our different hardware blocks are actually completely
separated, so it doesn't make much sense any more to
structure the code by pure chipset generations.

Start restructuring the code by separating our the UVD block.

v2: updated commit message
v3: rebased and restructurized start/stop functions for kv dpm.

Signed-off-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
15 files changed:
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/kv_dpm.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/rv770d.h
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/uvd_v1_0.c [new file with mode: 0644]
drivers/gpu/drm/radeon/uvd_v2_2.c [new file with mode: 0644]
drivers/gpu/drm/radeon/uvd_v3_1.c [new file with mode: 0644]
drivers/gpu/drm/radeon/uvd_v4_2.c [new file with mode: 0644]

index ea913cc681b4e31ef1293d78efae8698420935ef..1e23b18d549a1397a1cf4dd88622d149c45572d1 100644 (file)
@@ -82,6 +82,14 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
        trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \
        ci_dpm.o
 
+# add UVD block
+radeon-y += \
+       radeon_uvd.o \
+       uvd_v1_0.o \
+       uvd_v2_2.o \
+       uvd_v3_1.o \
+       uvd_v4_2.o
+
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
 radeon-$(CONFIG_ACPI) += radeon_acpi.o
index 34be795de173fb40ef5063b0720500ab89065fd0..1400b5203db15c25394caa71561ad85b0100e48e 100644 (file)
@@ -69,7 +69,6 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev);
 static void cik_program_aspm(struct radeon_device *rdev);
 static void cik_init_pg(struct radeon_device *rdev);
 static void cik_init_cg(struct radeon_device *rdev);
-void cik_uvd_resume(struct radeon_device *rdev);
 
 /* get temperature in millidegrees */
 int ci_get_temp(struct radeon_device *rdev)
@@ -7616,9 +7615,8 @@ static int cik_startup(struct radeon_device *rdev)
                return r;
        }
 
-       r = radeon_uvd_resume(rdev);
+       r = uvd_v4_2_resume(rdev);
        if (!r) {
-               cik_uvd_resume(rdev);
                r = radeon_fence_driver_start_ring(rdev,
                                                   R600_RING_TYPE_UVD_INDEX);
                if (r)
@@ -7705,7 +7703,7 @@ static int cik_startup(struct radeon_device *rdev)
                                     UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
                                     RADEON_CP_PACKET2);
                if (!r)
-                       r = r600_uvd_init(rdev, true);
+                       r = uvd_v1_0_init(rdev);
                if (r)
                        DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
        }
@@ -7770,7 +7768,7 @@ int cik_suspend(struct radeon_device *rdev)
        radeon_vm_manager_fini(rdev);
        cik_cp_enable(rdev, false);
        cik_sdma_enable(rdev, false);
-       r600_uvd_stop(rdev);
+       uvd_v1_0_fini(rdev);
        radeon_uvd_suspend(rdev);
        cik_irq_suspend(rdev);
        radeon_wb_disable(rdev);
@@ -7934,7 +7932,7 @@ void cik_fini(struct radeon_device *rdev)
        radeon_vm_manager_fini(rdev);
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
-       r600_uvd_stop(rdev);
+       uvd_v1_0_fini(rdev);
        radeon_uvd_fini(rdev);
        cik_pcie_gart_fini(rdev);
        r600_vram_scratch_fini(rdev);
@@ -8595,37 +8593,6 @@ int cik_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
        return r;
 }
 
-void cik_uvd_resume(struct radeon_device *rdev)
-{
-       uint64_t addr;
-       uint32_t size;
-
-       /* programm the VCPU memory controller bits 0-27 */
-       addr = rdev->uvd.gpu_addr >> 3;
-       size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 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));
-
-}
-
 static void cik_pcie_gen3_enable(struct radeon_device *rdev)
 {
        struct pci_dev *root = rdev->pdev->bus->self;
index 389f5a981358b9cbab6093034f31fee0ff27952e..52ed22333f0d94c1946f176fc0f36995c3cbb244 100644 (file)
@@ -5239,7 +5239,7 @@ static int evergreen_startup(struct radeon_device *rdev)
                return r;
        }
 
-       r = rv770_uvd_resume(rdev);
+       r = uvd_v2_2_resume(rdev);
        if (!r) {
                r = radeon_fence_driver_start_ring(rdev,
                                                   R600_RING_TYPE_UVD_INDEX);
@@ -5295,7 +5295,7 @@ static int evergreen_startup(struct radeon_device *rdev)
                                     UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
                                     RADEON_CP_PACKET2);
                if (!r)
-                       r = r600_uvd_init(rdev, true);
+                       r = uvd_v1_0_init(rdev);
 
                if (r)
                        DRM_ERROR("radeon: error initializing UVD (%d).\n", r);
@@ -5350,7 +5350,7 @@ int evergreen_resume(struct radeon_device *rdev)
 int evergreen_suspend(struct radeon_device *rdev)
 {
        r600_audio_fini(rdev);
-       r600_uvd_stop(rdev);
+       uvd_v1_0_fini(rdev);
        radeon_uvd_suspend(rdev);
        r700_cp_stop(rdev);
        r600_dma_stop(rdev);
@@ -5487,7 +5487,7 @@ void evergreen_fini(struct radeon_device *rdev)
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
        evergreen_pcie_gart_fini(rdev);
-       r600_uvd_stop(rdev);
+       uvd_v1_0_fini(rdev);
        radeon_uvd_fini(rdev);
        r600_vram_scratch_fini(rdev);
        radeon_gem_fini(rdev);
index 3e232a4d3f4c10ef234abc2a679f5a7e8c101ef2..ef6c901690da10e3d81547caeff9e08263cae64c 100644 (file)
@@ -26,6 +26,7 @@
 #include "cikd.h"
 #include "r600_dpm.h"
 #include "kv_dpm.h"
+#include "radeon_asic.h"
 #include <linux/seq_file.h>
 
 #define KV_MAX_DEEPSLEEP_DIVIDER_ID     5
@@ -59,10 +60,6 @@ extern void cik_exit_rlc_safe_mode(struct radeon_device *rdev);
 extern void cik_update_cg(struct radeon_device *rdev,
                          u32 block, bool enable);
 
-extern void cik_uvd_resume(struct radeon_device *rdev);
-extern int r600_uvd_init(struct radeon_device *rdev, bool ring_test);
-extern void r600_do_uvd_stop(struct radeon_device *rdev);
-
 static const struct kv_lcac_config_values sx_local_cac_cfg_kv[] =
 {
        {  0,       4,        1    },
@@ -1473,7 +1470,7 @@ void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate)
        pi->uvd_power_gated = gate;
 
        if (gate) {
-               r600_do_uvd_stop(rdev);
+               uvd_v1_0_stop(rdev);
                cik_update_cg(rdev, RADEON_CG_BLOCK_UVD, false);
                kv_update_uvd_dpm(rdev, gate);
                if (pi->caps_uvd_pg)
@@ -1481,8 +1478,8 @@ void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate)
        } else {
                if (pi->caps_uvd_pg)
                        kv_notify_message_to_smu(rdev, PPSMC_MSG_UVDPowerON);
-               cik_uvd_resume(rdev);
-               r600_uvd_init(rdev, false);
+               uvd_v4_2_resume(rdev);
+               uvd_v1_0_start(rdev);
                cik_update_cg(rdev, RADEON_CG_BLOCK_UVD, true);
                kv_update_uvd_dpm(rdev, gate);
        }
index e04b17338336e0648f1e8ec21a29b97df836bab8..0205fa1594faf363111907385eeec136423105d5 100644 (file)
@@ -1373,23 +1373,6 @@ void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
        radeon_ring_write(ring, 10); /* poll interval */
 }
 
-void cayman_uvd_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, PACKET0(UVD_SEMA_ADDR_LOW, 0));
-       radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF);
-
-       radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0));
-       radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF);
-
-       radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0));
-       radeon_ring_write(ring, 0x80 | (emit_wait ? 1 : 0));
-}
-
 static void cayman_cp_enable(struct radeon_device *rdev, bool enable)
 {
        if (enable)
@@ -2141,7 +2124,7 @@ static int cayman_startup(struct radeon_device *rdev)
                return r;
        }
 
-       r = rv770_uvd_resume(rdev);
+       r = uvd_v2_2_resume(rdev);
        if (!r) {
                r = radeon_fence_driver_start_ring(rdev,
                                                   R600_RING_TYPE_UVD_INDEX);
@@ -2229,7 +2212,7 @@ static int cayman_startup(struct radeon_device *rdev)
                                     UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
                                     RADEON_CP_PACKET2);
                if (!r)
-                       r = r600_uvd_init(rdev, true);
+                       r = uvd_v1_0_init(rdev);
                if (r)
                        DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
        }
@@ -2283,7 +2266,7 @@ int cayman_suspend(struct radeon_device *rdev)
        radeon_vm_manager_fini(rdev);
        cayman_cp_enable(rdev, false);
        cayman_dma_stop(rdev);
-       r600_uvd_stop(rdev);
+       uvd_v1_0_fini(rdev);
        radeon_uvd_suspend(rdev);
        evergreen_irq_suspend(rdev);
        radeon_wb_disable(rdev);
@@ -2414,7 +2397,7 @@ void cayman_fini(struct radeon_device *rdev)
        radeon_vm_manager_fini(rdev);
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
-       r600_uvd_stop(rdev);
+       uvd_v1_0_fini(rdev);
        radeon_uvd_fini(rdev);
        cayman_pcie_gart_fini(rdev);
        r600_vram_scratch_fini(rdev);
index 30849eca6e07353ef35997831218a8cbca5debaa..3a08ef92d33fe8c648c4b5a1e192297d890eacae 100644 (file)
@@ -2663,231 +2663,6 @@ void r600_dma_fini(struct radeon_device *rdev)
        radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]);
 }
 
-/*
- * UVD
- */
-uint32_t r600_uvd_get_rptr(struct radeon_device *rdev,
-                          struct radeon_ring *ring)
-{
-       return RREG32(UVD_RBC_RB_RPTR);
-}
-
-uint32_t r600_uvd_get_wptr(struct radeon_device *rdev,
-                          struct radeon_ring *ring)
-{
-       return RREG32(UVD_RBC_RB_WPTR);
-}
-
-void r600_uvd_set_wptr(struct radeon_device *rdev,
-                      struct radeon_ring *ring)
-{
-       WREG32(UVD_RBC_RB_WPTR, ring->wptr);
-}
-
-static int r600_uvd_rbc_start(struct radeon_device *rdev, bool ring_test)
-{
-       struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
-       uint32_t rb_bufsz, tmp;
-       int r;
-
-       /* force RBC into idle state */
-       WREG32(UVD_RBC_RB_CNTL, 0x11010101);
-
-       /* Set the write pointer delay */
-       WREG32(UVD_RBC_RB_WPTR_CNTL, 0);
-
-       /* programm the 4GB memory segment for rptr and ring buffer */
-       WREG32(UVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) |
-                                  (0x7 << 16) | (0x1 << 31));
-
-       /* Initialize the ring buffer's read and write pointers */
-       WREG32(UVD_RBC_RB_RPTR, 0x0);
-
-       ring->wptr = ring->rptr = RREG32(UVD_RBC_RB_RPTR);
-       WREG32(UVD_RBC_RB_WPTR, ring->wptr);
-
-       /* set the ring address */
-       WREG32(UVD_RBC_RB_BASE, ring->gpu_addr);
-
-       /* Set ring buffer size */
-       rb_bufsz = drm_order(ring->ring_size);
-       rb_bufsz = (0x1 << 8) | rb_bufsz;
-       WREG32_P(UVD_RBC_RB_CNTL, rb_bufsz, ~0x11f1f);
-
-       if (ring_test) {
-               ring->ready = true;
-               r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring);
-               if (r) {
-                       ring->ready = false;
-                       return r;
-               }
-
-               r = radeon_ring_lock(rdev, ring, 10);
-               if (r) {
-                       DRM_ERROR("radeon: ring failed to lock UVD ring (%d).\n", r);
-                       return r;
-               }
-
-               tmp = PACKET0(UVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0);
-               radeon_ring_write(ring, tmp);
-               radeon_ring_write(ring, 0xFFFFF);
-
-               tmp = PACKET0(UVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0);
-               radeon_ring_write(ring, tmp);
-               radeon_ring_write(ring, 0xFFFFF);
-
-               tmp = PACKET0(UVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0);
-               radeon_ring_write(ring, tmp);
-               radeon_ring_write(ring, 0xFFFFF);
-
-               /* Clear timeout status bits */
-               radeon_ring_write(ring, PACKET0(UVD_SEMA_TIMEOUT_STATUS, 0));
-               radeon_ring_write(ring, 0x8);
-
-               radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0));
-               radeon_ring_write(ring, 3);
-
-               radeon_ring_unlock_commit(rdev, ring);
-       }
-
-       return 0;
-}
-
-void r600_do_uvd_stop(struct radeon_device *rdev)
-{
-       /* force RBC into idle state */
-       WREG32(UVD_RBC_RB_CNTL, 0x11010101);
-
-       /* Stall UMC and register bus before resetting VCPU */
-       WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
-       WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
-       mdelay(1);
-
-       /* put VCPU into reset */
-       WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
-       mdelay(5);
-
-       /* disable VCPU clock */
-       WREG32(UVD_VCPU_CNTL, 0x0);
-
-       /* Unstall UMC and register bus */
-       WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
-       WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
-}
-
-void r600_uvd_stop(struct radeon_device *rdev)
-{
-       struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
-
-       r600_do_uvd_stop(rdev);
-       ring->ready = false;
-}
-
-int r600_uvd_init(struct radeon_device *rdev, bool ring_test)
-{
-       int i, j, r;
-       /* disable byte swapping */
-       u32 lmi_swap_cntl = 0;
-       u32 mp_swap_cntl = 0;
-
-       /* raise clocks while booting up the VCPU */
-       radeon_set_uvd_clocks(rdev, 53300, 40000);
-
-       /* disable clock gating */
-       WREG32(UVD_CGC_GATE, 0);
-
-       /* disable interupt */
-       WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1));
-
-       /* Stall UMC and register bus before resetting VCPU */
-       WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
-       WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
-       mdelay(1);
-
-       /* put LMI, VCPU, RBC etc... into reset */
-       WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET |
-              LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET |
-              CXW_SOFT_RESET | TAP_SOFT_RESET | LMI_UMC_SOFT_RESET);
-       mdelay(5);
-
-       /* take UVD block out of reset */
-       WREG32_P(SRBM_SOFT_RESET, 0, ~SOFT_RESET_UVD);
-       mdelay(5);
-
-       /* initialize UVD memory controller */
-       WREG32(UVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) |
-                            (1 << 21) | (1 << 9) | (1 << 20));
-
-#ifdef __BIG_ENDIAN
-       /* swap (8 in 32) RB and IB */
-       lmi_swap_cntl = 0xa;
-       mp_swap_cntl = 0;
-#endif
-       WREG32(UVD_LMI_SWAP_CNTL, lmi_swap_cntl);
-       WREG32(UVD_MP_SWAP_CNTL, mp_swap_cntl);
-
-       WREG32(UVD_MPC_SET_MUXA0, 0x40c2040);
-       WREG32(UVD_MPC_SET_MUXA1, 0x0);
-       WREG32(UVD_MPC_SET_MUXB0, 0x40c2040);
-       WREG32(UVD_MPC_SET_MUXB1, 0x0);
-       WREG32(UVD_MPC_SET_ALU, 0);
-       WREG32(UVD_MPC_SET_MUX, 0x88);
-
-       /* take all subblocks out of reset, except VCPU */
-       WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
-       mdelay(5);
-
-       /* enable VCPU clock */
-       WREG32(UVD_VCPU_CNTL,  1 << 9);
-
-       /* enable UMC */
-       WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
-
-       /* boot up the VCPU */
-       WREG32(UVD_SOFT_RESET, 0);
-       mdelay(10);
-
-       WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
-
-       for (i = 0; i < 10; ++i) {
-               uint32_t status;
-               for (j = 0; j < 100; ++j) {
-                       status = RREG32(UVD_STATUS);
-                       if (status & 2)
-                               break;
-                       mdelay(10);
-               }
-               r = 0;
-               if (status & 2)
-                       break;
-
-               DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n");
-               WREG32_P(UVD_SOFT_RESET, VCPU_SOFT_RESET, ~VCPU_SOFT_RESET);
-               mdelay(10);
-               WREG32_P(UVD_SOFT_RESET, 0, ~VCPU_SOFT_RESET);
-               mdelay(10);
-               r = -1;
-       }
-
-       if (r) {
-               DRM_ERROR("UVD not responding, giving up!!!\n");
-               goto done;
-       }
-
-       /* enable interupt */
-       WREG32_P(UVD_MASTINT_EN, 3<<1, ~(3 << 1));
-
-       r = r600_uvd_rbc_start(rdev, ring_test);
-       if (!r)
-               DRM_INFO("UVD initialized successfully.\n");
-
-done:
-       /* lower clocks again */
-       radeon_set_uvd_clocks(rdev, 0, 0);
-
-       return r;
-}
-
 /*
  * GPU scratch registers helpers function.
  */
@@ -2997,40 +2772,6 @@ int r600_dma_ring_test(struct radeon_device *rdev,
        return r;
 }
 
-int r600_uvd_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
-{
-       uint32_t tmp = 0;
-       unsigned i;
-       int r;
-
-       WREG32(UVD_CONTEXT_ID, 0xCAFEDEAD);
-       r = radeon_ring_lock(rdev, ring, 3);
-       if (r) {
-               DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n",
-                         ring->idx, r);
-               return r;
-       }
-       radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0));
-       radeon_ring_write(ring, 0xDEADBEEF);
-       radeon_ring_unlock_commit(rdev, ring);
-       for (i = 0; i < rdev->usec_timeout; i++) {
-               tmp = RREG32(UVD_CONTEXT_ID);
-               if (tmp == 0xDEADBEEF)
-                       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 (0x%08X)\n",
-                         ring->idx, tmp);
-               r = -EINVAL;
-       }
-       return r;
-}
-
 /*
  * CP fences/semaphores
  */
@@ -3082,30 +2823,6 @@ void r600_fence_ring_emit(struct radeon_device *rdev,
        }
 }
 
-void r600_uvd_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_CONTEXT_ID, 0));
-       radeon_ring_write(ring, fence->seq);
-       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, upper_32_bits(addr) & 0xff);
-       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;
-}
-
 void r600_semaphore_ring_emit(struct radeon_device *rdev,
                              struct radeon_ring *ring,
                              struct radeon_semaphore *semaphore,
@@ -3175,23 +2892,6 @@ void r600_dma_semaphore_ring_emit(struct radeon_device *rdev,
        radeon_ring_write(ring, upper_32_bits(addr) & 0xff);
 }
 
-void r600_uvd_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, PACKET0(UVD_SEMA_ADDR_LOW, 0));
-       radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF);
-
-       radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0));
-       radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF);
-
-       radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0));
-       radeon_ring_write(ring, emit_wait ? 1 : 0);
-}
-
 /**
  * r600_copy_cpdma - copy pages using the CP DMA engine
  *
@@ -3656,16 +3356,6 @@ void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
        radeon_ring_write(ring, ib->length_dw);
 }
 
-void r600_uvd_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
-{
-       struct radeon_ring *ring = &rdev->ring[ib->ring];
-
-       radeon_ring_write(ring, PACKET0(UVD_RBC_IB_BASE, 0));
-       radeon_ring_write(ring, ib->gpu_addr);
-       radeon_ring_write(ring, PACKET0(UVD_RBC_IB_SIZE, 0));
-       radeon_ring_write(ring, ib->length_dw);
-}
-
 int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
 {
        struct radeon_ib ib;
@@ -3783,41 +3473,6 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
        return r;
 }
 
-int r600_uvd_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
-{
-       struct radeon_fence *fence = NULL;
-       int r;
-
-       r = radeon_set_uvd_clocks(rdev, 53300, 40000);
-       if (r) {
-               DRM_ERROR("radeon: failed to raise UVD clocks (%d).\n", r);
-               return r;
-       }
-
-       r = radeon_uvd_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_uvd_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);
-               goto error;
-       }
-       DRM_INFO("ib test on ring %d succeeded\n",  ring->idx);
-error:
-       radeon_fence_unref(&fence);
-       radeon_set_uvd_clocks(rdev, 0, 0);
-       return r;
-}
-
 /**
  * r600_dma_ring_ib_execute - Schedule an IB on the DMA engine
  *
index 785b7a7add776c4387da5eac94f8b33a18063cca..da755bf37421399e1197576c6d73393284e8fb1e 100644 (file)
@@ -1150,16 +1150,16 @@ static struct radeon_asic rs780_asic = {
 };
 
 static struct radeon_asic_ring rv770_uvd_ring = {
-       .ib_execute = &r600_uvd_ib_execute,
-       .emit_fence = &r600_uvd_fence_emit,
-       .emit_semaphore = &r600_uvd_semaphore_emit,
+       .ib_execute = &uvd_v1_0_ib_execute,
+       .emit_fence = &uvd_v2_2_fence_emit,
+       .emit_semaphore = &uvd_v1_0_semaphore_emit,
        .cs_parse = &radeon_uvd_cs_parse,
-       .ring_test = &r600_uvd_ring_test,
-       .ib_test = &r600_uvd_ib_test,
+       .ring_test = &uvd_v1_0_ring_test,
+       .ib_test = &uvd_v1_0_ib_test,
        .is_lockup = &radeon_ring_test_lockup,
-       .get_rptr = &r600_uvd_get_rptr,
-       .get_wptr = &r600_uvd_get_wptr,
-       .set_wptr = &r600_uvd_set_wptr,
+       .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 rv770_asic = {
@@ -1586,16 +1586,16 @@ static struct radeon_asic_ring cayman_dma_ring = {
 };
 
 static struct radeon_asic_ring cayman_uvd_ring = {
-       .ib_execute = &r600_uvd_ib_execute,
-       .emit_fence = &r600_uvd_fence_emit,
-       .emit_semaphore = &cayman_uvd_semaphore_emit,
+       .ib_execute = &uvd_v1_0_ib_execute,
+       .emit_fence = &uvd_v2_2_fence_emit,
+       .emit_semaphore = &uvd_v3_1_semaphore_emit,
        .cs_parse = &radeon_uvd_cs_parse,
-       .ring_test = &r600_uvd_ring_test,
-       .ib_test = &r600_uvd_ib_test,
+       .ring_test = &uvd_v1_0_ring_test,
+       .ib_test = &uvd_v1_0_ib_test,
        .is_lockup = &radeon_ring_test_lockup,
-       .get_rptr = &r600_uvd_get_rptr,
-       .get_wptr = &r600_uvd_get_wptr,
-       .set_wptr = &r600_uvd_set_wptr,
+       .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 cayman_asic = {
index 5c53eb78b22dd397ea4d9f5f4a41e7682ec8518c..e69f00a7f153b970f1e874cc6d73e46ae8f2490a 100644 (file)
@@ -336,7 +336,6 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
 void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
 int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
 int r600_dma_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
-int r600_uvd_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);
 int r600_copy_cpdma(struct radeon_device *rdev,
                    uint64_t src_offset, uint64_t dst_offset,
                    unsigned num_gpu_pages, struct radeon_fence **fence);
@@ -430,24 +429,6 @@ void rs780_dpm_print_power_state(struct radeon_device *rdev,
 void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                                                       struct seq_file *m);
 
-/* uvd */
-uint32_t r600_uvd_get_rptr(struct radeon_device *rdev,
-                           struct radeon_ring *ring);
-uint32_t r600_uvd_get_wptr(struct radeon_device *rdev,
-                           struct radeon_ring *ring);
-void r600_uvd_set_wptr(struct radeon_device *rdev,
-                       struct radeon_ring *ring);
-int r600_uvd_init(struct radeon_device *rdev, bool ring_test);
-void r600_uvd_stop(struct radeon_device *rdev);
-int r600_uvd_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
-void r600_uvd_fence_emit(struct radeon_device *rdev,
-                        struct radeon_fence *fence);
-void r600_uvd_semaphore_emit(struct radeon_device *rdev,
-                            struct radeon_ring *ring,
-                            struct radeon_semaphore *semaphore,
-                            bool emit_wait);
-void r600_uvd_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
-
 /*
  * rv770,rv730,rv710,rv740
  */
@@ -465,7 +446,6 @@ int rv770_copy_dma(struct radeon_device *rdev,
                  unsigned num_gpu_pages,
                   struct radeon_fence **fence);
 u32 rv770_get_xclk(struct radeon_device *rdev);
-int rv770_uvd_resume(struct radeon_device *rdev);
 int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
 int rv770_get_temp(struct radeon_device *rdev);
 /* rv7xx pm */
@@ -800,4 +780,39 @@ int kv_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level);
 void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
 
+/* uvd v1.0 */
+uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev,
+                           struct radeon_ring *ring);
+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_init(struct radeon_device *rdev);
+void uvd_v1_0_fini(struct radeon_device *rdev);
+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);
+int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
+void uvd_v1_0_semaphore_emit(struct radeon_device *rdev,
+                            struct radeon_ring *ring,
+                            struct radeon_semaphore *semaphore,
+                            bool emit_wait);
+void uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
+
+/* uvd v2.2 */
+int uvd_v2_2_resume(struct radeon_device *rdev);
+void uvd_v2_2_fence_emit(struct radeon_device *rdev,
+                        struct radeon_fence *fence);
+
+/* uvd v3.1 */
+void uvd_v3_1_semaphore_emit(struct radeon_device *rdev,
+                            struct radeon_ring *ring,
+                            struct radeon_semaphore *semaphore,
+                            bool emit_wait);
+
+/* uvd v4.2 */
+int uvd_v4_2_resume(struct radeon_device *rdev);
+
 #endif
index fd9dcb2d182bb07f08b3710b8d4538d837a50ea9..aaab7b1bba27560d309a24ef926f67a1de92bea4 100644 (file)
@@ -801,103 +801,6 @@ u32 rv770_get_xclk(struct radeon_device *rdev)
        return reference_clock;
 }
 
-int rv770_uvd_resume(struct radeon_device *rdev)
-{
-       uint64_t addr;
-       uint32_t chip_id, 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;
-       size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 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));
-
-       /* tell firmware which hardware it is running on */
-       switch (rdev->family) {
-       default:
-               return -EINVAL;
-       case CHIP_RV710:
-               chip_id = 0x01000005;
-               break;
-       case CHIP_RV730:
-               chip_id = 0x01000006;
-               break;
-       case CHIP_RV740:
-               chip_id = 0x01000007;
-               break;
-       case CHIP_CYPRESS:
-       case CHIP_HEMLOCK:
-               chip_id = 0x01000008;
-               break;
-       case CHIP_JUNIPER:
-               chip_id = 0x01000009;
-               break;
-       case CHIP_REDWOOD:
-               chip_id = 0x0100000a;
-               break;
-       case CHIP_CEDAR:
-               chip_id = 0x0100000b;
-               break;
-       case CHIP_SUMO:
-       case CHIP_SUMO2:
-               chip_id = 0x0100000c;
-               break;
-       case CHIP_PALM:
-               chip_id = 0x0100000e;
-               break;
-       case CHIP_CAYMAN:
-               chip_id = 0x0100000f;
-               break;
-       case CHIP_BARTS:
-               chip_id = 0x01000010;
-               break;
-       case CHIP_TURKS:
-               chip_id = 0x01000011;
-               break;
-       case CHIP_CAICOS:
-               chip_id = 0x01000012;
-               break;
-       case CHIP_TAHITI:
-               chip_id = 0x01000014;
-               break;
-       case CHIP_VERDE:
-               chip_id = 0x01000015;
-               break;
-       case CHIP_PITCAIRN:
-               chip_id = 0x01000016;
-               break;
-       case CHIP_ARUBA:
-               chip_id = 0x01000017;
-               break;
-       }
-       WREG32(UVD_VCPU_CHIP_ID, chip_id);
-
-       return 0;
-}
-
 u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
 {
        struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
@@ -1870,7 +1773,7 @@ static int rv770_startup(struct radeon_device *rdev)
                return r;
        }
 
-       r = rv770_uvd_resume(rdev);
+       r = uvd_v2_2_resume(rdev);
        if (!r) {
                r = radeon_fence_driver_start_ring(rdev,
                                                   R600_RING_TYPE_UVD_INDEX);
@@ -1927,7 +1830,7 @@ static int rv770_startup(struct radeon_device *rdev)
                                     UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
                                     RADEON_CP_PACKET2);
                if (!r)
-                       r = r600_uvd_init(rdev, true);
+                       r = uvd_v1_0_init(rdev);
 
                if (r)
                        DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
@@ -1977,7 +1880,7 @@ int rv770_resume(struct radeon_device *rdev)
 int rv770_suspend(struct radeon_device *rdev)
 {
        r600_audio_fini(rdev);
-       r600_uvd_stop(rdev);
+       uvd_v1_0_fini(rdev);
        radeon_uvd_suspend(rdev);
        r700_cp_stop(rdev);
        r600_dma_stop(rdev);
@@ -2092,7 +1995,7 @@ void rv770_fini(struct radeon_device *rdev)
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
        rv770_pcie_gart_fini(rdev);
-       r600_uvd_stop(rdev);
+       uvd_v1_0_fini(rdev);
        radeon_uvd_fini(rdev);
        r600_vram_scratch_fini(rdev);
        radeon_gem_fini(rdev);
index 6bef2b7d601b9f6ac9b336cafc3a705b65202f84..9fe60e5429223c6cb5688af3ca50225d4570aa67 100644 (file)
 #       define TARGET_LINK_SPEED_MASK                     (0xf << 0)
 #       define SELECTABLE_DEEMPHASIS                      (1 << 6)
 
+/*
+ * PM4
+ */
+#define PACKET0(reg, n)        ((RADEON_PACKET_TYPE0 << 30) |                  \
+                        (((reg) >> 2) & 0xFFFF) |                      \
+                        ((n) & 0x3FFF) << 16)
+#define PACKET3(op, n) ((RADEON_PACKET_TYPE3 << 30) |                  \
+                        (((op) & 0xFF) << 8) |                         \
+                        ((n) & 0x3FFF) << 16)
+
 /* UVD */
+#define UVD_GPCOM_VCPU_CMD                             0xef0c
+#define UVD_GPCOM_VCPU_DATA0                           0xef10
+#define UVD_GPCOM_VCPU_DATA1                           0xef14
+
 #define UVD_LMI_EXT40_ADDR                             0xf498
 #define UVD_VCPU_CHIP_ID                               0xf4d4
 #define UVD_VCPU_CACHE_OFFSET0                         0xf4d8
 #define UVD_RBC_RB_RPTR                                        0xf690
 #define UVD_RBC_RB_WPTR                                        0xf694
 
+#define UVD_CONTEXT_ID                                 0xf6f4
+
 #endif
index ae232be62921e24334f924c24ecd70985fedb708..f3f79089405ea7ab2ee79516762163bc736fb3e1 100644 (file)
@@ -6339,7 +6339,7 @@ static int si_startup(struct radeon_device *rdev)
        }
 
        if (rdev->has_uvd) {
-               r = rv770_uvd_resume(rdev);
+               r = uvd_v2_2_resume(rdev);
                if (!r) {
                        r = radeon_fence_driver_start_ring(rdev,
                                                           R600_RING_TYPE_UVD_INDEX);
@@ -6420,7 +6420,7 @@ static int si_startup(struct radeon_device *rdev)
                                             UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
                                             RADEON_CP_PACKET2);
                        if (!r)
-                               r = r600_uvd_init(rdev, true);
+                               r = uvd_v1_0_init(rdev);
                        if (r)
                                DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
                }
@@ -6473,7 +6473,7 @@ int si_suspend(struct radeon_device *rdev)
        si_cp_enable(rdev, false);
        cayman_dma_stop(rdev);
        if (rdev->has_uvd) {
-               r600_uvd_stop(rdev);
+               uvd_v1_0_fini(rdev);
                radeon_uvd_suspend(rdev);
        }
        si_irq_suspend(rdev);
@@ -6616,7 +6616,7 @@ void si_fini(struct radeon_device *rdev)
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
        if (rdev->has_uvd) {
-               r600_uvd_stop(rdev);
+               uvd_v1_0_fini(rdev);
                radeon_uvd_fini(rdev);
        }
        si_pcie_gart_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c b/drivers/gpu/drm/radeon/uvd_v1_0.c
new file mode 100644 (file)
index 0000000..76ca669
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ *
+ * 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 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
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Christian König <christian.koenig@amd.com>
+ */
+
+#include <drm/drmP.h>
+#include "radeon.h"
+#include "radeon_asic.h"
+#include "r600d.h"
+
+/**
+ * uvd_v1_0_get_rptr - get read pointer
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring pointer
+ *
+ * Returns the current hardware read pointer
+ */
+uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev,
+                          struct radeon_ring *ring)
+{
+       return RREG32(UVD_RBC_RB_RPTR);
+}
+
+/**
+ * uvd_v1_0_get_wptr - get write pointer
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring pointer
+ *
+ * Returns the current hardware write pointer
+ */
+uint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev,
+                          struct radeon_ring *ring)
+{
+       return RREG32(UVD_RBC_RB_WPTR);
+}
+
+/**
+ * uvd_v1_0_set_wptr - set write pointer
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring pointer
+ *
+ * Commits the write pointer to the hardware
+ */
+void uvd_v1_0_set_wptr(struct radeon_device *rdev,
+                      struct radeon_ring *ring)
+{
+       WREG32(UVD_RBC_RB_WPTR, ring->wptr);
+}
+
+/**
+ * uvd_v1_0_init - start and test UVD block
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Initialize the hardware, boot up the VCPU and do some testing
+ */
+int uvd_v1_0_init(struct radeon_device *rdev)
+{
+       struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
+       uint32_t tmp;
+       int r;
+
+       /* raise clocks while booting up the VCPU */
+       radeon_set_uvd_clocks(rdev, 53300, 40000);
+
+       uvd_v1_0_start(rdev);
+
+       ring->ready = true;
+       r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring);
+       if (r) {
+               ring->ready = false;
+               goto done;
+       }
+
+       r = radeon_ring_lock(rdev, ring, 10);
+       if (r) {
+               DRM_ERROR("radeon: ring failed to lock UVD ring (%d).\n", r);
+               goto done;
+       }
+
+       tmp = PACKET0(UVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0);
+       radeon_ring_write(ring, tmp);
+       radeon_ring_write(ring, 0xFFFFF);
+
+       tmp = PACKET0(UVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0);
+       radeon_ring_write(ring, tmp);
+       radeon_ring_write(ring, 0xFFFFF);
+
+       tmp = PACKET0(UVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0);
+       radeon_ring_write(ring, tmp);
+       radeon_ring_write(ring, 0xFFFFF);
+
+       /* Clear timeout status bits */
+       radeon_ring_write(ring, PACKET0(UVD_SEMA_TIMEOUT_STATUS, 0));
+       radeon_ring_write(ring, 0x8);
+
+       radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0));
+       radeon_ring_write(ring, 3);
+
+       radeon_ring_unlock_commit(rdev, ring);
+
+done:
+       /* lower clocks again */
+       radeon_set_uvd_clocks(rdev, 0, 0);
+
+       if (!r)
+               DRM_INFO("UVD initialized successfully.\n");
+
+       return r;
+}
+
+/**
+ * uvd_v1_0_fini - stop the hardware block
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the UVD block, mark ring as not ready any more
+ */
+void uvd_v1_0_fini(struct radeon_device *rdev)
+{
+       struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
+
+       uvd_v1_0_stop(rdev);
+       ring->ready = false;
+}
+
+/**
+ * uvd_v1_0_start - start UVD block
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Setup and start the UVD block
+ */
+int uvd_v1_0_start(struct radeon_device *rdev)
+{
+       struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
+       uint32_t rb_bufsz;
+       int i, j, r;
+
+       /* disable byte swapping */
+       u32 lmi_swap_cntl = 0;
+       u32 mp_swap_cntl = 0;
+
+       /* disable clock gating */
+       WREG32(UVD_CGC_GATE, 0);
+
+       /* disable interupt */
+       WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1));
+
+       /* Stall UMC and register bus before resetting VCPU */
+       WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
+       WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
+       mdelay(1);
+
+       /* put LMI, VCPU, RBC etc... into reset */
+       WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET |
+              LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET |
+              CXW_SOFT_RESET | TAP_SOFT_RESET | LMI_UMC_SOFT_RESET);
+       mdelay(5);
+
+       /* take UVD block out of reset */
+       WREG32_P(SRBM_SOFT_RESET, 0, ~SOFT_RESET_UVD);
+       mdelay(5);
+
+       /* initialize UVD memory controller */
+       WREG32(UVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) |
+                            (1 << 21) | (1 << 9) | (1 << 20));
+
+#ifdef __BIG_ENDIAN
+       /* swap (8 in 32) RB and IB */
+       lmi_swap_cntl = 0xa;
+       mp_swap_cntl = 0;
+#endif
+       WREG32(UVD_LMI_SWAP_CNTL, lmi_swap_cntl);
+       WREG32(UVD_MP_SWAP_CNTL, mp_swap_cntl);
+
+       WREG32(UVD_MPC_SET_MUXA0, 0x40c2040);
+       WREG32(UVD_MPC_SET_MUXA1, 0x0);
+       WREG32(UVD_MPC_SET_MUXB0, 0x40c2040);
+       WREG32(UVD_MPC_SET_MUXB1, 0x0);
+       WREG32(UVD_MPC_SET_ALU, 0);
+       WREG32(UVD_MPC_SET_MUX, 0x88);
+
+       /* take all subblocks out of reset, except VCPU */
+       WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
+       mdelay(5);
+
+       /* enable VCPU clock */
+       WREG32(UVD_VCPU_CNTL,  1 << 9);
+
+       /* enable UMC */
+       WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
+
+       /* boot up the VCPU */
+       WREG32(UVD_SOFT_RESET, 0);
+       mdelay(10);
+
+       WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
+
+       for (i = 0; i < 10; ++i) {
+               uint32_t status;
+               for (j = 0; j < 100; ++j) {
+                       status = RREG32(UVD_STATUS);
+                       if (status & 2)
+                               break;
+                       mdelay(10);
+               }
+               r = 0;
+               if (status & 2)
+                       break;
+
+               DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n");
+               WREG32_P(UVD_SOFT_RESET, VCPU_SOFT_RESET, ~VCPU_SOFT_RESET);
+               mdelay(10);
+               WREG32_P(UVD_SOFT_RESET, 0, ~VCPU_SOFT_RESET);
+               mdelay(10);
+               r = -1;
+       }
+
+       if (r) {
+               DRM_ERROR("UVD not responding, giving up!!!\n");
+               return r;
+       }
+
+       /* enable interupt */
+       WREG32_P(UVD_MASTINT_EN, 3<<1, ~(3 << 1));
+
+       /* force RBC into idle state */
+       WREG32(UVD_RBC_RB_CNTL, 0x11010101);
+
+       /* Set the write pointer delay */
+       WREG32(UVD_RBC_RB_WPTR_CNTL, 0);
+
+       /* programm the 4GB memory segment for rptr and ring buffer */
+       WREG32(UVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) |
+                                  (0x7 << 16) | (0x1 << 31));
+
+       /* Initialize the ring buffer's read and write pointers */
+       WREG32(UVD_RBC_RB_RPTR, 0x0);
+
+       ring->wptr = ring->rptr = RREG32(UVD_RBC_RB_RPTR);
+       WREG32(UVD_RBC_RB_WPTR, ring->wptr);
+
+       /* set the ring address */
+       WREG32(UVD_RBC_RB_BASE, ring->gpu_addr);
+
+       /* Set ring buffer size */
+       rb_bufsz = drm_order(ring->ring_size);
+       rb_bufsz = (0x1 << 8) | rb_bufsz;
+       WREG32_P(UVD_RBC_RB_CNTL, rb_bufsz, ~0x11f1f);
+
+       return 0;
+}
+
+/**
+ * uvd_v1_0_stop - stop UVD block
+ *
+ * @rdev: radeon_device pointer
+ *
+ * stop the UVD block
+ */
+void uvd_v1_0_stop(struct radeon_device *rdev)
+{
+       /* force RBC into idle state */
+       WREG32(UVD_RBC_RB_CNTL, 0x11010101);
+
+       /* Stall UMC and register bus before resetting VCPU */
+       WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
+       WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
+       mdelay(1);
+
+       /* put VCPU into reset */
+       WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
+       mdelay(5);
+
+       /* disable VCPU clock */
+       WREG32(UVD_VCPU_CNTL, 0x0);
+
+       /* Unstall UMC and register bus */
+       WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
+       WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
+}
+
+/**
+ * uvd_v1_0_ring_test - register write test
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring pointer
+ *
+ * Test if we can successfully write to the context register
+ */
+int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+       uint32_t tmp = 0;
+       unsigned i;
+       int r;
+
+       WREG32(UVD_CONTEXT_ID, 0xCAFEDEAD);
+       r = radeon_ring_lock(rdev, ring, 3);
+       if (r) {
+               DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n",
+                         ring->idx, r);
+               return r;
+       }
+       radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0));
+       radeon_ring_write(ring, 0xDEADBEEF);
+       radeon_ring_unlock_commit(rdev, ring);
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               tmp = RREG32(UVD_CONTEXT_ID);
+               if (tmp == 0xDEADBEEF)
+                       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 (0x%08X)\n",
+                         ring->idx, tmp);
+               r = -EINVAL;
+       }
+       return r;
+}
+
+/**
+ * uvd_v1_0_semaphore_emit - emit semaphore command
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring pointer
+ * @semaphore: semaphore to emit commands for
+ * @emit_wait: true if we should emit a wait command
+ *
+ * Emit a semaphore command (either wait or signal) to the UVD ring.
+ */
+void uvd_v1_0_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, PACKET0(UVD_SEMA_ADDR_LOW, 0));
+       radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF);
+
+       radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0));
+       radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF);
+
+       radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0));
+       radeon_ring_write(ring, emit_wait ? 1 : 0);
+}
+
+/**
+ * uvd_v1_0_ib_execute - execute indirect buffer
+ *
+ * @rdev: radeon_device pointer
+ * @ib: indirect buffer to execute
+ *
+ * Write ring commands to execute the indirect buffer
+ */
+void uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+       struct radeon_ring *ring = &rdev->ring[ib->ring];
+
+       radeon_ring_write(ring, PACKET0(UVD_RBC_IB_BASE, 0));
+       radeon_ring_write(ring, ib->gpu_addr);
+       radeon_ring_write(ring, PACKET0(UVD_RBC_IB_SIZE, 0));
+       radeon_ring_write(ring, ib->length_dw);
+}
+
+/**
+ * uvd_v1_0_ib_test - test ib execution
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring pointer
+ *
+ * Test if we can successfully execute an IB
+ */
+int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+       struct radeon_fence *fence = NULL;
+       int r;
+
+       r = radeon_set_uvd_clocks(rdev, 53300, 40000);
+       if (r) {
+               DRM_ERROR("radeon: failed to raise UVD clocks (%d).\n", r);
+               return r;
+       }
+
+       r = radeon_uvd_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_uvd_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);
+               goto error;
+       }
+       DRM_INFO("ib test on ring %d succeeded\n",  ring->idx);
+error:
+       radeon_fence_unref(&fence);
+       radeon_set_uvd_clocks(rdev, 0, 0);
+       return r;
+}
diff --git a/drivers/gpu/drm/radeon/uvd_v2_2.c b/drivers/gpu/drm/radeon/uvd_v2_2.c
new file mode 100644 (file)
index 0000000..b19ef49
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ *
+ * 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 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
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Christian König <christian.koenig@amd.com>
+ */
+
+#include <linux/firmware.h>
+#include <drm/drmP.h>
+#include "radeon.h"
+#include "radeon_asic.h"
+#include "rv770d.h"
+
+/**
+ * uvd_v2_2_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_v2_2_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_CONTEXT_ID, 0));
+       radeon_ring_write(ring, fence->seq);
+       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, upper_32_bits(addr) & 0xff);
+       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_v2_2_resume - memory controller programming
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Let the UVD memory controller know it's offsets
+ */
+int uvd_v2_2_resume(struct radeon_device *rdev)
+{
+       uint64_t addr;
+       uint32_t chip_id, 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;
+       size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 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));
+
+       /* tell firmware which hardware it is running on */
+       switch (rdev->family) {
+       default:
+               return -EINVAL;
+       case CHIP_RV710:
+               chip_id = 0x01000005;
+               break;
+       case CHIP_RV730:
+               chip_id = 0x01000006;
+               break;
+       case CHIP_RV740:
+               chip_id = 0x01000007;
+               break;
+       case CHIP_CYPRESS:
+       case CHIP_HEMLOCK:
+               chip_id = 0x01000008;
+               break;
+       case CHIP_JUNIPER:
+               chip_id = 0x01000009;
+               break;
+       case CHIP_REDWOOD:
+               chip_id = 0x0100000a;
+               break;
+       case CHIP_CEDAR:
+               chip_id = 0x0100000b;
+               break;
+       case CHIP_SUMO:
+       case CHIP_SUMO2:
+               chip_id = 0x0100000c;
+               break;
+       case CHIP_PALM:
+               chip_id = 0x0100000e;
+               break;
+       case CHIP_CAYMAN:
+               chip_id = 0x0100000f;
+               break;
+       case CHIP_BARTS:
+               chip_id = 0x01000010;
+               break;
+       case CHIP_TURKS:
+               chip_id = 0x01000011;
+               break;
+       case CHIP_CAICOS:
+               chip_id = 0x01000012;
+               break;
+       case CHIP_TAHITI:
+               chip_id = 0x01000014;
+               break;
+       case CHIP_VERDE:
+               chip_id = 0x01000015;
+               break;
+       case CHIP_PITCAIRN:
+               chip_id = 0x01000016;
+               break;
+       case CHIP_ARUBA:
+               chip_id = 0x01000017;
+               break;
+       }
+       WREG32(UVD_VCPU_CHIP_ID, chip_id);
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/radeon/uvd_v3_1.c b/drivers/gpu/drm/radeon/uvd_v3_1.c
new file mode 100644 (file)
index 0000000..5b6fa1f
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ *
+ * 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 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
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Christian König <christian.koenig@amd.com>
+ */
+
+#include <drm/drmP.h>
+#include "radeon.h"
+#include "radeon_asic.h"
+#include "nid.h"
+
+/**
+ * uvd_v3_1_semaphore_emit - emit semaphore command
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring pointer
+ * @semaphore: semaphore to emit commands for
+ * @emit_wait: true if we should emit a wait command
+ *
+ * Emit a semaphore command (either wait or signal) to the UVD ring.
+ */
+void uvd_v3_1_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, PACKET0(UVD_SEMA_ADDR_LOW, 0));
+       radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF);
+
+       radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0));
+       radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF);
+
+       radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0));
+       radeon_ring_write(ring, 0x80 | (emit_wait ? 1 : 0));
+}
diff --git a/drivers/gpu/drm/radeon/uvd_v4_2.c b/drivers/gpu/drm/radeon/uvd_v4_2.c
new file mode 100644 (file)
index 0000000..d7e4807
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ *
+ * 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 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
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: 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"
+
+/**
+ * uvd_v4_2_resume - memory controller programming
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Let the UVD memory controller know it's offsets
+ */
+int uvd_v4_2_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;
+       size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 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));
+
+       return 0;
+}