These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / radeon / vce_v1_0.c
index b44d9c8..a01efe3 100644 (file)
 #include "radeon_asic.h"
 #include "sid.h"
 
+#define VCE_V1_0_FW_SIZE       (256 * 1024)
+#define VCE_V1_0_STACK_SIZE    (64 * 1024)
+#define VCE_V1_0_DATA_SIZE     (7808 * (RADEON_MAX_VCE_HANDLES + 1))
+
+struct vce_v1_0_fw_signature
+{
+       int32_t off;
+       uint32_t len;
+       int32_t num;
+       struct {
+               uint32_t chip_id;
+               uint32_t keyselect;
+               uint32_t nonce[4];
+               uint32_t sigval[4];
+       } val[8];
+};
+
 /**
  * vce_v1_0_get_rptr - get read pointer
  *
@@ -82,6 +99,186 @@ void vce_v1_0_set_wptr(struct radeon_device *rdev,
                WREG32(VCE_RB_WPTR2, ring->wptr);
 }
 
+void vce_v1_0_enable_mgcg(struct radeon_device *rdev, bool enable)
+{
+       u32 tmp;
+
+       if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_VCE_MGCG)) {
+               tmp = RREG32(VCE_CLOCK_GATING_A);
+               tmp |= CGC_DYN_CLOCK_MODE;
+               WREG32(VCE_CLOCK_GATING_A, tmp);
+
+               tmp = RREG32(VCE_UENC_CLOCK_GATING);
+               tmp &= ~0x1ff000;
+               tmp |= 0xff800000;
+               WREG32(VCE_UENC_CLOCK_GATING, tmp);
+
+               tmp = RREG32(VCE_UENC_REG_CLOCK_GATING);
+               tmp &= ~0x3ff;
+               WREG32(VCE_UENC_REG_CLOCK_GATING, tmp);
+       } else {
+               tmp = RREG32(VCE_CLOCK_GATING_A);
+               tmp &= ~CGC_DYN_CLOCK_MODE;
+               WREG32(VCE_CLOCK_GATING_A, tmp);
+
+               tmp = RREG32(VCE_UENC_CLOCK_GATING);
+               tmp |= 0x1ff000;
+               tmp &= ~0xff800000;
+               WREG32(VCE_UENC_CLOCK_GATING, tmp);
+
+               tmp = RREG32(VCE_UENC_REG_CLOCK_GATING);
+               tmp |= 0x3ff;
+               WREG32(VCE_UENC_REG_CLOCK_GATING, tmp);
+       }
+}
+
+static void vce_v1_0_init_cg(struct radeon_device *rdev)
+{
+       u32 tmp;
+
+       tmp = RREG32(VCE_CLOCK_GATING_A);
+       tmp |= CGC_DYN_CLOCK_MODE;
+       WREG32(VCE_CLOCK_GATING_A, tmp);
+
+       tmp = RREG32(VCE_CLOCK_GATING_B);
+       tmp |= 0x1e;
+       tmp &= ~0xe100e1;
+       WREG32(VCE_CLOCK_GATING_B, tmp);
+
+       tmp = RREG32(VCE_UENC_CLOCK_GATING);
+       tmp &= ~0xff9ff000;
+       WREG32(VCE_UENC_CLOCK_GATING, tmp);
+
+       tmp = RREG32(VCE_UENC_REG_CLOCK_GATING);
+       tmp &= ~0x3ff;
+       WREG32(VCE_UENC_REG_CLOCK_GATING, tmp);
+}
+
+int vce_v1_0_load_fw(struct radeon_device *rdev, uint32_t *data)
+{
+       struct vce_v1_0_fw_signature *sign = (void*)rdev->vce_fw->data;
+       uint32_t chip_id;
+       int i;
+
+       switch (rdev->family) {
+       case CHIP_TAHITI:
+               chip_id = 0x01000014;
+               break;
+       case CHIP_VERDE:
+               chip_id = 0x01000015;
+               break;
+       case CHIP_PITCAIRN:
+       case CHIP_OLAND:
+               chip_id = 0x01000016;
+               break;
+       case CHIP_ARUBA:
+               chip_id = 0x01000017;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       for (i = 0; i < le32_to_cpu(sign->num); ++i) {
+               if (le32_to_cpu(sign->val[i].chip_id) == chip_id)
+                       break;
+       }
+
+       if (i == le32_to_cpu(sign->num))
+               return -EINVAL;
+
+       data += (256 - 64) / 4;
+       data[0] = sign->val[i].nonce[0];
+       data[1] = sign->val[i].nonce[1];
+       data[2] = sign->val[i].nonce[2];
+       data[3] = sign->val[i].nonce[3];
+       data[4] = cpu_to_le32(le32_to_cpu(sign->len) + 64);
+
+       memset(&data[5], 0, 44);
+       memcpy(&data[16], &sign[1], rdev->vce_fw->size - sizeof(*sign));
+
+       data += le32_to_cpu(data[4]) / 4;
+       data[0] = sign->val[i].sigval[0];
+       data[1] = sign->val[i].sigval[1];
+       data[2] = sign->val[i].sigval[2];
+       data[3] = sign->val[i].sigval[3];
+
+       rdev->vce.keyselect = le32_to_cpu(sign->val[i].keyselect);
+
+       return 0;
+}
+
+unsigned vce_v1_0_bo_size(struct radeon_device *rdev)
+{
+       WARN_ON(VCE_V1_0_FW_SIZE < rdev->vce_fw->size);
+       return VCE_V1_0_FW_SIZE + VCE_V1_0_STACK_SIZE + VCE_V1_0_DATA_SIZE;
+}
+
+int vce_v1_0_resume(struct radeon_device *rdev)
+{
+       uint64_t addr = rdev->vce.gpu_addr;
+       uint32_t size;
+       int i;
+
+       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, 0);
+
+       WREG32_P(VCE_LMI_FW_PERIODIC_CTRL, 0x4, ~0x4);
+
+       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);
+
+       WREG32(VCE_VCPU_SCRATCH7, RADEON_MAX_VCE_HANDLES);
+
+       addr += 256;
+       size = VCE_V1_0_FW_SIZE;
+       WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff);
+       WREG32(VCE_VCPU_CACHE_SIZE0, size);
+
+       addr += size;
+       size = VCE_V1_0_STACK_SIZE;
+       WREG32(VCE_VCPU_CACHE_OFFSET1, addr & 0x7fffffff);
+       WREG32(VCE_VCPU_CACHE_SIZE1, size);
+
+       addr += size;
+       size = VCE_V1_0_DATA_SIZE;
+       WREG32(VCE_VCPU_CACHE_OFFSET2, addr & 0x7fffffff);
+       WREG32(VCE_VCPU_CACHE_SIZE2, size);
+
+       WREG32_P(VCE_LMI_CTRL2, 0x0, ~0x100);
+
+       WREG32(VCE_LMI_FW_START_KEYSEL, rdev->vce.keyselect);
+
+       for (i = 0; i < 10; ++i) {
+               mdelay(10);
+               if (RREG32(VCE_FW_REG_STATUS) & VCE_FW_REG_STATUS_DONE)
+                       break;
+       }
+
+       if (i == 10)
+               return -ETIMEDOUT;
+
+       if (!(RREG32(VCE_FW_REG_STATUS) & VCE_FW_REG_STATUS_PASS))
+               return -EINVAL;
+
+       for (i = 0; i < 10; ++i) {
+               mdelay(10);
+               if (!(RREG32(VCE_FW_REG_STATUS) & VCE_FW_REG_STATUS_BUSY))
+                       break;
+       }
+
+       if (i == 10)
+               return -ETIMEDOUT;
+
+       vce_v1_0_init_cg(rdev);
+
+       return 0;
+}
+
 /**
  * vce_v1_0_start - start VCE block
  *