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 46aaa36a97SAlex Deucher 47e9822622SLeo Liu #define VCE_V3_0_FW_SIZE (384 * 1024) 48e9822622SLeo Liu #define VCE_V3_0_STACK_SIZE (64 * 1024) 49e9822622SLeo Liu #define VCE_V3_0_DATA_SIZE ((16 * 1024 * AMDGPU_MAX_VCE_HANDLES) + (52 * 1024)) 50e9822622SLeo Liu 515bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx); 52aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev); 53aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev); 54aaa36a97SAlex Deucher 55aaa36a97SAlex Deucher /** 56aaa36a97SAlex Deucher * vce_v3_0_ring_get_rptr - get read pointer 57aaa36a97SAlex Deucher * 58aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 59aaa36a97SAlex Deucher * 60aaa36a97SAlex Deucher * Returns the current hardware read pointer 61aaa36a97SAlex Deucher */ 62aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring) 63aaa36a97SAlex Deucher { 64aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 65aaa36a97SAlex Deucher 66aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 67aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR); 68aaa36a97SAlex Deucher else 69aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR2); 70aaa36a97SAlex Deucher } 71aaa36a97SAlex Deucher 72aaa36a97SAlex Deucher /** 73aaa36a97SAlex Deucher * vce_v3_0_ring_get_wptr - get write pointer 74aaa36a97SAlex Deucher * 75aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 76aaa36a97SAlex Deucher * 77aaa36a97SAlex Deucher * Returns the current hardware write pointer 78aaa36a97SAlex Deucher */ 79aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring) 80aaa36a97SAlex Deucher { 81aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 82aaa36a97SAlex Deucher 83aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 84aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR); 85aaa36a97SAlex Deucher else 86aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR2); 87aaa36a97SAlex Deucher } 88aaa36a97SAlex Deucher 89aaa36a97SAlex Deucher /** 90aaa36a97SAlex Deucher * vce_v3_0_ring_set_wptr - set write pointer 91aaa36a97SAlex Deucher * 92aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 93aaa36a97SAlex Deucher * 94aaa36a97SAlex Deucher * Commits the write pointer to the hardware 95aaa36a97SAlex Deucher */ 96aaa36a97SAlex Deucher static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring) 97aaa36a97SAlex Deucher { 98aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 99aaa36a97SAlex Deucher 100aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 101aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR, ring->wptr); 102aaa36a97SAlex Deucher else 103aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR2, ring->wptr); 104aaa36a97SAlex Deucher } 105aaa36a97SAlex Deucher 1060689a570SEric Huang static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override) 1070689a570SEric Huang { 1080689a570SEric Huang u32 tmp, data; 1090689a570SEric Huang 1100689a570SEric Huang tmp = data = RREG32(mmVCE_RB_ARB_CTRL); 1110689a570SEric Huang if (override) 1120689a570SEric Huang data |= VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; 1130689a570SEric Huang else 1140689a570SEric Huang data &= ~VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; 1150689a570SEric Huang 1160689a570SEric Huang if (tmp != data) 1170689a570SEric Huang WREG32(mmVCE_RB_ARB_CTRL, data); 1180689a570SEric Huang } 1190689a570SEric Huang 1200689a570SEric Huang static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, 1210689a570SEric Huang bool gated) 1220689a570SEric Huang { 1230689a570SEric Huang u32 tmp, data; 1240689a570SEric Huang /* Set Override to disable Clock Gating */ 1250689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, true); 1260689a570SEric Huang 1270689a570SEric Huang if (!gated) { 1280689a570SEric Huang /* Force CLOCK ON for VCE_CLOCK_GATING_B, 1290689a570SEric Huang * {*_FORCE_ON, *_FORCE_OFF} = {1, 0} 1300689a570SEric Huang * VREG can be FORCE ON or set to Dynamic, but can't be OFF 1310689a570SEric Huang */ 1320689a570SEric Huang tmp = data = RREG32(mmVCE_CLOCK_GATING_B); 1330689a570SEric Huang data |= 0x1ff; 1340689a570SEric Huang data &= ~0xef0000; 1350689a570SEric Huang if (tmp != data) 1360689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1370689a570SEric Huang 1380689a570SEric Huang /* Force CLOCK ON for VCE_UENC_CLOCK_GATING, 1390689a570SEric Huang * {*_FORCE_ON, *_FORCE_OFF} = {1, 0} 1400689a570SEric Huang */ 1410689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); 1420689a570SEric Huang data |= 0x3ff000; 1430689a570SEric Huang data &= ~0xffc00000; 1440689a570SEric Huang if (tmp != data) 1450689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1460689a570SEric Huang 1470689a570SEric Huang /* set VCE_UENC_CLOCK_GATING_2 */ 1480689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1490689a570SEric Huang data |= 0x2; 1500689a570SEric Huang data &= ~0x2; 1510689a570SEric Huang if (tmp != data) 1520689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1530689a570SEric Huang 1540689a570SEric Huang /* Force CLOCK ON for VCE_UENC_REG_CLOCK_GATING */ 1550689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1560689a570SEric Huang data |= 0x37f; 1570689a570SEric Huang if (tmp != data) 1580689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1590689a570SEric Huang 1600689a570SEric Huang /* Force VCE_UENC_DMA_DCLK_CTRL Clock ON */ 1610689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1620689a570SEric Huang data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1630689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1640689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1650689a570SEric Huang 0x8; 1660689a570SEric Huang if (tmp != data) 1670689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1680689a570SEric Huang } else { 1690689a570SEric Huang /* Force CLOCK OFF for VCE_CLOCK_GATING_B, 1700689a570SEric Huang * {*, *_FORCE_OFF} = {*, 1} 1710689a570SEric Huang * set VREG to Dynamic, as it can't be OFF 1720689a570SEric Huang */ 1730689a570SEric Huang tmp = data = RREG32(mmVCE_CLOCK_GATING_B); 1740689a570SEric Huang data &= ~0x80010; 1750689a570SEric Huang data |= 0xe70008; 1760689a570SEric Huang if (tmp != data) 1770689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1780689a570SEric Huang /* Force CLOCK OFF for VCE_UENC_CLOCK_GATING, 1790689a570SEric Huang * Force ClOCK OFF takes precedent over Force CLOCK ON setting. 1800689a570SEric Huang * {*_FORCE_ON, *_FORCE_OFF} = {*, 1} 1810689a570SEric Huang */ 1820689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); 1830689a570SEric Huang data |= 0xffc00000; 1840689a570SEric Huang if (tmp != data) 1850689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1860689a570SEric Huang /* Set VCE_UENC_CLOCK_GATING_2 */ 1870689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1880689a570SEric Huang data |= 0x10000; 1890689a570SEric Huang if (tmp != data) 1900689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1910689a570SEric Huang /* Set VCE_UENC_REG_CLOCK_GATING to dynamic */ 1920689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1930689a570SEric Huang data &= ~0xffc00000; 1940689a570SEric Huang if (tmp != data) 1950689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1960689a570SEric Huang /* Set VCE_UENC_DMA_DCLK_CTRL CG always in dynamic mode */ 1970689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1980689a570SEric Huang data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1990689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 2000689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 2010689a570SEric Huang 0x8); 2020689a570SEric Huang if (tmp != data) 2030689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 2040689a570SEric Huang } 2050689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, false); 2060689a570SEric Huang } 2070689a570SEric Huang 208aaa36a97SAlex Deucher /** 209aaa36a97SAlex Deucher * vce_v3_0_start - start VCE block 210aaa36a97SAlex Deucher * 211aaa36a97SAlex Deucher * @adev: amdgpu_device pointer 212aaa36a97SAlex Deucher * 213aaa36a97SAlex Deucher * Setup and start the VCE block 214aaa36a97SAlex Deucher */ 215aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev) 216aaa36a97SAlex Deucher { 217aaa36a97SAlex Deucher struct amdgpu_ring *ring; 2185bbc553aSLeo Liu int idx, i, j, r; 219aaa36a97SAlex Deucher 2205bbc553aSLeo Liu mutex_lock(&adev->grbm_idx_mutex); 2215bbc553aSLeo Liu for (idx = 0; idx < 2; ++idx) { 2226a585777SAlex Deucher 2236a585777SAlex Deucher if (adev->vce.harvest_config & (1 << idx)) 2246a585777SAlex Deucher continue; 2256a585777SAlex Deucher 2265bbc553aSLeo Liu if (idx == 0) 2275bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 0, 2285bbc553aSLeo Liu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2295bbc553aSLeo Liu else 2305bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 2315bbc553aSLeo Liu GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 2325bbc553aSLeo Liu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2335bbc553aSLeo Liu 2345bbc553aSLeo Liu vce_v3_0_mc_resume(adev, idx); 235aaa36a97SAlex Deucher 236aaa36a97SAlex Deucher /* set BUSY flag */ 237aaa36a97SAlex Deucher WREG32_P(mmVCE_STATUS, 1, ~1); 2383c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) 2393c0ff9f1SLeo Liu WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001); 2403c0ff9f1SLeo Liu else 2415bbc553aSLeo Liu WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, 2425bbc553aSLeo Liu ~VCE_VCPU_CNTL__CLK_EN_MASK); 243aaa36a97SAlex Deucher 244aaa36a97SAlex Deucher WREG32_P(mmVCE_SOFT_RESET, 245aaa36a97SAlex Deucher VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, 246aaa36a97SAlex Deucher ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 247aaa36a97SAlex Deucher 248aaa36a97SAlex Deucher mdelay(100); 249aaa36a97SAlex Deucher 2505bbc553aSLeo Liu WREG32_P(mmVCE_SOFT_RESET, 0, 2515bbc553aSLeo Liu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 252aaa36a97SAlex Deucher 253aaa36a97SAlex Deucher for (i = 0; i < 10; ++i) { 254aaa36a97SAlex Deucher uint32_t status; 255aaa36a97SAlex Deucher for (j = 0; j < 100; ++j) { 256aaa36a97SAlex Deucher status = RREG32(mmVCE_STATUS); 257aaa36a97SAlex Deucher if (status & 2) 258aaa36a97SAlex Deucher break; 259aaa36a97SAlex Deucher mdelay(10); 260aaa36a97SAlex Deucher } 261aaa36a97SAlex Deucher r = 0; 262aaa36a97SAlex Deucher if (status & 2) 263aaa36a97SAlex Deucher break; 264aaa36a97SAlex Deucher 265aaa36a97SAlex Deucher DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); 2665bbc553aSLeo Liu WREG32_P(mmVCE_SOFT_RESET, 2675bbc553aSLeo Liu VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, 268aaa36a97SAlex Deucher ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 269aaa36a97SAlex Deucher mdelay(10); 2705bbc553aSLeo Liu WREG32_P(mmVCE_SOFT_RESET, 0, 2715bbc553aSLeo Liu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 272aaa36a97SAlex Deucher mdelay(10); 273aaa36a97SAlex Deucher r = -1; 274aaa36a97SAlex Deucher } 275aaa36a97SAlex Deucher 276aaa36a97SAlex Deucher /* clear BUSY flag */ 277aaa36a97SAlex Deucher WREG32_P(mmVCE_STATUS, 0, ~1); 278aaa36a97SAlex Deucher 2790689a570SEric Huang /* Set Clock-Gating off */ 2800689a570SEric Huang if (adev->cg_flags & AMDGPU_CG_SUPPORT_VCE_MGCG) 2810689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, false); 2820689a570SEric Huang 283aaa36a97SAlex Deucher if (r) { 284aaa36a97SAlex Deucher DRM_ERROR("VCE not responding, giving up!!!\n"); 2855bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 286aaa36a97SAlex Deucher return r; 287aaa36a97SAlex Deucher } 2885bbc553aSLeo Liu } 2895bbc553aSLeo Liu 2905bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2915bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 2925bbc553aSLeo Liu 2935bbc553aSLeo Liu ring = &adev->vce.ring[0]; 2945bbc553aSLeo Liu WREG32(mmVCE_RB_RPTR, ring->wptr); 2955bbc553aSLeo Liu WREG32(mmVCE_RB_WPTR, ring->wptr); 2965bbc553aSLeo Liu WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr); 2975bbc553aSLeo Liu WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); 2985bbc553aSLeo Liu WREG32(mmVCE_RB_SIZE, ring->ring_size / 4); 2995bbc553aSLeo Liu 3005bbc553aSLeo Liu ring = &adev->vce.ring[1]; 3015bbc553aSLeo Liu WREG32(mmVCE_RB_RPTR2, ring->wptr); 3025bbc553aSLeo Liu WREG32(mmVCE_RB_WPTR2, ring->wptr); 3035bbc553aSLeo Liu WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr); 3045bbc553aSLeo Liu WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); 3055bbc553aSLeo Liu WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4); 306aaa36a97SAlex Deucher 307aaa36a97SAlex Deucher return 0; 308aaa36a97SAlex Deucher } 309aaa36a97SAlex Deucher 3106a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS 0xC0014074 3116a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT 27 3126a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK 0x18000000 3136a585777SAlex Deucher 3146a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) 3156a585777SAlex Deucher { 3166a585777SAlex Deucher u32 tmp; 3176a585777SAlex Deucher unsigned ret; 3186a585777SAlex Deucher 319cfaba566SSamuel Li /* Fiji, Stoney are single pipe */ 320cfaba566SSamuel Li if ((adev->asic_type == CHIP_FIJI) || 321cfaba566SSamuel Li (adev->asic_type == CHIP_STONEY)){ 322188a9bcdSAlex Deucher ret = AMDGPU_VCE_HARVEST_VCE1; 323188a9bcdSAlex Deucher return ret; 324188a9bcdSAlex Deucher } 325188a9bcdSAlex Deucher 326188a9bcdSAlex Deucher /* Tonga and CZ are dual or single pipe */ 3272f7d10b3SJammy Zhou if (adev->flags & AMD_IS_APU) 3286a585777SAlex Deucher tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) & 3296a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__MASK) >> 3306a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__SHIFT; 3316a585777SAlex Deucher else 3326a585777SAlex Deucher tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) & 3336a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE_MASK) >> 3346a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE__SHIFT; 3356a585777SAlex Deucher 3366a585777SAlex Deucher switch (tmp) { 3376a585777SAlex Deucher case 1: 3386a585777SAlex Deucher ret = AMDGPU_VCE_HARVEST_VCE0; 3396a585777SAlex Deucher break; 3406a585777SAlex Deucher case 2: 3416a585777SAlex Deucher ret = AMDGPU_VCE_HARVEST_VCE1; 3426a585777SAlex Deucher break; 3436a585777SAlex Deucher case 3: 3446a585777SAlex Deucher ret = AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1; 3456a585777SAlex Deucher break; 3466a585777SAlex Deucher default: 3476a585777SAlex Deucher ret = 0; 3486a585777SAlex Deucher } 3496a585777SAlex Deucher 3506a585777SAlex Deucher return ret; 3516a585777SAlex Deucher } 3526a585777SAlex Deucher 3535fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle) 354aaa36a97SAlex Deucher { 3555fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 3565fc3aeebSyanyang1 3576a585777SAlex Deucher adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); 3586a585777SAlex Deucher 3596a585777SAlex Deucher if ((adev->vce.harvest_config & 3606a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) == 3616a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 3626a585777SAlex Deucher return -ENOENT; 3636a585777SAlex Deucher 364aaa36a97SAlex Deucher vce_v3_0_set_ring_funcs(adev); 365aaa36a97SAlex Deucher vce_v3_0_set_irq_funcs(adev); 366aaa36a97SAlex Deucher 367aaa36a97SAlex Deucher return 0; 368aaa36a97SAlex Deucher } 369aaa36a97SAlex Deucher 3705fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle) 371aaa36a97SAlex Deucher { 3725fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 373aaa36a97SAlex Deucher struct amdgpu_ring *ring; 374aaa36a97SAlex Deucher int r; 375aaa36a97SAlex Deucher 376aaa36a97SAlex Deucher /* VCE */ 377aaa36a97SAlex Deucher r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq); 378aaa36a97SAlex Deucher if (r) 379aaa36a97SAlex Deucher return r; 380aaa36a97SAlex Deucher 381e9822622SLeo Liu r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE + 382e9822622SLeo Liu (VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2); 383aaa36a97SAlex Deucher if (r) 384aaa36a97SAlex Deucher return r; 385aaa36a97SAlex Deucher 386aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 387aaa36a97SAlex Deucher if (r) 388aaa36a97SAlex Deucher return r; 389aaa36a97SAlex Deucher 390aaa36a97SAlex Deucher ring = &adev->vce.ring[0]; 391aaa36a97SAlex Deucher sprintf(ring->name, "vce0"); 392aaa36a97SAlex Deucher r = amdgpu_ring_init(adev, ring, 4096, VCE_CMD_NO_OP, 0xf, 393aaa36a97SAlex Deucher &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); 394aaa36a97SAlex Deucher if (r) 395aaa36a97SAlex Deucher return r; 396aaa36a97SAlex Deucher 397aaa36a97SAlex Deucher ring = &adev->vce.ring[1]; 398aaa36a97SAlex Deucher sprintf(ring->name, "vce1"); 399aaa36a97SAlex Deucher r = amdgpu_ring_init(adev, ring, 4096, VCE_CMD_NO_OP, 0xf, 400aaa36a97SAlex Deucher &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); 401aaa36a97SAlex Deucher if (r) 402aaa36a97SAlex Deucher return r; 403aaa36a97SAlex Deucher 404aaa36a97SAlex Deucher return r; 405aaa36a97SAlex Deucher } 406aaa36a97SAlex Deucher 4075fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle) 408aaa36a97SAlex Deucher { 409aaa36a97SAlex Deucher int r; 4105fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 411aaa36a97SAlex Deucher 412aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 413aaa36a97SAlex Deucher if (r) 414aaa36a97SAlex Deucher return r; 415aaa36a97SAlex Deucher 416aaa36a97SAlex Deucher r = amdgpu_vce_sw_fini(adev); 417aaa36a97SAlex Deucher if (r) 418aaa36a97SAlex Deucher return r; 419aaa36a97SAlex Deucher 420aaa36a97SAlex Deucher return r; 421aaa36a97SAlex Deucher } 422aaa36a97SAlex Deucher 4235fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle) 424aaa36a97SAlex Deucher { 425aaa36a97SAlex Deucher struct amdgpu_ring *ring; 426aaa36a97SAlex Deucher int r; 4275fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 428aaa36a97SAlex Deucher 429aaa36a97SAlex Deucher r = vce_v3_0_start(adev); 430aaa36a97SAlex Deucher if (r) 431aaa36a97SAlex Deucher return r; 432aaa36a97SAlex Deucher 433aaa36a97SAlex Deucher ring = &adev->vce.ring[0]; 434aaa36a97SAlex Deucher ring->ready = true; 435aaa36a97SAlex Deucher r = amdgpu_ring_test_ring(ring); 436aaa36a97SAlex Deucher if (r) { 437aaa36a97SAlex Deucher ring->ready = false; 438aaa36a97SAlex Deucher return r; 439aaa36a97SAlex Deucher } 440aaa36a97SAlex Deucher 441aaa36a97SAlex Deucher ring = &adev->vce.ring[1]; 442aaa36a97SAlex Deucher ring->ready = true; 443aaa36a97SAlex Deucher r = amdgpu_ring_test_ring(ring); 444aaa36a97SAlex Deucher if (r) { 445aaa36a97SAlex Deucher ring->ready = false; 446aaa36a97SAlex Deucher return r; 447aaa36a97SAlex Deucher } 448aaa36a97SAlex Deucher 449aaa36a97SAlex Deucher DRM_INFO("VCE initialized successfully.\n"); 450aaa36a97SAlex Deucher 451aaa36a97SAlex Deucher return 0; 452aaa36a97SAlex Deucher } 453aaa36a97SAlex Deucher 4545fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle) 455aaa36a97SAlex Deucher { 456aaa36a97SAlex Deucher return 0; 457aaa36a97SAlex Deucher } 458aaa36a97SAlex Deucher 4595fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle) 460aaa36a97SAlex Deucher { 461aaa36a97SAlex Deucher int r; 4625fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 463aaa36a97SAlex Deucher 464aaa36a97SAlex Deucher r = vce_v3_0_hw_fini(adev); 465aaa36a97SAlex Deucher if (r) 466aaa36a97SAlex Deucher return r; 467aaa36a97SAlex Deucher 468aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 469aaa36a97SAlex Deucher if (r) 470aaa36a97SAlex Deucher return r; 471aaa36a97SAlex Deucher 472aaa36a97SAlex Deucher return r; 473aaa36a97SAlex Deucher } 474aaa36a97SAlex Deucher 4755fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle) 476aaa36a97SAlex Deucher { 477aaa36a97SAlex Deucher int r; 4785fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 479aaa36a97SAlex Deucher 480aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 481aaa36a97SAlex Deucher if (r) 482aaa36a97SAlex Deucher return r; 483aaa36a97SAlex Deucher 484aaa36a97SAlex Deucher r = vce_v3_0_hw_init(adev); 485aaa36a97SAlex Deucher if (r) 486aaa36a97SAlex Deucher return r; 487aaa36a97SAlex Deucher 488aaa36a97SAlex Deucher return r; 489aaa36a97SAlex Deucher } 490aaa36a97SAlex Deucher 4915bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) 492aaa36a97SAlex Deucher { 493aaa36a97SAlex Deucher uint32_t offset, size; 494aaa36a97SAlex Deucher 495aaa36a97SAlex Deucher WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16)); 496aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); 497aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); 498aaa36a97SAlex Deucher WREG32(mmVCE_CLOCK_GATING_B, 0xf7); 499aaa36a97SAlex Deucher 500aaa36a97SAlex Deucher WREG32(mmVCE_LMI_CTRL, 0x00398000); 501aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1); 502aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL, 0); 503aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL1, 0); 504aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VM_CTRL, 0); 5053c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) { 5063c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8)); 5073c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8)); 5083c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8)); 5093c0ff9f1SLeo Liu } else 510aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8)); 511aaa36a97SAlex Deucher offset = AMDGPU_VCE_FIRMWARE_OFFSET; 512e9822622SLeo Liu size = VCE_V3_0_FW_SIZE; 513aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff); 514aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE0, size); 515aaa36a97SAlex Deucher 5165bbc553aSLeo Liu if (idx == 0) { 517aaa36a97SAlex Deucher offset += size; 518e9822622SLeo Liu size = VCE_V3_0_STACK_SIZE; 519aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff); 520aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 521aaa36a97SAlex Deucher offset += size; 522e9822622SLeo Liu size = VCE_V3_0_DATA_SIZE; 523aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff); 524aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5255bbc553aSLeo Liu } else { 5265bbc553aSLeo Liu offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE; 5275bbc553aSLeo Liu size = VCE_V3_0_STACK_SIZE; 5285bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff); 5295bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 5305bbc553aSLeo Liu offset += size; 5315bbc553aSLeo Liu size = VCE_V3_0_DATA_SIZE; 5325bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff); 5335bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5345bbc553aSLeo Liu } 535aaa36a97SAlex Deucher 536aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); 537aaa36a97SAlex Deucher 538aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK, 539aaa36a97SAlex Deucher ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 540aaa36a97SAlex Deucher } 541aaa36a97SAlex Deucher 5425fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle) 543aaa36a97SAlex Deucher { 5445fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 545be4f38e2SAlex Deucher u32 mask = 0; 546be4f38e2SAlex Deucher int idx; 5475fc3aeebSyanyang1 548be4f38e2SAlex Deucher for (idx = 0; idx < 2; ++idx) { 549be4f38e2SAlex Deucher if (adev->vce.harvest_config & (1 << idx)) 550be4f38e2SAlex Deucher continue; 551be4f38e2SAlex Deucher 552be4f38e2SAlex Deucher if (idx == 0) 553be4f38e2SAlex Deucher mask |= SRBM_STATUS2__VCE0_BUSY_MASK; 554be4f38e2SAlex Deucher else 555be4f38e2SAlex Deucher mask |= SRBM_STATUS2__VCE1_BUSY_MASK; 556be4f38e2SAlex Deucher } 557be4f38e2SAlex Deucher 558be4f38e2SAlex Deucher return !(RREG32(mmSRBM_STATUS2) & mask); 559aaa36a97SAlex Deucher } 560aaa36a97SAlex Deucher 5615fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle) 562aaa36a97SAlex Deucher { 563aaa36a97SAlex Deucher unsigned i; 5645fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 565be4f38e2SAlex Deucher u32 mask = 0; 566be4f38e2SAlex Deucher int idx; 567be4f38e2SAlex Deucher 568be4f38e2SAlex Deucher for (idx = 0; idx < 2; ++idx) { 569be4f38e2SAlex Deucher if (adev->vce.harvest_config & (1 << idx)) 570be4f38e2SAlex Deucher continue; 571be4f38e2SAlex Deucher 572be4f38e2SAlex Deucher if (idx == 0) 573be4f38e2SAlex Deucher mask |= SRBM_STATUS2__VCE0_BUSY_MASK; 574be4f38e2SAlex Deucher else 575be4f38e2SAlex Deucher mask |= SRBM_STATUS2__VCE1_BUSY_MASK; 576be4f38e2SAlex Deucher } 577aaa36a97SAlex Deucher 578aaa36a97SAlex Deucher for (i = 0; i < adev->usec_timeout; i++) { 579be4f38e2SAlex Deucher if (!(RREG32(mmSRBM_STATUS2) & mask)) 580aaa36a97SAlex Deucher return 0; 581aaa36a97SAlex Deucher } 582aaa36a97SAlex Deucher return -ETIMEDOUT; 583aaa36a97SAlex Deucher } 584aaa36a97SAlex Deucher 5855fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle) 586aaa36a97SAlex Deucher { 5875fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 588be4f38e2SAlex Deucher u32 mask = 0; 589be4f38e2SAlex Deucher int idx; 5905fc3aeebSyanyang1 591be4f38e2SAlex Deucher for (idx = 0; idx < 2; ++idx) { 592be4f38e2SAlex Deucher if (adev->vce.harvest_config & (1 << idx)) 593be4f38e2SAlex Deucher continue; 594be4f38e2SAlex Deucher 595be4f38e2SAlex Deucher if (idx == 0) 596be4f38e2SAlex Deucher mask |= SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK; 597be4f38e2SAlex Deucher else 598be4f38e2SAlex Deucher mask |= SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK; 599be4f38e2SAlex Deucher } 600be4f38e2SAlex Deucher WREG32_P(mmSRBM_SOFT_RESET, mask, 601be4f38e2SAlex Deucher ~(SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK | 602be4f38e2SAlex Deucher SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK)); 603aaa36a97SAlex Deucher mdelay(5); 604aaa36a97SAlex Deucher 605aaa36a97SAlex Deucher return vce_v3_0_start(adev); 606aaa36a97SAlex Deucher } 607aaa36a97SAlex Deucher 6085fc3aeebSyanyang1 static void vce_v3_0_print_status(void *handle) 609aaa36a97SAlex Deucher { 6105fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 6115fc3aeebSyanyang1 612aaa36a97SAlex Deucher dev_info(adev->dev, "VCE 3.0 registers\n"); 613aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_STATUS=0x%08X\n", 614aaa36a97SAlex Deucher RREG32(mmVCE_STATUS)); 615aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_VCPU_CNTL=0x%08X\n", 616aaa36a97SAlex Deucher RREG32(mmVCE_VCPU_CNTL)); 617aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_VCPU_CACHE_OFFSET0=0x%08X\n", 618aaa36a97SAlex Deucher RREG32(mmVCE_VCPU_CACHE_OFFSET0)); 619aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_VCPU_CACHE_SIZE0=0x%08X\n", 620aaa36a97SAlex Deucher RREG32(mmVCE_VCPU_CACHE_SIZE0)); 621aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_VCPU_CACHE_OFFSET1=0x%08X\n", 622aaa36a97SAlex Deucher RREG32(mmVCE_VCPU_CACHE_OFFSET1)); 623aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_VCPU_CACHE_SIZE1=0x%08X\n", 624aaa36a97SAlex Deucher RREG32(mmVCE_VCPU_CACHE_SIZE1)); 625aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_VCPU_CACHE_OFFSET2=0x%08X\n", 626aaa36a97SAlex Deucher RREG32(mmVCE_VCPU_CACHE_OFFSET2)); 627aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_VCPU_CACHE_SIZE2=0x%08X\n", 628aaa36a97SAlex Deucher RREG32(mmVCE_VCPU_CACHE_SIZE2)); 629aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_SOFT_RESET=0x%08X\n", 630aaa36a97SAlex Deucher RREG32(mmVCE_SOFT_RESET)); 631aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_RB_BASE_LO2=0x%08X\n", 632aaa36a97SAlex Deucher RREG32(mmVCE_RB_BASE_LO2)); 633aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_RB_BASE_HI2=0x%08X\n", 634aaa36a97SAlex Deucher RREG32(mmVCE_RB_BASE_HI2)); 635aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_RB_SIZE2=0x%08X\n", 636aaa36a97SAlex Deucher RREG32(mmVCE_RB_SIZE2)); 637aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_RB_RPTR2=0x%08X\n", 638aaa36a97SAlex Deucher RREG32(mmVCE_RB_RPTR2)); 639aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_RB_WPTR2=0x%08X\n", 640aaa36a97SAlex Deucher RREG32(mmVCE_RB_WPTR2)); 641aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_RB_BASE_LO=0x%08X\n", 642aaa36a97SAlex Deucher RREG32(mmVCE_RB_BASE_LO)); 643aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_RB_BASE_HI=0x%08X\n", 644aaa36a97SAlex Deucher RREG32(mmVCE_RB_BASE_HI)); 645aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_RB_SIZE=0x%08X\n", 646aaa36a97SAlex Deucher RREG32(mmVCE_RB_SIZE)); 647aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_RB_RPTR=0x%08X\n", 648aaa36a97SAlex Deucher RREG32(mmVCE_RB_RPTR)); 649aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_RB_WPTR=0x%08X\n", 650aaa36a97SAlex Deucher RREG32(mmVCE_RB_WPTR)); 651aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_CLOCK_GATING_A=0x%08X\n", 652aaa36a97SAlex Deucher RREG32(mmVCE_CLOCK_GATING_A)); 653aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_CLOCK_GATING_B=0x%08X\n", 654aaa36a97SAlex Deucher RREG32(mmVCE_CLOCK_GATING_B)); 655aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_UENC_CLOCK_GATING=0x%08X\n", 656aaa36a97SAlex Deucher RREG32(mmVCE_UENC_CLOCK_GATING)); 657aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_UENC_REG_CLOCK_GATING=0x%08X\n", 658aaa36a97SAlex Deucher RREG32(mmVCE_UENC_REG_CLOCK_GATING)); 659aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_SYS_INT_EN=0x%08X\n", 660aaa36a97SAlex Deucher RREG32(mmVCE_SYS_INT_EN)); 661aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_LMI_CTRL2=0x%08X\n", 662aaa36a97SAlex Deucher RREG32(mmVCE_LMI_CTRL2)); 663aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_LMI_CTRL=0x%08X\n", 664aaa36a97SAlex Deucher RREG32(mmVCE_LMI_CTRL)); 665aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_LMI_VM_CTRL=0x%08X\n", 666aaa36a97SAlex Deucher RREG32(mmVCE_LMI_VM_CTRL)); 667aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_LMI_SWAP_CNTL=0x%08X\n", 668aaa36a97SAlex Deucher RREG32(mmVCE_LMI_SWAP_CNTL)); 669aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_LMI_SWAP_CNTL1=0x%08X\n", 670aaa36a97SAlex Deucher RREG32(mmVCE_LMI_SWAP_CNTL1)); 671aaa36a97SAlex Deucher dev_info(adev->dev, " VCE_LMI_CACHE_CTRL=0x%08X\n", 672aaa36a97SAlex Deucher RREG32(mmVCE_LMI_CACHE_CTRL)); 673aaa36a97SAlex Deucher } 674aaa36a97SAlex Deucher 675aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, 676aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 677aaa36a97SAlex Deucher unsigned type, 678aaa36a97SAlex Deucher enum amdgpu_interrupt_state state) 679aaa36a97SAlex Deucher { 680aaa36a97SAlex Deucher uint32_t val = 0; 681aaa36a97SAlex Deucher 682aaa36a97SAlex Deucher if (state == AMDGPU_IRQ_STATE_ENABLE) 683aaa36a97SAlex Deucher val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK; 684aaa36a97SAlex Deucher 685aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 686aaa36a97SAlex Deucher return 0; 687aaa36a97SAlex Deucher } 688aaa36a97SAlex Deucher 689aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev, 690aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 691aaa36a97SAlex Deucher struct amdgpu_iv_entry *entry) 692aaa36a97SAlex Deucher { 693aaa36a97SAlex Deucher DRM_DEBUG("IH: VCE\n"); 694d6c29c30SLeo Liu 695d6c29c30SLeo Liu WREG32_P(mmVCE_SYS_INT_STATUS, 696d6c29c30SLeo Liu VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK, 697d6c29c30SLeo Liu ~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK); 698d6c29c30SLeo Liu 699aaa36a97SAlex Deucher switch (entry->src_data) { 700aaa36a97SAlex Deucher case 0: 701aaa36a97SAlex Deucher amdgpu_fence_process(&adev->vce.ring[0]); 702aaa36a97SAlex Deucher break; 703aaa36a97SAlex Deucher case 1: 704aaa36a97SAlex Deucher amdgpu_fence_process(&adev->vce.ring[1]); 705aaa36a97SAlex Deucher break; 706aaa36a97SAlex Deucher default: 707aaa36a97SAlex Deucher DRM_ERROR("Unhandled interrupt: %d %d\n", 708aaa36a97SAlex Deucher entry->src_id, entry->src_data); 709aaa36a97SAlex Deucher break; 710aaa36a97SAlex Deucher } 711aaa36a97SAlex Deucher 712aaa36a97SAlex Deucher return 0; 713aaa36a97SAlex Deucher } 714aaa36a97SAlex Deucher 7155fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle, 7165fc3aeebSyanyang1 enum amd_clockgating_state state) 717aaa36a97SAlex Deucher { 7180689a570SEric Huang struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7190689a570SEric Huang bool enable = (state == AMD_CG_STATE_GATE) ? true : false; 7200689a570SEric Huang int i; 7210689a570SEric Huang 7220689a570SEric Huang if (!(adev->cg_flags & AMDGPU_CG_SUPPORT_VCE_MGCG)) 7230689a570SEric Huang return 0; 7240689a570SEric Huang 7250689a570SEric Huang mutex_lock(&adev->grbm_idx_mutex); 7260689a570SEric Huang for (i = 0; i < 2; i++) { 7270689a570SEric Huang /* Program VCE Instance 0 or 1 if not harvested */ 7280689a570SEric Huang if (adev->vce.harvest_config & (1 << i)) 7290689a570SEric Huang continue; 7300689a570SEric Huang 7310689a570SEric Huang if (i == 0) 7320689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 0, 7330689a570SEric Huang ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 7340689a570SEric Huang else 7350689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 7360689a570SEric Huang GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 7370689a570SEric Huang ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 7380689a570SEric Huang 7390689a570SEric Huang if (enable) { 7400689a570SEric Huang /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ 7410689a570SEric Huang uint32_t data = RREG32(mmVCE_CLOCK_GATING_A); 7420689a570SEric Huang data &= ~(0xf | 0xff0); 7430689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7440689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_A, data); 7450689a570SEric Huang 7460689a570SEric Huang /* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */ 7470689a570SEric Huang data = RREG32(mmVCE_UENC_CLOCK_GATING); 7480689a570SEric Huang data &= ~(0xf | 0xff0); 7490689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7500689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 7510689a570SEric Huang } 7520689a570SEric Huang 7530689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, enable); 7540689a570SEric Huang } 7550689a570SEric Huang 7560689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 7570689a570SEric Huang mutex_unlock(&adev->grbm_idx_mutex); 7580689a570SEric Huang 759aaa36a97SAlex Deucher return 0; 760aaa36a97SAlex Deucher } 761aaa36a97SAlex Deucher 7625fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle, 7635fc3aeebSyanyang1 enum amd_powergating_state state) 764aaa36a97SAlex Deucher { 765aaa36a97SAlex Deucher /* This doesn't actually powergate the VCE block. 766aaa36a97SAlex Deucher * That's done in the dpm code via the SMC. This 767aaa36a97SAlex Deucher * just re-inits the block as necessary. The actual 768aaa36a97SAlex Deucher * gating still happens in the dpm code. We should 769aaa36a97SAlex Deucher * revisit this when there is a cleaner line between 770aaa36a97SAlex Deucher * the smc and the hw blocks 771aaa36a97SAlex Deucher */ 7725fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7735fc3aeebSyanyang1 7745fc3aeebSyanyang1 if (state == AMD_PG_STATE_GATE) 775aaa36a97SAlex Deucher /* XXX do we need a vce_v3_0_stop()? */ 776aaa36a97SAlex Deucher return 0; 777aaa36a97SAlex Deucher else 778aaa36a97SAlex Deucher return vce_v3_0_start(adev); 779aaa36a97SAlex Deucher } 780aaa36a97SAlex Deucher 7815fc3aeebSyanyang1 const struct amd_ip_funcs vce_v3_0_ip_funcs = { 782aaa36a97SAlex Deucher .early_init = vce_v3_0_early_init, 783aaa36a97SAlex Deucher .late_init = NULL, 784aaa36a97SAlex Deucher .sw_init = vce_v3_0_sw_init, 785aaa36a97SAlex Deucher .sw_fini = vce_v3_0_sw_fini, 786aaa36a97SAlex Deucher .hw_init = vce_v3_0_hw_init, 787aaa36a97SAlex Deucher .hw_fini = vce_v3_0_hw_fini, 788aaa36a97SAlex Deucher .suspend = vce_v3_0_suspend, 789aaa36a97SAlex Deucher .resume = vce_v3_0_resume, 790aaa36a97SAlex Deucher .is_idle = vce_v3_0_is_idle, 791aaa36a97SAlex Deucher .wait_for_idle = vce_v3_0_wait_for_idle, 792aaa36a97SAlex Deucher .soft_reset = vce_v3_0_soft_reset, 793aaa36a97SAlex Deucher .print_status = vce_v3_0_print_status, 794aaa36a97SAlex Deucher .set_clockgating_state = vce_v3_0_set_clockgating_state, 795aaa36a97SAlex Deucher .set_powergating_state = vce_v3_0_set_powergating_state, 796aaa36a97SAlex Deucher }; 797aaa36a97SAlex Deucher 798aaa36a97SAlex Deucher static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = { 799aaa36a97SAlex Deucher .get_rptr = vce_v3_0_ring_get_rptr, 800aaa36a97SAlex Deucher .get_wptr = vce_v3_0_ring_get_wptr, 801aaa36a97SAlex Deucher .set_wptr = vce_v3_0_ring_set_wptr, 802aaa36a97SAlex Deucher .parse_cs = amdgpu_vce_ring_parse_cs, 803aaa36a97SAlex Deucher .emit_ib = amdgpu_vce_ring_emit_ib, 804aaa36a97SAlex Deucher .emit_fence = amdgpu_vce_ring_emit_fence, 805aaa36a97SAlex Deucher .emit_semaphore = amdgpu_vce_ring_emit_semaphore, 806aaa36a97SAlex Deucher .test_ring = amdgpu_vce_ring_test_ring, 807aaa36a97SAlex Deucher .test_ib = amdgpu_vce_ring_test_ib, 808edff0e28SJammy Zhou .insert_nop = amdgpu_ring_insert_nop, 809aaa36a97SAlex Deucher }; 810aaa36a97SAlex Deucher 811aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) 812aaa36a97SAlex Deucher { 813aaa36a97SAlex Deucher adev->vce.ring[0].funcs = &vce_v3_0_ring_funcs; 814aaa36a97SAlex Deucher adev->vce.ring[1].funcs = &vce_v3_0_ring_funcs; 815aaa36a97SAlex Deucher } 816aaa36a97SAlex Deucher 817aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = { 818aaa36a97SAlex Deucher .set = vce_v3_0_set_interrupt_state, 819aaa36a97SAlex Deucher .process = vce_v3_0_process_interrupt, 820aaa36a97SAlex Deucher }; 821aaa36a97SAlex Deucher 822aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev) 823aaa36a97SAlex Deucher { 824aaa36a97SAlex Deucher adev->vce.irq.num_types = 1; 825aaa36a97SAlex Deucher adev->vce.irq.funcs = &vce_v3_0_irq_funcs; 826aaa36a97SAlex Deucher }; 827