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 55ef6239e0SAlex Deucher #define FW_52_8_3 ((52 << 24) | (8 << 16) | (3 << 8)) 56ef6239e0SAlex Deucher 575bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx); 58aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev); 59aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev); 60567e6e29Sjimqu static int vce_v3_0_wait_for_idle(void *handle); 61aaa36a97SAlex Deucher 62aaa36a97SAlex Deucher /** 63aaa36a97SAlex Deucher * vce_v3_0_ring_get_rptr - get read pointer 64aaa36a97SAlex Deucher * 65aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 66aaa36a97SAlex Deucher * 67aaa36a97SAlex Deucher * Returns the current hardware read pointer 68aaa36a97SAlex Deucher */ 69aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring) 70aaa36a97SAlex Deucher { 71aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 72aaa36a97SAlex Deucher 73aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 74aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR); 756f0359ffSAlex Deucher else if (ring == &adev->vce.ring[1]) 76aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR2); 776f0359ffSAlex Deucher else 786f0359ffSAlex Deucher return RREG32(mmVCE_RB_RPTR3); 79aaa36a97SAlex Deucher } 80aaa36a97SAlex Deucher 81aaa36a97SAlex Deucher /** 82aaa36a97SAlex Deucher * vce_v3_0_ring_get_wptr - get write pointer 83aaa36a97SAlex Deucher * 84aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 85aaa36a97SAlex Deucher * 86aaa36a97SAlex Deucher * Returns the current hardware write pointer 87aaa36a97SAlex Deucher */ 88aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring) 89aaa36a97SAlex Deucher { 90aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 91aaa36a97SAlex Deucher 92aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 93aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR); 946f0359ffSAlex Deucher else if (ring == &adev->vce.ring[1]) 95aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR2); 966f0359ffSAlex Deucher else 976f0359ffSAlex Deucher return RREG32(mmVCE_RB_WPTR3); 98aaa36a97SAlex Deucher } 99aaa36a97SAlex Deucher 100aaa36a97SAlex Deucher /** 101aaa36a97SAlex Deucher * vce_v3_0_ring_set_wptr - set write pointer 102aaa36a97SAlex Deucher * 103aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 104aaa36a97SAlex Deucher * 105aaa36a97SAlex Deucher * Commits the write pointer to the hardware 106aaa36a97SAlex Deucher */ 107aaa36a97SAlex Deucher static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring) 108aaa36a97SAlex Deucher { 109aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 110aaa36a97SAlex Deucher 111aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 112aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR, ring->wptr); 1136f0359ffSAlex Deucher else if (ring == &adev->vce.ring[1]) 114aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR2, ring->wptr); 1156f0359ffSAlex Deucher else 1166f0359ffSAlex Deucher WREG32(mmVCE_RB_WPTR3, ring->wptr); 117aaa36a97SAlex Deucher } 118aaa36a97SAlex Deucher 1190689a570SEric Huang static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override) 1200689a570SEric Huang { 121f3f0ea95STom St Denis WREG32_FIELD(VCE_RB_ARB_CTRL, VCE_CGTT_OVERRIDE, override ? 1 : 0); 1220689a570SEric Huang } 1230689a570SEric Huang 1240689a570SEric Huang static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, 1250689a570SEric Huang bool gated) 1260689a570SEric Huang { 127f3f0ea95STom St Denis u32 data; 128f16fe6d3STom St Denis 1290689a570SEric Huang /* Set Override to disable Clock Gating */ 1300689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, true); 1310689a570SEric Huang 1326f906814STom St Denis /* This function enables MGCG which is controlled by firmware. 1336f906814STom St Denis With the clocks in the gated state the core is still 1346f906814STom St Denis accessible but the firmware will throttle the clocks on the 1356f906814STom St Denis fly as necessary. 1360689a570SEric Huang */ 137ecc2cf7cSMaruthi Srinivas Bayyavarapu if (!gated) { 138f3f0ea95STom St Denis data = RREG32(mmVCE_CLOCK_GATING_B); 1390689a570SEric Huang data |= 0x1ff; 1400689a570SEric Huang data &= ~0xef0000; 1410689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1420689a570SEric Huang 143f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_CLOCK_GATING); 1440689a570SEric Huang data |= 0x3ff000; 1450689a570SEric Huang data &= ~0xffc00000; 1460689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1470689a570SEric Huang 148f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1490689a570SEric Huang data |= 0x2; 1506f906814STom St Denis data &= ~0x00010000; 1510689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1520689a570SEric Huang 153f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1540689a570SEric Huang data |= 0x37f; 1550689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1560689a570SEric Huang 157f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1580689a570SEric Huang data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1590689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1600689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1610689a570SEric Huang 0x8; 1620689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1630689a570SEric Huang } else { 164f3f0ea95STom St Denis data = RREG32(mmVCE_CLOCK_GATING_B); 1650689a570SEric Huang data &= ~0x80010; 1660689a570SEric Huang data |= 0xe70008; 1670689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1686f906814STom St Denis 169f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_CLOCK_GATING); 1700689a570SEric Huang data |= 0xffc00000; 1710689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1726f906814STom St Denis 173f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1740689a570SEric Huang data |= 0x10000; 1750689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1766f906814STom St Denis 177f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1780689a570SEric Huang data &= ~0xffc00000; 1790689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1806f906814STom St Denis 181f3f0ea95STom St Denis data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1820689a570SEric Huang data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1830689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1840689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1850689a570SEric Huang 0x8); 1860689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1870689a570SEric Huang } 1880689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, false); 1890689a570SEric Huang } 1900689a570SEric Huang 191567e6e29Sjimqu static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev) 192567e6e29Sjimqu { 193567e6e29Sjimqu int i, j; 194567e6e29Sjimqu 195567e6e29Sjimqu for (i = 0; i < 10; ++i) { 196567e6e29Sjimqu for (j = 0; j < 100; ++j) { 197b7e2e9f7Sjimqu uint32_t status = RREG32(mmVCE_STATUS); 198b7e2e9f7Sjimqu 199567e6e29Sjimqu if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK) 200567e6e29Sjimqu return 0; 201567e6e29Sjimqu mdelay(10); 202567e6e29Sjimqu } 203567e6e29Sjimqu 204567e6e29Sjimqu DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); 205f3f0ea95STom St Denis WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1); 206567e6e29Sjimqu mdelay(10); 207f3f0ea95STom St Denis WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0); 208567e6e29Sjimqu mdelay(10); 209567e6e29Sjimqu } 210567e6e29Sjimqu 211567e6e29Sjimqu return -ETIMEDOUT; 212567e6e29Sjimqu } 213567e6e29Sjimqu 214aaa36a97SAlex Deucher /** 215aaa36a97SAlex Deucher * vce_v3_0_start - start VCE block 216aaa36a97SAlex Deucher * 217aaa36a97SAlex Deucher * @adev: amdgpu_device pointer 218aaa36a97SAlex Deucher * 219aaa36a97SAlex Deucher * Setup and start the VCE block 220aaa36a97SAlex Deucher */ 221aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev) 222aaa36a97SAlex Deucher { 223aaa36a97SAlex Deucher struct amdgpu_ring *ring; 224567e6e29Sjimqu int idx, r; 225567e6e29Sjimqu 226567e6e29Sjimqu ring = &adev->vce.ring[0]; 227567e6e29Sjimqu WREG32(mmVCE_RB_RPTR, ring->wptr); 228567e6e29Sjimqu WREG32(mmVCE_RB_WPTR, ring->wptr); 229567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr); 230567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); 231567e6e29Sjimqu WREG32(mmVCE_RB_SIZE, ring->ring_size / 4); 232567e6e29Sjimqu 233567e6e29Sjimqu ring = &adev->vce.ring[1]; 234567e6e29Sjimqu WREG32(mmVCE_RB_RPTR2, ring->wptr); 235567e6e29Sjimqu WREG32(mmVCE_RB_WPTR2, ring->wptr); 236567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr); 237567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); 238567e6e29Sjimqu WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4); 239aaa36a97SAlex Deucher 2406f0359ffSAlex Deucher ring = &adev->vce.ring[2]; 2416f0359ffSAlex Deucher WREG32(mmVCE_RB_RPTR3, ring->wptr); 2426f0359ffSAlex Deucher WREG32(mmVCE_RB_WPTR3, ring->wptr); 2436f0359ffSAlex Deucher WREG32(mmVCE_RB_BASE_LO3, ring->gpu_addr); 2446f0359ffSAlex Deucher WREG32(mmVCE_RB_BASE_HI3, upper_32_bits(ring->gpu_addr)); 2456f0359ffSAlex Deucher WREG32(mmVCE_RB_SIZE3, ring->ring_size / 4); 2466f0359ffSAlex Deucher 2475bbc553aSLeo Liu mutex_lock(&adev->grbm_idx_mutex); 2485bbc553aSLeo Liu for (idx = 0; idx < 2; ++idx) { 2496a585777SAlex Deucher if (adev->vce.harvest_config & (1 << idx)) 2506a585777SAlex Deucher continue; 2516a585777SAlex Deucher 252f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx); 2535bbc553aSLeo Liu vce_v3_0_mc_resume(adev, idx); 254f3f0ea95STom St Denis WREG32_FIELD(VCE_STATUS, JOB_BUSY, 1); 255567e6e29Sjimqu 2563c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) 2573c0ff9f1SLeo Liu WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001); 2583c0ff9f1SLeo Liu else 259f3f0ea95STom St Denis WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 1); 260aaa36a97SAlex Deucher 261f3f0ea95STom St Denis WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0); 262aaa36a97SAlex Deucher mdelay(100); 263aaa36a97SAlex Deucher 264567e6e29Sjimqu r = vce_v3_0_firmware_loaded(adev); 265aaa36a97SAlex Deucher 266aaa36a97SAlex Deucher /* clear BUSY flag */ 267f3f0ea95STom St Denis WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0); 268aaa36a97SAlex Deucher 269aaa36a97SAlex Deucher if (r) { 270aaa36a97SAlex Deucher DRM_ERROR("VCE not responding, giving up!!!\n"); 2715bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 272aaa36a97SAlex Deucher return r; 273aaa36a97SAlex Deucher } 2745bbc553aSLeo Liu } 2755bbc553aSLeo Liu 276f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); 2775bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 2785bbc553aSLeo Liu 279567e6e29Sjimqu return 0; 280567e6e29Sjimqu } 2815bbc553aSLeo Liu 282567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev) 283567e6e29Sjimqu { 284567e6e29Sjimqu int idx; 285567e6e29Sjimqu 286567e6e29Sjimqu mutex_lock(&adev->grbm_idx_mutex); 287567e6e29Sjimqu for (idx = 0; idx < 2; ++idx) { 288567e6e29Sjimqu if (adev->vce.harvest_config & (1 << idx)) 289567e6e29Sjimqu continue; 290567e6e29Sjimqu 291f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx); 292567e6e29Sjimqu 293567e6e29Sjimqu if (adev->asic_type >= CHIP_STONEY) 294567e6e29Sjimqu WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001); 295567e6e29Sjimqu else 296f3f0ea95STom St Denis WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 0); 297f3f0ea95STom St Denis 298567e6e29Sjimqu /* hold on ECPU */ 299f3f0ea95STom St Denis WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1); 300567e6e29Sjimqu 301567e6e29Sjimqu /* clear BUSY flag */ 302f3f0ea95STom St Denis WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0); 303567e6e29Sjimqu 304567e6e29Sjimqu /* Set Clock-Gating off */ 305567e6e29Sjimqu if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) 306567e6e29Sjimqu vce_v3_0_set_vce_sw_clock_gating(adev, false); 307567e6e29Sjimqu } 308567e6e29Sjimqu 309f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); 310567e6e29Sjimqu mutex_unlock(&adev->grbm_idx_mutex); 311aaa36a97SAlex Deucher 312aaa36a97SAlex Deucher return 0; 313aaa36a97SAlex Deucher } 314aaa36a97SAlex Deucher 3156a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS 0xC0014074 3166a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT 27 3176a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK 0x18000000 3186a585777SAlex Deucher 3196a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) 3206a585777SAlex Deucher { 3216a585777SAlex Deucher u32 tmp; 3226a585777SAlex Deucher 3232cc0c0b5SFlora Cui /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */ 324cfaba566SSamuel Li if ((adev->asic_type == CHIP_FIJI) || 3251b4eeea5SSonny Jiang (adev->asic_type == CHIP_STONEY) || 3262cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS10) || 3272cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS11)) 3281dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 329188a9bcdSAlex Deucher 330188a9bcdSAlex Deucher /* Tonga and CZ are dual or single pipe */ 3312f7d10b3SJammy Zhou if (adev->flags & AMD_IS_APU) 3326a585777SAlex Deucher tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) & 3336a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__MASK) >> 3346a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__SHIFT; 3356a585777SAlex Deucher else 3366a585777SAlex Deucher tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) & 3376a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE_MASK) >> 3386a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE__SHIFT; 3396a585777SAlex Deucher 3406a585777SAlex Deucher switch (tmp) { 3416a585777SAlex Deucher case 1: 3421dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0; 3436a585777SAlex Deucher case 2: 3441dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 3456a585777SAlex Deucher case 3: 3461dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1; 3476a585777SAlex Deucher default: 3481dab5f06STom St Denis return 0; 3496a585777SAlex Deucher } 3506a585777SAlex Deucher } 3516a585777SAlex Deucher 3525fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle) 353aaa36a97SAlex Deucher { 3545fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 3555fc3aeebSyanyang1 3566a585777SAlex Deucher adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); 3576a585777SAlex Deucher 3586a585777SAlex Deucher if ((adev->vce.harvest_config & 3596a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) == 3606a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 3616a585777SAlex Deucher return -ENOENT; 3626a585777SAlex Deucher 3636f0359ffSAlex Deucher adev->vce.num_rings = 3; 36475c65480SAlex Deucher 365aaa36a97SAlex Deucher vce_v3_0_set_ring_funcs(adev); 366aaa36a97SAlex Deucher vce_v3_0_set_irq_funcs(adev); 367aaa36a97SAlex Deucher 368aaa36a97SAlex Deucher return 0; 369aaa36a97SAlex Deucher } 370aaa36a97SAlex Deucher 3715fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle) 372aaa36a97SAlex Deucher { 3735fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 374aaa36a97SAlex Deucher struct amdgpu_ring *ring; 37575c65480SAlex Deucher int r, i; 376aaa36a97SAlex Deucher 377aaa36a97SAlex Deucher /* VCE */ 378aaa36a97SAlex Deucher r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq); 379aaa36a97SAlex Deucher if (r) 380aaa36a97SAlex Deucher return r; 381aaa36a97SAlex Deucher 382e9822622SLeo Liu r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE + 383e9822622SLeo Liu (VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2); 384aaa36a97SAlex Deucher if (r) 385aaa36a97SAlex Deucher return r; 386aaa36a97SAlex Deucher 387ef6239e0SAlex Deucher /* 52.8.3 required for 3 ring support */ 388ef6239e0SAlex Deucher if (adev->vce.fw_version < FW_52_8_3) 389ef6239e0SAlex Deucher adev->vce.num_rings = 2; 390ef6239e0SAlex Deucher 391aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 392aaa36a97SAlex Deucher if (r) 393aaa36a97SAlex Deucher return r; 394aaa36a97SAlex Deucher 39575c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) { 39675c65480SAlex Deucher ring = &adev->vce.ring[i]; 39775c65480SAlex Deucher sprintf(ring->name, "vce%d", i); 39879887142SChristian König r = amdgpu_ring_init(adev, ring, 512, &adev->vce.irq, 0); 399aaa36a97SAlex Deucher if (r) 400aaa36a97SAlex Deucher return r; 40175c65480SAlex Deucher } 402aaa36a97SAlex Deucher 403aaa36a97SAlex Deucher return r; 404aaa36a97SAlex Deucher } 405aaa36a97SAlex Deucher 4065fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle) 407aaa36a97SAlex Deucher { 408aaa36a97SAlex Deucher int r; 4095fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 410aaa36a97SAlex Deucher 411aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 412aaa36a97SAlex Deucher if (r) 413aaa36a97SAlex Deucher return r; 414aaa36a97SAlex Deucher 415aaa36a97SAlex Deucher r = amdgpu_vce_sw_fini(adev); 416aaa36a97SAlex Deucher if (r) 417aaa36a97SAlex Deucher return r; 418aaa36a97SAlex Deucher 419aaa36a97SAlex Deucher return r; 420aaa36a97SAlex Deucher } 421aaa36a97SAlex Deucher 4225fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle) 423aaa36a97SAlex Deucher { 424691ca86aSTom St Denis int r, i; 4255fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 426aaa36a97SAlex Deucher 427aaa36a97SAlex Deucher r = vce_v3_0_start(adev); 428aaa36a97SAlex Deucher if (r) 429aaa36a97SAlex Deucher return r; 430aaa36a97SAlex Deucher 43175c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) 43275c65480SAlex Deucher adev->vce.ring[i].ready = false; 433aaa36a97SAlex Deucher 43475c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) { 435691ca86aSTom St Denis r = amdgpu_ring_test_ring(&adev->vce.ring[i]); 436691ca86aSTom St Denis if (r) 437aaa36a97SAlex Deucher return r; 438691ca86aSTom St Denis else 439691ca86aSTom St Denis adev->vce.ring[i].ready = true; 440aaa36a97SAlex Deucher } 441aaa36a97SAlex Deucher 442aaa36a97SAlex Deucher DRM_INFO("VCE initialized successfully.\n"); 443aaa36a97SAlex Deucher 444aaa36a97SAlex Deucher return 0; 445aaa36a97SAlex Deucher } 446aaa36a97SAlex Deucher 4475fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle) 448aaa36a97SAlex Deucher { 449567e6e29Sjimqu int r; 450567e6e29Sjimqu struct amdgpu_device *adev = (struct amdgpu_device *)handle; 451567e6e29Sjimqu 452567e6e29Sjimqu r = vce_v3_0_wait_for_idle(handle); 453567e6e29Sjimqu if (r) 454567e6e29Sjimqu return r; 455567e6e29Sjimqu 456567e6e29Sjimqu return vce_v3_0_stop(adev); 457aaa36a97SAlex Deucher } 458aaa36a97SAlex Deucher 4595fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle) 460aaa36a97SAlex Deucher { 461aaa36a97SAlex Deucher int r; 4625fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 463aaa36a97SAlex Deucher 464aaa36a97SAlex Deucher r = vce_v3_0_hw_fini(adev); 465aaa36a97SAlex Deucher if (r) 466aaa36a97SAlex Deucher return r; 467aaa36a97SAlex Deucher 468aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 469aaa36a97SAlex Deucher if (r) 470aaa36a97SAlex Deucher return r; 471aaa36a97SAlex Deucher 472aaa36a97SAlex Deucher return r; 473aaa36a97SAlex Deucher } 474aaa36a97SAlex Deucher 4755fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle) 476aaa36a97SAlex Deucher { 477aaa36a97SAlex Deucher int r; 4785fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 479aaa36a97SAlex Deucher 480aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 481aaa36a97SAlex Deucher if (r) 482aaa36a97SAlex Deucher return r; 483aaa36a97SAlex Deucher 484aaa36a97SAlex Deucher r = vce_v3_0_hw_init(adev); 485aaa36a97SAlex Deucher if (r) 486aaa36a97SAlex Deucher return r; 487aaa36a97SAlex Deucher 488aaa36a97SAlex Deucher return r; 489aaa36a97SAlex Deucher } 490aaa36a97SAlex Deucher 4915bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) 492aaa36a97SAlex Deucher { 493aaa36a97SAlex Deucher uint32_t offset, size; 494aaa36a97SAlex Deucher 495aaa36a97SAlex Deucher WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16)); 496aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); 497aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); 4986f906814STom St Denis WREG32(mmVCE_CLOCK_GATING_B, 0x1FF); 499aaa36a97SAlex Deucher 500aaa36a97SAlex Deucher WREG32(mmVCE_LMI_CTRL, 0x00398000); 501aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1); 502aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL, 0); 503aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL1, 0); 504aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VM_CTRL, 0); 5053c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) { 5063c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8)); 5073c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8)); 5083c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8)); 5093c0ff9f1SLeo Liu } else 510aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8)); 511aaa36a97SAlex Deucher offset = AMDGPU_VCE_FIRMWARE_OFFSET; 512e9822622SLeo Liu size = VCE_V3_0_FW_SIZE; 513aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff); 514aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE0, size); 515aaa36a97SAlex Deucher 5165bbc553aSLeo Liu if (idx == 0) { 517aaa36a97SAlex Deucher offset += size; 518e9822622SLeo Liu size = VCE_V3_0_STACK_SIZE; 519aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff); 520aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 521aaa36a97SAlex Deucher offset += size; 522e9822622SLeo Liu size = VCE_V3_0_DATA_SIZE; 523aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff); 524aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5255bbc553aSLeo Liu } else { 5265bbc553aSLeo Liu offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE; 5275bbc553aSLeo Liu size = VCE_V3_0_STACK_SIZE; 5285bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff); 5295bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 5305bbc553aSLeo Liu offset += size; 5315bbc553aSLeo Liu size = VCE_V3_0_DATA_SIZE; 5325bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff); 5335bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5345bbc553aSLeo Liu } 535aaa36a97SAlex Deucher 536aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); 537f3f0ea95STom St Denis WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1); 538aaa36a97SAlex Deucher } 539aaa36a97SAlex Deucher 5405fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle) 541aaa36a97SAlex Deucher { 5425fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 543be4f38e2SAlex Deucher u32 mask = 0; 5445fc3aeebSyanyang1 54574af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK; 54674af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK; 547be4f38e2SAlex Deucher 548be4f38e2SAlex Deucher return !(RREG32(mmSRBM_STATUS2) & mask); 549aaa36a97SAlex Deucher } 550aaa36a97SAlex Deucher 5515fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle) 552aaa36a97SAlex Deucher { 553aaa36a97SAlex Deucher unsigned i; 5545fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 555be4f38e2SAlex Deucher 55692988e60STom St Denis for (i = 0; i < adev->usec_timeout; i++) 55792988e60STom St Denis if (vce_v3_0_is_idle(handle)) 558aaa36a97SAlex Deucher return 0; 55992988e60STom St Denis 560aaa36a97SAlex Deucher return -ETIMEDOUT; 561aaa36a97SAlex Deucher } 562aaa36a97SAlex Deucher 563ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK 0x00000008L /* AUTO_BUSY */ 564ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK 0x00000010L /* RB0_BUSY */ 565ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_RB1_BUSY_MASK 0x00000020L /* RB1_BUSY */ 566ac8e3f30SRex Zhu #define AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \ 567ac8e3f30SRex Zhu VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK) 568115933a5SChunming Zhou 569da146d3bSAlex Deucher static bool vce_v3_0_check_soft_reset(void *handle) 570115933a5SChunming Zhou { 571115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 572115933a5SChunming Zhou u32 srbm_soft_reset = 0; 573115933a5SChunming Zhou 574115933a5SChunming Zhou /* According to VCE team , we should use VCE_STATUS instead 575115933a5SChunming Zhou * SRBM_STATUS.VCE_BUSY bit for busy status checking. 576115933a5SChunming Zhou * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE 577115933a5SChunming Zhou * instance's registers are accessed 578115933a5SChunming Zhou * (0 for 1st instance, 10 for 2nd instance). 579115933a5SChunming Zhou * 580115933a5SChunming Zhou *VCE_STATUS 581115933a5SChunming Zhou *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 | |FW_LOADED|JOB | 582115933a5SChunming Zhou *|----+----+-----------+----+----+----+----------+---------+----| 583115933a5SChunming Zhou *|bit8|bit7| bit6 |bit5|bit4|bit3| bit2 | bit1 |bit0| 584115933a5SChunming Zhou * 585115933a5SChunming Zhou * VCE team suggest use bit 3--bit 6 for busy status check 586115933a5SChunming Zhou */ 5879aeb774cSTom St Denis mutex_lock(&adev->grbm_idx_mutex); 588f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 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, 0x10); 594115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 595115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 596115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 597115933a5SChunming Zhou } 598f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 599da146d3bSAlex Deucher mutex_unlock(&adev->grbm_idx_mutex); 600115933a5SChunming Zhou 601115933a5SChunming Zhou if (srbm_soft_reset) { 602115933a5SChunming Zhou adev->vce.srbm_soft_reset = srbm_soft_reset; 603da146d3bSAlex Deucher return true; 604115933a5SChunming Zhou } else { 605115933a5SChunming Zhou adev->vce.srbm_soft_reset = 0; 606da146d3bSAlex Deucher return false; 607115933a5SChunming Zhou } 608115933a5SChunming Zhou } 609115933a5SChunming Zhou 6105fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle) 611aaa36a97SAlex Deucher { 6125fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 613115933a5SChunming Zhou u32 srbm_soft_reset; 6145fc3aeebSyanyang1 615da146d3bSAlex Deucher if (!adev->vce.srbm_soft_reset) 616115933a5SChunming Zhou return 0; 617115933a5SChunming Zhou srbm_soft_reset = adev->vce.srbm_soft_reset; 618be4f38e2SAlex Deucher 619115933a5SChunming Zhou if (srbm_soft_reset) { 620115933a5SChunming Zhou u32 tmp; 621115933a5SChunming Zhou 622115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 623115933a5SChunming Zhou tmp |= srbm_soft_reset; 624115933a5SChunming Zhou dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); 625115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 626115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 627115933a5SChunming Zhou 628115933a5SChunming Zhou udelay(50); 629115933a5SChunming Zhou 630115933a5SChunming Zhou tmp &= ~srbm_soft_reset; 631115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 632115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 633115933a5SChunming Zhou 634115933a5SChunming Zhou /* Wait a little for things to settle down */ 635115933a5SChunming Zhou udelay(50); 636115933a5SChunming Zhou } 637115933a5SChunming Zhou 638115933a5SChunming Zhou return 0; 639115933a5SChunming Zhou } 640115933a5SChunming Zhou 641115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle) 642115933a5SChunming Zhou { 643115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 644115933a5SChunming Zhou 645da146d3bSAlex Deucher if (!adev->vce.srbm_soft_reset) 646115933a5SChunming Zhou return 0; 647115933a5SChunming Zhou 648aaa36a97SAlex Deucher mdelay(5); 649aaa36a97SAlex Deucher 650115933a5SChunming Zhou return vce_v3_0_suspend(adev); 651115933a5SChunming Zhou } 652115933a5SChunming Zhou 653115933a5SChunming Zhou 654115933a5SChunming Zhou static int vce_v3_0_post_soft_reset(void *handle) 655115933a5SChunming Zhou { 656115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 657115933a5SChunming Zhou 658da146d3bSAlex Deucher if (!adev->vce.srbm_soft_reset) 659115933a5SChunming Zhou return 0; 660115933a5SChunming Zhou 661115933a5SChunming Zhou mdelay(5); 662115933a5SChunming Zhou 663115933a5SChunming Zhou return vce_v3_0_resume(adev); 664aaa36a97SAlex Deucher } 665aaa36a97SAlex Deucher 666aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, 667aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 668aaa36a97SAlex Deucher unsigned type, 669aaa36a97SAlex Deucher enum amdgpu_interrupt_state state) 670aaa36a97SAlex Deucher { 671aaa36a97SAlex Deucher uint32_t val = 0; 672aaa36a97SAlex Deucher 673aaa36a97SAlex Deucher if (state == AMDGPU_IRQ_STATE_ENABLE) 674aaa36a97SAlex Deucher val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK; 675aaa36a97SAlex Deucher 676aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 677aaa36a97SAlex Deucher return 0; 678aaa36a97SAlex Deucher } 679aaa36a97SAlex Deucher 680aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev, 681aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 682aaa36a97SAlex Deucher struct amdgpu_iv_entry *entry) 683aaa36a97SAlex Deucher { 684aaa36a97SAlex Deucher DRM_DEBUG("IH: VCE\n"); 685d6c29c30SLeo Liu 686f3f0ea95STom St Denis WREG32_FIELD(VCE_SYS_INT_STATUS, VCE_SYS_INT_TRAP_INTERRUPT_INT, 1); 687d6c29c30SLeo Liu 688aaa36a97SAlex Deucher switch (entry->src_data) { 689aaa36a97SAlex Deucher case 0: 690aaa36a97SAlex Deucher case 1: 6916f0359ffSAlex Deucher case 2: 69281da2edeSTom St Denis amdgpu_fence_process(&adev->vce.ring[entry->src_data]); 693aaa36a97SAlex Deucher break; 694aaa36a97SAlex Deucher default: 695aaa36a97SAlex Deucher DRM_ERROR("Unhandled interrupt: %d %d\n", 696aaa36a97SAlex Deucher entry->src_id, entry->src_data); 697aaa36a97SAlex Deucher break; 698aaa36a97SAlex Deucher } 699aaa36a97SAlex Deucher 700aaa36a97SAlex Deucher return 0; 701aaa36a97SAlex Deucher } 702aaa36a97SAlex Deucher 7030174df4eSRex Zhu static void vce_v3_0_set_bypass_mode(struct amdgpu_device *adev, bool enable) 704ec38f188SRex Zhu { 705ec38f188SRex Zhu u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL); 706ec38f188SRex Zhu 707ec38f188SRex Zhu if (enable) 708ec38f188SRex Zhu tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 709ec38f188SRex Zhu else 710ec38f188SRex Zhu tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 711ec38f188SRex Zhu 712ec38f188SRex Zhu WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp); 713ec38f188SRex Zhu } 714ec38f188SRex Zhu 7155fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle, 7165fc3aeebSyanyang1 enum amd_clockgating_state state) 717aaa36a97SAlex Deucher { 7180689a570SEric Huang struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7190689a570SEric Huang bool enable = (state == AMD_CG_STATE_GATE) ? true : false; 7200689a570SEric Huang int i; 7210689a570SEric Huang 722c04399f1SRex Zhu if ((adev->asic_type == CHIP_POLARIS10) || 7233374dcebSRex Zhu (adev->asic_type == CHIP_TONGA) || 7243374dcebSRex Zhu (adev->asic_type == CHIP_FIJI)) 7250174df4eSRex Zhu vce_v3_0_set_bypass_mode(adev, enable); 726ec38f188SRex Zhu 727e3b04bc7SAlex Deucher if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) 7280689a570SEric Huang return 0; 7290689a570SEric Huang 7300689a570SEric Huang mutex_lock(&adev->grbm_idx_mutex); 7310689a570SEric Huang for (i = 0; i < 2; i++) { 7320689a570SEric Huang /* Program VCE Instance 0 or 1 if not harvested */ 7330689a570SEric Huang if (adev->vce.harvest_config & (1 << i)) 7340689a570SEric Huang continue; 7350689a570SEric Huang 736f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i); 7370689a570SEric Huang 7380689a570SEric Huang if (enable) { 7390689a570SEric Huang /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ 7400689a570SEric Huang uint32_t data = RREG32(mmVCE_CLOCK_GATING_A); 7410689a570SEric Huang data &= ~(0xf | 0xff0); 7420689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7430689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_A, data); 7440689a570SEric Huang 7450689a570SEric Huang /* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */ 7460689a570SEric Huang data = RREG32(mmVCE_UENC_CLOCK_GATING); 7470689a570SEric Huang data &= ~(0xf | 0xff0); 7480689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7490689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 7500689a570SEric Huang } 7510689a570SEric Huang 7520689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, enable); 7530689a570SEric Huang } 7540689a570SEric Huang 755f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); 7560689a570SEric Huang mutex_unlock(&adev->grbm_idx_mutex); 7570689a570SEric Huang 758aaa36a97SAlex Deucher return 0; 759aaa36a97SAlex Deucher } 760aaa36a97SAlex Deucher 7615fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle, 7625fc3aeebSyanyang1 enum amd_powergating_state state) 763aaa36a97SAlex Deucher { 764aaa36a97SAlex Deucher /* This doesn't actually powergate the VCE block. 765aaa36a97SAlex Deucher * That's done in the dpm code via the SMC. This 766aaa36a97SAlex Deucher * just re-inits the block as necessary. The actual 767aaa36a97SAlex Deucher * gating still happens in the dpm code. We should 768aaa36a97SAlex Deucher * revisit this when there is a cleaner line between 769aaa36a97SAlex Deucher * the smc and the hw blocks 770aaa36a97SAlex Deucher */ 7715fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7725fc3aeebSyanyang1 773e3b04bc7SAlex Deucher if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE)) 774808a934fSAlex Deucher return 0; 775808a934fSAlex Deucher 7765fc3aeebSyanyang1 if (state == AMD_PG_STATE_GATE) 777aaa36a97SAlex Deucher /* XXX do we need a vce_v3_0_stop()? */ 778aaa36a97SAlex Deucher return 0; 779aaa36a97SAlex Deucher else 780aaa36a97SAlex Deucher return vce_v3_0_start(adev); 781aaa36a97SAlex Deucher } 782aaa36a97SAlex Deucher 783ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring, 784ea4a8c1dSMaruthi Srinivas Bayyavarapu struct amdgpu_ib *ib, unsigned int vm_id, bool ctx_switch) 785ea4a8c1dSMaruthi Srinivas Bayyavarapu { 786ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_IB_VM); 787ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, vm_id); 788ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr)); 789ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr)); 790ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, ib->length_dw); 791ea4a8c1dSMaruthi Srinivas Bayyavarapu } 792ea4a8c1dSMaruthi Srinivas Bayyavarapu 793ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring, 794ea4a8c1dSMaruthi Srinivas Bayyavarapu unsigned int vm_id, uint64_t pd_addr) 795ea4a8c1dSMaruthi Srinivas Bayyavarapu { 796ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_UPDATE_PTB); 797ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, vm_id); 798ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, pd_addr >> 12); 799ea4a8c1dSMaruthi Srinivas Bayyavarapu 800ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_FLUSH_TLB); 801ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, vm_id); 802ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_END); 803ea4a8c1dSMaruthi Srinivas Bayyavarapu } 804ea4a8c1dSMaruthi Srinivas Bayyavarapu 805ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_pipeline_sync(struct amdgpu_ring *ring) 806ea4a8c1dSMaruthi Srinivas Bayyavarapu { 807ea4a8c1dSMaruthi Srinivas Bayyavarapu uint32_t seq = ring->fence_drv.sync_seq; 808ea4a8c1dSMaruthi Srinivas Bayyavarapu uint64_t addr = ring->fence_drv.gpu_addr; 809ea4a8c1dSMaruthi Srinivas Bayyavarapu 810ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_WAIT_GE); 811ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, lower_32_bits(addr)); 812ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, upper_32_bits(addr)); 813ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, seq); 814ea4a8c1dSMaruthi Srinivas Bayyavarapu } 815ea4a8c1dSMaruthi Srinivas Bayyavarapu 816a1255107SAlex Deucher static const struct amd_ip_funcs vce_v3_0_ip_funcs = { 81788a907d6STom St Denis .name = "vce_v3_0", 818aaa36a97SAlex Deucher .early_init = vce_v3_0_early_init, 819aaa36a97SAlex Deucher .late_init = NULL, 820aaa36a97SAlex Deucher .sw_init = vce_v3_0_sw_init, 821aaa36a97SAlex Deucher .sw_fini = vce_v3_0_sw_fini, 822aaa36a97SAlex Deucher .hw_init = vce_v3_0_hw_init, 823aaa36a97SAlex Deucher .hw_fini = vce_v3_0_hw_fini, 824aaa36a97SAlex Deucher .suspend = vce_v3_0_suspend, 825aaa36a97SAlex Deucher .resume = vce_v3_0_resume, 826aaa36a97SAlex Deucher .is_idle = vce_v3_0_is_idle, 827aaa36a97SAlex Deucher .wait_for_idle = vce_v3_0_wait_for_idle, 828115933a5SChunming Zhou .check_soft_reset = vce_v3_0_check_soft_reset, 829115933a5SChunming Zhou .pre_soft_reset = vce_v3_0_pre_soft_reset, 830aaa36a97SAlex Deucher .soft_reset = vce_v3_0_soft_reset, 831115933a5SChunming Zhou .post_soft_reset = vce_v3_0_post_soft_reset, 832aaa36a97SAlex Deucher .set_clockgating_state = vce_v3_0_set_clockgating_state, 833aaa36a97SAlex Deucher .set_powergating_state = vce_v3_0_set_powergating_state, 834aaa36a97SAlex Deucher }; 835aaa36a97SAlex Deucher 836ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = { 83721cd942eSChristian König .type = AMDGPU_RING_TYPE_VCE, 83879887142SChristian König .align_mask = 0xf, 83979887142SChristian König .nop = VCE_CMD_NO_OP, 840aaa36a97SAlex Deucher .get_rptr = vce_v3_0_ring_get_rptr, 841aaa36a97SAlex Deucher .get_wptr = vce_v3_0_ring_get_wptr, 842aaa36a97SAlex Deucher .set_wptr = vce_v3_0_ring_set_wptr, 843aaa36a97SAlex Deucher .parse_cs = amdgpu_vce_ring_parse_cs, 844e12f3d7aSChristian König .emit_frame_size = 845e12f3d7aSChristian König 4 + /* vce_v3_0_emit_pipeline_sync */ 846e12f3d7aSChristian König 6, /* amdgpu_vce_ring_emit_fence x1 no user fence */ 847e12f3d7aSChristian König .emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */ 848aaa36a97SAlex Deucher .emit_ib = amdgpu_vce_ring_emit_ib, 849aaa36a97SAlex Deucher .emit_fence = amdgpu_vce_ring_emit_fence, 850aaa36a97SAlex Deucher .test_ring = amdgpu_vce_ring_test_ring, 851aaa36a97SAlex Deucher .test_ib = amdgpu_vce_ring_test_ib, 852edff0e28SJammy Zhou .insert_nop = amdgpu_ring_insert_nop, 8539e5d5309SChristian König .pad_ib = amdgpu_ring_generic_pad_ib, 854ebff485eSChristian König .begin_use = amdgpu_vce_ring_begin_use, 855ebff485eSChristian König .end_use = amdgpu_vce_ring_end_use, 856aaa36a97SAlex Deucher }; 857aaa36a97SAlex Deucher 858ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = { 85921cd942eSChristian König .type = AMDGPU_RING_TYPE_VCE, 86079887142SChristian König .align_mask = 0xf, 86179887142SChristian König .nop = VCE_CMD_NO_OP, 862ea4a8c1dSMaruthi Srinivas Bayyavarapu .get_rptr = vce_v3_0_ring_get_rptr, 863ea4a8c1dSMaruthi Srinivas Bayyavarapu .get_wptr = vce_v3_0_ring_get_wptr, 864ea4a8c1dSMaruthi Srinivas Bayyavarapu .set_wptr = vce_v3_0_ring_set_wptr, 86598614701SChristian König .parse_cs = amdgpu_vce_ring_parse_cs_vm, 866e12f3d7aSChristian König .emit_frame_size = 867e12f3d7aSChristian König 6 + /* vce_v3_0_emit_vm_flush */ 868e12f3d7aSChristian König 4 + /* vce_v3_0_emit_pipeline_sync */ 869e12f3d7aSChristian König 6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */ 870e12f3d7aSChristian König .emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */ 871ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_ib = vce_v3_0_ring_emit_ib, 872ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_vm_flush = vce_v3_0_emit_vm_flush, 873ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_pipeline_sync = vce_v3_0_emit_pipeline_sync, 874ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_fence = amdgpu_vce_ring_emit_fence, 875ea4a8c1dSMaruthi Srinivas Bayyavarapu .test_ring = amdgpu_vce_ring_test_ring, 876ea4a8c1dSMaruthi Srinivas Bayyavarapu .test_ib = amdgpu_vce_ring_test_ib, 877ea4a8c1dSMaruthi Srinivas Bayyavarapu .insert_nop = amdgpu_ring_insert_nop, 878ea4a8c1dSMaruthi Srinivas Bayyavarapu .pad_ib = amdgpu_ring_generic_pad_ib, 879ea4a8c1dSMaruthi Srinivas Bayyavarapu .begin_use = amdgpu_vce_ring_begin_use, 880ea4a8c1dSMaruthi Srinivas Bayyavarapu .end_use = amdgpu_vce_ring_end_use, 881ea4a8c1dSMaruthi Srinivas Bayyavarapu }; 882ea4a8c1dSMaruthi Srinivas Bayyavarapu 883aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) 884aaa36a97SAlex Deucher { 88575c65480SAlex Deucher int i; 88675c65480SAlex Deucher 887ea4a8c1dSMaruthi Srinivas Bayyavarapu if (adev->asic_type >= CHIP_STONEY) { 88875c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) 889ea4a8c1dSMaruthi Srinivas Bayyavarapu adev->vce.ring[i].funcs = &vce_v3_0_ring_vm_funcs; 890ea4a8c1dSMaruthi Srinivas Bayyavarapu DRM_INFO("VCE enabled in VM mode\n"); 891ea4a8c1dSMaruthi Srinivas Bayyavarapu } else { 892ea4a8c1dSMaruthi Srinivas Bayyavarapu for (i = 0; i < adev->vce.num_rings; i++) 893ea4a8c1dSMaruthi Srinivas Bayyavarapu adev->vce.ring[i].funcs = &vce_v3_0_ring_phys_funcs; 894ea4a8c1dSMaruthi Srinivas Bayyavarapu DRM_INFO("VCE enabled in physical mode\n"); 895ea4a8c1dSMaruthi Srinivas Bayyavarapu } 896aaa36a97SAlex Deucher } 897aaa36a97SAlex Deucher 898aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = { 899aaa36a97SAlex Deucher .set = vce_v3_0_set_interrupt_state, 900aaa36a97SAlex Deucher .process = vce_v3_0_process_interrupt, 901aaa36a97SAlex Deucher }; 902aaa36a97SAlex Deucher 903aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev) 904aaa36a97SAlex Deucher { 905aaa36a97SAlex Deucher adev->vce.irq.num_types = 1; 906aaa36a97SAlex Deucher adev->vce.irq.funcs = &vce_v3_0_irq_funcs; 907aaa36a97SAlex Deucher }; 908a1255107SAlex Deucher 909a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_0_ip_block = 910a1255107SAlex Deucher { 911a1255107SAlex Deucher .type = AMD_IP_BLOCK_TYPE_VCE, 912a1255107SAlex Deucher .major = 3, 913a1255107SAlex Deucher .minor = 0, 914a1255107SAlex Deucher .rev = 0, 915a1255107SAlex Deucher .funcs = &vce_v3_0_ip_funcs, 916a1255107SAlex Deucher }; 917a1255107SAlex Deucher 918a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_1_ip_block = 919a1255107SAlex Deucher { 920a1255107SAlex Deucher .type = AMD_IP_BLOCK_TYPE_VCE, 921a1255107SAlex Deucher .major = 3, 922a1255107SAlex Deucher .minor = 1, 923a1255107SAlex Deucher .rev = 0, 924a1255107SAlex Deucher .funcs = &vce_v3_0_ip_funcs, 925a1255107SAlex Deucher }; 926a1255107SAlex Deucher 927a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_4_ip_block = 928a1255107SAlex Deucher { 929a1255107SAlex Deucher .type = AMD_IP_BLOCK_TYPE_VCE, 930a1255107SAlex Deucher .major = 3, 931a1255107SAlex Deucher .minor = 4, 932a1255107SAlex Deucher .rev = 0, 933a1255107SAlex Deucher .funcs = &vce_v3_0_ip_funcs, 934a1255107SAlex Deucher }; 935