xref: /openbmc/linux/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c (revision 567e6e29)
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"
405bbc553aSLeo Liu 
415bbc553aSLeo Liu #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT	0x04
425bbc553aSLeo Liu #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK	0x10
433c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0	0x8616
443c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1	0x8617
453c0ff9f1SLeo Liu #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2	0x8618
46567e6e29Sjimqu #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK	0x02
47aaa36a97SAlex Deucher 
48e9822622SLeo Liu #define VCE_V3_0_FW_SIZE	(384 * 1024)
49e9822622SLeo Liu #define VCE_V3_0_STACK_SIZE	(64 * 1024)
50e9822622SLeo Liu #define VCE_V3_0_DATA_SIZE	((16 * 1024 * AMDGPU_MAX_VCE_HANDLES) + (52 * 1024))
51e9822622SLeo Liu 
525bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx);
53aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev);
54aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev);
55567e6e29Sjimqu static int vce_v3_0_wait_for_idle(void *handle);
56aaa36a97SAlex Deucher 
57aaa36a97SAlex Deucher /**
58aaa36a97SAlex Deucher  * vce_v3_0_ring_get_rptr - get read pointer
59aaa36a97SAlex Deucher  *
60aaa36a97SAlex Deucher  * @ring: amdgpu_ring pointer
61aaa36a97SAlex Deucher  *
62aaa36a97SAlex Deucher  * Returns the current hardware read pointer
63aaa36a97SAlex Deucher  */
64aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring)
65aaa36a97SAlex Deucher {
66aaa36a97SAlex Deucher 	struct amdgpu_device *adev = ring->adev;
67aaa36a97SAlex Deucher 
68aaa36a97SAlex Deucher 	if (ring == &adev->vce.ring[0])
69aaa36a97SAlex Deucher 		return RREG32(mmVCE_RB_RPTR);
70aaa36a97SAlex Deucher 	else
71aaa36a97SAlex Deucher 		return RREG32(mmVCE_RB_RPTR2);
72aaa36a97SAlex Deucher }
73aaa36a97SAlex Deucher 
74aaa36a97SAlex Deucher /**
75aaa36a97SAlex Deucher  * vce_v3_0_ring_get_wptr - get write pointer
76aaa36a97SAlex Deucher  *
77aaa36a97SAlex Deucher  * @ring: amdgpu_ring pointer
78aaa36a97SAlex Deucher  *
79aaa36a97SAlex Deucher  * Returns the current hardware write pointer
80aaa36a97SAlex Deucher  */
81aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring)
82aaa36a97SAlex Deucher {
83aaa36a97SAlex Deucher 	struct amdgpu_device *adev = ring->adev;
84aaa36a97SAlex Deucher 
85aaa36a97SAlex Deucher 	if (ring == &adev->vce.ring[0])
86aaa36a97SAlex Deucher 		return RREG32(mmVCE_RB_WPTR);
87aaa36a97SAlex Deucher 	else
88aaa36a97SAlex Deucher 		return RREG32(mmVCE_RB_WPTR2);
89aaa36a97SAlex Deucher }
90aaa36a97SAlex Deucher 
91aaa36a97SAlex Deucher /**
92aaa36a97SAlex Deucher  * vce_v3_0_ring_set_wptr - set write pointer
93aaa36a97SAlex Deucher  *
94aaa36a97SAlex Deucher  * @ring: amdgpu_ring pointer
95aaa36a97SAlex Deucher  *
96aaa36a97SAlex Deucher  * Commits the write pointer to the hardware
97aaa36a97SAlex Deucher  */
98aaa36a97SAlex Deucher static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring)
99aaa36a97SAlex Deucher {
100aaa36a97SAlex Deucher 	struct amdgpu_device *adev = ring->adev;
101aaa36a97SAlex Deucher 
102aaa36a97SAlex Deucher 	if (ring == &adev->vce.ring[0])
103aaa36a97SAlex Deucher 		WREG32(mmVCE_RB_WPTR, ring->wptr);
104aaa36a97SAlex Deucher 	else
105aaa36a97SAlex Deucher 		WREG32(mmVCE_RB_WPTR2, ring->wptr);
106aaa36a97SAlex Deucher }
107aaa36a97SAlex Deucher 
1080689a570SEric Huang static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override)
1090689a570SEric Huang {
1100689a570SEric Huang 	u32 tmp, data;
1110689a570SEric Huang 
1120689a570SEric Huang 	tmp = data = RREG32(mmVCE_RB_ARB_CTRL);
1130689a570SEric Huang 	if (override)
1140689a570SEric Huang 		data |= VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK;
1150689a570SEric Huang 	else
1160689a570SEric Huang 		data &= ~VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK;
1170689a570SEric Huang 
1180689a570SEric Huang 	if (tmp != data)
1190689a570SEric Huang 		WREG32(mmVCE_RB_ARB_CTRL, data);
1200689a570SEric Huang }
1210689a570SEric Huang 
1220689a570SEric Huang static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev,
1230689a570SEric Huang 					     bool gated)
1240689a570SEric Huang {
1250689a570SEric Huang 	u32 tmp, data;
1260689a570SEric Huang 	/* Set Override to disable Clock Gating */
1270689a570SEric Huang 	vce_v3_0_override_vce_clock_gating(adev, true);
1280689a570SEric Huang 
1290689a570SEric Huang 	if (!gated) {
1300689a570SEric Huang 		/* Force CLOCK ON for VCE_CLOCK_GATING_B,
1310689a570SEric Huang 		 * {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
1320689a570SEric Huang 		 * VREG can be FORCE ON or set to Dynamic, but can't be OFF
1330689a570SEric Huang 		 */
1340689a570SEric Huang 		tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
1350689a570SEric Huang 		data |= 0x1ff;
1360689a570SEric Huang 		data &= ~0xef0000;
1370689a570SEric Huang 		if (tmp != data)
1380689a570SEric Huang 			WREG32(mmVCE_CLOCK_GATING_B, data);
1390689a570SEric Huang 
1400689a570SEric Huang 		/* Force CLOCK ON for VCE_UENC_CLOCK_GATING,
1410689a570SEric Huang 		 * {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
1420689a570SEric Huang 		 */
1430689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
1440689a570SEric Huang 		data |= 0x3ff000;
1450689a570SEric Huang 		data &= ~0xffc00000;
1460689a570SEric Huang 		if (tmp != data)
1470689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING, data);
1480689a570SEric Huang 
1490689a570SEric Huang 		/* set VCE_UENC_CLOCK_GATING_2 */
1500689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
1510689a570SEric Huang 		data |= 0x2;
1520689a570SEric Huang 		data &= ~0x2;
1530689a570SEric Huang 		if (tmp != data)
1540689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
1550689a570SEric Huang 
1560689a570SEric Huang 		/* Force CLOCK ON for VCE_UENC_REG_CLOCK_GATING */
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 		/* Force VCE_UENC_DMA_DCLK_CTRL Clock ON */
1630689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
1640689a570SEric Huang 		data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
1650689a570SEric Huang 				VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
1660689a570SEric Huang 				VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
1670689a570SEric Huang 				0x8;
1680689a570SEric Huang 		if (tmp != data)
1690689a570SEric Huang 			WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
1700689a570SEric Huang 	} else {
1710689a570SEric Huang 		/* Force CLOCK OFF for VCE_CLOCK_GATING_B,
1720689a570SEric Huang 		 * {*, *_FORCE_OFF} = {*, 1}
1730689a570SEric Huang 		 * set VREG to Dynamic, as it can't be OFF
1740689a570SEric Huang 		 */
1750689a570SEric Huang 		tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
1760689a570SEric Huang 		data &= ~0x80010;
1770689a570SEric Huang 		data |= 0xe70008;
1780689a570SEric Huang 		if (tmp != data)
1790689a570SEric Huang 			WREG32(mmVCE_CLOCK_GATING_B, data);
1800689a570SEric Huang 		/* Force CLOCK OFF for VCE_UENC_CLOCK_GATING,
1810689a570SEric Huang 		 * Force ClOCK OFF takes precedent over Force CLOCK ON setting.
1820689a570SEric Huang 		 * {*_FORCE_ON, *_FORCE_OFF} = {*, 1}
1830689a570SEric Huang 		 */
1840689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
1850689a570SEric Huang 		data |= 0xffc00000;
1860689a570SEric Huang 		if (tmp != data)
1870689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING, data);
1880689a570SEric Huang 		/* Set VCE_UENC_CLOCK_GATING_2 */
1890689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
1900689a570SEric Huang 		data |= 0x10000;
1910689a570SEric Huang 		if (tmp != data)
1920689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
1930689a570SEric Huang 		/* Set VCE_UENC_REG_CLOCK_GATING to dynamic */
1940689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
1950689a570SEric Huang 		data &= ~0xffc00000;
1960689a570SEric Huang 		if (tmp != data)
1970689a570SEric Huang 			WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
1980689a570SEric Huang 		/* Set VCE_UENC_DMA_DCLK_CTRL CG always in dynamic mode */
1990689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
2000689a570SEric Huang 		data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
2010689a570SEric Huang 				VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
2020689a570SEric Huang 				VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
2030689a570SEric Huang 				0x8);
2040689a570SEric Huang 		if (tmp != data)
2050689a570SEric Huang 			WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
2060689a570SEric Huang 	}
2070689a570SEric Huang 	vce_v3_0_override_vce_clock_gating(adev, false);
2080689a570SEric Huang }
2090689a570SEric Huang 
210567e6e29Sjimqu static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev)
211567e6e29Sjimqu {
212567e6e29Sjimqu 	int i, j;
213567e6e29Sjimqu 	uint32_t status = 0;
214567e6e29Sjimqu 
215567e6e29Sjimqu 	for (i = 0; i < 10; ++i) {
216567e6e29Sjimqu 		for (j = 0; j < 100; ++j) {
217567e6e29Sjimqu 			status = RREG32(mmVCE_STATUS);
218567e6e29Sjimqu 			if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK)
219567e6e29Sjimqu 				return 0;
220567e6e29Sjimqu 			mdelay(10);
221567e6e29Sjimqu 		}
222567e6e29Sjimqu 
223567e6e29Sjimqu 		DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
224567e6e29Sjimqu 		WREG32_P(mmVCE_SOFT_RESET,
225567e6e29Sjimqu 			VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
226567e6e29Sjimqu 			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
227567e6e29Sjimqu 		mdelay(10);
228567e6e29Sjimqu 		WREG32_P(mmVCE_SOFT_RESET, 0,
229567e6e29Sjimqu 			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
230567e6e29Sjimqu 		mdelay(10);
231567e6e29Sjimqu 	}
232567e6e29Sjimqu 
233567e6e29Sjimqu 	return -ETIMEDOUT;
234567e6e29Sjimqu }
235567e6e29Sjimqu 
236aaa36a97SAlex Deucher /**
237aaa36a97SAlex Deucher  * vce_v3_0_start - start VCE block
238aaa36a97SAlex Deucher  *
239aaa36a97SAlex Deucher  * @adev: amdgpu_device pointer
240aaa36a97SAlex Deucher  *
241aaa36a97SAlex Deucher  * Setup and start the VCE block
242aaa36a97SAlex Deucher  */
243aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev)
244aaa36a97SAlex Deucher {
245aaa36a97SAlex Deucher 	struct amdgpu_ring *ring;
246567e6e29Sjimqu 	int idx, r;
247567e6e29Sjimqu 
248567e6e29Sjimqu 	ring = &adev->vce.ring[0];
249567e6e29Sjimqu 	WREG32(mmVCE_RB_RPTR, ring->wptr);
250567e6e29Sjimqu 	WREG32(mmVCE_RB_WPTR, ring->wptr);
251567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr);
252567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
253567e6e29Sjimqu 	WREG32(mmVCE_RB_SIZE, ring->ring_size / 4);
254567e6e29Sjimqu 
255567e6e29Sjimqu 	ring = &adev->vce.ring[1];
256567e6e29Sjimqu 	WREG32(mmVCE_RB_RPTR2, ring->wptr);
257567e6e29Sjimqu 	WREG32(mmVCE_RB_WPTR2, ring->wptr);
258567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr);
259567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
260567e6e29Sjimqu 	WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4);
261aaa36a97SAlex Deucher 
2625bbc553aSLeo Liu 	mutex_lock(&adev->grbm_idx_mutex);
2635bbc553aSLeo Liu 	for (idx = 0; idx < 2; ++idx) {
2646a585777SAlex Deucher 		if (adev->vce.harvest_config & (1 << idx))
2656a585777SAlex Deucher 			continue;
2666a585777SAlex Deucher 
2675bbc553aSLeo Liu 		if (idx == 0)
2685bbc553aSLeo Liu 			WREG32_P(mmGRBM_GFX_INDEX, 0,
2695bbc553aSLeo Liu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
2705bbc553aSLeo Liu 		else
2715bbc553aSLeo Liu 			WREG32_P(mmGRBM_GFX_INDEX,
2725bbc553aSLeo Liu 				GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
2735bbc553aSLeo Liu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
2745bbc553aSLeo Liu 
2755bbc553aSLeo Liu 		vce_v3_0_mc_resume(adev, idx);
276aaa36a97SAlex Deucher 
277567e6e29Sjimqu 		WREG32_P(mmVCE_STATUS, VCE_STATUS__JOB_BUSY_MASK,
278567e6e29Sjimqu 		         ~VCE_STATUS__JOB_BUSY_MASK);
279567e6e29Sjimqu 
2803c0ff9f1SLeo Liu 		if (adev->asic_type >= CHIP_STONEY)
2813c0ff9f1SLeo Liu 			WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001);
2823c0ff9f1SLeo Liu 		else
2835bbc553aSLeo Liu 			WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK,
2845bbc553aSLeo Liu 				~VCE_VCPU_CNTL__CLK_EN_MASK);
285aaa36a97SAlex Deucher 
286567e6e29Sjimqu 		WREG32_P(mmVCE_SOFT_RESET, 0,
287aaa36a97SAlex Deucher 			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
288aaa36a97SAlex Deucher 
289aaa36a97SAlex Deucher 		mdelay(100);
290aaa36a97SAlex Deucher 
291567e6e29Sjimqu 		r = vce_v3_0_firmware_loaded(adev);
292aaa36a97SAlex Deucher 
293aaa36a97SAlex Deucher 		/* clear BUSY flag */
294567e6e29Sjimqu 		WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK);
295aaa36a97SAlex Deucher 
2960689a570SEric Huang 		/* Set Clock-Gating off */
297e3b04bc7SAlex Deucher 		if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
2980689a570SEric Huang 			vce_v3_0_set_vce_sw_clock_gating(adev, false);
2990689a570SEric Huang 
300aaa36a97SAlex Deucher 		if (r) {
301aaa36a97SAlex Deucher 			DRM_ERROR("VCE not responding, giving up!!!\n");
3025bbc553aSLeo Liu 			mutex_unlock(&adev->grbm_idx_mutex);
303aaa36a97SAlex Deucher 			return r;
304aaa36a97SAlex Deucher 		}
3055bbc553aSLeo Liu 	}
3065bbc553aSLeo Liu 
3075bbc553aSLeo Liu 	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
3085bbc553aSLeo Liu 	mutex_unlock(&adev->grbm_idx_mutex);
3095bbc553aSLeo Liu 
310567e6e29Sjimqu 	return 0;
311567e6e29Sjimqu }
3125bbc553aSLeo Liu 
313567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev)
314567e6e29Sjimqu {
315567e6e29Sjimqu 	int idx;
316567e6e29Sjimqu 
317567e6e29Sjimqu 	mutex_lock(&adev->grbm_idx_mutex);
318567e6e29Sjimqu 	for (idx = 0; idx < 2; ++idx) {
319567e6e29Sjimqu 		if (adev->vce.harvest_config & (1 << idx))
320567e6e29Sjimqu 			continue;
321567e6e29Sjimqu 
322567e6e29Sjimqu 		if (idx == 0)
323567e6e29Sjimqu 			WREG32_P(mmGRBM_GFX_INDEX, 0,
324567e6e29Sjimqu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
325567e6e29Sjimqu 		else
326567e6e29Sjimqu 			WREG32_P(mmGRBM_GFX_INDEX,
327567e6e29Sjimqu 				GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
328567e6e29Sjimqu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
329567e6e29Sjimqu 
330567e6e29Sjimqu 		if (adev->asic_type >= CHIP_STONEY)
331567e6e29Sjimqu 			WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001);
332567e6e29Sjimqu 		else
333567e6e29Sjimqu 			WREG32_P(mmVCE_VCPU_CNTL, 0,
334567e6e29Sjimqu 				~VCE_VCPU_CNTL__CLK_EN_MASK);
335567e6e29Sjimqu 		/* hold on ECPU */
336567e6e29Sjimqu 		WREG32_P(mmVCE_SOFT_RESET,
337567e6e29Sjimqu 			 VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
338567e6e29Sjimqu 			 ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
339567e6e29Sjimqu 
340567e6e29Sjimqu 		/* clear BUSY flag */
341567e6e29Sjimqu 		WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK);
342567e6e29Sjimqu 
343567e6e29Sjimqu 		/* Set Clock-Gating off */
344567e6e29Sjimqu 		if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
345567e6e29Sjimqu 			vce_v3_0_set_vce_sw_clock_gating(adev, false);
346567e6e29Sjimqu 	}
347567e6e29Sjimqu 
348567e6e29Sjimqu 	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
349567e6e29Sjimqu 	mutex_unlock(&adev->grbm_idx_mutex);
350aaa36a97SAlex Deucher 
351aaa36a97SAlex Deucher 	return 0;
352aaa36a97SAlex Deucher }
353aaa36a97SAlex Deucher 
3546a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS     0xC0014074
3556a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT       27
3566a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK        0x18000000
3576a585777SAlex Deucher 
3586a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
3596a585777SAlex Deucher {
3606a585777SAlex Deucher 	u32 tmp;
3616a585777SAlex Deucher 
3622cc0c0b5SFlora Cui 	/* Fiji, Stoney, Polaris10, Polaris11 are single pipe */
363cfaba566SSamuel Li 	if ((adev->asic_type == CHIP_FIJI) ||
3641b4eeea5SSonny Jiang 	    (adev->asic_type == CHIP_STONEY) ||
3652cc0c0b5SFlora Cui 	    (adev->asic_type == CHIP_POLARIS10) ||
3662cc0c0b5SFlora Cui 	    (adev->asic_type == CHIP_POLARIS11))
3671dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
368188a9bcdSAlex Deucher 
369188a9bcdSAlex Deucher 	/* Tonga and CZ are dual or single pipe */
3702f7d10b3SJammy Zhou 	if (adev->flags & AMD_IS_APU)
3716a585777SAlex Deucher 		tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) &
3726a585777SAlex Deucher 		       VCE_HARVEST_FUSE_MACRO__MASK) >>
3736a585777SAlex Deucher 			VCE_HARVEST_FUSE_MACRO__SHIFT;
3746a585777SAlex Deucher 	else
3756a585777SAlex Deucher 		tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) &
3766a585777SAlex Deucher 		       CC_HARVEST_FUSES__VCE_DISABLE_MASK) >>
3776a585777SAlex Deucher 			CC_HARVEST_FUSES__VCE_DISABLE__SHIFT;
3786a585777SAlex Deucher 
3796a585777SAlex Deucher 	switch (tmp) {
3806a585777SAlex Deucher 	case 1:
3811dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0;
3826a585777SAlex Deucher 	case 2:
3831dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
3846a585777SAlex Deucher 	case 3:
3851dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1;
3866a585777SAlex Deucher 	default:
3871dab5f06STom St Denis 		return 0;
3886a585777SAlex Deucher 	}
3896a585777SAlex Deucher }
3906a585777SAlex Deucher 
3915fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle)
392aaa36a97SAlex Deucher {
3935fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
3945fc3aeebSyanyang1 
3956a585777SAlex Deucher 	adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev);
3966a585777SAlex Deucher 
3976a585777SAlex Deucher 	if ((adev->vce.harvest_config &
3986a585777SAlex Deucher 	     (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) ==
3996a585777SAlex Deucher 	    (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1))
4006a585777SAlex Deucher 		return -ENOENT;
4016a585777SAlex Deucher 
402aaa36a97SAlex Deucher 	vce_v3_0_set_ring_funcs(adev);
403aaa36a97SAlex Deucher 	vce_v3_0_set_irq_funcs(adev);
404aaa36a97SAlex Deucher 
405aaa36a97SAlex Deucher 	return 0;
406aaa36a97SAlex Deucher }
407aaa36a97SAlex Deucher 
4085fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle)
409aaa36a97SAlex Deucher {
4105fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
411aaa36a97SAlex Deucher 	struct amdgpu_ring *ring;
412aaa36a97SAlex Deucher 	int r;
413aaa36a97SAlex Deucher 
414aaa36a97SAlex Deucher 	/* VCE */
415aaa36a97SAlex Deucher 	r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq);
416aaa36a97SAlex Deucher 	if (r)
417aaa36a97SAlex Deucher 		return r;
418aaa36a97SAlex Deucher 
419e9822622SLeo Liu 	r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE +
420e9822622SLeo Liu 		(VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2);
421aaa36a97SAlex Deucher 	if (r)
422aaa36a97SAlex Deucher 		return r;
423aaa36a97SAlex Deucher 
424aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
425aaa36a97SAlex Deucher 	if (r)
426aaa36a97SAlex Deucher 		return r;
427aaa36a97SAlex Deucher 
428aaa36a97SAlex Deucher 	ring = &adev->vce.ring[0];
429aaa36a97SAlex Deucher 	sprintf(ring->name, "vce0");
430a3f1cf35SChristian König 	r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
431aaa36a97SAlex Deucher 			     &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
432aaa36a97SAlex Deucher 	if (r)
433aaa36a97SAlex Deucher 		return r;
434aaa36a97SAlex Deucher 
435aaa36a97SAlex Deucher 	ring = &adev->vce.ring[1];
436aaa36a97SAlex Deucher 	sprintf(ring->name, "vce1");
437a3f1cf35SChristian König 	r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
438aaa36a97SAlex Deucher 			     &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
439aaa36a97SAlex Deucher 	if (r)
440aaa36a97SAlex Deucher 		return r;
441aaa36a97SAlex Deucher 
442aaa36a97SAlex Deucher 	return r;
443aaa36a97SAlex Deucher }
444aaa36a97SAlex Deucher 
4455fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle)
446aaa36a97SAlex Deucher {
447aaa36a97SAlex Deucher 	int r;
4485fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
449aaa36a97SAlex Deucher 
450aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
451aaa36a97SAlex Deucher 	if (r)
452aaa36a97SAlex Deucher 		return r;
453aaa36a97SAlex Deucher 
454aaa36a97SAlex Deucher 	r = amdgpu_vce_sw_fini(adev);
455aaa36a97SAlex Deucher 	if (r)
456aaa36a97SAlex Deucher 		return r;
457aaa36a97SAlex Deucher 
458aaa36a97SAlex Deucher 	return r;
459aaa36a97SAlex Deucher }
460aaa36a97SAlex Deucher 
4615fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle)
462aaa36a97SAlex Deucher {
463691ca86aSTom St Denis 	int r, i;
4645fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
465aaa36a97SAlex Deucher 
466aaa36a97SAlex Deucher 	r = vce_v3_0_start(adev);
467aaa36a97SAlex Deucher 	if (r)
468aaa36a97SAlex Deucher 		return r;
469aaa36a97SAlex Deucher 
470691ca86aSTom St Denis 	adev->vce.ring[0].ready = false;
471691ca86aSTom St Denis 	adev->vce.ring[1].ready = false;
472aaa36a97SAlex Deucher 
473691ca86aSTom St Denis 	for (i = 0; i < 2; i++) {
474691ca86aSTom St Denis 		r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
475691ca86aSTom St Denis 		if (r)
476aaa36a97SAlex Deucher 			return r;
477691ca86aSTom St Denis 		else
478691ca86aSTom St Denis 			adev->vce.ring[i].ready = true;
479aaa36a97SAlex Deucher 	}
480aaa36a97SAlex Deucher 
481aaa36a97SAlex Deucher 	DRM_INFO("VCE initialized successfully.\n");
482aaa36a97SAlex Deucher 
483aaa36a97SAlex Deucher 	return 0;
484aaa36a97SAlex Deucher }
485aaa36a97SAlex Deucher 
4865fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle)
487aaa36a97SAlex Deucher {
488567e6e29Sjimqu 	int r;
489567e6e29Sjimqu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
490567e6e29Sjimqu 
491567e6e29Sjimqu 	r = vce_v3_0_wait_for_idle(handle);
492567e6e29Sjimqu 	if (r)
493567e6e29Sjimqu 		return r;
494567e6e29Sjimqu 
495567e6e29Sjimqu 	return vce_v3_0_stop(adev);
496aaa36a97SAlex Deucher }
497aaa36a97SAlex Deucher 
4985fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle)
499aaa36a97SAlex Deucher {
500aaa36a97SAlex Deucher 	int r;
5015fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
502aaa36a97SAlex Deucher 
503aaa36a97SAlex Deucher 	r = vce_v3_0_hw_fini(adev);
504aaa36a97SAlex Deucher 	if (r)
505aaa36a97SAlex Deucher 		return r;
506aaa36a97SAlex Deucher 
507aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
508aaa36a97SAlex Deucher 	if (r)
509aaa36a97SAlex Deucher 		return r;
510aaa36a97SAlex Deucher 
511aaa36a97SAlex Deucher 	return r;
512aaa36a97SAlex Deucher }
513aaa36a97SAlex Deucher 
5145fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle)
515aaa36a97SAlex Deucher {
516aaa36a97SAlex Deucher 	int r;
5175fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
518aaa36a97SAlex Deucher 
519aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
520aaa36a97SAlex Deucher 	if (r)
521aaa36a97SAlex Deucher 		return r;
522aaa36a97SAlex Deucher 
523aaa36a97SAlex Deucher 	r = vce_v3_0_hw_init(adev);
524aaa36a97SAlex Deucher 	if (r)
525aaa36a97SAlex Deucher 		return r;
526aaa36a97SAlex Deucher 
527aaa36a97SAlex Deucher 	return r;
528aaa36a97SAlex Deucher }
529aaa36a97SAlex Deucher 
5305bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx)
531aaa36a97SAlex Deucher {
532aaa36a97SAlex Deucher 	uint32_t offset, size;
533aaa36a97SAlex Deucher 
534aaa36a97SAlex Deucher 	WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16));
535aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000);
536aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F);
537aaa36a97SAlex Deucher 	WREG32(mmVCE_CLOCK_GATING_B, 0xf7);
538aaa36a97SAlex Deucher 
539aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_CTRL, 0x00398000);
540aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1);
541aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL, 0);
542aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL1, 0);
543aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_VM_CTRL, 0);
5443c0ff9f1SLeo Liu 	if (adev->asic_type >= CHIP_STONEY) {
5453c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8));
5463c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8));
5473c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8));
5483c0ff9f1SLeo Liu 	} else
549aaa36a97SAlex Deucher 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
550aaa36a97SAlex Deucher 	offset = AMDGPU_VCE_FIRMWARE_OFFSET;
551e9822622SLeo Liu 	size = VCE_V3_0_FW_SIZE;
552aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
553aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_SIZE0, size);
554aaa36a97SAlex Deucher 
5555bbc553aSLeo Liu 	if (idx == 0) {
556aaa36a97SAlex Deucher 		offset += size;
557e9822622SLeo Liu 		size = VCE_V3_0_STACK_SIZE;
558aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff);
559aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
560aaa36a97SAlex Deucher 		offset += size;
561e9822622SLeo Liu 		size = VCE_V3_0_DATA_SIZE;
562aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff);
563aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5645bbc553aSLeo Liu 	} else {
5655bbc553aSLeo Liu 		offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE;
5665bbc553aSLeo Liu 		size = VCE_V3_0_STACK_SIZE;
5675bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff);
5685bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
5695bbc553aSLeo Liu 		offset += size;
5705bbc553aSLeo Liu 		size = VCE_V3_0_DATA_SIZE;
5715bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff);
5725bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5735bbc553aSLeo Liu 	}
574aaa36a97SAlex Deucher 
575aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100);
576aaa36a97SAlex Deucher 
577aaa36a97SAlex Deucher 	WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK,
578aaa36a97SAlex Deucher 		 ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
579aaa36a97SAlex Deucher }
580aaa36a97SAlex Deucher 
5815fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle)
582aaa36a97SAlex Deucher {
5835fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
584be4f38e2SAlex Deucher 	u32 mask = 0;
5855fc3aeebSyanyang1 
58674af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK;
58774af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK;
588be4f38e2SAlex Deucher 
589be4f38e2SAlex Deucher 	return !(RREG32(mmSRBM_STATUS2) & mask);
590aaa36a97SAlex Deucher }
591aaa36a97SAlex Deucher 
5925fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle)
593aaa36a97SAlex Deucher {
594aaa36a97SAlex Deucher 	unsigned i;
5955fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
596be4f38e2SAlex Deucher 
59792988e60STom St Denis 	for (i = 0; i < adev->usec_timeout; i++)
59892988e60STom St Denis 		if (vce_v3_0_is_idle(handle))
599aaa36a97SAlex Deucher 			return 0;
60092988e60STom St Denis 
601aaa36a97SAlex Deucher 	return -ETIMEDOUT;
602aaa36a97SAlex Deucher }
603aaa36a97SAlex Deucher 
6045fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle)
605aaa36a97SAlex Deucher {
6065fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
607be4f38e2SAlex Deucher 	u32 mask = 0;
6085fc3aeebSyanyang1 
60974af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK;
61074af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK;
611be4f38e2SAlex Deucher 
612be4f38e2SAlex Deucher 	WREG32_P(mmSRBM_SOFT_RESET, mask,
613be4f38e2SAlex Deucher 		 ~(SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK |
614be4f38e2SAlex Deucher 		   SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK));
615aaa36a97SAlex Deucher 	mdelay(5);
616aaa36a97SAlex Deucher 
617aaa36a97SAlex Deucher 	return vce_v3_0_start(adev);
618aaa36a97SAlex Deucher }
619aaa36a97SAlex Deucher 
620aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev,
621aaa36a97SAlex Deucher 					struct amdgpu_irq_src *source,
622aaa36a97SAlex Deucher 					unsigned type,
623aaa36a97SAlex Deucher 					enum amdgpu_interrupt_state state)
624aaa36a97SAlex Deucher {
625aaa36a97SAlex Deucher 	uint32_t val = 0;
626aaa36a97SAlex Deucher 
627aaa36a97SAlex Deucher 	if (state == AMDGPU_IRQ_STATE_ENABLE)
628aaa36a97SAlex Deucher 		val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK;
629aaa36a97SAlex Deucher 
630aaa36a97SAlex Deucher 	WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
631aaa36a97SAlex Deucher 	return 0;
632aaa36a97SAlex Deucher }
633aaa36a97SAlex Deucher 
634aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
635aaa36a97SAlex Deucher 				      struct amdgpu_irq_src *source,
636aaa36a97SAlex Deucher 				      struct amdgpu_iv_entry *entry)
637aaa36a97SAlex Deucher {
638aaa36a97SAlex Deucher 	DRM_DEBUG("IH: VCE\n");
639d6c29c30SLeo Liu 
640d6c29c30SLeo Liu 	WREG32_P(mmVCE_SYS_INT_STATUS,
641d6c29c30SLeo Liu 		VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK,
642d6c29c30SLeo Liu 		~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK);
643d6c29c30SLeo Liu 
644aaa36a97SAlex Deucher 	switch (entry->src_data) {
645aaa36a97SAlex Deucher 	case 0:
646aaa36a97SAlex Deucher 	case 1:
64781da2edeSTom St Denis 		amdgpu_fence_process(&adev->vce.ring[entry->src_data]);
648aaa36a97SAlex Deucher 		break;
649aaa36a97SAlex Deucher 	default:
650aaa36a97SAlex Deucher 		DRM_ERROR("Unhandled interrupt: %d %d\n",
651aaa36a97SAlex Deucher 			  entry->src_id, entry->src_data);
652aaa36a97SAlex Deucher 		break;
653aaa36a97SAlex Deucher 	}
654aaa36a97SAlex Deucher 
655aaa36a97SAlex Deucher 	return 0;
656aaa36a97SAlex Deucher }
657aaa36a97SAlex Deucher 
6585fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle,
6595fc3aeebSyanyang1 					  enum amd_clockgating_state state)
660aaa36a97SAlex Deucher {
6610689a570SEric Huang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
6620689a570SEric Huang 	bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
6630689a570SEric Huang 	int i;
6640689a570SEric Huang 
665e3b04bc7SAlex Deucher 	if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG))
6660689a570SEric Huang 		return 0;
6670689a570SEric Huang 
6680689a570SEric Huang 	mutex_lock(&adev->grbm_idx_mutex);
6690689a570SEric Huang 	for (i = 0; i < 2; i++) {
6700689a570SEric Huang 		/* Program VCE Instance 0 or 1 if not harvested */
6710689a570SEric Huang 		if (adev->vce.harvest_config & (1 << i))
6720689a570SEric Huang 			continue;
6730689a570SEric Huang 
6740689a570SEric Huang 		if (i == 0)
6750689a570SEric Huang 			WREG32_P(mmGRBM_GFX_INDEX, 0,
6760689a570SEric Huang 					~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
6770689a570SEric Huang 		else
6780689a570SEric Huang 			WREG32_P(mmGRBM_GFX_INDEX,
6790689a570SEric Huang 					GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
6800689a570SEric Huang 					~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
6810689a570SEric Huang 
6820689a570SEric Huang 		if (enable) {
6830689a570SEric Huang 			/* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
6840689a570SEric Huang 			uint32_t data = RREG32(mmVCE_CLOCK_GATING_A);
6850689a570SEric Huang 			data &= ~(0xf | 0xff0);
6860689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
6870689a570SEric Huang 			WREG32(mmVCE_CLOCK_GATING_A, data);
6880689a570SEric Huang 
6890689a570SEric Huang 			/* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */
6900689a570SEric Huang 			data = RREG32(mmVCE_UENC_CLOCK_GATING);
6910689a570SEric Huang 			data &= ~(0xf | 0xff0);
6920689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
6930689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING, data);
6940689a570SEric Huang 		}
6950689a570SEric Huang 
6960689a570SEric Huang 		vce_v3_0_set_vce_sw_clock_gating(adev, enable);
6970689a570SEric Huang 	}
6980689a570SEric Huang 
6990689a570SEric Huang 	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
7000689a570SEric Huang 	mutex_unlock(&adev->grbm_idx_mutex);
7010689a570SEric Huang 
702aaa36a97SAlex Deucher 	return 0;
703aaa36a97SAlex Deucher }
704aaa36a97SAlex Deucher 
7055fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle,
7065fc3aeebSyanyang1 					  enum amd_powergating_state state)
707aaa36a97SAlex Deucher {
708aaa36a97SAlex Deucher 	/* This doesn't actually powergate the VCE block.
709aaa36a97SAlex Deucher 	 * That's done in the dpm code via the SMC.  This
710aaa36a97SAlex Deucher 	 * just re-inits the block as necessary.  The actual
711aaa36a97SAlex Deucher 	 * gating still happens in the dpm code.  We should
712aaa36a97SAlex Deucher 	 * revisit this when there is a cleaner line between
713aaa36a97SAlex Deucher 	 * the smc and the hw blocks
714aaa36a97SAlex Deucher 	 */
7155fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
7165fc3aeebSyanyang1 
717e3b04bc7SAlex Deucher 	if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE))
718808a934fSAlex Deucher 		return 0;
719808a934fSAlex Deucher 
7205fc3aeebSyanyang1 	if (state == AMD_PG_STATE_GATE)
721aaa36a97SAlex Deucher 		/* XXX do we need a vce_v3_0_stop()? */
722aaa36a97SAlex Deucher 		return 0;
723aaa36a97SAlex Deucher 	else
724aaa36a97SAlex Deucher 		return vce_v3_0_start(adev);
725aaa36a97SAlex Deucher }
726aaa36a97SAlex Deucher 
7275fc3aeebSyanyang1 const struct amd_ip_funcs vce_v3_0_ip_funcs = {
72888a907d6STom St Denis 	.name = "vce_v3_0",
729aaa36a97SAlex Deucher 	.early_init = vce_v3_0_early_init,
730aaa36a97SAlex Deucher 	.late_init = NULL,
731aaa36a97SAlex Deucher 	.sw_init = vce_v3_0_sw_init,
732aaa36a97SAlex Deucher 	.sw_fini = vce_v3_0_sw_fini,
733aaa36a97SAlex Deucher 	.hw_init = vce_v3_0_hw_init,
734aaa36a97SAlex Deucher 	.hw_fini = vce_v3_0_hw_fini,
735aaa36a97SAlex Deucher 	.suspend = vce_v3_0_suspend,
736aaa36a97SAlex Deucher 	.resume = vce_v3_0_resume,
737aaa36a97SAlex Deucher 	.is_idle = vce_v3_0_is_idle,
738aaa36a97SAlex Deucher 	.wait_for_idle = vce_v3_0_wait_for_idle,
739aaa36a97SAlex Deucher 	.soft_reset = vce_v3_0_soft_reset,
740aaa36a97SAlex Deucher 	.set_clockgating_state = vce_v3_0_set_clockgating_state,
741aaa36a97SAlex Deucher 	.set_powergating_state = vce_v3_0_set_powergating_state,
742aaa36a97SAlex Deucher };
743aaa36a97SAlex Deucher 
744aaa36a97SAlex Deucher static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = {
745aaa36a97SAlex Deucher 	.get_rptr = vce_v3_0_ring_get_rptr,
746aaa36a97SAlex Deucher 	.get_wptr = vce_v3_0_ring_get_wptr,
747aaa36a97SAlex Deucher 	.set_wptr = vce_v3_0_ring_set_wptr,
748aaa36a97SAlex Deucher 	.parse_cs = amdgpu_vce_ring_parse_cs,
749aaa36a97SAlex Deucher 	.emit_ib = amdgpu_vce_ring_emit_ib,
750aaa36a97SAlex Deucher 	.emit_fence = amdgpu_vce_ring_emit_fence,
751aaa36a97SAlex Deucher 	.test_ring = amdgpu_vce_ring_test_ring,
752aaa36a97SAlex Deucher 	.test_ib = amdgpu_vce_ring_test_ib,
753edff0e28SJammy Zhou 	.insert_nop = amdgpu_ring_insert_nop,
7549e5d5309SChristian König 	.pad_ib = amdgpu_ring_generic_pad_ib,
755aaa36a97SAlex Deucher };
756aaa36a97SAlex Deucher 
757aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev)
758aaa36a97SAlex Deucher {
759aaa36a97SAlex Deucher 	adev->vce.ring[0].funcs = &vce_v3_0_ring_funcs;
760aaa36a97SAlex Deucher 	adev->vce.ring[1].funcs = &vce_v3_0_ring_funcs;
761aaa36a97SAlex Deucher }
762aaa36a97SAlex Deucher 
763aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = {
764aaa36a97SAlex Deucher 	.set = vce_v3_0_set_interrupt_state,
765aaa36a97SAlex Deucher 	.process = vce_v3_0_process_interrupt,
766aaa36a97SAlex Deucher };
767aaa36a97SAlex Deucher 
768aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev)
769aaa36a97SAlex Deucher {
770aaa36a97SAlex Deucher 	adev->vce.irq.num_types = 1;
771aaa36a97SAlex Deucher 	adev->vce.irq.funcs = &vce_v3_0_irq_funcs;
772aaa36a97SAlex Deucher };
773