drm/amdgpu: implement UVD6 check/pre/post_soft_reset
authorChunming Zhou <David1.Zhou@amd.com>
Mon, 18 Jul 2016 09:18:01 +0000 (17:18 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 8 Aug 2016 15:32:11 +0000 (11:32 -0400)
Signed-off-by: Chunming Zhou <David1.Zhou@amd.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c

index e4a731b..108e04f 100644 (file)
@@ -1689,6 +1689,7 @@ struct amdgpu_uvd {
        bool                    address_64_bit;
        bool                    use_ctx_buf;
        struct amd_sched_entity entity;
+       uint32_t                srbm_soft_reset;
 };
 
 /*
index 3640b12..309e58c 100644 (file)
@@ -1977,7 +1977,6 @@ static bool amdgpu_need_full_reset(struct amdgpu_device *adev)
 {
        if (adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang ||
            adev->ip_block_status[AMD_IP_BLOCK_TYPE_SMC].hang ||
-           adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang ||
            adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang ||
            adev->ip_block_status[AMD_IP_BLOCK_TYPE_ACP].hang ||
            adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang) {
index 7f21102..4fa5091 100644 (file)
@@ -754,14 +754,76 @@ static int uvd_v6_0_wait_for_idle(void *handle)
        return -ETIMEDOUT;
 }
 
-static int uvd_v6_0_soft_reset(void *handle)
+#define AMDGPU_UVD_STATUS_BUSY_MASK    0xfd
+static int uvd_v6_0_check_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 srbm_soft_reset = 0;
+       u32 tmp = RREG32(mmSRBM_STATUS);
+
+       if (REG_GET_FIELD(tmp, SRBM_STATUS, UVD_RQ_PENDING) ||
+           REG_GET_FIELD(tmp, SRBM_STATUS, UVD_BUSY) ||
+           (RREG32(mmUVD_STATUS) & AMDGPU_UVD_STATUS_BUSY_MASK))
+               srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_UVD, 1);
+
+       if (srbm_soft_reset) {
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang = true;
+               adev->uvd.srbm_soft_reset = srbm_soft_reset;
+       } else {
+               adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang = false;
+               adev->uvd.srbm_soft_reset = 0;
+       }
+       return 0;
+}
+static int uvd_v6_0_pre_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang)
+               return 0;
+
        uvd_v6_0_stop(adev);
+       return 0;
+}
+
+static int uvd_v6_0_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       u32 srbm_soft_reset;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang)
+               return 0;
+       srbm_soft_reset = adev->uvd.srbm_soft_reset;
+
+       if (srbm_soft_reset) {
+               u32 tmp;
+
+               tmp = RREG32(mmSRBM_SOFT_RESET);
+               tmp |= srbm_soft_reset;
+               dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+               WREG32(mmSRBM_SOFT_RESET, tmp);
+               tmp = RREG32(mmSRBM_SOFT_RESET);
+
+               udelay(50);
+
+               tmp &= ~srbm_soft_reset;
+               WREG32(mmSRBM_SOFT_RESET, tmp);
+               tmp = RREG32(mmSRBM_SOFT_RESET);
+
+               /* Wait a little for things to settle down */
+               udelay(50);
+       }
+
+       return 0;
+}
+
+static int uvd_v6_0_post_soft_reset(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang)
+               return 0;
 
-       WREG32_P(mmSRBM_SOFT_RESET, SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK,
-                       ~SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK);
        mdelay(5);
 
        return uvd_v6_0_start(adev);
@@ -966,7 +1028,10 @@ const struct amd_ip_funcs uvd_v6_0_ip_funcs = {
        .resume = uvd_v6_0_resume,
        .is_idle = uvd_v6_0_is_idle,
        .wait_for_idle = uvd_v6_0_wait_for_idle,
+       .check_soft_reset = uvd_v6_0_check_soft_reset,
+       .pre_soft_reset = uvd_v6_0_pre_soft_reset,
        .soft_reset = uvd_v6_0_soft_reset,
+       .post_soft_reset = uvd_v6_0_post_soft_reset,
        .set_clockgating_state = uvd_v6_0_set_clockgating_state,
        .set_powergating_state = uvd_v6_0_set_powergating_state,
 };