1aaa36a97SAlex Deucher /* 2aaa36a97SAlex Deucher * Copyright 2014 Advanced Micro Devices, Inc. 3aaa36a97SAlex Deucher * All Rights Reserved. 4aaa36a97SAlex Deucher * 5aaa36a97SAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a 6aaa36a97SAlex Deucher * copy of this software and associated documentation files (the 7aaa36a97SAlex Deucher * "Software"), to deal in the Software without restriction, including 8aaa36a97SAlex Deucher * without limitation the rights to use, copy, modify, merge, publish, 9aaa36a97SAlex Deucher * distribute, sub license, and/or sell copies of the Software, and to 10aaa36a97SAlex Deucher * permit persons to whom the Software is furnished to do so, subject to 11aaa36a97SAlex Deucher * the following conditions: 12aaa36a97SAlex Deucher * 13aaa36a97SAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14aaa36a97SAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15aaa36a97SAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 16aaa36a97SAlex Deucher * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 17aaa36a97SAlex Deucher * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18aaa36a97SAlex Deucher * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 19aaa36a97SAlex Deucher * USE OR OTHER DEALINGS IN THE SOFTWARE. 20aaa36a97SAlex Deucher * 21aaa36a97SAlex Deucher * The above copyright notice and this permission notice (including the 22aaa36a97SAlex Deucher * next paragraph) shall be included in all copies or substantial portions 23aaa36a97SAlex Deucher * of the Software. 24aaa36a97SAlex Deucher * 25aaa36a97SAlex Deucher * Authors: Christian König <christian.koenig@amd.com> 26aaa36a97SAlex Deucher */ 27aaa36a97SAlex Deucher 28aaa36a97SAlex Deucher #include <linux/firmware.h> 29aaa36a97SAlex Deucher #include <drm/drmP.h> 30aaa36a97SAlex Deucher #include "amdgpu.h" 31aaa36a97SAlex Deucher #include "amdgpu_vce.h" 32aaa36a97SAlex Deucher #include "vid.h" 33aaa36a97SAlex Deucher #include "vce/vce_3_0_d.h" 34aaa36a97SAlex Deucher #include "vce/vce_3_0_sh_mask.h" 35be4f38e2SAlex Deucher #include "oss/oss_3_0_d.h" 36be4f38e2SAlex Deucher #include "oss/oss_3_0_sh_mask.h" 375bbc553aSLeo Liu #include "gca/gfx_8_0_d.h" 386a585777SAlex Deucher #include "smu/smu_7_1_2_d.h" 396a585777SAlex Deucher #include "smu/smu_7_1_2_sh_mask.h" 40115933a5SChunming Zhou #include "gca/gfx_8_0_d.h" 41115933a5SChunming Zhou #include "gca/gfx_8_0_sh_mask.h" 42115933a5SChunming Zhou 435bbc553aSLeo Liu 445bbc553aSLeo Liu #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04 455bbc553aSLeo Liu #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK 0x10 463c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0 0x8616 473c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1 0x8617 483c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2 0x8618 49567e6e29Sjimqu #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02 50aaa36a97SAlex Deucher 51e9822622SLeo Liu #define VCE_V3_0_FW_SIZE (384 * 1024) 52e9822622SLeo Liu #define VCE_V3_0_STACK_SIZE (64 * 1024) 53e9822622SLeo Liu #define VCE_V3_0_DATA_SIZE ((16 * 1024 * AMDGPU_MAX_VCE_HANDLES) + (52 * 1024)) 54e9822622SLeo Liu 555bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx); 56aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev); 57aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev); 58567e6e29Sjimqu static int vce_v3_0_wait_for_idle(void *handle); 59aaa36a97SAlex Deucher 60aaa36a97SAlex Deucher /** 61aaa36a97SAlex Deucher * vce_v3_0_ring_get_rptr - get read pointer 62aaa36a97SAlex Deucher * 63aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 64aaa36a97SAlex Deucher * 65aaa36a97SAlex Deucher * Returns the current hardware read pointer 66aaa36a97SAlex Deucher */ 67aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring) 68aaa36a97SAlex Deucher { 69aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 70aaa36a97SAlex Deucher 71aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 72aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR); 73aaa36a97SAlex Deucher else 74aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR2); 75aaa36a97SAlex Deucher } 76aaa36a97SAlex Deucher 77aaa36a97SAlex Deucher /** 78aaa36a97SAlex Deucher * vce_v3_0_ring_get_wptr - get write pointer 79aaa36a97SAlex Deucher * 80aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 81aaa36a97SAlex Deucher * 82aaa36a97SAlex Deucher * Returns the current hardware write pointer 83aaa36a97SAlex Deucher */ 84aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring) 85aaa36a97SAlex Deucher { 86aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 87aaa36a97SAlex Deucher 88aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 89aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR); 90aaa36a97SAlex Deucher else 91aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR2); 92aaa36a97SAlex Deucher } 93aaa36a97SAlex Deucher 94aaa36a97SAlex Deucher /** 95aaa36a97SAlex Deucher * vce_v3_0_ring_set_wptr - set write pointer 96aaa36a97SAlex Deucher * 97aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 98aaa36a97SAlex Deucher * 99aaa36a97SAlex Deucher * Commits the write pointer to the hardware 100aaa36a97SAlex Deucher */ 101aaa36a97SAlex Deucher static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring) 102aaa36a97SAlex Deucher { 103aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 104aaa36a97SAlex Deucher 105aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 106aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR, ring->wptr); 107aaa36a97SAlex Deucher else 108aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR2, ring->wptr); 109aaa36a97SAlex Deucher } 110aaa36a97SAlex Deucher 1110689a570SEric Huang static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override) 1120689a570SEric Huang { 1130689a570SEric Huang u32 tmp, data; 1140689a570SEric Huang 1150689a570SEric Huang tmp = data = RREG32(mmVCE_RB_ARB_CTRL); 1160689a570SEric Huang if (override) 1170689a570SEric Huang data |= VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; 1180689a570SEric Huang else 1190689a570SEric Huang data &= ~VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; 1200689a570SEric Huang 1210689a570SEric Huang if (tmp != data) 1220689a570SEric Huang WREG32(mmVCE_RB_ARB_CTRL, data); 1230689a570SEric Huang } 1240689a570SEric Huang 1250689a570SEric Huang static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, 1260689a570SEric Huang bool gated) 1270689a570SEric Huang { 1280689a570SEric Huang u32 tmp, data; 129f16fe6d3STom St Denis 1300689a570SEric Huang /* Set Override to disable Clock Gating */ 1310689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, true); 1320689a570SEric Huang 1330689a570SEric Huang if (!gated) { 1340689a570SEric Huang /* Force CLOCK ON for VCE_CLOCK_GATING_B, 1350689a570SEric Huang * {*_FORCE_ON, *_FORCE_OFF} = {1, 0} 1360689a570SEric Huang * VREG can be FORCE ON or set to Dynamic, but can't be OFF 1370689a570SEric Huang */ 1380689a570SEric Huang tmp = data = RREG32(mmVCE_CLOCK_GATING_B); 1390689a570SEric Huang data |= 0x1ff; 1400689a570SEric Huang data &= ~0xef0000; 1410689a570SEric Huang if (tmp != data) 1420689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1430689a570SEric Huang 1440689a570SEric Huang /* Force CLOCK ON for VCE_UENC_CLOCK_GATING, 1450689a570SEric Huang * {*_FORCE_ON, *_FORCE_OFF} = {1, 0} 1460689a570SEric Huang */ 1470689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); 1480689a570SEric Huang data |= 0x3ff000; 1490689a570SEric Huang data &= ~0xffc00000; 1500689a570SEric Huang if (tmp != data) 1510689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1520689a570SEric Huang 1530689a570SEric Huang /* set VCE_UENC_CLOCK_GATING_2 */ 1540689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1550689a570SEric Huang data |= 0x2; 1560689a570SEric Huang data &= ~0x2; 1570689a570SEric Huang if (tmp != data) 1580689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1590689a570SEric Huang 1600689a570SEric Huang /* Force CLOCK ON for VCE_UENC_REG_CLOCK_GATING */ 1610689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1620689a570SEric Huang data |= 0x37f; 1630689a570SEric Huang if (tmp != data) 1640689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1650689a570SEric Huang 1660689a570SEric Huang /* Force VCE_UENC_DMA_DCLK_CTRL Clock ON */ 1670689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1680689a570SEric Huang data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1690689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1700689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1710689a570SEric Huang 0x8; 1720689a570SEric Huang if (tmp != data) 1730689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1740689a570SEric Huang } else { 1750689a570SEric Huang /* Force CLOCK OFF for VCE_CLOCK_GATING_B, 1760689a570SEric Huang * {*, *_FORCE_OFF} = {*, 1} 1770689a570SEric Huang * set VREG to Dynamic, as it can't be OFF 1780689a570SEric Huang */ 1790689a570SEric Huang tmp = data = RREG32(mmVCE_CLOCK_GATING_B); 1800689a570SEric Huang data &= ~0x80010; 1810689a570SEric Huang data |= 0xe70008; 1820689a570SEric Huang if (tmp != data) 1830689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1840689a570SEric Huang /* Force CLOCK OFF for VCE_UENC_CLOCK_GATING, 1850689a570SEric Huang * Force ClOCK OFF takes precedent over Force CLOCK ON setting. 1860689a570SEric Huang * {*_FORCE_ON, *_FORCE_OFF} = {*, 1} 1870689a570SEric Huang */ 1880689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); 1890689a570SEric Huang data |= 0xffc00000; 1900689a570SEric Huang if (tmp != data) 1910689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1920689a570SEric Huang /* Set VCE_UENC_CLOCK_GATING_2 */ 1930689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1940689a570SEric Huang data |= 0x10000; 1950689a570SEric Huang if (tmp != data) 1960689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1970689a570SEric Huang /* Set VCE_UENC_REG_CLOCK_GATING to dynamic */ 1980689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1990689a570SEric Huang data &= ~0xffc00000; 2000689a570SEric Huang if (tmp != data) 2010689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 2020689a570SEric Huang /* Set VCE_UENC_DMA_DCLK_CTRL CG always in dynamic mode */ 2030689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 2040689a570SEric Huang data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 2050689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 2060689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 2070689a570SEric Huang 0x8); 2080689a570SEric Huang if (tmp != data) 2090689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 2100689a570SEric Huang } 2110689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, false); 2120689a570SEric Huang } 2130689a570SEric Huang 214567e6e29Sjimqu static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev) 215567e6e29Sjimqu { 216567e6e29Sjimqu int i, j; 217567e6e29Sjimqu 218567e6e29Sjimqu for (i = 0; i < 10; ++i) { 219567e6e29Sjimqu for (j = 0; j < 100; ++j) { 220b7e2e9f7Sjimqu uint32_t status = RREG32(mmVCE_STATUS); 221b7e2e9f7Sjimqu 222567e6e29Sjimqu if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK) 223567e6e29Sjimqu return 0; 224567e6e29Sjimqu mdelay(10); 225567e6e29Sjimqu } 226567e6e29Sjimqu 227567e6e29Sjimqu DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); 228567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 229567e6e29Sjimqu VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, 230567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 231567e6e29Sjimqu mdelay(10); 232567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 0, 233567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 234567e6e29Sjimqu mdelay(10); 235567e6e29Sjimqu } 236567e6e29Sjimqu 237567e6e29Sjimqu return -ETIMEDOUT; 238567e6e29Sjimqu } 239567e6e29Sjimqu 240aaa36a97SAlex Deucher /** 241aaa36a97SAlex Deucher * vce_v3_0_start - start VCE block 242aaa36a97SAlex Deucher * 243aaa36a97SAlex Deucher * @adev: amdgpu_device pointer 244aaa36a97SAlex Deucher * 245aaa36a97SAlex Deucher * Setup and start the VCE block 246aaa36a97SAlex Deucher */ 247aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev) 248aaa36a97SAlex Deucher { 249aaa36a97SAlex Deucher struct amdgpu_ring *ring; 250567e6e29Sjimqu int idx, r; 251567e6e29Sjimqu 252567e6e29Sjimqu ring = &adev->vce.ring[0]; 253567e6e29Sjimqu WREG32(mmVCE_RB_RPTR, ring->wptr); 254567e6e29Sjimqu WREG32(mmVCE_RB_WPTR, ring->wptr); 255567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr); 256567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); 257567e6e29Sjimqu WREG32(mmVCE_RB_SIZE, ring->ring_size / 4); 258567e6e29Sjimqu 259567e6e29Sjimqu ring = &adev->vce.ring[1]; 260567e6e29Sjimqu WREG32(mmVCE_RB_RPTR2, ring->wptr); 261567e6e29Sjimqu WREG32(mmVCE_RB_WPTR2, ring->wptr); 262567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr); 263567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); 264567e6e29Sjimqu WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4); 265aaa36a97SAlex Deucher 2665bbc553aSLeo Liu mutex_lock(&adev->grbm_idx_mutex); 2675bbc553aSLeo Liu for (idx = 0; idx < 2; ++idx) { 2686a585777SAlex Deucher if (adev->vce.harvest_config & (1 << idx)) 2696a585777SAlex Deucher continue; 2706a585777SAlex Deucher 2715bbc553aSLeo Liu if (idx == 0) 2725bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 0, 2735bbc553aSLeo Liu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2745bbc553aSLeo Liu else 2755bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 2765bbc553aSLeo Liu GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 2775bbc553aSLeo Liu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2785bbc553aSLeo Liu 2795bbc553aSLeo Liu vce_v3_0_mc_resume(adev, idx); 280aaa36a97SAlex Deucher 281567e6e29Sjimqu WREG32_P(mmVCE_STATUS, VCE_STATUS__JOB_BUSY_MASK, 282567e6e29Sjimqu ~VCE_STATUS__JOB_BUSY_MASK); 283567e6e29Sjimqu 2843c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) 2853c0ff9f1SLeo Liu WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001); 2863c0ff9f1SLeo Liu else 2875bbc553aSLeo Liu WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, 2885bbc553aSLeo Liu ~VCE_VCPU_CNTL__CLK_EN_MASK); 289aaa36a97SAlex Deucher 290567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 0, 291aaa36a97SAlex Deucher ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 292aaa36a97SAlex Deucher 293aaa36a97SAlex Deucher mdelay(100); 294aaa36a97SAlex Deucher 295567e6e29Sjimqu r = vce_v3_0_firmware_loaded(adev); 296aaa36a97SAlex Deucher 297aaa36a97SAlex Deucher /* clear BUSY flag */ 298567e6e29Sjimqu WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK); 299aaa36a97SAlex Deucher 3000689a570SEric Huang /* Set Clock-Gating off */ 301e3b04bc7SAlex Deucher if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) 3020689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, false); 3030689a570SEric Huang 304aaa36a97SAlex Deucher if (r) { 305aaa36a97SAlex Deucher DRM_ERROR("VCE not responding, giving up!!!\n"); 3065bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 307aaa36a97SAlex Deucher return r; 308aaa36a97SAlex Deucher } 3095bbc553aSLeo Liu } 3105bbc553aSLeo Liu 3115bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 3125bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 3135bbc553aSLeo Liu 314567e6e29Sjimqu return 0; 315567e6e29Sjimqu } 3165bbc553aSLeo Liu 317567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev) 318567e6e29Sjimqu { 319567e6e29Sjimqu int idx; 320567e6e29Sjimqu 321567e6e29Sjimqu mutex_lock(&adev->grbm_idx_mutex); 322567e6e29Sjimqu for (idx = 0; idx < 2; ++idx) { 323567e6e29Sjimqu if (adev->vce.harvest_config & (1 << idx)) 324567e6e29Sjimqu continue; 325567e6e29Sjimqu 326567e6e29Sjimqu if (idx == 0) 327567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 0, 328567e6e29Sjimqu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 329567e6e29Sjimqu else 330567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 331567e6e29Sjimqu GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 332567e6e29Sjimqu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 333567e6e29Sjimqu 334567e6e29Sjimqu if (adev->asic_type >= CHIP_STONEY) 335567e6e29Sjimqu WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001); 336567e6e29Sjimqu else 337567e6e29Sjimqu WREG32_P(mmVCE_VCPU_CNTL, 0, 338567e6e29Sjimqu ~VCE_VCPU_CNTL__CLK_EN_MASK); 339567e6e29Sjimqu /* hold on ECPU */ 340567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 341567e6e29Sjimqu VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, 342567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 343567e6e29Sjimqu 344567e6e29Sjimqu /* clear BUSY flag */ 345567e6e29Sjimqu WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK); 346567e6e29Sjimqu 347567e6e29Sjimqu /* Set Clock-Gating off */ 348567e6e29Sjimqu if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) 349567e6e29Sjimqu vce_v3_0_set_vce_sw_clock_gating(adev, false); 350567e6e29Sjimqu } 351567e6e29Sjimqu 352567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 353567e6e29Sjimqu mutex_unlock(&adev->grbm_idx_mutex); 354aaa36a97SAlex Deucher 355aaa36a97SAlex Deucher return 0; 356aaa36a97SAlex Deucher } 357aaa36a97SAlex Deucher 3586a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS 0xC0014074 3596a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT 27 3606a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK 0x18000000 3616a585777SAlex Deucher 3626a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) 3636a585777SAlex Deucher { 3646a585777SAlex Deucher u32 tmp; 3656a585777SAlex Deucher 3662cc0c0b5SFlora Cui /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */ 367cfaba566SSamuel Li if ((adev->asic_type == CHIP_FIJI) || 3681b4eeea5SSonny Jiang (adev->asic_type == CHIP_STONEY) || 3692cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS10) || 3702cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS11)) 3711dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 372188a9bcdSAlex Deucher 373188a9bcdSAlex Deucher /* Tonga and CZ are dual or single pipe */ 3742f7d10b3SJammy Zhou if (adev->flags & AMD_IS_APU) 3756a585777SAlex Deucher tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) & 3766a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__MASK) >> 3776a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__SHIFT; 3786a585777SAlex Deucher else 3796a585777SAlex Deucher tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) & 3806a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE_MASK) >> 3816a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE__SHIFT; 3826a585777SAlex Deucher 3836a585777SAlex Deucher switch (tmp) { 3846a585777SAlex Deucher case 1: 3851dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0; 3866a585777SAlex Deucher case 2: 3871dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 3886a585777SAlex Deucher case 3: 3891dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1; 3906a585777SAlex Deucher default: 3911dab5f06STom St Denis return 0; 3926a585777SAlex Deucher } 3936a585777SAlex Deucher } 3946a585777SAlex Deucher 3955fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle) 396aaa36a97SAlex Deucher { 3975fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 3985fc3aeebSyanyang1 3996a585777SAlex Deucher adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); 4006a585777SAlex Deucher 4016a585777SAlex Deucher if ((adev->vce.harvest_config & 4026a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) == 4036a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 4046a585777SAlex Deucher return -ENOENT; 4056a585777SAlex Deucher 406aaa36a97SAlex Deucher vce_v3_0_set_ring_funcs(adev); 407aaa36a97SAlex Deucher vce_v3_0_set_irq_funcs(adev); 408aaa36a97SAlex Deucher 409aaa36a97SAlex Deucher return 0; 410aaa36a97SAlex Deucher } 411aaa36a97SAlex Deucher 4125fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle) 413aaa36a97SAlex Deucher { 4145fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 415aaa36a97SAlex Deucher struct amdgpu_ring *ring; 416aaa36a97SAlex Deucher int r; 417aaa36a97SAlex Deucher 418aaa36a97SAlex Deucher /* VCE */ 419aaa36a97SAlex Deucher r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq); 420aaa36a97SAlex Deucher if (r) 421aaa36a97SAlex Deucher return r; 422aaa36a97SAlex Deucher 423e9822622SLeo Liu r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE + 424e9822622SLeo Liu (VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2); 425aaa36a97SAlex Deucher if (r) 426aaa36a97SAlex Deucher return r; 427aaa36a97SAlex Deucher 428aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 429aaa36a97SAlex Deucher if (r) 430aaa36a97SAlex Deucher return r; 431aaa36a97SAlex Deucher 432aaa36a97SAlex Deucher ring = &adev->vce.ring[0]; 433aaa36a97SAlex Deucher sprintf(ring->name, "vce0"); 434a3f1cf35SChristian König r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf, 435aaa36a97SAlex Deucher &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); 436aaa36a97SAlex Deucher if (r) 437aaa36a97SAlex Deucher return r; 438aaa36a97SAlex Deucher 439aaa36a97SAlex Deucher ring = &adev->vce.ring[1]; 440aaa36a97SAlex Deucher sprintf(ring->name, "vce1"); 441a3f1cf35SChristian König r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf, 442aaa36a97SAlex Deucher &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); 443aaa36a97SAlex Deucher if (r) 444aaa36a97SAlex Deucher return r; 445aaa36a97SAlex Deucher 446aaa36a97SAlex Deucher return r; 447aaa36a97SAlex Deucher } 448aaa36a97SAlex Deucher 4495fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle) 450aaa36a97SAlex Deucher { 451aaa36a97SAlex Deucher int r; 4525fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 453aaa36a97SAlex Deucher 454aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 455aaa36a97SAlex Deucher if (r) 456aaa36a97SAlex Deucher return r; 457aaa36a97SAlex Deucher 458aaa36a97SAlex Deucher r = amdgpu_vce_sw_fini(adev); 459aaa36a97SAlex Deucher if (r) 460aaa36a97SAlex Deucher return r; 461aaa36a97SAlex Deucher 462aaa36a97SAlex Deucher return r; 463aaa36a97SAlex Deucher } 464aaa36a97SAlex Deucher 4655fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle) 466aaa36a97SAlex Deucher { 467691ca86aSTom St Denis int r, i; 4685fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 469aaa36a97SAlex Deucher 470aaa36a97SAlex Deucher r = vce_v3_0_start(adev); 471aaa36a97SAlex Deucher if (r) 472aaa36a97SAlex Deucher return r; 473aaa36a97SAlex Deucher 474691ca86aSTom St Denis adev->vce.ring[0].ready = false; 475691ca86aSTom St Denis adev->vce.ring[1].ready = false; 476aaa36a97SAlex Deucher 477691ca86aSTom St Denis for (i = 0; i < 2; i++) { 478691ca86aSTom St Denis r = amdgpu_ring_test_ring(&adev->vce.ring[i]); 479691ca86aSTom St Denis if (r) 480aaa36a97SAlex Deucher return r; 481691ca86aSTom St Denis else 482691ca86aSTom St Denis adev->vce.ring[i].ready = true; 483aaa36a97SAlex Deucher } 484aaa36a97SAlex Deucher 485aaa36a97SAlex Deucher DRM_INFO("VCE initialized successfully.\n"); 486aaa36a97SAlex Deucher 487aaa36a97SAlex Deucher return 0; 488aaa36a97SAlex Deucher } 489aaa36a97SAlex Deucher 4905fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle) 491aaa36a97SAlex Deucher { 492567e6e29Sjimqu int r; 493567e6e29Sjimqu struct amdgpu_device *adev = (struct amdgpu_device *)handle; 494567e6e29Sjimqu 495567e6e29Sjimqu r = vce_v3_0_wait_for_idle(handle); 496567e6e29Sjimqu if (r) 497567e6e29Sjimqu return r; 498567e6e29Sjimqu 499567e6e29Sjimqu return vce_v3_0_stop(adev); 500aaa36a97SAlex Deucher } 501aaa36a97SAlex Deucher 5025fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle) 503aaa36a97SAlex Deucher { 504aaa36a97SAlex Deucher int r; 5055fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 506aaa36a97SAlex Deucher 507aaa36a97SAlex Deucher r = vce_v3_0_hw_fini(adev); 508aaa36a97SAlex Deucher if (r) 509aaa36a97SAlex Deucher return r; 510aaa36a97SAlex Deucher 511aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 512aaa36a97SAlex Deucher if (r) 513aaa36a97SAlex Deucher return r; 514aaa36a97SAlex Deucher 515aaa36a97SAlex Deucher return r; 516aaa36a97SAlex Deucher } 517aaa36a97SAlex Deucher 5185fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle) 519aaa36a97SAlex Deucher { 520aaa36a97SAlex Deucher int r; 5215fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 522aaa36a97SAlex Deucher 523aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 524aaa36a97SAlex Deucher if (r) 525aaa36a97SAlex Deucher return r; 526aaa36a97SAlex Deucher 527aaa36a97SAlex Deucher r = vce_v3_0_hw_init(adev); 528aaa36a97SAlex Deucher if (r) 529aaa36a97SAlex Deucher return r; 530aaa36a97SAlex Deucher 531aaa36a97SAlex Deucher return r; 532aaa36a97SAlex Deucher } 533aaa36a97SAlex Deucher 5345bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) 535aaa36a97SAlex Deucher { 536aaa36a97SAlex Deucher uint32_t offset, size; 537aaa36a97SAlex Deucher 538aaa36a97SAlex Deucher WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16)); 539aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); 540aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); 541aaa36a97SAlex Deucher WREG32(mmVCE_CLOCK_GATING_B, 0xf7); 542aaa36a97SAlex Deucher 543aaa36a97SAlex Deucher WREG32(mmVCE_LMI_CTRL, 0x00398000); 544aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1); 545aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL, 0); 546aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL1, 0); 547aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VM_CTRL, 0); 5483c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) { 5493c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8)); 5503c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8)); 5513c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8)); 5523c0ff9f1SLeo Liu } else 553aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8)); 554aaa36a97SAlex Deucher offset = AMDGPU_VCE_FIRMWARE_OFFSET; 555e9822622SLeo Liu size = VCE_V3_0_FW_SIZE; 556aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff); 557aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE0, size); 558aaa36a97SAlex Deucher 5595bbc553aSLeo Liu if (idx == 0) { 560aaa36a97SAlex Deucher offset += size; 561e9822622SLeo Liu size = VCE_V3_0_STACK_SIZE; 562aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff); 563aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 564aaa36a97SAlex Deucher offset += size; 565e9822622SLeo Liu size = VCE_V3_0_DATA_SIZE; 566aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff); 567aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5685bbc553aSLeo Liu } else { 5695bbc553aSLeo Liu offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE; 5705bbc553aSLeo Liu size = VCE_V3_0_STACK_SIZE; 5715bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff); 5725bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 5735bbc553aSLeo Liu offset += size; 5745bbc553aSLeo Liu size = VCE_V3_0_DATA_SIZE; 5755bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff); 5765bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5775bbc553aSLeo Liu } 578aaa36a97SAlex Deucher 579aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); 580aaa36a97SAlex Deucher 581aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK, 582aaa36a97SAlex Deucher ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 583aaa36a97SAlex Deucher } 584aaa36a97SAlex Deucher 5855fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle) 586aaa36a97SAlex Deucher { 5875fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 588be4f38e2SAlex Deucher u32 mask = 0; 5895fc3aeebSyanyang1 59074af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK; 59174af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK; 592be4f38e2SAlex Deucher 593be4f38e2SAlex Deucher return !(RREG32(mmSRBM_STATUS2) & mask); 594aaa36a97SAlex Deucher } 595aaa36a97SAlex Deucher 5965fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle) 597aaa36a97SAlex Deucher { 598aaa36a97SAlex Deucher unsigned i; 5995fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 600be4f38e2SAlex Deucher 60192988e60STom St Denis for (i = 0; i < adev->usec_timeout; i++) 60292988e60STom St Denis if (vce_v3_0_is_idle(handle)) 603aaa36a97SAlex Deucher return 0; 60492988e60STom St Denis 605aaa36a97SAlex Deucher return -ETIMEDOUT; 606aaa36a97SAlex Deucher } 607aaa36a97SAlex Deucher 608115933a5SChunming Zhou #define AMDGPU_VCE_STATUS_BUSY_MASK 0x78 609115933a5SChunming Zhou 610115933a5SChunming Zhou static int vce_v3_0_check_soft_reset(void *handle) 611115933a5SChunming Zhou { 612115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 613115933a5SChunming Zhou u32 srbm_soft_reset = 0; 614115933a5SChunming Zhou u32 tmp; 615115933a5SChunming Zhou 616115933a5SChunming Zhou /* VCE BUG: it is always busy, so skip its checking now */ 617115933a5SChunming Zhou return 0; 618115933a5SChunming Zhou 619115933a5SChunming Zhou /* According to VCE team , we should use VCE_STATUS instead 620115933a5SChunming Zhou * SRBM_STATUS.VCE_BUSY bit for busy status checking. 621115933a5SChunming Zhou * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE 622115933a5SChunming Zhou * instance's registers are accessed 623115933a5SChunming Zhou * (0 for 1st instance, 10 for 2nd instance). 624115933a5SChunming Zhou * 625115933a5SChunming Zhou *VCE_STATUS 626115933a5SChunming Zhou *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 | |FW_LOADED|JOB | 627115933a5SChunming Zhou *|----+----+-----------+----+----+----+----------+---------+----| 628115933a5SChunming Zhou *|bit8|bit7| bit6 |bit5|bit4|bit3| bit2 | bit1 |bit0| 629115933a5SChunming Zhou * 630115933a5SChunming Zhou * VCE team suggest use bit 3--bit 6 for busy status check 631115933a5SChunming Zhou */ 632115933a5SChunming Zhou tmp = RREG32(mmGRBM_GFX_INDEX); 633115933a5SChunming Zhou tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 634115933a5SChunming Zhou WREG32(mmGRBM_GFX_INDEX, tmp); 635115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 636115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 637115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 638115933a5SChunming Zhou } 639115933a5SChunming Zhou tmp = RREG32(mmGRBM_GFX_INDEX); 640115933a5SChunming Zhou tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10); 641115933a5SChunming Zhou WREG32(mmGRBM_GFX_INDEX, tmp); 642115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 643115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 644115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 645115933a5SChunming Zhou } 646115933a5SChunming Zhou tmp = RREG32(mmGRBM_GFX_INDEX); 647115933a5SChunming Zhou tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 648115933a5SChunming Zhou WREG32(mmGRBM_GFX_INDEX, tmp); 649115933a5SChunming Zhou 650115933a5SChunming Zhou if (adev->vce.harvest_config & (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 651115933a5SChunming Zhou srbm_soft_reset = 0; 652115933a5SChunming Zhou 653115933a5SChunming Zhou if (srbm_soft_reset) { 654115933a5SChunming Zhou adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = true; 655115933a5SChunming Zhou adev->vce.srbm_soft_reset = srbm_soft_reset; 656115933a5SChunming Zhou } else { 657115933a5SChunming Zhou adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = false; 658115933a5SChunming Zhou adev->vce.srbm_soft_reset = 0; 659115933a5SChunming Zhou } 660115933a5SChunming Zhou return 0; 661115933a5SChunming Zhou } 662115933a5SChunming Zhou 6635fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle) 664aaa36a97SAlex Deucher { 6655fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 666115933a5SChunming Zhou u32 srbm_soft_reset; 6675fc3aeebSyanyang1 668115933a5SChunming Zhou if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) 669115933a5SChunming Zhou return 0; 670115933a5SChunming Zhou srbm_soft_reset = adev->vce.srbm_soft_reset; 671be4f38e2SAlex Deucher 672115933a5SChunming Zhou if (srbm_soft_reset) { 673115933a5SChunming Zhou u32 tmp; 674115933a5SChunming Zhou 675115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 676115933a5SChunming Zhou tmp |= srbm_soft_reset; 677115933a5SChunming Zhou dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); 678115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 679115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 680115933a5SChunming Zhou 681115933a5SChunming Zhou udelay(50); 682115933a5SChunming Zhou 683115933a5SChunming Zhou tmp &= ~srbm_soft_reset; 684115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 685115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 686115933a5SChunming Zhou 687115933a5SChunming Zhou /* Wait a little for things to settle down */ 688115933a5SChunming Zhou udelay(50); 689115933a5SChunming Zhou } 690115933a5SChunming Zhou 691115933a5SChunming Zhou return 0; 692115933a5SChunming Zhou } 693115933a5SChunming Zhou 694115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle) 695115933a5SChunming Zhou { 696115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 697115933a5SChunming Zhou 698115933a5SChunming Zhou if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) 699115933a5SChunming Zhou return 0; 700115933a5SChunming Zhou 701aaa36a97SAlex Deucher mdelay(5); 702aaa36a97SAlex Deucher 703115933a5SChunming Zhou return vce_v3_0_suspend(adev); 704115933a5SChunming Zhou } 705115933a5SChunming Zhou 706115933a5SChunming Zhou 707115933a5SChunming Zhou static int vce_v3_0_post_soft_reset(void *handle) 708115933a5SChunming Zhou { 709115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 710115933a5SChunming Zhou 711115933a5SChunming Zhou if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) 712115933a5SChunming Zhou return 0; 713115933a5SChunming Zhou 714115933a5SChunming Zhou mdelay(5); 715115933a5SChunming Zhou 716115933a5SChunming Zhou return vce_v3_0_resume(adev); 717aaa36a97SAlex Deucher } 718aaa36a97SAlex Deucher 719aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, 720aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 721aaa36a97SAlex Deucher unsigned type, 722aaa36a97SAlex Deucher enum amdgpu_interrupt_state state) 723aaa36a97SAlex Deucher { 724aaa36a97SAlex Deucher uint32_t val = 0; 725aaa36a97SAlex Deucher 726aaa36a97SAlex Deucher if (state == AMDGPU_IRQ_STATE_ENABLE) 727aaa36a97SAlex Deucher val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK; 728aaa36a97SAlex Deucher 729aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 730aaa36a97SAlex Deucher return 0; 731aaa36a97SAlex Deucher } 732aaa36a97SAlex Deucher 733aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev, 734aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 735aaa36a97SAlex Deucher struct amdgpu_iv_entry *entry) 736aaa36a97SAlex Deucher { 737aaa36a97SAlex Deucher DRM_DEBUG("IH: VCE\n"); 738d6c29c30SLeo Liu 739d6c29c30SLeo Liu WREG32_P(mmVCE_SYS_INT_STATUS, 740d6c29c30SLeo Liu VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK, 741d6c29c30SLeo Liu ~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK); 742d6c29c30SLeo Liu 743aaa36a97SAlex Deucher switch (entry->src_data) { 744aaa36a97SAlex Deucher case 0: 745aaa36a97SAlex Deucher case 1: 74681da2edeSTom St Denis amdgpu_fence_process(&adev->vce.ring[entry->src_data]); 747aaa36a97SAlex Deucher break; 748aaa36a97SAlex Deucher default: 749aaa36a97SAlex Deucher DRM_ERROR("Unhandled interrupt: %d %d\n", 750aaa36a97SAlex Deucher entry->src_id, entry->src_data); 751aaa36a97SAlex Deucher break; 752aaa36a97SAlex Deucher } 753aaa36a97SAlex Deucher 754aaa36a97SAlex Deucher return 0; 755aaa36a97SAlex Deucher } 756aaa36a97SAlex Deucher 757ec38f188SRex Zhu static void vce_v3_set_bypass_mode(struct amdgpu_device *adev, bool enable) 758ec38f188SRex Zhu { 759ec38f188SRex Zhu u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL); 760ec38f188SRex Zhu 761ec38f188SRex Zhu if (enable) 762ec38f188SRex Zhu tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 763ec38f188SRex Zhu else 764ec38f188SRex Zhu tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 765ec38f188SRex Zhu 766ec38f188SRex Zhu WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp); 767ec38f188SRex Zhu } 768ec38f188SRex Zhu 7695fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle, 7705fc3aeebSyanyang1 enum amd_clockgating_state state) 771aaa36a97SAlex Deucher { 7720689a570SEric Huang struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7730689a570SEric Huang bool enable = (state == AMD_CG_STATE_GATE) ? true : false; 7740689a570SEric Huang int i; 7750689a570SEric Huang 776ec38f188SRex Zhu if (adev->asic_type == CHIP_POLARIS10) 777ec38f188SRex Zhu vce_v3_set_bypass_mode(adev, enable); 778ec38f188SRex Zhu 779e3b04bc7SAlex Deucher if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) 7800689a570SEric Huang return 0; 7810689a570SEric Huang 7820689a570SEric Huang mutex_lock(&adev->grbm_idx_mutex); 7830689a570SEric Huang for (i = 0; i < 2; i++) { 7840689a570SEric Huang /* Program VCE Instance 0 or 1 if not harvested */ 7850689a570SEric Huang if (adev->vce.harvest_config & (1 << i)) 7860689a570SEric Huang continue; 7870689a570SEric Huang 7880689a570SEric Huang if (i == 0) 7890689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 0, 7900689a570SEric Huang ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 7910689a570SEric Huang else 7920689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 7930689a570SEric Huang GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 7940689a570SEric Huang ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 7950689a570SEric Huang 7960689a570SEric Huang if (enable) { 7970689a570SEric Huang /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ 7980689a570SEric Huang uint32_t data = RREG32(mmVCE_CLOCK_GATING_A); 7990689a570SEric Huang data &= ~(0xf | 0xff0); 8000689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 8010689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_A, data); 8020689a570SEric Huang 8030689a570SEric Huang /* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */ 8040689a570SEric Huang data = RREG32(mmVCE_UENC_CLOCK_GATING); 8050689a570SEric Huang data &= ~(0xf | 0xff0); 8060689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 8070689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 8080689a570SEric Huang } 8090689a570SEric Huang 8100689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, enable); 8110689a570SEric Huang } 8120689a570SEric Huang 8130689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 8140689a570SEric Huang mutex_unlock(&adev->grbm_idx_mutex); 8150689a570SEric Huang 816aaa36a97SAlex Deucher return 0; 817aaa36a97SAlex Deucher } 818aaa36a97SAlex Deucher 8195fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle, 8205fc3aeebSyanyang1 enum amd_powergating_state state) 821aaa36a97SAlex Deucher { 822aaa36a97SAlex Deucher /* This doesn't actually powergate the VCE block. 823aaa36a97SAlex Deucher * That's done in the dpm code via the SMC. This 824aaa36a97SAlex Deucher * just re-inits the block as necessary. The actual 825aaa36a97SAlex Deucher * gating still happens in the dpm code. We should 826aaa36a97SAlex Deucher * revisit this when there is a cleaner line between 827aaa36a97SAlex Deucher * the smc and the hw blocks 828aaa36a97SAlex Deucher */ 8295fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 8305fc3aeebSyanyang1 831e3b04bc7SAlex Deucher if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE)) 832808a934fSAlex Deucher return 0; 833808a934fSAlex Deucher 8345fc3aeebSyanyang1 if (state == AMD_PG_STATE_GATE) 835aaa36a97SAlex Deucher /* XXX do we need a vce_v3_0_stop()? */ 836aaa36a97SAlex Deucher return 0; 837aaa36a97SAlex Deucher else 838aaa36a97SAlex Deucher return vce_v3_0_start(adev); 839aaa36a97SAlex Deucher } 840aaa36a97SAlex Deucher 8415fc3aeebSyanyang1 const struct amd_ip_funcs vce_v3_0_ip_funcs = { 84288a907d6STom St Denis .name = "vce_v3_0", 843aaa36a97SAlex Deucher .early_init = vce_v3_0_early_init, 844aaa36a97SAlex Deucher .late_init = NULL, 845aaa36a97SAlex Deucher .sw_init = vce_v3_0_sw_init, 846aaa36a97SAlex Deucher .sw_fini = vce_v3_0_sw_fini, 847aaa36a97SAlex Deucher .hw_init = vce_v3_0_hw_init, 848aaa36a97SAlex Deucher .hw_fini = vce_v3_0_hw_fini, 849aaa36a97SAlex Deucher .suspend = vce_v3_0_suspend, 850aaa36a97SAlex Deucher .resume = vce_v3_0_resume, 851aaa36a97SAlex Deucher .is_idle = vce_v3_0_is_idle, 852aaa36a97SAlex Deucher .wait_for_idle = vce_v3_0_wait_for_idle, 853115933a5SChunming Zhou .check_soft_reset = vce_v3_0_check_soft_reset, 854115933a5SChunming Zhou .pre_soft_reset = vce_v3_0_pre_soft_reset, 855aaa36a97SAlex Deucher .soft_reset = vce_v3_0_soft_reset, 856115933a5SChunming Zhou .post_soft_reset = vce_v3_0_post_soft_reset, 857aaa36a97SAlex Deucher .set_clockgating_state = vce_v3_0_set_clockgating_state, 858aaa36a97SAlex Deucher .set_powergating_state = vce_v3_0_set_powergating_state, 859aaa36a97SAlex Deucher }; 860aaa36a97SAlex Deucher 861aaa36a97SAlex Deucher static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = { 862aaa36a97SAlex Deucher .get_rptr = vce_v3_0_ring_get_rptr, 863aaa36a97SAlex Deucher .get_wptr = vce_v3_0_ring_get_wptr, 864aaa36a97SAlex Deucher .set_wptr = vce_v3_0_ring_set_wptr, 865aaa36a97SAlex Deucher .parse_cs = amdgpu_vce_ring_parse_cs, 866aaa36a97SAlex Deucher .emit_ib = amdgpu_vce_ring_emit_ib, 867aaa36a97SAlex Deucher .emit_fence = amdgpu_vce_ring_emit_fence, 868aaa36a97SAlex Deucher .test_ring = amdgpu_vce_ring_test_ring, 869aaa36a97SAlex Deucher .test_ib = amdgpu_vce_ring_test_ib, 870edff0e28SJammy Zhou .insert_nop = amdgpu_ring_insert_nop, 8719e5d5309SChristian König .pad_ib = amdgpu_ring_generic_pad_ib, 872ebff485eSChristian König .begin_use = amdgpu_vce_ring_begin_use, 873ebff485eSChristian König .end_use = amdgpu_vce_ring_end_use, 874aaa36a97SAlex Deucher }; 875aaa36a97SAlex Deucher 876aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) 877aaa36a97SAlex Deucher { 878aaa36a97SAlex Deucher adev->vce.ring[0].funcs = &vce_v3_0_ring_funcs; 879aaa36a97SAlex Deucher adev->vce.ring[1].funcs = &vce_v3_0_ring_funcs; 880aaa36a97SAlex Deucher } 881aaa36a97SAlex Deucher 882aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = { 883aaa36a97SAlex Deucher .set = vce_v3_0_set_interrupt_state, 884aaa36a97SAlex Deucher .process = vce_v3_0_process_interrupt, 885aaa36a97SAlex Deucher }; 886aaa36a97SAlex Deucher 887aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev) 888aaa36a97SAlex Deucher { 889aaa36a97SAlex Deucher adev->vce.irq.num_types = 1; 890aaa36a97SAlex Deucher adev->vce.irq.funcs = &vce_v3_0_irq_funcs; 891aaa36a97SAlex Deucher }; 892