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); 178e05208deSRex Zhu data &= ~0x3ff; 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 323c4642a47SJunwei Zhang /* Fiji, Stoney, Polaris10, Polaris11, Polaris12 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) || 327c4642a47SJunwei Zhang (adev->asic_type == CHIP_POLARIS11) || 328c4642a47SJunwei Zhang (adev->asic_type == CHIP_POLARIS12)) 3291dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 330188a9bcdSAlex Deucher 331188a9bcdSAlex Deucher /* Tonga and CZ are dual or single pipe */ 3322f7d10b3SJammy Zhou if (adev->flags & AMD_IS_APU) 3336a585777SAlex Deucher tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) & 3346a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__MASK) >> 3356a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__SHIFT; 3366a585777SAlex Deucher else 3376a585777SAlex Deucher tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) & 3386a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE_MASK) >> 3396a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE__SHIFT; 3406a585777SAlex Deucher 3416a585777SAlex Deucher switch (tmp) { 3426a585777SAlex Deucher case 1: 3431dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0; 3446a585777SAlex Deucher case 2: 3451dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 3466a585777SAlex Deucher case 3: 3471dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1; 3486a585777SAlex Deucher default: 3491dab5f06STom St Denis return 0; 3506a585777SAlex Deucher } 3516a585777SAlex Deucher } 3526a585777SAlex Deucher 3535fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle) 354aaa36a97SAlex Deucher { 3555fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 3565fc3aeebSyanyang1 3576a585777SAlex Deucher adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); 3586a585777SAlex Deucher 3596a585777SAlex Deucher if ((adev->vce.harvest_config & 3606a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) == 3616a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 3626a585777SAlex Deucher return -ENOENT; 3636a585777SAlex Deucher 3646f0359ffSAlex Deucher adev->vce.num_rings = 3; 36575c65480SAlex Deucher 366aaa36a97SAlex Deucher vce_v3_0_set_ring_funcs(adev); 367aaa36a97SAlex Deucher vce_v3_0_set_irq_funcs(adev); 368aaa36a97SAlex Deucher 369aaa36a97SAlex Deucher return 0; 370aaa36a97SAlex Deucher } 371aaa36a97SAlex Deucher 3725fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle) 373aaa36a97SAlex Deucher { 3745fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 375aaa36a97SAlex Deucher struct amdgpu_ring *ring; 37675c65480SAlex Deucher int r, i; 377aaa36a97SAlex Deucher 378aaa36a97SAlex Deucher /* VCE */ 379aaa36a97SAlex Deucher r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq); 380aaa36a97SAlex Deucher if (r) 381aaa36a97SAlex Deucher return r; 382aaa36a97SAlex Deucher 383e9822622SLeo Liu r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE + 384e9822622SLeo Liu (VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2); 385aaa36a97SAlex Deucher if (r) 386aaa36a97SAlex Deucher return r; 387aaa36a97SAlex Deucher 388ef6239e0SAlex Deucher /* 52.8.3 required for 3 ring support */ 389ef6239e0SAlex Deucher if (adev->vce.fw_version < FW_52_8_3) 390ef6239e0SAlex Deucher adev->vce.num_rings = 2; 391ef6239e0SAlex Deucher 392aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 393aaa36a97SAlex Deucher if (r) 394aaa36a97SAlex Deucher return r; 395aaa36a97SAlex Deucher 39675c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) { 39775c65480SAlex Deucher ring = &adev->vce.ring[i]; 39875c65480SAlex Deucher sprintf(ring->name, "vce%d", i); 39979887142SChristian König r = amdgpu_ring_init(adev, ring, 512, &adev->vce.irq, 0); 400aaa36a97SAlex Deucher if (r) 401aaa36a97SAlex Deucher return r; 40275c65480SAlex Deucher } 403aaa36a97SAlex Deucher 404aaa36a97SAlex Deucher return r; 405aaa36a97SAlex Deucher } 406aaa36a97SAlex Deucher 4075fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle) 408aaa36a97SAlex Deucher { 409aaa36a97SAlex Deucher int r; 4105fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 411aaa36a97SAlex Deucher 412aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 413aaa36a97SAlex Deucher if (r) 414aaa36a97SAlex Deucher return r; 415aaa36a97SAlex Deucher 416aaa36a97SAlex Deucher r = amdgpu_vce_sw_fini(adev); 417aaa36a97SAlex Deucher if (r) 418aaa36a97SAlex Deucher return r; 419aaa36a97SAlex Deucher 420aaa36a97SAlex Deucher return r; 421aaa36a97SAlex Deucher } 422aaa36a97SAlex Deucher 4235fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle) 424aaa36a97SAlex Deucher { 425691ca86aSTom St Denis int r, i; 4265fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 427aaa36a97SAlex Deucher 428aaa36a97SAlex Deucher r = vce_v3_0_start(adev); 429aaa36a97SAlex Deucher if (r) 430aaa36a97SAlex Deucher return r; 431aaa36a97SAlex Deucher 43275c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) 43375c65480SAlex Deucher adev->vce.ring[i].ready = false; 434aaa36a97SAlex Deucher 43575c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) { 436691ca86aSTom St Denis r = amdgpu_ring_test_ring(&adev->vce.ring[i]); 437691ca86aSTom St Denis if (r) 438aaa36a97SAlex Deucher return r; 439691ca86aSTom St Denis else 440691ca86aSTom St Denis adev->vce.ring[i].ready = true; 441aaa36a97SAlex Deucher } 442aaa36a97SAlex Deucher 443aaa36a97SAlex Deucher DRM_INFO("VCE initialized successfully.\n"); 444aaa36a97SAlex Deucher 445aaa36a97SAlex Deucher return 0; 446aaa36a97SAlex Deucher } 447aaa36a97SAlex Deucher 4485fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle) 449aaa36a97SAlex Deucher { 450567e6e29Sjimqu int r; 451567e6e29Sjimqu struct amdgpu_device *adev = (struct amdgpu_device *)handle; 452567e6e29Sjimqu 453567e6e29Sjimqu r = vce_v3_0_wait_for_idle(handle); 454567e6e29Sjimqu if (r) 455567e6e29Sjimqu return r; 456567e6e29Sjimqu 457567e6e29Sjimqu return vce_v3_0_stop(adev); 458aaa36a97SAlex Deucher } 459aaa36a97SAlex Deucher 4605fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle) 461aaa36a97SAlex Deucher { 462aaa36a97SAlex Deucher int r; 4635fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 464aaa36a97SAlex Deucher 465aaa36a97SAlex Deucher r = vce_v3_0_hw_fini(adev); 466aaa36a97SAlex Deucher if (r) 467aaa36a97SAlex Deucher return r; 468aaa36a97SAlex Deucher 469aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 470aaa36a97SAlex Deucher if (r) 471aaa36a97SAlex Deucher return r; 472aaa36a97SAlex Deucher 473aaa36a97SAlex Deucher return r; 474aaa36a97SAlex Deucher } 475aaa36a97SAlex Deucher 4765fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle) 477aaa36a97SAlex Deucher { 478aaa36a97SAlex Deucher int r; 4795fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 480aaa36a97SAlex Deucher 481aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 482aaa36a97SAlex Deucher if (r) 483aaa36a97SAlex Deucher return r; 484aaa36a97SAlex Deucher 485aaa36a97SAlex Deucher r = vce_v3_0_hw_init(adev); 486aaa36a97SAlex Deucher if (r) 487aaa36a97SAlex Deucher return r; 488aaa36a97SAlex Deucher 489aaa36a97SAlex Deucher return r; 490aaa36a97SAlex Deucher } 491aaa36a97SAlex Deucher 4925bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) 493aaa36a97SAlex Deucher { 494aaa36a97SAlex Deucher uint32_t offset, size; 495aaa36a97SAlex Deucher 496aaa36a97SAlex Deucher WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16)); 497aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); 498aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); 4996f906814STom St Denis WREG32(mmVCE_CLOCK_GATING_B, 0x1FF); 500aaa36a97SAlex Deucher 501aaa36a97SAlex Deucher WREG32(mmVCE_LMI_CTRL, 0x00398000); 502aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1); 503aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL, 0); 504aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL1, 0); 505aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VM_CTRL, 0); 5063c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) { 5073c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8)); 5083c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8)); 5093c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8)); 5103c0ff9f1SLeo Liu } else 511aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8)); 512aaa36a97SAlex Deucher offset = AMDGPU_VCE_FIRMWARE_OFFSET; 513e9822622SLeo Liu size = VCE_V3_0_FW_SIZE; 514aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff); 515aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE0, size); 516aaa36a97SAlex Deucher 5175bbc553aSLeo Liu if (idx == 0) { 518aaa36a97SAlex Deucher offset += size; 519e9822622SLeo Liu size = VCE_V3_0_STACK_SIZE; 520aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff); 521aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 522aaa36a97SAlex Deucher offset += size; 523e9822622SLeo Liu size = VCE_V3_0_DATA_SIZE; 524aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff); 525aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5265bbc553aSLeo Liu } else { 5275bbc553aSLeo Liu offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE; 5285bbc553aSLeo Liu size = VCE_V3_0_STACK_SIZE; 5295bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff); 5305bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 5315bbc553aSLeo Liu offset += size; 5325bbc553aSLeo Liu size = VCE_V3_0_DATA_SIZE; 5335bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff); 5345bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5355bbc553aSLeo Liu } 536aaa36a97SAlex Deucher 537aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); 538f3f0ea95STom St Denis WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1); 539aaa36a97SAlex Deucher } 540aaa36a97SAlex Deucher 5415fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle) 542aaa36a97SAlex Deucher { 5435fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 544be4f38e2SAlex Deucher u32 mask = 0; 5455fc3aeebSyanyang1 54674af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK; 54774af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK; 548be4f38e2SAlex Deucher 549be4f38e2SAlex Deucher return !(RREG32(mmSRBM_STATUS2) & mask); 550aaa36a97SAlex Deucher } 551aaa36a97SAlex Deucher 5525fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle) 553aaa36a97SAlex Deucher { 554aaa36a97SAlex Deucher unsigned i; 5555fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 556be4f38e2SAlex Deucher 55792988e60STom St Denis for (i = 0; i < adev->usec_timeout; i++) 55892988e60STom St Denis if (vce_v3_0_is_idle(handle)) 559aaa36a97SAlex Deucher return 0; 56092988e60STom St Denis 561aaa36a97SAlex Deucher return -ETIMEDOUT; 562aaa36a97SAlex Deucher } 563aaa36a97SAlex Deucher 564ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK 0x00000008L /* AUTO_BUSY */ 565ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK 0x00000010L /* RB0_BUSY */ 566ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_RB1_BUSY_MASK 0x00000020L /* RB1_BUSY */ 567ac8e3f30SRex Zhu #define AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \ 568ac8e3f30SRex Zhu VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK) 569115933a5SChunming Zhou 570da146d3bSAlex Deucher static bool vce_v3_0_check_soft_reset(void *handle) 571115933a5SChunming Zhou { 572115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 573115933a5SChunming Zhou u32 srbm_soft_reset = 0; 574115933a5SChunming Zhou 575115933a5SChunming Zhou /* According to VCE team , we should use VCE_STATUS instead 576115933a5SChunming Zhou * SRBM_STATUS.VCE_BUSY bit for busy status checking. 577115933a5SChunming Zhou * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE 578115933a5SChunming Zhou * instance's registers are accessed 579115933a5SChunming Zhou * (0 for 1st instance, 10 for 2nd instance). 580115933a5SChunming Zhou * 581115933a5SChunming Zhou *VCE_STATUS 582115933a5SChunming Zhou *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 | |FW_LOADED|JOB | 583115933a5SChunming Zhou *|----+----+-----------+----+----+----+----------+---------+----| 584115933a5SChunming Zhou *|bit8|bit7| bit6 |bit5|bit4|bit3| bit2 | bit1 |bit0| 585115933a5SChunming Zhou * 586115933a5SChunming Zhou * VCE team suggest use bit 3--bit 6 for busy status check 587115933a5SChunming Zhou */ 5889aeb774cSTom St Denis mutex_lock(&adev->grbm_idx_mutex); 589f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 590115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 591115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 592115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 593115933a5SChunming Zhou } 594f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10); 595115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 596115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 597115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 598115933a5SChunming Zhou } 599f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 600da146d3bSAlex Deucher mutex_unlock(&adev->grbm_idx_mutex); 601115933a5SChunming Zhou 602115933a5SChunming Zhou if (srbm_soft_reset) { 603115933a5SChunming Zhou adev->vce.srbm_soft_reset = srbm_soft_reset; 604da146d3bSAlex Deucher return true; 605115933a5SChunming Zhou } else { 606115933a5SChunming Zhou adev->vce.srbm_soft_reset = 0; 607da146d3bSAlex Deucher return false; 608115933a5SChunming Zhou } 609115933a5SChunming Zhou } 610115933a5SChunming Zhou 6115fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle) 612aaa36a97SAlex Deucher { 6135fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 614115933a5SChunming Zhou u32 srbm_soft_reset; 6155fc3aeebSyanyang1 616da146d3bSAlex Deucher if (!adev->vce.srbm_soft_reset) 617115933a5SChunming Zhou return 0; 618115933a5SChunming Zhou srbm_soft_reset = adev->vce.srbm_soft_reset; 619be4f38e2SAlex Deucher 620115933a5SChunming Zhou if (srbm_soft_reset) { 621115933a5SChunming Zhou u32 tmp; 622115933a5SChunming Zhou 623115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 624115933a5SChunming Zhou tmp |= srbm_soft_reset; 625115933a5SChunming Zhou dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); 626115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 627115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 628115933a5SChunming Zhou 629115933a5SChunming Zhou udelay(50); 630115933a5SChunming Zhou 631115933a5SChunming Zhou tmp &= ~srbm_soft_reset; 632115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 633115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 634115933a5SChunming Zhou 635115933a5SChunming Zhou /* Wait a little for things to settle down */ 636115933a5SChunming Zhou udelay(50); 637115933a5SChunming Zhou } 638115933a5SChunming Zhou 639115933a5SChunming Zhou return 0; 640115933a5SChunming Zhou } 641115933a5SChunming Zhou 642115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle) 643115933a5SChunming Zhou { 644115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 645115933a5SChunming Zhou 646da146d3bSAlex Deucher if (!adev->vce.srbm_soft_reset) 647115933a5SChunming Zhou return 0; 648115933a5SChunming Zhou 649aaa36a97SAlex Deucher mdelay(5); 650aaa36a97SAlex Deucher 651115933a5SChunming Zhou return vce_v3_0_suspend(adev); 652115933a5SChunming Zhou } 653115933a5SChunming Zhou 654115933a5SChunming Zhou 655115933a5SChunming Zhou static int vce_v3_0_post_soft_reset(void *handle) 656115933a5SChunming Zhou { 657115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 658115933a5SChunming Zhou 659da146d3bSAlex Deucher if (!adev->vce.srbm_soft_reset) 660115933a5SChunming Zhou return 0; 661115933a5SChunming Zhou 662115933a5SChunming Zhou mdelay(5); 663115933a5SChunming Zhou 664115933a5SChunming Zhou return vce_v3_0_resume(adev); 665aaa36a97SAlex Deucher } 666aaa36a97SAlex Deucher 667aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, 668aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 669aaa36a97SAlex Deucher unsigned type, 670aaa36a97SAlex Deucher enum amdgpu_interrupt_state state) 671aaa36a97SAlex Deucher { 672aaa36a97SAlex Deucher uint32_t val = 0; 673aaa36a97SAlex Deucher 674aaa36a97SAlex Deucher if (state == AMDGPU_IRQ_STATE_ENABLE) 675aaa36a97SAlex Deucher val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK; 676aaa36a97SAlex Deucher 677aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 678aaa36a97SAlex Deucher return 0; 679aaa36a97SAlex Deucher } 680aaa36a97SAlex Deucher 681aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev, 682aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 683aaa36a97SAlex Deucher struct amdgpu_iv_entry *entry) 684aaa36a97SAlex Deucher { 685aaa36a97SAlex Deucher DRM_DEBUG("IH: VCE\n"); 686d6c29c30SLeo Liu 687f3f0ea95STom St Denis WREG32_FIELD(VCE_SYS_INT_STATUS, VCE_SYS_INT_TRAP_INTERRUPT_INT, 1); 688d6c29c30SLeo Liu 689aaa36a97SAlex Deucher switch (entry->src_data) { 690aaa36a97SAlex Deucher case 0: 691aaa36a97SAlex Deucher case 1: 6926f0359ffSAlex Deucher case 2: 69381da2edeSTom St Denis amdgpu_fence_process(&adev->vce.ring[entry->src_data]); 694aaa36a97SAlex Deucher break; 695aaa36a97SAlex Deucher default: 696aaa36a97SAlex Deucher DRM_ERROR("Unhandled interrupt: %d %d\n", 697aaa36a97SAlex Deucher entry->src_id, entry->src_data); 698aaa36a97SAlex Deucher break; 699aaa36a97SAlex Deucher } 700aaa36a97SAlex Deucher 701aaa36a97SAlex Deucher return 0; 702aaa36a97SAlex Deucher } 703aaa36a97SAlex Deucher 7040174df4eSRex Zhu static void vce_v3_0_set_bypass_mode(struct amdgpu_device *adev, bool enable) 705ec38f188SRex Zhu { 706ec38f188SRex Zhu u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL); 707ec38f188SRex Zhu 708ec38f188SRex Zhu if (enable) 709ec38f188SRex Zhu tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 710ec38f188SRex Zhu else 711ec38f188SRex Zhu tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 712ec38f188SRex Zhu 713ec38f188SRex Zhu WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp); 714ec38f188SRex Zhu } 715ec38f188SRex Zhu 7165fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle, 7175fc3aeebSyanyang1 enum amd_clockgating_state state) 718aaa36a97SAlex Deucher { 7190689a570SEric Huang struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7200689a570SEric Huang bool enable = (state == AMD_CG_STATE_GATE) ? true : false; 7210689a570SEric Huang int i; 7220689a570SEric Huang 723c04399f1SRex Zhu if ((adev->asic_type == CHIP_POLARIS10) || 7243374dcebSRex Zhu (adev->asic_type == CHIP_TONGA) || 7253374dcebSRex Zhu (adev->asic_type == CHIP_FIJI)) 7260174df4eSRex Zhu vce_v3_0_set_bypass_mode(adev, enable); 727ec38f188SRex Zhu 728e3b04bc7SAlex Deucher if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) 7290689a570SEric Huang return 0; 7300689a570SEric Huang 7310689a570SEric Huang mutex_lock(&adev->grbm_idx_mutex); 7320689a570SEric Huang for (i = 0; i < 2; i++) { 7330689a570SEric Huang /* Program VCE Instance 0 or 1 if not harvested */ 7340689a570SEric Huang if (adev->vce.harvest_config & (1 << i)) 7350689a570SEric Huang continue; 7360689a570SEric Huang 737f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i); 7380689a570SEric Huang 7390689a570SEric Huang if (enable) { 7400689a570SEric Huang /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ 7410689a570SEric Huang uint32_t data = RREG32(mmVCE_CLOCK_GATING_A); 7420689a570SEric Huang data &= ~(0xf | 0xff0); 7430689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7440689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_A, data); 7450689a570SEric Huang 7460689a570SEric Huang /* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */ 7470689a570SEric Huang data = RREG32(mmVCE_UENC_CLOCK_GATING); 7480689a570SEric Huang data &= ~(0xf | 0xff0); 7490689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7500689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 7510689a570SEric Huang } 7520689a570SEric Huang 7530689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, enable); 7540689a570SEric Huang } 7550689a570SEric Huang 756f3f0ea95STom St Denis WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); 7570689a570SEric Huang mutex_unlock(&adev->grbm_idx_mutex); 7580689a570SEric Huang 759aaa36a97SAlex Deucher return 0; 760aaa36a97SAlex Deucher } 761aaa36a97SAlex Deucher 7625fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle, 7635fc3aeebSyanyang1 enum amd_powergating_state state) 764aaa36a97SAlex Deucher { 765aaa36a97SAlex Deucher /* This doesn't actually powergate the VCE block. 766aaa36a97SAlex Deucher * That's done in the dpm code via the SMC. This 767aaa36a97SAlex Deucher * just re-inits the block as necessary. The actual 768aaa36a97SAlex Deucher * gating still happens in the dpm code. We should 769aaa36a97SAlex Deucher * revisit this when there is a cleaner line between 770aaa36a97SAlex Deucher * the smc and the hw blocks 771aaa36a97SAlex Deucher */ 7725fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7735fc3aeebSyanyang1 774e3b04bc7SAlex Deucher if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE)) 775808a934fSAlex Deucher return 0; 776808a934fSAlex Deucher 7775fc3aeebSyanyang1 if (state == AMD_PG_STATE_GATE) 778aaa36a97SAlex Deucher /* XXX do we need a vce_v3_0_stop()? */ 779aaa36a97SAlex Deucher return 0; 780aaa36a97SAlex Deucher else 781aaa36a97SAlex Deucher return vce_v3_0_start(adev); 782aaa36a97SAlex Deucher } 783aaa36a97SAlex Deucher 784ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring, 785ea4a8c1dSMaruthi Srinivas Bayyavarapu struct amdgpu_ib *ib, unsigned int vm_id, bool ctx_switch) 786ea4a8c1dSMaruthi Srinivas Bayyavarapu { 787ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_IB_VM); 788ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, vm_id); 789ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr)); 790ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr)); 791ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, ib->length_dw); 792ea4a8c1dSMaruthi Srinivas Bayyavarapu } 793ea4a8c1dSMaruthi Srinivas Bayyavarapu 794ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring, 795ea4a8c1dSMaruthi Srinivas Bayyavarapu unsigned int vm_id, uint64_t pd_addr) 796ea4a8c1dSMaruthi Srinivas Bayyavarapu { 797ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_UPDATE_PTB); 798ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, vm_id); 799ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, pd_addr >> 12); 800ea4a8c1dSMaruthi Srinivas Bayyavarapu 801ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_FLUSH_TLB); 802ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, vm_id); 803ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_END); 804ea4a8c1dSMaruthi Srinivas Bayyavarapu } 805ea4a8c1dSMaruthi Srinivas Bayyavarapu 806ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_pipeline_sync(struct amdgpu_ring *ring) 807ea4a8c1dSMaruthi Srinivas Bayyavarapu { 808ea4a8c1dSMaruthi Srinivas Bayyavarapu uint32_t seq = ring->fence_drv.sync_seq; 809ea4a8c1dSMaruthi Srinivas Bayyavarapu uint64_t addr = ring->fence_drv.gpu_addr; 810ea4a8c1dSMaruthi Srinivas Bayyavarapu 811ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, VCE_CMD_WAIT_GE); 812ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, lower_32_bits(addr)); 813ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, upper_32_bits(addr)); 814ea4a8c1dSMaruthi Srinivas Bayyavarapu amdgpu_ring_write(ring, seq); 815ea4a8c1dSMaruthi Srinivas Bayyavarapu } 816ea4a8c1dSMaruthi Srinivas Bayyavarapu 817a1255107SAlex Deucher static const struct amd_ip_funcs vce_v3_0_ip_funcs = { 81888a907d6STom St Denis .name = "vce_v3_0", 819aaa36a97SAlex Deucher .early_init = vce_v3_0_early_init, 820aaa36a97SAlex Deucher .late_init = NULL, 821aaa36a97SAlex Deucher .sw_init = vce_v3_0_sw_init, 822aaa36a97SAlex Deucher .sw_fini = vce_v3_0_sw_fini, 823aaa36a97SAlex Deucher .hw_init = vce_v3_0_hw_init, 824aaa36a97SAlex Deucher .hw_fini = vce_v3_0_hw_fini, 825aaa36a97SAlex Deucher .suspend = vce_v3_0_suspend, 826aaa36a97SAlex Deucher .resume = vce_v3_0_resume, 827aaa36a97SAlex Deucher .is_idle = vce_v3_0_is_idle, 828aaa36a97SAlex Deucher .wait_for_idle = vce_v3_0_wait_for_idle, 829115933a5SChunming Zhou .check_soft_reset = vce_v3_0_check_soft_reset, 830115933a5SChunming Zhou .pre_soft_reset = vce_v3_0_pre_soft_reset, 831aaa36a97SAlex Deucher .soft_reset = vce_v3_0_soft_reset, 832115933a5SChunming Zhou .post_soft_reset = vce_v3_0_post_soft_reset, 833aaa36a97SAlex Deucher .set_clockgating_state = vce_v3_0_set_clockgating_state, 834aaa36a97SAlex Deucher .set_powergating_state = vce_v3_0_set_powergating_state, 835aaa36a97SAlex Deucher }; 836aaa36a97SAlex Deucher 837ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = { 83821cd942eSChristian König .type = AMDGPU_RING_TYPE_VCE, 83979887142SChristian König .align_mask = 0xf, 84079887142SChristian König .nop = VCE_CMD_NO_OP, 841aaa36a97SAlex Deucher .get_rptr = vce_v3_0_ring_get_rptr, 842aaa36a97SAlex Deucher .get_wptr = vce_v3_0_ring_get_wptr, 843aaa36a97SAlex Deucher .set_wptr = vce_v3_0_ring_set_wptr, 844aaa36a97SAlex Deucher .parse_cs = amdgpu_vce_ring_parse_cs, 845e12f3d7aSChristian König .emit_frame_size = 846e12f3d7aSChristian König 4 + /* vce_v3_0_emit_pipeline_sync */ 847e12f3d7aSChristian König 6, /* amdgpu_vce_ring_emit_fence x1 no user fence */ 848e12f3d7aSChristian König .emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */ 849aaa36a97SAlex Deucher .emit_ib = amdgpu_vce_ring_emit_ib, 850aaa36a97SAlex Deucher .emit_fence = amdgpu_vce_ring_emit_fence, 851aaa36a97SAlex Deucher .test_ring = amdgpu_vce_ring_test_ring, 852aaa36a97SAlex Deucher .test_ib = amdgpu_vce_ring_test_ib, 853edff0e28SJammy Zhou .insert_nop = amdgpu_ring_insert_nop, 8549e5d5309SChristian König .pad_ib = amdgpu_ring_generic_pad_ib, 855ebff485eSChristian König .begin_use = amdgpu_vce_ring_begin_use, 856ebff485eSChristian König .end_use = amdgpu_vce_ring_end_use, 857aaa36a97SAlex Deucher }; 858aaa36a97SAlex Deucher 859ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = { 86021cd942eSChristian König .type = AMDGPU_RING_TYPE_VCE, 86179887142SChristian König .align_mask = 0xf, 86279887142SChristian König .nop = VCE_CMD_NO_OP, 863ea4a8c1dSMaruthi Srinivas Bayyavarapu .get_rptr = vce_v3_0_ring_get_rptr, 864ea4a8c1dSMaruthi Srinivas Bayyavarapu .get_wptr = vce_v3_0_ring_get_wptr, 865ea4a8c1dSMaruthi Srinivas Bayyavarapu .set_wptr = vce_v3_0_ring_set_wptr, 86698614701SChristian König .parse_cs = amdgpu_vce_ring_parse_cs_vm, 867e12f3d7aSChristian König .emit_frame_size = 868e12f3d7aSChristian König 6 + /* vce_v3_0_emit_vm_flush */ 869e12f3d7aSChristian König 4 + /* vce_v3_0_emit_pipeline_sync */ 870e12f3d7aSChristian König 6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */ 871e12f3d7aSChristian König .emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */ 872ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_ib = vce_v3_0_ring_emit_ib, 873ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_vm_flush = vce_v3_0_emit_vm_flush, 874ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_pipeline_sync = vce_v3_0_emit_pipeline_sync, 875ea4a8c1dSMaruthi Srinivas Bayyavarapu .emit_fence = amdgpu_vce_ring_emit_fence, 876ea4a8c1dSMaruthi Srinivas Bayyavarapu .test_ring = amdgpu_vce_ring_test_ring, 877ea4a8c1dSMaruthi Srinivas Bayyavarapu .test_ib = amdgpu_vce_ring_test_ib, 878ea4a8c1dSMaruthi Srinivas Bayyavarapu .insert_nop = amdgpu_ring_insert_nop, 879ea4a8c1dSMaruthi Srinivas Bayyavarapu .pad_ib = amdgpu_ring_generic_pad_ib, 880ea4a8c1dSMaruthi Srinivas Bayyavarapu .begin_use = amdgpu_vce_ring_begin_use, 881ea4a8c1dSMaruthi Srinivas Bayyavarapu .end_use = amdgpu_vce_ring_end_use, 882ea4a8c1dSMaruthi Srinivas Bayyavarapu }; 883ea4a8c1dSMaruthi Srinivas Bayyavarapu 884aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) 885aaa36a97SAlex Deucher { 88675c65480SAlex Deucher int i; 88775c65480SAlex Deucher 888ea4a8c1dSMaruthi Srinivas Bayyavarapu if (adev->asic_type >= CHIP_STONEY) { 88975c65480SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++) 890ea4a8c1dSMaruthi Srinivas Bayyavarapu adev->vce.ring[i].funcs = &vce_v3_0_ring_vm_funcs; 891ea4a8c1dSMaruthi Srinivas Bayyavarapu DRM_INFO("VCE enabled in VM mode\n"); 892ea4a8c1dSMaruthi Srinivas Bayyavarapu } else { 893ea4a8c1dSMaruthi Srinivas Bayyavarapu for (i = 0; i < adev->vce.num_rings; i++) 894ea4a8c1dSMaruthi Srinivas Bayyavarapu adev->vce.ring[i].funcs = &vce_v3_0_ring_phys_funcs; 895ea4a8c1dSMaruthi Srinivas Bayyavarapu DRM_INFO("VCE enabled in physical mode\n"); 896ea4a8c1dSMaruthi Srinivas Bayyavarapu } 897aaa36a97SAlex Deucher } 898aaa36a97SAlex Deucher 899aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = { 900aaa36a97SAlex Deucher .set = vce_v3_0_set_interrupt_state, 901aaa36a97SAlex Deucher .process = vce_v3_0_process_interrupt, 902aaa36a97SAlex Deucher }; 903aaa36a97SAlex Deucher 904aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev) 905aaa36a97SAlex Deucher { 906aaa36a97SAlex Deucher adev->vce.irq.num_types = 1; 907aaa36a97SAlex Deucher adev->vce.irq.funcs = &vce_v3_0_irq_funcs; 908aaa36a97SAlex Deucher }; 909a1255107SAlex Deucher 910a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_0_ip_block = 911a1255107SAlex Deucher { 912a1255107SAlex Deucher .type = AMD_IP_BLOCK_TYPE_VCE, 913a1255107SAlex Deucher .major = 3, 914a1255107SAlex Deucher .minor = 0, 915a1255107SAlex Deucher .rev = 0, 916a1255107SAlex Deucher .funcs = &vce_v3_0_ip_funcs, 917a1255107SAlex Deucher }; 918a1255107SAlex Deucher 919a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_1_ip_block = 920a1255107SAlex Deucher { 921a1255107SAlex Deucher .type = AMD_IP_BLOCK_TYPE_VCE, 922a1255107SAlex Deucher .major = 3, 923a1255107SAlex Deucher .minor = 1, 924a1255107SAlex Deucher .rev = 0, 925a1255107SAlex Deucher .funcs = &vce_v3_0_ip_funcs, 926a1255107SAlex Deucher }; 927a1255107SAlex Deucher 928a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_4_ip_block = 929a1255107SAlex Deucher { 930a1255107SAlex Deucher .type = AMD_IP_BLOCK_TYPE_VCE, 931a1255107SAlex Deucher .major = 3, 932a1255107SAlex Deucher .minor = 4, 933a1255107SAlex Deucher .rev = 0, 934a1255107SAlex Deucher .funcs = &vce_v3_0_ip_funcs, 935a1255107SAlex Deucher }; 936