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; 1290689a570SEric Huang /* Set Override to disable Clock Gating */ 1300689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, true); 1310689a570SEric Huang 1320689a570SEric Huang if (!gated) { 1330689a570SEric Huang /* Force CLOCK ON for VCE_CLOCK_GATING_B, 1340689a570SEric Huang * {*_FORCE_ON, *_FORCE_OFF} = {1, 0} 1350689a570SEric Huang * VREG can be FORCE ON or set to Dynamic, but can't be OFF 1360689a570SEric Huang */ 1370689a570SEric Huang tmp = data = RREG32(mmVCE_CLOCK_GATING_B); 1380689a570SEric Huang data |= 0x1ff; 1390689a570SEric Huang data &= ~0xef0000; 1400689a570SEric Huang if (tmp != data) 1410689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1420689a570SEric Huang 1430689a570SEric Huang /* Force CLOCK ON for VCE_UENC_CLOCK_GATING, 1440689a570SEric Huang * {*_FORCE_ON, *_FORCE_OFF} = {1, 0} 1450689a570SEric Huang */ 1460689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); 1470689a570SEric Huang data |= 0x3ff000; 1480689a570SEric Huang data &= ~0xffc00000; 1490689a570SEric Huang if (tmp != data) 1500689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1510689a570SEric Huang 1520689a570SEric Huang /* set VCE_UENC_CLOCK_GATING_2 */ 1530689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1540689a570SEric Huang data |= 0x2; 1550689a570SEric Huang data &= ~0x2; 1560689a570SEric Huang if (tmp != data) 1570689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1580689a570SEric Huang 1590689a570SEric Huang /* Force CLOCK ON for VCE_UENC_REG_CLOCK_GATING */ 1600689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1610689a570SEric Huang data |= 0x37f; 1620689a570SEric Huang if (tmp != data) 1630689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1640689a570SEric Huang 1650689a570SEric Huang /* Force VCE_UENC_DMA_DCLK_CTRL Clock ON */ 1660689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1670689a570SEric Huang data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1680689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1690689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1700689a570SEric Huang 0x8; 1710689a570SEric Huang if (tmp != data) 1720689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1730689a570SEric Huang } else { 1740689a570SEric Huang /* Force CLOCK OFF for VCE_CLOCK_GATING_B, 1750689a570SEric Huang * {*, *_FORCE_OFF} = {*, 1} 1760689a570SEric Huang * set VREG to Dynamic, as it can't be OFF 1770689a570SEric Huang */ 1780689a570SEric Huang tmp = data = RREG32(mmVCE_CLOCK_GATING_B); 1790689a570SEric Huang data &= ~0x80010; 1800689a570SEric Huang data |= 0xe70008; 1810689a570SEric Huang if (tmp != data) 1820689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1830689a570SEric Huang /* Force CLOCK OFF for VCE_UENC_CLOCK_GATING, 1840689a570SEric Huang * Force ClOCK OFF takes precedent over Force CLOCK ON setting. 1850689a570SEric Huang * {*_FORCE_ON, *_FORCE_OFF} = {*, 1} 1860689a570SEric Huang */ 1870689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); 1880689a570SEric Huang data |= 0xffc00000; 1890689a570SEric Huang if (tmp != data) 1900689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1910689a570SEric Huang /* Set VCE_UENC_CLOCK_GATING_2 */ 1920689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1930689a570SEric Huang data |= 0x10000; 1940689a570SEric Huang if (tmp != data) 1950689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1960689a570SEric Huang /* Set VCE_UENC_REG_CLOCK_GATING to dynamic */ 1970689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1980689a570SEric Huang data &= ~0xffc00000; 1990689a570SEric Huang if (tmp != data) 2000689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 2010689a570SEric Huang /* Set VCE_UENC_DMA_DCLK_CTRL CG always in dynamic mode */ 2020689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 2030689a570SEric Huang data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 2040689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 2050689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 2060689a570SEric Huang 0x8); 2070689a570SEric Huang if (tmp != data) 2080689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 2090689a570SEric Huang } 2100689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, false); 2110689a570SEric Huang } 2120689a570SEric Huang 213567e6e29Sjimqu static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev) 214567e6e29Sjimqu { 215567e6e29Sjimqu int i, j; 216567e6e29Sjimqu 217567e6e29Sjimqu for (i = 0; i < 10; ++i) { 218567e6e29Sjimqu for (j = 0; j < 100; ++j) { 219b7e2e9f7Sjimqu uint32_t status = RREG32(mmVCE_STATUS); 220b7e2e9f7Sjimqu 221567e6e29Sjimqu if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK) 222567e6e29Sjimqu return 0; 223567e6e29Sjimqu mdelay(10); 224567e6e29Sjimqu } 225567e6e29Sjimqu 226567e6e29Sjimqu DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); 227567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 228567e6e29Sjimqu VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, 229567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 230567e6e29Sjimqu mdelay(10); 231567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 0, 232567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 233567e6e29Sjimqu mdelay(10); 234567e6e29Sjimqu } 235567e6e29Sjimqu 236567e6e29Sjimqu return -ETIMEDOUT; 237567e6e29Sjimqu } 238567e6e29Sjimqu 239aaa36a97SAlex Deucher /** 240aaa36a97SAlex Deucher * vce_v3_0_start - start VCE block 241aaa36a97SAlex Deucher * 242aaa36a97SAlex Deucher * @adev: amdgpu_device pointer 243aaa36a97SAlex Deucher * 244aaa36a97SAlex Deucher * Setup and start the VCE block 245aaa36a97SAlex Deucher */ 246aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev) 247aaa36a97SAlex Deucher { 248aaa36a97SAlex Deucher struct amdgpu_ring *ring; 249567e6e29Sjimqu int idx, r; 250567e6e29Sjimqu 251567e6e29Sjimqu ring = &adev->vce.ring[0]; 252567e6e29Sjimqu WREG32(mmVCE_RB_RPTR, ring->wptr); 253567e6e29Sjimqu WREG32(mmVCE_RB_WPTR, ring->wptr); 254567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr); 255567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); 256567e6e29Sjimqu WREG32(mmVCE_RB_SIZE, ring->ring_size / 4); 257567e6e29Sjimqu 258567e6e29Sjimqu ring = &adev->vce.ring[1]; 259567e6e29Sjimqu WREG32(mmVCE_RB_RPTR2, ring->wptr); 260567e6e29Sjimqu WREG32(mmVCE_RB_WPTR2, ring->wptr); 261567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr); 262567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); 263567e6e29Sjimqu WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4); 264aaa36a97SAlex Deucher 2655bbc553aSLeo Liu mutex_lock(&adev->grbm_idx_mutex); 2665bbc553aSLeo Liu for (idx = 0; idx < 2; ++idx) { 2676a585777SAlex Deucher if (adev->vce.harvest_config & (1 << idx)) 2686a585777SAlex Deucher continue; 2696a585777SAlex Deucher 2705bbc553aSLeo Liu if (idx == 0) 2715bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 0, 2725bbc553aSLeo Liu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2735bbc553aSLeo Liu else 2745bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 2755bbc553aSLeo Liu GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 2765bbc553aSLeo Liu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2775bbc553aSLeo Liu 2785bbc553aSLeo Liu vce_v3_0_mc_resume(adev, idx); 279aaa36a97SAlex Deucher 280567e6e29Sjimqu WREG32_P(mmVCE_STATUS, VCE_STATUS__JOB_BUSY_MASK, 281567e6e29Sjimqu ~VCE_STATUS__JOB_BUSY_MASK); 282567e6e29Sjimqu 2833c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) 2843c0ff9f1SLeo Liu WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001); 2853c0ff9f1SLeo Liu else 2865bbc553aSLeo Liu WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, 2875bbc553aSLeo Liu ~VCE_VCPU_CNTL__CLK_EN_MASK); 288aaa36a97SAlex Deucher 289567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 0, 290aaa36a97SAlex Deucher ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 291aaa36a97SAlex Deucher 292aaa36a97SAlex Deucher mdelay(100); 293aaa36a97SAlex Deucher 294567e6e29Sjimqu r = vce_v3_0_firmware_loaded(adev); 295aaa36a97SAlex Deucher 296aaa36a97SAlex Deucher /* clear BUSY flag */ 297567e6e29Sjimqu WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK); 298aaa36a97SAlex Deucher 2990689a570SEric Huang /* Set Clock-Gating off */ 300e3b04bc7SAlex Deucher if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) 3010689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, false); 3020689a570SEric Huang 303aaa36a97SAlex Deucher if (r) { 304aaa36a97SAlex Deucher DRM_ERROR("VCE not responding, giving up!!!\n"); 3055bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 306aaa36a97SAlex Deucher return r; 307aaa36a97SAlex Deucher } 3085bbc553aSLeo Liu } 3095bbc553aSLeo Liu 3105bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 3115bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 3125bbc553aSLeo Liu 313567e6e29Sjimqu return 0; 314567e6e29Sjimqu } 3155bbc553aSLeo Liu 316567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev) 317567e6e29Sjimqu { 318567e6e29Sjimqu int idx; 319567e6e29Sjimqu 320567e6e29Sjimqu mutex_lock(&adev->grbm_idx_mutex); 321567e6e29Sjimqu for (idx = 0; idx < 2; ++idx) { 322567e6e29Sjimqu if (adev->vce.harvest_config & (1 << idx)) 323567e6e29Sjimqu continue; 324567e6e29Sjimqu 325567e6e29Sjimqu if (idx == 0) 326567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 0, 327567e6e29Sjimqu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 328567e6e29Sjimqu else 329567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 330567e6e29Sjimqu GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 331567e6e29Sjimqu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 332567e6e29Sjimqu 333567e6e29Sjimqu if (adev->asic_type >= CHIP_STONEY) 334567e6e29Sjimqu WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001); 335567e6e29Sjimqu else 336567e6e29Sjimqu WREG32_P(mmVCE_VCPU_CNTL, 0, 337567e6e29Sjimqu ~VCE_VCPU_CNTL__CLK_EN_MASK); 338567e6e29Sjimqu /* hold on ECPU */ 339567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 340567e6e29Sjimqu VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, 341567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 342567e6e29Sjimqu 343567e6e29Sjimqu /* clear BUSY flag */ 344567e6e29Sjimqu WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK); 345567e6e29Sjimqu 346567e6e29Sjimqu /* Set Clock-Gating off */ 347567e6e29Sjimqu if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) 348567e6e29Sjimqu vce_v3_0_set_vce_sw_clock_gating(adev, false); 349567e6e29Sjimqu } 350567e6e29Sjimqu 351567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 352567e6e29Sjimqu mutex_unlock(&adev->grbm_idx_mutex); 353aaa36a97SAlex Deucher 354aaa36a97SAlex Deucher return 0; 355aaa36a97SAlex Deucher } 356aaa36a97SAlex Deucher 3576a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS 0xC0014074 3586a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT 27 3596a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK 0x18000000 3606a585777SAlex Deucher 3616a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) 3626a585777SAlex Deucher { 3636a585777SAlex Deucher u32 tmp; 3646a585777SAlex Deucher 3652cc0c0b5SFlora Cui /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */ 366cfaba566SSamuel Li if ((adev->asic_type == CHIP_FIJI) || 3671b4eeea5SSonny Jiang (adev->asic_type == CHIP_STONEY) || 3682cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS10) || 3692cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS11)) 3701dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 371188a9bcdSAlex Deucher 372188a9bcdSAlex Deucher /* Tonga and CZ are dual or single pipe */ 3732f7d10b3SJammy Zhou if (adev->flags & AMD_IS_APU) 3746a585777SAlex Deucher tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) & 3756a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__MASK) >> 3766a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__SHIFT; 3776a585777SAlex Deucher else 3786a585777SAlex Deucher tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) & 3796a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE_MASK) >> 3806a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE__SHIFT; 3816a585777SAlex Deucher 3826a585777SAlex Deucher switch (tmp) { 3836a585777SAlex Deucher case 1: 3841dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0; 3856a585777SAlex Deucher case 2: 3861dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 3876a585777SAlex Deucher case 3: 3881dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1; 3896a585777SAlex Deucher default: 3901dab5f06STom St Denis return 0; 3916a585777SAlex Deucher } 3926a585777SAlex Deucher } 3936a585777SAlex Deucher 3945fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle) 395aaa36a97SAlex Deucher { 3965fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 3975fc3aeebSyanyang1 3986a585777SAlex Deucher adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); 3996a585777SAlex Deucher 4006a585777SAlex Deucher if ((adev->vce.harvest_config & 4016a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) == 4026a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 4036a585777SAlex Deucher return -ENOENT; 4046a585777SAlex Deucher 405aaa36a97SAlex Deucher vce_v3_0_set_ring_funcs(adev); 406aaa36a97SAlex Deucher vce_v3_0_set_irq_funcs(adev); 407aaa36a97SAlex Deucher 408aaa36a97SAlex Deucher return 0; 409aaa36a97SAlex Deucher } 410aaa36a97SAlex Deucher 4115fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle) 412aaa36a97SAlex Deucher { 4135fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 414aaa36a97SAlex Deucher struct amdgpu_ring *ring; 415aaa36a97SAlex Deucher int r; 416aaa36a97SAlex Deucher 417aaa36a97SAlex Deucher /* VCE */ 418aaa36a97SAlex Deucher r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq); 419aaa36a97SAlex Deucher if (r) 420aaa36a97SAlex Deucher return r; 421aaa36a97SAlex Deucher 422e9822622SLeo Liu r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE + 423e9822622SLeo Liu (VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2); 424aaa36a97SAlex Deucher if (r) 425aaa36a97SAlex Deucher return r; 426aaa36a97SAlex Deucher 427aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 428aaa36a97SAlex Deucher if (r) 429aaa36a97SAlex Deucher return r; 430aaa36a97SAlex Deucher 431aaa36a97SAlex Deucher ring = &adev->vce.ring[0]; 432aaa36a97SAlex Deucher sprintf(ring->name, "vce0"); 433a3f1cf35SChristian König r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf, 434aaa36a97SAlex Deucher &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); 435aaa36a97SAlex Deucher if (r) 436aaa36a97SAlex Deucher return r; 437aaa36a97SAlex Deucher 438aaa36a97SAlex Deucher ring = &adev->vce.ring[1]; 439aaa36a97SAlex Deucher sprintf(ring->name, "vce1"); 440a3f1cf35SChristian König r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf, 441aaa36a97SAlex Deucher &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); 442aaa36a97SAlex Deucher if (r) 443aaa36a97SAlex Deucher return r; 444aaa36a97SAlex Deucher 445aaa36a97SAlex Deucher return r; 446aaa36a97SAlex Deucher } 447aaa36a97SAlex Deucher 4485fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle) 449aaa36a97SAlex Deucher { 450aaa36a97SAlex Deucher int r; 4515fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 452aaa36a97SAlex Deucher 453aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 454aaa36a97SAlex Deucher if (r) 455aaa36a97SAlex Deucher return r; 456aaa36a97SAlex Deucher 457aaa36a97SAlex Deucher r = amdgpu_vce_sw_fini(adev); 458aaa36a97SAlex Deucher if (r) 459aaa36a97SAlex Deucher return r; 460aaa36a97SAlex Deucher 461aaa36a97SAlex Deucher return r; 462aaa36a97SAlex Deucher } 463aaa36a97SAlex Deucher 4645fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle) 465aaa36a97SAlex Deucher { 466691ca86aSTom St Denis int r, i; 4675fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 468aaa36a97SAlex Deucher 469aaa36a97SAlex Deucher r = vce_v3_0_start(adev); 470aaa36a97SAlex Deucher if (r) 471aaa36a97SAlex Deucher return r; 472aaa36a97SAlex Deucher 473691ca86aSTom St Denis adev->vce.ring[0].ready = false; 474691ca86aSTom St Denis adev->vce.ring[1].ready = false; 475aaa36a97SAlex Deucher 476691ca86aSTom St Denis for (i = 0; i < 2; i++) { 477691ca86aSTom St Denis r = amdgpu_ring_test_ring(&adev->vce.ring[i]); 478691ca86aSTom St Denis if (r) 479aaa36a97SAlex Deucher return r; 480691ca86aSTom St Denis else 481691ca86aSTom St Denis adev->vce.ring[i].ready = true; 482aaa36a97SAlex Deucher } 483aaa36a97SAlex Deucher 484aaa36a97SAlex Deucher DRM_INFO("VCE initialized successfully.\n"); 485aaa36a97SAlex Deucher 486aaa36a97SAlex Deucher return 0; 487aaa36a97SAlex Deucher } 488aaa36a97SAlex Deucher 4895fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle) 490aaa36a97SAlex Deucher { 491567e6e29Sjimqu int r; 492567e6e29Sjimqu struct amdgpu_device *adev = (struct amdgpu_device *)handle; 493567e6e29Sjimqu 494567e6e29Sjimqu r = vce_v3_0_wait_for_idle(handle); 495567e6e29Sjimqu if (r) 496567e6e29Sjimqu return r; 497567e6e29Sjimqu 498567e6e29Sjimqu return vce_v3_0_stop(adev); 499aaa36a97SAlex Deucher } 500aaa36a97SAlex Deucher 5015fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle) 502aaa36a97SAlex Deucher { 503aaa36a97SAlex Deucher int r; 5045fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 505aaa36a97SAlex Deucher 506aaa36a97SAlex Deucher r = vce_v3_0_hw_fini(adev); 507aaa36a97SAlex Deucher if (r) 508aaa36a97SAlex Deucher return r; 509aaa36a97SAlex Deucher 510aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 511aaa36a97SAlex Deucher if (r) 512aaa36a97SAlex Deucher return r; 513aaa36a97SAlex Deucher 514aaa36a97SAlex Deucher return r; 515aaa36a97SAlex Deucher } 516aaa36a97SAlex Deucher 5175fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle) 518aaa36a97SAlex Deucher { 519aaa36a97SAlex Deucher int r; 5205fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 521aaa36a97SAlex Deucher 522aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 523aaa36a97SAlex Deucher if (r) 524aaa36a97SAlex Deucher return r; 525aaa36a97SAlex Deucher 526aaa36a97SAlex Deucher r = vce_v3_0_hw_init(adev); 527aaa36a97SAlex Deucher if (r) 528aaa36a97SAlex Deucher return r; 529aaa36a97SAlex Deucher 530aaa36a97SAlex Deucher return r; 531aaa36a97SAlex Deucher } 532aaa36a97SAlex Deucher 5335bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) 534aaa36a97SAlex Deucher { 535aaa36a97SAlex Deucher uint32_t offset, size; 536aaa36a97SAlex Deucher 537aaa36a97SAlex Deucher WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16)); 538aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); 539aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); 540aaa36a97SAlex Deucher WREG32(mmVCE_CLOCK_GATING_B, 0xf7); 541aaa36a97SAlex Deucher 542aaa36a97SAlex Deucher WREG32(mmVCE_LMI_CTRL, 0x00398000); 543aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1); 544aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL, 0); 545aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL1, 0); 546aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VM_CTRL, 0); 5473c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) { 5483c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8)); 5493c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8)); 5503c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8)); 5513c0ff9f1SLeo Liu } else 552aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8)); 553aaa36a97SAlex Deucher offset = AMDGPU_VCE_FIRMWARE_OFFSET; 554e9822622SLeo Liu size = VCE_V3_0_FW_SIZE; 555aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff); 556aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE0, size); 557aaa36a97SAlex Deucher 5585bbc553aSLeo Liu if (idx == 0) { 559aaa36a97SAlex Deucher offset += size; 560e9822622SLeo Liu size = VCE_V3_0_STACK_SIZE; 561aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff); 562aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 563aaa36a97SAlex Deucher offset += size; 564e9822622SLeo Liu size = VCE_V3_0_DATA_SIZE; 565aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff); 566aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5675bbc553aSLeo Liu } else { 5685bbc553aSLeo Liu offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE; 5695bbc553aSLeo Liu size = VCE_V3_0_STACK_SIZE; 5705bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff); 5715bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 5725bbc553aSLeo Liu offset += size; 5735bbc553aSLeo Liu size = VCE_V3_0_DATA_SIZE; 5745bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff); 5755bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5765bbc553aSLeo Liu } 577aaa36a97SAlex Deucher 578aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); 579aaa36a97SAlex Deucher 580aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK, 581aaa36a97SAlex Deucher ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 582aaa36a97SAlex Deucher } 583aaa36a97SAlex Deucher 5845fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle) 585aaa36a97SAlex Deucher { 5865fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 587be4f38e2SAlex Deucher u32 mask = 0; 5885fc3aeebSyanyang1 58974af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK; 59074af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK; 591be4f38e2SAlex Deucher 592be4f38e2SAlex Deucher return !(RREG32(mmSRBM_STATUS2) & mask); 593aaa36a97SAlex Deucher } 594aaa36a97SAlex Deucher 5955fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle) 596aaa36a97SAlex Deucher { 597aaa36a97SAlex Deucher unsigned i; 5985fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 599be4f38e2SAlex Deucher 60092988e60STom St Denis for (i = 0; i < adev->usec_timeout; i++) 60192988e60STom St Denis if (vce_v3_0_is_idle(handle)) 602aaa36a97SAlex Deucher return 0; 60392988e60STom St Denis 604aaa36a97SAlex Deucher return -ETIMEDOUT; 605aaa36a97SAlex Deucher } 606aaa36a97SAlex Deucher 607115933a5SChunming Zhou #define AMDGPU_VCE_STATUS_BUSY_MASK 0x78 608115933a5SChunming Zhou 609115933a5SChunming Zhou static int vce_v3_0_check_soft_reset(void *handle) 610115933a5SChunming Zhou { 611115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 612115933a5SChunming Zhou u32 srbm_soft_reset = 0; 613115933a5SChunming Zhou u32 tmp; 614115933a5SChunming Zhou 615115933a5SChunming Zhou /* VCE BUG: it is always busy, so skip its checking now */ 616115933a5SChunming Zhou return 0; 617115933a5SChunming Zhou 618115933a5SChunming Zhou /* According to VCE team , we should use VCE_STATUS instead 619115933a5SChunming Zhou * SRBM_STATUS.VCE_BUSY bit for busy status checking. 620115933a5SChunming Zhou * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE 621115933a5SChunming Zhou * instance's registers are accessed 622115933a5SChunming Zhou * (0 for 1st instance, 10 for 2nd instance). 623115933a5SChunming Zhou * 624115933a5SChunming Zhou *VCE_STATUS 625115933a5SChunming Zhou *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 | |FW_LOADED|JOB | 626115933a5SChunming Zhou *|----+----+-----------+----+----+----+----------+---------+----| 627115933a5SChunming Zhou *|bit8|bit7| bit6 |bit5|bit4|bit3| bit2 | bit1 |bit0| 628115933a5SChunming Zhou * 629115933a5SChunming Zhou * VCE team suggest use bit 3--bit 6 for busy status check 630115933a5SChunming Zhou */ 631115933a5SChunming Zhou tmp = RREG32(mmGRBM_GFX_INDEX); 632115933a5SChunming Zhou tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 633115933a5SChunming Zhou WREG32(mmGRBM_GFX_INDEX, tmp); 634115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 635115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 636115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 637115933a5SChunming Zhou } 638115933a5SChunming Zhou tmp = RREG32(mmGRBM_GFX_INDEX); 639115933a5SChunming Zhou tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10); 640115933a5SChunming Zhou WREG32(mmGRBM_GFX_INDEX, tmp); 641115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 642115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 643115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 644115933a5SChunming Zhou } 645115933a5SChunming Zhou tmp = RREG32(mmGRBM_GFX_INDEX); 646115933a5SChunming Zhou tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 647115933a5SChunming Zhou WREG32(mmGRBM_GFX_INDEX, tmp); 648115933a5SChunming Zhou 649115933a5SChunming Zhou if (adev->vce.harvest_config & (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 650115933a5SChunming Zhou srbm_soft_reset = 0; 651115933a5SChunming Zhou 652115933a5SChunming Zhou if (srbm_soft_reset) { 653115933a5SChunming Zhou adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = true; 654115933a5SChunming Zhou adev->vce.srbm_soft_reset = srbm_soft_reset; 655115933a5SChunming Zhou } else { 656115933a5SChunming Zhou adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = false; 657115933a5SChunming Zhou adev->vce.srbm_soft_reset = 0; 658115933a5SChunming Zhou } 659115933a5SChunming Zhou return 0; 660115933a5SChunming Zhou } 661115933a5SChunming Zhou 6625fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle) 663aaa36a97SAlex Deucher { 6645fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 665115933a5SChunming Zhou u32 srbm_soft_reset; 6665fc3aeebSyanyang1 667115933a5SChunming Zhou if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) 668115933a5SChunming Zhou return 0; 669115933a5SChunming Zhou srbm_soft_reset = adev->vce.srbm_soft_reset; 670be4f38e2SAlex Deucher 671115933a5SChunming Zhou if (srbm_soft_reset) { 672115933a5SChunming Zhou u32 tmp; 673115933a5SChunming Zhou 674115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 675115933a5SChunming Zhou tmp |= srbm_soft_reset; 676115933a5SChunming Zhou dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); 677115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 678115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 679115933a5SChunming Zhou 680115933a5SChunming Zhou udelay(50); 681115933a5SChunming Zhou 682115933a5SChunming Zhou tmp &= ~srbm_soft_reset; 683115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 684115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 685115933a5SChunming Zhou 686115933a5SChunming Zhou /* Wait a little for things to settle down */ 687115933a5SChunming Zhou udelay(50); 688115933a5SChunming Zhou } 689115933a5SChunming Zhou 690115933a5SChunming Zhou return 0; 691115933a5SChunming Zhou } 692115933a5SChunming Zhou 693115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle) 694115933a5SChunming Zhou { 695115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 696115933a5SChunming Zhou 697115933a5SChunming Zhou if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) 698115933a5SChunming Zhou return 0; 699115933a5SChunming Zhou 700aaa36a97SAlex Deucher mdelay(5); 701aaa36a97SAlex Deucher 702115933a5SChunming Zhou return vce_v3_0_suspend(adev); 703115933a5SChunming Zhou } 704115933a5SChunming Zhou 705115933a5SChunming Zhou 706115933a5SChunming Zhou static int vce_v3_0_post_soft_reset(void *handle) 707115933a5SChunming Zhou { 708115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 709115933a5SChunming Zhou 710115933a5SChunming Zhou if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) 711115933a5SChunming Zhou return 0; 712115933a5SChunming Zhou 713115933a5SChunming Zhou mdelay(5); 714115933a5SChunming Zhou 715115933a5SChunming Zhou return vce_v3_0_resume(adev); 716aaa36a97SAlex Deucher } 717aaa36a97SAlex Deucher 718aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, 719aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 720aaa36a97SAlex Deucher unsigned type, 721aaa36a97SAlex Deucher enum amdgpu_interrupt_state state) 722aaa36a97SAlex Deucher { 723aaa36a97SAlex Deucher uint32_t val = 0; 724aaa36a97SAlex Deucher 725aaa36a97SAlex Deucher if (state == AMDGPU_IRQ_STATE_ENABLE) 726aaa36a97SAlex Deucher val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK; 727aaa36a97SAlex Deucher 728aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 729aaa36a97SAlex Deucher return 0; 730aaa36a97SAlex Deucher } 731aaa36a97SAlex Deucher 732aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev, 733aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 734aaa36a97SAlex Deucher struct amdgpu_iv_entry *entry) 735aaa36a97SAlex Deucher { 736aaa36a97SAlex Deucher DRM_DEBUG("IH: VCE\n"); 737d6c29c30SLeo Liu 738d6c29c30SLeo Liu WREG32_P(mmVCE_SYS_INT_STATUS, 739d6c29c30SLeo Liu VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK, 740d6c29c30SLeo Liu ~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK); 741d6c29c30SLeo Liu 742aaa36a97SAlex Deucher switch (entry->src_data) { 743aaa36a97SAlex Deucher case 0: 744aaa36a97SAlex Deucher case 1: 74581da2edeSTom St Denis amdgpu_fence_process(&adev->vce.ring[entry->src_data]); 746aaa36a97SAlex Deucher break; 747aaa36a97SAlex Deucher default: 748aaa36a97SAlex Deucher DRM_ERROR("Unhandled interrupt: %d %d\n", 749aaa36a97SAlex Deucher entry->src_id, entry->src_data); 750aaa36a97SAlex Deucher break; 751aaa36a97SAlex Deucher } 752aaa36a97SAlex Deucher 753aaa36a97SAlex Deucher return 0; 754aaa36a97SAlex Deucher } 755aaa36a97SAlex Deucher 756ec38f188SRex Zhu static void vce_v3_set_bypass_mode(struct amdgpu_device *adev, bool enable) 757ec38f188SRex Zhu { 758ec38f188SRex Zhu u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL); 759ec38f188SRex Zhu 760ec38f188SRex Zhu if (enable) 761ec38f188SRex Zhu tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 762ec38f188SRex Zhu else 763ec38f188SRex Zhu tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 764ec38f188SRex Zhu 765ec38f188SRex Zhu WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp); 766ec38f188SRex Zhu } 767ec38f188SRex Zhu 7685fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle, 7695fc3aeebSyanyang1 enum amd_clockgating_state state) 770aaa36a97SAlex Deucher { 7710689a570SEric Huang struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7720689a570SEric Huang bool enable = (state == AMD_CG_STATE_GATE) ? true : false; 7730689a570SEric Huang int i; 7740689a570SEric Huang 775ec38f188SRex Zhu if (adev->asic_type == CHIP_POLARIS10) 776ec38f188SRex Zhu vce_v3_set_bypass_mode(adev, enable); 777ec38f188SRex Zhu 778e3b04bc7SAlex Deucher if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) 7790689a570SEric Huang return 0; 7800689a570SEric Huang 7810689a570SEric Huang mutex_lock(&adev->grbm_idx_mutex); 7820689a570SEric Huang for (i = 0; i < 2; i++) { 7830689a570SEric Huang /* Program VCE Instance 0 or 1 if not harvested */ 7840689a570SEric Huang if (adev->vce.harvest_config & (1 << i)) 7850689a570SEric Huang continue; 7860689a570SEric Huang 7870689a570SEric Huang if (i == 0) 7880689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 0, 7890689a570SEric Huang ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 7900689a570SEric Huang else 7910689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 7920689a570SEric Huang GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 7930689a570SEric Huang ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 7940689a570SEric Huang 7950689a570SEric Huang if (enable) { 7960689a570SEric Huang /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ 7970689a570SEric Huang uint32_t data = RREG32(mmVCE_CLOCK_GATING_A); 7980689a570SEric Huang data &= ~(0xf | 0xff0); 7990689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 8000689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_A, data); 8010689a570SEric Huang 8020689a570SEric Huang /* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */ 8030689a570SEric Huang data = RREG32(mmVCE_UENC_CLOCK_GATING); 8040689a570SEric Huang data &= ~(0xf | 0xff0); 8050689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 8060689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 8070689a570SEric Huang } 8080689a570SEric Huang 8090689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, enable); 8100689a570SEric Huang } 8110689a570SEric Huang 8120689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 8130689a570SEric Huang mutex_unlock(&adev->grbm_idx_mutex); 8140689a570SEric Huang 815aaa36a97SAlex Deucher return 0; 816aaa36a97SAlex Deucher } 817aaa36a97SAlex Deucher 8185fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle, 8195fc3aeebSyanyang1 enum amd_powergating_state state) 820aaa36a97SAlex Deucher { 821aaa36a97SAlex Deucher /* This doesn't actually powergate the VCE block. 822aaa36a97SAlex Deucher * That's done in the dpm code via the SMC. This 823aaa36a97SAlex Deucher * just re-inits the block as necessary. The actual 824aaa36a97SAlex Deucher * gating still happens in the dpm code. We should 825aaa36a97SAlex Deucher * revisit this when there is a cleaner line between 826aaa36a97SAlex Deucher * the smc and the hw blocks 827aaa36a97SAlex Deucher */ 8285fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 8295fc3aeebSyanyang1 830e3b04bc7SAlex Deucher if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE)) 831808a934fSAlex Deucher return 0; 832808a934fSAlex Deucher 8335fc3aeebSyanyang1 if (state == AMD_PG_STATE_GATE) 834aaa36a97SAlex Deucher /* XXX do we need a vce_v3_0_stop()? */ 835aaa36a97SAlex Deucher return 0; 836aaa36a97SAlex Deucher else 837aaa36a97SAlex Deucher return vce_v3_0_start(adev); 838aaa36a97SAlex Deucher } 839aaa36a97SAlex Deucher 8405fc3aeebSyanyang1 const struct amd_ip_funcs vce_v3_0_ip_funcs = { 84188a907d6STom St Denis .name = "vce_v3_0", 842aaa36a97SAlex Deucher .early_init = vce_v3_0_early_init, 843aaa36a97SAlex Deucher .late_init = NULL, 844aaa36a97SAlex Deucher .sw_init = vce_v3_0_sw_init, 845aaa36a97SAlex Deucher .sw_fini = vce_v3_0_sw_fini, 846aaa36a97SAlex Deucher .hw_init = vce_v3_0_hw_init, 847aaa36a97SAlex Deucher .hw_fini = vce_v3_0_hw_fini, 848aaa36a97SAlex Deucher .suspend = vce_v3_0_suspend, 849aaa36a97SAlex Deucher .resume = vce_v3_0_resume, 850aaa36a97SAlex Deucher .is_idle = vce_v3_0_is_idle, 851aaa36a97SAlex Deucher .wait_for_idle = vce_v3_0_wait_for_idle, 852115933a5SChunming Zhou .check_soft_reset = vce_v3_0_check_soft_reset, 853115933a5SChunming Zhou .pre_soft_reset = vce_v3_0_pre_soft_reset, 854aaa36a97SAlex Deucher .soft_reset = vce_v3_0_soft_reset, 855115933a5SChunming Zhou .post_soft_reset = vce_v3_0_post_soft_reset, 856aaa36a97SAlex Deucher .set_clockgating_state = vce_v3_0_set_clockgating_state, 857aaa36a97SAlex Deucher .set_powergating_state = vce_v3_0_set_powergating_state, 858aaa36a97SAlex Deucher }; 859aaa36a97SAlex Deucher 860aaa36a97SAlex Deucher static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = { 861aaa36a97SAlex Deucher .get_rptr = vce_v3_0_ring_get_rptr, 862aaa36a97SAlex Deucher .get_wptr = vce_v3_0_ring_get_wptr, 863aaa36a97SAlex Deucher .set_wptr = vce_v3_0_ring_set_wptr, 864aaa36a97SAlex Deucher .parse_cs = amdgpu_vce_ring_parse_cs, 865aaa36a97SAlex Deucher .emit_ib = amdgpu_vce_ring_emit_ib, 866aaa36a97SAlex Deucher .emit_fence = amdgpu_vce_ring_emit_fence, 867aaa36a97SAlex Deucher .test_ring = amdgpu_vce_ring_test_ring, 868aaa36a97SAlex Deucher .test_ib = amdgpu_vce_ring_test_ib, 869edff0e28SJammy Zhou .insert_nop = amdgpu_ring_insert_nop, 8709e5d5309SChristian König .pad_ib = amdgpu_ring_generic_pad_ib, 871ebff485eSChristian König .begin_use = amdgpu_vce_ring_begin_use, 872ebff485eSChristian König .end_use = amdgpu_vce_ring_end_use, 873aaa36a97SAlex Deucher }; 874aaa36a97SAlex Deucher 875aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) 876aaa36a97SAlex Deucher { 877aaa36a97SAlex Deucher adev->vce.ring[0].funcs = &vce_v3_0_ring_funcs; 878aaa36a97SAlex Deucher adev->vce.ring[1].funcs = &vce_v3_0_ring_funcs; 879aaa36a97SAlex Deucher } 880aaa36a97SAlex Deucher 881aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = { 882aaa36a97SAlex Deucher .set = vce_v3_0_set_interrupt_state, 883aaa36a97SAlex Deucher .process = vce_v3_0_process_interrupt, 884aaa36a97SAlex Deucher }; 885aaa36a97SAlex Deucher 886aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev) 887aaa36a97SAlex Deucher { 888aaa36a97SAlex Deucher adev->vce.irq.num_types = 1; 889aaa36a97SAlex Deucher adev->vce.irq.funcs = &vce_v3_0_irq_funcs; 890aaa36a97SAlex Deucher }; 891