1aaa36a97SAlex Deucher /* 2aaa36a97SAlex Deucher * Copyright 2014 Advanced Micro Devices, Inc. 3aaa36a97SAlex Deucher * All Rights Reserved. 4aaa36a97SAlex Deucher * 5aaa36a97SAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a 6aaa36a97SAlex Deucher * copy of this software and associated documentation files (the 7aaa36a97SAlex Deucher * "Software"), to deal in the Software without restriction, including 8aaa36a97SAlex Deucher * without limitation the rights to use, copy, modify, merge, publish, 9aaa36a97SAlex Deucher * distribute, sub license, and/or sell copies of the Software, and to 10aaa36a97SAlex Deucher * permit persons to whom the Software is furnished to do so, subject to 11aaa36a97SAlex Deucher * the following conditions: 12aaa36a97SAlex Deucher * 13aaa36a97SAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14aaa36a97SAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15aaa36a97SAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 16aaa36a97SAlex Deucher * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 17aaa36a97SAlex Deucher * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18aaa36a97SAlex Deucher * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 19aaa36a97SAlex Deucher * USE OR OTHER DEALINGS IN THE SOFTWARE. 20aaa36a97SAlex Deucher * 21aaa36a97SAlex Deucher * The above copyright notice and this permission notice (including the 22aaa36a97SAlex Deucher * next paragraph) shall be included in all copies or substantial portions 23aaa36a97SAlex Deucher * of the Software. 24aaa36a97SAlex Deucher * 25aaa36a97SAlex Deucher * Authors: Christian König <christian.koenig@amd.com> 26aaa36a97SAlex Deucher */ 27aaa36a97SAlex Deucher 28aaa36a97SAlex Deucher #include <linux/firmware.h> 29aaa36a97SAlex Deucher #include <drm/drmP.h> 30aaa36a97SAlex Deucher #include "amdgpu.h" 31aaa36a97SAlex Deucher #include "amdgpu_vce.h" 32aaa36a97SAlex Deucher #include "vid.h" 33aaa36a97SAlex Deucher #include "vce/vce_3_0_d.h" 34aaa36a97SAlex Deucher #include "vce/vce_3_0_sh_mask.h" 35be4f38e2SAlex Deucher #include "oss/oss_3_0_d.h" 36be4f38e2SAlex Deucher #include "oss/oss_3_0_sh_mask.h" 375bbc553aSLeo Liu #include "gca/gfx_8_0_d.h" 386a585777SAlex Deucher #include "smu/smu_7_1_2_d.h" 396a585777SAlex Deucher #include "smu/smu_7_1_2_sh_mask.h" 40115933a5SChunming Zhou #include "gca/gfx_8_0_d.h" 41115933a5SChunming Zhou #include "gca/gfx_8_0_sh_mask.h" 42115933a5SChunming Zhou 435bbc553aSLeo Liu 445bbc553aSLeo Liu #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04 455bbc553aSLeo Liu #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK 0x10 463c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0 0x8616 473c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1 0x8617 483c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2 0x8618 49567e6e29Sjimqu #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02 50aaa36a97SAlex Deucher 51e9822622SLeo Liu #define VCE_V3_0_FW_SIZE (384 * 1024) 52e9822622SLeo Liu #define VCE_V3_0_STACK_SIZE (64 * 1024) 53e9822622SLeo Liu #define VCE_V3_0_DATA_SIZE ((16 * 1024 * AMDGPU_MAX_VCE_HANDLES) + (52 * 1024)) 54e9822622SLeo Liu 555bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx); 56aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev); 57aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev); 58567e6e29Sjimqu static int vce_v3_0_wait_for_idle(void *handle); 59aaa36a97SAlex Deucher 60aaa36a97SAlex Deucher /** 61aaa36a97SAlex Deucher * vce_v3_0_ring_get_rptr - get read pointer 62aaa36a97SAlex Deucher * 63aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 64aaa36a97SAlex Deucher * 65aaa36a97SAlex Deucher * Returns the current hardware read pointer 66aaa36a97SAlex Deucher */ 67aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring) 68aaa36a97SAlex Deucher { 69aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 70aaa36a97SAlex Deucher 71aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 72aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR); 73aaa36a97SAlex Deucher else 74aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR2); 75aaa36a97SAlex Deucher } 76aaa36a97SAlex Deucher 77aaa36a97SAlex Deucher /** 78aaa36a97SAlex Deucher * vce_v3_0_ring_get_wptr - get write pointer 79aaa36a97SAlex Deucher * 80aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 81aaa36a97SAlex Deucher * 82aaa36a97SAlex Deucher * Returns the current hardware write pointer 83aaa36a97SAlex Deucher */ 84aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring) 85aaa36a97SAlex Deucher { 86aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 87aaa36a97SAlex Deucher 88aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 89aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR); 90aaa36a97SAlex Deucher else 91aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR2); 92aaa36a97SAlex Deucher } 93aaa36a97SAlex Deucher 94aaa36a97SAlex Deucher /** 95aaa36a97SAlex Deucher * vce_v3_0_ring_set_wptr - set write pointer 96aaa36a97SAlex Deucher * 97aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 98aaa36a97SAlex Deucher * 99aaa36a97SAlex Deucher * Commits the write pointer to the hardware 100aaa36a97SAlex Deucher */ 101aaa36a97SAlex Deucher static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring) 102aaa36a97SAlex Deucher { 103aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 104aaa36a97SAlex Deucher 105aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 106aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR, ring->wptr); 107aaa36a97SAlex Deucher else 108aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR2, ring->wptr); 109aaa36a97SAlex Deucher } 110aaa36a97SAlex Deucher 1110689a570SEric Huang static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override) 1120689a570SEric Huang { 1130689a570SEric Huang u32 tmp, data; 1140689a570SEric Huang 1150689a570SEric Huang tmp = data = RREG32(mmVCE_RB_ARB_CTRL); 1160689a570SEric Huang if (override) 1170689a570SEric Huang data |= VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; 1180689a570SEric Huang else 1190689a570SEric Huang data &= ~VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; 1200689a570SEric Huang 1210689a570SEric Huang if (tmp != data) 1220689a570SEric Huang WREG32(mmVCE_RB_ARB_CTRL, data); 1230689a570SEric Huang } 1240689a570SEric Huang 1250689a570SEric Huang static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, 1260689a570SEric Huang bool gated) 1270689a570SEric Huang { 1280689a570SEric Huang u32 tmp, data; 129f16fe6d3STom St Denis 1300689a570SEric Huang /* Set Override to disable Clock Gating */ 1310689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, true); 1320689a570SEric Huang 1336f906814STom St Denis /* This function enables MGCG which is controlled by firmware. 1346f906814STom St Denis With the clocks in the gated state the core is still 1356f906814STom St Denis accessible but the firmware will throttle the clocks on the 1366f906814STom St Denis fly as necessary. 1370689a570SEric Huang */ 1386f906814STom St Denis if (gated) { 1390689a570SEric Huang tmp = data = RREG32(mmVCE_CLOCK_GATING_B); 1400689a570SEric Huang data |= 0x1ff; 1410689a570SEric Huang data &= ~0xef0000; 1420689a570SEric Huang if (tmp != data) 1430689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1440689a570SEric Huang 1450689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); 1460689a570SEric Huang data |= 0x3ff000; 1470689a570SEric Huang data &= ~0xffc00000; 1480689a570SEric Huang if (tmp != data) 1490689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1500689a570SEric Huang 1510689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1520689a570SEric Huang data |= 0x2; 1536f906814STom St Denis data &= ~0x00010000; 1540689a570SEric Huang if (tmp != data) 1550689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1560689a570SEric Huang 1570689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1580689a570SEric Huang data |= 0x37f; 1590689a570SEric Huang if (tmp != data) 1600689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1610689a570SEric Huang 1620689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1630689a570SEric Huang data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1640689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1650689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1660689a570SEric Huang 0x8; 1670689a570SEric Huang if (tmp != data) 1680689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1690689a570SEric Huang } else { 1700689a570SEric Huang tmp = data = RREG32(mmVCE_CLOCK_GATING_B); 1710689a570SEric Huang data &= ~0x80010; 1720689a570SEric Huang data |= 0xe70008; 1730689a570SEric Huang if (tmp != data) 1740689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1756f906814STom St Denis 1760689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); 1770689a570SEric Huang data |= 0xffc00000; 1780689a570SEric Huang if (tmp != data) 1790689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1806f906814STom St Denis 1810689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1820689a570SEric Huang data |= 0x10000; 1830689a570SEric Huang if (tmp != data) 1840689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1856f906814STom St Denis 1860689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1870689a570SEric Huang data &= ~0xffc00000; 1880689a570SEric Huang if (tmp != data) 1890689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1906f906814STom St Denis 1910689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1920689a570SEric Huang data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1930689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1940689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1950689a570SEric Huang 0x8); 1960689a570SEric Huang if (tmp != data) 1970689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1980689a570SEric Huang } 1990689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, false); 2000689a570SEric Huang } 2010689a570SEric Huang 202567e6e29Sjimqu static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev) 203567e6e29Sjimqu { 204567e6e29Sjimqu int i, j; 205567e6e29Sjimqu 206567e6e29Sjimqu for (i = 0; i < 10; ++i) { 207567e6e29Sjimqu for (j = 0; j < 100; ++j) { 208b7e2e9f7Sjimqu uint32_t status = RREG32(mmVCE_STATUS); 209b7e2e9f7Sjimqu 210567e6e29Sjimqu if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK) 211567e6e29Sjimqu return 0; 212567e6e29Sjimqu mdelay(10); 213567e6e29Sjimqu } 214567e6e29Sjimqu 215567e6e29Sjimqu DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); 216567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 217567e6e29Sjimqu VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, 218567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 219567e6e29Sjimqu mdelay(10); 220567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 0, 221567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 222567e6e29Sjimqu mdelay(10); 223567e6e29Sjimqu } 224567e6e29Sjimqu 225567e6e29Sjimqu return -ETIMEDOUT; 226567e6e29Sjimqu } 227567e6e29Sjimqu 228aaa36a97SAlex Deucher /** 229aaa36a97SAlex Deucher * vce_v3_0_start - start VCE block 230aaa36a97SAlex Deucher * 231aaa36a97SAlex Deucher * @adev: amdgpu_device pointer 232aaa36a97SAlex Deucher * 233aaa36a97SAlex Deucher * Setup and start the VCE block 234aaa36a97SAlex Deucher */ 235aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev) 236aaa36a97SAlex Deucher { 237aaa36a97SAlex Deucher struct amdgpu_ring *ring; 238567e6e29Sjimqu int idx, r; 239567e6e29Sjimqu 240567e6e29Sjimqu ring = &adev->vce.ring[0]; 241567e6e29Sjimqu WREG32(mmVCE_RB_RPTR, ring->wptr); 242567e6e29Sjimqu WREG32(mmVCE_RB_WPTR, ring->wptr); 243567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr); 244567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); 245567e6e29Sjimqu WREG32(mmVCE_RB_SIZE, ring->ring_size / 4); 246567e6e29Sjimqu 247567e6e29Sjimqu ring = &adev->vce.ring[1]; 248567e6e29Sjimqu WREG32(mmVCE_RB_RPTR2, ring->wptr); 249567e6e29Sjimqu WREG32(mmVCE_RB_WPTR2, ring->wptr); 250567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr); 251567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); 252567e6e29Sjimqu WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4); 253aaa36a97SAlex Deucher 2545bbc553aSLeo Liu mutex_lock(&adev->grbm_idx_mutex); 2555bbc553aSLeo Liu for (idx = 0; idx < 2; ++idx) { 2566a585777SAlex Deucher if (adev->vce.harvest_config & (1 << idx)) 2576a585777SAlex Deucher continue; 2586a585777SAlex Deucher 2595bbc553aSLeo Liu if (idx == 0) 2605bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 0, 2615bbc553aSLeo Liu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2625bbc553aSLeo Liu else 2635bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 2645bbc553aSLeo Liu GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 2655bbc553aSLeo Liu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2665bbc553aSLeo Liu 2675bbc553aSLeo Liu vce_v3_0_mc_resume(adev, idx); 268aaa36a97SAlex Deucher 269567e6e29Sjimqu WREG32_P(mmVCE_STATUS, VCE_STATUS__JOB_BUSY_MASK, 270567e6e29Sjimqu ~VCE_STATUS__JOB_BUSY_MASK); 271567e6e29Sjimqu 2723c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) 2733c0ff9f1SLeo Liu WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001); 2743c0ff9f1SLeo Liu else 2755bbc553aSLeo Liu WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, 2765bbc553aSLeo Liu ~VCE_VCPU_CNTL__CLK_EN_MASK); 277aaa36a97SAlex Deucher 278567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 0, 279aaa36a97SAlex Deucher ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 280aaa36a97SAlex Deucher 281aaa36a97SAlex Deucher mdelay(100); 282aaa36a97SAlex Deucher 283567e6e29Sjimqu r = vce_v3_0_firmware_loaded(adev); 284aaa36a97SAlex Deucher 285aaa36a97SAlex Deucher /* clear BUSY flag */ 286567e6e29Sjimqu WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK); 287aaa36a97SAlex Deucher 2880689a570SEric Huang /* Set Clock-Gating off */ 289e3b04bc7SAlex Deucher if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) 2900689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, false); 2910689a570SEric Huang 292aaa36a97SAlex Deucher if (r) { 293aaa36a97SAlex Deucher DRM_ERROR("VCE not responding, giving up!!!\n"); 2945bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 295aaa36a97SAlex Deucher return r; 296aaa36a97SAlex Deucher } 2975bbc553aSLeo Liu } 2985bbc553aSLeo Liu 2995bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 3005bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 3015bbc553aSLeo Liu 302567e6e29Sjimqu return 0; 303567e6e29Sjimqu } 3045bbc553aSLeo Liu 305567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev) 306567e6e29Sjimqu { 307567e6e29Sjimqu int idx; 308567e6e29Sjimqu 309567e6e29Sjimqu mutex_lock(&adev->grbm_idx_mutex); 310567e6e29Sjimqu for (idx = 0; idx < 2; ++idx) { 311567e6e29Sjimqu if (adev->vce.harvest_config & (1 << idx)) 312567e6e29Sjimqu continue; 313567e6e29Sjimqu 314567e6e29Sjimqu if (idx == 0) 315567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 0, 316567e6e29Sjimqu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 317567e6e29Sjimqu else 318567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 319567e6e29Sjimqu GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 320567e6e29Sjimqu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 321567e6e29Sjimqu 322567e6e29Sjimqu if (adev->asic_type >= CHIP_STONEY) 323567e6e29Sjimqu WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001); 324567e6e29Sjimqu else 325567e6e29Sjimqu WREG32_P(mmVCE_VCPU_CNTL, 0, 326567e6e29Sjimqu ~VCE_VCPU_CNTL__CLK_EN_MASK); 327567e6e29Sjimqu /* hold on ECPU */ 328567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 329567e6e29Sjimqu VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, 330567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 331567e6e29Sjimqu 332567e6e29Sjimqu /* clear BUSY flag */ 333567e6e29Sjimqu WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK); 334567e6e29Sjimqu 335567e6e29Sjimqu /* Set Clock-Gating off */ 336567e6e29Sjimqu if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) 337567e6e29Sjimqu vce_v3_0_set_vce_sw_clock_gating(adev, false); 338567e6e29Sjimqu } 339567e6e29Sjimqu 340567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 341567e6e29Sjimqu mutex_unlock(&adev->grbm_idx_mutex); 342aaa36a97SAlex Deucher 343aaa36a97SAlex Deucher return 0; 344aaa36a97SAlex Deucher } 345aaa36a97SAlex Deucher 3466a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS 0xC0014074 3476a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT 27 3486a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK 0x18000000 3496a585777SAlex Deucher 3506a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) 3516a585777SAlex Deucher { 3526a585777SAlex Deucher u32 tmp; 3536a585777SAlex Deucher 3542cc0c0b5SFlora Cui /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */ 355cfaba566SSamuel Li if ((adev->asic_type == CHIP_FIJI) || 3561b4eeea5SSonny Jiang (adev->asic_type == CHIP_STONEY) || 3572cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS10) || 3582cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS11)) 3591dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 360188a9bcdSAlex Deucher 361188a9bcdSAlex Deucher /* Tonga and CZ are dual or single pipe */ 3622f7d10b3SJammy Zhou if (adev->flags & AMD_IS_APU) 3636a585777SAlex Deucher tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) & 3646a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__MASK) >> 3656a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__SHIFT; 3666a585777SAlex Deucher else 3676a585777SAlex Deucher tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) & 3686a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE_MASK) >> 3696a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE__SHIFT; 3706a585777SAlex Deucher 3716a585777SAlex Deucher switch (tmp) { 3726a585777SAlex Deucher case 1: 3731dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0; 3746a585777SAlex Deucher case 2: 3751dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 3766a585777SAlex Deucher case 3: 3771dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1; 3786a585777SAlex Deucher default: 3791dab5f06STom St Denis return 0; 3806a585777SAlex Deucher } 3816a585777SAlex Deucher } 3826a585777SAlex Deucher 3835fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle) 384aaa36a97SAlex Deucher { 3855fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 3865fc3aeebSyanyang1 3876a585777SAlex Deucher adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); 3886a585777SAlex Deucher 3896a585777SAlex Deucher if ((adev->vce.harvest_config & 3906a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) == 3916a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 3926a585777SAlex Deucher return -ENOENT; 3936a585777SAlex Deucher 394aaa36a97SAlex Deucher vce_v3_0_set_ring_funcs(adev); 395aaa36a97SAlex Deucher vce_v3_0_set_irq_funcs(adev); 396aaa36a97SAlex Deucher 397aaa36a97SAlex Deucher return 0; 398aaa36a97SAlex Deucher } 399aaa36a97SAlex Deucher 4005fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle) 401aaa36a97SAlex Deucher { 4025fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 403aaa36a97SAlex Deucher struct amdgpu_ring *ring; 404aaa36a97SAlex Deucher int r; 405aaa36a97SAlex Deucher 406aaa36a97SAlex Deucher /* VCE */ 407aaa36a97SAlex Deucher r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq); 408aaa36a97SAlex Deucher if (r) 409aaa36a97SAlex Deucher return r; 410aaa36a97SAlex Deucher 411e9822622SLeo Liu r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE + 412e9822622SLeo Liu (VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2); 413aaa36a97SAlex Deucher if (r) 414aaa36a97SAlex Deucher return r; 415aaa36a97SAlex Deucher 416aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 417aaa36a97SAlex Deucher if (r) 418aaa36a97SAlex Deucher return r; 419aaa36a97SAlex Deucher 420aaa36a97SAlex Deucher ring = &adev->vce.ring[0]; 421aaa36a97SAlex Deucher sprintf(ring->name, "vce0"); 422a3f1cf35SChristian König r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf, 423aaa36a97SAlex Deucher &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); 424aaa36a97SAlex Deucher if (r) 425aaa36a97SAlex Deucher return r; 426aaa36a97SAlex Deucher 427aaa36a97SAlex Deucher ring = &adev->vce.ring[1]; 428aaa36a97SAlex Deucher sprintf(ring->name, "vce1"); 429a3f1cf35SChristian König r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf, 430aaa36a97SAlex Deucher &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); 431aaa36a97SAlex Deucher if (r) 432aaa36a97SAlex Deucher return r; 433aaa36a97SAlex Deucher 434aaa36a97SAlex Deucher return r; 435aaa36a97SAlex Deucher } 436aaa36a97SAlex Deucher 4375fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle) 438aaa36a97SAlex Deucher { 439aaa36a97SAlex Deucher int r; 4405fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 441aaa36a97SAlex Deucher 442aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 443aaa36a97SAlex Deucher if (r) 444aaa36a97SAlex Deucher return r; 445aaa36a97SAlex Deucher 446aaa36a97SAlex Deucher r = amdgpu_vce_sw_fini(adev); 447aaa36a97SAlex Deucher if (r) 448aaa36a97SAlex Deucher return r; 449aaa36a97SAlex Deucher 450aaa36a97SAlex Deucher return r; 451aaa36a97SAlex Deucher } 452aaa36a97SAlex Deucher 4535fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle) 454aaa36a97SAlex Deucher { 455691ca86aSTom St Denis int r, i; 4565fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 457aaa36a97SAlex Deucher 458aaa36a97SAlex Deucher r = vce_v3_0_start(adev); 459aaa36a97SAlex Deucher if (r) 460aaa36a97SAlex Deucher return r; 461aaa36a97SAlex Deucher 462691ca86aSTom St Denis adev->vce.ring[0].ready = false; 463691ca86aSTom St Denis adev->vce.ring[1].ready = false; 464aaa36a97SAlex Deucher 465691ca86aSTom St Denis for (i = 0; i < 2; i++) { 466691ca86aSTom St Denis r = amdgpu_ring_test_ring(&adev->vce.ring[i]); 467691ca86aSTom St Denis if (r) 468aaa36a97SAlex Deucher return r; 469691ca86aSTom St Denis else 470691ca86aSTom St Denis adev->vce.ring[i].ready = true; 471aaa36a97SAlex Deucher } 472aaa36a97SAlex Deucher 473aaa36a97SAlex Deucher DRM_INFO("VCE initialized successfully.\n"); 474aaa36a97SAlex Deucher 475aaa36a97SAlex Deucher return 0; 476aaa36a97SAlex Deucher } 477aaa36a97SAlex Deucher 4785fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle) 479aaa36a97SAlex Deucher { 480567e6e29Sjimqu int r; 481567e6e29Sjimqu struct amdgpu_device *adev = (struct amdgpu_device *)handle; 482567e6e29Sjimqu 483567e6e29Sjimqu r = vce_v3_0_wait_for_idle(handle); 484567e6e29Sjimqu if (r) 485567e6e29Sjimqu return r; 486567e6e29Sjimqu 487567e6e29Sjimqu return vce_v3_0_stop(adev); 488aaa36a97SAlex Deucher } 489aaa36a97SAlex Deucher 4905fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle) 491aaa36a97SAlex Deucher { 492aaa36a97SAlex Deucher int r; 4935fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 494aaa36a97SAlex Deucher 495aaa36a97SAlex Deucher r = vce_v3_0_hw_fini(adev); 496aaa36a97SAlex Deucher if (r) 497aaa36a97SAlex Deucher return r; 498aaa36a97SAlex Deucher 499aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 500aaa36a97SAlex Deucher if (r) 501aaa36a97SAlex Deucher return r; 502aaa36a97SAlex Deucher 503aaa36a97SAlex Deucher return r; 504aaa36a97SAlex Deucher } 505aaa36a97SAlex Deucher 5065fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle) 507aaa36a97SAlex Deucher { 508aaa36a97SAlex Deucher int r; 5095fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 510aaa36a97SAlex Deucher 511aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 512aaa36a97SAlex Deucher if (r) 513aaa36a97SAlex Deucher return r; 514aaa36a97SAlex Deucher 515aaa36a97SAlex Deucher r = vce_v3_0_hw_init(adev); 516aaa36a97SAlex Deucher if (r) 517aaa36a97SAlex Deucher return r; 518aaa36a97SAlex Deucher 519aaa36a97SAlex Deucher return r; 520aaa36a97SAlex Deucher } 521aaa36a97SAlex Deucher 5225bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) 523aaa36a97SAlex Deucher { 524aaa36a97SAlex Deucher uint32_t offset, size; 525aaa36a97SAlex Deucher 526aaa36a97SAlex Deucher WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16)); 527aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); 528aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); 5296f906814STom St Denis WREG32(mmVCE_CLOCK_GATING_B, 0x1FF); 530aaa36a97SAlex Deucher 531aaa36a97SAlex Deucher WREG32(mmVCE_LMI_CTRL, 0x00398000); 532aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1); 533aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL, 0); 534aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL1, 0); 535aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VM_CTRL, 0); 5363c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) { 5373c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8)); 5383c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8)); 5393c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8)); 5403c0ff9f1SLeo Liu } else 541aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8)); 542aaa36a97SAlex Deucher offset = AMDGPU_VCE_FIRMWARE_OFFSET; 543e9822622SLeo Liu size = VCE_V3_0_FW_SIZE; 544aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff); 545aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE0, size); 546aaa36a97SAlex Deucher 5475bbc553aSLeo Liu if (idx == 0) { 548aaa36a97SAlex Deucher offset += size; 549e9822622SLeo Liu size = VCE_V3_0_STACK_SIZE; 550aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff); 551aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 552aaa36a97SAlex Deucher offset += size; 553e9822622SLeo Liu size = VCE_V3_0_DATA_SIZE; 554aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff); 555aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5565bbc553aSLeo Liu } else { 5575bbc553aSLeo Liu offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE; 5585bbc553aSLeo Liu size = VCE_V3_0_STACK_SIZE; 5595bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff); 5605bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 5615bbc553aSLeo Liu offset += size; 5625bbc553aSLeo Liu size = VCE_V3_0_DATA_SIZE; 5635bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff); 5645bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5655bbc553aSLeo Liu } 566aaa36a97SAlex Deucher 567aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); 568aaa36a97SAlex Deucher 569aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK, 570aaa36a97SAlex Deucher ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 571aaa36a97SAlex Deucher } 572aaa36a97SAlex Deucher 5735fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle) 574aaa36a97SAlex Deucher { 5755fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 576be4f38e2SAlex Deucher u32 mask = 0; 5775fc3aeebSyanyang1 57874af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK; 57974af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK; 580be4f38e2SAlex Deucher 581be4f38e2SAlex Deucher return !(RREG32(mmSRBM_STATUS2) & mask); 582aaa36a97SAlex Deucher } 583aaa36a97SAlex Deucher 5845fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle) 585aaa36a97SAlex Deucher { 586aaa36a97SAlex Deucher unsigned i; 5875fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 588be4f38e2SAlex Deucher 58992988e60STom St Denis for (i = 0; i < adev->usec_timeout; i++) 59092988e60STom St Denis if (vce_v3_0_is_idle(handle)) 591aaa36a97SAlex Deucher return 0; 59292988e60STom St Denis 593aaa36a97SAlex Deucher return -ETIMEDOUT; 594aaa36a97SAlex Deucher } 595aaa36a97SAlex Deucher 596115933a5SChunming Zhou #define AMDGPU_VCE_STATUS_BUSY_MASK 0x78 597115933a5SChunming Zhou 598115933a5SChunming Zhou static int vce_v3_0_check_soft_reset(void *handle) 599115933a5SChunming Zhou { 600115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 601115933a5SChunming Zhou u32 srbm_soft_reset = 0; 602115933a5SChunming Zhou u32 tmp; 603115933a5SChunming Zhou 604115933a5SChunming Zhou /* VCE BUG: it is always busy, so skip its checking now */ 605115933a5SChunming Zhou return 0; 606115933a5SChunming Zhou 607115933a5SChunming Zhou /* According to VCE team , we should use VCE_STATUS instead 608115933a5SChunming Zhou * SRBM_STATUS.VCE_BUSY bit for busy status checking. 609115933a5SChunming Zhou * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE 610115933a5SChunming Zhou * instance's registers are accessed 611115933a5SChunming Zhou * (0 for 1st instance, 10 for 2nd instance). 612115933a5SChunming Zhou * 613115933a5SChunming Zhou *VCE_STATUS 614115933a5SChunming Zhou *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 | |FW_LOADED|JOB | 615115933a5SChunming Zhou *|----+----+-----------+----+----+----+----------+---------+----| 616115933a5SChunming Zhou *|bit8|bit7| bit6 |bit5|bit4|bit3| bit2 | bit1 |bit0| 617115933a5SChunming Zhou * 618115933a5SChunming Zhou * VCE team suggest use bit 3--bit 6 for busy status check 619115933a5SChunming Zhou */ 620115933a5SChunming Zhou tmp = RREG32(mmGRBM_GFX_INDEX); 621115933a5SChunming Zhou tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 622115933a5SChunming Zhou WREG32(mmGRBM_GFX_INDEX, tmp); 623115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 624115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 625115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 626115933a5SChunming Zhou } 627115933a5SChunming Zhou tmp = RREG32(mmGRBM_GFX_INDEX); 628115933a5SChunming Zhou tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10); 629115933a5SChunming Zhou WREG32(mmGRBM_GFX_INDEX, tmp); 630115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 631115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 632115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 633115933a5SChunming Zhou } 634115933a5SChunming Zhou tmp = RREG32(mmGRBM_GFX_INDEX); 635115933a5SChunming Zhou tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 636115933a5SChunming Zhou WREG32(mmGRBM_GFX_INDEX, tmp); 637115933a5SChunming Zhou 638115933a5SChunming Zhou if (adev->vce.harvest_config & (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 639115933a5SChunming Zhou srbm_soft_reset = 0; 640115933a5SChunming Zhou 641115933a5SChunming Zhou if (srbm_soft_reset) { 642115933a5SChunming Zhou adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = true; 643115933a5SChunming Zhou adev->vce.srbm_soft_reset = srbm_soft_reset; 644115933a5SChunming Zhou } else { 645115933a5SChunming Zhou adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = false; 646115933a5SChunming Zhou adev->vce.srbm_soft_reset = 0; 647115933a5SChunming Zhou } 648115933a5SChunming Zhou return 0; 649115933a5SChunming Zhou } 650115933a5SChunming Zhou 6515fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle) 652aaa36a97SAlex Deucher { 6535fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 654115933a5SChunming Zhou u32 srbm_soft_reset; 6555fc3aeebSyanyang1 656115933a5SChunming Zhou if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) 657115933a5SChunming Zhou return 0; 658115933a5SChunming Zhou srbm_soft_reset = adev->vce.srbm_soft_reset; 659be4f38e2SAlex Deucher 660115933a5SChunming Zhou if (srbm_soft_reset) { 661115933a5SChunming Zhou u32 tmp; 662115933a5SChunming Zhou 663115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 664115933a5SChunming Zhou tmp |= srbm_soft_reset; 665115933a5SChunming Zhou dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); 666115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 667115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 668115933a5SChunming Zhou 669115933a5SChunming Zhou udelay(50); 670115933a5SChunming Zhou 671115933a5SChunming Zhou tmp &= ~srbm_soft_reset; 672115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 673115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 674115933a5SChunming Zhou 675115933a5SChunming Zhou /* Wait a little for things to settle down */ 676115933a5SChunming Zhou udelay(50); 677115933a5SChunming Zhou } 678115933a5SChunming Zhou 679115933a5SChunming Zhou return 0; 680115933a5SChunming Zhou } 681115933a5SChunming Zhou 682115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle) 683115933a5SChunming Zhou { 684115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 685115933a5SChunming Zhou 686115933a5SChunming Zhou if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) 687115933a5SChunming Zhou return 0; 688115933a5SChunming Zhou 689aaa36a97SAlex Deucher mdelay(5); 690aaa36a97SAlex Deucher 691115933a5SChunming Zhou return vce_v3_0_suspend(adev); 692115933a5SChunming Zhou } 693115933a5SChunming Zhou 694115933a5SChunming Zhou 695115933a5SChunming Zhou static int vce_v3_0_post_soft_reset(void *handle) 696115933a5SChunming Zhou { 697115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 698115933a5SChunming Zhou 699115933a5SChunming Zhou if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) 700115933a5SChunming Zhou return 0; 701115933a5SChunming Zhou 702115933a5SChunming Zhou mdelay(5); 703115933a5SChunming Zhou 704115933a5SChunming Zhou return vce_v3_0_resume(adev); 705aaa36a97SAlex Deucher } 706aaa36a97SAlex Deucher 707aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, 708aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 709aaa36a97SAlex Deucher unsigned type, 710aaa36a97SAlex Deucher enum amdgpu_interrupt_state state) 711aaa36a97SAlex Deucher { 712aaa36a97SAlex Deucher uint32_t val = 0; 713aaa36a97SAlex Deucher 714aaa36a97SAlex Deucher if (state == AMDGPU_IRQ_STATE_ENABLE) 715aaa36a97SAlex Deucher val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK; 716aaa36a97SAlex Deucher 717aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 718aaa36a97SAlex Deucher return 0; 719aaa36a97SAlex Deucher } 720aaa36a97SAlex Deucher 721aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev, 722aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 723aaa36a97SAlex Deucher struct amdgpu_iv_entry *entry) 724aaa36a97SAlex Deucher { 725aaa36a97SAlex Deucher DRM_DEBUG("IH: VCE\n"); 726d6c29c30SLeo Liu 727d6c29c30SLeo Liu WREG32_P(mmVCE_SYS_INT_STATUS, 728d6c29c30SLeo Liu VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK, 729d6c29c30SLeo Liu ~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK); 730d6c29c30SLeo Liu 731aaa36a97SAlex Deucher switch (entry->src_data) { 732aaa36a97SAlex Deucher case 0: 733aaa36a97SAlex Deucher case 1: 73481da2edeSTom St Denis amdgpu_fence_process(&adev->vce.ring[entry->src_data]); 735aaa36a97SAlex Deucher break; 736aaa36a97SAlex Deucher default: 737aaa36a97SAlex Deucher DRM_ERROR("Unhandled interrupt: %d %d\n", 738aaa36a97SAlex Deucher entry->src_id, entry->src_data); 739aaa36a97SAlex Deucher break; 740aaa36a97SAlex Deucher } 741aaa36a97SAlex Deucher 742aaa36a97SAlex Deucher return 0; 743aaa36a97SAlex Deucher } 744aaa36a97SAlex Deucher 745ec38f188SRex Zhu static void vce_v3_set_bypass_mode(struct amdgpu_device *adev, bool enable) 746ec38f188SRex Zhu { 747ec38f188SRex Zhu u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL); 748ec38f188SRex Zhu 749ec38f188SRex Zhu if (enable) 750ec38f188SRex Zhu tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 751ec38f188SRex Zhu else 752ec38f188SRex Zhu tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 753ec38f188SRex Zhu 754ec38f188SRex Zhu WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp); 755ec38f188SRex Zhu } 756ec38f188SRex Zhu 7575fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle, 7585fc3aeebSyanyang1 enum amd_clockgating_state state) 759aaa36a97SAlex Deucher { 7600689a570SEric Huang struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7610689a570SEric Huang bool enable = (state == AMD_CG_STATE_GATE) ? true : false; 7620689a570SEric Huang int i; 7630689a570SEric Huang 764ec38f188SRex Zhu if (adev->asic_type == CHIP_POLARIS10) 765ec38f188SRex Zhu vce_v3_set_bypass_mode(adev, enable); 766ec38f188SRex Zhu 767e3b04bc7SAlex Deucher if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) 7680689a570SEric Huang return 0; 7690689a570SEric Huang 7700689a570SEric Huang mutex_lock(&adev->grbm_idx_mutex); 7710689a570SEric Huang for (i = 0; i < 2; i++) { 7720689a570SEric Huang /* Program VCE Instance 0 or 1 if not harvested */ 7730689a570SEric Huang if (adev->vce.harvest_config & (1 << i)) 7740689a570SEric Huang continue; 7750689a570SEric Huang 7760689a570SEric Huang if (i == 0) 7770689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 0, 7780689a570SEric Huang ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 7790689a570SEric Huang else 7800689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 7810689a570SEric Huang GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 7820689a570SEric Huang ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 7830689a570SEric Huang 7840689a570SEric Huang if (enable) { 7850689a570SEric Huang /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ 7860689a570SEric Huang uint32_t data = RREG32(mmVCE_CLOCK_GATING_A); 7870689a570SEric Huang data &= ~(0xf | 0xff0); 7880689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7890689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_A, data); 7900689a570SEric Huang 7910689a570SEric Huang /* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */ 7920689a570SEric Huang data = RREG32(mmVCE_UENC_CLOCK_GATING); 7930689a570SEric Huang data &= ~(0xf | 0xff0); 7940689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7950689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 7960689a570SEric Huang } 7970689a570SEric Huang 7980689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, enable); 7990689a570SEric Huang } 8000689a570SEric Huang 8010689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 8020689a570SEric Huang mutex_unlock(&adev->grbm_idx_mutex); 8030689a570SEric Huang 804aaa36a97SAlex Deucher return 0; 805aaa36a97SAlex Deucher } 806aaa36a97SAlex Deucher 8075fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle, 8085fc3aeebSyanyang1 enum amd_powergating_state state) 809aaa36a97SAlex Deucher { 810aaa36a97SAlex Deucher /* This doesn't actually powergate the VCE block. 811aaa36a97SAlex Deucher * That's done in the dpm code via the SMC. This 812aaa36a97SAlex Deucher * just re-inits the block as necessary. The actual 813aaa36a97SAlex Deucher * gating still happens in the dpm code. We should 814aaa36a97SAlex Deucher * revisit this when there is a cleaner line between 815aaa36a97SAlex Deucher * the smc and the hw blocks 816aaa36a97SAlex Deucher */ 8175fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 8185fc3aeebSyanyang1 819e3b04bc7SAlex Deucher if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE)) 820808a934fSAlex Deucher return 0; 821808a934fSAlex Deucher 8225fc3aeebSyanyang1 if (state == AMD_PG_STATE_GATE) 823aaa36a97SAlex Deucher /* XXX do we need a vce_v3_0_stop()? */ 824aaa36a97SAlex Deucher return 0; 825aaa36a97SAlex Deucher else 826aaa36a97SAlex Deucher return vce_v3_0_start(adev); 827aaa36a97SAlex Deucher } 828aaa36a97SAlex Deucher 8295fc3aeebSyanyang1 const struct amd_ip_funcs vce_v3_0_ip_funcs = { 83088a907d6STom St Denis .name = "vce_v3_0", 831aaa36a97SAlex Deucher .early_init = vce_v3_0_early_init, 832aaa36a97SAlex Deucher .late_init = NULL, 833aaa36a97SAlex Deucher .sw_init = vce_v3_0_sw_init, 834aaa36a97SAlex Deucher .sw_fini = vce_v3_0_sw_fini, 835aaa36a97SAlex Deucher .hw_init = vce_v3_0_hw_init, 836aaa36a97SAlex Deucher .hw_fini = vce_v3_0_hw_fini, 837aaa36a97SAlex Deucher .suspend = vce_v3_0_suspend, 838aaa36a97SAlex Deucher .resume = vce_v3_0_resume, 839aaa36a97SAlex Deucher .is_idle = vce_v3_0_is_idle, 840aaa36a97SAlex Deucher .wait_for_idle = vce_v3_0_wait_for_idle, 841115933a5SChunming Zhou .check_soft_reset = vce_v3_0_check_soft_reset, 842115933a5SChunming Zhou .pre_soft_reset = vce_v3_0_pre_soft_reset, 843aaa36a97SAlex Deucher .soft_reset = vce_v3_0_soft_reset, 844115933a5SChunming Zhou .post_soft_reset = vce_v3_0_post_soft_reset, 845aaa36a97SAlex Deucher .set_clockgating_state = vce_v3_0_set_clockgating_state, 846aaa36a97SAlex Deucher .set_powergating_state = vce_v3_0_set_powergating_state, 847aaa36a97SAlex Deucher }; 848aaa36a97SAlex Deucher 849aaa36a97SAlex Deucher static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = { 850aaa36a97SAlex Deucher .get_rptr = vce_v3_0_ring_get_rptr, 851aaa36a97SAlex Deucher .get_wptr = vce_v3_0_ring_get_wptr, 852aaa36a97SAlex Deucher .set_wptr = vce_v3_0_ring_set_wptr, 853aaa36a97SAlex Deucher .parse_cs = amdgpu_vce_ring_parse_cs, 854aaa36a97SAlex Deucher .emit_ib = amdgpu_vce_ring_emit_ib, 855aaa36a97SAlex Deucher .emit_fence = amdgpu_vce_ring_emit_fence, 856aaa36a97SAlex Deucher .test_ring = amdgpu_vce_ring_test_ring, 857aaa36a97SAlex Deucher .test_ib = amdgpu_vce_ring_test_ib, 858edff0e28SJammy Zhou .insert_nop = amdgpu_ring_insert_nop, 8599e5d5309SChristian König .pad_ib = amdgpu_ring_generic_pad_ib, 860ebff485eSChristian König .begin_use = amdgpu_vce_ring_begin_use, 861ebff485eSChristian König .end_use = amdgpu_vce_ring_end_use, 862aaa36a97SAlex Deucher }; 863aaa36a97SAlex Deucher 864aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) 865aaa36a97SAlex Deucher { 866aaa36a97SAlex Deucher adev->vce.ring[0].funcs = &vce_v3_0_ring_funcs; 867aaa36a97SAlex Deucher adev->vce.ring[1].funcs = &vce_v3_0_ring_funcs; 868aaa36a97SAlex Deucher } 869aaa36a97SAlex Deucher 870aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = { 871aaa36a97SAlex Deucher .set = vce_v3_0_set_interrupt_state, 872aaa36a97SAlex Deucher .process = vce_v3_0_process_interrupt, 873aaa36a97SAlex Deucher }; 874aaa36a97SAlex Deucher 875aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev) 876aaa36a97SAlex Deucher { 877aaa36a97SAlex Deucher adev->vce.irq.num_types = 1; 878aaa36a97SAlex Deucher adev->vce.irq.funcs = &vce_v3_0_irq_funcs; 879aaa36a97SAlex Deucher }; 880