]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amdgpu/vcn4.0.3: implement DPG pause mode handling for VCN 4.0.3
authorJesse.Zhang <Jesse.Zhang@amd.com>
Wed, 14 Jan 2026 02:37:59 +0000 (10:37 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 21 Jan 2026 19:17:36 +0000 (14:17 -0500)
For MI projects, when Dynamic Power Gating (DPG) is enabled,
VCN reset operations should be performed with DPG in pause mode.
Otherwise, the hardware may perform undesirable reset operations

Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Jesse Zhang <jesse.zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c

index cb7123ec1a5d1a3e8011a4bab87d69026756819c..0ce85dbd7abb17acb1958869b3b10db7d7717be7 100644 (file)
@@ -847,6 +847,7 @@ static int vcn_v4_0_3_start_dpg_mode(struct amdgpu_vcn_inst *vinst,
        int inst_idx = vinst->inst;
        struct amdgpu_vcn4_fw_shared *fw_shared =
                                                adev->vcn.inst[inst_idx].fw_shared.cpu_addr;
+       struct dpg_pause_state state = {.fw_based = VCN_DPG_STATE__PAUSE};
        struct amdgpu_ring *ring;
        int vcn_inst, ret;
        uint32_t tmp;
@@ -951,6 +952,9 @@ static int vcn_v4_0_3_start_dpg_mode(struct amdgpu_vcn_inst *vinst,
 
        ring = &adev->vcn.inst[inst_idx].ring_enc[0];
 
+       /* Pause dpg */
+       vcn_v4_0_3_pause_dpg_mode(vinst, &state);
+
        /* program the RB_BASE for ring buffer */
        WREG32_SOC15(VCN, vcn_inst, regUVD_RB_BASE_LO,
                     lower_32_bits(ring->gpu_addr));
@@ -1360,9 +1364,13 @@ static int vcn_v4_0_3_stop_dpg_mode(struct amdgpu_vcn_inst *vinst)
        int inst_idx = vinst->inst;
        uint32_t tmp;
        int vcn_inst;
+       struct dpg_pause_state state = {.fw_based = VCN_DPG_STATE__UNPAUSE};
 
        vcn_inst = GET_INST(VCN, inst_idx);
 
+       /* Unpause dpg */
+       vcn_v4_0_3_pause_dpg_mode(vinst, &state);
+
        /* Wait for power status to be 1 */
        SOC15_WAIT_ON_RREG(VCN, vcn_inst, regUVD_POWER_STATUS, 1,
                           UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
@@ -1486,6 +1494,39 @@ Done:
 static int vcn_v4_0_3_pause_dpg_mode(struct amdgpu_vcn_inst *vinst,
                                     struct dpg_pause_state *new_state)
 {
+       struct amdgpu_device *adev = vinst->adev;
+       int inst_idx = vinst->inst;
+       uint32_t reg_data = 0;
+       int ret_code;
+
+       /* pause/unpause if state is changed */
+       if (adev->vcn.inst[inst_idx].pause_state.fw_based != new_state->fw_based) {
+               DRM_DEV_DEBUG(adev->dev, "dpg pause state changed %d -> %d",
+                       adev->vcn.inst[inst_idx].pause_state.fw_based,  new_state->fw_based);
+               reg_data = RREG32_SOC15(VCN, inst_idx, regUVD_DPG_PAUSE) &
+                       (~UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK);
+
+               if (new_state->fw_based == VCN_DPG_STATE__PAUSE) {
+                       ret_code = SOC15_WAIT_ON_RREG(VCN, inst_idx, regUVD_POWER_STATUS, 0x1,
+                               UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
+
+                       if (!ret_code) {
+                               /* pause DPG */
+                               reg_data |= UVD_DPG_PAUSE__NJ_PAUSE_DPG_REQ_MASK;
+                               WREG32_SOC15(VCN, inst_idx, regUVD_DPG_PAUSE, reg_data);
+
+                               /* wait for ACK */
+                               SOC15_WAIT_ON_RREG(VCN, inst_idx, regUVD_DPG_PAUSE,
+                                       UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK,
+                                       UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK);
+                       }
+               } else {
+                       /* unpause dpg, no need to wait */
+                       reg_data &= ~UVD_DPG_PAUSE__NJ_PAUSE_DPG_REQ_MASK;
+                       WREG32_SOC15(VCN, inst_idx, regUVD_DPG_PAUSE, reg_data);
+               }
+               adev->vcn.inst[inst_idx].pause_state.fw_based = new_state->fw_based;
+       }
 
        return 0;
 }