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" 405bbc553aSLeo Liu 415bbc553aSLeo Liu #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04 425bbc553aSLeo Liu #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK 0x10 433c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0 0x8616 443c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1 0x8617 453c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2 0x8618 46567e6e29Sjimqu #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02 47aaa36a97SAlex Deucher 48e9822622SLeo Liu #define VCE_V3_0_FW_SIZE (384 * 1024) 49e9822622SLeo Liu #define VCE_V3_0_STACK_SIZE (64 * 1024) 50e9822622SLeo Liu #define VCE_V3_0_DATA_SIZE ((16 * 1024 * AMDGPU_MAX_VCE_HANDLES) + (52 * 1024)) 51e9822622SLeo Liu 525bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx); 53aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev); 54aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev); 55567e6e29Sjimqu static int vce_v3_0_wait_for_idle(void *handle); 56aaa36a97SAlex Deucher 57aaa36a97SAlex Deucher /** 58aaa36a97SAlex Deucher * vce_v3_0_ring_get_rptr - get read pointer 59aaa36a97SAlex Deucher * 60aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 61aaa36a97SAlex Deucher * 62aaa36a97SAlex Deucher * Returns the current hardware read pointer 63aaa36a97SAlex Deucher */ 64aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring) 65aaa36a97SAlex Deucher { 66aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 67aaa36a97SAlex Deucher 68aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 69aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR); 70aaa36a97SAlex Deucher else 71aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR2); 72aaa36a97SAlex Deucher } 73aaa36a97SAlex Deucher 74aaa36a97SAlex Deucher /** 75aaa36a97SAlex Deucher * vce_v3_0_ring_get_wptr - get write pointer 76aaa36a97SAlex Deucher * 77aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 78aaa36a97SAlex Deucher * 79aaa36a97SAlex Deucher * Returns the current hardware write pointer 80aaa36a97SAlex Deucher */ 81aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring) 82aaa36a97SAlex Deucher { 83aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 84aaa36a97SAlex Deucher 85aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 86aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR); 87aaa36a97SAlex Deucher else 88aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR2); 89aaa36a97SAlex Deucher } 90aaa36a97SAlex Deucher 91aaa36a97SAlex Deucher /** 92aaa36a97SAlex Deucher * vce_v3_0_ring_set_wptr - set write pointer 93aaa36a97SAlex Deucher * 94aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 95aaa36a97SAlex Deucher * 96aaa36a97SAlex Deucher * Commits the write pointer to the hardware 97aaa36a97SAlex Deucher */ 98aaa36a97SAlex Deucher static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring) 99aaa36a97SAlex Deucher { 100aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 101aaa36a97SAlex Deucher 102aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 103aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR, ring->wptr); 104aaa36a97SAlex Deucher else 105aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR2, ring->wptr); 106aaa36a97SAlex Deucher } 107aaa36a97SAlex Deucher 1080689a570SEric Huang static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override) 1090689a570SEric Huang { 1100689a570SEric Huang u32 tmp, data; 1110689a570SEric Huang 1120689a570SEric Huang tmp = data = RREG32(mmVCE_RB_ARB_CTRL); 1130689a570SEric Huang if (override) 1140689a570SEric Huang data |= VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; 1150689a570SEric Huang else 1160689a570SEric Huang data &= ~VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; 1170689a570SEric Huang 1180689a570SEric Huang if (tmp != data) 1190689a570SEric Huang WREG32(mmVCE_RB_ARB_CTRL, data); 1200689a570SEric Huang } 1210689a570SEric Huang 1220689a570SEric Huang static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, 1230689a570SEric Huang bool gated) 1240689a570SEric Huang { 1250689a570SEric Huang u32 tmp, data; 1260689a570SEric Huang /* Set Override to disable Clock Gating */ 1270689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, true); 1280689a570SEric Huang 1290689a570SEric Huang if (!gated) { 1300689a570SEric Huang /* Force CLOCK ON for VCE_CLOCK_GATING_B, 1310689a570SEric Huang * {*_FORCE_ON, *_FORCE_OFF} = {1, 0} 1320689a570SEric Huang * VREG can be FORCE ON or set to Dynamic, but can't be OFF 1330689a570SEric Huang */ 1340689a570SEric Huang tmp = data = RREG32(mmVCE_CLOCK_GATING_B); 1350689a570SEric Huang data |= 0x1ff; 1360689a570SEric Huang data &= ~0xef0000; 1370689a570SEric Huang if (tmp != data) 1380689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1390689a570SEric Huang 1400689a570SEric Huang /* Force CLOCK ON for VCE_UENC_CLOCK_GATING, 1410689a570SEric Huang * {*_FORCE_ON, *_FORCE_OFF} = {1, 0} 1420689a570SEric Huang */ 1430689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); 1440689a570SEric Huang data |= 0x3ff000; 1450689a570SEric Huang data &= ~0xffc00000; 1460689a570SEric Huang if (tmp != data) 1470689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1480689a570SEric Huang 1490689a570SEric Huang /* set VCE_UENC_CLOCK_GATING_2 */ 1500689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1510689a570SEric Huang data |= 0x2; 1520689a570SEric Huang data &= ~0x2; 1530689a570SEric Huang if (tmp != data) 1540689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1550689a570SEric Huang 1560689a570SEric Huang /* Force CLOCK ON for VCE_UENC_REG_CLOCK_GATING */ 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 /* Force VCE_UENC_DMA_DCLK_CTRL Clock ON */ 1630689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1640689a570SEric Huang data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1650689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1660689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1670689a570SEric Huang 0x8; 1680689a570SEric Huang if (tmp != data) 1690689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1700689a570SEric Huang } else { 1710689a570SEric Huang /* Force CLOCK OFF for VCE_CLOCK_GATING_B, 1720689a570SEric Huang * {*, *_FORCE_OFF} = {*, 1} 1730689a570SEric Huang * set VREG to Dynamic, as it can't be OFF 1740689a570SEric Huang */ 1750689a570SEric Huang tmp = data = RREG32(mmVCE_CLOCK_GATING_B); 1760689a570SEric Huang data &= ~0x80010; 1770689a570SEric Huang data |= 0xe70008; 1780689a570SEric Huang if (tmp != data) 1790689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1800689a570SEric Huang /* Force CLOCK OFF for VCE_UENC_CLOCK_GATING, 1810689a570SEric Huang * Force ClOCK OFF takes precedent over Force CLOCK ON setting. 1820689a570SEric Huang * {*_FORCE_ON, *_FORCE_OFF} = {*, 1} 1830689a570SEric Huang */ 1840689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); 1850689a570SEric Huang data |= 0xffc00000; 1860689a570SEric Huang if (tmp != data) 1870689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1880689a570SEric Huang /* Set VCE_UENC_CLOCK_GATING_2 */ 1890689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1900689a570SEric Huang data |= 0x10000; 1910689a570SEric Huang if (tmp != data) 1920689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1930689a570SEric Huang /* Set VCE_UENC_REG_CLOCK_GATING to dynamic */ 1940689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1950689a570SEric Huang data &= ~0xffc00000; 1960689a570SEric Huang if (tmp != data) 1970689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1980689a570SEric Huang /* Set VCE_UENC_DMA_DCLK_CTRL CG always in dynamic mode */ 1990689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 2000689a570SEric Huang data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 2010689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 2020689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 2030689a570SEric Huang 0x8); 2040689a570SEric Huang if (tmp != data) 2050689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 2060689a570SEric Huang } 2070689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, false); 2080689a570SEric Huang } 2090689a570SEric Huang 210567e6e29Sjimqu static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev) 211567e6e29Sjimqu { 212567e6e29Sjimqu int i, j; 213567e6e29Sjimqu 214567e6e29Sjimqu for (i = 0; i < 10; ++i) { 215567e6e29Sjimqu for (j = 0; j < 100; ++j) { 216b7e2e9f7Sjimqu uint32_t status = RREG32(mmVCE_STATUS); 217b7e2e9f7Sjimqu 218567e6e29Sjimqu if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK) 219567e6e29Sjimqu return 0; 220567e6e29Sjimqu mdelay(10); 221567e6e29Sjimqu } 222567e6e29Sjimqu 223567e6e29Sjimqu DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); 224567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 225567e6e29Sjimqu VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, 226567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 227567e6e29Sjimqu mdelay(10); 228567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 0, 229567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 230567e6e29Sjimqu mdelay(10); 231567e6e29Sjimqu } 232567e6e29Sjimqu 233567e6e29Sjimqu return -ETIMEDOUT; 234567e6e29Sjimqu } 235567e6e29Sjimqu 236aaa36a97SAlex Deucher /** 237aaa36a97SAlex Deucher * vce_v3_0_start - start VCE block 238aaa36a97SAlex Deucher * 239aaa36a97SAlex Deucher * @adev: amdgpu_device pointer 240aaa36a97SAlex Deucher * 241aaa36a97SAlex Deucher * Setup and start the VCE block 242aaa36a97SAlex Deucher */ 243aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev) 244aaa36a97SAlex Deucher { 245aaa36a97SAlex Deucher struct amdgpu_ring *ring; 246567e6e29Sjimqu int idx, r; 247567e6e29Sjimqu 248567e6e29Sjimqu ring = &adev->vce.ring[0]; 249567e6e29Sjimqu WREG32(mmVCE_RB_RPTR, ring->wptr); 250567e6e29Sjimqu WREG32(mmVCE_RB_WPTR, ring->wptr); 251567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr); 252567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); 253567e6e29Sjimqu WREG32(mmVCE_RB_SIZE, ring->ring_size / 4); 254567e6e29Sjimqu 255567e6e29Sjimqu ring = &adev->vce.ring[1]; 256567e6e29Sjimqu WREG32(mmVCE_RB_RPTR2, ring->wptr); 257567e6e29Sjimqu WREG32(mmVCE_RB_WPTR2, ring->wptr); 258567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr); 259567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); 260567e6e29Sjimqu WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4); 261aaa36a97SAlex Deucher 2625bbc553aSLeo Liu mutex_lock(&adev->grbm_idx_mutex); 2635bbc553aSLeo Liu for (idx = 0; idx < 2; ++idx) { 2646a585777SAlex Deucher if (adev->vce.harvest_config & (1 << idx)) 2656a585777SAlex Deucher continue; 2666a585777SAlex Deucher 2675bbc553aSLeo Liu if (idx == 0) 2685bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 0, 2695bbc553aSLeo Liu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2705bbc553aSLeo Liu else 2715bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 2725bbc553aSLeo Liu GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 2735bbc553aSLeo Liu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2745bbc553aSLeo Liu 2755bbc553aSLeo Liu vce_v3_0_mc_resume(adev, idx); 276aaa36a97SAlex Deucher 277567e6e29Sjimqu WREG32_P(mmVCE_STATUS, VCE_STATUS__JOB_BUSY_MASK, 278567e6e29Sjimqu ~VCE_STATUS__JOB_BUSY_MASK); 279567e6e29Sjimqu 2803c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) 2813c0ff9f1SLeo Liu WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001); 2823c0ff9f1SLeo Liu else 2835bbc553aSLeo Liu WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, 2845bbc553aSLeo Liu ~VCE_VCPU_CNTL__CLK_EN_MASK); 285aaa36a97SAlex Deucher 286567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 0, 287aaa36a97SAlex Deucher ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 288aaa36a97SAlex Deucher 289aaa36a97SAlex Deucher mdelay(100); 290aaa36a97SAlex Deucher 291567e6e29Sjimqu r = vce_v3_0_firmware_loaded(adev); 292aaa36a97SAlex Deucher 293aaa36a97SAlex Deucher /* clear BUSY flag */ 294567e6e29Sjimqu WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK); 295aaa36a97SAlex Deucher 2960689a570SEric Huang /* Set Clock-Gating off */ 297e3b04bc7SAlex Deucher if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) 2980689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, false); 2990689a570SEric Huang 300aaa36a97SAlex Deucher if (r) { 301aaa36a97SAlex Deucher DRM_ERROR("VCE not responding, giving up!!!\n"); 3025bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 303aaa36a97SAlex Deucher return r; 304aaa36a97SAlex Deucher } 3055bbc553aSLeo Liu } 3065bbc553aSLeo Liu 3075bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 3085bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 3095bbc553aSLeo Liu 310567e6e29Sjimqu return 0; 311567e6e29Sjimqu } 3125bbc553aSLeo Liu 313567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev) 314567e6e29Sjimqu { 315567e6e29Sjimqu int idx; 316567e6e29Sjimqu 317567e6e29Sjimqu mutex_lock(&adev->grbm_idx_mutex); 318567e6e29Sjimqu for (idx = 0; idx < 2; ++idx) { 319567e6e29Sjimqu if (adev->vce.harvest_config & (1 << idx)) 320567e6e29Sjimqu continue; 321567e6e29Sjimqu 322567e6e29Sjimqu if (idx == 0) 323567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 0, 324567e6e29Sjimqu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 325567e6e29Sjimqu else 326567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 327567e6e29Sjimqu GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 328567e6e29Sjimqu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 329567e6e29Sjimqu 330567e6e29Sjimqu if (adev->asic_type >= CHIP_STONEY) 331567e6e29Sjimqu WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001); 332567e6e29Sjimqu else 333567e6e29Sjimqu WREG32_P(mmVCE_VCPU_CNTL, 0, 334567e6e29Sjimqu ~VCE_VCPU_CNTL__CLK_EN_MASK); 335567e6e29Sjimqu /* hold on ECPU */ 336567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 337567e6e29Sjimqu VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, 338567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 339567e6e29Sjimqu 340567e6e29Sjimqu /* clear BUSY flag */ 341567e6e29Sjimqu WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK); 342567e6e29Sjimqu 343567e6e29Sjimqu /* Set Clock-Gating off */ 344567e6e29Sjimqu if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) 345567e6e29Sjimqu vce_v3_0_set_vce_sw_clock_gating(adev, false); 346567e6e29Sjimqu } 347567e6e29Sjimqu 348567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 349567e6e29Sjimqu mutex_unlock(&adev->grbm_idx_mutex); 350aaa36a97SAlex Deucher 351aaa36a97SAlex Deucher return 0; 352aaa36a97SAlex Deucher } 353aaa36a97SAlex Deucher 3546a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS 0xC0014074 3556a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT 27 3566a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK 0x18000000 3576a585777SAlex Deucher 3586a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) 3596a585777SAlex Deucher { 3606a585777SAlex Deucher u32 tmp; 3616a585777SAlex Deucher 3622cc0c0b5SFlora Cui /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */ 363cfaba566SSamuel Li if ((adev->asic_type == CHIP_FIJI) || 3641b4eeea5SSonny Jiang (adev->asic_type == CHIP_STONEY) || 3652cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS10) || 3662cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS11)) 3671dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 368188a9bcdSAlex Deucher 369188a9bcdSAlex Deucher /* Tonga and CZ are dual or single pipe */ 3702f7d10b3SJammy Zhou if (adev->flags & AMD_IS_APU) 3716a585777SAlex Deucher tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) & 3726a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__MASK) >> 3736a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__SHIFT; 3746a585777SAlex Deucher else 3756a585777SAlex Deucher tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) & 3766a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE_MASK) >> 3776a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE__SHIFT; 3786a585777SAlex Deucher 3796a585777SAlex Deucher switch (tmp) { 3806a585777SAlex Deucher case 1: 3811dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0; 3826a585777SAlex Deucher case 2: 3831dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 3846a585777SAlex Deucher case 3: 3851dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1; 3866a585777SAlex Deucher default: 3871dab5f06STom St Denis return 0; 3886a585777SAlex Deucher } 3896a585777SAlex Deucher } 3906a585777SAlex Deucher 3915fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle) 392aaa36a97SAlex Deucher { 3935fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 3945fc3aeebSyanyang1 3956a585777SAlex Deucher adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); 3966a585777SAlex Deucher 3976a585777SAlex Deucher if ((adev->vce.harvest_config & 3986a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) == 3996a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 4006a585777SAlex Deucher return -ENOENT; 4016a585777SAlex Deucher 402aaa36a97SAlex Deucher vce_v3_0_set_ring_funcs(adev); 403aaa36a97SAlex Deucher vce_v3_0_set_irq_funcs(adev); 404aaa36a97SAlex Deucher 405aaa36a97SAlex Deucher return 0; 406aaa36a97SAlex Deucher } 407aaa36a97SAlex Deucher 4085fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle) 409aaa36a97SAlex Deucher { 4105fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 411aaa36a97SAlex Deucher struct amdgpu_ring *ring; 412aaa36a97SAlex Deucher int r; 413aaa36a97SAlex Deucher 414aaa36a97SAlex Deucher /* VCE */ 415aaa36a97SAlex Deucher r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq); 416aaa36a97SAlex Deucher if (r) 417aaa36a97SAlex Deucher return r; 418aaa36a97SAlex Deucher 419e9822622SLeo Liu r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE + 420e9822622SLeo Liu (VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2); 421aaa36a97SAlex Deucher if (r) 422aaa36a97SAlex Deucher return r; 423aaa36a97SAlex Deucher 424aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 425aaa36a97SAlex Deucher if (r) 426aaa36a97SAlex Deucher return r; 427aaa36a97SAlex Deucher 428aaa36a97SAlex Deucher ring = &adev->vce.ring[0]; 429aaa36a97SAlex Deucher sprintf(ring->name, "vce0"); 430a3f1cf35SChristian König r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf, 431aaa36a97SAlex Deucher &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); 432aaa36a97SAlex Deucher if (r) 433aaa36a97SAlex Deucher return r; 434aaa36a97SAlex Deucher 435aaa36a97SAlex Deucher ring = &adev->vce.ring[1]; 436aaa36a97SAlex Deucher sprintf(ring->name, "vce1"); 437a3f1cf35SChristian König r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf, 438aaa36a97SAlex Deucher &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); 439aaa36a97SAlex Deucher if (r) 440aaa36a97SAlex Deucher return r; 441aaa36a97SAlex Deucher 442aaa36a97SAlex Deucher return r; 443aaa36a97SAlex Deucher } 444aaa36a97SAlex Deucher 4455fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle) 446aaa36a97SAlex Deucher { 447aaa36a97SAlex Deucher int r; 4485fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 449aaa36a97SAlex Deucher 450aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 451aaa36a97SAlex Deucher if (r) 452aaa36a97SAlex Deucher return r; 453aaa36a97SAlex Deucher 454aaa36a97SAlex Deucher r = amdgpu_vce_sw_fini(adev); 455aaa36a97SAlex Deucher if (r) 456aaa36a97SAlex Deucher return r; 457aaa36a97SAlex Deucher 458aaa36a97SAlex Deucher return r; 459aaa36a97SAlex Deucher } 460aaa36a97SAlex Deucher 4615fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle) 462aaa36a97SAlex Deucher { 463691ca86aSTom St Denis int r, i; 4645fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 465aaa36a97SAlex Deucher 466aaa36a97SAlex Deucher r = vce_v3_0_start(adev); 467aaa36a97SAlex Deucher if (r) 468aaa36a97SAlex Deucher return r; 469aaa36a97SAlex Deucher 470691ca86aSTom St Denis adev->vce.ring[0].ready = false; 471691ca86aSTom St Denis adev->vce.ring[1].ready = false; 472aaa36a97SAlex Deucher 473691ca86aSTom St Denis for (i = 0; i < 2; i++) { 474691ca86aSTom St Denis r = amdgpu_ring_test_ring(&adev->vce.ring[i]); 475691ca86aSTom St Denis if (r) 476aaa36a97SAlex Deucher return r; 477691ca86aSTom St Denis else 478691ca86aSTom St Denis adev->vce.ring[i].ready = true; 479aaa36a97SAlex Deucher } 480aaa36a97SAlex Deucher 481aaa36a97SAlex Deucher DRM_INFO("VCE initialized successfully.\n"); 482aaa36a97SAlex Deucher 483aaa36a97SAlex Deucher return 0; 484aaa36a97SAlex Deucher } 485aaa36a97SAlex Deucher 4865fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle) 487aaa36a97SAlex Deucher { 488567e6e29Sjimqu int r; 489567e6e29Sjimqu struct amdgpu_device *adev = (struct amdgpu_device *)handle; 490567e6e29Sjimqu 491567e6e29Sjimqu r = vce_v3_0_wait_for_idle(handle); 492567e6e29Sjimqu if (r) 493567e6e29Sjimqu return r; 494567e6e29Sjimqu 495567e6e29Sjimqu return vce_v3_0_stop(adev); 496aaa36a97SAlex Deucher } 497aaa36a97SAlex Deucher 4985fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle) 499aaa36a97SAlex Deucher { 500aaa36a97SAlex Deucher int r; 5015fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 502aaa36a97SAlex Deucher 503aaa36a97SAlex Deucher r = vce_v3_0_hw_fini(adev); 504aaa36a97SAlex Deucher if (r) 505aaa36a97SAlex Deucher return r; 506aaa36a97SAlex Deucher 507aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 508aaa36a97SAlex Deucher if (r) 509aaa36a97SAlex Deucher return r; 510aaa36a97SAlex Deucher 511aaa36a97SAlex Deucher return r; 512aaa36a97SAlex Deucher } 513aaa36a97SAlex Deucher 5145fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle) 515aaa36a97SAlex Deucher { 516aaa36a97SAlex Deucher int r; 5175fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 518aaa36a97SAlex Deucher 519aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 520aaa36a97SAlex Deucher if (r) 521aaa36a97SAlex Deucher return r; 522aaa36a97SAlex Deucher 523aaa36a97SAlex Deucher r = vce_v3_0_hw_init(adev); 524aaa36a97SAlex Deucher if (r) 525aaa36a97SAlex Deucher return r; 526aaa36a97SAlex Deucher 527aaa36a97SAlex Deucher return r; 528aaa36a97SAlex Deucher } 529aaa36a97SAlex Deucher 5305bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) 531aaa36a97SAlex Deucher { 532aaa36a97SAlex Deucher uint32_t offset, size; 533aaa36a97SAlex Deucher 534aaa36a97SAlex Deucher WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16)); 535aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); 536aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); 537aaa36a97SAlex Deucher WREG32(mmVCE_CLOCK_GATING_B, 0xf7); 538aaa36a97SAlex Deucher 539aaa36a97SAlex Deucher WREG32(mmVCE_LMI_CTRL, 0x00398000); 540aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1); 541aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL, 0); 542aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL1, 0); 543aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VM_CTRL, 0); 5443c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) { 5453c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8)); 5463c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8)); 5473c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8)); 5483c0ff9f1SLeo Liu } else 549aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8)); 550aaa36a97SAlex Deucher offset = AMDGPU_VCE_FIRMWARE_OFFSET; 551e9822622SLeo Liu size = VCE_V3_0_FW_SIZE; 552aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff); 553aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE0, size); 554aaa36a97SAlex Deucher 5555bbc553aSLeo Liu if (idx == 0) { 556aaa36a97SAlex Deucher offset += size; 557e9822622SLeo Liu size = VCE_V3_0_STACK_SIZE; 558aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff); 559aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 560aaa36a97SAlex Deucher offset += size; 561e9822622SLeo Liu size = VCE_V3_0_DATA_SIZE; 562aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff); 563aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5645bbc553aSLeo Liu } else { 5655bbc553aSLeo Liu offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE; 5665bbc553aSLeo Liu size = VCE_V3_0_STACK_SIZE; 5675bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff); 5685bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 5695bbc553aSLeo Liu offset += size; 5705bbc553aSLeo Liu size = VCE_V3_0_DATA_SIZE; 5715bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff); 5725bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5735bbc553aSLeo Liu } 574aaa36a97SAlex Deucher 575aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); 576aaa36a97SAlex Deucher 577aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK, 578aaa36a97SAlex Deucher ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 579aaa36a97SAlex Deucher } 580aaa36a97SAlex Deucher 5815fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle) 582aaa36a97SAlex Deucher { 5835fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 584be4f38e2SAlex Deucher u32 mask = 0; 5855fc3aeebSyanyang1 58674af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK; 58774af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK; 588be4f38e2SAlex Deucher 589be4f38e2SAlex Deucher return !(RREG32(mmSRBM_STATUS2) & mask); 590aaa36a97SAlex Deucher } 591aaa36a97SAlex Deucher 5925fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle) 593aaa36a97SAlex Deucher { 594aaa36a97SAlex Deucher unsigned i; 5955fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 596be4f38e2SAlex Deucher 59792988e60STom St Denis for (i = 0; i < adev->usec_timeout; i++) 59892988e60STom St Denis if (vce_v3_0_is_idle(handle)) 599aaa36a97SAlex Deucher return 0; 60092988e60STom St Denis 601aaa36a97SAlex Deucher return -ETIMEDOUT; 602aaa36a97SAlex Deucher } 603aaa36a97SAlex Deucher 6045fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle) 605aaa36a97SAlex Deucher { 6065fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 607be4f38e2SAlex Deucher u32 mask = 0; 6085fc3aeebSyanyang1 60974af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK; 61074af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK; 611be4f38e2SAlex Deucher 612be4f38e2SAlex Deucher WREG32_P(mmSRBM_SOFT_RESET, mask, 613be4f38e2SAlex Deucher ~(SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK | 614be4f38e2SAlex Deucher SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK)); 615aaa36a97SAlex Deucher mdelay(5); 616aaa36a97SAlex Deucher 617aaa36a97SAlex Deucher return vce_v3_0_start(adev); 618aaa36a97SAlex Deucher } 619aaa36a97SAlex Deucher 620aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, 621aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 622aaa36a97SAlex Deucher unsigned type, 623aaa36a97SAlex Deucher enum amdgpu_interrupt_state state) 624aaa36a97SAlex Deucher { 625aaa36a97SAlex Deucher uint32_t val = 0; 626aaa36a97SAlex Deucher 627aaa36a97SAlex Deucher if (state == AMDGPU_IRQ_STATE_ENABLE) 628aaa36a97SAlex Deucher val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK; 629aaa36a97SAlex Deucher 630aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 631aaa36a97SAlex Deucher return 0; 632aaa36a97SAlex Deucher } 633aaa36a97SAlex Deucher 634aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev, 635aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 636aaa36a97SAlex Deucher struct amdgpu_iv_entry *entry) 637aaa36a97SAlex Deucher { 638aaa36a97SAlex Deucher DRM_DEBUG("IH: VCE\n"); 639d6c29c30SLeo Liu 640d6c29c30SLeo Liu WREG32_P(mmVCE_SYS_INT_STATUS, 641d6c29c30SLeo Liu VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK, 642d6c29c30SLeo Liu ~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK); 643d6c29c30SLeo Liu 644aaa36a97SAlex Deucher switch (entry->src_data) { 645aaa36a97SAlex Deucher case 0: 646aaa36a97SAlex Deucher case 1: 64781da2edeSTom St Denis amdgpu_fence_process(&adev->vce.ring[entry->src_data]); 648aaa36a97SAlex Deucher break; 649aaa36a97SAlex Deucher default: 650aaa36a97SAlex Deucher DRM_ERROR("Unhandled interrupt: %d %d\n", 651aaa36a97SAlex Deucher entry->src_id, entry->src_data); 652aaa36a97SAlex Deucher break; 653aaa36a97SAlex Deucher } 654aaa36a97SAlex Deucher 655aaa36a97SAlex Deucher return 0; 656aaa36a97SAlex Deucher } 657aaa36a97SAlex Deucher 658ec38f188SRex Zhu static void vce_v3_set_bypass_mode(struct amdgpu_device *adev, bool enable) 659ec38f188SRex Zhu { 660ec38f188SRex Zhu u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL); 661ec38f188SRex Zhu 662ec38f188SRex Zhu if (enable) 663ec38f188SRex Zhu tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 664ec38f188SRex Zhu else 665ec38f188SRex Zhu tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 666ec38f188SRex Zhu 667ec38f188SRex Zhu WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp); 668ec38f188SRex Zhu } 669ec38f188SRex Zhu 6705fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle, 6715fc3aeebSyanyang1 enum amd_clockgating_state state) 672aaa36a97SAlex Deucher { 6730689a570SEric Huang struct amdgpu_device *adev = (struct amdgpu_device *)handle; 6740689a570SEric Huang bool enable = (state == AMD_CG_STATE_GATE) ? true : false; 6750689a570SEric Huang int i; 6760689a570SEric Huang 677ec38f188SRex Zhu if (adev->asic_type == CHIP_POLARIS10) 678ec38f188SRex Zhu vce_v3_set_bypass_mode(adev, enable); 679ec38f188SRex Zhu 680e3b04bc7SAlex Deucher if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) 6810689a570SEric Huang return 0; 6820689a570SEric Huang 6830689a570SEric Huang mutex_lock(&adev->grbm_idx_mutex); 6840689a570SEric Huang for (i = 0; i < 2; i++) { 6850689a570SEric Huang /* Program VCE Instance 0 or 1 if not harvested */ 6860689a570SEric Huang if (adev->vce.harvest_config & (1 << i)) 6870689a570SEric Huang continue; 6880689a570SEric Huang 6890689a570SEric Huang if (i == 0) 6900689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 0, 6910689a570SEric Huang ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 6920689a570SEric Huang else 6930689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 6940689a570SEric Huang GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 6950689a570SEric Huang ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 6960689a570SEric Huang 6970689a570SEric Huang if (enable) { 6980689a570SEric Huang /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ 6990689a570SEric Huang uint32_t data = RREG32(mmVCE_CLOCK_GATING_A); 7000689a570SEric Huang data &= ~(0xf | 0xff0); 7010689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7020689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_A, data); 7030689a570SEric Huang 7040689a570SEric Huang /* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */ 7050689a570SEric Huang data = RREG32(mmVCE_UENC_CLOCK_GATING); 7060689a570SEric Huang data &= ~(0xf | 0xff0); 7070689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7080689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 7090689a570SEric Huang } 7100689a570SEric Huang 7110689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, enable); 7120689a570SEric Huang } 7130689a570SEric Huang 7140689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 7150689a570SEric Huang mutex_unlock(&adev->grbm_idx_mutex); 7160689a570SEric Huang 717aaa36a97SAlex Deucher return 0; 718aaa36a97SAlex Deucher } 719aaa36a97SAlex Deucher 7205fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle, 7215fc3aeebSyanyang1 enum amd_powergating_state state) 722aaa36a97SAlex Deucher { 723aaa36a97SAlex Deucher /* This doesn't actually powergate the VCE block. 724aaa36a97SAlex Deucher * That's done in the dpm code via the SMC. This 725aaa36a97SAlex Deucher * just re-inits the block as necessary. The actual 726aaa36a97SAlex Deucher * gating still happens in the dpm code. We should 727aaa36a97SAlex Deucher * revisit this when there is a cleaner line between 728aaa36a97SAlex Deucher * the smc and the hw blocks 729aaa36a97SAlex Deucher */ 7305fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7315fc3aeebSyanyang1 732e3b04bc7SAlex Deucher if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE)) 733808a934fSAlex Deucher return 0; 734808a934fSAlex Deucher 7355fc3aeebSyanyang1 if (state == AMD_PG_STATE_GATE) 736aaa36a97SAlex Deucher /* XXX do we need a vce_v3_0_stop()? */ 737aaa36a97SAlex Deucher return 0; 738aaa36a97SAlex Deucher else 739aaa36a97SAlex Deucher return vce_v3_0_start(adev); 740aaa36a97SAlex Deucher } 741aaa36a97SAlex Deucher 7425fc3aeebSyanyang1 const struct amd_ip_funcs vce_v3_0_ip_funcs = { 74388a907d6STom St Denis .name = "vce_v3_0", 744aaa36a97SAlex Deucher .early_init = vce_v3_0_early_init, 745aaa36a97SAlex Deucher .late_init = NULL, 746aaa36a97SAlex Deucher .sw_init = vce_v3_0_sw_init, 747aaa36a97SAlex Deucher .sw_fini = vce_v3_0_sw_fini, 748aaa36a97SAlex Deucher .hw_init = vce_v3_0_hw_init, 749aaa36a97SAlex Deucher .hw_fini = vce_v3_0_hw_fini, 750aaa36a97SAlex Deucher .suspend = vce_v3_0_suspend, 751aaa36a97SAlex Deucher .resume = vce_v3_0_resume, 752aaa36a97SAlex Deucher .is_idle = vce_v3_0_is_idle, 753aaa36a97SAlex Deucher .wait_for_idle = vce_v3_0_wait_for_idle, 754aaa36a97SAlex Deucher .soft_reset = vce_v3_0_soft_reset, 755aaa36a97SAlex Deucher .set_clockgating_state = vce_v3_0_set_clockgating_state, 756aaa36a97SAlex Deucher .set_powergating_state = vce_v3_0_set_powergating_state, 757aaa36a97SAlex Deucher }; 758aaa36a97SAlex Deucher 759aaa36a97SAlex Deucher static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = { 760aaa36a97SAlex Deucher .get_rptr = vce_v3_0_ring_get_rptr, 761aaa36a97SAlex Deucher .get_wptr = vce_v3_0_ring_get_wptr, 762aaa36a97SAlex Deucher .set_wptr = vce_v3_0_ring_set_wptr, 763aaa36a97SAlex Deucher .parse_cs = amdgpu_vce_ring_parse_cs, 764aaa36a97SAlex Deucher .emit_ib = amdgpu_vce_ring_emit_ib, 765aaa36a97SAlex Deucher .emit_fence = amdgpu_vce_ring_emit_fence, 766aaa36a97SAlex Deucher .test_ring = amdgpu_vce_ring_test_ring, 767aaa36a97SAlex Deucher .test_ib = amdgpu_vce_ring_test_ib, 768edff0e28SJammy Zhou .insert_nop = amdgpu_ring_insert_nop, 7699e5d5309SChristian König .pad_ib = amdgpu_ring_generic_pad_ib, 770ebff485eSChristian König .begin_use = amdgpu_vce_ring_begin_use, 771ebff485eSChristian König .end_use = amdgpu_vce_ring_end_use, 772aaa36a97SAlex Deucher }; 773aaa36a97SAlex Deucher 774aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) 775aaa36a97SAlex Deucher { 776aaa36a97SAlex Deucher adev->vce.ring[0].funcs = &vce_v3_0_ring_funcs; 777aaa36a97SAlex Deucher adev->vce.ring[1].funcs = &vce_v3_0_ring_funcs; 778aaa36a97SAlex Deucher } 779aaa36a97SAlex Deucher 780aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = { 781aaa36a97SAlex Deucher .set = vce_v3_0_set_interrupt_state, 782aaa36a97SAlex Deucher .process = vce_v3_0_process_interrupt, 783aaa36a97SAlex Deucher }; 784aaa36a97SAlex Deucher 785aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev) 786aaa36a97SAlex Deucher { 787aaa36a97SAlex Deucher adev->vce.irq.num_types = 1; 788aaa36a97SAlex Deucher adev->vce.irq.funcs = &vce_v3_0_irq_funcs; 789aaa36a97SAlex Deucher }; 790