aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0423-drm-amdgpu-Add-DPG-pause-mode-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0423-drm-amdgpu-Add-DPG-pause-mode-support.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0423-drm-amdgpu-Add-DPG-pause-mode-support.patch217
1 files changed, 217 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0423-drm-amdgpu-Add-DPG-pause-mode-support.patch b/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0423-drm-amdgpu-Add-DPG-pause-mode-support.patch
new file mode 100644
index 00000000..189b501b
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0423-drm-amdgpu-Add-DPG-pause-mode-support.patch
@@ -0,0 +1,217 @@
+From 28a2f3cb0b96a181b0597fc6056baa1b68ad24e5 Mon Sep 17 00:00:00 2001
+From: James Zhu <James.Zhu@amd.com>
+Date: Fri, 21 Sep 2018 14:43:18 -0400
+Subject: [PATCH 0423/2940] drm/amdgpu:Add DPG pause mode support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add functions to support VCN DPG pause mode.
+
+Signed-off-by: James Zhu <James.Zhu@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Reviewed-by: Huang Rui <ray.huang@amd.com>
+Acked-by: Christian König <christian.koenig@amd.com>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 161 +++++++++++++++++++++++-
+ 1 file changed, 159 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
+index ec28969d09e6..5616cf21ea7d 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
+@@ -36,6 +36,7 @@
+ #include "soc15_common.h"
+
+ #include "vcn/vcn_1_0_offset.h"
++#include "vcn/vcn_1_0_sh_mask.h"
+
+ /* 1 second timeout */
+ #define VCN_IDLE_TIMEOUT msecs_to_jiffies(1000)
+@@ -212,18 +213,158 @@ int amdgpu_vcn_resume(struct amdgpu_device *adev)
+ return 0;
+ }
+
++static int amdgpu_vcn_pause_dpg_mode(struct amdgpu_device *adev,
++ struct dpg_pause_state *new_state)
++{
++ int ret_code;
++ uint32_t reg_data = 0;
++ uint32_t reg_data2 = 0;
++ struct amdgpu_ring *ring;
++
++ /* pause/unpause if state is changed */
++ if (adev->vcn.pause_state.fw_based != new_state->fw_based) {
++ DRM_DEBUG("dpg pause state changed %d:%d -> %d:%d",
++ adev->vcn.pause_state.fw_based, adev->vcn.pause_state.jpeg,
++ new_state->fw_based, new_state->jpeg);
++
++ reg_data = RREG32_SOC15(UVD, 0, mmUVD_DPG_PAUSE) &
++ (~UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK);
++
++ if (new_state->fw_based == VCN_DPG_STATE__PAUSE) {
++ ret_code = 0;
++
++ if (!(reg_data & UVD_DPG_PAUSE__JPEG_PAUSE_DPG_ACK_MASK))
++ SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_POWER_STATUS,
++ UVD_POWER_STATUS__UVD_POWER_STATUS_TILES_OFF,
++ UVD_POWER_STATUS__UVD_POWER_STATUS_MASK, ret_code);
++
++ if (!ret_code) {
++ /* pause DPG non-jpeg */
++ reg_data |= UVD_DPG_PAUSE__NJ_PAUSE_DPG_REQ_MASK;
++ WREG32_SOC15(UVD, 0, mmUVD_DPG_PAUSE, reg_data);
++ SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_DPG_PAUSE,
++ UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK,
++ UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK, ret_code);
++
++ /* Restore */
++ ring = &adev->vcn.ring_enc[0];
++ WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_LO, ring->gpu_addr);
++ WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
++ WREG32_SOC15(UVD, 0, mmUVD_RB_SIZE, ring->ring_size / 4);
++ WREG32_SOC15(UVD, 0, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
++ WREG32_SOC15(UVD, 0, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
++
++ ring = &adev->vcn.ring_enc[1];
++ WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_LO2, ring->gpu_addr);
++ WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
++ WREG32_SOC15(UVD, 0, mmUVD_RB_SIZE2, ring->ring_size / 4);
++ WREG32_SOC15(UVD, 0, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
++ WREG32_SOC15(UVD, 0, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
++
++ ring = &adev->vcn.ring_dec;
++ WREG32_SOC15(UVD, 0, mmUVD_RBC_RB_WPTR,
++ lower_32_bits(ring->wptr) | 0x80000000);
++ SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_POWER_STATUS,
++ UVD_PGFSM_CONFIG__UVDM_UVDU_PWR_ON,
++ UVD_POWER_STATUS__UVD_POWER_STATUS_MASK, ret_code);
++ }
++ } else {
++ /* unpause dpg non-jpeg, no need to wait */
++ reg_data &= ~UVD_DPG_PAUSE__NJ_PAUSE_DPG_REQ_MASK;
++ WREG32_SOC15(UVD, 0, mmUVD_DPG_PAUSE, reg_data);
++ }
++ adev->vcn.pause_state.fw_based = new_state->fw_based;
++ }
++
++ /* pause/unpause if state is changed */
++ if (adev->vcn.pause_state.jpeg != new_state->jpeg) {
++ DRM_DEBUG("dpg pause state changed %d:%d -> %d:%d",
++ adev->vcn.pause_state.fw_based, adev->vcn.pause_state.jpeg,
++ new_state->fw_based, new_state->jpeg);
++
++ reg_data = RREG32_SOC15(UVD, 0, mmUVD_DPG_PAUSE) &
++ (~UVD_DPG_PAUSE__JPEG_PAUSE_DPG_ACK_MASK);
++
++ if (new_state->jpeg == VCN_DPG_STATE__PAUSE) {
++ ret_code = 0;
++
++ if (!(reg_data & UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK))
++ SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_POWER_STATUS,
++ UVD_POWER_STATUS__UVD_POWER_STATUS_TILES_OFF,
++ UVD_POWER_STATUS__UVD_POWER_STATUS_MASK, ret_code);
++
++ if (!ret_code) {
++ /* Make sure JPRG Snoop is disabled before sending the pause */
++ reg_data2 = RREG32_SOC15(UVD, 0, mmUVD_POWER_STATUS);
++ reg_data2 |= UVD_POWER_STATUS__JRBC_SNOOP_DIS_MASK;
++ WREG32_SOC15(UVD, 0, mmUVD_POWER_STATUS, reg_data2);
++
++ /* pause DPG jpeg */
++ reg_data |= UVD_DPG_PAUSE__JPEG_PAUSE_DPG_REQ_MASK;
++ WREG32_SOC15(UVD, 0, mmUVD_DPG_PAUSE, reg_data);
++ SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_DPG_PAUSE,
++ UVD_DPG_PAUSE__JPEG_PAUSE_DPG_ACK_MASK,
++ UVD_DPG_PAUSE__JPEG_PAUSE_DPG_ACK_MASK, ret_code);
++
++ /* Restore */
++ ring = &adev->vcn.ring_jpeg;
++ WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_VMID, 0);
++ WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, 0x00000001L | 0x00000002L);
++ WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_LOW,
++ lower_32_bits(ring->gpu_addr));
++ WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_HIGH,
++ upper_32_bits(ring->gpu_addr));
++ WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_RPTR, ring->wptr);
++ WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR, ring->wptr);
++ WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, 0x00000002L);
++
++ ring = &adev->vcn.ring_dec;
++ WREG32_SOC15(UVD, 0, mmUVD_RBC_RB_WPTR,
++ lower_32_bits(ring->wptr) | 0x80000000);
++ SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_POWER_STATUS,
++ UVD_PGFSM_CONFIG__UVDM_UVDU_PWR_ON,
++ UVD_POWER_STATUS__UVD_POWER_STATUS_MASK, ret_code);
++ }
++ } else {
++ /* unpause dpg jpeg, no need to wait */
++ reg_data &= ~UVD_DPG_PAUSE__JPEG_PAUSE_DPG_REQ_MASK;
++ WREG32_SOC15(UVD, 0, mmUVD_DPG_PAUSE, reg_data);
++ }
++ adev->vcn.pause_state.jpeg = new_state->jpeg;
++ }
++
++ return 0;
++}
++
+ static void amdgpu_vcn_idle_work_handler(struct work_struct *work)
+ {
+ struct amdgpu_device *adev =
+ container_of(work, struct amdgpu_device, vcn.idle_work.work);
+- unsigned fences = amdgpu_fence_count_emitted(&adev->vcn.ring_dec);
+- unsigned i;
++ unsigned int fences = 0;
++ unsigned int i;
+
+ for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
+ fences += amdgpu_fence_count_emitted(&adev->vcn.ring_enc[i]);
+ }
+
++ if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
++ struct dpg_pause_state new_state;
++
++ if (fences)
++ new_state.fw_based = VCN_DPG_STATE__PAUSE;
++ else
++ new_state.fw_based = VCN_DPG_STATE__UNPAUSE;
++
++ if (amdgpu_fence_count_emitted(&adev->vcn.ring_jpeg))
++ new_state.jpeg = VCN_DPG_STATE__PAUSE;
++ else
++ new_state.jpeg = VCN_DPG_STATE__UNPAUSE;
++
++ amdgpu_vcn_pause_dpg_mode(adev, &new_state);
++ }
++
+ fences += amdgpu_fence_count_emitted(&adev->vcn.ring_jpeg);
++ fences += amdgpu_fence_count_emitted(&adev->vcn.ring_dec);
+
+ if (fences == 0) {
+ amdgpu_gfx_off_ctrl(adev, true);
+@@ -250,6 +391,22 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring)
+ amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN,
+ AMD_PG_STATE_UNGATE);
+ }
++
++ if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
++ struct dpg_pause_state new_state;
++
++ if (ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC)
++ new_state.fw_based = VCN_DPG_STATE__PAUSE;
++ else
++ new_state.fw_based = adev->vcn.pause_state.fw_based;
++
++ if (ring->funcs->type == AMDGPU_RING_TYPE_VCN_JPEG)
++ new_state.jpeg = VCN_DPG_STATE__PAUSE;
++ else
++ new_state.jpeg = adev->vcn.pause_state.jpeg;
++
++ amdgpu_vcn_pause_dpg_mode(adev, &new_state);
++ }
+ }
+
+ void amdgpu_vcn_ring_end_use(struct amdgpu_ring *ring)
+--
+2.17.1
+