xref: /openbmc/linux/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c (revision 6f906814)
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 
2880689a570SEric Huang 		/* Set Clock-Gating off */
289e3b04bc7SAlex Deucher 		if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
2900689a570SEric Huang 			vce_v3_0_set_vce_sw_clock_gating(adev, false);
2910689a570SEric Huang 
292aaa36a97SAlex Deucher 		if (r) {
293aaa36a97SAlex Deucher 			DRM_ERROR("VCE not responding, giving up!!!\n");
2945bbc553aSLeo Liu 			mutex_unlock(&adev->grbm_idx_mutex);
295aaa36a97SAlex Deucher 			return r;
296aaa36a97SAlex Deucher 		}
2975bbc553aSLeo Liu 	}
2985bbc553aSLeo Liu 
2995bbc553aSLeo Liu 	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
3005bbc553aSLeo Liu 	mutex_unlock(&adev->grbm_idx_mutex);
3015bbc553aSLeo Liu 
302567e6e29Sjimqu 	return 0;
303567e6e29Sjimqu }
3045bbc553aSLeo Liu 
305567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev)
306567e6e29Sjimqu {
307567e6e29Sjimqu 	int idx;
308567e6e29Sjimqu 
309567e6e29Sjimqu 	mutex_lock(&adev->grbm_idx_mutex);
310567e6e29Sjimqu 	for (idx = 0; idx < 2; ++idx) {
311567e6e29Sjimqu 		if (adev->vce.harvest_config & (1 << idx))
312567e6e29Sjimqu 			continue;
313567e6e29Sjimqu 
314567e6e29Sjimqu 		if (idx == 0)
315567e6e29Sjimqu 			WREG32_P(mmGRBM_GFX_INDEX, 0,
316567e6e29Sjimqu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
317567e6e29Sjimqu 		else
318567e6e29Sjimqu 			WREG32_P(mmGRBM_GFX_INDEX,
319567e6e29Sjimqu 				GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
320567e6e29Sjimqu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
321567e6e29Sjimqu 
322567e6e29Sjimqu 		if (adev->asic_type >= CHIP_STONEY)
323567e6e29Sjimqu 			WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001);
324567e6e29Sjimqu 		else
325567e6e29Sjimqu 			WREG32_P(mmVCE_VCPU_CNTL, 0,
326567e6e29Sjimqu 				~VCE_VCPU_CNTL__CLK_EN_MASK);
327567e6e29Sjimqu 		/* hold on ECPU */
328567e6e29Sjimqu 		WREG32_P(mmVCE_SOFT_RESET,
329567e6e29Sjimqu 			 VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
330567e6e29Sjimqu 			 ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
331567e6e29Sjimqu 
332567e6e29Sjimqu 		/* clear BUSY flag */
333567e6e29Sjimqu 		WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK);
334567e6e29Sjimqu 
335567e6e29Sjimqu 		/* Set Clock-Gating off */
336567e6e29Sjimqu 		if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
337567e6e29Sjimqu 			vce_v3_0_set_vce_sw_clock_gating(adev, false);
338567e6e29Sjimqu 	}
339567e6e29Sjimqu 
340567e6e29Sjimqu 	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
341567e6e29Sjimqu 	mutex_unlock(&adev->grbm_idx_mutex);
342aaa36a97SAlex Deucher 
343aaa36a97SAlex Deucher 	return 0;
344aaa36a97SAlex Deucher }
345aaa36a97SAlex Deucher 
3466a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS     0xC0014074
3476a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT       27
3486a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK        0x18000000
3496a585777SAlex Deucher 
3506a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
3516a585777SAlex Deucher {
3526a585777SAlex Deucher 	u32 tmp;
3536a585777SAlex Deucher 
3542cc0c0b5SFlora Cui 	/* Fiji, Stoney, Polaris10, Polaris11 are single pipe */
355cfaba566SSamuel Li 	if ((adev->asic_type == CHIP_FIJI) ||
3561b4eeea5SSonny Jiang 	    (adev->asic_type == CHIP_STONEY) ||
3572cc0c0b5SFlora Cui 	    (adev->asic_type == CHIP_POLARIS10) ||
3582cc0c0b5SFlora Cui 	    (adev->asic_type == CHIP_POLARIS11))
3591dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
360188a9bcdSAlex Deucher 
361188a9bcdSAlex Deucher 	/* Tonga and CZ are dual or single pipe */
3622f7d10b3SJammy Zhou 	if (adev->flags & AMD_IS_APU)
3636a585777SAlex Deucher 		tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) &
3646a585777SAlex Deucher 		       VCE_HARVEST_FUSE_MACRO__MASK) >>
3656a585777SAlex Deucher 			VCE_HARVEST_FUSE_MACRO__SHIFT;
3666a585777SAlex Deucher 	else
3676a585777SAlex Deucher 		tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) &
3686a585777SAlex Deucher 		       CC_HARVEST_FUSES__VCE_DISABLE_MASK) >>
3696a585777SAlex Deucher 			CC_HARVEST_FUSES__VCE_DISABLE__SHIFT;
3706a585777SAlex Deucher 
3716a585777SAlex Deucher 	switch (tmp) {
3726a585777SAlex Deucher 	case 1:
3731dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0;
3746a585777SAlex Deucher 	case 2:
3751dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
3766a585777SAlex Deucher 	case 3:
3771dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1;
3786a585777SAlex Deucher 	default:
3791dab5f06STom St Denis 		return 0;
3806a585777SAlex Deucher 	}
3816a585777SAlex Deucher }
3826a585777SAlex Deucher 
3835fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle)
384aaa36a97SAlex Deucher {
3855fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
3865fc3aeebSyanyang1 
3876a585777SAlex Deucher 	adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev);
3886a585777SAlex Deucher 
3896a585777SAlex Deucher 	if ((adev->vce.harvest_config &
3906a585777SAlex Deucher 	     (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) ==
3916a585777SAlex Deucher 	    (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1))
3926a585777SAlex Deucher 		return -ENOENT;
3936a585777SAlex Deucher 
394aaa36a97SAlex Deucher 	vce_v3_0_set_ring_funcs(adev);
395aaa36a97SAlex Deucher 	vce_v3_0_set_irq_funcs(adev);
396aaa36a97SAlex Deucher 
397aaa36a97SAlex Deucher 	return 0;
398aaa36a97SAlex Deucher }
399aaa36a97SAlex Deucher 
4005fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle)
401aaa36a97SAlex Deucher {
4025fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
403aaa36a97SAlex Deucher 	struct amdgpu_ring *ring;
404aaa36a97SAlex Deucher 	int r;
405aaa36a97SAlex Deucher 
406aaa36a97SAlex Deucher 	/* VCE */
407aaa36a97SAlex Deucher 	r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq);
408aaa36a97SAlex Deucher 	if (r)
409aaa36a97SAlex Deucher 		return r;
410aaa36a97SAlex Deucher 
411e9822622SLeo Liu 	r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE +
412e9822622SLeo Liu 		(VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2);
413aaa36a97SAlex Deucher 	if (r)
414aaa36a97SAlex Deucher 		return r;
415aaa36a97SAlex Deucher 
416aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
417aaa36a97SAlex Deucher 	if (r)
418aaa36a97SAlex Deucher 		return r;
419aaa36a97SAlex Deucher 
420aaa36a97SAlex Deucher 	ring = &adev->vce.ring[0];
421aaa36a97SAlex Deucher 	sprintf(ring->name, "vce0");
422a3f1cf35SChristian König 	r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
423aaa36a97SAlex Deucher 			     &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
424aaa36a97SAlex Deucher 	if (r)
425aaa36a97SAlex Deucher 		return r;
426aaa36a97SAlex Deucher 
427aaa36a97SAlex Deucher 	ring = &adev->vce.ring[1];
428aaa36a97SAlex Deucher 	sprintf(ring->name, "vce1");
429a3f1cf35SChristian König 	r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
430aaa36a97SAlex Deucher 			     &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
431aaa36a97SAlex Deucher 	if (r)
432aaa36a97SAlex Deucher 		return r;
433aaa36a97SAlex Deucher 
434aaa36a97SAlex Deucher 	return r;
435aaa36a97SAlex Deucher }
436aaa36a97SAlex Deucher 
4375fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle)
438aaa36a97SAlex Deucher {
439aaa36a97SAlex Deucher 	int r;
4405fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
441aaa36a97SAlex Deucher 
442aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
443aaa36a97SAlex Deucher 	if (r)
444aaa36a97SAlex Deucher 		return r;
445aaa36a97SAlex Deucher 
446aaa36a97SAlex Deucher 	r = amdgpu_vce_sw_fini(adev);
447aaa36a97SAlex Deucher 	if (r)
448aaa36a97SAlex Deucher 		return r;
449aaa36a97SAlex Deucher 
450aaa36a97SAlex Deucher 	return r;
451aaa36a97SAlex Deucher }
452aaa36a97SAlex Deucher 
4535fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle)
454aaa36a97SAlex Deucher {
455691ca86aSTom St Denis 	int r, i;
4565fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
457aaa36a97SAlex Deucher 
458aaa36a97SAlex Deucher 	r = vce_v3_0_start(adev);
459aaa36a97SAlex Deucher 	if (r)
460aaa36a97SAlex Deucher 		return r;
461aaa36a97SAlex Deucher 
462691ca86aSTom St Denis 	adev->vce.ring[0].ready = false;
463691ca86aSTom St Denis 	adev->vce.ring[1].ready = false;
464aaa36a97SAlex Deucher 
465691ca86aSTom St Denis 	for (i = 0; i < 2; i++) {
466691ca86aSTom St Denis 		r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
467691ca86aSTom St Denis 		if (r)
468aaa36a97SAlex Deucher 			return r;
469691ca86aSTom St Denis 		else
470691ca86aSTom St Denis 			adev->vce.ring[i].ready = true;
471aaa36a97SAlex Deucher 	}
472aaa36a97SAlex Deucher 
473aaa36a97SAlex Deucher 	DRM_INFO("VCE initialized successfully.\n");
474aaa36a97SAlex Deucher 
475aaa36a97SAlex Deucher 	return 0;
476aaa36a97SAlex Deucher }
477aaa36a97SAlex Deucher 
4785fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle)
479aaa36a97SAlex Deucher {
480567e6e29Sjimqu 	int r;
481567e6e29Sjimqu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
482567e6e29Sjimqu 
483567e6e29Sjimqu 	r = vce_v3_0_wait_for_idle(handle);
484567e6e29Sjimqu 	if (r)
485567e6e29Sjimqu 		return r;
486567e6e29Sjimqu 
487567e6e29Sjimqu 	return vce_v3_0_stop(adev);
488aaa36a97SAlex Deucher }
489aaa36a97SAlex Deucher 
4905fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle)
491aaa36a97SAlex Deucher {
492aaa36a97SAlex Deucher 	int r;
4935fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
494aaa36a97SAlex Deucher 
495aaa36a97SAlex Deucher 	r = vce_v3_0_hw_fini(adev);
496aaa36a97SAlex Deucher 	if (r)
497aaa36a97SAlex Deucher 		return r;
498aaa36a97SAlex Deucher 
499aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
500aaa36a97SAlex Deucher 	if (r)
501aaa36a97SAlex Deucher 		return r;
502aaa36a97SAlex Deucher 
503aaa36a97SAlex Deucher 	return r;
504aaa36a97SAlex Deucher }
505aaa36a97SAlex Deucher 
5065fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle)
507aaa36a97SAlex Deucher {
508aaa36a97SAlex Deucher 	int r;
5095fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
510aaa36a97SAlex Deucher 
511aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
512aaa36a97SAlex Deucher 	if (r)
513aaa36a97SAlex Deucher 		return r;
514aaa36a97SAlex Deucher 
515aaa36a97SAlex Deucher 	r = vce_v3_0_hw_init(adev);
516aaa36a97SAlex Deucher 	if (r)
517aaa36a97SAlex Deucher 		return r;
518aaa36a97SAlex Deucher 
519aaa36a97SAlex Deucher 	return r;
520aaa36a97SAlex Deucher }
521aaa36a97SAlex Deucher 
5225bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx)
523aaa36a97SAlex Deucher {
524aaa36a97SAlex Deucher 	uint32_t offset, size;
525aaa36a97SAlex Deucher 
526aaa36a97SAlex Deucher 	WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16));
527aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000);
528aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F);
5296f906814STom St Denis 	WREG32(mmVCE_CLOCK_GATING_B, 0x1FF);
530aaa36a97SAlex Deucher 
531aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_CTRL, 0x00398000);
532aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1);
533aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL, 0);
534aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL1, 0);
535aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_VM_CTRL, 0);
5363c0ff9f1SLeo Liu 	if (adev->asic_type >= CHIP_STONEY) {
5373c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8));
5383c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8));
5393c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8));
5403c0ff9f1SLeo Liu 	} else
541aaa36a97SAlex Deucher 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
542aaa36a97SAlex Deucher 	offset = AMDGPU_VCE_FIRMWARE_OFFSET;
543e9822622SLeo Liu 	size = VCE_V3_0_FW_SIZE;
544aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
545aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_SIZE0, size);
546aaa36a97SAlex Deucher 
5475bbc553aSLeo Liu 	if (idx == 0) {
548aaa36a97SAlex Deucher 		offset += size;
549e9822622SLeo Liu 		size = VCE_V3_0_STACK_SIZE;
550aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff);
551aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
552aaa36a97SAlex Deucher 		offset += size;
553e9822622SLeo Liu 		size = VCE_V3_0_DATA_SIZE;
554aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff);
555aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5565bbc553aSLeo Liu 	} else {
5575bbc553aSLeo Liu 		offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE;
5585bbc553aSLeo Liu 		size = VCE_V3_0_STACK_SIZE;
5595bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff);
5605bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
5615bbc553aSLeo Liu 		offset += size;
5625bbc553aSLeo Liu 		size = VCE_V3_0_DATA_SIZE;
5635bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff);
5645bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5655bbc553aSLeo Liu 	}
566aaa36a97SAlex Deucher 
567aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100);
568aaa36a97SAlex Deucher 
569aaa36a97SAlex Deucher 	WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK,
570aaa36a97SAlex Deucher 		 ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
571aaa36a97SAlex Deucher }
572aaa36a97SAlex Deucher 
5735fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle)
574aaa36a97SAlex Deucher {
5755fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
576be4f38e2SAlex Deucher 	u32 mask = 0;
5775fc3aeebSyanyang1 
57874af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK;
57974af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK;
580be4f38e2SAlex Deucher 
581be4f38e2SAlex Deucher 	return !(RREG32(mmSRBM_STATUS2) & mask);
582aaa36a97SAlex Deucher }
583aaa36a97SAlex Deucher 
5845fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle)
585aaa36a97SAlex Deucher {
586aaa36a97SAlex Deucher 	unsigned i;
5875fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
588be4f38e2SAlex Deucher 
58992988e60STom St Denis 	for (i = 0; i < adev->usec_timeout; i++)
59092988e60STom St Denis 		if (vce_v3_0_is_idle(handle))
591aaa36a97SAlex Deucher 			return 0;
59292988e60STom St Denis 
593aaa36a97SAlex Deucher 	return -ETIMEDOUT;
594aaa36a97SAlex Deucher }
595aaa36a97SAlex Deucher 
596115933a5SChunming Zhou #define AMDGPU_VCE_STATUS_BUSY_MASK    0x78
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 (adev->vce.harvest_config & (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1))
639115933a5SChunming Zhou 		srbm_soft_reset = 0;
640115933a5SChunming Zhou 
641115933a5SChunming Zhou 	if (srbm_soft_reset) {
642115933a5SChunming Zhou 		adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = true;
643115933a5SChunming Zhou 		adev->vce.srbm_soft_reset = srbm_soft_reset;
644115933a5SChunming Zhou 	} else {
645115933a5SChunming Zhou 		adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = false;
646115933a5SChunming Zhou 		adev->vce.srbm_soft_reset = 0;
647115933a5SChunming Zhou 	}
648115933a5SChunming Zhou 	return 0;
649115933a5SChunming Zhou }
650115933a5SChunming Zhou 
6515fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle)
652aaa36a97SAlex Deucher {
6535fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
654115933a5SChunming Zhou 	u32 srbm_soft_reset;
6555fc3aeebSyanyang1 
656115933a5SChunming Zhou 	if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
657115933a5SChunming Zhou 		return 0;
658115933a5SChunming Zhou 	srbm_soft_reset = adev->vce.srbm_soft_reset;
659be4f38e2SAlex Deucher 
660115933a5SChunming Zhou 	if (srbm_soft_reset) {
661115933a5SChunming Zhou 		u32 tmp;
662115933a5SChunming Zhou 
663115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
664115933a5SChunming Zhou 		tmp |= srbm_soft_reset;
665115933a5SChunming Zhou 		dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
666115933a5SChunming Zhou 		WREG32(mmSRBM_SOFT_RESET, tmp);
667115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
668115933a5SChunming Zhou 
669115933a5SChunming Zhou 		udelay(50);
670115933a5SChunming Zhou 
671115933a5SChunming Zhou 		tmp &= ~srbm_soft_reset;
672115933a5SChunming Zhou 		WREG32(mmSRBM_SOFT_RESET, tmp);
673115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
674115933a5SChunming Zhou 
675115933a5SChunming Zhou 		/* Wait a little for things to settle down */
676115933a5SChunming Zhou 		udelay(50);
677115933a5SChunming Zhou 	}
678115933a5SChunming Zhou 
679115933a5SChunming Zhou 	return 0;
680115933a5SChunming Zhou }
681115933a5SChunming Zhou 
682115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle)
683115933a5SChunming Zhou {
684115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
685115933a5SChunming Zhou 
686115933a5SChunming Zhou 	if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
687115933a5SChunming Zhou 		return 0;
688115933a5SChunming Zhou 
689aaa36a97SAlex Deucher 	mdelay(5);
690aaa36a97SAlex Deucher 
691115933a5SChunming Zhou 	return vce_v3_0_suspend(adev);
692115933a5SChunming Zhou }
693115933a5SChunming Zhou 
694115933a5SChunming Zhou 
695115933a5SChunming Zhou static int vce_v3_0_post_soft_reset(void *handle)
696115933a5SChunming Zhou {
697115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
698115933a5SChunming Zhou 
699115933a5SChunming Zhou 	if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
700115933a5SChunming Zhou 		return 0;
701115933a5SChunming Zhou 
702115933a5SChunming Zhou 	mdelay(5);
703115933a5SChunming Zhou 
704115933a5SChunming Zhou 	return vce_v3_0_resume(adev);
705aaa36a97SAlex Deucher }
706aaa36a97SAlex Deucher 
707aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev,
708aaa36a97SAlex Deucher 					struct amdgpu_irq_src *source,
709aaa36a97SAlex Deucher 					unsigned type,
710aaa36a97SAlex Deucher 					enum amdgpu_interrupt_state state)
711aaa36a97SAlex Deucher {
712aaa36a97SAlex Deucher 	uint32_t val = 0;
713aaa36a97SAlex Deucher 
714aaa36a97SAlex Deucher 	if (state == AMDGPU_IRQ_STATE_ENABLE)
715aaa36a97SAlex Deucher 		val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK;
716aaa36a97SAlex Deucher 
717aaa36a97SAlex Deucher 	WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
718aaa36a97SAlex Deucher 	return 0;
719aaa36a97SAlex Deucher }
720aaa36a97SAlex Deucher 
721aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
722aaa36a97SAlex Deucher 				      struct amdgpu_irq_src *source,
723aaa36a97SAlex Deucher 				      struct amdgpu_iv_entry *entry)
724aaa36a97SAlex Deucher {
725aaa36a97SAlex Deucher 	DRM_DEBUG("IH: VCE\n");
726d6c29c30SLeo Liu 
727d6c29c30SLeo Liu 	WREG32_P(mmVCE_SYS_INT_STATUS,
728d6c29c30SLeo Liu 		VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK,
729d6c29c30SLeo Liu 		~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK);
730d6c29c30SLeo Liu 
731aaa36a97SAlex Deucher 	switch (entry->src_data) {
732aaa36a97SAlex Deucher 	case 0:
733aaa36a97SAlex Deucher 	case 1:
73481da2edeSTom St Denis 		amdgpu_fence_process(&adev->vce.ring[entry->src_data]);
735aaa36a97SAlex Deucher 		break;
736aaa36a97SAlex Deucher 	default:
737aaa36a97SAlex Deucher 		DRM_ERROR("Unhandled interrupt: %d %d\n",
738aaa36a97SAlex Deucher 			  entry->src_id, entry->src_data);
739aaa36a97SAlex Deucher 		break;
740aaa36a97SAlex Deucher 	}
741aaa36a97SAlex Deucher 
742aaa36a97SAlex Deucher 	return 0;
743aaa36a97SAlex Deucher }
744aaa36a97SAlex Deucher 
745ec38f188SRex Zhu static void vce_v3_set_bypass_mode(struct amdgpu_device *adev, bool enable)
746ec38f188SRex Zhu {
747ec38f188SRex Zhu 	u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL);
748ec38f188SRex Zhu 
749ec38f188SRex Zhu 	if (enable)
750ec38f188SRex Zhu 		tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
751ec38f188SRex Zhu 	else
752ec38f188SRex Zhu 		tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
753ec38f188SRex Zhu 
754ec38f188SRex Zhu 	WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp);
755ec38f188SRex Zhu }
756ec38f188SRex Zhu 
7575fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle,
7585fc3aeebSyanyang1 					  enum amd_clockgating_state state)
759aaa36a97SAlex Deucher {
7600689a570SEric Huang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
7610689a570SEric Huang 	bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
7620689a570SEric Huang 	int i;
7630689a570SEric Huang 
764ec38f188SRex Zhu 	if (adev->asic_type == CHIP_POLARIS10)
765ec38f188SRex Zhu 		vce_v3_set_bypass_mode(adev, enable);
766ec38f188SRex Zhu 
767e3b04bc7SAlex Deucher 	if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG))
7680689a570SEric Huang 		return 0;
7690689a570SEric Huang 
7700689a570SEric Huang 	mutex_lock(&adev->grbm_idx_mutex);
7710689a570SEric Huang 	for (i = 0; i < 2; i++) {
7720689a570SEric Huang 		/* Program VCE Instance 0 or 1 if not harvested */
7730689a570SEric Huang 		if (adev->vce.harvest_config & (1 << i))
7740689a570SEric Huang 			continue;
7750689a570SEric Huang 
7760689a570SEric Huang 		if (i == 0)
7770689a570SEric Huang 			WREG32_P(mmGRBM_GFX_INDEX, 0,
7780689a570SEric Huang 					~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
7790689a570SEric Huang 		else
7800689a570SEric Huang 			WREG32_P(mmGRBM_GFX_INDEX,
7810689a570SEric Huang 					GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
7820689a570SEric Huang 					~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
7830689a570SEric Huang 
7840689a570SEric Huang 		if (enable) {
7850689a570SEric Huang 			/* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
7860689a570SEric Huang 			uint32_t data = RREG32(mmVCE_CLOCK_GATING_A);
7870689a570SEric Huang 			data &= ~(0xf | 0xff0);
7880689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
7890689a570SEric Huang 			WREG32(mmVCE_CLOCK_GATING_A, data);
7900689a570SEric Huang 
7910689a570SEric Huang 			/* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */
7920689a570SEric Huang 			data = RREG32(mmVCE_UENC_CLOCK_GATING);
7930689a570SEric Huang 			data &= ~(0xf | 0xff0);
7940689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
7950689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING, data);
7960689a570SEric Huang 		}
7970689a570SEric Huang 
7980689a570SEric Huang 		vce_v3_0_set_vce_sw_clock_gating(adev, enable);
7990689a570SEric Huang 	}
8000689a570SEric Huang 
8010689a570SEric Huang 	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
8020689a570SEric Huang 	mutex_unlock(&adev->grbm_idx_mutex);
8030689a570SEric Huang 
804aaa36a97SAlex Deucher 	return 0;
805aaa36a97SAlex Deucher }
806aaa36a97SAlex Deucher 
8075fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle,
8085fc3aeebSyanyang1 					  enum amd_powergating_state state)
809aaa36a97SAlex Deucher {
810aaa36a97SAlex Deucher 	/* This doesn't actually powergate the VCE block.
811aaa36a97SAlex Deucher 	 * That's done in the dpm code via the SMC.  This
812aaa36a97SAlex Deucher 	 * just re-inits the block as necessary.  The actual
813aaa36a97SAlex Deucher 	 * gating still happens in the dpm code.  We should
814aaa36a97SAlex Deucher 	 * revisit this when there is a cleaner line between
815aaa36a97SAlex Deucher 	 * the smc and the hw blocks
816aaa36a97SAlex Deucher 	 */
8175fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
8185fc3aeebSyanyang1 
819e3b04bc7SAlex Deucher 	if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE))
820808a934fSAlex Deucher 		return 0;
821808a934fSAlex Deucher 
8225fc3aeebSyanyang1 	if (state == AMD_PG_STATE_GATE)
823aaa36a97SAlex Deucher 		/* XXX do we need a vce_v3_0_stop()? */
824aaa36a97SAlex Deucher 		return 0;
825aaa36a97SAlex Deucher 	else
826aaa36a97SAlex Deucher 		return vce_v3_0_start(adev);
827aaa36a97SAlex Deucher }
828aaa36a97SAlex Deucher 
8295fc3aeebSyanyang1 const struct amd_ip_funcs vce_v3_0_ip_funcs = {
83088a907d6STom St Denis 	.name = "vce_v3_0",
831aaa36a97SAlex Deucher 	.early_init = vce_v3_0_early_init,
832aaa36a97SAlex Deucher 	.late_init = NULL,
833aaa36a97SAlex Deucher 	.sw_init = vce_v3_0_sw_init,
834aaa36a97SAlex Deucher 	.sw_fini = vce_v3_0_sw_fini,
835aaa36a97SAlex Deucher 	.hw_init = vce_v3_0_hw_init,
836aaa36a97SAlex Deucher 	.hw_fini = vce_v3_0_hw_fini,
837aaa36a97SAlex Deucher 	.suspend = vce_v3_0_suspend,
838aaa36a97SAlex Deucher 	.resume = vce_v3_0_resume,
839aaa36a97SAlex Deucher 	.is_idle = vce_v3_0_is_idle,
840aaa36a97SAlex Deucher 	.wait_for_idle = vce_v3_0_wait_for_idle,
841115933a5SChunming Zhou 	.check_soft_reset = vce_v3_0_check_soft_reset,
842115933a5SChunming Zhou 	.pre_soft_reset = vce_v3_0_pre_soft_reset,
843aaa36a97SAlex Deucher 	.soft_reset = vce_v3_0_soft_reset,
844115933a5SChunming Zhou 	.post_soft_reset = vce_v3_0_post_soft_reset,
845aaa36a97SAlex Deucher 	.set_clockgating_state = vce_v3_0_set_clockgating_state,
846aaa36a97SAlex Deucher 	.set_powergating_state = vce_v3_0_set_powergating_state,
847aaa36a97SAlex Deucher };
848aaa36a97SAlex Deucher 
849aaa36a97SAlex Deucher static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = {
850aaa36a97SAlex Deucher 	.get_rptr = vce_v3_0_ring_get_rptr,
851aaa36a97SAlex Deucher 	.get_wptr = vce_v3_0_ring_get_wptr,
852aaa36a97SAlex Deucher 	.set_wptr = vce_v3_0_ring_set_wptr,
853aaa36a97SAlex Deucher 	.parse_cs = amdgpu_vce_ring_parse_cs,
854aaa36a97SAlex Deucher 	.emit_ib = amdgpu_vce_ring_emit_ib,
855aaa36a97SAlex Deucher 	.emit_fence = amdgpu_vce_ring_emit_fence,
856aaa36a97SAlex Deucher 	.test_ring = amdgpu_vce_ring_test_ring,
857aaa36a97SAlex Deucher 	.test_ib = amdgpu_vce_ring_test_ib,
858edff0e28SJammy Zhou 	.insert_nop = amdgpu_ring_insert_nop,
8599e5d5309SChristian König 	.pad_ib = amdgpu_ring_generic_pad_ib,
860ebff485eSChristian König 	.begin_use = amdgpu_vce_ring_begin_use,
861ebff485eSChristian König 	.end_use = amdgpu_vce_ring_end_use,
862aaa36a97SAlex Deucher };
863aaa36a97SAlex Deucher 
864aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev)
865aaa36a97SAlex Deucher {
866aaa36a97SAlex Deucher 	adev->vce.ring[0].funcs = &vce_v3_0_ring_funcs;
867aaa36a97SAlex Deucher 	adev->vce.ring[1].funcs = &vce_v3_0_ring_funcs;
868aaa36a97SAlex Deucher }
869aaa36a97SAlex Deucher 
870aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = {
871aaa36a97SAlex Deucher 	.set = vce_v3_0_set_interrupt_state,
872aaa36a97SAlex Deucher 	.process = vce_v3_0_process_interrupt,
873aaa36a97SAlex Deucher };
874aaa36a97SAlex Deucher 
875aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev)
876aaa36a97SAlex Deucher {
877aaa36a97SAlex Deucher 	adev->vce.irq.num_types = 1;
878aaa36a97SAlex Deucher 	adev->vce.irq.funcs = &vce_v3_0_irq_funcs;
879aaa36a97SAlex Deucher };
880