drm/radeon: add UVD support for older asics v4
authorChristian König <christian.koenig@amd.com>
Tue, 16 Apr 2013 20:11:22 +0000 (22:11 +0200)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 27 Aug 2014 16:47:55 +0000 (12:47 -0400)
v2: cleanup R600 support
v3: rebased on current drm-fixes-3.12
v4: rebased on drm-next-3.14

Signed-off-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/uvd_v1_0.c
drivers/gpu/drm/radeon/uvd_v2_2.c

index 011d97f6fc7fb40041d343591a753be5de1dc12a..14cb31e25c2f128fe2555c837958575c05173607 100644 (file)
@@ -3009,6 +3009,17 @@ static int r600_startup(struct radeon_device *rdev)
                return r;
        }
 
+       r = uvd_v1_0_resume(rdev);
+       if (!r) {
+               r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX);
+               if (r) {
+                       dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r);
+               }
+       }
+       if (r) {
+               rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+       }
+
        /* Enable IRQ */
        if (!rdev->irq.installed) {
                r = radeon_irq_kms_init(rdev);
@@ -3037,6 +3048,16 @@ static int r600_startup(struct radeon_device *rdev)
        if (r)
                return r;
 
+       ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
+       if (ring->ring_size) {
+               r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
+                                    RADEON_CP_PACKET2);
+               if (!r)
+                       r = uvd_v1_0_init(rdev);
+               if (r)
+                       DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
+       }
+
        r = radeon_ib_pool_init(rdev);
        if (r) {
                dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
@@ -3096,6 +3117,8 @@ int r600_suspend(struct radeon_device *rdev)
        radeon_pm_suspend(rdev);
        r600_audio_fini(rdev);
        r600_cp_stop(rdev);
+       uvd_v1_0_fini(rdev);
+       radeon_uvd_suspend(rdev);
        r600_irq_suspend(rdev);
        radeon_wb_disable(rdev);
        r600_pcie_gart_disable(rdev);
@@ -3175,6 +3198,12 @@ int r600_init(struct radeon_device *rdev)
        rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
        r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
 
+       r = radeon_uvd_init(rdev);
+       if (!r) {
+               rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL;
+               r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096);
+       }
+
        rdev->ih.ring_obj = NULL;
        r600_ih_ring_init(rdev, 64 * 1024);
 
@@ -3204,6 +3233,8 @@ void r600_fini(struct radeon_device *rdev)
        r600_audio_fini(rdev);
        r600_cp_fini(rdev);
        r600_irq_fini(rdev);
+       uvd_v1_0_fini(rdev);
+       radeon_uvd_fini(rdev);
        radeon_wb_fini(rdev);
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
index 8c3fdd581a72389395bf5606f17bb57472cd3119..420bed19e1397d304fb8b061d181e775d1b0090f 100644 (file)
 #define UVD_CGC_GATE                                   0xf4a8
 #define UVD_LMI_CTRL2                                  0xf4f4
 #define UVD_MASTINT_EN                                 0xf500
+#define UVD_FW_START                                   0xf51C
 #define UVD_LMI_ADDR_EXT                               0xf594
 #define UVD_LMI_CTRL                                   0xf598
 #define UVD_LMI_SWAP_CNTL                              0xf5b4
 #define UVD_MPC_SET_MUX                                        0xf5f4
 #define UVD_MPC_SET_ALU                                        0xf5f8
 
+#define UVD_VCPU_CACHE_OFFSET0                         0xf608
+#define UVD_VCPU_CACHE_SIZE0                           0xf60c
+#define UVD_VCPU_CACHE_OFFSET1                         0xf610
+#define UVD_VCPU_CACHE_SIZE1                           0xf614
+#define UVD_VCPU_CACHE_OFFSET2                         0xf618
+#define UVD_VCPU_CACHE_SIZE2                           0xf61c
+
 #define UVD_VCPU_CNTL                                  0xf660
 #define UVD_SOFT_RESET                                 0xf680
 #define                RBC_SOFT_RESET                                  (1<<0)
index eeeeabe09758ddccf2175ad48d9b9bd62e896e83..9e6699a9a0b491d4d01ab0fc207e7b87dff79500 100644 (file)
@@ -965,6 +965,19 @@ static struct radeon_asic r600_asic = {
        },
 };
 
+static struct radeon_asic_ring rv6xx_uvd_ring = {
+       .ib_execute = &uvd_v1_0_ib_execute,
+       .emit_fence = &uvd_v1_0_fence_emit,
+       .emit_semaphore = &uvd_v1_0_semaphore_emit,
+       .cs_parse = &radeon_uvd_cs_parse,
+       .ring_test = &uvd_v1_0_ring_test,
+       .ib_test = &uvd_v1_0_ib_test,
+       .is_lockup = &radeon_ring_test_lockup,
+       .get_rptr = &uvd_v1_0_get_rptr,
+       .get_wptr = &uvd_v1_0_get_wptr,
+       .set_wptr = &uvd_v1_0_set_wptr,
+};
+
 static struct radeon_asic rv6xx_asic = {
        .init = &r600_init,
        .fini = &r600_fini,
@@ -984,6 +997,7 @@ static struct radeon_asic rv6xx_asic = {
        .ring = {
                [RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring,
                [R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring,
+               [R600_RING_TYPE_UVD_INDEX] = &rv6xx_uvd_ring,
        },
        .irq = {
                .set = &r600_irq_set,
@@ -1074,6 +1088,7 @@ static struct radeon_asic rs780_asic = {
        .ring = {
                [RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring,
                [R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring,
+               [R600_RING_TYPE_UVD_INDEX] = &rv6xx_uvd_ring,
        },
        .irq = {
                .set = &r600_irq_set,
index 275a5dc01780f7bedbed2cb3486c4c3d383710eb..987a3b713e06b115fec33bae8d9ff8605aa4cb98 100644 (file)
@@ -883,6 +883,7 @@ uint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev,
                            struct radeon_ring *ring);
 void uvd_v1_0_set_wptr(struct radeon_device *rdev,
                        struct radeon_ring *ring);
+int uvd_v1_0_resume(struct radeon_device *rdev);
 
 int uvd_v1_0_init(struct radeon_device *rdev);
 void uvd_v1_0_fini(struct radeon_device *rdev);
@@ -890,6 +891,8 @@ int uvd_v1_0_start(struct radeon_device *rdev);
 void uvd_v1_0_stop(struct radeon_device *rdev);
 
 int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);
+void uvd_v1_0_fence_emit(struct radeon_device *rdev,
+                        struct radeon_fence *fence);
 int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
 bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev,
                             struct radeon_ring *ring,
index cda391347286c3545bdd952234b3b5fb7186a5d9..62d7086f0e0845079ab203c69395f6d340c1995e 100644 (file)
@@ -22,6 +22,7 @@
  * Authors: Christian König <christian.koenig@amd.com>
  */
 
+#include <linux/firmware.h>
 #include <drm/drmP.h>
 #include "radeon.h"
 #include "radeon_asic.h"
@@ -69,6 +70,82 @@ void uvd_v1_0_set_wptr(struct radeon_device *rdev,
        WREG32(UVD_RBC_RB_WPTR, ring->wptr);
 }
 
+/**
+ * uvd_v1_0_fence_emit - emit an fence & trap command
+ *
+ * @rdev: radeon_device pointer
+ * @fence: fence to emit
+ *
+ * Write a fence and a trap command to the ring.
+ */
+void uvd_v1_0_fence_emit(struct radeon_device *rdev,
+                        struct radeon_fence *fence)
+{
+       struct radeon_ring *ring = &rdev->ring[fence->ring];
+       uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr;
+
+       radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0));
+       radeon_ring_write(ring, addr & 0xffffffff);
+       radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0));
+       radeon_ring_write(ring, fence->seq);
+       radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
+       radeon_ring_write(ring, 0);
+
+       radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0));
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0));
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
+       radeon_ring_write(ring, 2);
+       return;
+}
+
+/**
+ * uvd_v1_0_resume - memory controller programming
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Let the UVD memory controller know it's offsets
+ */
+int uvd_v1_0_resume(struct radeon_device *rdev)
+{
+       uint64_t addr;
+       uint32_t size;
+       int r;
+
+       r = radeon_uvd_resume(rdev);
+       if (r)
+               return r;
+
+       /* programm the VCPU memory controller bits 0-27 */
+       addr = (rdev->uvd.gpu_addr >> 3) + 16;
+       size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size) >> 3;
+       WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
+       WREG32(UVD_VCPU_CACHE_SIZE0, size);
+
+       addr += size;
+       size = RADEON_UVD_STACK_SIZE >> 3;
+       WREG32(UVD_VCPU_CACHE_OFFSET1, addr);
+       WREG32(UVD_VCPU_CACHE_SIZE1, size);
+
+       addr += size;
+       size = RADEON_UVD_HEAP_SIZE >> 3;
+       WREG32(UVD_VCPU_CACHE_OFFSET2, addr);
+       WREG32(UVD_VCPU_CACHE_SIZE2, size);
+
+       /* bits 28-31 */
+       addr = (rdev->uvd.gpu_addr >> 28) & 0xF;
+       WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0));
+
+       /* bits 32-39 */
+       addr = (rdev->uvd.gpu_addr >> 32) & 0xFF;
+       WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31));
+
+       WREG32(UVD_FW_START, *((uint32_t*)rdev->uvd.cpu_addr));
+
+       return 0;
+}
+
 /**
  * uvd_v1_0_init - start and test UVD block
  *
index 8bfdadd5659881d6a47b10ff888592c96417ebee..89193519f8a1faf32fd7fe9013ddd8107cafd977 100644 (file)
@@ -72,6 +72,10 @@ int uvd_v2_2_resume(struct radeon_device *rdev)
        uint32_t chip_id, size;
        int r;
 
+       /* RV770 uses V1.0 MC */
+       if (rdev->family == CHIP_RV770)
+               return uvd_v1_0_resume(rdev);
+
        r = radeon_uvd_resume(rdev);
        if (r)
                return r;