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); 736f0359ffSAlex Deucher else if (ring == &adev->vce.ring[1]) 74aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR2); 756f0359ffSAlex Deucher else 766f0359ffSAlex Deucher return RREG32(mmVCE_RB_RPTR3); 77aaa36a97SAlex Deucher } 78aaa36a97SAlex Deucher 79aaa36a97SAlex Deucher /** 80aaa36a97SAlex Deucher * vce_v3_0_ring_get_wptr - get write pointer 81aaa36a97SAlex Deucher * 82aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 83aaa36a97SAlex Deucher * 84aaa36a97SAlex Deucher * Returns the current hardware write pointer 85aaa36a97SAlex Deucher */ 86aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring) 87aaa36a97SAlex Deucher { 88aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 89aaa36a97SAlex Deucher 90aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 91aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR); 926f0359ffSAlex Deucher else if (ring == &adev->vce.ring[1]) 93aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR2); 946f0359ffSAlex Deucher else 956f0359ffSAlex Deucher return RREG32(mmVCE_RB_WPTR3); 96aaa36a97SAlex Deucher } 97aaa36a97SAlex Deucher 98aaa36a97SAlex Deucher /** 99aaa36a97SAlex Deucher * vce_v3_0_ring_set_wptr - set write pointer 100aaa36a97SAlex Deucher * 101aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 102aaa36a97SAlex Deucher * 103aaa36a97SAlex Deucher * Commits the write pointer to the hardware 104aaa36a97SAlex Deucher */ 105aaa36a97SAlex Deucher static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring) 106aaa36a97SAlex Deucher { 107aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 108aaa36a97SAlex Deucher 109aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 110aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR, ring->wptr); 1116f0359ffSAlex Deucher else if (ring == &adev->vce.ring[1]) 112aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR2, ring->wptr); 1136f0359ffSAlex Deucher else 1146f0359ffSAlex Deucher WREG32(mmVCE_RB_WPTR3, ring->wptr); 115aaa36a97SAlex Deucher } 116aaa36a97SAlex Deucher 1170689a570SEric Huang static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override) 1180689a570SEric Huang { 119f3f0ea95STom St Denis WREG32_FIELD(VCE_RB_ARB_CTRL, VCE_CGTT_OVERRIDE, override ? 1 : 0); 1200689a570SEric Huang } 1210689a570SEric Huang 1220689a570SEric Huang static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, 1230689a570SEric Huang bool gated) 1240689a570SEric Huang { 125f3f0ea95STom St Denis u32 data; 126f16fe6d3STom St Denis 1270689a570SEric Huang /* Set Override to disable Clock Gating */ 1280689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, true); 1290689a570SEric Huang 1306f906814STom St Denis /* This function enables MGCG which is controlled by firmware. 1316f906814STom St Denis With the clocks in the gated state the core is still 1326f906814STom St Denis accessible but the firmware will throttle the clocks on the 1336f906814STom St Denis fly as necessary. 1340689a570SEric Huang */ 1356f906814STom St Denis if (gated) { 136f3f0ea95STom St Denis data = RREG32(mmVCE_CLOCK_GATING_B); 1370689a570SEric Huang data |= 0x1ff; 1380689a570SEric Huang data &= ~0xef0000; 1390689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1400689a570SEric Huang 141f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_CLOCK_GATING); 1420689a570SEric Huang data |= 0x3ff000; 1430689a570SEric Huang data &= ~0xffc00000; 1440689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1450689a570SEric Huang 146f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1470689a570SEric Huang data |= 0x2; 1486f906814STom St Denis data &= ~0x00010000; 1490689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1500689a570SEric Huang 151f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1520689a570SEric Huang data |= 0x37f; 1530689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1540689a570SEric Huang 155f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1560689a570SEric Huang data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1570689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1580689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1590689a570SEric Huang 0x8; 1600689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1610689a570SEric Huang } else { 162f3f0ea95STom St Denis data = RREG32(mmVCE_CLOCK_GATING_B); 1630689a570SEric Huang data &= ~0x80010; 1640689a570SEric Huang data |= 0xe70008; 1650689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1666f906814STom St Denis 167f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_CLOCK_GATING); 1680689a570SEric Huang data |= 0xffc00000; 1690689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1706f906814STom St Denis 171f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1720689a570SEric Huang data |= 0x10000; 1730689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1746f906814STom St Denis 175f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1760689a570SEric Huang data &= ~0xffc00000; 1770689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1786f906814STom St Denis 179f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1800689a570SEric Huang data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1810689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1820689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1830689a570SEric Huang 0x8); 1840689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1850689a570SEric Huang } 1860689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, false); 1870689a570SEric Huang } 1880689a570SEric Huang 189567e6e29Sjimqu static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev) 190567e6e29Sjimqu { 191567e6e29Sjimqu int i, j; 192567e6e29Sjimqu 193567e6e29Sjimqu for (i = 0; i < 10; ++i) { 194567e6e29Sjimqu for (j = 0; j < 100; ++j) { 195b7e2e9f7Sjimqu uint32_t status = RREG32(mmVCE_STATUS); 196b7e2e9f7Sjimqu 197567e6e29Sjimqu if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK) 198567e6e29Sjimqu return 0; 199567e6e29Sjimqu mdelay(10); 200567e6e29Sjimqu } 201567e6e29Sjimqu 202567e6e29Sjimqu DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); 203f3f0ea95STom St Denis WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1); 204567e6e29Sjimqu mdelay(10); 205f3f0ea95STom St Denis WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0); 206567e6e29Sjimqu mdelay(10); 207567e6e29Sjimqu } 208567e6e29Sjimqu 209567e6e29Sjimqu return -ETIMEDOUT; 210567e6e29Sjimqu } 211567e6e29Sjimqu 212aaa36a97SAlex Deucher /** 213aaa36a97SAlex Deucher * vce_v3_0_start - start VCE block 214aaa36a97SAlex Deucher * 215aaa36a97SAlex Deucher * @adev: amdgpu_device pointer 216aaa36a97SAlex Deucher * 217aaa36a97SAlex Deucher * Setup and start the VCE block 218aaa36a97SAlex Deucher */ 219aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev) 220aaa36a97SAlex Deucher { 221aaa36a97SAlex Deucher struct amdgpu_ring *ring; 222567e6e29Sjimqu int idx, r; 223567e6e29Sjimqu 224567e6e29Sjimqu ring = &adev->vce.ring[0]; 225567e6e29Sjimqu WREG32(mmVCE_RB_RPTR, ring->wptr); 226567e6e29Sjimqu WREG32(mmVCE_RB_WPTR, ring->wptr); 227567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr); 228567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); 229567e6e29Sjimqu WREG32(mmVCE_RB_SIZE, ring->ring_size / 4); 230567e6e29Sjimqu 231567e6e29Sjimqu ring = &adev->vce.ring[1]; 232567e6e29Sjimqu WREG32(mmVCE_RB_RPTR2, ring->wptr); 233567e6e29Sjimqu WREG32(mmVCE_RB_WPTR2, ring->wptr); 234567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr); 235567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); 236567e6e29Sjimqu WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4); 237aaa36a97SAlex Deucher 2386f0359ffSAlex Deucher ring = &adev->vce.ring[2]; 2396f0359ffSAlex Deucher WREG32(mmVCE_RB_RPTR3, ring->wptr); 2406f0359ffSAlex Deucher WREG32(mmVCE_RB_WPTR3, ring->wptr); 2416f0359ffSAlex Deucher WREG32(mmVCE_RB_BASE_LO3, ring->gpu_addr); 2426f0359ffSAlex Deucher WREG32(mmVCE_RB_BASE_HI3, upper_32_bits(ring->gpu_addr)); 2436f0359ffSAlex Deucher WREG32(mmVCE_RB_SIZE3, ring->ring_size / 4); 2446f0359ffSAlex Deucher 2455bbc553aSLeo Liu mutex_lock(&adev->grbm_idx_mutex); 2465bbc553aSLeo Liu for (idx = 0; idx < 2; ++idx) { 2476a585777SAlex Deucher if (adev->vce.harvest_config & (1 << idx)) 2486a585777SAlex Deucher continue; 2496a585777SAlex Deucher 250f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx); 2515bbc553aSLeo Liu vce_v3_0_mc_resume(adev, idx); 252f3f0ea95STom St Denis WREG32_FIELD(VCE_STATUS, JOB_BUSY, 1); 253567e6e29Sjimqu 2543c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) 2553c0ff9f1SLeo Liu WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001); 2563c0ff9f1SLeo Liu else 257f3f0ea95STom St Denis WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 1); 258aaa36a97SAlex Deucher 259f3f0ea95STom St Denis WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0); 260aaa36a97SAlex Deucher mdelay(100); 261aaa36a97SAlex Deucher 262567e6e29Sjimqu r = vce_v3_0_firmware_loaded(adev); 263aaa36a97SAlex Deucher 264aaa36a97SAlex Deucher /* clear BUSY flag */ 265f3f0ea95STom St Denis WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0); 266aaa36a97SAlex Deucher 267aaa36a97SAlex Deucher if (r) { 268aaa36a97SAlex Deucher DRM_ERROR("VCE not responding, giving up!!!\n"); 2695bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 270aaa36a97SAlex Deucher return r; 271aaa36a97SAlex Deucher } 2725bbc553aSLeo Liu } 2735bbc553aSLeo Liu 274f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); 2755bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 2765bbc553aSLeo Liu 277567e6e29Sjimqu return 0; 278567e6e29Sjimqu } 2795bbc553aSLeo Liu 280567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev) 281567e6e29Sjimqu { 282567e6e29Sjimqu int idx; 283567e6e29Sjimqu 284567e6e29Sjimqu mutex_lock(&adev->grbm_idx_mutex); 285567e6e29Sjimqu for (idx = 0; idx < 2; ++idx) { 286567e6e29Sjimqu if (adev->vce.harvest_config & (1 << idx)) 287567e6e29Sjimqu continue; 288567e6e29Sjimqu 289f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx); 290567e6e29Sjimqu 291567e6e29Sjimqu if (adev->asic_type >= CHIP_STONEY) 292567e6e29Sjimqu WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001); 293567e6e29Sjimqu else 294f3f0ea95STom St Denis WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 0); 295f3f0ea95STom St Denis 296567e6e29Sjimqu /* hold on ECPU */ 297f3f0ea95STom St Denis WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1); 298567e6e29Sjimqu 299567e6e29Sjimqu /* clear BUSY flag */ 300f3f0ea95STom St Denis WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0); 301567e6e29Sjimqu 302567e6e29Sjimqu /* Set Clock-Gating off */ 303567e6e29Sjimqu if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) 304567e6e29Sjimqu vce_v3_0_set_vce_sw_clock_gating(adev, false); 305567e6e29Sjimqu } 306567e6e29Sjimqu 307f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); 308567e6e29Sjimqu mutex_unlock(&adev->grbm_idx_mutex); 309aaa36a97SAlex Deucher 310aaa36a97SAlex Deucher return 0; 311aaa36a97SAlex Deucher } 312aaa36a97SAlex Deucher 3136a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS 0xC0014074 3146a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT 27 3156a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK 0x18000000 3166a585777SAlex Deucher 3176a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) 3186a585777SAlex Deucher { 3196a585777SAlex Deucher u32 tmp; 3206a585777SAlex Deucher 3212cc0c0b5SFlora Cui /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */ 322cfaba566SSamuel Li if ((adev->asic_type == CHIP_FIJI) || 3231b4eeea5SSonny Jiang (adev->asic_type == CHIP_STONEY) || 3242cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS10) || 3252cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS11)) 3261dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 327188a9bcdSAlex Deucher 328188a9bcdSAlex Deucher /* Tonga and CZ are dual or single pipe */ 3292f7d10b3SJammy Zhou if (adev->flags & AMD_IS_APU) 3306a585777SAlex Deucher tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) & 3316a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__MASK) >> 3326a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__SHIFT; 3336a585777SAlex Deucher else 3346a585777SAlex Deucher tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) & 3356a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE_MASK) >> 3366a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE__SHIFT; 3376a585777SAlex Deucher 3386a585777SAlex Deucher switch (tmp) { 3396a585777SAlex Deucher case 1: 3401dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0; 3416a585777SAlex Deucher case 2: 3421dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 3436a585777SAlex Deucher case 3: 3441dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1; 3456a585777SAlex Deucher default: 3461dab5f06STom St Denis return 0; 3476a585777SAlex Deucher } 3486a585777SAlex Deucher } 3496a585777SAlex Deucher 3505fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle) 351aaa36a97SAlex Deucher { 3525fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 3535fc3aeebSyanyang1 3546a585777SAlex Deucher adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); 3556a585777SAlex Deucher 3566a585777SAlex Deucher if ((adev->vce.harvest_config & 3576a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) == 3586a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 3596a585777SAlex Deucher return -ENOENT; 3606a585777SAlex Deucher 3616f0359ffSAlex Deucher adev->vce.num_rings = 3; 36275c65480SAlex Deucher 363aaa36a97SAlex Deucher vce_v3_0_set_ring_funcs(adev); 364aaa36a97SAlex Deucher vce_v3_0_set_irq_funcs(adev); 365aaa36a97SAlex Deucher 366aaa36a97SAlex Deucher return 0; 367aaa36a97SAlex Deucher } 368aaa36a97SAlex Deucher 3695fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle) 370aaa36a97SAlex Deucher { 3715fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 372aaa36a97SAlex Deucher struct amdgpu_ring *ring; 37375c65480SAlex Deucher int r, i; 374aaa36a97SAlex Deucher 375aaa36a97SAlex Deucher /* VCE */ 376aaa36a97SAlex Deucher r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq); 377aaa36a97SAlex Deucher if (r) 378aaa36a97SAlex Deucher return r; 379aaa36a97SAlex Deucher 380e9822622SLeo Liu r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE + 381e9822622SLeo Liu (VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2); 382aaa36a97SAlex Deucher if (r) 383aaa36a97SAlex Deucher return r; 384aaa36a97SAlex Deucher 385aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 386aaa36a97SAlex Deucher if (r) 387aaa36a97SAlex Deucher return r; 388aaa36a97SAlex Deucher 38975c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) { 39075c65480SAlex Deucher ring = &adev->vce.ring[i]; 39175c65480SAlex Deucher sprintf(ring->name, "vce%d", i); 392a3f1cf35SChristian König r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf, 393aaa36a97SAlex Deucher &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); 394aaa36a97SAlex Deucher if (r) 395aaa36a97SAlex Deucher return r; 39675c65480SAlex Deucher } 397aaa36a97SAlex Deucher 398aaa36a97SAlex Deucher return r; 399aaa36a97SAlex Deucher } 400aaa36a97SAlex Deucher 4015fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle) 402aaa36a97SAlex Deucher { 403aaa36a97SAlex Deucher int r; 4045fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 405aaa36a97SAlex Deucher 406aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 407aaa36a97SAlex Deucher if (r) 408aaa36a97SAlex Deucher return r; 409aaa36a97SAlex Deucher 410aaa36a97SAlex Deucher r = amdgpu_vce_sw_fini(adev); 411aaa36a97SAlex Deucher if (r) 412aaa36a97SAlex Deucher return r; 413aaa36a97SAlex Deucher 414aaa36a97SAlex Deucher return r; 415aaa36a97SAlex Deucher } 416aaa36a97SAlex Deucher 4175fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle) 418aaa36a97SAlex Deucher { 419691ca86aSTom St Denis int r, i; 4205fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 421aaa36a97SAlex Deucher 422aaa36a97SAlex Deucher r = vce_v3_0_start(adev); 423aaa36a97SAlex Deucher if (r) 424aaa36a97SAlex Deucher return r; 425aaa36a97SAlex Deucher 42675c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) 42775c65480SAlex Deucher adev->vce.ring[i].ready = false; 428aaa36a97SAlex Deucher 42975c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) { 430691ca86aSTom St Denis r = amdgpu_ring_test_ring(&adev->vce.ring[i]); 431691ca86aSTom St Denis if (r) 432aaa36a97SAlex Deucher return r; 433691ca86aSTom St Denis else 434691ca86aSTom St Denis adev->vce.ring[i].ready = true; 435aaa36a97SAlex Deucher } 436aaa36a97SAlex Deucher 437aaa36a97SAlex Deucher DRM_INFO("VCE initialized successfully.\n"); 438aaa36a97SAlex Deucher 439aaa36a97SAlex Deucher return 0; 440aaa36a97SAlex Deucher } 441aaa36a97SAlex Deucher 4425fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle) 443aaa36a97SAlex Deucher { 444567e6e29Sjimqu int r; 445567e6e29Sjimqu struct amdgpu_device *adev = (struct amdgpu_device *)handle; 446567e6e29Sjimqu 447567e6e29Sjimqu r = vce_v3_0_wait_for_idle(handle); 448567e6e29Sjimqu if (r) 449567e6e29Sjimqu return r; 450567e6e29Sjimqu 451567e6e29Sjimqu return vce_v3_0_stop(adev); 452aaa36a97SAlex Deucher } 453aaa36a97SAlex Deucher 4545fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle) 455aaa36a97SAlex Deucher { 456aaa36a97SAlex Deucher int r; 4575fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 458aaa36a97SAlex Deucher 459aaa36a97SAlex Deucher r = vce_v3_0_hw_fini(adev); 460aaa36a97SAlex Deucher if (r) 461aaa36a97SAlex Deucher return r; 462aaa36a97SAlex Deucher 463aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 464aaa36a97SAlex Deucher if (r) 465aaa36a97SAlex Deucher return r; 466aaa36a97SAlex Deucher 467aaa36a97SAlex Deucher return r; 468aaa36a97SAlex Deucher } 469aaa36a97SAlex Deucher 4705fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle) 471aaa36a97SAlex Deucher { 472aaa36a97SAlex Deucher int r; 4735fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 474aaa36a97SAlex Deucher 475aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 476aaa36a97SAlex Deucher if (r) 477aaa36a97SAlex Deucher return r; 478aaa36a97SAlex Deucher 479aaa36a97SAlex Deucher r = vce_v3_0_hw_init(adev); 480aaa36a97SAlex Deucher if (r) 481aaa36a97SAlex Deucher return r; 482aaa36a97SAlex Deucher 483aaa36a97SAlex Deucher return r; 484aaa36a97SAlex Deucher } 485aaa36a97SAlex Deucher 4865bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) 487aaa36a97SAlex Deucher { 488aaa36a97SAlex Deucher uint32_t offset, size; 489aaa36a97SAlex Deucher 490aaa36a97SAlex Deucher WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16)); 491aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); 492aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); 4936f906814STom St Denis WREG32(mmVCE_CLOCK_GATING_B, 0x1FF); 494aaa36a97SAlex Deucher 495aaa36a97SAlex Deucher WREG32(mmVCE_LMI_CTRL, 0x00398000); 496aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1); 497aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL, 0); 498aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL1, 0); 499aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VM_CTRL, 0); 5003c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) { 5013c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8)); 5023c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8)); 5033c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8)); 5043c0ff9f1SLeo Liu } else 505aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8)); 506aaa36a97SAlex Deucher offset = AMDGPU_VCE_FIRMWARE_OFFSET; 507e9822622SLeo Liu size = VCE_V3_0_FW_SIZE; 508aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff); 509aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE0, size); 510aaa36a97SAlex Deucher 5115bbc553aSLeo Liu if (idx == 0) { 512aaa36a97SAlex Deucher offset += size; 513e9822622SLeo Liu size = VCE_V3_0_STACK_SIZE; 514aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff); 515aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 516aaa36a97SAlex Deucher offset += size; 517e9822622SLeo Liu size = VCE_V3_0_DATA_SIZE; 518aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff); 519aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5205bbc553aSLeo Liu } else { 5215bbc553aSLeo Liu offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE; 5225bbc553aSLeo Liu size = VCE_V3_0_STACK_SIZE; 5235bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff); 5245bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 5255bbc553aSLeo Liu offset += size; 5265bbc553aSLeo Liu size = VCE_V3_0_DATA_SIZE; 5275bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff); 5285bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5295bbc553aSLeo Liu } 530aaa36a97SAlex Deucher 531aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); 532f3f0ea95STom St Denis WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1); 533aaa36a97SAlex Deucher } 534aaa36a97SAlex Deucher 5355fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle) 536aaa36a97SAlex Deucher { 5375fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 538be4f38e2SAlex Deucher u32 mask = 0; 5395fc3aeebSyanyang1 54074af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK; 54174af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK; 542be4f38e2SAlex Deucher 543be4f38e2SAlex Deucher return !(RREG32(mmSRBM_STATUS2) & mask); 544aaa36a97SAlex Deucher } 545aaa36a97SAlex Deucher 5465fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle) 547aaa36a97SAlex Deucher { 548aaa36a97SAlex Deucher unsigned i; 5495fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 550be4f38e2SAlex Deucher 55192988e60STom St Denis for (i = 0; i < adev->usec_timeout; i++) 55292988e60STom St Denis if (vce_v3_0_is_idle(handle)) 553aaa36a97SAlex Deucher return 0; 55492988e60STom St Denis 555aaa36a97SAlex Deucher return -ETIMEDOUT; 556aaa36a97SAlex Deucher } 557aaa36a97SAlex Deucher 558ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK 0x00000008L /* AUTO_BUSY */ 559ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK 0x00000010L /* RB0_BUSY */ 560ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_RB1_BUSY_MASK 0x00000020L /* RB1_BUSY */ 561ac8e3f30SRex Zhu #define AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \ 562ac8e3f30SRex Zhu VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK) 563115933a5SChunming Zhou 564da146d3bSAlex Deucher static bool vce_v3_0_check_soft_reset(void *handle) 565115933a5SChunming Zhou { 566115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 567115933a5SChunming Zhou u32 srbm_soft_reset = 0; 568115933a5SChunming Zhou 569115933a5SChunming Zhou /* According to VCE team , we should use VCE_STATUS instead 570115933a5SChunming Zhou * SRBM_STATUS.VCE_BUSY bit for busy status checking. 571115933a5SChunming Zhou * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE 572115933a5SChunming Zhou * instance's registers are accessed 573115933a5SChunming Zhou * (0 for 1st instance, 10 for 2nd instance). 574115933a5SChunming Zhou * 575115933a5SChunming Zhou *VCE_STATUS 576115933a5SChunming Zhou *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 | |FW_LOADED|JOB | 577115933a5SChunming Zhou *|----+----+-----------+----+----+----+----------+---------+----| 578115933a5SChunming Zhou *|bit8|bit7| bit6 |bit5|bit4|bit3| bit2 | bit1 |bit0| 579115933a5SChunming Zhou * 580115933a5SChunming Zhou * VCE team suggest use bit 3--bit 6 for busy status check 581115933a5SChunming Zhou */ 5829aeb774cSTom St Denis mutex_lock(&adev->grbm_idx_mutex); 583f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 584115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 585115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 586115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 587115933a5SChunming Zhou } 588f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10); 589115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 590115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 591115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 592115933a5SChunming Zhou } 593f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 594da146d3bSAlex Deucher mutex_unlock(&adev->grbm_idx_mutex); 595115933a5SChunming Zhou 596115933a5SChunming Zhou if (srbm_soft_reset) { 597115933a5SChunming Zhou adev->vce.srbm_soft_reset = srbm_soft_reset; 598da146d3bSAlex Deucher return true; 599115933a5SChunming Zhou } else { 600115933a5SChunming Zhou adev->vce.srbm_soft_reset = 0; 601da146d3bSAlex Deucher return false; 602115933a5SChunming Zhou } 603115933a5SChunming Zhou } 604115933a5SChunming Zhou 6055fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle) 606aaa36a97SAlex Deucher { 6075fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 608115933a5SChunming Zhou u32 srbm_soft_reset; 6095fc3aeebSyanyang1 610da146d3bSAlex Deucher if (!adev->vce.srbm_soft_reset) 611115933a5SChunming Zhou return 0; 612115933a5SChunming Zhou srbm_soft_reset = adev->vce.srbm_soft_reset; 613be4f38e2SAlex Deucher 614115933a5SChunming Zhou if (srbm_soft_reset) { 615115933a5SChunming Zhou u32 tmp; 616115933a5SChunming Zhou 617115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 618115933a5SChunming Zhou tmp |= srbm_soft_reset; 619115933a5SChunming Zhou dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); 620115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 621115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 622115933a5SChunming Zhou 623115933a5SChunming Zhou udelay(50); 624115933a5SChunming Zhou 625115933a5SChunming Zhou tmp &= ~srbm_soft_reset; 626115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 627115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 628115933a5SChunming Zhou 629115933a5SChunming Zhou /* Wait a little for things to settle down */ 630115933a5SChunming Zhou udelay(50); 631115933a5SChunming Zhou } 632115933a5SChunming Zhou 633115933a5SChunming Zhou return 0; 634115933a5SChunming Zhou } 635115933a5SChunming Zhou 636115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle) 637115933a5SChunming Zhou { 638115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 639115933a5SChunming Zhou 640da146d3bSAlex Deucher if (!adev->vce.srbm_soft_reset) 641115933a5SChunming Zhou return 0; 642115933a5SChunming Zhou 643aaa36a97SAlex Deucher mdelay(5); 644aaa36a97SAlex Deucher 645115933a5SChunming Zhou return vce_v3_0_suspend(adev); 646115933a5SChunming Zhou } 647115933a5SChunming Zhou 648115933a5SChunming Zhou 649115933a5SChunming Zhou static int vce_v3_0_post_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 656115933a5SChunming Zhou mdelay(5); 657115933a5SChunming Zhou 658115933a5SChunming Zhou return vce_v3_0_resume(adev); 659aaa36a97SAlex Deucher } 660aaa36a97SAlex Deucher 661aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, 662aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 663aaa36a97SAlex Deucher unsigned type, 664aaa36a97SAlex Deucher enum amdgpu_interrupt_state state) 665aaa36a97SAlex Deucher { 666aaa36a97SAlex Deucher uint32_t val = 0; 667aaa36a97SAlex Deucher 668aaa36a97SAlex Deucher if (state == AMDGPU_IRQ_STATE_ENABLE) 669aaa36a97SAlex Deucher val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK; 670aaa36a97SAlex Deucher 671aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 672aaa36a97SAlex Deucher return 0; 673aaa36a97SAlex Deucher } 674aaa36a97SAlex Deucher 675aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev, 676aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 677aaa36a97SAlex Deucher struct amdgpu_iv_entry *entry) 678aaa36a97SAlex Deucher { 679aaa36a97SAlex Deucher DRM_DEBUG("IH: VCE\n"); 680d6c29c30SLeo Liu 681f3f0ea95STom St Denis WREG32_FIELD(VCE_SYS_INT_STATUS, VCE_SYS_INT_TRAP_INTERRUPT_INT, 1); 682d6c29c30SLeo Liu 683aaa36a97SAlex Deucher switch (entry->src_data) { 684aaa36a97SAlex Deucher case 0: 685aaa36a97SAlex Deucher case 1: 6866f0359ffSAlex Deucher case 2: 68781da2edeSTom St Denis amdgpu_fence_process(&adev->vce.ring[entry->src_data]); 688aaa36a97SAlex Deucher break; 689aaa36a97SAlex Deucher default: 690aaa36a97SAlex Deucher DRM_ERROR("Unhandled interrupt: %d %d\n", 691aaa36a97SAlex Deucher entry->src_id, entry->src_data); 692aaa36a97SAlex Deucher break; 693aaa36a97SAlex Deucher } 694aaa36a97SAlex Deucher 695aaa36a97SAlex Deucher return 0; 696aaa36a97SAlex Deucher } 697aaa36a97SAlex Deucher 6980174df4eSRex Zhu static void vce_v3_0_set_bypass_mode(struct amdgpu_device *adev, bool enable) 699ec38f188SRex Zhu { 700ec38f188SRex Zhu u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL); 701ec38f188SRex Zhu 702ec38f188SRex Zhu if (enable) 703ec38f188SRex Zhu tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 704ec38f188SRex Zhu else 705ec38f188SRex Zhu tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 706ec38f188SRex Zhu 707ec38f188SRex Zhu WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp); 708ec38f188SRex Zhu } 709ec38f188SRex Zhu 7105fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle, 7115fc3aeebSyanyang1 enum amd_clockgating_state state) 712aaa36a97SAlex Deucher { 7130689a570SEric Huang struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7140689a570SEric Huang bool enable = (state == AMD_CG_STATE_GATE) ? true : false; 7150689a570SEric Huang int i; 7160689a570SEric Huang 717c04399f1SRex Zhu if ((adev->asic_type == CHIP_POLARIS10) || 7183374dcebSRex Zhu (adev->asic_type == CHIP_TONGA) || 7193374dcebSRex Zhu (adev->asic_type == CHIP_FIJI)) 7200174df4eSRex Zhu vce_v3_0_set_bypass_mode(adev, enable); 721ec38f188SRex Zhu 722e3b04bc7SAlex Deucher if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) 7230689a570SEric Huang return 0; 7240689a570SEric Huang 7250689a570SEric Huang mutex_lock(&adev->grbm_idx_mutex); 7260689a570SEric Huang for (i = 0; i < 2; i++) { 7270689a570SEric Huang /* Program VCE Instance 0 or 1 if not harvested */ 7280689a570SEric Huang if (adev->vce.harvest_config & (1 << i)) 7290689a570SEric Huang continue; 7300689a570SEric Huang 731f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i); 7320689a570SEric Huang 7330689a570SEric Huang if (enable) { 7340689a570SEric Huang /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ 7350689a570SEric Huang uint32_t data = RREG32(mmVCE_CLOCK_GATING_A); 7360689a570SEric Huang data &= ~(0xf | 0xff0); 7370689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7380689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_A, data); 7390689a570SEric Huang 7400689a570SEric Huang /* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */ 7410689a570SEric Huang data = RREG32(mmVCE_UENC_CLOCK_GATING); 7420689a570SEric Huang data &= ~(0xf | 0xff0); 7430689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7440689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 7450689a570SEric Huang } 7460689a570SEric Huang 7470689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, enable); 7480689a570SEric Huang } 7490689a570SEric Huang 750f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); 7510689a570SEric Huang mutex_unlock(&adev->grbm_idx_mutex); 7520689a570SEric Huang 753aaa36a97SAlex Deucher return 0; 754aaa36a97SAlex Deucher } 755aaa36a97SAlex Deucher 7565fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle, 7575fc3aeebSyanyang1 enum amd_powergating_state state) 758aaa36a97SAlex Deucher { 759aaa36a97SAlex Deucher /* This doesn't actually powergate the VCE block. 760aaa36a97SAlex Deucher * That's done in the dpm code via the SMC. This 761aaa36a97SAlex Deucher * just re-inits the block as necessary. The actual 762aaa36a97SAlex Deucher * gating still happens in the dpm code. We should 763aaa36a97SAlex Deucher * revisit this when there is a cleaner line between 764aaa36a97SAlex Deucher * the smc and the hw blocks 765aaa36a97SAlex Deucher */ 7665fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7675fc3aeebSyanyang1 768e3b04bc7SAlex Deucher if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE)) 769808a934fSAlex Deucher return 0; 770808a934fSAlex Deucher 7715fc3aeebSyanyang1 if (state == AMD_PG_STATE_GATE) 772aaa36a97SAlex Deucher /* XXX do we need a vce_v3_0_stop()? */ 773aaa36a97SAlex Deucher return 0; 774aaa36a97SAlex Deucher else 775aaa36a97SAlex Deucher return vce_v3_0_start(adev); 776aaa36a97SAlex Deucher } 777aaa36a97SAlex Deucher 778ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring, 779ea4a8c1dSMaruthi Srinivas Bayyavarapu struct amdgpu_ib *ib, unsigned int vm_id, bool ctx_switch) 780ea4a8c1dSMaruthi Srinivas Bayyavarapu { 781ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_IB_VM); 782ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, vm_id); 783ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr)); 784ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr)); 785ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, ib->length_dw); 786ea4a8c1dSMaruthi Srinivas Bayyavarapu } 787ea4a8c1dSMaruthi Srinivas Bayyavarapu 788ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring, 789ea4a8c1dSMaruthi Srinivas Bayyavarapu unsigned int vm_id, uint64_t pd_addr) 790ea4a8c1dSMaruthi Srinivas Bayyavarapu { 791ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_UPDATE_PTB); 792ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, vm_id); 793ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, pd_addr >> 12); 794ea4a8c1dSMaruthi Srinivas Bayyavarapu 795ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_FLUSH_TLB); 796ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, vm_id); 797ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_END); 798ea4a8c1dSMaruthi Srinivas Bayyavarapu } 799ea4a8c1dSMaruthi Srinivas Bayyavarapu 800ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_pipeline_sync(struct amdgpu_ring *ring) 801ea4a8c1dSMaruthi Srinivas Bayyavarapu { 802ea4a8c1dSMaruthi Srinivas Bayyavarapu uint32_t seq = ring->fence_drv.sync_seq; 803ea4a8c1dSMaruthi Srinivas Bayyavarapu uint64_t addr = ring->fence_drv.gpu_addr; 804ea4a8c1dSMaruthi Srinivas Bayyavarapu 805ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_WAIT_GE); 806ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, lower_32_bits(addr)); 807ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, upper_32_bits(addr)); 808ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, seq); 809ea4a8c1dSMaruthi Srinivas Bayyavarapu } 810ea4a8c1dSMaruthi Srinivas Bayyavarapu 8115fc3aeebSyanyang1 const struct amd_ip_funcs vce_v3_0_ip_funcs = { 81288a907d6STom St Denis .name = "vce_v3_0", 813aaa36a97SAlex Deucher .early_init = vce_v3_0_early_init, 814aaa36a97SAlex Deucher .late_init = NULL, 815aaa36a97SAlex Deucher .sw_init = vce_v3_0_sw_init, 816aaa36a97SAlex Deucher .sw_fini = vce_v3_0_sw_fini, 817aaa36a97SAlex Deucher .hw_init = vce_v3_0_hw_init, 818aaa36a97SAlex Deucher .hw_fini = vce_v3_0_hw_fini, 819aaa36a97SAlex Deucher .suspend = vce_v3_0_suspend, 820aaa36a97SAlex Deucher .resume = vce_v3_0_resume, 821aaa36a97SAlex Deucher .is_idle = vce_v3_0_is_idle, 822aaa36a97SAlex Deucher .wait_for_idle = vce_v3_0_wait_for_idle, 823115933a5SChunming Zhou .check_soft_reset = vce_v3_0_check_soft_reset, 824115933a5SChunming Zhou .pre_soft_reset = vce_v3_0_pre_soft_reset, 825aaa36a97SAlex Deucher .soft_reset = vce_v3_0_soft_reset, 826115933a5SChunming Zhou .post_soft_reset = vce_v3_0_post_soft_reset, 827aaa36a97SAlex Deucher .set_clockgating_state = vce_v3_0_set_clockgating_state, 828aaa36a97SAlex Deucher .set_powergating_state = vce_v3_0_set_powergating_state, 829aaa36a97SAlex Deucher }; 830aaa36a97SAlex Deucher 831ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = { 832aaa36a97SAlex Deucher .get_rptr = vce_v3_0_ring_get_rptr, 833aaa36a97SAlex Deucher .get_wptr = vce_v3_0_ring_get_wptr, 834aaa36a97SAlex Deucher .set_wptr = vce_v3_0_ring_set_wptr, 835aaa36a97SAlex Deucher .parse_cs = amdgpu_vce_ring_parse_cs, 836e12f3d7aSChristian König .emit_frame_size = 837e12f3d7aSChristian König 4 + /* vce_v3_0_emit_pipeline_sync */ 838e12f3d7aSChristian König 6, /* amdgpu_vce_ring_emit_fence x1 no user fence */ 839e12f3d7aSChristian König .emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */ 840aaa36a97SAlex Deucher .emit_ib = amdgpu_vce_ring_emit_ib, 841aaa36a97SAlex Deucher .emit_fence = amdgpu_vce_ring_emit_fence, 842aaa36a97SAlex Deucher .test_ring = amdgpu_vce_ring_test_ring, 843aaa36a97SAlex Deucher .test_ib = amdgpu_vce_ring_test_ib, 844edff0e28SJammy Zhou .insert_nop = amdgpu_ring_insert_nop, 8459e5d5309SChristian König .pad_ib = amdgpu_ring_generic_pad_ib, 846ebff485eSChristian König .begin_use = amdgpu_vce_ring_begin_use, 847ebff485eSChristian König .end_use = amdgpu_vce_ring_end_use, 848aaa36a97SAlex Deucher }; 849aaa36a97SAlex Deucher 850ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = { 851ea4a8c1dSMaruthi Srinivas Bayyavarapu .get_rptr = vce_v3_0_ring_get_rptr, 852ea4a8c1dSMaruthi Srinivas Bayyavarapu .get_wptr = vce_v3_0_ring_get_wptr, 853ea4a8c1dSMaruthi Srinivas Bayyavarapu .set_wptr = vce_v3_0_ring_set_wptr, 854e12f3d7aSChristian König .emit_frame_size = 855e12f3d7aSChristian König 6 + /* vce_v3_0_emit_vm_flush */ 856e12f3d7aSChristian König 4 + /* vce_v3_0_emit_pipeline_sync */ 857e12f3d7aSChristian König 6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */ 858e12f3d7aSChristian König .emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */ 859ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_ib = vce_v3_0_ring_emit_ib, 860ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_vm_flush = vce_v3_0_emit_vm_flush, 861ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_pipeline_sync = vce_v3_0_emit_pipeline_sync, 862ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_fence = amdgpu_vce_ring_emit_fence, 863ea4a8c1dSMaruthi Srinivas Bayyavarapu .test_ring = amdgpu_vce_ring_test_ring, 864ea4a8c1dSMaruthi Srinivas Bayyavarapu .test_ib = amdgpu_vce_ring_test_ib, 865ea4a8c1dSMaruthi Srinivas Bayyavarapu .insert_nop = amdgpu_ring_insert_nop, 866ea4a8c1dSMaruthi Srinivas Bayyavarapu .pad_ib = amdgpu_ring_generic_pad_ib, 867ea4a8c1dSMaruthi Srinivas Bayyavarapu .begin_use = amdgpu_vce_ring_begin_use, 868ea4a8c1dSMaruthi Srinivas Bayyavarapu .end_use = amdgpu_vce_ring_end_use, 869ea4a8c1dSMaruthi Srinivas Bayyavarapu }; 870ea4a8c1dSMaruthi Srinivas Bayyavarapu 871aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) 872aaa36a97SAlex Deucher { 87375c65480SAlex Deucher int i; 87475c65480SAlex Deucher 875ea4a8c1dSMaruthi Srinivas Bayyavarapu if (adev->asic_type >= CHIP_STONEY) { 87675c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) 877ea4a8c1dSMaruthi Srinivas Bayyavarapu adev->vce.ring[i].funcs = &vce_v3_0_ring_vm_funcs; 878ea4a8c1dSMaruthi Srinivas Bayyavarapu DRM_INFO("VCE enabled in VM mode\n"); 879ea4a8c1dSMaruthi Srinivas Bayyavarapu } else { 880ea4a8c1dSMaruthi Srinivas Bayyavarapu for (i = 0; i < adev->vce.num_rings; i++) 881ea4a8c1dSMaruthi Srinivas Bayyavarapu adev->vce.ring[i].funcs = &vce_v3_0_ring_phys_funcs; 882ea4a8c1dSMaruthi Srinivas Bayyavarapu DRM_INFO("VCE enabled in physical mode\n"); 883ea4a8c1dSMaruthi Srinivas Bayyavarapu } 884aaa36a97SAlex Deucher } 885aaa36a97SAlex Deucher 886aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = { 887aaa36a97SAlex Deucher .set = vce_v3_0_set_interrupt_state, 888aaa36a97SAlex Deucher .process = vce_v3_0_process_interrupt, 889aaa36a97SAlex Deucher }; 890aaa36a97SAlex Deucher 891aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev) 892aaa36a97SAlex Deucher { 893aaa36a97SAlex Deucher adev->vce.irq.num_types = 1; 894aaa36a97SAlex Deucher adev->vce.irq.funcs = &vce_v3_0_irq_funcs; 895aaa36a97SAlex Deucher }; 896