1aaa36a97SAlex Deucher /* 2aaa36a97SAlex Deucher * Copyright 2014 Advanced Micro Devices, Inc. 3aaa36a97SAlex Deucher * All Rights Reserved. 4aaa36a97SAlex Deucher * 5aaa36a97SAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a 6aaa36a97SAlex Deucher * copy of this software and associated documentation files (the 7aaa36a97SAlex Deucher * "Software"), to deal in the Software without restriction, including 8aaa36a97SAlex Deucher * without limitation the rights to use, copy, modify, merge, publish, 9aaa36a97SAlex Deucher * distribute, sub license, and/or sell copies of the Software, and to 10aaa36a97SAlex Deucher * permit persons to whom the Software is furnished to do so, subject to 11aaa36a97SAlex Deucher * the following conditions: 12aaa36a97SAlex Deucher * 13aaa36a97SAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14aaa36a97SAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15aaa36a97SAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 16aaa36a97SAlex Deucher * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 17aaa36a97SAlex Deucher * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18aaa36a97SAlex Deucher * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 19aaa36a97SAlex Deucher * USE OR OTHER DEALINGS IN THE SOFTWARE. 20aaa36a97SAlex Deucher * 21aaa36a97SAlex Deucher * The above copyright notice and this permission notice (including the 22aaa36a97SAlex Deucher * next paragraph) shall be included in all copies or substantial portions 23aaa36a97SAlex Deucher * of the Software. 24aaa36a97SAlex Deucher * 25aaa36a97SAlex Deucher * Authors: Christian König <christian.koenig@amd.com> 26aaa36a97SAlex Deucher */ 27aaa36a97SAlex Deucher 28aaa36a97SAlex Deucher #include <linux/firmware.h> 29aaa36a97SAlex Deucher #include <drm/drmP.h> 30aaa36a97SAlex Deucher #include "amdgpu.h" 31aaa36a97SAlex Deucher #include "amdgpu_vce.h" 32aaa36a97SAlex Deucher #include "vid.h" 33aaa36a97SAlex Deucher #include "vce/vce_3_0_d.h" 34aaa36a97SAlex Deucher #include "vce/vce_3_0_sh_mask.h" 35be4f38e2SAlex Deucher #include "oss/oss_3_0_d.h" 36be4f38e2SAlex Deucher #include "oss/oss_3_0_sh_mask.h" 375bbc553aSLeo Liu #include "gca/gfx_8_0_d.h" 386a585777SAlex Deucher #include "smu/smu_7_1_2_d.h" 396a585777SAlex Deucher #include "smu/smu_7_1_2_sh_mask.h" 40115933a5SChunming Zhou #include "gca/gfx_8_0_d.h" 41115933a5SChunming Zhou #include "gca/gfx_8_0_sh_mask.h" 42115933a5SChunming Zhou 435bbc553aSLeo Liu 445bbc553aSLeo Liu #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04 455bbc553aSLeo Liu #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK 0x10 463c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0 0x8616 473c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1 0x8617 483c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2 0x8618 49567e6e29Sjimqu #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02 50aaa36a97SAlex Deucher 51e9822622SLeo Liu #define VCE_V3_0_FW_SIZE (384 * 1024) 52e9822622SLeo Liu #define VCE_V3_0_STACK_SIZE (64 * 1024) 53e9822622SLeo Liu #define VCE_V3_0_DATA_SIZE ((16 * 1024 * AMDGPU_MAX_VCE_HANDLES) + (52 * 1024)) 54e9822622SLeo Liu 555bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx); 56aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev); 57aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev); 58567e6e29Sjimqu static int vce_v3_0_wait_for_idle(void *handle); 59aaa36a97SAlex Deucher 60aaa36a97SAlex Deucher /** 61aaa36a97SAlex Deucher * vce_v3_0_ring_get_rptr - get read pointer 62aaa36a97SAlex Deucher * 63aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 64aaa36a97SAlex Deucher * 65aaa36a97SAlex Deucher * Returns the current hardware read pointer 66aaa36a97SAlex Deucher */ 67aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring) 68aaa36a97SAlex Deucher { 69aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 70aaa36a97SAlex Deucher 71aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 72aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR); 73aaa36a97SAlex Deucher else 74aaa36a97SAlex Deucher return RREG32(mmVCE_RB_RPTR2); 75aaa36a97SAlex Deucher } 76aaa36a97SAlex Deucher 77aaa36a97SAlex Deucher /** 78aaa36a97SAlex Deucher * vce_v3_0_ring_get_wptr - get write pointer 79aaa36a97SAlex Deucher * 80aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 81aaa36a97SAlex Deucher * 82aaa36a97SAlex Deucher * Returns the current hardware write pointer 83aaa36a97SAlex Deucher */ 84aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring) 85aaa36a97SAlex Deucher { 86aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 87aaa36a97SAlex Deucher 88aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 89aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR); 90aaa36a97SAlex Deucher else 91aaa36a97SAlex Deucher return RREG32(mmVCE_RB_WPTR2); 92aaa36a97SAlex Deucher } 93aaa36a97SAlex Deucher 94aaa36a97SAlex Deucher /** 95aaa36a97SAlex Deucher * vce_v3_0_ring_set_wptr - set write pointer 96aaa36a97SAlex Deucher * 97aaa36a97SAlex Deucher * @ring: amdgpu_ring pointer 98aaa36a97SAlex Deucher * 99aaa36a97SAlex Deucher * Commits the write pointer to the hardware 100aaa36a97SAlex Deucher */ 101aaa36a97SAlex Deucher static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring) 102aaa36a97SAlex Deucher { 103aaa36a97SAlex Deucher struct amdgpu_device *adev = ring->adev; 104aaa36a97SAlex Deucher 105aaa36a97SAlex Deucher if (ring == &adev->vce.ring[0]) 106aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR, ring->wptr); 107aaa36a97SAlex Deucher else 108aaa36a97SAlex Deucher WREG32(mmVCE_RB_WPTR2, ring->wptr); 109aaa36a97SAlex Deucher } 110aaa36a97SAlex Deucher 1110689a570SEric Huang static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override) 1120689a570SEric Huang { 1130689a570SEric Huang u32 tmp, data; 1140689a570SEric Huang 1150689a570SEric Huang tmp = data = RREG32(mmVCE_RB_ARB_CTRL); 1160689a570SEric Huang if (override) 1170689a570SEric Huang data |= VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; 1180689a570SEric Huang else 1190689a570SEric Huang data &= ~VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; 1200689a570SEric Huang 1210689a570SEric Huang if (tmp != data) 1220689a570SEric Huang WREG32(mmVCE_RB_ARB_CTRL, data); 1230689a570SEric Huang } 1240689a570SEric Huang 1250689a570SEric Huang static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, 1260689a570SEric Huang bool gated) 1270689a570SEric Huang { 1280689a570SEric Huang u32 tmp, data; 129f16fe6d3STom St Denis 1300689a570SEric Huang /* Set Override to disable Clock Gating */ 1310689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, true); 1320689a570SEric Huang 1336f906814STom St Denis /* This function enables MGCG which is controlled by firmware. 1346f906814STom St Denis With the clocks in the gated state the core is still 1356f906814STom St Denis accessible but the firmware will throttle the clocks on the 1366f906814STom St Denis fly as necessary. 1370689a570SEric Huang */ 1386f906814STom St Denis if (gated) { 1390689a570SEric Huang tmp = data = RREG32(mmVCE_CLOCK_GATING_B); 1400689a570SEric Huang data |= 0x1ff; 1410689a570SEric Huang data &= ~0xef0000; 1420689a570SEric Huang if (tmp != data) 1430689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1440689a570SEric Huang 1450689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); 1460689a570SEric Huang data |= 0x3ff000; 1470689a570SEric Huang data &= ~0xffc00000; 1480689a570SEric Huang if (tmp != data) 1490689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1500689a570SEric Huang 1510689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1520689a570SEric Huang data |= 0x2; 1536f906814STom St Denis data &= ~0x00010000; 1540689a570SEric Huang if (tmp != data) 1550689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1560689a570SEric Huang 1570689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1580689a570SEric Huang data |= 0x37f; 1590689a570SEric Huang if (tmp != data) 1600689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1610689a570SEric Huang 1620689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1630689a570SEric Huang data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1640689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1650689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1660689a570SEric Huang 0x8; 1670689a570SEric Huang if (tmp != data) 1680689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1690689a570SEric Huang } else { 1700689a570SEric Huang tmp = data = RREG32(mmVCE_CLOCK_GATING_B); 1710689a570SEric Huang data &= ~0x80010; 1720689a570SEric Huang data |= 0xe70008; 1730689a570SEric Huang if (tmp != data) 1740689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_B, data); 1756f906814STom St Denis 1760689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING); 1770689a570SEric Huang data |= 0xffc00000; 1780689a570SEric Huang if (tmp != data) 1790689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 1806f906814STom St Denis 1810689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2); 1820689a570SEric Huang data |= 0x10000; 1830689a570SEric Huang if (tmp != data) 1840689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING_2, data); 1856f906814STom St Denis 1860689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); 1870689a570SEric Huang data &= ~0xffc00000; 1880689a570SEric Huang if (tmp != data) 1890689a570SEric Huang WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); 1906f906814STom St Denis 1910689a570SEric Huang tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); 1920689a570SEric Huang data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | 1930689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | 1940689a570SEric Huang VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | 1950689a570SEric Huang 0x8); 1960689a570SEric Huang if (tmp != data) 1970689a570SEric Huang WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data); 1980689a570SEric Huang } 1990689a570SEric Huang vce_v3_0_override_vce_clock_gating(adev, false); 2000689a570SEric Huang } 2010689a570SEric Huang 202567e6e29Sjimqu static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev) 203567e6e29Sjimqu { 204567e6e29Sjimqu int i, j; 205567e6e29Sjimqu 206567e6e29Sjimqu for (i = 0; i < 10; ++i) { 207567e6e29Sjimqu for (j = 0; j < 100; ++j) { 208b7e2e9f7Sjimqu uint32_t status = RREG32(mmVCE_STATUS); 209b7e2e9f7Sjimqu 210567e6e29Sjimqu if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK) 211567e6e29Sjimqu return 0; 212567e6e29Sjimqu mdelay(10); 213567e6e29Sjimqu } 214567e6e29Sjimqu 215567e6e29Sjimqu DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); 216567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 217567e6e29Sjimqu VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, 218567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 219567e6e29Sjimqu mdelay(10); 220567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 0, 221567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 222567e6e29Sjimqu mdelay(10); 223567e6e29Sjimqu } 224567e6e29Sjimqu 225567e6e29Sjimqu return -ETIMEDOUT; 226567e6e29Sjimqu } 227567e6e29Sjimqu 228aaa36a97SAlex Deucher /** 229aaa36a97SAlex Deucher * vce_v3_0_start - start VCE block 230aaa36a97SAlex Deucher * 231aaa36a97SAlex Deucher * @adev: amdgpu_device pointer 232aaa36a97SAlex Deucher * 233aaa36a97SAlex Deucher * Setup and start the VCE block 234aaa36a97SAlex Deucher */ 235aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev) 236aaa36a97SAlex Deucher { 237aaa36a97SAlex Deucher struct amdgpu_ring *ring; 238567e6e29Sjimqu int idx, r; 239567e6e29Sjimqu 240567e6e29Sjimqu ring = &adev->vce.ring[0]; 241567e6e29Sjimqu WREG32(mmVCE_RB_RPTR, ring->wptr); 242567e6e29Sjimqu WREG32(mmVCE_RB_WPTR, ring->wptr); 243567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr); 244567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); 245567e6e29Sjimqu WREG32(mmVCE_RB_SIZE, ring->ring_size / 4); 246567e6e29Sjimqu 247567e6e29Sjimqu ring = &adev->vce.ring[1]; 248567e6e29Sjimqu WREG32(mmVCE_RB_RPTR2, ring->wptr); 249567e6e29Sjimqu WREG32(mmVCE_RB_WPTR2, ring->wptr); 250567e6e29Sjimqu WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr); 251567e6e29Sjimqu WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); 252567e6e29Sjimqu WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4); 253aaa36a97SAlex Deucher 2545bbc553aSLeo Liu mutex_lock(&adev->grbm_idx_mutex); 2555bbc553aSLeo Liu for (idx = 0; idx < 2; ++idx) { 2566a585777SAlex Deucher if (adev->vce.harvest_config & (1 << idx)) 2576a585777SAlex Deucher continue; 2586a585777SAlex Deucher 2595bbc553aSLeo Liu if (idx == 0) 2605bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 0, 2615bbc553aSLeo Liu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2625bbc553aSLeo Liu else 2635bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 2645bbc553aSLeo Liu GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 2655bbc553aSLeo Liu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2665bbc553aSLeo Liu 2675bbc553aSLeo Liu vce_v3_0_mc_resume(adev, idx); 268aaa36a97SAlex Deucher 269567e6e29Sjimqu WREG32_P(mmVCE_STATUS, VCE_STATUS__JOB_BUSY_MASK, 270567e6e29Sjimqu ~VCE_STATUS__JOB_BUSY_MASK); 271567e6e29Sjimqu 2723c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) 2733c0ff9f1SLeo Liu WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001); 2743c0ff9f1SLeo Liu else 2755bbc553aSLeo Liu WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, 2765bbc553aSLeo Liu ~VCE_VCPU_CNTL__CLK_EN_MASK); 277aaa36a97SAlex Deucher 278567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 0, 279aaa36a97SAlex Deucher ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 280aaa36a97SAlex Deucher 281aaa36a97SAlex Deucher mdelay(100); 282aaa36a97SAlex Deucher 283567e6e29Sjimqu r = vce_v3_0_firmware_loaded(adev); 284aaa36a97SAlex Deucher 285aaa36a97SAlex Deucher /* clear BUSY flag */ 286567e6e29Sjimqu WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK); 287aaa36a97SAlex Deucher 288aaa36a97SAlex Deucher if (r) { 289aaa36a97SAlex Deucher DRM_ERROR("VCE not responding, giving up!!!\n"); 2905bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 291aaa36a97SAlex Deucher return r; 292aaa36a97SAlex Deucher } 2935bbc553aSLeo Liu } 2945bbc553aSLeo Liu 2955bbc553aSLeo Liu WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 2965bbc553aSLeo Liu mutex_unlock(&adev->grbm_idx_mutex); 2975bbc553aSLeo Liu 298567e6e29Sjimqu return 0; 299567e6e29Sjimqu } 3005bbc553aSLeo Liu 301567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev) 302567e6e29Sjimqu { 303567e6e29Sjimqu int idx; 304567e6e29Sjimqu 305567e6e29Sjimqu mutex_lock(&adev->grbm_idx_mutex); 306567e6e29Sjimqu for (idx = 0; idx < 2; ++idx) { 307567e6e29Sjimqu if (adev->vce.harvest_config & (1 << idx)) 308567e6e29Sjimqu continue; 309567e6e29Sjimqu 310567e6e29Sjimqu if (idx == 0) 311567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 0, 312567e6e29Sjimqu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 313567e6e29Sjimqu else 314567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 315567e6e29Sjimqu GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 316567e6e29Sjimqu ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 317567e6e29Sjimqu 318567e6e29Sjimqu if (adev->asic_type >= CHIP_STONEY) 319567e6e29Sjimqu WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001); 320567e6e29Sjimqu else 321567e6e29Sjimqu WREG32_P(mmVCE_VCPU_CNTL, 0, 322567e6e29Sjimqu ~VCE_VCPU_CNTL__CLK_EN_MASK); 323567e6e29Sjimqu /* hold on ECPU */ 324567e6e29Sjimqu WREG32_P(mmVCE_SOFT_RESET, 325567e6e29Sjimqu VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, 326567e6e29Sjimqu ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK); 327567e6e29Sjimqu 328567e6e29Sjimqu /* clear BUSY flag */ 329567e6e29Sjimqu WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK); 330567e6e29Sjimqu 331567e6e29Sjimqu /* Set Clock-Gating off */ 332567e6e29Sjimqu if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG) 333567e6e29Sjimqu vce_v3_0_set_vce_sw_clock_gating(adev, false); 334567e6e29Sjimqu } 335567e6e29Sjimqu 336567e6e29Sjimqu WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 337567e6e29Sjimqu mutex_unlock(&adev->grbm_idx_mutex); 338aaa36a97SAlex Deucher 339aaa36a97SAlex Deucher return 0; 340aaa36a97SAlex Deucher } 341aaa36a97SAlex Deucher 3426a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS 0xC0014074 3436a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT 27 3446a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK 0x18000000 3456a585777SAlex Deucher 3466a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) 3476a585777SAlex Deucher { 3486a585777SAlex Deucher u32 tmp; 3496a585777SAlex Deucher 3502cc0c0b5SFlora Cui /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */ 351cfaba566SSamuel Li if ((adev->asic_type == CHIP_FIJI) || 3521b4eeea5SSonny Jiang (adev->asic_type == CHIP_STONEY) || 3532cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS10) || 3542cc0c0b5SFlora Cui (adev->asic_type == CHIP_POLARIS11)) 3551dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 356188a9bcdSAlex Deucher 357188a9bcdSAlex Deucher /* Tonga and CZ are dual or single pipe */ 3582f7d10b3SJammy Zhou if (adev->flags & AMD_IS_APU) 3596a585777SAlex Deucher tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) & 3606a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__MASK) >> 3616a585777SAlex Deucher VCE_HARVEST_FUSE_MACRO__SHIFT; 3626a585777SAlex Deucher else 3636a585777SAlex Deucher tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) & 3646a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE_MASK) >> 3656a585777SAlex Deucher CC_HARVEST_FUSES__VCE_DISABLE__SHIFT; 3666a585777SAlex Deucher 3676a585777SAlex Deucher switch (tmp) { 3686a585777SAlex Deucher case 1: 3691dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0; 3706a585777SAlex Deucher case 2: 3711dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE1; 3726a585777SAlex Deucher case 3: 3731dab5f06STom St Denis return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1; 3746a585777SAlex Deucher default: 3751dab5f06STom St Denis return 0; 3766a585777SAlex Deucher } 3776a585777SAlex Deucher } 3786a585777SAlex Deucher 3795fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle) 380aaa36a97SAlex Deucher { 3815fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 3825fc3aeebSyanyang1 3836a585777SAlex Deucher adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); 3846a585777SAlex Deucher 3856a585777SAlex Deucher if ((adev->vce.harvest_config & 3866a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) == 3876a585777SAlex Deucher (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) 3886a585777SAlex Deucher return -ENOENT; 3896a585777SAlex Deucher 390aaa36a97SAlex Deucher vce_v3_0_set_ring_funcs(adev); 391aaa36a97SAlex Deucher vce_v3_0_set_irq_funcs(adev); 392aaa36a97SAlex Deucher 393aaa36a97SAlex Deucher return 0; 394aaa36a97SAlex Deucher } 395aaa36a97SAlex Deucher 3965fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle) 397aaa36a97SAlex Deucher { 3985fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 399aaa36a97SAlex Deucher struct amdgpu_ring *ring; 400aaa36a97SAlex Deucher int r; 401aaa36a97SAlex Deucher 402aaa36a97SAlex Deucher /* VCE */ 403aaa36a97SAlex Deucher r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq); 404aaa36a97SAlex Deucher if (r) 405aaa36a97SAlex Deucher return r; 406aaa36a97SAlex Deucher 407e9822622SLeo Liu r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE + 408e9822622SLeo Liu (VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2); 409aaa36a97SAlex Deucher if (r) 410aaa36a97SAlex Deucher return r; 411aaa36a97SAlex Deucher 412aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 413aaa36a97SAlex Deucher if (r) 414aaa36a97SAlex Deucher return r; 415aaa36a97SAlex Deucher 416aaa36a97SAlex Deucher ring = &adev->vce.ring[0]; 417aaa36a97SAlex Deucher sprintf(ring->name, "vce0"); 418a3f1cf35SChristian König r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf, 419aaa36a97SAlex Deucher &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); 420aaa36a97SAlex Deucher if (r) 421aaa36a97SAlex Deucher return r; 422aaa36a97SAlex Deucher 423aaa36a97SAlex Deucher ring = &adev->vce.ring[1]; 424aaa36a97SAlex Deucher sprintf(ring->name, "vce1"); 425a3f1cf35SChristian König r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf, 426aaa36a97SAlex Deucher &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE); 427aaa36a97SAlex Deucher if (r) 428aaa36a97SAlex Deucher return r; 429aaa36a97SAlex Deucher 430aaa36a97SAlex Deucher return r; 431aaa36a97SAlex Deucher } 432aaa36a97SAlex Deucher 4335fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle) 434aaa36a97SAlex Deucher { 435aaa36a97SAlex Deucher int r; 4365fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 437aaa36a97SAlex Deucher 438aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 439aaa36a97SAlex Deucher if (r) 440aaa36a97SAlex Deucher return r; 441aaa36a97SAlex Deucher 442aaa36a97SAlex Deucher r = amdgpu_vce_sw_fini(adev); 443aaa36a97SAlex Deucher if (r) 444aaa36a97SAlex Deucher return r; 445aaa36a97SAlex Deucher 446aaa36a97SAlex Deucher return r; 447aaa36a97SAlex Deucher } 448aaa36a97SAlex Deucher 4495fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle) 450aaa36a97SAlex Deucher { 451691ca86aSTom St Denis int r, i; 4525fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 453aaa36a97SAlex Deucher 454aaa36a97SAlex Deucher r = vce_v3_0_start(adev); 455aaa36a97SAlex Deucher if (r) 456aaa36a97SAlex Deucher return r; 457aaa36a97SAlex Deucher 458691ca86aSTom St Denis adev->vce.ring[0].ready = false; 459691ca86aSTom St Denis adev->vce.ring[1].ready = false; 460aaa36a97SAlex Deucher 461691ca86aSTom St Denis for (i = 0; i < 2; i++) { 462691ca86aSTom St Denis r = amdgpu_ring_test_ring(&adev->vce.ring[i]); 463691ca86aSTom St Denis if (r) 464aaa36a97SAlex Deucher return r; 465691ca86aSTom St Denis else 466691ca86aSTom St Denis adev->vce.ring[i].ready = true; 467aaa36a97SAlex Deucher } 468aaa36a97SAlex Deucher 469aaa36a97SAlex Deucher DRM_INFO("VCE initialized successfully.\n"); 470aaa36a97SAlex Deucher 471aaa36a97SAlex Deucher return 0; 472aaa36a97SAlex Deucher } 473aaa36a97SAlex Deucher 4745fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle) 475aaa36a97SAlex Deucher { 476567e6e29Sjimqu int r; 477567e6e29Sjimqu struct amdgpu_device *adev = (struct amdgpu_device *)handle; 478567e6e29Sjimqu 479567e6e29Sjimqu r = vce_v3_0_wait_for_idle(handle); 480567e6e29Sjimqu if (r) 481567e6e29Sjimqu return r; 482567e6e29Sjimqu 483567e6e29Sjimqu return vce_v3_0_stop(adev); 484aaa36a97SAlex Deucher } 485aaa36a97SAlex Deucher 4865fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle) 487aaa36a97SAlex Deucher { 488aaa36a97SAlex Deucher int r; 4895fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 490aaa36a97SAlex Deucher 491aaa36a97SAlex Deucher r = vce_v3_0_hw_fini(adev); 492aaa36a97SAlex Deucher if (r) 493aaa36a97SAlex Deucher return r; 494aaa36a97SAlex Deucher 495aaa36a97SAlex Deucher r = amdgpu_vce_suspend(adev); 496aaa36a97SAlex Deucher if (r) 497aaa36a97SAlex Deucher return r; 498aaa36a97SAlex Deucher 499aaa36a97SAlex Deucher return r; 500aaa36a97SAlex Deucher } 501aaa36a97SAlex Deucher 5025fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle) 503aaa36a97SAlex Deucher { 504aaa36a97SAlex Deucher int r; 5055fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 506aaa36a97SAlex Deucher 507aaa36a97SAlex Deucher r = amdgpu_vce_resume(adev); 508aaa36a97SAlex Deucher if (r) 509aaa36a97SAlex Deucher return r; 510aaa36a97SAlex Deucher 511aaa36a97SAlex Deucher r = vce_v3_0_hw_init(adev); 512aaa36a97SAlex Deucher if (r) 513aaa36a97SAlex Deucher return r; 514aaa36a97SAlex Deucher 515aaa36a97SAlex Deucher return r; 516aaa36a97SAlex Deucher } 517aaa36a97SAlex Deucher 5185bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) 519aaa36a97SAlex Deucher { 520aaa36a97SAlex Deucher uint32_t offset, size; 521aaa36a97SAlex Deucher 522aaa36a97SAlex Deucher WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16)); 523aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); 524aaa36a97SAlex Deucher WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); 5256f906814STom St Denis WREG32(mmVCE_CLOCK_GATING_B, 0x1FF); 526aaa36a97SAlex Deucher 527aaa36a97SAlex Deucher WREG32(mmVCE_LMI_CTRL, 0x00398000); 528aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1); 529aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL, 0); 530aaa36a97SAlex Deucher WREG32(mmVCE_LMI_SWAP_CNTL1, 0); 531aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VM_CTRL, 0); 5323c0ff9f1SLeo Liu if (adev->asic_type >= CHIP_STONEY) { 5333c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8)); 5343c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8)); 5353c0ff9f1SLeo Liu WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8)); 5363c0ff9f1SLeo Liu } else 537aaa36a97SAlex Deucher WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8)); 538aaa36a97SAlex Deucher offset = AMDGPU_VCE_FIRMWARE_OFFSET; 539e9822622SLeo Liu size = VCE_V3_0_FW_SIZE; 540aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff); 541aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE0, size); 542aaa36a97SAlex Deucher 5435bbc553aSLeo Liu if (idx == 0) { 544aaa36a97SAlex Deucher offset += size; 545e9822622SLeo Liu size = VCE_V3_0_STACK_SIZE; 546aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff); 547aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 548aaa36a97SAlex Deucher offset += size; 549e9822622SLeo Liu size = VCE_V3_0_DATA_SIZE; 550aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff); 551aaa36a97SAlex Deucher WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5525bbc553aSLeo Liu } else { 5535bbc553aSLeo Liu offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE; 5545bbc553aSLeo Liu size = VCE_V3_0_STACK_SIZE; 5555bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff); 5565bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE1, size); 5575bbc553aSLeo Liu offset += size; 5585bbc553aSLeo Liu size = VCE_V3_0_DATA_SIZE; 5595bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff); 5605bbc553aSLeo Liu WREG32(mmVCE_VCPU_CACHE_SIZE2, size); 5615bbc553aSLeo Liu } 562aaa36a97SAlex Deucher 563aaa36a97SAlex Deucher WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100); 564aaa36a97SAlex Deucher 565aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK, 566aaa36a97SAlex Deucher ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 567aaa36a97SAlex Deucher } 568aaa36a97SAlex Deucher 5695fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle) 570aaa36a97SAlex Deucher { 5715fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 572be4f38e2SAlex Deucher u32 mask = 0; 5735fc3aeebSyanyang1 57474af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK; 57574af1276STom St Denis mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK; 576be4f38e2SAlex Deucher 577be4f38e2SAlex Deucher return !(RREG32(mmSRBM_STATUS2) & mask); 578aaa36a97SAlex Deucher } 579aaa36a97SAlex Deucher 5805fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle) 581aaa36a97SAlex Deucher { 582aaa36a97SAlex Deucher unsigned i; 5835fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 584be4f38e2SAlex Deucher 58592988e60STom St Denis for (i = 0; i < adev->usec_timeout; i++) 58692988e60STom St Denis if (vce_v3_0_is_idle(handle)) 587aaa36a97SAlex Deucher return 0; 58892988e60STom St Denis 589aaa36a97SAlex Deucher return -ETIMEDOUT; 590aaa36a97SAlex Deucher } 591aaa36a97SAlex Deucher 592ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK 0x00000008L /* AUTO_BUSY */ 593ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK 0x00000010L /* RB0_BUSY */ 594ac8e3f30SRex Zhu #define VCE_STATUS_VCPU_REPORT_RB1_BUSY_MASK 0x00000020L /* RB1_BUSY */ 595ac8e3f30SRex Zhu #define AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \ 596ac8e3f30SRex Zhu VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK) 597115933a5SChunming Zhou 598115933a5SChunming Zhou static int vce_v3_0_check_soft_reset(void *handle) 599115933a5SChunming Zhou { 600115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 601115933a5SChunming Zhou u32 srbm_soft_reset = 0; 602115933a5SChunming Zhou u32 tmp; 603115933a5SChunming Zhou 604115933a5SChunming Zhou /* VCE BUG: it is always busy, so skip its checking now */ 605115933a5SChunming Zhou return 0; 606115933a5SChunming Zhou 607115933a5SChunming Zhou /* According to VCE team , we should use VCE_STATUS instead 608115933a5SChunming Zhou * SRBM_STATUS.VCE_BUSY bit for busy status checking. 609115933a5SChunming Zhou * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE 610115933a5SChunming Zhou * instance's registers are accessed 611115933a5SChunming Zhou * (0 for 1st instance, 10 for 2nd instance). 612115933a5SChunming Zhou * 613115933a5SChunming Zhou *VCE_STATUS 614115933a5SChunming Zhou *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 | |FW_LOADED|JOB | 615115933a5SChunming Zhou *|----+----+-----------+----+----+----+----------+---------+----| 616115933a5SChunming Zhou *|bit8|bit7| bit6 |bit5|bit4|bit3| bit2 | bit1 |bit0| 617115933a5SChunming Zhou * 618115933a5SChunming Zhou * VCE team suggest use bit 3--bit 6 for busy status check 619115933a5SChunming Zhou */ 620115933a5SChunming Zhou tmp = RREG32(mmGRBM_GFX_INDEX); 621115933a5SChunming Zhou tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 622115933a5SChunming Zhou WREG32(mmGRBM_GFX_INDEX, tmp); 623115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 624115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 625115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 626115933a5SChunming Zhou } 627115933a5SChunming Zhou tmp = RREG32(mmGRBM_GFX_INDEX); 628115933a5SChunming Zhou tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10); 629115933a5SChunming Zhou WREG32(mmGRBM_GFX_INDEX, tmp); 630115933a5SChunming Zhou if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { 631115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); 632115933a5SChunming Zhou srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); 633115933a5SChunming Zhou } 634115933a5SChunming Zhou tmp = RREG32(mmGRBM_GFX_INDEX); 635115933a5SChunming Zhou tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0); 636115933a5SChunming Zhou WREG32(mmGRBM_GFX_INDEX, tmp); 637115933a5SChunming Zhou 638115933a5SChunming Zhou if (srbm_soft_reset) { 639115933a5SChunming Zhou adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = true; 640115933a5SChunming Zhou adev->vce.srbm_soft_reset = srbm_soft_reset; 641115933a5SChunming Zhou } else { 642115933a5SChunming Zhou adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = false; 643115933a5SChunming Zhou adev->vce.srbm_soft_reset = 0; 644115933a5SChunming Zhou } 645115933a5SChunming Zhou return 0; 646115933a5SChunming Zhou } 647115933a5SChunming Zhou 6485fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle) 649aaa36a97SAlex Deucher { 6505fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 651115933a5SChunming Zhou u32 srbm_soft_reset; 6525fc3aeebSyanyang1 653115933a5SChunming Zhou if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) 654115933a5SChunming Zhou return 0; 655115933a5SChunming Zhou srbm_soft_reset = adev->vce.srbm_soft_reset; 656be4f38e2SAlex Deucher 657115933a5SChunming Zhou if (srbm_soft_reset) { 658115933a5SChunming Zhou u32 tmp; 659115933a5SChunming Zhou 660115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 661115933a5SChunming Zhou tmp |= srbm_soft_reset; 662115933a5SChunming Zhou dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); 663115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 664115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 665115933a5SChunming Zhou 666115933a5SChunming Zhou udelay(50); 667115933a5SChunming Zhou 668115933a5SChunming Zhou tmp &= ~srbm_soft_reset; 669115933a5SChunming Zhou WREG32(mmSRBM_SOFT_RESET, tmp); 670115933a5SChunming Zhou tmp = RREG32(mmSRBM_SOFT_RESET); 671115933a5SChunming Zhou 672115933a5SChunming Zhou /* Wait a little for things to settle down */ 673115933a5SChunming Zhou udelay(50); 674115933a5SChunming Zhou } 675115933a5SChunming Zhou 676115933a5SChunming Zhou return 0; 677115933a5SChunming Zhou } 678115933a5SChunming Zhou 679115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle) 680115933a5SChunming Zhou { 681115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 682115933a5SChunming Zhou 683115933a5SChunming Zhou if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) 684115933a5SChunming Zhou return 0; 685115933a5SChunming Zhou 686aaa36a97SAlex Deucher mdelay(5); 687aaa36a97SAlex Deucher 688115933a5SChunming Zhou return vce_v3_0_suspend(adev); 689115933a5SChunming Zhou } 690115933a5SChunming Zhou 691115933a5SChunming Zhou 692115933a5SChunming Zhou static int vce_v3_0_post_soft_reset(void *handle) 693115933a5SChunming Zhou { 694115933a5SChunming Zhou struct amdgpu_device *adev = (struct amdgpu_device *)handle; 695115933a5SChunming Zhou 696115933a5SChunming Zhou if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang) 697115933a5SChunming Zhou return 0; 698115933a5SChunming Zhou 699115933a5SChunming Zhou mdelay(5); 700115933a5SChunming Zhou 701115933a5SChunming Zhou return vce_v3_0_resume(adev); 702aaa36a97SAlex Deucher } 703aaa36a97SAlex Deucher 704aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, 705aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 706aaa36a97SAlex Deucher unsigned type, 707aaa36a97SAlex Deucher enum amdgpu_interrupt_state state) 708aaa36a97SAlex Deucher { 709aaa36a97SAlex Deucher uint32_t val = 0; 710aaa36a97SAlex Deucher 711aaa36a97SAlex Deucher if (state == AMDGPU_IRQ_STATE_ENABLE) 712aaa36a97SAlex Deucher val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK; 713aaa36a97SAlex Deucher 714aaa36a97SAlex Deucher WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK); 715aaa36a97SAlex Deucher return 0; 716aaa36a97SAlex Deucher } 717aaa36a97SAlex Deucher 718aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev, 719aaa36a97SAlex Deucher struct amdgpu_irq_src *source, 720aaa36a97SAlex Deucher struct amdgpu_iv_entry *entry) 721aaa36a97SAlex Deucher { 722aaa36a97SAlex Deucher DRM_DEBUG("IH: VCE\n"); 723d6c29c30SLeo Liu 724d6c29c30SLeo Liu WREG32_P(mmVCE_SYS_INT_STATUS, 725d6c29c30SLeo Liu VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK, 726d6c29c30SLeo Liu ~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK); 727d6c29c30SLeo Liu 728aaa36a97SAlex Deucher switch (entry->src_data) { 729aaa36a97SAlex Deucher case 0: 730aaa36a97SAlex Deucher case 1: 73181da2edeSTom St Denis amdgpu_fence_process(&adev->vce.ring[entry->src_data]); 732aaa36a97SAlex Deucher break; 733aaa36a97SAlex Deucher default: 734aaa36a97SAlex Deucher DRM_ERROR("Unhandled interrupt: %d %d\n", 735aaa36a97SAlex Deucher entry->src_id, entry->src_data); 736aaa36a97SAlex Deucher break; 737aaa36a97SAlex Deucher } 738aaa36a97SAlex Deucher 739aaa36a97SAlex Deucher return 0; 740aaa36a97SAlex Deucher } 741aaa36a97SAlex Deucher 742ec38f188SRex Zhu static void vce_v3_set_bypass_mode(struct amdgpu_device *adev, bool enable) 743ec38f188SRex Zhu { 744ec38f188SRex Zhu u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL); 745ec38f188SRex Zhu 746ec38f188SRex Zhu if (enable) 747ec38f188SRex Zhu tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 748ec38f188SRex Zhu else 749ec38f188SRex Zhu tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; 750ec38f188SRex Zhu 751ec38f188SRex Zhu WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp); 752ec38f188SRex Zhu } 753ec38f188SRex Zhu 7545fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle, 7555fc3aeebSyanyang1 enum amd_clockgating_state state) 756aaa36a97SAlex Deucher { 7570689a570SEric Huang struct amdgpu_device *adev = (struct amdgpu_device *)handle; 7580689a570SEric Huang bool enable = (state == AMD_CG_STATE_GATE) ? true : false; 7590689a570SEric Huang int i; 7600689a570SEric Huang 761ec38f188SRex Zhu if (adev->asic_type == CHIP_POLARIS10) 762ec38f188SRex Zhu vce_v3_set_bypass_mode(adev, enable); 763ec38f188SRex Zhu 764e3b04bc7SAlex Deucher if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) 7650689a570SEric Huang return 0; 7660689a570SEric Huang 7670689a570SEric Huang mutex_lock(&adev->grbm_idx_mutex); 7680689a570SEric Huang for (i = 0; i < 2; i++) { 7690689a570SEric Huang /* Program VCE Instance 0 or 1 if not harvested */ 7700689a570SEric Huang if (adev->vce.harvest_config & (1 << i)) 7710689a570SEric Huang continue; 7720689a570SEric Huang 7730689a570SEric Huang if (i == 0) 7740689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 0, 7750689a570SEric Huang ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 7760689a570SEric Huang else 7770689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 7780689a570SEric Huang GRBM_GFX_INDEX__VCE_INSTANCE_MASK, 7790689a570SEric Huang ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 7800689a570SEric Huang 7810689a570SEric Huang if (enable) { 7820689a570SEric Huang /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ 7830689a570SEric Huang uint32_t data = RREG32(mmVCE_CLOCK_GATING_A); 7840689a570SEric Huang data &= ~(0xf | 0xff0); 7850689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7860689a570SEric Huang WREG32(mmVCE_CLOCK_GATING_A, data); 7870689a570SEric Huang 7880689a570SEric Huang /* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */ 7890689a570SEric Huang data = RREG32(mmVCE_UENC_CLOCK_GATING); 7900689a570SEric Huang data &= ~(0xf | 0xff0); 7910689a570SEric Huang data |= ((0x0 << 0) | (0x04 << 4)); 7920689a570SEric Huang WREG32(mmVCE_UENC_CLOCK_GATING, data); 7930689a570SEric Huang } 7940689a570SEric Huang 7950689a570SEric Huang vce_v3_0_set_vce_sw_clock_gating(adev, enable); 7960689a570SEric Huang } 7970689a570SEric Huang 7980689a570SEric Huang WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK); 7990689a570SEric Huang mutex_unlock(&adev->grbm_idx_mutex); 8000689a570SEric Huang 801aaa36a97SAlex Deucher return 0; 802aaa36a97SAlex Deucher } 803aaa36a97SAlex Deucher 8045fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle, 8055fc3aeebSyanyang1 enum amd_powergating_state state) 806aaa36a97SAlex Deucher { 807aaa36a97SAlex Deucher /* This doesn't actually powergate the VCE block. 808aaa36a97SAlex Deucher * That's done in the dpm code via the SMC. This 809aaa36a97SAlex Deucher * just re-inits the block as necessary. The actual 810aaa36a97SAlex Deucher * gating still happens in the dpm code. We should 811aaa36a97SAlex Deucher * revisit this when there is a cleaner line between 812aaa36a97SAlex Deucher * the smc and the hw blocks 813aaa36a97SAlex Deucher */ 8145fc3aeebSyanyang1 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 8155fc3aeebSyanyang1 816e3b04bc7SAlex Deucher if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE)) 817808a934fSAlex Deucher return 0; 818808a934fSAlex Deucher 8195fc3aeebSyanyang1 if (state == AMD_PG_STATE_GATE) 820aaa36a97SAlex Deucher /* XXX do we need a vce_v3_0_stop()? */ 821aaa36a97SAlex Deucher return 0; 822aaa36a97SAlex Deucher else 823aaa36a97SAlex Deucher return vce_v3_0_start(adev); 824aaa36a97SAlex Deucher } 825aaa36a97SAlex Deucher 8265fc3aeebSyanyang1 const struct amd_ip_funcs vce_v3_0_ip_funcs = { 82788a907d6STom St Denis .name = "vce_v3_0", 828aaa36a97SAlex Deucher .early_init = vce_v3_0_early_init, 829aaa36a97SAlex Deucher .late_init = NULL, 830aaa36a97SAlex Deucher .sw_init = vce_v3_0_sw_init, 831aaa36a97SAlex Deucher .sw_fini = vce_v3_0_sw_fini, 832aaa36a97SAlex Deucher .hw_init = vce_v3_0_hw_init, 833aaa36a97SAlex Deucher .hw_fini = vce_v3_0_hw_fini, 834aaa36a97SAlex Deucher .suspend = vce_v3_0_suspend, 835aaa36a97SAlex Deucher .resume = vce_v3_0_resume, 836aaa36a97SAlex Deucher .is_idle = vce_v3_0_is_idle, 837aaa36a97SAlex Deucher .wait_for_idle = vce_v3_0_wait_for_idle, 838115933a5SChunming Zhou .check_soft_reset = vce_v3_0_check_soft_reset, 839115933a5SChunming Zhou .pre_soft_reset = vce_v3_0_pre_soft_reset, 840aaa36a97SAlex Deucher .soft_reset = vce_v3_0_soft_reset, 841115933a5SChunming Zhou .post_soft_reset = vce_v3_0_post_soft_reset, 842aaa36a97SAlex Deucher .set_clockgating_state = vce_v3_0_set_clockgating_state, 843aaa36a97SAlex Deucher .set_powergating_state = vce_v3_0_set_powergating_state, 844aaa36a97SAlex Deucher }; 845aaa36a97SAlex Deucher 846aaa36a97SAlex Deucher static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = { 847aaa36a97SAlex Deucher .get_rptr = vce_v3_0_ring_get_rptr, 848aaa36a97SAlex Deucher .get_wptr = vce_v3_0_ring_get_wptr, 849aaa36a97SAlex Deucher .set_wptr = vce_v3_0_ring_set_wptr, 850aaa36a97SAlex Deucher .parse_cs = amdgpu_vce_ring_parse_cs, 851aaa36a97SAlex Deucher .emit_ib = amdgpu_vce_ring_emit_ib, 852aaa36a97SAlex Deucher .emit_fence = amdgpu_vce_ring_emit_fence, 853aaa36a97SAlex Deucher .test_ring = amdgpu_vce_ring_test_ring, 854aaa36a97SAlex Deucher .test_ib = amdgpu_vce_ring_test_ib, 855edff0e28SJammy Zhou .insert_nop = amdgpu_ring_insert_nop, 8569e5d5309SChristian König .pad_ib = amdgpu_ring_generic_pad_ib, 857ebff485eSChristian König .begin_use = amdgpu_vce_ring_begin_use, 858ebff485eSChristian König .end_use = amdgpu_vce_ring_end_use, 859aaa36a97SAlex Deucher }; 860aaa36a97SAlex Deucher 861aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) 862aaa36a97SAlex Deucher { 863aaa36a97SAlex Deucher adev->vce.ring[0].funcs = &vce_v3_0_ring_funcs; 864aaa36a97SAlex Deucher adev->vce.ring[1].funcs = &vce_v3_0_ring_funcs; 865aaa36a97SAlex Deucher } 866aaa36a97SAlex Deucher 867aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = { 868aaa36a97SAlex Deucher .set = vce_v3_0_set_interrupt_state, 869aaa36a97SAlex Deucher .process = vce_v3_0_process_interrupt, 870aaa36a97SAlex Deucher }; 871aaa36a97SAlex Deucher 872aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev) 873aaa36a97SAlex Deucher { 874aaa36a97SAlex Deucher adev->vce.irq.num_types = 1; 875aaa36a97SAlex Deucher adev->vce.irq.funcs = &vce_v3_0_irq_funcs; 876aaa36a97SAlex Deucher }; 877