xref: /openbmc/linux/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c (revision 115933a5)
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;
1290689a570SEric Huang 	/* Set Override to disable Clock Gating */
1300689a570SEric Huang 	vce_v3_0_override_vce_clock_gating(adev, true);
1310689a570SEric Huang 
1320689a570SEric Huang 	if (!gated) {
1330689a570SEric Huang 		/* Force CLOCK ON for VCE_CLOCK_GATING_B,
1340689a570SEric Huang 		 * {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
1350689a570SEric Huang 		 * VREG can be FORCE ON or set to Dynamic, but can't be OFF
1360689a570SEric Huang 		 */
1370689a570SEric Huang 		tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
1380689a570SEric Huang 		data |= 0x1ff;
1390689a570SEric Huang 		data &= ~0xef0000;
1400689a570SEric Huang 		if (tmp != data)
1410689a570SEric Huang 			WREG32(mmVCE_CLOCK_GATING_B, data);
1420689a570SEric Huang 
1430689a570SEric Huang 		/* Force CLOCK ON for VCE_UENC_CLOCK_GATING,
1440689a570SEric Huang 		 * {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
1450689a570SEric Huang 		 */
1460689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
1470689a570SEric Huang 		data |= 0x3ff000;
1480689a570SEric Huang 		data &= ~0xffc00000;
1490689a570SEric Huang 		if (tmp != data)
1500689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING, data);
1510689a570SEric Huang 
1520689a570SEric Huang 		/* set VCE_UENC_CLOCK_GATING_2 */
1530689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
1540689a570SEric Huang 		data |= 0x2;
1550689a570SEric Huang 		data &= ~0x2;
1560689a570SEric Huang 		if (tmp != data)
1570689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
1580689a570SEric Huang 
1590689a570SEric Huang 		/* Force CLOCK ON for VCE_UENC_REG_CLOCK_GATING */
1600689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
1610689a570SEric Huang 		data |= 0x37f;
1620689a570SEric Huang 		if (tmp != data)
1630689a570SEric Huang 			WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
1640689a570SEric Huang 
1650689a570SEric Huang 		/* Force VCE_UENC_DMA_DCLK_CTRL Clock ON */
1660689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
1670689a570SEric Huang 		data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
1680689a570SEric Huang 				VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
1690689a570SEric Huang 				VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
1700689a570SEric Huang 				0x8;
1710689a570SEric Huang 		if (tmp != data)
1720689a570SEric Huang 			WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
1730689a570SEric Huang 	} else {
1740689a570SEric Huang 		/* Force CLOCK OFF for VCE_CLOCK_GATING_B,
1750689a570SEric Huang 		 * {*, *_FORCE_OFF} = {*, 1}
1760689a570SEric Huang 		 * set VREG to Dynamic, as it can't be OFF
1770689a570SEric Huang 		 */
1780689a570SEric Huang 		tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
1790689a570SEric Huang 		data &= ~0x80010;
1800689a570SEric Huang 		data |= 0xe70008;
1810689a570SEric Huang 		if (tmp != data)
1820689a570SEric Huang 			WREG32(mmVCE_CLOCK_GATING_B, data);
1830689a570SEric Huang 		/* Force CLOCK OFF for VCE_UENC_CLOCK_GATING,
1840689a570SEric Huang 		 * Force ClOCK OFF takes precedent over Force CLOCK ON setting.
1850689a570SEric Huang 		 * {*_FORCE_ON, *_FORCE_OFF} = {*, 1}
1860689a570SEric Huang 		 */
1870689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
1880689a570SEric Huang 		data |= 0xffc00000;
1890689a570SEric Huang 		if (tmp != data)
1900689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING, data);
1910689a570SEric Huang 		/* Set VCE_UENC_CLOCK_GATING_2 */
1920689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
1930689a570SEric Huang 		data |= 0x10000;
1940689a570SEric Huang 		if (tmp != data)
1950689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
1960689a570SEric Huang 		/* Set VCE_UENC_REG_CLOCK_GATING to dynamic */
1970689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
1980689a570SEric Huang 		data &= ~0xffc00000;
1990689a570SEric Huang 		if (tmp != data)
2000689a570SEric Huang 			WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
2010689a570SEric Huang 		/* Set VCE_UENC_DMA_DCLK_CTRL CG always in dynamic mode */
2020689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
2030689a570SEric Huang 		data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
2040689a570SEric Huang 				VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
2050689a570SEric Huang 				VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
2060689a570SEric Huang 				0x8);
2070689a570SEric Huang 		if (tmp != data)
2080689a570SEric Huang 			WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
2090689a570SEric Huang 	}
2100689a570SEric Huang 	vce_v3_0_override_vce_clock_gating(adev, false);
2110689a570SEric Huang }
2120689a570SEric Huang 
213567e6e29Sjimqu static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev)
214567e6e29Sjimqu {
215567e6e29Sjimqu 	int i, j;
216567e6e29Sjimqu 
217567e6e29Sjimqu 	for (i = 0; i < 10; ++i) {
218567e6e29Sjimqu 		for (j = 0; j < 100; ++j) {
219b7e2e9f7Sjimqu 			uint32_t status = RREG32(mmVCE_STATUS);
220b7e2e9f7Sjimqu 
221567e6e29Sjimqu 			if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK)
222567e6e29Sjimqu 				return 0;
223567e6e29Sjimqu 			mdelay(10);
224567e6e29Sjimqu 		}
225567e6e29Sjimqu 
226567e6e29Sjimqu 		DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
227567e6e29Sjimqu 		WREG32_P(mmVCE_SOFT_RESET,
228567e6e29Sjimqu 			VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
229567e6e29Sjimqu 			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
230567e6e29Sjimqu 		mdelay(10);
231567e6e29Sjimqu 		WREG32_P(mmVCE_SOFT_RESET, 0,
232567e6e29Sjimqu 			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
233567e6e29Sjimqu 		mdelay(10);
234567e6e29Sjimqu 	}
235567e6e29Sjimqu 
236567e6e29Sjimqu 	return -ETIMEDOUT;
237567e6e29Sjimqu }
238567e6e29Sjimqu 
239aaa36a97SAlex Deucher /**
240aaa36a97SAlex Deucher  * vce_v3_0_start - start VCE block
241aaa36a97SAlex Deucher  *
242aaa36a97SAlex Deucher  * @adev: amdgpu_device pointer
243aaa36a97SAlex Deucher  *
244aaa36a97SAlex Deucher  * Setup and start the VCE block
245aaa36a97SAlex Deucher  */
246aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev)
247aaa36a97SAlex Deucher {
248aaa36a97SAlex Deucher 	struct amdgpu_ring *ring;
249567e6e29Sjimqu 	int idx, r;
250567e6e29Sjimqu 
251567e6e29Sjimqu 	ring = &adev->vce.ring[0];
252567e6e29Sjimqu 	WREG32(mmVCE_RB_RPTR, ring->wptr);
253567e6e29Sjimqu 	WREG32(mmVCE_RB_WPTR, ring->wptr);
254567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr);
255567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
256567e6e29Sjimqu 	WREG32(mmVCE_RB_SIZE, ring->ring_size / 4);
257567e6e29Sjimqu 
258567e6e29Sjimqu 	ring = &adev->vce.ring[1];
259567e6e29Sjimqu 	WREG32(mmVCE_RB_RPTR2, ring->wptr);
260567e6e29Sjimqu 	WREG32(mmVCE_RB_WPTR2, ring->wptr);
261567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr);
262567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
263567e6e29Sjimqu 	WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4);
264aaa36a97SAlex Deucher 
2655bbc553aSLeo Liu 	mutex_lock(&adev->grbm_idx_mutex);
2665bbc553aSLeo Liu 	for (idx = 0; idx < 2; ++idx) {
2676a585777SAlex Deucher 		if (adev->vce.harvest_config & (1 << idx))
2686a585777SAlex Deucher 			continue;
2696a585777SAlex Deucher 
2705bbc553aSLeo Liu 		if (idx == 0)
2715bbc553aSLeo Liu 			WREG32_P(mmGRBM_GFX_INDEX, 0,
2725bbc553aSLeo Liu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
2735bbc553aSLeo Liu 		else
2745bbc553aSLeo Liu 			WREG32_P(mmGRBM_GFX_INDEX,
2755bbc553aSLeo Liu 				GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
2765bbc553aSLeo Liu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
2775bbc553aSLeo Liu 
2785bbc553aSLeo Liu 		vce_v3_0_mc_resume(adev, idx);
279aaa36a97SAlex Deucher 
280567e6e29Sjimqu 		WREG32_P(mmVCE_STATUS, VCE_STATUS__JOB_BUSY_MASK,
281567e6e29Sjimqu 		         ~VCE_STATUS__JOB_BUSY_MASK);
282567e6e29Sjimqu 
2833c0ff9f1SLeo Liu 		if (adev->asic_type >= CHIP_STONEY)
2843c0ff9f1SLeo Liu 			WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001);
2853c0ff9f1SLeo Liu 		else
2865bbc553aSLeo Liu 			WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK,
2875bbc553aSLeo Liu 				~VCE_VCPU_CNTL__CLK_EN_MASK);
288aaa36a97SAlex Deucher 
289567e6e29Sjimqu 		WREG32_P(mmVCE_SOFT_RESET, 0,
290aaa36a97SAlex Deucher 			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
291aaa36a97SAlex Deucher 
292aaa36a97SAlex Deucher 		mdelay(100);
293aaa36a97SAlex Deucher 
294567e6e29Sjimqu 		r = vce_v3_0_firmware_loaded(adev);
295aaa36a97SAlex Deucher 
296aaa36a97SAlex Deucher 		/* clear BUSY flag */
297567e6e29Sjimqu 		WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK);
298aaa36a97SAlex Deucher 
2990689a570SEric Huang 		/* Set Clock-Gating off */
300e3b04bc7SAlex Deucher 		if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
3010689a570SEric Huang 			vce_v3_0_set_vce_sw_clock_gating(adev, false);
3020689a570SEric Huang 
303aaa36a97SAlex Deucher 		if (r) {
304aaa36a97SAlex Deucher 			DRM_ERROR("VCE not responding, giving up!!!\n");
3055bbc553aSLeo Liu 			mutex_unlock(&adev->grbm_idx_mutex);
306aaa36a97SAlex Deucher 			return r;
307aaa36a97SAlex Deucher 		}
3085bbc553aSLeo Liu 	}
3095bbc553aSLeo Liu 
3105bbc553aSLeo Liu 	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
3115bbc553aSLeo Liu 	mutex_unlock(&adev->grbm_idx_mutex);
3125bbc553aSLeo Liu 
313567e6e29Sjimqu 	return 0;
314567e6e29Sjimqu }
3155bbc553aSLeo Liu 
316567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev)
317567e6e29Sjimqu {
318567e6e29Sjimqu 	int idx;
319567e6e29Sjimqu 
320567e6e29Sjimqu 	mutex_lock(&adev->grbm_idx_mutex);
321567e6e29Sjimqu 	for (idx = 0; idx < 2; ++idx) {
322567e6e29Sjimqu 		if (adev->vce.harvest_config & (1 << idx))
323567e6e29Sjimqu 			continue;
324567e6e29Sjimqu 
325567e6e29Sjimqu 		if (idx == 0)
326567e6e29Sjimqu 			WREG32_P(mmGRBM_GFX_INDEX, 0,
327567e6e29Sjimqu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
328567e6e29Sjimqu 		else
329567e6e29Sjimqu 			WREG32_P(mmGRBM_GFX_INDEX,
330567e6e29Sjimqu 				GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
331567e6e29Sjimqu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
332567e6e29Sjimqu 
333567e6e29Sjimqu 		if (adev->asic_type >= CHIP_STONEY)
334567e6e29Sjimqu 			WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001);
335567e6e29Sjimqu 		else
336567e6e29Sjimqu 			WREG32_P(mmVCE_VCPU_CNTL, 0,
337567e6e29Sjimqu 				~VCE_VCPU_CNTL__CLK_EN_MASK);
338567e6e29Sjimqu 		/* hold on ECPU */
339567e6e29Sjimqu 		WREG32_P(mmVCE_SOFT_RESET,
340567e6e29Sjimqu 			 VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
341567e6e29Sjimqu 			 ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
342567e6e29Sjimqu 
343567e6e29Sjimqu 		/* clear BUSY flag */
344567e6e29Sjimqu 		WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK);
345567e6e29Sjimqu 
346567e6e29Sjimqu 		/* Set Clock-Gating off */
347567e6e29Sjimqu 		if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
348567e6e29Sjimqu 			vce_v3_0_set_vce_sw_clock_gating(adev, false);
349567e6e29Sjimqu 	}
350567e6e29Sjimqu 
351567e6e29Sjimqu 	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
352567e6e29Sjimqu 	mutex_unlock(&adev->grbm_idx_mutex);
353aaa36a97SAlex Deucher 
354aaa36a97SAlex Deucher 	return 0;
355aaa36a97SAlex Deucher }
356aaa36a97SAlex Deucher 
3576a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS     0xC0014074
3586a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT       27
3596a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK        0x18000000
3606a585777SAlex Deucher 
3616a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
3626a585777SAlex Deucher {
3636a585777SAlex Deucher 	u32 tmp;
3646a585777SAlex Deucher 
3652cc0c0b5SFlora Cui 	/* Fiji, Stoney, Polaris10, Polaris11 are single pipe */
366cfaba566SSamuel Li 	if ((adev->asic_type == CHIP_FIJI) ||
3671b4eeea5SSonny Jiang 	    (adev->asic_type == CHIP_STONEY) ||
3682cc0c0b5SFlora Cui 	    (adev->asic_type == CHIP_POLARIS10) ||
3692cc0c0b5SFlora Cui 	    (adev->asic_type == CHIP_POLARIS11))
3701dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
371188a9bcdSAlex Deucher 
372188a9bcdSAlex Deucher 	/* Tonga and CZ are dual or single pipe */
3732f7d10b3SJammy Zhou 	if (adev->flags & AMD_IS_APU)
3746a585777SAlex Deucher 		tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) &
3756a585777SAlex Deucher 		       VCE_HARVEST_FUSE_MACRO__MASK) >>
3766a585777SAlex Deucher 			VCE_HARVEST_FUSE_MACRO__SHIFT;
3776a585777SAlex Deucher 	else
3786a585777SAlex Deucher 		tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) &
3796a585777SAlex Deucher 		       CC_HARVEST_FUSES__VCE_DISABLE_MASK) >>
3806a585777SAlex Deucher 			CC_HARVEST_FUSES__VCE_DISABLE__SHIFT;
3816a585777SAlex Deucher 
3826a585777SAlex Deucher 	switch (tmp) {
3836a585777SAlex Deucher 	case 1:
3841dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0;
3856a585777SAlex Deucher 	case 2:
3861dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
3876a585777SAlex Deucher 	case 3:
3881dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1;
3896a585777SAlex Deucher 	default:
3901dab5f06STom St Denis 		return 0;
3916a585777SAlex Deucher 	}
3926a585777SAlex Deucher }
3936a585777SAlex Deucher 
3945fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle)
395aaa36a97SAlex Deucher {
3965fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
3975fc3aeebSyanyang1 
3986a585777SAlex Deucher 	adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev);
3996a585777SAlex Deucher 
4006a585777SAlex Deucher 	if ((adev->vce.harvest_config &
4016a585777SAlex Deucher 	     (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) ==
4026a585777SAlex Deucher 	    (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1))
4036a585777SAlex Deucher 		return -ENOENT;
4046a585777SAlex Deucher 
405aaa36a97SAlex Deucher 	vce_v3_0_set_ring_funcs(adev);
406aaa36a97SAlex Deucher 	vce_v3_0_set_irq_funcs(adev);
407aaa36a97SAlex Deucher 
408aaa36a97SAlex Deucher 	return 0;
409aaa36a97SAlex Deucher }
410aaa36a97SAlex Deucher 
4115fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle)
412aaa36a97SAlex Deucher {
4135fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
414aaa36a97SAlex Deucher 	struct amdgpu_ring *ring;
415aaa36a97SAlex Deucher 	int r;
416aaa36a97SAlex Deucher 
417aaa36a97SAlex Deucher 	/* VCE */
418aaa36a97SAlex Deucher 	r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq);
419aaa36a97SAlex Deucher 	if (r)
420aaa36a97SAlex Deucher 		return r;
421aaa36a97SAlex Deucher 
422e9822622SLeo Liu 	r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE +
423e9822622SLeo Liu 		(VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2);
424aaa36a97SAlex Deucher 	if (r)
425aaa36a97SAlex Deucher 		return r;
426aaa36a97SAlex Deucher 
427aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
428aaa36a97SAlex Deucher 	if (r)
429aaa36a97SAlex Deucher 		return r;
430aaa36a97SAlex Deucher 
431aaa36a97SAlex Deucher 	ring = &adev->vce.ring[0];
432aaa36a97SAlex Deucher 	sprintf(ring->name, "vce0");
433a3f1cf35SChristian König 	r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
434aaa36a97SAlex Deucher 			     &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
435aaa36a97SAlex Deucher 	if (r)
436aaa36a97SAlex Deucher 		return r;
437aaa36a97SAlex Deucher 
438aaa36a97SAlex Deucher 	ring = &adev->vce.ring[1];
439aaa36a97SAlex Deucher 	sprintf(ring->name, "vce1");
440a3f1cf35SChristian König 	r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
441aaa36a97SAlex Deucher 			     &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
442aaa36a97SAlex Deucher 	if (r)
443aaa36a97SAlex Deucher 		return r;
444aaa36a97SAlex Deucher 
445aaa36a97SAlex Deucher 	return r;
446aaa36a97SAlex Deucher }
447aaa36a97SAlex Deucher 
4485fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle)
449aaa36a97SAlex Deucher {
450aaa36a97SAlex Deucher 	int r;
4515fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
452aaa36a97SAlex Deucher 
453aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
454aaa36a97SAlex Deucher 	if (r)
455aaa36a97SAlex Deucher 		return r;
456aaa36a97SAlex Deucher 
457aaa36a97SAlex Deucher 	r = amdgpu_vce_sw_fini(adev);
458aaa36a97SAlex Deucher 	if (r)
459aaa36a97SAlex Deucher 		return r;
460aaa36a97SAlex Deucher 
461aaa36a97SAlex Deucher 	return r;
462aaa36a97SAlex Deucher }
463aaa36a97SAlex Deucher 
4645fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle)
465aaa36a97SAlex Deucher {
466691ca86aSTom St Denis 	int r, i;
4675fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
468aaa36a97SAlex Deucher 
469aaa36a97SAlex Deucher 	r = vce_v3_0_start(adev);
470aaa36a97SAlex Deucher 	if (r)
471aaa36a97SAlex Deucher 		return r;
472aaa36a97SAlex Deucher 
473691ca86aSTom St Denis 	adev->vce.ring[0].ready = false;
474691ca86aSTom St Denis 	adev->vce.ring[1].ready = false;
475aaa36a97SAlex Deucher 
476691ca86aSTom St Denis 	for (i = 0; i < 2; i++) {
477691ca86aSTom St Denis 		r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
478691ca86aSTom St Denis 		if (r)
479aaa36a97SAlex Deucher 			return r;
480691ca86aSTom St Denis 		else
481691ca86aSTom St Denis 			adev->vce.ring[i].ready = true;
482aaa36a97SAlex Deucher 	}
483aaa36a97SAlex Deucher 
484aaa36a97SAlex Deucher 	DRM_INFO("VCE initialized successfully.\n");
485aaa36a97SAlex Deucher 
486aaa36a97SAlex Deucher 	return 0;
487aaa36a97SAlex Deucher }
488aaa36a97SAlex Deucher 
4895fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle)
490aaa36a97SAlex Deucher {
491567e6e29Sjimqu 	int r;
492567e6e29Sjimqu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
493567e6e29Sjimqu 
494567e6e29Sjimqu 	r = vce_v3_0_wait_for_idle(handle);
495567e6e29Sjimqu 	if (r)
496567e6e29Sjimqu 		return r;
497567e6e29Sjimqu 
498567e6e29Sjimqu 	return vce_v3_0_stop(adev);
499aaa36a97SAlex Deucher }
500aaa36a97SAlex Deucher 
5015fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle)
502aaa36a97SAlex Deucher {
503aaa36a97SAlex Deucher 	int r;
5045fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
505aaa36a97SAlex Deucher 
506aaa36a97SAlex Deucher 	r = vce_v3_0_hw_fini(adev);
507aaa36a97SAlex Deucher 	if (r)
508aaa36a97SAlex Deucher 		return r;
509aaa36a97SAlex Deucher 
510aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
511aaa36a97SAlex Deucher 	if (r)
512aaa36a97SAlex Deucher 		return r;
513aaa36a97SAlex Deucher 
514aaa36a97SAlex Deucher 	return r;
515aaa36a97SAlex Deucher }
516aaa36a97SAlex Deucher 
5175fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle)
518aaa36a97SAlex Deucher {
519aaa36a97SAlex Deucher 	int r;
5205fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
521aaa36a97SAlex Deucher 
522aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
523aaa36a97SAlex Deucher 	if (r)
524aaa36a97SAlex Deucher 		return r;
525aaa36a97SAlex Deucher 
526aaa36a97SAlex Deucher 	r = vce_v3_0_hw_init(adev);
527aaa36a97SAlex Deucher 	if (r)
528aaa36a97SAlex Deucher 		return r;
529aaa36a97SAlex Deucher 
530aaa36a97SAlex Deucher 	return r;
531aaa36a97SAlex Deucher }
532aaa36a97SAlex Deucher 
5335bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx)
534aaa36a97SAlex Deucher {
535aaa36a97SAlex Deucher 	uint32_t offset, size;
536aaa36a97SAlex Deucher 
537aaa36a97SAlex Deucher 	WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16));
538aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000);
539aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F);
540aaa36a97SAlex Deucher 	WREG32(mmVCE_CLOCK_GATING_B, 0xf7);
541aaa36a97SAlex Deucher 
542aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_CTRL, 0x00398000);
543aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1);
544aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL, 0);
545aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL1, 0);
546aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_VM_CTRL, 0);
5473c0ff9f1SLeo Liu 	if (adev->asic_type >= CHIP_STONEY) {
5483c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8));
5493c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8));
5503c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8));
5513c0ff9f1SLeo Liu 	} else
552aaa36a97SAlex Deucher 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
553aaa36a97SAlex Deucher 	offset = AMDGPU_VCE_FIRMWARE_OFFSET;
554e9822622SLeo Liu 	size = VCE_V3_0_FW_SIZE;
555aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
556aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_SIZE0, size);
557aaa36a97SAlex Deucher 
5585bbc553aSLeo Liu 	if (idx == 0) {
559aaa36a97SAlex Deucher 		offset += size;
560e9822622SLeo Liu 		size = VCE_V3_0_STACK_SIZE;
561aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff);
562aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
563aaa36a97SAlex Deucher 		offset += size;
564e9822622SLeo Liu 		size = VCE_V3_0_DATA_SIZE;
565aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff);
566aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5675bbc553aSLeo Liu 	} else {
5685bbc553aSLeo Liu 		offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE;
5695bbc553aSLeo Liu 		size = VCE_V3_0_STACK_SIZE;
5705bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff);
5715bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
5725bbc553aSLeo Liu 		offset += size;
5735bbc553aSLeo Liu 		size = VCE_V3_0_DATA_SIZE;
5745bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff);
5755bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5765bbc553aSLeo Liu 	}
577aaa36a97SAlex Deucher 
578aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100);
579aaa36a97SAlex Deucher 
580aaa36a97SAlex Deucher 	WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK,
581aaa36a97SAlex Deucher 		 ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
582aaa36a97SAlex Deucher }
583aaa36a97SAlex Deucher 
5845fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle)
585aaa36a97SAlex Deucher {
5865fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
587be4f38e2SAlex Deucher 	u32 mask = 0;
5885fc3aeebSyanyang1 
58974af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK;
59074af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK;
591be4f38e2SAlex Deucher 
592be4f38e2SAlex Deucher 	return !(RREG32(mmSRBM_STATUS2) & mask);
593aaa36a97SAlex Deucher }
594aaa36a97SAlex Deucher 
5955fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle)
596aaa36a97SAlex Deucher {
597aaa36a97SAlex Deucher 	unsigned i;
5985fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
599be4f38e2SAlex Deucher 
60092988e60STom St Denis 	for (i = 0; i < adev->usec_timeout; i++)
60192988e60STom St Denis 		if (vce_v3_0_is_idle(handle))
602aaa36a97SAlex Deucher 			return 0;
60392988e60STom St Denis 
604aaa36a97SAlex Deucher 	return -ETIMEDOUT;
605aaa36a97SAlex Deucher }
606aaa36a97SAlex Deucher 
607115933a5SChunming Zhou #define AMDGPU_VCE_STATUS_BUSY_MASK    0x78
608115933a5SChunming Zhou 
609115933a5SChunming Zhou static int vce_v3_0_check_soft_reset(void *handle)
610115933a5SChunming Zhou {
611115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
612115933a5SChunming Zhou 	u32 srbm_soft_reset = 0;
613115933a5SChunming Zhou 	u32 tmp;
614115933a5SChunming Zhou 
615115933a5SChunming Zhou 	/* VCE BUG: it is always busy, so skip its checking now */
616115933a5SChunming Zhou 	return 0;
617115933a5SChunming Zhou 
618115933a5SChunming Zhou 	/* According to VCE team , we should use VCE_STATUS instead
619115933a5SChunming Zhou 	 * SRBM_STATUS.VCE_BUSY bit for busy status checking.
620115933a5SChunming Zhou 	 * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE
621115933a5SChunming Zhou 	 * instance's registers are accessed
622115933a5SChunming Zhou 	 * (0 for 1st instance, 10 for 2nd instance).
623115933a5SChunming Zhou 	 *
624115933a5SChunming Zhou 	 *VCE_STATUS
625115933a5SChunming Zhou 	 *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 |          |FW_LOADED|JOB |
626115933a5SChunming Zhou 	 *|----+----+-----------+----+----+----+----------+---------+----|
627115933a5SChunming Zhou 	 *|bit8|bit7|    bit6   |bit5|bit4|bit3|   bit2   |  bit1   |bit0|
628115933a5SChunming Zhou 	 *
629115933a5SChunming Zhou 	 * VCE team suggest use bit 3--bit 6 for busy status check
630115933a5SChunming Zhou 	 */
631115933a5SChunming Zhou 	tmp = RREG32(mmGRBM_GFX_INDEX);
632115933a5SChunming Zhou 	tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
633115933a5SChunming Zhou 	WREG32(mmGRBM_GFX_INDEX, tmp);
634115933a5SChunming Zhou 	if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
635115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
636115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
637115933a5SChunming Zhou 	}
638115933a5SChunming Zhou 	tmp = RREG32(mmGRBM_GFX_INDEX);
639115933a5SChunming Zhou 	tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10);
640115933a5SChunming Zhou 	WREG32(mmGRBM_GFX_INDEX, tmp);
641115933a5SChunming Zhou 	if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
642115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
643115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
644115933a5SChunming Zhou 	}
645115933a5SChunming Zhou 	tmp = RREG32(mmGRBM_GFX_INDEX);
646115933a5SChunming Zhou 	tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
647115933a5SChunming Zhou 	WREG32(mmGRBM_GFX_INDEX, tmp);
648115933a5SChunming Zhou 
649115933a5SChunming Zhou 	if (adev->vce.harvest_config & (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1))
650115933a5SChunming Zhou 		srbm_soft_reset = 0;
651115933a5SChunming Zhou 
652115933a5SChunming Zhou 	if (srbm_soft_reset) {
653115933a5SChunming Zhou 		adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = true;
654115933a5SChunming Zhou 		adev->vce.srbm_soft_reset = srbm_soft_reset;
655115933a5SChunming Zhou 	} else {
656115933a5SChunming Zhou 		adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = false;
657115933a5SChunming Zhou 		adev->vce.srbm_soft_reset = 0;
658115933a5SChunming Zhou 	}
659115933a5SChunming Zhou 	return 0;
660115933a5SChunming Zhou }
661115933a5SChunming Zhou 
6625fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle)
663aaa36a97SAlex Deucher {
6645fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
665115933a5SChunming Zhou 	u32 srbm_soft_reset;
6665fc3aeebSyanyang1 
667115933a5SChunming Zhou 	if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
668115933a5SChunming Zhou 		return 0;
669115933a5SChunming Zhou 	srbm_soft_reset = adev->vce.srbm_soft_reset;
670be4f38e2SAlex Deucher 
671115933a5SChunming Zhou 	if (srbm_soft_reset) {
672115933a5SChunming Zhou 		u32 tmp;
673115933a5SChunming Zhou 
674115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
675115933a5SChunming Zhou 		tmp |= srbm_soft_reset;
676115933a5SChunming Zhou 		dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
677115933a5SChunming Zhou 		WREG32(mmSRBM_SOFT_RESET, tmp);
678115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
679115933a5SChunming Zhou 
680115933a5SChunming Zhou 		udelay(50);
681115933a5SChunming Zhou 
682115933a5SChunming Zhou 		tmp &= ~srbm_soft_reset;
683115933a5SChunming Zhou 		WREG32(mmSRBM_SOFT_RESET, tmp);
684115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
685115933a5SChunming Zhou 
686115933a5SChunming Zhou 		/* Wait a little for things to settle down */
687115933a5SChunming Zhou 		udelay(50);
688115933a5SChunming Zhou 	}
689115933a5SChunming Zhou 
690115933a5SChunming Zhou 	return 0;
691115933a5SChunming Zhou }
692115933a5SChunming Zhou 
693115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle)
694115933a5SChunming Zhou {
695115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
696115933a5SChunming Zhou 
697115933a5SChunming Zhou 	if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
698115933a5SChunming Zhou 		return 0;
699115933a5SChunming Zhou 
700aaa36a97SAlex Deucher 	mdelay(5);
701aaa36a97SAlex Deucher 
702115933a5SChunming Zhou 	return vce_v3_0_suspend(adev);
703115933a5SChunming Zhou }
704115933a5SChunming Zhou 
705115933a5SChunming Zhou 
706115933a5SChunming Zhou static int vce_v3_0_post_soft_reset(void *handle)
707115933a5SChunming Zhou {
708115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
709115933a5SChunming Zhou 
710115933a5SChunming Zhou 	if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
711115933a5SChunming Zhou 		return 0;
712115933a5SChunming Zhou 
713115933a5SChunming Zhou 	mdelay(5);
714115933a5SChunming Zhou 
715115933a5SChunming Zhou 	return vce_v3_0_resume(adev);
716aaa36a97SAlex Deucher }
717aaa36a97SAlex Deucher 
718aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev,
719aaa36a97SAlex Deucher 					struct amdgpu_irq_src *source,
720aaa36a97SAlex Deucher 					unsigned type,
721aaa36a97SAlex Deucher 					enum amdgpu_interrupt_state state)
722aaa36a97SAlex Deucher {
723aaa36a97SAlex Deucher 	uint32_t val = 0;
724aaa36a97SAlex Deucher 
725aaa36a97SAlex Deucher 	if (state == AMDGPU_IRQ_STATE_ENABLE)
726aaa36a97SAlex Deucher 		val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK;
727aaa36a97SAlex Deucher 
728aaa36a97SAlex Deucher 	WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
729aaa36a97SAlex Deucher 	return 0;
730aaa36a97SAlex Deucher }
731aaa36a97SAlex Deucher 
732aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
733aaa36a97SAlex Deucher 				      struct amdgpu_irq_src *source,
734aaa36a97SAlex Deucher 				      struct amdgpu_iv_entry *entry)
735aaa36a97SAlex Deucher {
736aaa36a97SAlex Deucher 	DRM_DEBUG("IH: VCE\n");
737d6c29c30SLeo Liu 
738d6c29c30SLeo Liu 	WREG32_P(mmVCE_SYS_INT_STATUS,
739d6c29c30SLeo Liu 		VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK,
740d6c29c30SLeo Liu 		~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK);
741d6c29c30SLeo Liu 
742aaa36a97SAlex Deucher 	switch (entry->src_data) {
743aaa36a97SAlex Deucher 	case 0:
744aaa36a97SAlex Deucher 	case 1:
74581da2edeSTom St Denis 		amdgpu_fence_process(&adev->vce.ring[entry->src_data]);
746aaa36a97SAlex Deucher 		break;
747aaa36a97SAlex Deucher 	default:
748aaa36a97SAlex Deucher 		DRM_ERROR("Unhandled interrupt: %d %d\n",
749aaa36a97SAlex Deucher 			  entry->src_id, entry->src_data);
750aaa36a97SAlex Deucher 		break;
751aaa36a97SAlex Deucher 	}
752aaa36a97SAlex Deucher 
753aaa36a97SAlex Deucher 	return 0;
754aaa36a97SAlex Deucher }
755aaa36a97SAlex Deucher 
756ec38f188SRex Zhu static void vce_v3_set_bypass_mode(struct amdgpu_device *adev, bool enable)
757ec38f188SRex Zhu {
758ec38f188SRex Zhu 	u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL);
759ec38f188SRex Zhu 
760ec38f188SRex Zhu 	if (enable)
761ec38f188SRex Zhu 		tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
762ec38f188SRex Zhu 	else
763ec38f188SRex Zhu 		tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
764ec38f188SRex Zhu 
765ec38f188SRex Zhu 	WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp);
766ec38f188SRex Zhu }
767ec38f188SRex Zhu 
7685fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle,
7695fc3aeebSyanyang1 					  enum amd_clockgating_state state)
770aaa36a97SAlex Deucher {
7710689a570SEric Huang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
7720689a570SEric Huang 	bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
7730689a570SEric Huang 	int i;
7740689a570SEric Huang 
775ec38f188SRex Zhu 	if (adev->asic_type == CHIP_POLARIS10)
776ec38f188SRex Zhu 		vce_v3_set_bypass_mode(adev, enable);
777ec38f188SRex Zhu 
778e3b04bc7SAlex Deucher 	if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG))
7790689a570SEric Huang 		return 0;
7800689a570SEric Huang 
7810689a570SEric Huang 	mutex_lock(&adev->grbm_idx_mutex);
7820689a570SEric Huang 	for (i = 0; i < 2; i++) {
7830689a570SEric Huang 		/* Program VCE Instance 0 or 1 if not harvested */
7840689a570SEric Huang 		if (adev->vce.harvest_config & (1 << i))
7850689a570SEric Huang 			continue;
7860689a570SEric Huang 
7870689a570SEric Huang 		if (i == 0)
7880689a570SEric Huang 			WREG32_P(mmGRBM_GFX_INDEX, 0,
7890689a570SEric Huang 					~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
7900689a570SEric Huang 		else
7910689a570SEric Huang 			WREG32_P(mmGRBM_GFX_INDEX,
7920689a570SEric Huang 					GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
7930689a570SEric Huang 					~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
7940689a570SEric Huang 
7950689a570SEric Huang 		if (enable) {
7960689a570SEric Huang 			/* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
7970689a570SEric Huang 			uint32_t data = RREG32(mmVCE_CLOCK_GATING_A);
7980689a570SEric Huang 			data &= ~(0xf | 0xff0);
7990689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
8000689a570SEric Huang 			WREG32(mmVCE_CLOCK_GATING_A, data);
8010689a570SEric Huang 
8020689a570SEric Huang 			/* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */
8030689a570SEric Huang 			data = RREG32(mmVCE_UENC_CLOCK_GATING);
8040689a570SEric Huang 			data &= ~(0xf | 0xff0);
8050689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
8060689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING, data);
8070689a570SEric Huang 		}
8080689a570SEric Huang 
8090689a570SEric Huang 		vce_v3_0_set_vce_sw_clock_gating(adev, enable);
8100689a570SEric Huang 	}
8110689a570SEric Huang 
8120689a570SEric Huang 	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
8130689a570SEric Huang 	mutex_unlock(&adev->grbm_idx_mutex);
8140689a570SEric Huang 
815aaa36a97SAlex Deucher 	return 0;
816aaa36a97SAlex Deucher }
817aaa36a97SAlex Deucher 
8185fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle,
8195fc3aeebSyanyang1 					  enum amd_powergating_state state)
820aaa36a97SAlex Deucher {
821aaa36a97SAlex Deucher 	/* This doesn't actually powergate the VCE block.
822aaa36a97SAlex Deucher 	 * That's done in the dpm code via the SMC.  This
823aaa36a97SAlex Deucher 	 * just re-inits the block as necessary.  The actual
824aaa36a97SAlex Deucher 	 * gating still happens in the dpm code.  We should
825aaa36a97SAlex Deucher 	 * revisit this when there is a cleaner line between
826aaa36a97SAlex Deucher 	 * the smc and the hw blocks
827aaa36a97SAlex Deucher 	 */
8285fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
8295fc3aeebSyanyang1 
830e3b04bc7SAlex Deucher 	if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE))
831808a934fSAlex Deucher 		return 0;
832808a934fSAlex Deucher 
8335fc3aeebSyanyang1 	if (state == AMD_PG_STATE_GATE)
834aaa36a97SAlex Deucher 		/* XXX do we need a vce_v3_0_stop()? */
835aaa36a97SAlex Deucher 		return 0;
836aaa36a97SAlex Deucher 	else
837aaa36a97SAlex Deucher 		return vce_v3_0_start(adev);
838aaa36a97SAlex Deucher }
839aaa36a97SAlex Deucher 
8405fc3aeebSyanyang1 const struct amd_ip_funcs vce_v3_0_ip_funcs = {
84188a907d6STom St Denis 	.name = "vce_v3_0",
842aaa36a97SAlex Deucher 	.early_init = vce_v3_0_early_init,
843aaa36a97SAlex Deucher 	.late_init = NULL,
844aaa36a97SAlex Deucher 	.sw_init = vce_v3_0_sw_init,
845aaa36a97SAlex Deucher 	.sw_fini = vce_v3_0_sw_fini,
846aaa36a97SAlex Deucher 	.hw_init = vce_v3_0_hw_init,
847aaa36a97SAlex Deucher 	.hw_fini = vce_v3_0_hw_fini,
848aaa36a97SAlex Deucher 	.suspend = vce_v3_0_suspend,
849aaa36a97SAlex Deucher 	.resume = vce_v3_0_resume,
850aaa36a97SAlex Deucher 	.is_idle = vce_v3_0_is_idle,
851aaa36a97SAlex Deucher 	.wait_for_idle = vce_v3_0_wait_for_idle,
852115933a5SChunming Zhou 	.check_soft_reset = vce_v3_0_check_soft_reset,
853115933a5SChunming Zhou 	.pre_soft_reset = vce_v3_0_pre_soft_reset,
854aaa36a97SAlex Deucher 	.soft_reset = vce_v3_0_soft_reset,
855115933a5SChunming Zhou 	.post_soft_reset = vce_v3_0_post_soft_reset,
856aaa36a97SAlex Deucher 	.set_clockgating_state = vce_v3_0_set_clockgating_state,
857aaa36a97SAlex Deucher 	.set_powergating_state = vce_v3_0_set_powergating_state,
858aaa36a97SAlex Deucher };
859aaa36a97SAlex Deucher 
860aaa36a97SAlex Deucher static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = {
861aaa36a97SAlex Deucher 	.get_rptr = vce_v3_0_ring_get_rptr,
862aaa36a97SAlex Deucher 	.get_wptr = vce_v3_0_ring_get_wptr,
863aaa36a97SAlex Deucher 	.set_wptr = vce_v3_0_ring_set_wptr,
864aaa36a97SAlex Deucher 	.parse_cs = amdgpu_vce_ring_parse_cs,
865aaa36a97SAlex Deucher 	.emit_ib = amdgpu_vce_ring_emit_ib,
866aaa36a97SAlex Deucher 	.emit_fence = amdgpu_vce_ring_emit_fence,
867aaa36a97SAlex Deucher 	.test_ring = amdgpu_vce_ring_test_ring,
868aaa36a97SAlex Deucher 	.test_ib = amdgpu_vce_ring_test_ib,
869edff0e28SJammy Zhou 	.insert_nop = amdgpu_ring_insert_nop,
8709e5d5309SChristian König 	.pad_ib = amdgpu_ring_generic_pad_ib,
871ebff485eSChristian König 	.begin_use = amdgpu_vce_ring_begin_use,
872ebff485eSChristian König 	.end_use = amdgpu_vce_ring_end_use,
873aaa36a97SAlex Deucher };
874aaa36a97SAlex Deucher 
875aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev)
876aaa36a97SAlex Deucher {
877aaa36a97SAlex Deucher 	adev->vce.ring[0].funcs = &vce_v3_0_ring_funcs;
878aaa36a97SAlex Deucher 	adev->vce.ring[1].funcs = &vce_v3_0_ring_funcs;
879aaa36a97SAlex Deucher }
880aaa36a97SAlex Deucher 
881aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = {
882aaa36a97SAlex Deucher 	.set = vce_v3_0_set_interrupt_state,
883aaa36a97SAlex Deucher 	.process = vce_v3_0_process_interrupt,
884aaa36a97SAlex Deucher };
885aaa36a97SAlex Deucher 
886aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev)
887aaa36a97SAlex Deucher {
888aaa36a97SAlex Deucher 	adev->vce.irq.num_types = 1;
889aaa36a97SAlex Deucher 	adev->vce.irq.funcs = &vce_v3_0_irq_funcs;
890aaa36a97SAlex Deucher };
891