xref: /openbmc/linux/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c (revision ac8e3f30)
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