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 4650a1ebc7SRex Zhu #define GRBM_GFX_INDEX__VCE_ALL_PIPE 0x07 4750a1ebc7SRex Zhu 483c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0 0x8616 493c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1 0x8617 503c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2 0x8618 5150a1ebc7SRex Zhu #define mmGRBM_GFX_INDEX_DEFAULT 0xE0000000 5250a1ebc7SRex Zhu 53567e6e29Sjimqu #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02 54aaa36a97SAlex Deucher 55e9822622SLeo Liu #define VCE_V3_0_FW_SIZE (384 * 1024) 56e9822622SLeo Liu #define VCE_V3_0_STACK_SIZE (64 * 1024) 57e9822622SLeo Liu #define VCE_V3_0_DATA_SIZE ((16 * 1024 * AMDGPU_MAX_VCE_HANDLES) + (52 * 1024)) 58e9822622SLeo Liu 59ef6239e0SAlex Deucher #define FW_52_8_3 ((52 << 24) | (8 << 16) | (3 << 8)) 60ef6239e0SAlex Deucher 6150a1ebc7SRex Zhu #define GET_VCE_INSTANCE(i) ((i) << GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT \ 6250a1ebc7SRex Zhu | GRBM_GFX_INDEX__VCE_ALL_PIPE) 6350a1ebc7SRex Zhu 645bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx); 65aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev); 66aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev); 67567e6e29Sjimqu static int vce_v3_0_wait_for_idle(void *handle); 68aaa36a97SAlex Deucher 69aaa36a97SAlex Deucher /** 70aaa36a97SAlex Deucher * vce_v3_0_ring_get_rptr - get read pointer 71aaa36a97SAlex Deucher * 72aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 73aaa36a97SAlex Deucher * 74aaa36a97SAlex Deucher * Returns the current hardware read pointer 75aaa36a97SAlex Deucher */ 76aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring) 77aaa36a97SAlex Deucher { 78aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 79aaa36a97SAlex Deucher 80aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 81aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR); 826f0359ffSAlex Deucher else if (ring == &adev->vce.ring[1]) 83aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR2); 846f0359ffSAlex Deucher else 856f0359ffSAlex Deucher return RREG32(mmVCE_RB_RPTR3); 86aaa36a97SAlex Deucher } 87aaa36a97SAlex Deucher 88aaa36a97SAlex Deucher /** 89aaa36a97SAlex Deucher * vce_v3_0_ring_get_wptr - get write pointer 90aaa36a97SAlex Deucher * 91aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 92aaa36a97SAlex Deucher * 93aaa36a97SAlex Deucher * Returns the current hardware write pointer 94aaa36a97SAlex Deucher */ 95aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring) 96aaa36a97SAlex Deucher { 97aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 98aaa36a97SAlex Deucher 99aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 100aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR); 1016f0359ffSAlex Deucher else if (ring == &adev->vce.ring[1]) 102aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR2); 1036f0359ffSAlex Deucher else 1046f0359ffSAlex Deucher return RREG32(mmVCE_RB_WPTR3); 105aaa36a97SAlex Deucher } 106aaa36a97SAlex Deucher 107aaa36a97SAlex Deucher /** 108aaa36a97SAlex Deucher * vce_v3_0_ring_set_wptr - set write pointer 109aaa36a97SAlex Deucher * 110aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 111aaa36a97SAlex Deucher * 112aaa36a97SAlex Deucher * Commits the write pointer to the hardware 113aaa36a97SAlex Deucher */ 114aaa36a97SAlex Deucher static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring) 115aaa36a97SAlex Deucher { 116aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 117aaa36a97SAlex Deucher 118aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 119aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR, ring->wptr); 1206f0359ffSAlex Deucher else if (ring == &adev->vce.ring[1]) 121aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR2, ring->wptr); 1226f0359ffSAlex Deucher else 1236f0359ffSAlex Deucher WREG32(mmVCE_RB_WPTR3, ring->wptr); 124aaa36a97SAlex Deucher } 125aaa36a97SAlex Deucher 1260689a570SEric Huang static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override) 1270689a570SEric Huang { 128f3f0ea95STom St Denis WREG32_FIELD(VCE_RB_ARB_CTRL, VCE_CGTT_OVERRIDE, override ? 1 : 0); 1290689a570SEric Huang } 1300689a570SEric Huang 1310689a570SEric Huang static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, 1320689a570SEric Huang bool gated) 1330689a570SEric Huang { 134f3f0ea95STom St Denis u32 data; 135f16fe6d3STom St Denis 1360689a570SEric Huang /* Set Override to disable Clock Gating */ 1370689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, true); 1380689a570SEric Huang 1396f906814STom St Denis /* This function enables MGCG which is controlled by firmware. 1406f906814STom St Denis With the clocks in the gated state the core is still 1416f906814STom St Denis accessible but the firmware will throttle the clocks on the 1426f906814STom St Denis fly as necessary. 1430689a570SEric Huang */ 144ecc2cf7cSMaruthi Srinivas Bayyavarapu if (!gated) { 145f3f0ea95STom St Denis data = RREG32(mmVCE_CLOCK_GATING_B); 1460689a570SEric Huang data |= 0x1ff; 1470689a570SEric Huang data &= ~0xef0000; 1480689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1490689a570SEric Huang 150f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_CLOCK_GATING); 1510689a570SEric Huang data |= 0x3ff000; 1520689a570SEric Huang data &= ~0xffc00000; 1530689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1540689a570SEric Huang 155f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1560689a570SEric Huang data |= 0x2; 1576f906814STom St Denis data &= ~0x00010000; 1580689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1590689a570SEric Huang 160f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1610689a570SEric Huang data |= 0x37f; 1620689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1630689a570SEric Huang 164f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1650689a570SEric Huang data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1660689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1670689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1680689a570SEric Huang 0x8; 1690689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1700689a570SEric Huang } else { 171f3f0ea95STom St Denis data = RREG32(mmVCE_CLOCK_GATING_B); 1720689a570SEric Huang data &= ~0x80010; 1730689a570SEric Huang data |= 0xe70008; 1740689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1756f906814STom St Denis 176f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_CLOCK_GATING); 1770689a570SEric Huang data |= 0xffc00000; 1780689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1796f906814STom St Denis 180f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1810689a570SEric Huang data |= 0x10000; 1820689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1836f906814STom St Denis 184f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 185e05208deSRex Zhu data &= ~0x3ff; 1860689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1876f906814STom St Denis 188f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1890689a570SEric Huang data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1900689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1910689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1920689a570SEric Huang 0x8); 1930689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1940689a570SEric Huang } 1950689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, false); 1960689a570SEric Huang } 1970689a570SEric Huang 198567e6e29Sjimqu static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev) 199567e6e29Sjimqu { 200567e6e29Sjimqu int i, j; 201567e6e29Sjimqu 202567e6e29Sjimqu for (i = 0; i < 10; ++i) { 203567e6e29Sjimqu for (j = 0; j < 100; ++j) { 204b7e2e9f7Sjimqu uint32_t status = RREG32(mmVCE_STATUS); 205b7e2e9f7Sjimqu 206567e6e29Sjimqu if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK) 207567e6e29Sjimqu return 0; 208567e6e29Sjimqu mdelay(10); 209567e6e29Sjimqu } 210567e6e29Sjimqu 211567e6e29Sjimqu DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); 212f3f0ea95STom St Denis WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1); 213567e6e29Sjimqu mdelay(10); 214f3f0ea95STom St Denis WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0); 215567e6e29Sjimqu mdelay(10); 216567e6e29Sjimqu } 217567e6e29Sjimqu 218567e6e29Sjimqu return -ETIMEDOUT; 219567e6e29Sjimqu } 220567e6e29Sjimqu 221aaa36a97SAlex Deucher /** 222aaa36a97SAlex Deucher * vce_v3_0_start - start VCE block 223aaa36a97SAlex Deucher * 224aaa36a97SAlex Deucher * @adev: amdgpu_device pointer 225aaa36a97SAlex Deucher * 226aaa36a97SAlex Deucher * Setup and start the VCE block 227aaa36a97SAlex Deucher */ 228aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev) 229aaa36a97SAlex Deucher { 230aaa36a97SAlex Deucher struct amdgpu_ring *ring; 231567e6e29Sjimqu int idx, r; 232567e6e29Sjimqu 233567e6e29Sjimqu ring = &adev->vce.ring[0]; 234567e6e29Sjimqu WREG32(mmVCE_RB_RPTR, ring->wptr); 235567e6e29Sjimqu WREG32(mmVCE_RB_WPTR, ring->wptr); 236567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr); 237567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); 238567e6e29Sjimqu WREG32(mmVCE_RB_SIZE, ring->ring_size / 4); 239567e6e29Sjimqu 240567e6e29Sjimqu ring = &adev->vce.ring[1]; 241567e6e29Sjimqu WREG32(mmVCE_RB_RPTR2, ring->wptr); 242567e6e29Sjimqu WREG32(mmVCE_RB_WPTR2, ring->wptr); 243567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr); 244567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); 245567e6e29Sjimqu WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4); 246aaa36a97SAlex Deucher 2476f0359ffSAlex Deucher ring = &adev->vce.ring[2]; 2486f0359ffSAlex Deucher WREG32(mmVCE_RB_RPTR3, ring->wptr); 2496f0359ffSAlex Deucher WREG32(mmVCE_RB_WPTR3, ring->wptr); 2506f0359ffSAlex Deucher WREG32(mmVCE_RB_BASE_LO3, ring->gpu_addr); 2516f0359ffSAlex Deucher WREG32(mmVCE_RB_BASE_HI3, upper_32_bits(ring->gpu_addr)); 2526f0359ffSAlex Deucher WREG32(mmVCE_RB_SIZE3, ring->ring_size / 4); 2536f0359ffSAlex Deucher 2545bbc553aSLeo Liu mutex_lock(&adev->grbm_idx_mutex); 2555bbc553aSLeo Liu for (idx = 0; idx < 2; ++idx) { 2566a585777SAlex Deucher if (adev->vce.harvest_config & (1 << idx)) 2576a585777SAlex Deucher continue; 2586a585777SAlex Deucher 25950a1ebc7SRex Zhu WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(idx)); 2605bbc553aSLeo Liu vce_v3_0_mc_resume(adev, idx); 261f3f0ea95STom St Denis WREG32_FIELD(VCE_STATUS, JOB_BUSY, 1); 262567e6e29Sjimqu 2633c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) 2643c0ff9f1SLeo Liu WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001); 2653c0ff9f1SLeo Liu else 266f3f0ea95STom St Denis WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 1); 267aaa36a97SAlex Deucher 268f3f0ea95STom St Denis WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0); 269aaa36a97SAlex Deucher mdelay(100); 270aaa36a97SAlex Deucher 271567e6e29Sjimqu r = vce_v3_0_firmware_loaded(adev); 272aaa36a97SAlex Deucher 273aaa36a97SAlex Deucher /* clear BUSY flag */ 274f3f0ea95STom St Denis WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0); 275aaa36a97SAlex Deucher 276aaa36a97SAlex Deucher if (r) { 277aaa36a97SAlex Deucher DRM_ERROR("VCE not responding, giving up!!!\n"); 2785bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 279aaa36a97SAlex Deucher return r; 280aaa36a97SAlex Deucher } 2815bbc553aSLeo Liu } 2825bbc553aSLeo Liu 28350a1ebc7SRex Zhu WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT); 2845bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 2855bbc553aSLeo Liu 286567e6e29Sjimqu return 0; 287567e6e29Sjimqu } 2885bbc553aSLeo Liu 289567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev) 290567e6e29Sjimqu { 291567e6e29Sjimqu int idx; 292567e6e29Sjimqu 293567e6e29Sjimqu mutex_lock(&adev->grbm_idx_mutex); 294567e6e29Sjimqu for (idx = 0; idx < 2; ++idx) { 295567e6e29Sjimqu if (adev->vce.harvest_config & (1 << idx)) 296567e6e29Sjimqu continue; 297567e6e29Sjimqu 29850a1ebc7SRex Zhu WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(idx)); 299567e6e29Sjimqu 300567e6e29Sjimqu if (adev->asic_type >= CHIP_STONEY) 301567e6e29Sjimqu WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001); 302567e6e29Sjimqu else 303f3f0ea95STom St Denis WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 0); 304f3f0ea95STom St Denis 305567e6e29Sjimqu /* hold on ECPU */ 306f3f0ea95STom St Denis WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1); 307567e6e29Sjimqu 308567e6e29Sjimqu /* clear BUSY flag */ 309f3f0ea95STom St Denis WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0); 310567e6e29Sjimqu 311567e6e29Sjimqu /* Set Clock-Gating off */ 312567e6e29Sjimqu if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) 313567e6e29Sjimqu vce_v3_0_set_vce_sw_clock_gating(adev, false); 314567e6e29Sjimqu } 315567e6e29Sjimqu 31650a1ebc7SRex Zhu WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT); 317567e6e29Sjimqu mutex_unlock(&adev->grbm_idx_mutex); 318aaa36a97SAlex Deucher 319aaa36a97SAlex Deucher return 0; 320aaa36a97SAlex Deucher } 321aaa36a97SAlex Deucher 3226a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS 0xC0014074 3236a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT 27 3246a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK 0x18000000 3256a585777SAlex Deucher 3266a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) 3276a585777SAlex Deucher { 3286a585777SAlex Deucher u32 tmp; 3296a585777SAlex Deucher 330c4642a47SJunwei Zhang /* Fiji, Stoney, Polaris10, Polaris11, Polaris12 are single pipe */ 331cfaba566SSamuel Li if ((adev->asic_type == CHIP_FIJI) || 3321b4eeea5SSonny Jiang (adev->asic_type == CHIP_STONEY) || 3332cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS10) || 334c4642a47SJunwei Zhang (adev->asic_type == CHIP_POLARIS11) || 335c4642a47SJunwei Zhang (adev->asic_type == CHIP_POLARIS12)) 3361dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 337188a9bcdSAlex Deucher 338188a9bcdSAlex Deucher /* Tonga and CZ are dual or single pipe */ 3392f7d10b3SJammy Zhou if (adev->flags & AMD_IS_APU) 3406a585777SAlex Deucher tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) & 3416a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__MASK) >> 3426a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__SHIFT; 3436a585777SAlex Deucher else 3446a585777SAlex Deucher tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) & 3456a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE_MASK) >> 3466a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE__SHIFT; 3476a585777SAlex Deucher 3486a585777SAlex Deucher switch (tmp) { 3496a585777SAlex Deucher case 1: 3501dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0; 3516a585777SAlex Deucher case 2: 3521dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 3536a585777SAlex Deucher case 3: 3541dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1; 3556a585777SAlex Deucher default: 3561dab5f06STom St Denis return 0; 3576a585777SAlex Deucher } 3586a585777SAlex Deucher } 3596a585777SAlex Deucher 3605fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle) 361aaa36a97SAlex Deucher { 3625fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 3635fc3aeebSyanyang1 3646a585777SAlex Deucher adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); 3656a585777SAlex Deucher 3666a585777SAlex Deucher if ((adev->vce.harvest_config & 3676a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) == 3686a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 3696a585777SAlex Deucher return -ENOENT; 3706a585777SAlex Deucher 3716f0359ffSAlex Deucher adev->vce.num_rings = 3; 37275c65480SAlex Deucher 373aaa36a97SAlex Deucher vce_v3_0_set_ring_funcs(adev); 374aaa36a97SAlex Deucher vce_v3_0_set_irq_funcs(adev); 375aaa36a97SAlex Deucher 376aaa36a97SAlex Deucher return 0; 377aaa36a97SAlex Deucher } 378aaa36a97SAlex Deucher 3795fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle) 380aaa36a97SAlex Deucher { 3815fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 382aaa36a97SAlex Deucher struct amdgpu_ring *ring; 38375c65480SAlex Deucher int r, i; 384aaa36a97SAlex Deucher 385aaa36a97SAlex Deucher /* VCE */ 386aaa36a97SAlex Deucher r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq); 387aaa36a97SAlex Deucher if (r) 388aaa36a97SAlex Deucher return r; 389aaa36a97SAlex Deucher 390e9822622SLeo Liu r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE + 391e9822622SLeo Liu (VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2); 392aaa36a97SAlex Deucher if (r) 393aaa36a97SAlex Deucher return r; 394aaa36a97SAlex Deucher 395ef6239e0SAlex Deucher /* 52.8.3 required for 3 ring support */ 396ef6239e0SAlex Deucher if (adev->vce.fw_version < FW_52_8_3) 397ef6239e0SAlex Deucher adev->vce.num_rings = 2; 398ef6239e0SAlex Deucher 399aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 400aaa36a97SAlex Deucher if (r) 401aaa36a97SAlex Deucher return r; 402aaa36a97SAlex Deucher 40375c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) { 40475c65480SAlex Deucher ring = &adev->vce.ring[i]; 40575c65480SAlex Deucher sprintf(ring->name, "vce%d", i); 40679887142SChristian König r = amdgpu_ring_init(adev, ring, 512, &adev->vce.irq, 0); 407aaa36a97SAlex Deucher if (r) 408aaa36a97SAlex Deucher return r; 40975c65480SAlex Deucher } 410aaa36a97SAlex Deucher 411aaa36a97SAlex Deucher return r; 412aaa36a97SAlex Deucher } 413aaa36a97SAlex Deucher 4145fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle) 415aaa36a97SAlex Deucher { 416aaa36a97SAlex Deucher int r; 4175fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 418aaa36a97SAlex Deucher 419aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 420aaa36a97SAlex Deucher if (r) 421aaa36a97SAlex Deucher return r; 422aaa36a97SAlex Deucher 423aaa36a97SAlex Deucher r = amdgpu_vce_sw_fini(adev); 424aaa36a97SAlex Deucher if (r) 425aaa36a97SAlex Deucher return r; 426aaa36a97SAlex Deucher 427aaa36a97SAlex Deucher return r; 428aaa36a97SAlex Deucher } 429aaa36a97SAlex Deucher 4305fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle) 431aaa36a97SAlex Deucher { 432691ca86aSTom St Denis int r, i; 4335fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 434aaa36a97SAlex Deucher 435aaa36a97SAlex Deucher r = vce_v3_0_start(adev); 436aaa36a97SAlex Deucher if (r) 437aaa36a97SAlex Deucher return r; 438aaa36a97SAlex Deucher 43975c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) 44075c65480SAlex Deucher adev->vce.ring[i].ready = false; 441aaa36a97SAlex Deucher 44275c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) { 443691ca86aSTom St Denis r = amdgpu_ring_test_ring(&adev->vce.ring[i]); 444691ca86aSTom St Denis if (r) 445aaa36a97SAlex Deucher return r; 446691ca86aSTom St Denis else 447691ca86aSTom St Denis adev->vce.ring[i].ready = true; 448aaa36a97SAlex Deucher } 449aaa36a97SAlex Deucher 450aaa36a97SAlex Deucher DRM_INFO("VCE initialized successfully.\n"); 451aaa36a97SAlex Deucher 452aaa36a97SAlex Deucher return 0; 453aaa36a97SAlex Deucher } 454aaa36a97SAlex Deucher 4555fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle) 456aaa36a97SAlex Deucher { 457567e6e29Sjimqu int r; 458567e6e29Sjimqu struct amdgpu_device *adev = (struct amdgpu_device *)handle; 459567e6e29Sjimqu 460567e6e29Sjimqu r = vce_v3_0_wait_for_idle(handle); 461567e6e29Sjimqu if (r) 462567e6e29Sjimqu return r; 463567e6e29Sjimqu 464567e6e29Sjimqu return vce_v3_0_stop(adev); 465aaa36a97SAlex Deucher } 466aaa36a97SAlex Deucher 4675fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle) 468aaa36a97SAlex Deucher { 469aaa36a97SAlex Deucher int r; 4705fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 471aaa36a97SAlex Deucher 472aaa36a97SAlex Deucher r = vce_v3_0_hw_fini(adev); 473aaa36a97SAlex Deucher if (r) 474aaa36a97SAlex Deucher return r; 475aaa36a97SAlex Deucher 476aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 477aaa36a97SAlex Deucher if (r) 478aaa36a97SAlex Deucher return r; 479aaa36a97SAlex Deucher 480aaa36a97SAlex Deucher return r; 481aaa36a97SAlex Deucher } 482aaa36a97SAlex Deucher 4835fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle) 484aaa36a97SAlex Deucher { 485aaa36a97SAlex Deucher int r; 4865fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 487aaa36a97SAlex Deucher 488aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 489aaa36a97SAlex Deucher if (r) 490aaa36a97SAlex Deucher return r; 491aaa36a97SAlex Deucher 492aaa36a97SAlex Deucher r = vce_v3_0_hw_init(adev); 493aaa36a97SAlex Deucher if (r) 494aaa36a97SAlex Deucher return r; 495aaa36a97SAlex Deucher 496aaa36a97SAlex Deucher return r; 497aaa36a97SAlex Deucher } 498aaa36a97SAlex Deucher 4995bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) 500aaa36a97SAlex Deucher { 501aaa36a97SAlex Deucher uint32_t offset, size; 502aaa36a97SAlex Deucher 503aaa36a97SAlex Deucher WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16)); 504aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); 505aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); 5066f906814STom St Denis WREG32(mmVCE_CLOCK_GATING_B, 0x1FF); 507aaa36a97SAlex Deucher 508aaa36a97SAlex Deucher WREG32(mmVCE_LMI_CTRL, 0x00398000); 509aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1); 510aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL, 0); 511aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL1, 0); 512aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VM_CTRL, 0); 5133c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) { 5143c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8)); 5153c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8)); 5163c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8)); 5173c0ff9f1SLeo Liu } else 518aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8)); 519aaa36a97SAlex Deucher offset = AMDGPU_VCE_FIRMWARE_OFFSET; 520e9822622SLeo Liu size = VCE_V3_0_FW_SIZE; 521aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff); 522aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE0, size); 523aaa36a97SAlex Deucher 5245bbc553aSLeo Liu if (idx == 0) { 525aaa36a97SAlex Deucher offset += size; 526e9822622SLeo Liu size = VCE_V3_0_STACK_SIZE; 527aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff); 528aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 529aaa36a97SAlex Deucher offset += size; 530e9822622SLeo Liu size = VCE_V3_0_DATA_SIZE; 531aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff); 532aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5335bbc553aSLeo Liu } else { 5345bbc553aSLeo Liu offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE; 5355bbc553aSLeo Liu size = VCE_V3_0_STACK_SIZE; 5365bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff); 5375bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 5385bbc553aSLeo Liu offset += size; 5395bbc553aSLeo Liu size = VCE_V3_0_DATA_SIZE; 5405bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff); 5415bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5425bbc553aSLeo Liu } 543aaa36a97SAlex Deucher 544aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); 545f3f0ea95STom St Denis WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1); 546aaa36a97SAlex Deucher } 547aaa36a97SAlex Deucher 5485fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle) 549aaa36a97SAlex Deucher { 5505fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 551be4f38e2SAlex Deucher u32 mask = 0; 5525fc3aeebSyanyang1 55374af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK; 55474af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK; 555be4f38e2SAlex Deucher 556be4f38e2SAlex Deucher return !(RREG32(mmSRBM_STATUS2) & mask); 557aaa36a97SAlex Deucher } 558aaa36a97SAlex Deucher 5595fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle) 560aaa36a97SAlex Deucher { 561aaa36a97SAlex Deucher unsigned i; 5625fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 563be4f38e2SAlex Deucher 56492988e60STom St Denis for (i = 0; i < adev->usec_timeout; i++) 56592988e60STom St Denis if (vce_v3_0_is_idle(handle)) 566aaa36a97SAlex Deucher return 0; 56792988e60STom St Denis 568aaa36a97SAlex Deucher return -ETIMEDOUT; 569aaa36a97SAlex Deucher } 570aaa36a97SAlex Deucher 571ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK 0x00000008L /* AUTO_BUSY */ 572ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK 0x00000010L /* RB0_BUSY */ 573ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_RB1_BUSY_MASK 0x00000020L /* RB1_BUSY */ 574ac8e3f30SRex Zhu #define AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \ 575ac8e3f30SRex Zhu VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK) 576115933a5SChunming Zhou 577da146d3bSAlex Deucher static bool vce_v3_0_check_soft_reset(void *handle) 578115933a5SChunming Zhou { 579115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 580115933a5SChunming Zhou u32 srbm_soft_reset = 0; 581115933a5SChunming Zhou 582115933a5SChunming Zhou /* According to VCE team , we should use VCE_STATUS instead 583115933a5SChunming Zhou * SRBM_STATUS.VCE_BUSY bit for busy status checking. 584115933a5SChunming Zhou * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE 585115933a5SChunming Zhou * instance's registers are accessed 586115933a5SChunming Zhou * (0 for 1st instance, 10 for 2nd instance). 587115933a5SChunming Zhou * 588115933a5SChunming Zhou *VCE_STATUS 589115933a5SChunming Zhou *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 | |FW_LOADED|JOB | 590115933a5SChunming Zhou *|----+----+-----------+----+----+----+----------+---------+----| 591115933a5SChunming Zhou *|bit8|bit7| bit6 |bit5|bit4|bit3| bit2 | bit1 |bit0| 592115933a5SChunming Zhou * 593115933a5SChunming Zhou * VCE team suggest use bit 3--bit 6 for busy status check 594115933a5SChunming Zhou */ 5959aeb774cSTom St Denis mutex_lock(&adev->grbm_idx_mutex); 59650a1ebc7SRex Zhu WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0)); 597115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 598115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 599115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 600115933a5SChunming Zhou } 60150a1ebc7SRex Zhu WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1)); 602115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 603115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 604115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 605115933a5SChunming Zhou } 60650a1ebc7SRex Zhu WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0)); 607da146d3bSAlex Deucher mutex_unlock(&adev->grbm_idx_mutex); 608115933a5SChunming Zhou 609115933a5SChunming Zhou if (srbm_soft_reset) { 610115933a5SChunming Zhou adev->vce.srbm_soft_reset = srbm_soft_reset; 611da146d3bSAlex Deucher return true; 612115933a5SChunming Zhou } else { 613115933a5SChunming Zhou adev->vce.srbm_soft_reset = 0; 614da146d3bSAlex Deucher return false; 615115933a5SChunming Zhou } 616115933a5SChunming Zhou } 617115933a5SChunming Zhou 6185fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle) 619aaa36a97SAlex Deucher { 6205fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 621115933a5SChunming Zhou u32 srbm_soft_reset; 6225fc3aeebSyanyang1 623da146d3bSAlex Deucher if (!adev->vce.srbm_soft_reset) 624115933a5SChunming Zhou return 0; 625115933a5SChunming Zhou srbm_soft_reset = adev->vce.srbm_soft_reset; 626be4f38e2SAlex Deucher 627115933a5SChunming Zhou if (srbm_soft_reset) { 628115933a5SChunming Zhou u32 tmp; 629115933a5SChunming Zhou 630115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 631115933a5SChunming Zhou tmp |= srbm_soft_reset; 632115933a5SChunming Zhou dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); 633115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 634115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 635115933a5SChunming Zhou 636115933a5SChunming Zhou udelay(50); 637115933a5SChunming Zhou 638115933a5SChunming Zhou tmp &= ~srbm_soft_reset; 639115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 640115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 641115933a5SChunming Zhou 642115933a5SChunming Zhou /* Wait a little for things to settle down */ 643115933a5SChunming Zhou udelay(50); 644115933a5SChunming Zhou } 645115933a5SChunming Zhou 646115933a5SChunming Zhou return 0; 647115933a5SChunming Zhou } 648115933a5SChunming Zhou 649115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle) 650115933a5SChunming Zhou { 651115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 652115933a5SChunming Zhou 653da146d3bSAlex Deucher if (!adev->vce.srbm_soft_reset) 654115933a5SChunming Zhou return 0; 655115933a5SChunming Zhou 656aaa36a97SAlex Deucher mdelay(5); 657aaa36a97SAlex Deucher 658115933a5SChunming Zhou return vce_v3_0_suspend(adev); 659115933a5SChunming Zhou } 660115933a5SChunming Zhou 661115933a5SChunming Zhou 662115933a5SChunming Zhou static int vce_v3_0_post_soft_reset(void *handle) 663115933a5SChunming Zhou { 664115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 665115933a5SChunming Zhou 666da146d3bSAlex Deucher if (!adev->vce.srbm_soft_reset) 667115933a5SChunming Zhou return 0; 668115933a5SChunming Zhou 669115933a5SChunming Zhou mdelay(5); 670115933a5SChunming Zhou 671115933a5SChunming Zhou return vce_v3_0_resume(adev); 672aaa36a97SAlex Deucher } 673aaa36a97SAlex Deucher 674aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, 675aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 676aaa36a97SAlex Deucher unsigned type, 677aaa36a97SAlex Deucher enum amdgpu_interrupt_state state) 678aaa36a97SAlex Deucher { 679aaa36a97SAlex Deucher uint32_t val = 0; 680aaa36a97SAlex Deucher 681aaa36a97SAlex Deucher if (state == AMDGPU_IRQ_STATE_ENABLE) 682aaa36a97SAlex Deucher val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK; 683aaa36a97SAlex Deucher 684aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 685aaa36a97SAlex Deucher return 0; 686aaa36a97SAlex Deucher } 687aaa36a97SAlex Deucher 688aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev, 689aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 690aaa36a97SAlex Deucher struct amdgpu_iv_entry *entry) 691aaa36a97SAlex Deucher { 692aaa36a97SAlex Deucher DRM_DEBUG("IH: VCE\n"); 693d6c29c30SLeo Liu 694f3f0ea95STom St Denis WREG32_FIELD(VCE_SYS_INT_STATUS, VCE_SYS_INT_TRAP_INTERRUPT_INT, 1); 695d6c29c30SLeo Liu 696aaa36a97SAlex Deucher switch (entry->src_data) { 697aaa36a97SAlex Deucher case 0: 698aaa36a97SAlex Deucher case 1: 6996f0359ffSAlex Deucher case 2: 70081da2edeSTom St Denis amdgpu_fence_process(&adev->vce.ring[entry->src_data]); 701aaa36a97SAlex Deucher break; 702aaa36a97SAlex Deucher default: 703aaa36a97SAlex Deucher DRM_ERROR("Unhandled interrupt: %d %d\n", 704aaa36a97SAlex Deucher entry->src_id, entry->src_data); 705aaa36a97SAlex Deucher break; 706aaa36a97SAlex Deucher } 707aaa36a97SAlex Deucher 708aaa36a97SAlex Deucher return 0; 709aaa36a97SAlex Deucher } 710aaa36a97SAlex Deucher 7110174df4eSRex Zhu static void vce_v3_0_set_bypass_mode(struct amdgpu_device *adev, bool enable) 712ec38f188SRex Zhu { 713ec38f188SRex Zhu u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL); 714ec38f188SRex Zhu 715ec38f188SRex Zhu if (enable) 716ec38f188SRex Zhu tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 717ec38f188SRex Zhu else 718ec38f188SRex Zhu tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 719ec38f188SRex Zhu 720ec38f188SRex Zhu WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp); 721ec38f188SRex Zhu } 722ec38f188SRex Zhu 7235fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle, 7245fc3aeebSyanyang1 enum amd_clockgating_state state) 725aaa36a97SAlex Deucher { 7260689a570SEric Huang struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7270689a570SEric Huang bool enable = (state == AMD_CG_STATE_GATE) ? true : false; 7280689a570SEric Huang int i; 7290689a570SEric Huang 730c04399f1SRex Zhu if ((adev->asic_type == CHIP_POLARIS10) || 7313374dcebSRex Zhu (adev->asic_type == CHIP_TONGA) || 7323374dcebSRex Zhu (adev->asic_type == CHIP_FIJI)) 7330174df4eSRex Zhu vce_v3_0_set_bypass_mode(adev, enable); 734ec38f188SRex Zhu 735e3b04bc7SAlex Deucher if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) 7360689a570SEric Huang return 0; 7370689a570SEric Huang 7380689a570SEric Huang mutex_lock(&adev->grbm_idx_mutex); 7390689a570SEric Huang for (i = 0; i < 2; i++) { 7400689a570SEric Huang /* Program VCE Instance 0 or 1 if not harvested */ 7410689a570SEric Huang if (adev->vce.harvest_config & (1 << i)) 7420689a570SEric Huang continue; 7430689a570SEric Huang 74450a1ebc7SRex Zhu WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(i)); 7450689a570SEric Huang 7460689a570SEric Huang if (enable) { 7470689a570SEric Huang /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ 7480689a570SEric Huang uint32_t data = RREG32(mmVCE_CLOCK_GATING_A); 7490689a570SEric Huang data &= ~(0xf | 0xff0); 7500689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7510689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_A, data); 7520689a570SEric Huang 7530689a570SEric Huang /* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */ 7540689a570SEric Huang data = RREG32(mmVCE_UENC_CLOCK_GATING); 7550689a570SEric Huang data &= ~(0xf | 0xff0); 7560689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7570689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 7580689a570SEric Huang } 7590689a570SEric Huang 7600689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, enable); 7610689a570SEric Huang } 7620689a570SEric Huang 76350a1ebc7SRex Zhu WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT); 7640689a570SEric Huang mutex_unlock(&adev->grbm_idx_mutex); 7650689a570SEric Huang 766aaa36a97SAlex Deucher return 0; 767aaa36a97SAlex Deucher } 768aaa36a97SAlex Deucher 7695fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle, 7705fc3aeebSyanyang1 enum amd_powergating_state state) 771aaa36a97SAlex Deucher { 772aaa36a97SAlex Deucher /* This doesn't actually powergate the VCE block. 773aaa36a97SAlex Deucher * That's done in the dpm code via the SMC. This 774aaa36a97SAlex Deucher * just re-inits the block as necessary. The actual 775aaa36a97SAlex Deucher * gating still happens in the dpm code. We should 776aaa36a97SAlex Deucher * revisit this when there is a cleaner line between 777aaa36a97SAlex Deucher * the smc and the hw blocks 778aaa36a97SAlex Deucher */ 7795fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 780c79b5561SHuang Rui int ret = 0; 7815fc3aeebSyanyang1 782e3b04bc7SAlex Deucher if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE)) 783808a934fSAlex Deucher return 0; 784808a934fSAlex Deucher 785c79b5561SHuang Rui if (state == AMD_PG_STATE_GATE) { 786c79b5561SHuang Rui adev->vce.is_powergated = true; 787aaa36a97SAlex Deucher /* XXX do we need a vce_v3_0_stop()? */ 788c79b5561SHuang Rui } else { 789c79b5561SHuang Rui ret = vce_v3_0_start(adev); 790c79b5561SHuang Rui if (ret) 791c79b5561SHuang Rui goto out; 792c79b5561SHuang Rui adev->vce.is_powergated = false; 793c79b5561SHuang Rui } 794c79b5561SHuang Rui 795c79b5561SHuang Rui out: 796c79b5561SHuang Rui return ret; 797c79b5561SHuang Rui } 798c79b5561SHuang Rui 799c79b5561SHuang Rui static void vce_v3_0_get_clockgating_state(void *handle, u32 *flags) 800c79b5561SHuang Rui { 801c79b5561SHuang Rui struct amdgpu_device *adev = (struct amdgpu_device *)handle; 802c79b5561SHuang Rui int data; 803c79b5561SHuang Rui 804c79b5561SHuang Rui mutex_lock(&adev->pm.mutex); 805c79b5561SHuang Rui 806c79b5561SHuang Rui if (adev->vce.is_powergated) { 807c79b5561SHuang Rui DRM_INFO("Cannot get clockgating state when VCE is powergated.\n"); 808c79b5561SHuang Rui goto out; 809c79b5561SHuang Rui } 810c79b5561SHuang Rui 811c79b5561SHuang Rui WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); 812c79b5561SHuang Rui 813c79b5561SHuang Rui /* AMD_CG_SUPPORT_VCE_MGCG */ 814c79b5561SHuang Rui data = RREG32(mmVCE_CLOCK_GATING_A); 815c79b5561SHuang Rui if (data & (0x04 << 4)) 816c79b5561SHuang Rui *flags |= AMD_CG_SUPPORT_VCE_MGCG; 817c79b5561SHuang Rui 818c79b5561SHuang Rui out: 819c79b5561SHuang Rui mutex_unlock(&adev->pm.mutex); 820aaa36a97SAlex Deucher } 821aaa36a97SAlex Deucher 822ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring, 823ea4a8c1dSMaruthi Srinivas Bayyavarapu struct amdgpu_ib *ib, unsigned int vm_id, bool ctx_switch) 824ea4a8c1dSMaruthi Srinivas Bayyavarapu { 825ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_IB_VM); 826ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, vm_id); 827ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr)); 828ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr)); 829ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, ib->length_dw); 830ea4a8c1dSMaruthi Srinivas Bayyavarapu } 831ea4a8c1dSMaruthi Srinivas Bayyavarapu 832ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring, 833ea4a8c1dSMaruthi Srinivas Bayyavarapu unsigned int vm_id, uint64_t pd_addr) 834ea4a8c1dSMaruthi Srinivas Bayyavarapu { 835ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_UPDATE_PTB); 836ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, vm_id); 837ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, pd_addr >> 12); 838ea4a8c1dSMaruthi Srinivas Bayyavarapu 839ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_FLUSH_TLB); 840ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, vm_id); 841ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_END); 842ea4a8c1dSMaruthi Srinivas Bayyavarapu } 843ea4a8c1dSMaruthi Srinivas Bayyavarapu 844ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_pipeline_sync(struct amdgpu_ring *ring) 845ea4a8c1dSMaruthi Srinivas Bayyavarapu { 846ea4a8c1dSMaruthi Srinivas Bayyavarapu uint32_t seq = ring->fence_drv.sync_seq; 847ea4a8c1dSMaruthi Srinivas Bayyavarapu uint64_t addr = ring->fence_drv.gpu_addr; 848ea4a8c1dSMaruthi Srinivas Bayyavarapu 849ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_WAIT_GE); 850ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, lower_32_bits(addr)); 851ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, upper_32_bits(addr)); 852ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, seq); 853ea4a8c1dSMaruthi Srinivas Bayyavarapu } 854ea4a8c1dSMaruthi Srinivas Bayyavarapu 855a1255107SAlex Deucher static const struct amd_ip_funcs vce_v3_0_ip_funcs = { 85688a907d6STom St Denis .name = "vce_v3_0", 857aaa36a97SAlex Deucher .early_init = vce_v3_0_early_init, 858aaa36a97SAlex Deucher .late_init = NULL, 859aaa36a97SAlex Deucher .sw_init = vce_v3_0_sw_init, 860aaa36a97SAlex Deucher .sw_fini = vce_v3_0_sw_fini, 861aaa36a97SAlex Deucher .hw_init = vce_v3_0_hw_init, 862aaa36a97SAlex Deucher .hw_fini = vce_v3_0_hw_fini, 863aaa36a97SAlex Deucher .suspend = vce_v3_0_suspend, 864aaa36a97SAlex Deucher .resume = vce_v3_0_resume, 865aaa36a97SAlex Deucher .is_idle = vce_v3_0_is_idle, 866aaa36a97SAlex Deucher .wait_for_idle = vce_v3_0_wait_for_idle, 867115933a5SChunming Zhou .check_soft_reset = vce_v3_0_check_soft_reset, 868115933a5SChunming Zhou .pre_soft_reset = vce_v3_0_pre_soft_reset, 869aaa36a97SAlex Deucher .soft_reset = vce_v3_0_soft_reset, 870115933a5SChunming Zhou .post_soft_reset = vce_v3_0_post_soft_reset, 871aaa36a97SAlex Deucher .set_clockgating_state = vce_v3_0_set_clockgating_state, 872aaa36a97SAlex Deucher .set_powergating_state = vce_v3_0_set_powergating_state, 873c79b5561SHuang Rui .get_clockgating_state = vce_v3_0_get_clockgating_state, 874aaa36a97SAlex Deucher }; 875aaa36a97SAlex Deucher 876ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = { 87721cd942eSChristian König .type = AMDGPU_RING_TYPE_VCE, 87879887142SChristian König .align_mask = 0xf, 87979887142SChristian König .nop = VCE_CMD_NO_OP, 880aaa36a97SAlex Deucher .get_rptr = vce_v3_0_ring_get_rptr, 881aaa36a97SAlex Deucher .get_wptr = vce_v3_0_ring_get_wptr, 882aaa36a97SAlex Deucher .set_wptr = vce_v3_0_ring_set_wptr, 883aaa36a97SAlex Deucher .parse_cs = amdgpu_vce_ring_parse_cs, 884e12f3d7aSChristian König .emit_frame_size = 885e12f3d7aSChristian König 4 + /* vce_v3_0_emit_pipeline_sync */ 886e12f3d7aSChristian König 6, /* amdgpu_vce_ring_emit_fence x1 no user fence */ 887e12f3d7aSChristian König .emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */ 888aaa36a97SAlex Deucher .emit_ib = amdgpu_vce_ring_emit_ib, 889aaa36a97SAlex Deucher .emit_fence = amdgpu_vce_ring_emit_fence, 890aaa36a97SAlex Deucher .test_ring = amdgpu_vce_ring_test_ring, 891aaa36a97SAlex Deucher .test_ib = amdgpu_vce_ring_test_ib, 892edff0e28SJammy Zhou .insert_nop = amdgpu_ring_insert_nop, 8939e5d5309SChristian König .pad_ib = amdgpu_ring_generic_pad_ib, 894ebff485eSChristian König .begin_use = amdgpu_vce_ring_begin_use, 895ebff485eSChristian König .end_use = amdgpu_vce_ring_end_use, 896aaa36a97SAlex Deucher }; 897aaa36a97SAlex Deucher 898ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = { 89921cd942eSChristian König .type = AMDGPU_RING_TYPE_VCE, 90079887142SChristian König .align_mask = 0xf, 90179887142SChristian König .nop = VCE_CMD_NO_OP, 902ea4a8c1dSMaruthi Srinivas Bayyavarapu .get_rptr = vce_v3_0_ring_get_rptr, 903ea4a8c1dSMaruthi Srinivas Bayyavarapu .get_wptr = vce_v3_0_ring_get_wptr, 904ea4a8c1dSMaruthi Srinivas Bayyavarapu .set_wptr = vce_v3_0_ring_set_wptr, 90598614701SChristian König .parse_cs = amdgpu_vce_ring_parse_cs_vm, 906e12f3d7aSChristian König .emit_frame_size = 907e12f3d7aSChristian König 6 + /* vce_v3_0_emit_vm_flush */ 908e12f3d7aSChristian König 4 + /* vce_v3_0_emit_pipeline_sync */ 909e12f3d7aSChristian König 6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */ 910e12f3d7aSChristian König .emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */ 911ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_ib = vce_v3_0_ring_emit_ib, 912ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_vm_flush = vce_v3_0_emit_vm_flush, 913ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_pipeline_sync = vce_v3_0_emit_pipeline_sync, 914ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_fence = amdgpu_vce_ring_emit_fence, 915ea4a8c1dSMaruthi Srinivas Bayyavarapu .test_ring = amdgpu_vce_ring_test_ring, 916ea4a8c1dSMaruthi Srinivas Bayyavarapu .test_ib = amdgpu_vce_ring_test_ib, 917ea4a8c1dSMaruthi Srinivas Bayyavarapu .insert_nop = amdgpu_ring_insert_nop, 918ea4a8c1dSMaruthi Srinivas Bayyavarapu .pad_ib = amdgpu_ring_generic_pad_ib, 919ea4a8c1dSMaruthi Srinivas Bayyavarapu .begin_use = amdgpu_vce_ring_begin_use, 920ea4a8c1dSMaruthi Srinivas Bayyavarapu .end_use = amdgpu_vce_ring_end_use, 921ea4a8c1dSMaruthi Srinivas Bayyavarapu }; 922ea4a8c1dSMaruthi Srinivas Bayyavarapu 923aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) 924aaa36a97SAlex Deucher { 92575c65480SAlex Deucher int i; 92675c65480SAlex Deucher 927ea4a8c1dSMaruthi Srinivas Bayyavarapu if (adev->asic_type >= CHIP_STONEY) { 92875c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) 929ea4a8c1dSMaruthi Srinivas Bayyavarapu adev->vce.ring[i].funcs = &vce_v3_0_ring_vm_funcs; 930ea4a8c1dSMaruthi Srinivas Bayyavarapu DRM_INFO("VCE enabled in VM mode\n"); 931ea4a8c1dSMaruthi Srinivas Bayyavarapu } else { 932ea4a8c1dSMaruthi Srinivas Bayyavarapu for (i = 0; i < adev->vce.num_rings; i++) 933ea4a8c1dSMaruthi Srinivas Bayyavarapu adev->vce.ring[i].funcs = &vce_v3_0_ring_phys_funcs; 934ea4a8c1dSMaruthi Srinivas Bayyavarapu DRM_INFO("VCE enabled in physical mode\n"); 935ea4a8c1dSMaruthi Srinivas Bayyavarapu } 936aaa36a97SAlex Deucher } 937aaa36a97SAlex Deucher 938aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = { 939aaa36a97SAlex Deucher .set = vce_v3_0_set_interrupt_state, 940aaa36a97SAlex Deucher .process = vce_v3_0_process_interrupt, 941aaa36a97SAlex Deucher }; 942aaa36a97SAlex Deucher 943aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev) 944aaa36a97SAlex Deucher { 945aaa36a97SAlex Deucher adev->vce.irq.num_types = 1; 946aaa36a97SAlex Deucher adev->vce.irq.funcs = &vce_v3_0_irq_funcs; 947aaa36a97SAlex Deucher }; 948a1255107SAlex Deucher 949a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_0_ip_block = 950a1255107SAlex Deucher { 951a1255107SAlex Deucher .type = AMD_IP_BLOCK_TYPE_VCE, 952a1255107SAlex Deucher .major = 3, 953a1255107SAlex Deucher .minor = 0, 954a1255107SAlex Deucher .rev = 0, 955a1255107SAlex Deucher .funcs = &vce_v3_0_ip_funcs, 956a1255107SAlex Deucher }; 957a1255107SAlex Deucher 958a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_1_ip_block = 959a1255107SAlex Deucher { 960a1255107SAlex Deucher .type = AMD_IP_BLOCK_TYPE_VCE, 961a1255107SAlex Deucher .major = 3, 962a1255107SAlex Deucher .minor = 1, 963a1255107SAlex Deucher .rev = 0, 964a1255107SAlex Deucher .funcs = &vce_v3_0_ip_funcs, 965a1255107SAlex Deucher }; 966a1255107SAlex Deucher 967a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_4_ip_block = 968a1255107SAlex Deucher { 969a1255107SAlex Deucher .type = AMD_IP_BLOCK_TYPE_VCE, 970a1255107SAlex Deucher .major = 3, 971a1255107SAlex Deucher .minor = 4, 972a1255107SAlex Deucher .rev = 0, 973a1255107SAlex Deucher .funcs = &vce_v3_0_ip_funcs, 974a1255107SAlex Deucher }; 975