xref: /openbmc/linux/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c (revision f16fe6d3)
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 
1330689a570SEric Huang 	if (!gated) {
1340689a570SEric Huang 		/* Force CLOCK ON for VCE_CLOCK_GATING_B,
1350689a570SEric Huang 		 * {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
1360689a570SEric Huang 		 * VREG can be FORCE ON or set to Dynamic, but can't be OFF
1370689a570SEric Huang 		 */
1380689a570SEric Huang 		tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
1390689a570SEric Huang 		data |= 0x1ff;
1400689a570SEric Huang 		data &= ~0xef0000;
1410689a570SEric Huang 		if (tmp != data)
1420689a570SEric Huang 			WREG32(mmVCE_CLOCK_GATING_B, data);
1430689a570SEric Huang 
1440689a570SEric Huang 		/* Force CLOCK ON for VCE_UENC_CLOCK_GATING,
1450689a570SEric Huang 		 * {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
1460689a570SEric Huang 		 */
1470689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
1480689a570SEric Huang 		data |= 0x3ff000;
1490689a570SEric Huang 		data &= ~0xffc00000;
1500689a570SEric Huang 		if (tmp != data)
1510689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING, data);
1520689a570SEric Huang 
1530689a570SEric Huang 		/* set VCE_UENC_CLOCK_GATING_2 */
1540689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
1550689a570SEric Huang 		data |= 0x2;
1560689a570SEric Huang 		data &= ~0x2;
1570689a570SEric Huang 		if (tmp != data)
1580689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
1590689a570SEric Huang 
1600689a570SEric Huang 		/* Force CLOCK ON for VCE_UENC_REG_CLOCK_GATING */
1610689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
1620689a570SEric Huang 		data |= 0x37f;
1630689a570SEric Huang 		if (tmp != data)
1640689a570SEric Huang 			WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
1650689a570SEric Huang 
1660689a570SEric Huang 		/* Force VCE_UENC_DMA_DCLK_CTRL Clock ON */
1670689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
1680689a570SEric Huang 		data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
1690689a570SEric Huang 			VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
1700689a570SEric Huang 			VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
1710689a570SEric Huang 			0x8;
1720689a570SEric Huang 		if (tmp != data)
1730689a570SEric Huang 			WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
1740689a570SEric Huang 	} else {
1750689a570SEric Huang 		/* Force CLOCK OFF for VCE_CLOCK_GATING_B,
1760689a570SEric Huang 		 * {*, *_FORCE_OFF} = {*, 1}
1770689a570SEric Huang 		 * set VREG to Dynamic, as it can't be OFF
1780689a570SEric Huang 		 */
1790689a570SEric Huang 		tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
1800689a570SEric Huang 		data &= ~0x80010;
1810689a570SEric Huang 		data |= 0xe70008;
1820689a570SEric Huang 		if (tmp != data)
1830689a570SEric Huang 			WREG32(mmVCE_CLOCK_GATING_B, data);
1840689a570SEric Huang 		/* Force CLOCK OFF for VCE_UENC_CLOCK_GATING,
1850689a570SEric Huang 		 * Force ClOCK OFF takes precedent over Force CLOCK ON setting.
1860689a570SEric Huang 		 * {*_FORCE_ON, *_FORCE_OFF} = {*, 1}
1870689a570SEric Huang 		 */
1880689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
1890689a570SEric Huang 		data |= 0xffc00000;
1900689a570SEric Huang 		if (tmp != data)
1910689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING, data);
1920689a570SEric Huang 		/* Set VCE_UENC_CLOCK_GATING_2 */
1930689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
1940689a570SEric Huang 		data |= 0x10000;
1950689a570SEric Huang 		if (tmp != data)
1960689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
1970689a570SEric Huang 		/* Set VCE_UENC_REG_CLOCK_GATING to dynamic */
1980689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
1990689a570SEric Huang 		data &= ~0xffc00000;
2000689a570SEric Huang 		if (tmp != data)
2010689a570SEric Huang 			WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
2020689a570SEric Huang 		/* Set VCE_UENC_DMA_DCLK_CTRL CG always in dynamic mode */
2030689a570SEric Huang 		tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
2040689a570SEric Huang 		data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
2050689a570SEric Huang 			  VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
2060689a570SEric Huang 			  VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
2070689a570SEric Huang 			  0x8);
2080689a570SEric Huang 		if (tmp != data)
2090689a570SEric Huang 			WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
2100689a570SEric Huang 	}
2110689a570SEric Huang 	vce_v3_0_override_vce_clock_gating(adev, false);
2120689a570SEric Huang }
2130689a570SEric Huang 
214567e6e29Sjimqu static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev)
215567e6e29Sjimqu {
216567e6e29Sjimqu 	int i, j;
217567e6e29Sjimqu 
218567e6e29Sjimqu 	for (i = 0; i < 10; ++i) {
219567e6e29Sjimqu 		for (j = 0; j < 100; ++j) {
220b7e2e9f7Sjimqu 			uint32_t status = RREG32(mmVCE_STATUS);
221b7e2e9f7Sjimqu 
222567e6e29Sjimqu 			if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK)
223567e6e29Sjimqu 				return 0;
224567e6e29Sjimqu 			mdelay(10);
225567e6e29Sjimqu 		}
226567e6e29Sjimqu 
227567e6e29Sjimqu 		DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
228567e6e29Sjimqu 		WREG32_P(mmVCE_SOFT_RESET,
229567e6e29Sjimqu 			VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
230567e6e29Sjimqu 			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
231567e6e29Sjimqu 		mdelay(10);
232567e6e29Sjimqu 		WREG32_P(mmVCE_SOFT_RESET, 0,
233567e6e29Sjimqu 			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
234567e6e29Sjimqu 		mdelay(10);
235567e6e29Sjimqu 	}
236567e6e29Sjimqu 
237567e6e29Sjimqu 	return -ETIMEDOUT;
238567e6e29Sjimqu }
239567e6e29Sjimqu 
240aaa36a97SAlex Deucher /**
241aaa36a97SAlex Deucher  * vce_v3_0_start - start VCE block
242aaa36a97SAlex Deucher  *
243aaa36a97SAlex Deucher  * @adev: amdgpu_device pointer
244aaa36a97SAlex Deucher  *
245aaa36a97SAlex Deucher  * Setup and start the VCE block
246aaa36a97SAlex Deucher  */
247aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev)
248aaa36a97SAlex Deucher {
249aaa36a97SAlex Deucher 	struct amdgpu_ring *ring;
250567e6e29Sjimqu 	int idx, r;
251567e6e29Sjimqu 
252567e6e29Sjimqu 	ring = &adev->vce.ring[0];
253567e6e29Sjimqu 	WREG32(mmVCE_RB_RPTR, ring->wptr);
254567e6e29Sjimqu 	WREG32(mmVCE_RB_WPTR, ring->wptr);
255567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr);
256567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
257567e6e29Sjimqu 	WREG32(mmVCE_RB_SIZE, ring->ring_size / 4);
258567e6e29Sjimqu 
259567e6e29Sjimqu 	ring = &adev->vce.ring[1];
260567e6e29Sjimqu 	WREG32(mmVCE_RB_RPTR2, ring->wptr);
261567e6e29Sjimqu 	WREG32(mmVCE_RB_WPTR2, ring->wptr);
262567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr);
263567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
264567e6e29Sjimqu 	WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4);
265aaa36a97SAlex Deucher 
2665bbc553aSLeo Liu 	mutex_lock(&adev->grbm_idx_mutex);
2675bbc553aSLeo Liu 	for (idx = 0; idx < 2; ++idx) {
2686a585777SAlex Deucher 		if (adev->vce.harvest_config & (1 << idx))
2696a585777SAlex Deucher 			continue;
2706a585777SAlex Deucher 
2715bbc553aSLeo Liu 		if (idx == 0)
2725bbc553aSLeo Liu 			WREG32_P(mmGRBM_GFX_INDEX, 0,
2735bbc553aSLeo Liu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
2745bbc553aSLeo Liu 		else
2755bbc553aSLeo Liu 			WREG32_P(mmGRBM_GFX_INDEX,
2765bbc553aSLeo Liu 				GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
2775bbc553aSLeo Liu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
2785bbc553aSLeo Liu 
2795bbc553aSLeo Liu 		vce_v3_0_mc_resume(adev, idx);
280aaa36a97SAlex Deucher 
281567e6e29Sjimqu 		WREG32_P(mmVCE_STATUS, VCE_STATUS__JOB_BUSY_MASK,
282567e6e29Sjimqu 		         ~VCE_STATUS__JOB_BUSY_MASK);
283567e6e29Sjimqu 
2843c0ff9f1SLeo Liu 		if (adev->asic_type >= CHIP_STONEY)
2853c0ff9f1SLeo Liu 			WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001);
2863c0ff9f1SLeo Liu 		else
2875bbc553aSLeo Liu 			WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK,
2885bbc553aSLeo Liu 				~VCE_VCPU_CNTL__CLK_EN_MASK);
289aaa36a97SAlex Deucher 
290567e6e29Sjimqu 		WREG32_P(mmVCE_SOFT_RESET, 0,
291aaa36a97SAlex Deucher 			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
292aaa36a97SAlex Deucher 
293aaa36a97SAlex Deucher 		mdelay(100);
294aaa36a97SAlex Deucher 
295567e6e29Sjimqu 		r = vce_v3_0_firmware_loaded(adev);
296aaa36a97SAlex Deucher 
297aaa36a97SAlex Deucher 		/* clear BUSY flag */
298567e6e29Sjimqu 		WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK);
299aaa36a97SAlex Deucher 
3000689a570SEric Huang 		/* Set Clock-Gating off */
301e3b04bc7SAlex Deucher 		if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
3020689a570SEric Huang 			vce_v3_0_set_vce_sw_clock_gating(adev, false);
3030689a570SEric Huang 
304aaa36a97SAlex Deucher 		if (r) {
305aaa36a97SAlex Deucher 			DRM_ERROR("VCE not responding, giving up!!!\n");
3065bbc553aSLeo Liu 			mutex_unlock(&adev->grbm_idx_mutex);
307aaa36a97SAlex Deucher 			return r;
308aaa36a97SAlex Deucher 		}
3095bbc553aSLeo Liu 	}
3105bbc553aSLeo Liu 
3115bbc553aSLeo Liu 	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
3125bbc553aSLeo Liu 	mutex_unlock(&adev->grbm_idx_mutex);
3135bbc553aSLeo Liu 
314567e6e29Sjimqu 	return 0;
315567e6e29Sjimqu }
3165bbc553aSLeo Liu 
317567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev)
318567e6e29Sjimqu {
319567e6e29Sjimqu 	int idx;
320567e6e29Sjimqu 
321567e6e29Sjimqu 	mutex_lock(&adev->grbm_idx_mutex);
322567e6e29Sjimqu 	for (idx = 0; idx < 2; ++idx) {
323567e6e29Sjimqu 		if (adev->vce.harvest_config & (1 << idx))
324567e6e29Sjimqu 			continue;
325567e6e29Sjimqu 
326567e6e29Sjimqu 		if (idx == 0)
327567e6e29Sjimqu 			WREG32_P(mmGRBM_GFX_INDEX, 0,
328567e6e29Sjimqu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
329567e6e29Sjimqu 		else
330567e6e29Sjimqu 			WREG32_P(mmGRBM_GFX_INDEX,
331567e6e29Sjimqu 				GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
332567e6e29Sjimqu 				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
333567e6e29Sjimqu 
334567e6e29Sjimqu 		if (adev->asic_type >= CHIP_STONEY)
335567e6e29Sjimqu 			WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001);
336567e6e29Sjimqu 		else
337567e6e29Sjimqu 			WREG32_P(mmVCE_VCPU_CNTL, 0,
338567e6e29Sjimqu 				~VCE_VCPU_CNTL__CLK_EN_MASK);
339567e6e29Sjimqu 		/* hold on ECPU */
340567e6e29Sjimqu 		WREG32_P(mmVCE_SOFT_RESET,
341567e6e29Sjimqu 			 VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
342567e6e29Sjimqu 			 ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
343567e6e29Sjimqu 
344567e6e29Sjimqu 		/* clear BUSY flag */
345567e6e29Sjimqu 		WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK);
346567e6e29Sjimqu 
347567e6e29Sjimqu 		/* Set Clock-Gating off */
348567e6e29Sjimqu 		if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
349567e6e29Sjimqu 			vce_v3_0_set_vce_sw_clock_gating(adev, false);
350567e6e29Sjimqu 	}
351567e6e29Sjimqu 
352567e6e29Sjimqu 	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
353567e6e29Sjimqu 	mutex_unlock(&adev->grbm_idx_mutex);
354aaa36a97SAlex Deucher 
355aaa36a97SAlex Deucher 	return 0;
356aaa36a97SAlex Deucher }
357aaa36a97SAlex Deucher 
3586a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS     0xC0014074
3596a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT       27
3606a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK        0x18000000
3616a585777SAlex Deucher 
3626a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
3636a585777SAlex Deucher {
3646a585777SAlex Deucher 	u32 tmp;
3656a585777SAlex Deucher 
3662cc0c0b5SFlora Cui 	/* Fiji, Stoney, Polaris10, Polaris11 are single pipe */
367cfaba566SSamuel Li 	if ((adev->asic_type == CHIP_FIJI) ||
3681b4eeea5SSonny Jiang 	    (adev->asic_type == CHIP_STONEY) ||
3692cc0c0b5SFlora Cui 	    (adev->asic_type == CHIP_POLARIS10) ||
3702cc0c0b5SFlora Cui 	    (adev->asic_type == CHIP_POLARIS11))
3711dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
372188a9bcdSAlex Deucher 
373188a9bcdSAlex Deucher 	/* Tonga and CZ are dual or single pipe */
3742f7d10b3SJammy Zhou 	if (adev->flags & AMD_IS_APU)
3756a585777SAlex Deucher 		tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) &
3766a585777SAlex Deucher 		       VCE_HARVEST_FUSE_MACRO__MASK) >>
3776a585777SAlex Deucher 			VCE_HARVEST_FUSE_MACRO__SHIFT;
3786a585777SAlex Deucher 	else
3796a585777SAlex Deucher 		tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) &
3806a585777SAlex Deucher 		       CC_HARVEST_FUSES__VCE_DISABLE_MASK) >>
3816a585777SAlex Deucher 			CC_HARVEST_FUSES__VCE_DISABLE__SHIFT;
3826a585777SAlex Deucher 
3836a585777SAlex Deucher 	switch (tmp) {
3846a585777SAlex Deucher 	case 1:
3851dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0;
3866a585777SAlex Deucher 	case 2:
3871dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
3886a585777SAlex Deucher 	case 3:
3891dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1;
3906a585777SAlex Deucher 	default:
3911dab5f06STom St Denis 		return 0;
3926a585777SAlex Deucher 	}
3936a585777SAlex Deucher }
3946a585777SAlex Deucher 
3955fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle)
396aaa36a97SAlex Deucher {
3975fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
3985fc3aeebSyanyang1 
3996a585777SAlex Deucher 	adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev);
4006a585777SAlex Deucher 
4016a585777SAlex Deucher 	if ((adev->vce.harvest_config &
4026a585777SAlex Deucher 	     (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) ==
4036a585777SAlex Deucher 	    (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1))
4046a585777SAlex Deucher 		return -ENOENT;
4056a585777SAlex Deucher 
406aaa36a97SAlex Deucher 	vce_v3_0_set_ring_funcs(adev);
407aaa36a97SAlex Deucher 	vce_v3_0_set_irq_funcs(adev);
408aaa36a97SAlex Deucher 
409aaa36a97SAlex Deucher 	return 0;
410aaa36a97SAlex Deucher }
411aaa36a97SAlex Deucher 
4125fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle)
413aaa36a97SAlex Deucher {
4145fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
415aaa36a97SAlex Deucher 	struct amdgpu_ring *ring;
416aaa36a97SAlex Deucher 	int r;
417aaa36a97SAlex Deucher 
418aaa36a97SAlex Deucher 	/* VCE */
419aaa36a97SAlex Deucher 	r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq);
420aaa36a97SAlex Deucher 	if (r)
421aaa36a97SAlex Deucher 		return r;
422aaa36a97SAlex Deucher 
423e9822622SLeo Liu 	r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE +
424e9822622SLeo Liu 		(VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2);
425aaa36a97SAlex Deucher 	if (r)
426aaa36a97SAlex Deucher 		return r;
427aaa36a97SAlex Deucher 
428aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
429aaa36a97SAlex Deucher 	if (r)
430aaa36a97SAlex Deucher 		return r;
431aaa36a97SAlex Deucher 
432aaa36a97SAlex Deucher 	ring = &adev->vce.ring[0];
433aaa36a97SAlex Deucher 	sprintf(ring->name, "vce0");
434a3f1cf35SChristian König 	r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
435aaa36a97SAlex Deucher 			     &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
436aaa36a97SAlex Deucher 	if (r)
437aaa36a97SAlex Deucher 		return r;
438aaa36a97SAlex Deucher 
439aaa36a97SAlex Deucher 	ring = &adev->vce.ring[1];
440aaa36a97SAlex Deucher 	sprintf(ring->name, "vce1");
441a3f1cf35SChristian König 	r = amdgpu_ring_init(adev, ring, 512, VCE_CMD_NO_OP, 0xf,
442aaa36a97SAlex Deucher 			     &adev->vce.irq, 0, AMDGPU_RING_TYPE_VCE);
443aaa36a97SAlex Deucher 	if (r)
444aaa36a97SAlex Deucher 		return r;
445aaa36a97SAlex Deucher 
446aaa36a97SAlex Deucher 	return r;
447aaa36a97SAlex Deucher }
448aaa36a97SAlex Deucher 
4495fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle)
450aaa36a97SAlex Deucher {
451aaa36a97SAlex Deucher 	int r;
4525fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
453aaa36a97SAlex Deucher 
454aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
455aaa36a97SAlex Deucher 	if (r)
456aaa36a97SAlex Deucher 		return r;
457aaa36a97SAlex Deucher 
458aaa36a97SAlex Deucher 	r = amdgpu_vce_sw_fini(adev);
459aaa36a97SAlex Deucher 	if (r)
460aaa36a97SAlex Deucher 		return r;
461aaa36a97SAlex Deucher 
462aaa36a97SAlex Deucher 	return r;
463aaa36a97SAlex Deucher }
464aaa36a97SAlex Deucher 
4655fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle)
466aaa36a97SAlex Deucher {
467691ca86aSTom St Denis 	int r, i;
4685fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
469aaa36a97SAlex Deucher 
470aaa36a97SAlex Deucher 	r = vce_v3_0_start(adev);
471aaa36a97SAlex Deucher 	if (r)
472aaa36a97SAlex Deucher 		return r;
473aaa36a97SAlex Deucher 
474691ca86aSTom St Denis 	adev->vce.ring[0].ready = false;
475691ca86aSTom St Denis 	adev->vce.ring[1].ready = false;
476aaa36a97SAlex Deucher 
477691ca86aSTom St Denis 	for (i = 0; i < 2; i++) {
478691ca86aSTom St Denis 		r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
479691ca86aSTom St Denis 		if (r)
480aaa36a97SAlex Deucher 			return r;
481691ca86aSTom St Denis 		else
482691ca86aSTom St Denis 			adev->vce.ring[i].ready = true;
483aaa36a97SAlex Deucher 	}
484aaa36a97SAlex Deucher 
485aaa36a97SAlex Deucher 	DRM_INFO("VCE initialized successfully.\n");
486aaa36a97SAlex Deucher 
487aaa36a97SAlex Deucher 	return 0;
488aaa36a97SAlex Deucher }
489aaa36a97SAlex Deucher 
4905fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle)
491aaa36a97SAlex Deucher {
492567e6e29Sjimqu 	int r;
493567e6e29Sjimqu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
494567e6e29Sjimqu 
495567e6e29Sjimqu 	r = vce_v3_0_wait_for_idle(handle);
496567e6e29Sjimqu 	if (r)
497567e6e29Sjimqu 		return r;
498567e6e29Sjimqu 
499567e6e29Sjimqu 	return vce_v3_0_stop(adev);
500aaa36a97SAlex Deucher }
501aaa36a97SAlex Deucher 
5025fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle)
503aaa36a97SAlex Deucher {
504aaa36a97SAlex Deucher 	int r;
5055fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
506aaa36a97SAlex Deucher 
507aaa36a97SAlex Deucher 	r = vce_v3_0_hw_fini(adev);
508aaa36a97SAlex Deucher 	if (r)
509aaa36a97SAlex Deucher 		return r;
510aaa36a97SAlex Deucher 
511aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
512aaa36a97SAlex Deucher 	if (r)
513aaa36a97SAlex Deucher 		return r;
514aaa36a97SAlex Deucher 
515aaa36a97SAlex Deucher 	return r;
516aaa36a97SAlex Deucher }
517aaa36a97SAlex Deucher 
5185fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle)
519aaa36a97SAlex Deucher {
520aaa36a97SAlex Deucher 	int r;
5215fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
522aaa36a97SAlex Deucher 
523aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
524aaa36a97SAlex Deucher 	if (r)
525aaa36a97SAlex Deucher 		return r;
526aaa36a97SAlex Deucher 
527aaa36a97SAlex Deucher 	r = vce_v3_0_hw_init(adev);
528aaa36a97SAlex Deucher 	if (r)
529aaa36a97SAlex Deucher 		return r;
530aaa36a97SAlex Deucher 
531aaa36a97SAlex Deucher 	return r;
532aaa36a97SAlex Deucher }
533aaa36a97SAlex Deucher 
5345bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx)
535aaa36a97SAlex Deucher {
536aaa36a97SAlex Deucher 	uint32_t offset, size;
537aaa36a97SAlex Deucher 
538aaa36a97SAlex Deucher 	WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16));
539aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000);
540aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F);
541aaa36a97SAlex Deucher 	WREG32(mmVCE_CLOCK_GATING_B, 0xf7);
542aaa36a97SAlex Deucher 
543aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_CTRL, 0x00398000);
544aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1);
545aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL, 0);
546aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL1, 0);
547aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_VM_CTRL, 0);
5483c0ff9f1SLeo Liu 	if (adev->asic_type >= CHIP_STONEY) {
5493c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8));
5503c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8));
5513c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8));
5523c0ff9f1SLeo Liu 	} else
553aaa36a97SAlex Deucher 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
554aaa36a97SAlex Deucher 	offset = AMDGPU_VCE_FIRMWARE_OFFSET;
555e9822622SLeo Liu 	size = VCE_V3_0_FW_SIZE;
556aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
557aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_SIZE0, size);
558aaa36a97SAlex Deucher 
5595bbc553aSLeo Liu 	if (idx == 0) {
560aaa36a97SAlex Deucher 		offset += size;
561e9822622SLeo Liu 		size = VCE_V3_0_STACK_SIZE;
562aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff);
563aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
564aaa36a97SAlex Deucher 		offset += size;
565e9822622SLeo Liu 		size = VCE_V3_0_DATA_SIZE;
566aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff);
567aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5685bbc553aSLeo Liu 	} else {
5695bbc553aSLeo Liu 		offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE;
5705bbc553aSLeo Liu 		size = VCE_V3_0_STACK_SIZE;
5715bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff);
5725bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
5735bbc553aSLeo Liu 		offset += size;
5745bbc553aSLeo Liu 		size = VCE_V3_0_DATA_SIZE;
5755bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff);
5765bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5775bbc553aSLeo Liu 	}
578aaa36a97SAlex Deucher 
579aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100);
580aaa36a97SAlex Deucher 
581aaa36a97SAlex Deucher 	WREG32_P(mmVCE_SYS_INT_EN, VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK,
582aaa36a97SAlex Deucher 		 ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
583aaa36a97SAlex Deucher }
584aaa36a97SAlex Deucher 
5855fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle)
586aaa36a97SAlex Deucher {
5875fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
588be4f38e2SAlex Deucher 	u32 mask = 0;
5895fc3aeebSyanyang1 
59074af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK;
59174af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK;
592be4f38e2SAlex Deucher 
593be4f38e2SAlex Deucher 	return !(RREG32(mmSRBM_STATUS2) & mask);
594aaa36a97SAlex Deucher }
595aaa36a97SAlex Deucher 
5965fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle)
597aaa36a97SAlex Deucher {
598aaa36a97SAlex Deucher 	unsigned i;
5995fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
600be4f38e2SAlex Deucher 
60192988e60STom St Denis 	for (i = 0; i < adev->usec_timeout; i++)
60292988e60STom St Denis 		if (vce_v3_0_is_idle(handle))
603aaa36a97SAlex Deucher 			return 0;
60492988e60STom St Denis 
605aaa36a97SAlex Deucher 	return -ETIMEDOUT;
606aaa36a97SAlex Deucher }
607aaa36a97SAlex Deucher 
608115933a5SChunming Zhou #define AMDGPU_VCE_STATUS_BUSY_MASK    0x78
609115933a5SChunming Zhou 
610115933a5SChunming Zhou static int vce_v3_0_check_soft_reset(void *handle)
611115933a5SChunming Zhou {
612115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
613115933a5SChunming Zhou 	u32 srbm_soft_reset = 0;
614115933a5SChunming Zhou 	u32 tmp;
615115933a5SChunming Zhou 
616115933a5SChunming Zhou 	/* VCE BUG: it is always busy, so skip its checking now */
617115933a5SChunming Zhou 	return 0;
618115933a5SChunming Zhou 
619115933a5SChunming Zhou 	/* According to VCE team , we should use VCE_STATUS instead
620115933a5SChunming Zhou 	 * SRBM_STATUS.VCE_BUSY bit for busy status checking.
621115933a5SChunming Zhou 	 * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE
622115933a5SChunming Zhou 	 * instance's registers are accessed
623115933a5SChunming Zhou 	 * (0 for 1st instance, 10 for 2nd instance).
624115933a5SChunming Zhou 	 *
625115933a5SChunming Zhou 	 *VCE_STATUS
626115933a5SChunming Zhou 	 *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 |          |FW_LOADED|JOB |
627115933a5SChunming Zhou 	 *|----+----+-----------+----+----+----+----------+---------+----|
628115933a5SChunming Zhou 	 *|bit8|bit7|    bit6   |bit5|bit4|bit3|   bit2   |  bit1   |bit0|
629115933a5SChunming Zhou 	 *
630115933a5SChunming Zhou 	 * VCE team suggest use bit 3--bit 6 for busy status check
631115933a5SChunming Zhou 	 */
632115933a5SChunming Zhou 	tmp = RREG32(mmGRBM_GFX_INDEX);
633115933a5SChunming Zhou 	tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
634115933a5SChunming Zhou 	WREG32(mmGRBM_GFX_INDEX, tmp);
635115933a5SChunming Zhou 	if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
636115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
637115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
638115933a5SChunming Zhou 	}
639115933a5SChunming Zhou 	tmp = RREG32(mmGRBM_GFX_INDEX);
640115933a5SChunming Zhou 	tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10);
641115933a5SChunming Zhou 	WREG32(mmGRBM_GFX_INDEX, tmp);
642115933a5SChunming Zhou 	if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
643115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
644115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
645115933a5SChunming Zhou 	}
646115933a5SChunming Zhou 	tmp = RREG32(mmGRBM_GFX_INDEX);
647115933a5SChunming Zhou 	tmp = REG_SET_FIELD(tmp, GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
648115933a5SChunming Zhou 	WREG32(mmGRBM_GFX_INDEX, tmp);
649115933a5SChunming Zhou 
650115933a5SChunming Zhou 	if (adev->vce.harvest_config & (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1))
651115933a5SChunming Zhou 		srbm_soft_reset = 0;
652115933a5SChunming Zhou 
653115933a5SChunming Zhou 	if (srbm_soft_reset) {
654115933a5SChunming Zhou 		adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = true;
655115933a5SChunming Zhou 		adev->vce.srbm_soft_reset = srbm_soft_reset;
656115933a5SChunming Zhou 	} else {
657115933a5SChunming Zhou 		adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = false;
658115933a5SChunming Zhou 		adev->vce.srbm_soft_reset = 0;
659115933a5SChunming Zhou 	}
660115933a5SChunming Zhou 	return 0;
661115933a5SChunming Zhou }
662115933a5SChunming Zhou 
6635fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle)
664aaa36a97SAlex Deucher {
6655fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
666115933a5SChunming Zhou 	u32 srbm_soft_reset;
6675fc3aeebSyanyang1 
668115933a5SChunming Zhou 	if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
669115933a5SChunming Zhou 		return 0;
670115933a5SChunming Zhou 	srbm_soft_reset = adev->vce.srbm_soft_reset;
671be4f38e2SAlex Deucher 
672115933a5SChunming Zhou 	if (srbm_soft_reset) {
673115933a5SChunming Zhou 		u32 tmp;
674115933a5SChunming Zhou 
675115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
676115933a5SChunming Zhou 		tmp |= srbm_soft_reset;
677115933a5SChunming Zhou 		dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
678115933a5SChunming Zhou 		WREG32(mmSRBM_SOFT_RESET, tmp);
679115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
680115933a5SChunming Zhou 
681115933a5SChunming Zhou 		udelay(50);
682115933a5SChunming Zhou 
683115933a5SChunming Zhou 		tmp &= ~srbm_soft_reset;
684115933a5SChunming Zhou 		WREG32(mmSRBM_SOFT_RESET, tmp);
685115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
686115933a5SChunming Zhou 
687115933a5SChunming Zhou 		/* Wait a little for things to settle down */
688115933a5SChunming Zhou 		udelay(50);
689115933a5SChunming Zhou 	}
690115933a5SChunming Zhou 
691115933a5SChunming Zhou 	return 0;
692115933a5SChunming Zhou }
693115933a5SChunming Zhou 
694115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle)
695115933a5SChunming Zhou {
696115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
697115933a5SChunming Zhou 
698115933a5SChunming Zhou 	if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
699115933a5SChunming Zhou 		return 0;
700115933a5SChunming Zhou 
701aaa36a97SAlex Deucher 	mdelay(5);
702aaa36a97SAlex Deucher 
703115933a5SChunming Zhou 	return vce_v3_0_suspend(adev);
704115933a5SChunming Zhou }
705115933a5SChunming Zhou 
706115933a5SChunming Zhou 
707115933a5SChunming Zhou static int vce_v3_0_post_soft_reset(void *handle)
708115933a5SChunming Zhou {
709115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
710115933a5SChunming Zhou 
711115933a5SChunming Zhou 	if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
712115933a5SChunming Zhou 		return 0;
713115933a5SChunming Zhou 
714115933a5SChunming Zhou 	mdelay(5);
715115933a5SChunming Zhou 
716115933a5SChunming Zhou 	return vce_v3_0_resume(adev);
717aaa36a97SAlex Deucher }
718aaa36a97SAlex Deucher 
719aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev,
720aaa36a97SAlex Deucher 					struct amdgpu_irq_src *source,
721aaa36a97SAlex Deucher 					unsigned type,
722aaa36a97SAlex Deucher 					enum amdgpu_interrupt_state state)
723aaa36a97SAlex Deucher {
724aaa36a97SAlex Deucher 	uint32_t val = 0;
725aaa36a97SAlex Deucher 
726aaa36a97SAlex Deucher 	if (state == AMDGPU_IRQ_STATE_ENABLE)
727aaa36a97SAlex Deucher 		val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK;
728aaa36a97SAlex Deucher 
729aaa36a97SAlex Deucher 	WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
730aaa36a97SAlex Deucher 	return 0;
731aaa36a97SAlex Deucher }
732aaa36a97SAlex Deucher 
733aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
734aaa36a97SAlex Deucher 				      struct amdgpu_irq_src *source,
735aaa36a97SAlex Deucher 				      struct amdgpu_iv_entry *entry)
736aaa36a97SAlex Deucher {
737aaa36a97SAlex Deucher 	DRM_DEBUG("IH: VCE\n");
738d6c29c30SLeo Liu 
739d6c29c30SLeo Liu 	WREG32_P(mmVCE_SYS_INT_STATUS,
740d6c29c30SLeo Liu 		VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK,
741d6c29c30SLeo Liu 		~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK);
742d6c29c30SLeo Liu 
743aaa36a97SAlex Deucher 	switch (entry->src_data) {
744aaa36a97SAlex Deucher 	case 0:
745aaa36a97SAlex Deucher 	case 1:
74681da2edeSTom St Denis 		amdgpu_fence_process(&adev->vce.ring[entry->src_data]);
747aaa36a97SAlex Deucher 		break;
748aaa36a97SAlex Deucher 	default:
749aaa36a97SAlex Deucher 		DRM_ERROR("Unhandled interrupt: %d %d\n",
750aaa36a97SAlex Deucher 			  entry->src_id, entry->src_data);
751aaa36a97SAlex Deucher 		break;
752aaa36a97SAlex Deucher 	}
753aaa36a97SAlex Deucher 
754aaa36a97SAlex Deucher 	return 0;
755aaa36a97SAlex Deucher }
756aaa36a97SAlex Deucher 
757ec38f188SRex Zhu static void vce_v3_set_bypass_mode(struct amdgpu_device *adev, bool enable)
758ec38f188SRex Zhu {
759ec38f188SRex Zhu 	u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL);
760ec38f188SRex Zhu 
761ec38f188SRex Zhu 	if (enable)
762ec38f188SRex Zhu 		tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
763ec38f188SRex Zhu 	else
764ec38f188SRex Zhu 		tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
765ec38f188SRex Zhu 
766ec38f188SRex Zhu 	WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp);
767ec38f188SRex Zhu }
768ec38f188SRex Zhu 
7695fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle,
7705fc3aeebSyanyang1 					  enum amd_clockgating_state state)
771aaa36a97SAlex Deucher {
7720689a570SEric Huang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
7730689a570SEric Huang 	bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
7740689a570SEric Huang 	int i;
7750689a570SEric Huang 
776ec38f188SRex Zhu 	if (adev->asic_type == CHIP_POLARIS10)
777ec38f188SRex Zhu 		vce_v3_set_bypass_mode(adev, enable);
778ec38f188SRex Zhu 
779e3b04bc7SAlex Deucher 	if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG))
7800689a570SEric Huang 		return 0;
7810689a570SEric Huang 
7820689a570SEric Huang 	mutex_lock(&adev->grbm_idx_mutex);
7830689a570SEric Huang 	for (i = 0; i < 2; i++) {
7840689a570SEric Huang 		/* Program VCE Instance 0 or 1 if not harvested */
7850689a570SEric Huang 		if (adev->vce.harvest_config & (1 << i))
7860689a570SEric Huang 			continue;
7870689a570SEric Huang 
7880689a570SEric Huang 		if (i == 0)
7890689a570SEric Huang 			WREG32_P(mmGRBM_GFX_INDEX, 0,
7900689a570SEric Huang 					~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
7910689a570SEric Huang 		else
7920689a570SEric Huang 			WREG32_P(mmGRBM_GFX_INDEX,
7930689a570SEric Huang 					GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
7940689a570SEric Huang 					~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
7950689a570SEric Huang 
7960689a570SEric Huang 		if (enable) {
7970689a570SEric Huang 			/* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
7980689a570SEric Huang 			uint32_t data = RREG32(mmVCE_CLOCK_GATING_A);
7990689a570SEric Huang 			data &= ~(0xf | 0xff0);
8000689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
8010689a570SEric Huang 			WREG32(mmVCE_CLOCK_GATING_A, data);
8020689a570SEric Huang 
8030689a570SEric Huang 			/* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */
8040689a570SEric Huang 			data = RREG32(mmVCE_UENC_CLOCK_GATING);
8050689a570SEric Huang 			data &= ~(0xf | 0xff0);
8060689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
8070689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING, data);
8080689a570SEric Huang 		}
8090689a570SEric Huang 
8100689a570SEric Huang 		vce_v3_0_set_vce_sw_clock_gating(adev, enable);
8110689a570SEric Huang 	}
8120689a570SEric Huang 
8130689a570SEric Huang 	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
8140689a570SEric Huang 	mutex_unlock(&adev->grbm_idx_mutex);
8150689a570SEric Huang 
816aaa36a97SAlex Deucher 	return 0;
817aaa36a97SAlex Deucher }
818aaa36a97SAlex Deucher 
8195fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle,
8205fc3aeebSyanyang1 					  enum amd_powergating_state state)
821aaa36a97SAlex Deucher {
822aaa36a97SAlex Deucher 	/* This doesn't actually powergate the VCE block.
823aaa36a97SAlex Deucher 	 * That's done in the dpm code via the SMC.  This
824aaa36a97SAlex Deucher 	 * just re-inits the block as necessary.  The actual
825aaa36a97SAlex Deucher 	 * gating still happens in the dpm code.  We should
826aaa36a97SAlex Deucher 	 * revisit this when there is a cleaner line between
827aaa36a97SAlex Deucher 	 * the smc and the hw blocks
828aaa36a97SAlex Deucher 	 */
8295fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
8305fc3aeebSyanyang1 
831e3b04bc7SAlex Deucher 	if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE))
832808a934fSAlex Deucher 		return 0;
833808a934fSAlex Deucher 
8345fc3aeebSyanyang1 	if (state == AMD_PG_STATE_GATE)
835aaa36a97SAlex Deucher 		/* XXX do we need a vce_v3_0_stop()? */
836aaa36a97SAlex Deucher 		return 0;
837aaa36a97SAlex Deucher 	else
838aaa36a97SAlex Deucher 		return vce_v3_0_start(adev);
839aaa36a97SAlex Deucher }
840aaa36a97SAlex Deucher 
8415fc3aeebSyanyang1 const struct amd_ip_funcs vce_v3_0_ip_funcs = {
84288a907d6STom St Denis 	.name = "vce_v3_0",
843aaa36a97SAlex Deucher 	.early_init = vce_v3_0_early_init,
844aaa36a97SAlex Deucher 	.late_init = NULL,
845aaa36a97SAlex Deucher 	.sw_init = vce_v3_0_sw_init,
846aaa36a97SAlex Deucher 	.sw_fini = vce_v3_0_sw_fini,
847aaa36a97SAlex Deucher 	.hw_init = vce_v3_0_hw_init,
848aaa36a97SAlex Deucher 	.hw_fini = vce_v3_0_hw_fini,
849aaa36a97SAlex Deucher 	.suspend = vce_v3_0_suspend,
850aaa36a97SAlex Deucher 	.resume = vce_v3_0_resume,
851aaa36a97SAlex Deucher 	.is_idle = vce_v3_0_is_idle,
852aaa36a97SAlex Deucher 	.wait_for_idle = vce_v3_0_wait_for_idle,
853115933a5SChunming Zhou 	.check_soft_reset = vce_v3_0_check_soft_reset,
854115933a5SChunming Zhou 	.pre_soft_reset = vce_v3_0_pre_soft_reset,
855aaa36a97SAlex Deucher 	.soft_reset = vce_v3_0_soft_reset,
856115933a5SChunming Zhou 	.post_soft_reset = vce_v3_0_post_soft_reset,
857aaa36a97SAlex Deucher 	.set_clockgating_state = vce_v3_0_set_clockgating_state,
858aaa36a97SAlex Deucher 	.set_powergating_state = vce_v3_0_set_powergating_state,
859aaa36a97SAlex Deucher };
860aaa36a97SAlex Deucher 
861aaa36a97SAlex Deucher static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = {
862aaa36a97SAlex Deucher 	.get_rptr = vce_v3_0_ring_get_rptr,
863aaa36a97SAlex Deucher 	.get_wptr = vce_v3_0_ring_get_wptr,
864aaa36a97SAlex Deucher 	.set_wptr = vce_v3_0_ring_set_wptr,
865aaa36a97SAlex Deucher 	.parse_cs = amdgpu_vce_ring_parse_cs,
866aaa36a97SAlex Deucher 	.emit_ib = amdgpu_vce_ring_emit_ib,
867aaa36a97SAlex Deucher 	.emit_fence = amdgpu_vce_ring_emit_fence,
868aaa36a97SAlex Deucher 	.test_ring = amdgpu_vce_ring_test_ring,
869aaa36a97SAlex Deucher 	.test_ib = amdgpu_vce_ring_test_ib,
870edff0e28SJammy Zhou 	.insert_nop = amdgpu_ring_insert_nop,
8719e5d5309SChristian König 	.pad_ib = amdgpu_ring_generic_pad_ib,
872ebff485eSChristian König 	.begin_use = amdgpu_vce_ring_begin_use,
873ebff485eSChristian König 	.end_use = amdgpu_vce_ring_end_use,
874aaa36a97SAlex Deucher };
875aaa36a97SAlex Deucher 
876aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev)
877aaa36a97SAlex Deucher {
878aaa36a97SAlex Deucher 	adev->vce.ring[0].funcs = &vce_v3_0_ring_funcs;
879aaa36a97SAlex Deucher 	adev->vce.ring[1].funcs = &vce_v3_0_ring_funcs;
880aaa36a97SAlex Deucher }
881aaa36a97SAlex Deucher 
882aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = {
883aaa36a97SAlex Deucher 	.set = vce_v3_0_set_interrupt_state,
884aaa36a97SAlex Deucher 	.process = vce_v3_0_process_interrupt,
885aaa36a97SAlex Deucher };
886aaa36a97SAlex Deucher 
887aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev)
888aaa36a97SAlex Deucher {
889aaa36a97SAlex Deucher 	adev->vce.irq.num_types = 1;
890aaa36a97SAlex Deucher 	adev->vce.irq.funcs = &vce_v3_0_irq_funcs;
891aaa36a97SAlex Deucher };
892