xref: /openbmc/linux/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c (revision a1255107)
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);
736f0359ffSAlex Deucher 	else if (ring == &adev->vce.ring[1])
74aaa36a97SAlex Deucher 		return RREG32(mmVCE_RB_RPTR2);
756f0359ffSAlex Deucher 	else
766f0359ffSAlex Deucher 		return RREG32(mmVCE_RB_RPTR3);
77aaa36a97SAlex Deucher }
78aaa36a97SAlex Deucher 
79aaa36a97SAlex Deucher /**
80aaa36a97SAlex Deucher  * vce_v3_0_ring_get_wptr - get write pointer
81aaa36a97SAlex Deucher  *
82aaa36a97SAlex Deucher  * @ring: amdgpu_ring pointer
83aaa36a97SAlex Deucher  *
84aaa36a97SAlex Deucher  * Returns the current hardware write pointer
85aaa36a97SAlex Deucher  */
86aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring)
87aaa36a97SAlex Deucher {
88aaa36a97SAlex Deucher 	struct amdgpu_device *adev = ring->adev;
89aaa36a97SAlex Deucher 
90aaa36a97SAlex Deucher 	if (ring == &adev->vce.ring[0])
91aaa36a97SAlex Deucher 		return RREG32(mmVCE_RB_WPTR);
926f0359ffSAlex Deucher 	else if (ring == &adev->vce.ring[1])
93aaa36a97SAlex Deucher 		return RREG32(mmVCE_RB_WPTR2);
946f0359ffSAlex Deucher 	else
956f0359ffSAlex Deucher 		return RREG32(mmVCE_RB_WPTR3);
96aaa36a97SAlex Deucher }
97aaa36a97SAlex Deucher 
98aaa36a97SAlex Deucher /**
99aaa36a97SAlex Deucher  * vce_v3_0_ring_set_wptr - set write pointer
100aaa36a97SAlex Deucher  *
101aaa36a97SAlex Deucher  * @ring: amdgpu_ring pointer
102aaa36a97SAlex Deucher  *
103aaa36a97SAlex Deucher  * Commits the write pointer to the hardware
104aaa36a97SAlex Deucher  */
105aaa36a97SAlex Deucher static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring)
106aaa36a97SAlex Deucher {
107aaa36a97SAlex Deucher 	struct amdgpu_device *adev = ring->adev;
108aaa36a97SAlex Deucher 
109aaa36a97SAlex Deucher 	if (ring == &adev->vce.ring[0])
110aaa36a97SAlex Deucher 		WREG32(mmVCE_RB_WPTR, ring->wptr);
1116f0359ffSAlex Deucher 	else if (ring == &adev->vce.ring[1])
112aaa36a97SAlex Deucher 		WREG32(mmVCE_RB_WPTR2, ring->wptr);
1136f0359ffSAlex Deucher 	else
1146f0359ffSAlex Deucher 		WREG32(mmVCE_RB_WPTR3, ring->wptr);
115aaa36a97SAlex Deucher }
116aaa36a97SAlex Deucher 
1170689a570SEric Huang static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override)
1180689a570SEric Huang {
119f3f0ea95STom St Denis 	WREG32_FIELD(VCE_RB_ARB_CTRL, VCE_CGTT_OVERRIDE, override ? 1 : 0);
1200689a570SEric Huang }
1210689a570SEric Huang 
1220689a570SEric Huang static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev,
1230689a570SEric Huang 					     bool gated)
1240689a570SEric Huang {
125f3f0ea95STom St Denis 	u32 data;
126f16fe6d3STom St Denis 
1270689a570SEric Huang 	/* Set Override to disable Clock Gating */
1280689a570SEric Huang 	vce_v3_0_override_vce_clock_gating(adev, true);
1290689a570SEric Huang 
1306f906814STom St Denis 	/* This function enables MGCG which is controlled by firmware.
1316f906814STom St Denis 	   With the clocks in the gated state the core is still
1326f906814STom St Denis 	   accessible but the firmware will throttle the clocks on the
1336f906814STom St Denis 	   fly as necessary.
1340689a570SEric Huang 	*/
1356f906814STom St Denis 	if (gated) {
136f3f0ea95STom St Denis 		data = RREG32(mmVCE_CLOCK_GATING_B);
1370689a570SEric Huang 		data |= 0x1ff;
1380689a570SEric Huang 		data &= ~0xef0000;
1390689a570SEric Huang 		WREG32(mmVCE_CLOCK_GATING_B, data);
1400689a570SEric Huang 
141f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_CLOCK_GATING);
1420689a570SEric Huang 		data |= 0x3ff000;
1430689a570SEric Huang 		data &= ~0xffc00000;
1440689a570SEric Huang 		WREG32(mmVCE_UENC_CLOCK_GATING, data);
1450689a570SEric Huang 
146f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
1470689a570SEric Huang 		data |= 0x2;
1486f906814STom St Denis 		data &= ~0x00010000;
1490689a570SEric Huang 		WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
1500689a570SEric Huang 
151f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
1520689a570SEric Huang 		data |= 0x37f;
1530689a570SEric Huang 		WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
1540689a570SEric Huang 
155f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
1560689a570SEric Huang 		data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
1570689a570SEric Huang 			VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
1580689a570SEric Huang 			VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
1590689a570SEric Huang 			0x8;
1600689a570SEric Huang 		WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
1610689a570SEric Huang 	} else {
162f3f0ea95STom St Denis 		data = RREG32(mmVCE_CLOCK_GATING_B);
1630689a570SEric Huang 		data &= ~0x80010;
1640689a570SEric Huang 		data |= 0xe70008;
1650689a570SEric Huang 		WREG32(mmVCE_CLOCK_GATING_B, data);
1666f906814STom St Denis 
167f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_CLOCK_GATING);
1680689a570SEric Huang 		data |= 0xffc00000;
1690689a570SEric Huang 		WREG32(mmVCE_UENC_CLOCK_GATING, data);
1706f906814STom St Denis 
171f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
1720689a570SEric Huang 		data |= 0x10000;
1730689a570SEric Huang 		WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
1746f906814STom St Denis 
175f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
1760689a570SEric Huang 		data &= ~0xffc00000;
1770689a570SEric Huang 		WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
1786f906814STom St Denis 
179f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
1800689a570SEric Huang 		data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
1810689a570SEric Huang 			  VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
1820689a570SEric Huang 			  VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
1830689a570SEric Huang 			  0x8);
1840689a570SEric Huang 		WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
1850689a570SEric Huang 	}
1860689a570SEric Huang 	vce_v3_0_override_vce_clock_gating(adev, false);
1870689a570SEric Huang }
1880689a570SEric Huang 
189567e6e29Sjimqu static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev)
190567e6e29Sjimqu {
191567e6e29Sjimqu 	int i, j;
192567e6e29Sjimqu 
193567e6e29Sjimqu 	for (i = 0; i < 10; ++i) {
194567e6e29Sjimqu 		for (j = 0; j < 100; ++j) {
195b7e2e9f7Sjimqu 			uint32_t status = RREG32(mmVCE_STATUS);
196b7e2e9f7Sjimqu 
197567e6e29Sjimqu 			if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK)
198567e6e29Sjimqu 				return 0;
199567e6e29Sjimqu 			mdelay(10);
200567e6e29Sjimqu 		}
201567e6e29Sjimqu 
202567e6e29Sjimqu 		DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
203f3f0ea95STom St Denis 		WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1);
204567e6e29Sjimqu 		mdelay(10);
205f3f0ea95STom St Denis 		WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0);
206567e6e29Sjimqu 		mdelay(10);
207567e6e29Sjimqu 	}
208567e6e29Sjimqu 
209567e6e29Sjimqu 	return -ETIMEDOUT;
210567e6e29Sjimqu }
211567e6e29Sjimqu 
212aaa36a97SAlex Deucher /**
213aaa36a97SAlex Deucher  * vce_v3_0_start - start VCE block
214aaa36a97SAlex Deucher  *
215aaa36a97SAlex Deucher  * @adev: amdgpu_device pointer
216aaa36a97SAlex Deucher  *
217aaa36a97SAlex Deucher  * Setup and start the VCE block
218aaa36a97SAlex Deucher  */
219aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev)
220aaa36a97SAlex Deucher {
221aaa36a97SAlex Deucher 	struct amdgpu_ring *ring;
222567e6e29Sjimqu 	int idx, r;
223567e6e29Sjimqu 
224567e6e29Sjimqu 	ring = &adev->vce.ring[0];
225567e6e29Sjimqu 	WREG32(mmVCE_RB_RPTR, ring->wptr);
226567e6e29Sjimqu 	WREG32(mmVCE_RB_WPTR, ring->wptr);
227567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr);
228567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
229567e6e29Sjimqu 	WREG32(mmVCE_RB_SIZE, ring->ring_size / 4);
230567e6e29Sjimqu 
231567e6e29Sjimqu 	ring = &adev->vce.ring[1];
232567e6e29Sjimqu 	WREG32(mmVCE_RB_RPTR2, ring->wptr);
233567e6e29Sjimqu 	WREG32(mmVCE_RB_WPTR2, ring->wptr);
234567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr);
235567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
236567e6e29Sjimqu 	WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4);
237aaa36a97SAlex Deucher 
2386f0359ffSAlex Deucher 	ring = &adev->vce.ring[2];
2396f0359ffSAlex Deucher 	WREG32(mmVCE_RB_RPTR3, ring->wptr);
2406f0359ffSAlex Deucher 	WREG32(mmVCE_RB_WPTR3, ring->wptr);
2416f0359ffSAlex Deucher 	WREG32(mmVCE_RB_BASE_LO3, ring->gpu_addr);
2426f0359ffSAlex Deucher 	WREG32(mmVCE_RB_BASE_HI3, upper_32_bits(ring->gpu_addr));
2436f0359ffSAlex Deucher 	WREG32(mmVCE_RB_SIZE3, ring->ring_size / 4);
2446f0359ffSAlex Deucher 
2455bbc553aSLeo Liu 	mutex_lock(&adev->grbm_idx_mutex);
2465bbc553aSLeo Liu 	for (idx = 0; idx < 2; ++idx) {
2476a585777SAlex Deucher 		if (adev->vce.harvest_config & (1 << idx))
2486a585777SAlex Deucher 			continue;
2496a585777SAlex Deucher 
250f3f0ea95STom St Denis 		WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx);
2515bbc553aSLeo Liu 		vce_v3_0_mc_resume(adev, idx);
252f3f0ea95STom St Denis 		WREG32_FIELD(VCE_STATUS, JOB_BUSY, 1);
253567e6e29Sjimqu 
2543c0ff9f1SLeo Liu 		if (adev->asic_type >= CHIP_STONEY)
2553c0ff9f1SLeo Liu 			WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001);
2563c0ff9f1SLeo Liu 		else
257f3f0ea95STom St Denis 			WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 1);
258aaa36a97SAlex Deucher 
259f3f0ea95STom St Denis 		WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0);
260aaa36a97SAlex Deucher 		mdelay(100);
261aaa36a97SAlex Deucher 
262567e6e29Sjimqu 		r = vce_v3_0_firmware_loaded(adev);
263aaa36a97SAlex Deucher 
264aaa36a97SAlex Deucher 		/* clear BUSY flag */
265f3f0ea95STom St Denis 		WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0);
266aaa36a97SAlex Deucher 
267aaa36a97SAlex Deucher 		if (r) {
268aaa36a97SAlex Deucher 			DRM_ERROR("VCE not responding, giving up!!!\n");
2695bbc553aSLeo Liu 			mutex_unlock(&adev->grbm_idx_mutex);
270aaa36a97SAlex Deucher 			return r;
271aaa36a97SAlex Deucher 		}
2725bbc553aSLeo Liu 	}
2735bbc553aSLeo Liu 
274f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
2755bbc553aSLeo Liu 	mutex_unlock(&adev->grbm_idx_mutex);
2765bbc553aSLeo Liu 
277567e6e29Sjimqu 	return 0;
278567e6e29Sjimqu }
2795bbc553aSLeo Liu 
280567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev)
281567e6e29Sjimqu {
282567e6e29Sjimqu 	int idx;
283567e6e29Sjimqu 
284567e6e29Sjimqu 	mutex_lock(&adev->grbm_idx_mutex);
285567e6e29Sjimqu 	for (idx = 0; idx < 2; ++idx) {
286567e6e29Sjimqu 		if (adev->vce.harvest_config & (1 << idx))
287567e6e29Sjimqu 			continue;
288567e6e29Sjimqu 
289f3f0ea95STom St Denis 		WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx);
290567e6e29Sjimqu 
291567e6e29Sjimqu 		if (adev->asic_type >= CHIP_STONEY)
292567e6e29Sjimqu 			WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001);
293567e6e29Sjimqu 		else
294f3f0ea95STom St Denis 			WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 0);
295f3f0ea95STom St Denis 
296567e6e29Sjimqu 		/* hold on ECPU */
297f3f0ea95STom St Denis 		WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1);
298567e6e29Sjimqu 
299567e6e29Sjimqu 		/* clear BUSY flag */
300f3f0ea95STom St Denis 		WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0);
301567e6e29Sjimqu 
302567e6e29Sjimqu 		/* Set Clock-Gating off */
303567e6e29Sjimqu 		if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
304567e6e29Sjimqu 			vce_v3_0_set_vce_sw_clock_gating(adev, false);
305567e6e29Sjimqu 	}
306567e6e29Sjimqu 
307f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
308567e6e29Sjimqu 	mutex_unlock(&adev->grbm_idx_mutex);
309aaa36a97SAlex Deucher 
310aaa36a97SAlex Deucher 	return 0;
311aaa36a97SAlex Deucher }
312aaa36a97SAlex Deucher 
3136a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS     0xC0014074
3146a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT       27
3156a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK        0x18000000
3166a585777SAlex Deucher 
3176a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
3186a585777SAlex Deucher {
3196a585777SAlex Deucher 	u32 tmp;
3206a585777SAlex Deucher 
3212cc0c0b5SFlora Cui 	/* Fiji, Stoney, Polaris10, Polaris11 are single pipe */
322cfaba566SSamuel Li 	if ((adev->asic_type == CHIP_FIJI) ||
3231b4eeea5SSonny Jiang 	    (adev->asic_type == CHIP_STONEY) ||
3242cc0c0b5SFlora Cui 	    (adev->asic_type == CHIP_POLARIS10) ||
3252cc0c0b5SFlora Cui 	    (adev->asic_type == CHIP_POLARIS11))
3261dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
327188a9bcdSAlex Deucher 
328188a9bcdSAlex Deucher 	/* Tonga and CZ are dual or single pipe */
3292f7d10b3SJammy Zhou 	if (adev->flags & AMD_IS_APU)
3306a585777SAlex Deucher 		tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) &
3316a585777SAlex Deucher 		       VCE_HARVEST_FUSE_MACRO__MASK) >>
3326a585777SAlex Deucher 			VCE_HARVEST_FUSE_MACRO__SHIFT;
3336a585777SAlex Deucher 	else
3346a585777SAlex Deucher 		tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) &
3356a585777SAlex Deucher 		       CC_HARVEST_FUSES__VCE_DISABLE_MASK) >>
3366a585777SAlex Deucher 			CC_HARVEST_FUSES__VCE_DISABLE__SHIFT;
3376a585777SAlex Deucher 
3386a585777SAlex Deucher 	switch (tmp) {
3396a585777SAlex Deucher 	case 1:
3401dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0;
3416a585777SAlex Deucher 	case 2:
3421dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
3436a585777SAlex Deucher 	case 3:
3441dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1;
3456a585777SAlex Deucher 	default:
3461dab5f06STom St Denis 		return 0;
3476a585777SAlex Deucher 	}
3486a585777SAlex Deucher }
3496a585777SAlex Deucher 
3505fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle)
351aaa36a97SAlex Deucher {
3525fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
3535fc3aeebSyanyang1 
3546a585777SAlex Deucher 	adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev);
3556a585777SAlex Deucher 
3566a585777SAlex Deucher 	if ((adev->vce.harvest_config &
3576a585777SAlex Deucher 	     (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) ==
3586a585777SAlex Deucher 	    (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1))
3596a585777SAlex Deucher 		return -ENOENT;
3606a585777SAlex Deucher 
3616f0359ffSAlex Deucher 	adev->vce.num_rings = 3;
36275c65480SAlex Deucher 
363aaa36a97SAlex Deucher 	vce_v3_0_set_ring_funcs(adev);
364aaa36a97SAlex Deucher 	vce_v3_0_set_irq_funcs(adev);
365aaa36a97SAlex Deucher 
366aaa36a97SAlex Deucher 	return 0;
367aaa36a97SAlex Deucher }
368aaa36a97SAlex Deucher 
3695fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle)
370aaa36a97SAlex Deucher {
3715fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
372aaa36a97SAlex Deucher 	struct amdgpu_ring *ring;
37375c65480SAlex Deucher 	int r, i;
374aaa36a97SAlex Deucher 
375aaa36a97SAlex Deucher 	/* VCE */
376aaa36a97SAlex Deucher 	r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq);
377aaa36a97SAlex Deucher 	if (r)
378aaa36a97SAlex Deucher 		return r;
379aaa36a97SAlex Deucher 
380e9822622SLeo Liu 	r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE +
381e9822622SLeo Liu 		(VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2);
382aaa36a97SAlex Deucher 	if (r)
383aaa36a97SAlex Deucher 		return r;
384aaa36a97SAlex Deucher 
385aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
386aaa36a97SAlex Deucher 	if (r)
387aaa36a97SAlex Deucher 		return r;
388aaa36a97SAlex Deucher 
38975c65480SAlex Deucher 	for (i = 0; i < adev->vce.num_rings; i++) {
39075c65480SAlex Deucher 		ring = &adev->vce.ring[i];
39175c65480SAlex Deucher 		sprintf(ring->name, "vce%d", i);
39279887142SChristian König 		r = amdgpu_ring_init(adev, ring, 512, &adev->vce.irq, 0);
393aaa36a97SAlex Deucher 		if (r)
394aaa36a97SAlex Deucher 			return r;
39575c65480SAlex Deucher 	}
396aaa36a97SAlex Deucher 
397aaa36a97SAlex Deucher 	return r;
398aaa36a97SAlex Deucher }
399aaa36a97SAlex Deucher 
4005fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle)
401aaa36a97SAlex Deucher {
402aaa36a97SAlex Deucher 	int r;
4035fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
404aaa36a97SAlex Deucher 
405aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
406aaa36a97SAlex Deucher 	if (r)
407aaa36a97SAlex Deucher 		return r;
408aaa36a97SAlex Deucher 
409aaa36a97SAlex Deucher 	r = amdgpu_vce_sw_fini(adev);
410aaa36a97SAlex Deucher 	if (r)
411aaa36a97SAlex Deucher 		return r;
412aaa36a97SAlex Deucher 
413aaa36a97SAlex Deucher 	return r;
414aaa36a97SAlex Deucher }
415aaa36a97SAlex Deucher 
4165fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle)
417aaa36a97SAlex Deucher {
418691ca86aSTom St Denis 	int r, i;
4195fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
420aaa36a97SAlex Deucher 
421aaa36a97SAlex Deucher 	r = vce_v3_0_start(adev);
422aaa36a97SAlex Deucher 	if (r)
423aaa36a97SAlex Deucher 		return r;
424aaa36a97SAlex Deucher 
42575c65480SAlex Deucher 	for (i = 0; i < adev->vce.num_rings; i++)
42675c65480SAlex Deucher 		adev->vce.ring[i].ready = false;
427aaa36a97SAlex Deucher 
42875c65480SAlex Deucher 	for (i = 0; i < adev->vce.num_rings; i++) {
429691ca86aSTom St Denis 		r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
430691ca86aSTom St Denis 		if (r)
431aaa36a97SAlex Deucher 			return r;
432691ca86aSTom St Denis 		else
433691ca86aSTom St Denis 			adev->vce.ring[i].ready = true;
434aaa36a97SAlex Deucher 	}
435aaa36a97SAlex Deucher 
436aaa36a97SAlex Deucher 	DRM_INFO("VCE initialized successfully.\n");
437aaa36a97SAlex Deucher 
438aaa36a97SAlex Deucher 	return 0;
439aaa36a97SAlex Deucher }
440aaa36a97SAlex Deucher 
4415fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle)
442aaa36a97SAlex Deucher {
443567e6e29Sjimqu 	int r;
444567e6e29Sjimqu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
445567e6e29Sjimqu 
446567e6e29Sjimqu 	r = vce_v3_0_wait_for_idle(handle);
447567e6e29Sjimqu 	if (r)
448567e6e29Sjimqu 		return r;
449567e6e29Sjimqu 
450567e6e29Sjimqu 	return vce_v3_0_stop(adev);
451aaa36a97SAlex Deucher }
452aaa36a97SAlex Deucher 
4535fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle)
454aaa36a97SAlex Deucher {
455aaa36a97SAlex Deucher 	int r;
4565fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
457aaa36a97SAlex Deucher 
458aaa36a97SAlex Deucher 	r = vce_v3_0_hw_fini(adev);
459aaa36a97SAlex Deucher 	if (r)
460aaa36a97SAlex Deucher 		return r;
461aaa36a97SAlex Deucher 
462aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
463aaa36a97SAlex Deucher 	if (r)
464aaa36a97SAlex Deucher 		return r;
465aaa36a97SAlex Deucher 
466aaa36a97SAlex Deucher 	return r;
467aaa36a97SAlex Deucher }
468aaa36a97SAlex Deucher 
4695fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle)
470aaa36a97SAlex Deucher {
471aaa36a97SAlex Deucher 	int r;
4725fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
473aaa36a97SAlex Deucher 
474aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
475aaa36a97SAlex Deucher 	if (r)
476aaa36a97SAlex Deucher 		return r;
477aaa36a97SAlex Deucher 
478aaa36a97SAlex Deucher 	r = vce_v3_0_hw_init(adev);
479aaa36a97SAlex Deucher 	if (r)
480aaa36a97SAlex Deucher 		return r;
481aaa36a97SAlex Deucher 
482aaa36a97SAlex Deucher 	return r;
483aaa36a97SAlex Deucher }
484aaa36a97SAlex Deucher 
4855bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx)
486aaa36a97SAlex Deucher {
487aaa36a97SAlex Deucher 	uint32_t offset, size;
488aaa36a97SAlex Deucher 
489aaa36a97SAlex Deucher 	WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16));
490aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000);
491aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F);
4926f906814STom St Denis 	WREG32(mmVCE_CLOCK_GATING_B, 0x1FF);
493aaa36a97SAlex Deucher 
494aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_CTRL, 0x00398000);
495aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1);
496aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL, 0);
497aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL1, 0);
498aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_VM_CTRL, 0);
4993c0ff9f1SLeo Liu 	if (adev->asic_type >= CHIP_STONEY) {
5003c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8));
5013c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8));
5023c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8));
5033c0ff9f1SLeo Liu 	} else
504aaa36a97SAlex Deucher 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
505aaa36a97SAlex Deucher 	offset = AMDGPU_VCE_FIRMWARE_OFFSET;
506e9822622SLeo Liu 	size = VCE_V3_0_FW_SIZE;
507aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
508aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_SIZE0, size);
509aaa36a97SAlex Deucher 
5105bbc553aSLeo Liu 	if (idx == 0) {
511aaa36a97SAlex Deucher 		offset += size;
512e9822622SLeo Liu 		size = VCE_V3_0_STACK_SIZE;
513aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff);
514aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
515aaa36a97SAlex Deucher 		offset += size;
516e9822622SLeo Liu 		size = VCE_V3_0_DATA_SIZE;
517aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff);
518aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5195bbc553aSLeo Liu 	} else {
5205bbc553aSLeo Liu 		offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE;
5215bbc553aSLeo Liu 		size = VCE_V3_0_STACK_SIZE;
5225bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff);
5235bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
5245bbc553aSLeo Liu 		offset += size;
5255bbc553aSLeo Liu 		size = VCE_V3_0_DATA_SIZE;
5265bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff);
5275bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5285bbc553aSLeo Liu 	}
529aaa36a97SAlex Deucher 
530aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100);
531f3f0ea95STom St Denis 	WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1);
532aaa36a97SAlex Deucher }
533aaa36a97SAlex Deucher 
5345fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle)
535aaa36a97SAlex Deucher {
5365fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
537be4f38e2SAlex Deucher 	u32 mask = 0;
5385fc3aeebSyanyang1 
53974af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK;
54074af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK;
541be4f38e2SAlex Deucher 
542be4f38e2SAlex Deucher 	return !(RREG32(mmSRBM_STATUS2) & mask);
543aaa36a97SAlex Deucher }
544aaa36a97SAlex Deucher 
5455fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle)
546aaa36a97SAlex Deucher {
547aaa36a97SAlex Deucher 	unsigned i;
5485fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
549be4f38e2SAlex Deucher 
55092988e60STom St Denis 	for (i = 0; i < adev->usec_timeout; i++)
55192988e60STom St Denis 		if (vce_v3_0_is_idle(handle))
552aaa36a97SAlex Deucher 			return 0;
55392988e60STom St Denis 
554aaa36a97SAlex Deucher 	return -ETIMEDOUT;
555aaa36a97SAlex Deucher }
556aaa36a97SAlex Deucher 
557ac8e3f30SRex Zhu #define  VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK  0x00000008L   /* AUTO_BUSY */
558ac8e3f30SRex Zhu #define  VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK   0x00000010L   /* RB0_BUSY */
559ac8e3f30SRex Zhu #define  VCE_STATUS_VCPU_REPORT_RB1_BUSY_MASK   0x00000020L   /* RB1_BUSY */
560ac8e3f30SRex Zhu #define  AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \
561ac8e3f30SRex Zhu 				      VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK)
562115933a5SChunming Zhou 
563da146d3bSAlex Deucher static bool vce_v3_0_check_soft_reset(void *handle)
564115933a5SChunming Zhou {
565115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
566115933a5SChunming Zhou 	u32 srbm_soft_reset = 0;
567115933a5SChunming Zhou 
568115933a5SChunming Zhou 	/* According to VCE team , we should use VCE_STATUS instead
569115933a5SChunming Zhou 	 * SRBM_STATUS.VCE_BUSY bit for busy status checking.
570115933a5SChunming Zhou 	 * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE
571115933a5SChunming Zhou 	 * instance's registers are accessed
572115933a5SChunming Zhou 	 * (0 for 1st instance, 10 for 2nd instance).
573115933a5SChunming Zhou 	 *
574115933a5SChunming Zhou 	 *VCE_STATUS
575115933a5SChunming Zhou 	 *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 |          |FW_LOADED|JOB |
576115933a5SChunming Zhou 	 *|----+----+-----------+----+----+----+----------+---------+----|
577115933a5SChunming Zhou 	 *|bit8|bit7|    bit6   |bit5|bit4|bit3|   bit2   |  bit1   |bit0|
578115933a5SChunming Zhou 	 *
579115933a5SChunming Zhou 	 * VCE team suggest use bit 3--bit 6 for busy status check
580115933a5SChunming Zhou 	 */
5819aeb774cSTom St Denis 	mutex_lock(&adev->grbm_idx_mutex);
582f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
583115933a5SChunming Zhou 	if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
584115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
585115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
586115933a5SChunming Zhou 	}
587f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10);
588115933a5SChunming Zhou 	if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
589115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
590115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
591115933a5SChunming Zhou 	}
592f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
593da146d3bSAlex Deucher 	mutex_unlock(&adev->grbm_idx_mutex);
594115933a5SChunming Zhou 
595115933a5SChunming Zhou 	if (srbm_soft_reset) {
596115933a5SChunming Zhou 		adev->vce.srbm_soft_reset = srbm_soft_reset;
597da146d3bSAlex Deucher 		return true;
598115933a5SChunming Zhou 	} else {
599115933a5SChunming Zhou 		adev->vce.srbm_soft_reset = 0;
600da146d3bSAlex Deucher 		return false;
601115933a5SChunming Zhou 	}
602115933a5SChunming Zhou }
603115933a5SChunming Zhou 
6045fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle)
605aaa36a97SAlex Deucher {
6065fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
607115933a5SChunming Zhou 	u32 srbm_soft_reset;
6085fc3aeebSyanyang1 
609da146d3bSAlex Deucher 	if (!adev->vce.srbm_soft_reset)
610115933a5SChunming Zhou 		return 0;
611115933a5SChunming Zhou 	srbm_soft_reset = adev->vce.srbm_soft_reset;
612be4f38e2SAlex Deucher 
613115933a5SChunming Zhou 	if (srbm_soft_reset) {
614115933a5SChunming Zhou 		u32 tmp;
615115933a5SChunming Zhou 
616115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
617115933a5SChunming Zhou 		tmp |= srbm_soft_reset;
618115933a5SChunming Zhou 		dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
619115933a5SChunming Zhou 		WREG32(mmSRBM_SOFT_RESET, tmp);
620115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
621115933a5SChunming Zhou 
622115933a5SChunming Zhou 		udelay(50);
623115933a5SChunming Zhou 
624115933a5SChunming Zhou 		tmp &= ~srbm_soft_reset;
625115933a5SChunming Zhou 		WREG32(mmSRBM_SOFT_RESET, tmp);
626115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
627115933a5SChunming Zhou 
628115933a5SChunming Zhou 		/* Wait a little for things to settle down */
629115933a5SChunming Zhou 		udelay(50);
630115933a5SChunming Zhou 	}
631115933a5SChunming Zhou 
632115933a5SChunming Zhou 	return 0;
633115933a5SChunming Zhou }
634115933a5SChunming Zhou 
635115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle)
636115933a5SChunming Zhou {
637115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
638115933a5SChunming Zhou 
639da146d3bSAlex Deucher 	if (!adev->vce.srbm_soft_reset)
640115933a5SChunming Zhou 		return 0;
641115933a5SChunming Zhou 
642aaa36a97SAlex Deucher 	mdelay(5);
643aaa36a97SAlex Deucher 
644115933a5SChunming Zhou 	return vce_v3_0_suspend(adev);
645115933a5SChunming Zhou }
646115933a5SChunming Zhou 
647115933a5SChunming Zhou 
648115933a5SChunming Zhou static int vce_v3_0_post_soft_reset(void *handle)
649115933a5SChunming Zhou {
650115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
651115933a5SChunming Zhou 
652da146d3bSAlex Deucher 	if (!adev->vce.srbm_soft_reset)
653115933a5SChunming Zhou 		return 0;
654115933a5SChunming Zhou 
655115933a5SChunming Zhou 	mdelay(5);
656115933a5SChunming Zhou 
657115933a5SChunming Zhou 	return vce_v3_0_resume(adev);
658aaa36a97SAlex Deucher }
659aaa36a97SAlex Deucher 
660aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev,
661aaa36a97SAlex Deucher 					struct amdgpu_irq_src *source,
662aaa36a97SAlex Deucher 					unsigned type,
663aaa36a97SAlex Deucher 					enum amdgpu_interrupt_state state)
664aaa36a97SAlex Deucher {
665aaa36a97SAlex Deucher 	uint32_t val = 0;
666aaa36a97SAlex Deucher 
667aaa36a97SAlex Deucher 	if (state == AMDGPU_IRQ_STATE_ENABLE)
668aaa36a97SAlex Deucher 		val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK;
669aaa36a97SAlex Deucher 
670aaa36a97SAlex Deucher 	WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
671aaa36a97SAlex Deucher 	return 0;
672aaa36a97SAlex Deucher }
673aaa36a97SAlex Deucher 
674aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
675aaa36a97SAlex Deucher 				      struct amdgpu_irq_src *source,
676aaa36a97SAlex Deucher 				      struct amdgpu_iv_entry *entry)
677aaa36a97SAlex Deucher {
678aaa36a97SAlex Deucher 	DRM_DEBUG("IH: VCE\n");
679d6c29c30SLeo Liu 
680f3f0ea95STom St Denis 	WREG32_FIELD(VCE_SYS_INT_STATUS, VCE_SYS_INT_TRAP_INTERRUPT_INT, 1);
681d6c29c30SLeo Liu 
682aaa36a97SAlex Deucher 	switch (entry->src_data) {
683aaa36a97SAlex Deucher 	case 0:
684aaa36a97SAlex Deucher 	case 1:
6856f0359ffSAlex Deucher 	case 2:
68681da2edeSTom St Denis 		amdgpu_fence_process(&adev->vce.ring[entry->src_data]);
687aaa36a97SAlex Deucher 		break;
688aaa36a97SAlex Deucher 	default:
689aaa36a97SAlex Deucher 		DRM_ERROR("Unhandled interrupt: %d %d\n",
690aaa36a97SAlex Deucher 			  entry->src_id, entry->src_data);
691aaa36a97SAlex Deucher 		break;
692aaa36a97SAlex Deucher 	}
693aaa36a97SAlex Deucher 
694aaa36a97SAlex Deucher 	return 0;
695aaa36a97SAlex Deucher }
696aaa36a97SAlex Deucher 
6970174df4eSRex Zhu static void vce_v3_0_set_bypass_mode(struct amdgpu_device *adev, bool enable)
698ec38f188SRex Zhu {
699ec38f188SRex Zhu 	u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL);
700ec38f188SRex Zhu 
701ec38f188SRex Zhu 	if (enable)
702ec38f188SRex Zhu 		tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
703ec38f188SRex Zhu 	else
704ec38f188SRex Zhu 		tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
705ec38f188SRex Zhu 
706ec38f188SRex Zhu 	WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp);
707ec38f188SRex Zhu }
708ec38f188SRex Zhu 
7095fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle,
7105fc3aeebSyanyang1 					  enum amd_clockgating_state state)
711aaa36a97SAlex Deucher {
7120689a570SEric Huang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
7130689a570SEric Huang 	bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
7140689a570SEric Huang 	int i;
7150689a570SEric Huang 
716c04399f1SRex Zhu 	if ((adev->asic_type == CHIP_POLARIS10) ||
7173374dcebSRex Zhu 		(adev->asic_type == CHIP_TONGA) ||
7183374dcebSRex Zhu 		(adev->asic_type == CHIP_FIJI))
7190174df4eSRex Zhu 		vce_v3_0_set_bypass_mode(adev, enable);
720ec38f188SRex Zhu 
721e3b04bc7SAlex Deucher 	if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG))
7220689a570SEric Huang 		return 0;
7230689a570SEric Huang 
7240689a570SEric Huang 	mutex_lock(&adev->grbm_idx_mutex);
7250689a570SEric Huang 	for (i = 0; i < 2; i++) {
7260689a570SEric Huang 		/* Program VCE Instance 0 or 1 if not harvested */
7270689a570SEric Huang 		if (adev->vce.harvest_config & (1 << i))
7280689a570SEric Huang 			continue;
7290689a570SEric Huang 
730f3f0ea95STom St Denis 		WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i);
7310689a570SEric Huang 
7320689a570SEric Huang 		if (enable) {
7330689a570SEric Huang 			/* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
7340689a570SEric Huang 			uint32_t data = RREG32(mmVCE_CLOCK_GATING_A);
7350689a570SEric Huang 			data &= ~(0xf | 0xff0);
7360689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
7370689a570SEric Huang 			WREG32(mmVCE_CLOCK_GATING_A, data);
7380689a570SEric Huang 
7390689a570SEric Huang 			/* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */
7400689a570SEric Huang 			data = RREG32(mmVCE_UENC_CLOCK_GATING);
7410689a570SEric Huang 			data &= ~(0xf | 0xff0);
7420689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
7430689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING, data);
7440689a570SEric Huang 		}
7450689a570SEric Huang 
7460689a570SEric Huang 		vce_v3_0_set_vce_sw_clock_gating(adev, enable);
7470689a570SEric Huang 	}
7480689a570SEric Huang 
749f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
7500689a570SEric Huang 	mutex_unlock(&adev->grbm_idx_mutex);
7510689a570SEric Huang 
752aaa36a97SAlex Deucher 	return 0;
753aaa36a97SAlex Deucher }
754aaa36a97SAlex Deucher 
7555fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle,
7565fc3aeebSyanyang1 					  enum amd_powergating_state state)
757aaa36a97SAlex Deucher {
758aaa36a97SAlex Deucher 	/* This doesn't actually powergate the VCE block.
759aaa36a97SAlex Deucher 	 * That's done in the dpm code via the SMC.  This
760aaa36a97SAlex Deucher 	 * just re-inits the block as necessary.  The actual
761aaa36a97SAlex Deucher 	 * gating still happens in the dpm code.  We should
762aaa36a97SAlex Deucher 	 * revisit this when there is a cleaner line between
763aaa36a97SAlex Deucher 	 * the smc and the hw blocks
764aaa36a97SAlex Deucher 	 */
7655fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
7665fc3aeebSyanyang1 
767e3b04bc7SAlex Deucher 	if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE))
768808a934fSAlex Deucher 		return 0;
769808a934fSAlex Deucher 
7705fc3aeebSyanyang1 	if (state == AMD_PG_STATE_GATE)
771aaa36a97SAlex Deucher 		/* XXX do we need a vce_v3_0_stop()? */
772aaa36a97SAlex Deucher 		return 0;
773aaa36a97SAlex Deucher 	else
774aaa36a97SAlex Deucher 		return vce_v3_0_start(adev);
775aaa36a97SAlex Deucher }
776aaa36a97SAlex Deucher 
777ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring,
778ea4a8c1dSMaruthi Srinivas Bayyavarapu 		struct amdgpu_ib *ib, unsigned int vm_id, bool ctx_switch)
779ea4a8c1dSMaruthi Srinivas Bayyavarapu {
780ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_IB_VM);
781ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, vm_id);
782ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
783ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
784ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, ib->length_dw);
785ea4a8c1dSMaruthi Srinivas Bayyavarapu }
786ea4a8c1dSMaruthi Srinivas Bayyavarapu 
787ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring,
788ea4a8c1dSMaruthi Srinivas Bayyavarapu 			 unsigned int vm_id, uint64_t pd_addr)
789ea4a8c1dSMaruthi Srinivas Bayyavarapu {
790ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_UPDATE_PTB);
791ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, vm_id);
792ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, pd_addr >> 12);
793ea4a8c1dSMaruthi Srinivas Bayyavarapu 
794ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_FLUSH_TLB);
795ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, vm_id);
796ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_END);
797ea4a8c1dSMaruthi Srinivas Bayyavarapu }
798ea4a8c1dSMaruthi Srinivas Bayyavarapu 
799ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_pipeline_sync(struct amdgpu_ring *ring)
800ea4a8c1dSMaruthi Srinivas Bayyavarapu {
801ea4a8c1dSMaruthi Srinivas Bayyavarapu 	uint32_t seq = ring->fence_drv.sync_seq;
802ea4a8c1dSMaruthi Srinivas Bayyavarapu 	uint64_t addr = ring->fence_drv.gpu_addr;
803ea4a8c1dSMaruthi Srinivas Bayyavarapu 
804ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_WAIT_GE);
805ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, lower_32_bits(addr));
806ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, upper_32_bits(addr));
807ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, seq);
808ea4a8c1dSMaruthi Srinivas Bayyavarapu }
809ea4a8c1dSMaruthi Srinivas Bayyavarapu 
810a1255107SAlex Deucher static const struct amd_ip_funcs vce_v3_0_ip_funcs = {
81188a907d6STom St Denis 	.name = "vce_v3_0",
812aaa36a97SAlex Deucher 	.early_init = vce_v3_0_early_init,
813aaa36a97SAlex Deucher 	.late_init = NULL,
814aaa36a97SAlex Deucher 	.sw_init = vce_v3_0_sw_init,
815aaa36a97SAlex Deucher 	.sw_fini = vce_v3_0_sw_fini,
816aaa36a97SAlex Deucher 	.hw_init = vce_v3_0_hw_init,
817aaa36a97SAlex Deucher 	.hw_fini = vce_v3_0_hw_fini,
818aaa36a97SAlex Deucher 	.suspend = vce_v3_0_suspend,
819aaa36a97SAlex Deucher 	.resume = vce_v3_0_resume,
820aaa36a97SAlex Deucher 	.is_idle = vce_v3_0_is_idle,
821aaa36a97SAlex Deucher 	.wait_for_idle = vce_v3_0_wait_for_idle,
822115933a5SChunming Zhou 	.check_soft_reset = vce_v3_0_check_soft_reset,
823115933a5SChunming Zhou 	.pre_soft_reset = vce_v3_0_pre_soft_reset,
824aaa36a97SAlex Deucher 	.soft_reset = vce_v3_0_soft_reset,
825115933a5SChunming Zhou 	.post_soft_reset = vce_v3_0_post_soft_reset,
826aaa36a97SAlex Deucher 	.set_clockgating_state = vce_v3_0_set_clockgating_state,
827aaa36a97SAlex Deucher 	.set_powergating_state = vce_v3_0_set_powergating_state,
828aaa36a97SAlex Deucher };
829aaa36a97SAlex Deucher 
830ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = {
83121cd942eSChristian König 	.type = AMDGPU_RING_TYPE_VCE,
83279887142SChristian König 	.align_mask = 0xf,
83379887142SChristian König 	.nop = VCE_CMD_NO_OP,
834aaa36a97SAlex Deucher 	.get_rptr = vce_v3_0_ring_get_rptr,
835aaa36a97SAlex Deucher 	.get_wptr = vce_v3_0_ring_get_wptr,
836aaa36a97SAlex Deucher 	.set_wptr = vce_v3_0_ring_set_wptr,
837aaa36a97SAlex Deucher 	.parse_cs = amdgpu_vce_ring_parse_cs,
838e12f3d7aSChristian König 	.emit_frame_size =
839e12f3d7aSChristian König 		4 + /* vce_v3_0_emit_pipeline_sync */
840e12f3d7aSChristian König 		6, /* amdgpu_vce_ring_emit_fence x1 no user fence */
841e12f3d7aSChristian König 	.emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */
842aaa36a97SAlex Deucher 	.emit_ib = amdgpu_vce_ring_emit_ib,
843aaa36a97SAlex Deucher 	.emit_fence = amdgpu_vce_ring_emit_fence,
844aaa36a97SAlex Deucher 	.test_ring = amdgpu_vce_ring_test_ring,
845aaa36a97SAlex Deucher 	.test_ib = amdgpu_vce_ring_test_ib,
846edff0e28SJammy Zhou 	.insert_nop = amdgpu_ring_insert_nop,
8479e5d5309SChristian König 	.pad_ib = amdgpu_ring_generic_pad_ib,
848ebff485eSChristian König 	.begin_use = amdgpu_vce_ring_begin_use,
849ebff485eSChristian König 	.end_use = amdgpu_vce_ring_end_use,
850aaa36a97SAlex Deucher };
851aaa36a97SAlex Deucher 
852ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = {
85321cd942eSChristian König 	.type = AMDGPU_RING_TYPE_VCE,
85479887142SChristian König 	.align_mask = 0xf,
85579887142SChristian König 	.nop = VCE_CMD_NO_OP,
856ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.get_rptr = vce_v3_0_ring_get_rptr,
857ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.get_wptr = vce_v3_0_ring_get_wptr,
858ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.set_wptr = vce_v3_0_ring_set_wptr,
859e12f3d7aSChristian König 	.emit_frame_size =
860e12f3d7aSChristian König 		6 + /* vce_v3_0_emit_vm_flush */
861e12f3d7aSChristian König 		4 + /* vce_v3_0_emit_pipeline_sync */
862e12f3d7aSChristian König 		6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */
863e12f3d7aSChristian König 	.emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */
864ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.emit_ib = vce_v3_0_ring_emit_ib,
865ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.emit_vm_flush = vce_v3_0_emit_vm_flush,
866ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.emit_pipeline_sync = vce_v3_0_emit_pipeline_sync,
867ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.emit_fence = amdgpu_vce_ring_emit_fence,
868ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.test_ring = amdgpu_vce_ring_test_ring,
869ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.test_ib = amdgpu_vce_ring_test_ib,
870ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.insert_nop = amdgpu_ring_insert_nop,
871ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.pad_ib = amdgpu_ring_generic_pad_ib,
872ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.begin_use = amdgpu_vce_ring_begin_use,
873ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.end_use = amdgpu_vce_ring_end_use,
874ea4a8c1dSMaruthi Srinivas Bayyavarapu };
875ea4a8c1dSMaruthi Srinivas Bayyavarapu 
876aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev)
877aaa36a97SAlex Deucher {
87875c65480SAlex Deucher 	int i;
87975c65480SAlex Deucher 
880ea4a8c1dSMaruthi Srinivas Bayyavarapu 	if (adev->asic_type >= CHIP_STONEY) {
88175c65480SAlex Deucher 		for (i = 0; i < adev->vce.num_rings; i++)
882ea4a8c1dSMaruthi Srinivas Bayyavarapu 			adev->vce.ring[i].funcs = &vce_v3_0_ring_vm_funcs;
883ea4a8c1dSMaruthi Srinivas Bayyavarapu 		DRM_INFO("VCE enabled in VM mode\n");
884ea4a8c1dSMaruthi Srinivas Bayyavarapu 	} else {
885ea4a8c1dSMaruthi Srinivas Bayyavarapu 		for (i = 0; i < adev->vce.num_rings; i++)
886ea4a8c1dSMaruthi Srinivas Bayyavarapu 			adev->vce.ring[i].funcs = &vce_v3_0_ring_phys_funcs;
887ea4a8c1dSMaruthi Srinivas Bayyavarapu 		DRM_INFO("VCE enabled in physical mode\n");
888ea4a8c1dSMaruthi Srinivas Bayyavarapu 	}
889aaa36a97SAlex Deucher }
890aaa36a97SAlex Deucher 
891aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = {
892aaa36a97SAlex Deucher 	.set = vce_v3_0_set_interrupt_state,
893aaa36a97SAlex Deucher 	.process = vce_v3_0_process_interrupt,
894aaa36a97SAlex Deucher };
895aaa36a97SAlex Deucher 
896aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev)
897aaa36a97SAlex Deucher {
898aaa36a97SAlex Deucher 	adev->vce.irq.num_types = 1;
899aaa36a97SAlex Deucher 	adev->vce.irq.funcs = &vce_v3_0_irq_funcs;
900aaa36a97SAlex Deucher };
901a1255107SAlex Deucher 
902a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_0_ip_block =
903a1255107SAlex Deucher {
904a1255107SAlex Deucher 	.type = AMD_IP_BLOCK_TYPE_VCE,
905a1255107SAlex Deucher 	.major = 3,
906a1255107SAlex Deucher 	.minor = 0,
907a1255107SAlex Deucher 	.rev = 0,
908a1255107SAlex Deucher 	.funcs = &vce_v3_0_ip_funcs,
909a1255107SAlex Deucher };
910a1255107SAlex Deucher 
911a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_1_ip_block =
912a1255107SAlex Deucher {
913a1255107SAlex Deucher 	.type = AMD_IP_BLOCK_TYPE_VCE,
914a1255107SAlex Deucher 	.major = 3,
915a1255107SAlex Deucher 	.minor = 1,
916a1255107SAlex Deucher 	.rev = 0,
917a1255107SAlex Deucher 	.funcs = &vce_v3_0_ip_funcs,
918a1255107SAlex Deucher };
919a1255107SAlex Deucher 
920a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_4_ip_block =
921a1255107SAlex Deucher {
922a1255107SAlex Deucher 	.type = AMD_IP_BLOCK_TYPE_VCE,
923a1255107SAlex Deucher 	.major = 3,
924a1255107SAlex Deucher 	.minor = 4,
925a1255107SAlex Deucher 	.rev = 0,
926a1255107SAlex Deucher 	.funcs = &vce_v3_0_ip_funcs,
927a1255107SAlex Deucher };
928