xref: /openbmc/linux/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c (revision e05208de)
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 
55ef6239e0SAlex Deucher #define FW_52_8_3	((52 << 24) | (8 << 16) | (3 << 8))
56ef6239e0SAlex Deucher 
575bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx);
58aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev);
59aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev);
60567e6e29Sjimqu static int vce_v3_0_wait_for_idle(void *handle);
61aaa36a97SAlex Deucher 
62aaa36a97SAlex Deucher /**
63aaa36a97SAlex Deucher  * vce_v3_0_ring_get_rptr - get read pointer
64aaa36a97SAlex Deucher  *
65aaa36a97SAlex Deucher  * @ring: amdgpu_ring pointer
66aaa36a97SAlex Deucher  *
67aaa36a97SAlex Deucher  * Returns the current hardware read pointer
68aaa36a97SAlex Deucher  */
69aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring)
70aaa36a97SAlex Deucher {
71aaa36a97SAlex Deucher 	struct amdgpu_device *adev = ring->adev;
72aaa36a97SAlex Deucher 
73aaa36a97SAlex Deucher 	if (ring == &adev->vce.ring[0])
74aaa36a97SAlex Deucher 		return RREG32(mmVCE_RB_RPTR);
756f0359ffSAlex Deucher 	else if (ring == &adev->vce.ring[1])
76aaa36a97SAlex Deucher 		return RREG32(mmVCE_RB_RPTR2);
776f0359ffSAlex Deucher 	else
786f0359ffSAlex Deucher 		return RREG32(mmVCE_RB_RPTR3);
79aaa36a97SAlex Deucher }
80aaa36a97SAlex Deucher 
81aaa36a97SAlex Deucher /**
82aaa36a97SAlex Deucher  * vce_v3_0_ring_get_wptr - get write pointer
83aaa36a97SAlex Deucher  *
84aaa36a97SAlex Deucher  * @ring: amdgpu_ring pointer
85aaa36a97SAlex Deucher  *
86aaa36a97SAlex Deucher  * Returns the current hardware write pointer
87aaa36a97SAlex Deucher  */
88aaa36a97SAlex Deucher static uint32_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring)
89aaa36a97SAlex Deucher {
90aaa36a97SAlex Deucher 	struct amdgpu_device *adev = ring->adev;
91aaa36a97SAlex Deucher 
92aaa36a97SAlex Deucher 	if (ring == &adev->vce.ring[0])
93aaa36a97SAlex Deucher 		return RREG32(mmVCE_RB_WPTR);
946f0359ffSAlex Deucher 	else if (ring == &adev->vce.ring[1])
95aaa36a97SAlex Deucher 		return RREG32(mmVCE_RB_WPTR2);
966f0359ffSAlex Deucher 	else
976f0359ffSAlex Deucher 		return RREG32(mmVCE_RB_WPTR3);
98aaa36a97SAlex Deucher }
99aaa36a97SAlex Deucher 
100aaa36a97SAlex Deucher /**
101aaa36a97SAlex Deucher  * vce_v3_0_ring_set_wptr - set write pointer
102aaa36a97SAlex Deucher  *
103aaa36a97SAlex Deucher  * @ring: amdgpu_ring pointer
104aaa36a97SAlex Deucher  *
105aaa36a97SAlex Deucher  * Commits the write pointer to the hardware
106aaa36a97SAlex Deucher  */
107aaa36a97SAlex Deucher static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring)
108aaa36a97SAlex Deucher {
109aaa36a97SAlex Deucher 	struct amdgpu_device *adev = ring->adev;
110aaa36a97SAlex Deucher 
111aaa36a97SAlex Deucher 	if (ring == &adev->vce.ring[0])
112aaa36a97SAlex Deucher 		WREG32(mmVCE_RB_WPTR, ring->wptr);
1136f0359ffSAlex Deucher 	else if (ring == &adev->vce.ring[1])
114aaa36a97SAlex Deucher 		WREG32(mmVCE_RB_WPTR2, ring->wptr);
1156f0359ffSAlex Deucher 	else
1166f0359ffSAlex Deucher 		WREG32(mmVCE_RB_WPTR3, ring->wptr);
117aaa36a97SAlex Deucher }
118aaa36a97SAlex Deucher 
1190689a570SEric Huang static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override)
1200689a570SEric Huang {
121f3f0ea95STom St Denis 	WREG32_FIELD(VCE_RB_ARB_CTRL, VCE_CGTT_OVERRIDE, override ? 1 : 0);
1220689a570SEric Huang }
1230689a570SEric Huang 
1240689a570SEric Huang static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev,
1250689a570SEric Huang 					     bool gated)
1260689a570SEric Huang {
127f3f0ea95STom St Denis 	u32 data;
128f16fe6d3STom St Denis 
1290689a570SEric Huang 	/* Set Override to disable Clock Gating */
1300689a570SEric Huang 	vce_v3_0_override_vce_clock_gating(adev, true);
1310689a570SEric Huang 
1326f906814STom St Denis 	/* This function enables MGCG which is controlled by firmware.
1336f906814STom St Denis 	   With the clocks in the gated state the core is still
1346f906814STom St Denis 	   accessible but the firmware will throttle the clocks on the
1356f906814STom St Denis 	   fly as necessary.
1360689a570SEric Huang 	*/
137ecc2cf7cSMaruthi Srinivas Bayyavarapu 	if (!gated) {
138f3f0ea95STom St Denis 		data = RREG32(mmVCE_CLOCK_GATING_B);
1390689a570SEric Huang 		data |= 0x1ff;
1400689a570SEric Huang 		data &= ~0xef0000;
1410689a570SEric Huang 		WREG32(mmVCE_CLOCK_GATING_B, data);
1420689a570SEric Huang 
143f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_CLOCK_GATING);
1440689a570SEric Huang 		data |= 0x3ff000;
1450689a570SEric Huang 		data &= ~0xffc00000;
1460689a570SEric Huang 		WREG32(mmVCE_UENC_CLOCK_GATING, data);
1470689a570SEric Huang 
148f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
1490689a570SEric Huang 		data |= 0x2;
1506f906814STom St Denis 		data &= ~0x00010000;
1510689a570SEric Huang 		WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
1520689a570SEric Huang 
153f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
1540689a570SEric Huang 		data |= 0x37f;
1550689a570SEric Huang 		WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
1560689a570SEric Huang 
157f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
1580689a570SEric Huang 		data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
1590689a570SEric Huang 			VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
1600689a570SEric Huang 			VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
1610689a570SEric Huang 			0x8;
1620689a570SEric Huang 		WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
1630689a570SEric Huang 	} else {
164f3f0ea95STom St Denis 		data = RREG32(mmVCE_CLOCK_GATING_B);
1650689a570SEric Huang 		data &= ~0x80010;
1660689a570SEric Huang 		data |= 0xe70008;
1670689a570SEric Huang 		WREG32(mmVCE_CLOCK_GATING_B, data);
1686f906814STom St Denis 
169f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_CLOCK_GATING);
1700689a570SEric Huang 		data |= 0xffc00000;
1710689a570SEric Huang 		WREG32(mmVCE_UENC_CLOCK_GATING, data);
1726f906814STom St Denis 
173f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
1740689a570SEric Huang 		data |= 0x10000;
1750689a570SEric Huang 		WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
1766f906814STom St Denis 
177f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
178e05208deSRex Zhu 		data &= ~0x3ff;
1790689a570SEric Huang 		WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
1806f906814STom St Denis 
181f3f0ea95STom St Denis 		data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
1820689a570SEric Huang 		data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
1830689a570SEric Huang 			  VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
1840689a570SEric Huang 			  VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK  |
1850689a570SEric Huang 			  0x8);
1860689a570SEric Huang 		WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
1870689a570SEric Huang 	}
1880689a570SEric Huang 	vce_v3_0_override_vce_clock_gating(adev, false);
1890689a570SEric Huang }
1900689a570SEric Huang 
191567e6e29Sjimqu static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev)
192567e6e29Sjimqu {
193567e6e29Sjimqu 	int i, j;
194567e6e29Sjimqu 
195567e6e29Sjimqu 	for (i = 0; i < 10; ++i) {
196567e6e29Sjimqu 		for (j = 0; j < 100; ++j) {
197b7e2e9f7Sjimqu 			uint32_t status = RREG32(mmVCE_STATUS);
198b7e2e9f7Sjimqu 
199567e6e29Sjimqu 			if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK)
200567e6e29Sjimqu 				return 0;
201567e6e29Sjimqu 			mdelay(10);
202567e6e29Sjimqu 		}
203567e6e29Sjimqu 
204567e6e29Sjimqu 		DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
205f3f0ea95STom St Denis 		WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1);
206567e6e29Sjimqu 		mdelay(10);
207f3f0ea95STom St Denis 		WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0);
208567e6e29Sjimqu 		mdelay(10);
209567e6e29Sjimqu 	}
210567e6e29Sjimqu 
211567e6e29Sjimqu 	return -ETIMEDOUT;
212567e6e29Sjimqu }
213567e6e29Sjimqu 
214aaa36a97SAlex Deucher /**
215aaa36a97SAlex Deucher  * vce_v3_0_start - start VCE block
216aaa36a97SAlex Deucher  *
217aaa36a97SAlex Deucher  * @adev: amdgpu_device pointer
218aaa36a97SAlex Deucher  *
219aaa36a97SAlex Deucher  * Setup and start the VCE block
220aaa36a97SAlex Deucher  */
221aaa36a97SAlex Deucher static int vce_v3_0_start(struct amdgpu_device *adev)
222aaa36a97SAlex Deucher {
223aaa36a97SAlex Deucher 	struct amdgpu_ring *ring;
224567e6e29Sjimqu 	int idx, r;
225567e6e29Sjimqu 
226567e6e29Sjimqu 	ring = &adev->vce.ring[0];
227567e6e29Sjimqu 	WREG32(mmVCE_RB_RPTR, ring->wptr);
228567e6e29Sjimqu 	WREG32(mmVCE_RB_WPTR, ring->wptr);
229567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr);
230567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
231567e6e29Sjimqu 	WREG32(mmVCE_RB_SIZE, ring->ring_size / 4);
232567e6e29Sjimqu 
233567e6e29Sjimqu 	ring = &adev->vce.ring[1];
234567e6e29Sjimqu 	WREG32(mmVCE_RB_RPTR2, ring->wptr);
235567e6e29Sjimqu 	WREG32(mmVCE_RB_WPTR2, ring->wptr);
236567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr);
237567e6e29Sjimqu 	WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
238567e6e29Sjimqu 	WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4);
239aaa36a97SAlex Deucher 
2406f0359ffSAlex Deucher 	ring = &adev->vce.ring[2];
2416f0359ffSAlex Deucher 	WREG32(mmVCE_RB_RPTR3, ring->wptr);
2426f0359ffSAlex Deucher 	WREG32(mmVCE_RB_WPTR3, ring->wptr);
2436f0359ffSAlex Deucher 	WREG32(mmVCE_RB_BASE_LO3, ring->gpu_addr);
2446f0359ffSAlex Deucher 	WREG32(mmVCE_RB_BASE_HI3, upper_32_bits(ring->gpu_addr));
2456f0359ffSAlex Deucher 	WREG32(mmVCE_RB_SIZE3, ring->ring_size / 4);
2466f0359ffSAlex Deucher 
2475bbc553aSLeo Liu 	mutex_lock(&adev->grbm_idx_mutex);
2485bbc553aSLeo Liu 	for (idx = 0; idx < 2; ++idx) {
2496a585777SAlex Deucher 		if (adev->vce.harvest_config & (1 << idx))
2506a585777SAlex Deucher 			continue;
2516a585777SAlex Deucher 
252f3f0ea95STom St Denis 		WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx);
2535bbc553aSLeo Liu 		vce_v3_0_mc_resume(adev, idx);
254f3f0ea95STom St Denis 		WREG32_FIELD(VCE_STATUS, JOB_BUSY, 1);
255567e6e29Sjimqu 
2563c0ff9f1SLeo Liu 		if (adev->asic_type >= CHIP_STONEY)
2573c0ff9f1SLeo Liu 			WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001);
2583c0ff9f1SLeo Liu 		else
259f3f0ea95STom St Denis 			WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 1);
260aaa36a97SAlex Deucher 
261f3f0ea95STom St Denis 		WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0);
262aaa36a97SAlex Deucher 		mdelay(100);
263aaa36a97SAlex Deucher 
264567e6e29Sjimqu 		r = vce_v3_0_firmware_loaded(adev);
265aaa36a97SAlex Deucher 
266aaa36a97SAlex Deucher 		/* clear BUSY flag */
267f3f0ea95STom St Denis 		WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0);
268aaa36a97SAlex Deucher 
269aaa36a97SAlex Deucher 		if (r) {
270aaa36a97SAlex Deucher 			DRM_ERROR("VCE not responding, giving up!!!\n");
2715bbc553aSLeo Liu 			mutex_unlock(&adev->grbm_idx_mutex);
272aaa36a97SAlex Deucher 			return r;
273aaa36a97SAlex Deucher 		}
2745bbc553aSLeo Liu 	}
2755bbc553aSLeo Liu 
276f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
2775bbc553aSLeo Liu 	mutex_unlock(&adev->grbm_idx_mutex);
2785bbc553aSLeo Liu 
279567e6e29Sjimqu 	return 0;
280567e6e29Sjimqu }
2815bbc553aSLeo Liu 
282567e6e29Sjimqu static int vce_v3_0_stop(struct amdgpu_device *adev)
283567e6e29Sjimqu {
284567e6e29Sjimqu 	int idx;
285567e6e29Sjimqu 
286567e6e29Sjimqu 	mutex_lock(&adev->grbm_idx_mutex);
287567e6e29Sjimqu 	for (idx = 0; idx < 2; ++idx) {
288567e6e29Sjimqu 		if (adev->vce.harvest_config & (1 << idx))
289567e6e29Sjimqu 			continue;
290567e6e29Sjimqu 
291f3f0ea95STom St Denis 		WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx);
292567e6e29Sjimqu 
293567e6e29Sjimqu 		if (adev->asic_type >= CHIP_STONEY)
294567e6e29Sjimqu 			WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001);
295567e6e29Sjimqu 		else
296f3f0ea95STom St Denis 			WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 0);
297f3f0ea95STom St Denis 
298567e6e29Sjimqu 		/* hold on ECPU */
299f3f0ea95STom St Denis 		WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1);
300567e6e29Sjimqu 
301567e6e29Sjimqu 		/* clear BUSY flag */
302f3f0ea95STom St Denis 		WREG32_FIELD(VCE_STATUS, JOB_BUSY, 0);
303567e6e29Sjimqu 
304567e6e29Sjimqu 		/* Set Clock-Gating off */
305567e6e29Sjimqu 		if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
306567e6e29Sjimqu 			vce_v3_0_set_vce_sw_clock_gating(adev, false);
307567e6e29Sjimqu 	}
308567e6e29Sjimqu 
309f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
310567e6e29Sjimqu 	mutex_unlock(&adev->grbm_idx_mutex);
311aaa36a97SAlex Deucher 
312aaa36a97SAlex Deucher 	return 0;
313aaa36a97SAlex Deucher }
314aaa36a97SAlex Deucher 
3156a585777SAlex Deucher #define ixVCE_HARVEST_FUSE_MACRO__ADDRESS     0xC0014074
3166a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__SHIFT       27
3176a585777SAlex Deucher #define VCE_HARVEST_FUSE_MACRO__MASK        0x18000000
3186a585777SAlex Deucher 
3196a585777SAlex Deucher static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
3206a585777SAlex Deucher {
3216a585777SAlex Deucher 	u32 tmp;
3226a585777SAlex Deucher 
323c4642a47SJunwei Zhang 	/* Fiji, Stoney, Polaris10, Polaris11, Polaris12 are single pipe */
324cfaba566SSamuel Li 	if ((adev->asic_type == CHIP_FIJI) ||
3251b4eeea5SSonny Jiang 	    (adev->asic_type == CHIP_STONEY) ||
3262cc0c0b5SFlora Cui 	    (adev->asic_type == CHIP_POLARIS10) ||
327c4642a47SJunwei Zhang 	    (adev->asic_type == CHIP_POLARIS11) ||
328c4642a47SJunwei Zhang 	    (adev->asic_type == CHIP_POLARIS12))
3291dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
330188a9bcdSAlex Deucher 
331188a9bcdSAlex Deucher 	/* Tonga and CZ are dual or single pipe */
3322f7d10b3SJammy Zhou 	if (adev->flags & AMD_IS_APU)
3336a585777SAlex Deucher 		tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) &
3346a585777SAlex Deucher 		       VCE_HARVEST_FUSE_MACRO__MASK) >>
3356a585777SAlex Deucher 			VCE_HARVEST_FUSE_MACRO__SHIFT;
3366a585777SAlex Deucher 	else
3376a585777SAlex Deucher 		tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) &
3386a585777SAlex Deucher 		       CC_HARVEST_FUSES__VCE_DISABLE_MASK) >>
3396a585777SAlex Deucher 			CC_HARVEST_FUSES__VCE_DISABLE__SHIFT;
3406a585777SAlex Deucher 
3416a585777SAlex Deucher 	switch (tmp) {
3426a585777SAlex Deucher 	case 1:
3431dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0;
3446a585777SAlex Deucher 	case 2:
3451dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
3466a585777SAlex Deucher 	case 3:
3471dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1;
3486a585777SAlex Deucher 	default:
3491dab5f06STom St Denis 		return 0;
3506a585777SAlex Deucher 	}
3516a585777SAlex Deucher }
3526a585777SAlex Deucher 
3535fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle)
354aaa36a97SAlex Deucher {
3555fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
3565fc3aeebSyanyang1 
3576a585777SAlex Deucher 	adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev);
3586a585777SAlex Deucher 
3596a585777SAlex Deucher 	if ((adev->vce.harvest_config &
3606a585777SAlex Deucher 	     (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) ==
3616a585777SAlex Deucher 	    (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1))
3626a585777SAlex Deucher 		return -ENOENT;
3636a585777SAlex Deucher 
3646f0359ffSAlex Deucher 	adev->vce.num_rings = 3;
36575c65480SAlex Deucher 
366aaa36a97SAlex Deucher 	vce_v3_0_set_ring_funcs(adev);
367aaa36a97SAlex Deucher 	vce_v3_0_set_irq_funcs(adev);
368aaa36a97SAlex Deucher 
369aaa36a97SAlex Deucher 	return 0;
370aaa36a97SAlex Deucher }
371aaa36a97SAlex Deucher 
3725fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle)
373aaa36a97SAlex Deucher {
3745fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
375aaa36a97SAlex Deucher 	struct amdgpu_ring *ring;
37675c65480SAlex Deucher 	int r, i;
377aaa36a97SAlex Deucher 
378aaa36a97SAlex Deucher 	/* VCE */
379aaa36a97SAlex Deucher 	r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq);
380aaa36a97SAlex Deucher 	if (r)
381aaa36a97SAlex Deucher 		return r;
382aaa36a97SAlex Deucher 
383e9822622SLeo Liu 	r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE +
384e9822622SLeo Liu 		(VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2);
385aaa36a97SAlex Deucher 	if (r)
386aaa36a97SAlex Deucher 		return r;
387aaa36a97SAlex Deucher 
388ef6239e0SAlex Deucher 	/* 52.8.3 required for 3 ring support */
389ef6239e0SAlex Deucher 	if (adev->vce.fw_version < FW_52_8_3)
390ef6239e0SAlex Deucher 		adev->vce.num_rings = 2;
391ef6239e0SAlex Deucher 
392aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
393aaa36a97SAlex Deucher 	if (r)
394aaa36a97SAlex Deucher 		return r;
395aaa36a97SAlex Deucher 
39675c65480SAlex Deucher 	for (i = 0; i < adev->vce.num_rings; i++) {
39775c65480SAlex Deucher 		ring = &adev->vce.ring[i];
39875c65480SAlex Deucher 		sprintf(ring->name, "vce%d", i);
39979887142SChristian König 		r = amdgpu_ring_init(adev, ring, 512, &adev->vce.irq, 0);
400aaa36a97SAlex Deucher 		if (r)
401aaa36a97SAlex Deucher 			return r;
40275c65480SAlex Deucher 	}
403aaa36a97SAlex Deucher 
404aaa36a97SAlex Deucher 	return r;
405aaa36a97SAlex Deucher }
406aaa36a97SAlex Deucher 
4075fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle)
408aaa36a97SAlex Deucher {
409aaa36a97SAlex Deucher 	int r;
4105fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
411aaa36a97SAlex Deucher 
412aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
413aaa36a97SAlex Deucher 	if (r)
414aaa36a97SAlex Deucher 		return r;
415aaa36a97SAlex Deucher 
416aaa36a97SAlex Deucher 	r = amdgpu_vce_sw_fini(adev);
417aaa36a97SAlex Deucher 	if (r)
418aaa36a97SAlex Deucher 		return r;
419aaa36a97SAlex Deucher 
420aaa36a97SAlex Deucher 	return r;
421aaa36a97SAlex Deucher }
422aaa36a97SAlex Deucher 
4235fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle)
424aaa36a97SAlex Deucher {
425691ca86aSTom St Denis 	int r, i;
4265fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
427aaa36a97SAlex Deucher 
428aaa36a97SAlex Deucher 	r = vce_v3_0_start(adev);
429aaa36a97SAlex Deucher 	if (r)
430aaa36a97SAlex Deucher 		return r;
431aaa36a97SAlex Deucher 
43275c65480SAlex Deucher 	for (i = 0; i < adev->vce.num_rings; i++)
43375c65480SAlex Deucher 		adev->vce.ring[i].ready = false;
434aaa36a97SAlex Deucher 
43575c65480SAlex Deucher 	for (i = 0; i < adev->vce.num_rings; i++) {
436691ca86aSTom St Denis 		r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
437691ca86aSTom St Denis 		if (r)
438aaa36a97SAlex Deucher 			return r;
439691ca86aSTom St Denis 		else
440691ca86aSTom St Denis 			adev->vce.ring[i].ready = true;
441aaa36a97SAlex Deucher 	}
442aaa36a97SAlex Deucher 
443aaa36a97SAlex Deucher 	DRM_INFO("VCE initialized successfully.\n");
444aaa36a97SAlex Deucher 
445aaa36a97SAlex Deucher 	return 0;
446aaa36a97SAlex Deucher }
447aaa36a97SAlex Deucher 
4485fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle)
449aaa36a97SAlex Deucher {
450567e6e29Sjimqu 	int r;
451567e6e29Sjimqu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
452567e6e29Sjimqu 
453567e6e29Sjimqu 	r = vce_v3_0_wait_for_idle(handle);
454567e6e29Sjimqu 	if (r)
455567e6e29Sjimqu 		return r;
456567e6e29Sjimqu 
457567e6e29Sjimqu 	return vce_v3_0_stop(adev);
458aaa36a97SAlex Deucher }
459aaa36a97SAlex Deucher 
4605fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle)
461aaa36a97SAlex Deucher {
462aaa36a97SAlex Deucher 	int r;
4635fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
464aaa36a97SAlex Deucher 
465aaa36a97SAlex Deucher 	r = vce_v3_0_hw_fini(adev);
466aaa36a97SAlex Deucher 	if (r)
467aaa36a97SAlex Deucher 		return r;
468aaa36a97SAlex Deucher 
469aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
470aaa36a97SAlex Deucher 	if (r)
471aaa36a97SAlex Deucher 		return r;
472aaa36a97SAlex Deucher 
473aaa36a97SAlex Deucher 	return r;
474aaa36a97SAlex Deucher }
475aaa36a97SAlex Deucher 
4765fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle)
477aaa36a97SAlex Deucher {
478aaa36a97SAlex Deucher 	int r;
4795fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
480aaa36a97SAlex Deucher 
481aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
482aaa36a97SAlex Deucher 	if (r)
483aaa36a97SAlex Deucher 		return r;
484aaa36a97SAlex Deucher 
485aaa36a97SAlex Deucher 	r = vce_v3_0_hw_init(adev);
486aaa36a97SAlex Deucher 	if (r)
487aaa36a97SAlex Deucher 		return r;
488aaa36a97SAlex Deucher 
489aaa36a97SAlex Deucher 	return r;
490aaa36a97SAlex Deucher }
491aaa36a97SAlex Deucher 
4925bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx)
493aaa36a97SAlex Deucher {
494aaa36a97SAlex Deucher 	uint32_t offset, size;
495aaa36a97SAlex Deucher 
496aaa36a97SAlex Deucher 	WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16));
497aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000);
498aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F);
4996f906814STom St Denis 	WREG32(mmVCE_CLOCK_GATING_B, 0x1FF);
500aaa36a97SAlex Deucher 
501aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_CTRL, 0x00398000);
502aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1);
503aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL, 0);
504aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL1, 0);
505aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_VM_CTRL, 0);
5063c0ff9f1SLeo Liu 	if (adev->asic_type >= CHIP_STONEY) {
5073c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8));
5083c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8));
5093c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8));
5103c0ff9f1SLeo Liu 	} else
511aaa36a97SAlex Deucher 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
512aaa36a97SAlex Deucher 	offset = AMDGPU_VCE_FIRMWARE_OFFSET;
513e9822622SLeo Liu 	size = VCE_V3_0_FW_SIZE;
514aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
515aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_SIZE0, size);
516aaa36a97SAlex Deucher 
5175bbc553aSLeo Liu 	if (idx == 0) {
518aaa36a97SAlex Deucher 		offset += size;
519e9822622SLeo Liu 		size = VCE_V3_0_STACK_SIZE;
520aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff);
521aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
522aaa36a97SAlex Deucher 		offset += size;
523e9822622SLeo Liu 		size = VCE_V3_0_DATA_SIZE;
524aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff);
525aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5265bbc553aSLeo Liu 	} else {
5275bbc553aSLeo Liu 		offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE;
5285bbc553aSLeo Liu 		size = VCE_V3_0_STACK_SIZE;
5295bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff);
5305bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
5315bbc553aSLeo Liu 		offset += size;
5325bbc553aSLeo Liu 		size = VCE_V3_0_DATA_SIZE;
5335bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff);
5345bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5355bbc553aSLeo Liu 	}
536aaa36a97SAlex Deucher 
537aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100);
538f3f0ea95STom St Denis 	WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1);
539aaa36a97SAlex Deucher }
540aaa36a97SAlex Deucher 
5415fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle)
542aaa36a97SAlex Deucher {
5435fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
544be4f38e2SAlex Deucher 	u32 mask = 0;
5455fc3aeebSyanyang1 
54674af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK;
54774af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK;
548be4f38e2SAlex Deucher 
549be4f38e2SAlex Deucher 	return !(RREG32(mmSRBM_STATUS2) & mask);
550aaa36a97SAlex Deucher }
551aaa36a97SAlex Deucher 
5525fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle)
553aaa36a97SAlex Deucher {
554aaa36a97SAlex Deucher 	unsigned i;
5555fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
556be4f38e2SAlex Deucher 
55792988e60STom St Denis 	for (i = 0; i < adev->usec_timeout; i++)
55892988e60STom St Denis 		if (vce_v3_0_is_idle(handle))
559aaa36a97SAlex Deucher 			return 0;
56092988e60STom St Denis 
561aaa36a97SAlex Deucher 	return -ETIMEDOUT;
562aaa36a97SAlex Deucher }
563aaa36a97SAlex Deucher 
564ac8e3f30SRex Zhu #define  VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK  0x00000008L   /* AUTO_BUSY */
565ac8e3f30SRex Zhu #define  VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK   0x00000010L   /* RB0_BUSY */
566ac8e3f30SRex Zhu #define  VCE_STATUS_VCPU_REPORT_RB1_BUSY_MASK   0x00000020L   /* RB1_BUSY */
567ac8e3f30SRex Zhu #define  AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \
568ac8e3f30SRex Zhu 				      VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK)
569115933a5SChunming Zhou 
570da146d3bSAlex Deucher static bool vce_v3_0_check_soft_reset(void *handle)
571115933a5SChunming Zhou {
572115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
573115933a5SChunming Zhou 	u32 srbm_soft_reset = 0;
574115933a5SChunming Zhou 
575115933a5SChunming Zhou 	/* According to VCE team , we should use VCE_STATUS instead
576115933a5SChunming Zhou 	 * SRBM_STATUS.VCE_BUSY bit for busy status checking.
577115933a5SChunming Zhou 	 * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE
578115933a5SChunming Zhou 	 * instance's registers are accessed
579115933a5SChunming Zhou 	 * (0 for 1st instance, 10 for 2nd instance).
580115933a5SChunming Zhou 	 *
581115933a5SChunming Zhou 	 *VCE_STATUS
582115933a5SChunming Zhou 	 *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 |          |FW_LOADED|JOB |
583115933a5SChunming Zhou 	 *|----+----+-----------+----+----+----+----------+---------+----|
584115933a5SChunming Zhou 	 *|bit8|bit7|    bit6   |bit5|bit4|bit3|   bit2   |  bit1   |bit0|
585115933a5SChunming Zhou 	 *
586115933a5SChunming Zhou 	 * VCE team suggest use bit 3--bit 6 for busy status check
587115933a5SChunming Zhou 	 */
5889aeb774cSTom St Denis 	mutex_lock(&adev->grbm_idx_mutex);
589f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
590115933a5SChunming Zhou 	if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
591115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
592115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
593115933a5SChunming Zhou 	}
594f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10);
595115933a5SChunming Zhou 	if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
596115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
597115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
598115933a5SChunming Zhou 	}
599f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
600da146d3bSAlex Deucher 	mutex_unlock(&adev->grbm_idx_mutex);
601115933a5SChunming Zhou 
602115933a5SChunming Zhou 	if (srbm_soft_reset) {
603115933a5SChunming Zhou 		adev->vce.srbm_soft_reset = srbm_soft_reset;
604da146d3bSAlex Deucher 		return true;
605115933a5SChunming Zhou 	} else {
606115933a5SChunming Zhou 		adev->vce.srbm_soft_reset = 0;
607da146d3bSAlex Deucher 		return false;
608115933a5SChunming Zhou 	}
609115933a5SChunming Zhou }
610115933a5SChunming Zhou 
6115fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle)
612aaa36a97SAlex Deucher {
6135fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
614115933a5SChunming Zhou 	u32 srbm_soft_reset;
6155fc3aeebSyanyang1 
616da146d3bSAlex Deucher 	if (!adev->vce.srbm_soft_reset)
617115933a5SChunming Zhou 		return 0;
618115933a5SChunming Zhou 	srbm_soft_reset = adev->vce.srbm_soft_reset;
619be4f38e2SAlex Deucher 
620115933a5SChunming Zhou 	if (srbm_soft_reset) {
621115933a5SChunming Zhou 		u32 tmp;
622115933a5SChunming Zhou 
623115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
624115933a5SChunming Zhou 		tmp |= srbm_soft_reset;
625115933a5SChunming Zhou 		dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
626115933a5SChunming Zhou 		WREG32(mmSRBM_SOFT_RESET, tmp);
627115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
628115933a5SChunming Zhou 
629115933a5SChunming Zhou 		udelay(50);
630115933a5SChunming Zhou 
631115933a5SChunming Zhou 		tmp &= ~srbm_soft_reset;
632115933a5SChunming Zhou 		WREG32(mmSRBM_SOFT_RESET, tmp);
633115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
634115933a5SChunming Zhou 
635115933a5SChunming Zhou 		/* Wait a little for things to settle down */
636115933a5SChunming Zhou 		udelay(50);
637115933a5SChunming Zhou 	}
638115933a5SChunming Zhou 
639115933a5SChunming Zhou 	return 0;
640115933a5SChunming Zhou }
641115933a5SChunming Zhou 
642115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle)
643115933a5SChunming Zhou {
644115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
645115933a5SChunming Zhou 
646da146d3bSAlex Deucher 	if (!adev->vce.srbm_soft_reset)
647115933a5SChunming Zhou 		return 0;
648115933a5SChunming Zhou 
649aaa36a97SAlex Deucher 	mdelay(5);
650aaa36a97SAlex Deucher 
651115933a5SChunming Zhou 	return vce_v3_0_suspend(adev);
652115933a5SChunming Zhou }
653115933a5SChunming Zhou 
654115933a5SChunming Zhou 
655115933a5SChunming Zhou static int vce_v3_0_post_soft_reset(void *handle)
656115933a5SChunming Zhou {
657115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
658115933a5SChunming Zhou 
659da146d3bSAlex Deucher 	if (!adev->vce.srbm_soft_reset)
660115933a5SChunming Zhou 		return 0;
661115933a5SChunming Zhou 
662115933a5SChunming Zhou 	mdelay(5);
663115933a5SChunming Zhou 
664115933a5SChunming Zhou 	return vce_v3_0_resume(adev);
665aaa36a97SAlex Deucher }
666aaa36a97SAlex Deucher 
667aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev,
668aaa36a97SAlex Deucher 					struct amdgpu_irq_src *source,
669aaa36a97SAlex Deucher 					unsigned type,
670aaa36a97SAlex Deucher 					enum amdgpu_interrupt_state state)
671aaa36a97SAlex Deucher {
672aaa36a97SAlex Deucher 	uint32_t val = 0;
673aaa36a97SAlex Deucher 
674aaa36a97SAlex Deucher 	if (state == AMDGPU_IRQ_STATE_ENABLE)
675aaa36a97SAlex Deucher 		val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK;
676aaa36a97SAlex Deucher 
677aaa36a97SAlex Deucher 	WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
678aaa36a97SAlex Deucher 	return 0;
679aaa36a97SAlex Deucher }
680aaa36a97SAlex Deucher 
681aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
682aaa36a97SAlex Deucher 				      struct amdgpu_irq_src *source,
683aaa36a97SAlex Deucher 				      struct amdgpu_iv_entry *entry)
684aaa36a97SAlex Deucher {
685aaa36a97SAlex Deucher 	DRM_DEBUG("IH: VCE\n");
686d6c29c30SLeo Liu 
687f3f0ea95STom St Denis 	WREG32_FIELD(VCE_SYS_INT_STATUS, VCE_SYS_INT_TRAP_INTERRUPT_INT, 1);
688d6c29c30SLeo Liu 
689aaa36a97SAlex Deucher 	switch (entry->src_data) {
690aaa36a97SAlex Deucher 	case 0:
691aaa36a97SAlex Deucher 	case 1:
6926f0359ffSAlex Deucher 	case 2:
69381da2edeSTom St Denis 		amdgpu_fence_process(&adev->vce.ring[entry->src_data]);
694aaa36a97SAlex Deucher 		break;
695aaa36a97SAlex Deucher 	default:
696aaa36a97SAlex Deucher 		DRM_ERROR("Unhandled interrupt: %d %d\n",
697aaa36a97SAlex Deucher 			  entry->src_id, entry->src_data);
698aaa36a97SAlex Deucher 		break;
699aaa36a97SAlex Deucher 	}
700aaa36a97SAlex Deucher 
701aaa36a97SAlex Deucher 	return 0;
702aaa36a97SAlex Deucher }
703aaa36a97SAlex Deucher 
7040174df4eSRex Zhu static void vce_v3_0_set_bypass_mode(struct amdgpu_device *adev, bool enable)
705ec38f188SRex Zhu {
706ec38f188SRex Zhu 	u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL);
707ec38f188SRex Zhu 
708ec38f188SRex Zhu 	if (enable)
709ec38f188SRex Zhu 		tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
710ec38f188SRex Zhu 	else
711ec38f188SRex Zhu 		tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
712ec38f188SRex Zhu 
713ec38f188SRex Zhu 	WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp);
714ec38f188SRex Zhu }
715ec38f188SRex Zhu 
7165fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle,
7175fc3aeebSyanyang1 					  enum amd_clockgating_state state)
718aaa36a97SAlex Deucher {
7190689a570SEric Huang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
7200689a570SEric Huang 	bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
7210689a570SEric Huang 	int i;
7220689a570SEric Huang 
723c04399f1SRex Zhu 	if ((adev->asic_type == CHIP_POLARIS10) ||
7243374dcebSRex Zhu 		(adev->asic_type == CHIP_TONGA) ||
7253374dcebSRex Zhu 		(adev->asic_type == CHIP_FIJI))
7260174df4eSRex Zhu 		vce_v3_0_set_bypass_mode(adev, enable);
727ec38f188SRex Zhu 
728e3b04bc7SAlex Deucher 	if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG))
7290689a570SEric Huang 		return 0;
7300689a570SEric Huang 
7310689a570SEric Huang 	mutex_lock(&adev->grbm_idx_mutex);
7320689a570SEric Huang 	for (i = 0; i < 2; i++) {
7330689a570SEric Huang 		/* Program VCE Instance 0 or 1 if not harvested */
7340689a570SEric Huang 		if (adev->vce.harvest_config & (1 << i))
7350689a570SEric Huang 			continue;
7360689a570SEric Huang 
737f3f0ea95STom St Denis 		WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i);
7380689a570SEric Huang 
7390689a570SEric Huang 		if (enable) {
7400689a570SEric Huang 			/* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
7410689a570SEric Huang 			uint32_t data = RREG32(mmVCE_CLOCK_GATING_A);
7420689a570SEric Huang 			data &= ~(0xf | 0xff0);
7430689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
7440689a570SEric Huang 			WREG32(mmVCE_CLOCK_GATING_A, data);
7450689a570SEric Huang 
7460689a570SEric Huang 			/* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */
7470689a570SEric Huang 			data = RREG32(mmVCE_UENC_CLOCK_GATING);
7480689a570SEric Huang 			data &= ~(0xf | 0xff0);
7490689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
7500689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING, data);
7510689a570SEric Huang 		}
7520689a570SEric Huang 
7530689a570SEric Huang 		vce_v3_0_set_vce_sw_clock_gating(adev, enable);
7540689a570SEric Huang 	}
7550689a570SEric Huang 
756f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
7570689a570SEric Huang 	mutex_unlock(&adev->grbm_idx_mutex);
7580689a570SEric Huang 
759aaa36a97SAlex Deucher 	return 0;
760aaa36a97SAlex Deucher }
761aaa36a97SAlex Deucher 
7625fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle,
7635fc3aeebSyanyang1 					  enum amd_powergating_state state)
764aaa36a97SAlex Deucher {
765aaa36a97SAlex Deucher 	/* This doesn't actually powergate the VCE block.
766aaa36a97SAlex Deucher 	 * That's done in the dpm code via the SMC.  This
767aaa36a97SAlex Deucher 	 * just re-inits the block as necessary.  The actual
768aaa36a97SAlex Deucher 	 * gating still happens in the dpm code.  We should
769aaa36a97SAlex Deucher 	 * revisit this when there is a cleaner line between
770aaa36a97SAlex Deucher 	 * the smc and the hw blocks
771aaa36a97SAlex Deucher 	 */
7725fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
7735fc3aeebSyanyang1 
774e3b04bc7SAlex Deucher 	if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE))
775808a934fSAlex Deucher 		return 0;
776808a934fSAlex Deucher 
7775fc3aeebSyanyang1 	if (state == AMD_PG_STATE_GATE)
778aaa36a97SAlex Deucher 		/* XXX do we need a vce_v3_0_stop()? */
779aaa36a97SAlex Deucher 		return 0;
780aaa36a97SAlex Deucher 	else
781aaa36a97SAlex Deucher 		return vce_v3_0_start(adev);
782aaa36a97SAlex Deucher }
783aaa36a97SAlex Deucher 
784ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring,
785ea4a8c1dSMaruthi Srinivas Bayyavarapu 		struct amdgpu_ib *ib, unsigned int vm_id, bool ctx_switch)
786ea4a8c1dSMaruthi Srinivas Bayyavarapu {
787ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_IB_VM);
788ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, vm_id);
789ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
790ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
791ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, ib->length_dw);
792ea4a8c1dSMaruthi Srinivas Bayyavarapu }
793ea4a8c1dSMaruthi Srinivas Bayyavarapu 
794ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring,
795ea4a8c1dSMaruthi Srinivas Bayyavarapu 			 unsigned int vm_id, uint64_t pd_addr)
796ea4a8c1dSMaruthi Srinivas Bayyavarapu {
797ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_UPDATE_PTB);
798ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, vm_id);
799ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, pd_addr >> 12);
800ea4a8c1dSMaruthi Srinivas Bayyavarapu 
801ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_FLUSH_TLB);
802ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, vm_id);
803ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_END);
804ea4a8c1dSMaruthi Srinivas Bayyavarapu }
805ea4a8c1dSMaruthi Srinivas Bayyavarapu 
806ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_pipeline_sync(struct amdgpu_ring *ring)
807ea4a8c1dSMaruthi Srinivas Bayyavarapu {
808ea4a8c1dSMaruthi Srinivas Bayyavarapu 	uint32_t seq = ring->fence_drv.sync_seq;
809ea4a8c1dSMaruthi Srinivas Bayyavarapu 	uint64_t addr = ring->fence_drv.gpu_addr;
810ea4a8c1dSMaruthi Srinivas Bayyavarapu 
811ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_WAIT_GE);
812ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, lower_32_bits(addr));
813ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, upper_32_bits(addr));
814ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, seq);
815ea4a8c1dSMaruthi Srinivas Bayyavarapu }
816ea4a8c1dSMaruthi Srinivas Bayyavarapu 
817a1255107SAlex Deucher static const struct amd_ip_funcs vce_v3_0_ip_funcs = {
81888a907d6STom St Denis 	.name = "vce_v3_0",
819aaa36a97SAlex Deucher 	.early_init = vce_v3_0_early_init,
820aaa36a97SAlex Deucher 	.late_init = NULL,
821aaa36a97SAlex Deucher 	.sw_init = vce_v3_0_sw_init,
822aaa36a97SAlex Deucher 	.sw_fini = vce_v3_0_sw_fini,
823aaa36a97SAlex Deucher 	.hw_init = vce_v3_0_hw_init,
824aaa36a97SAlex Deucher 	.hw_fini = vce_v3_0_hw_fini,
825aaa36a97SAlex Deucher 	.suspend = vce_v3_0_suspend,
826aaa36a97SAlex Deucher 	.resume = vce_v3_0_resume,
827aaa36a97SAlex Deucher 	.is_idle = vce_v3_0_is_idle,
828aaa36a97SAlex Deucher 	.wait_for_idle = vce_v3_0_wait_for_idle,
829115933a5SChunming Zhou 	.check_soft_reset = vce_v3_0_check_soft_reset,
830115933a5SChunming Zhou 	.pre_soft_reset = vce_v3_0_pre_soft_reset,
831aaa36a97SAlex Deucher 	.soft_reset = vce_v3_0_soft_reset,
832115933a5SChunming Zhou 	.post_soft_reset = vce_v3_0_post_soft_reset,
833aaa36a97SAlex Deucher 	.set_clockgating_state = vce_v3_0_set_clockgating_state,
834aaa36a97SAlex Deucher 	.set_powergating_state = vce_v3_0_set_powergating_state,
835aaa36a97SAlex Deucher };
836aaa36a97SAlex Deucher 
837ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = {
83821cd942eSChristian König 	.type = AMDGPU_RING_TYPE_VCE,
83979887142SChristian König 	.align_mask = 0xf,
84079887142SChristian König 	.nop = VCE_CMD_NO_OP,
841aaa36a97SAlex Deucher 	.get_rptr = vce_v3_0_ring_get_rptr,
842aaa36a97SAlex Deucher 	.get_wptr = vce_v3_0_ring_get_wptr,
843aaa36a97SAlex Deucher 	.set_wptr = vce_v3_0_ring_set_wptr,
844aaa36a97SAlex Deucher 	.parse_cs = amdgpu_vce_ring_parse_cs,
845e12f3d7aSChristian König 	.emit_frame_size =
846e12f3d7aSChristian König 		4 + /* vce_v3_0_emit_pipeline_sync */
847e12f3d7aSChristian König 		6, /* amdgpu_vce_ring_emit_fence x1 no user fence */
848e12f3d7aSChristian König 	.emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */
849aaa36a97SAlex Deucher 	.emit_ib = amdgpu_vce_ring_emit_ib,
850aaa36a97SAlex Deucher 	.emit_fence = amdgpu_vce_ring_emit_fence,
851aaa36a97SAlex Deucher 	.test_ring = amdgpu_vce_ring_test_ring,
852aaa36a97SAlex Deucher 	.test_ib = amdgpu_vce_ring_test_ib,
853edff0e28SJammy Zhou 	.insert_nop = amdgpu_ring_insert_nop,
8549e5d5309SChristian König 	.pad_ib = amdgpu_ring_generic_pad_ib,
855ebff485eSChristian König 	.begin_use = amdgpu_vce_ring_begin_use,
856ebff485eSChristian König 	.end_use = amdgpu_vce_ring_end_use,
857aaa36a97SAlex Deucher };
858aaa36a97SAlex Deucher 
859ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = {
86021cd942eSChristian König 	.type = AMDGPU_RING_TYPE_VCE,
86179887142SChristian König 	.align_mask = 0xf,
86279887142SChristian König 	.nop = VCE_CMD_NO_OP,
863ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.get_rptr = vce_v3_0_ring_get_rptr,
864ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.get_wptr = vce_v3_0_ring_get_wptr,
865ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.set_wptr = vce_v3_0_ring_set_wptr,
86698614701SChristian König 	.parse_cs = amdgpu_vce_ring_parse_cs_vm,
867e12f3d7aSChristian König 	.emit_frame_size =
868e12f3d7aSChristian König 		6 + /* vce_v3_0_emit_vm_flush */
869e12f3d7aSChristian König 		4 + /* vce_v3_0_emit_pipeline_sync */
870e12f3d7aSChristian König 		6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */
871e12f3d7aSChristian König 	.emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */
872ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.emit_ib = vce_v3_0_ring_emit_ib,
873ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.emit_vm_flush = vce_v3_0_emit_vm_flush,
874ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.emit_pipeline_sync = vce_v3_0_emit_pipeline_sync,
875ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.emit_fence = amdgpu_vce_ring_emit_fence,
876ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.test_ring = amdgpu_vce_ring_test_ring,
877ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.test_ib = amdgpu_vce_ring_test_ib,
878ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.insert_nop = amdgpu_ring_insert_nop,
879ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.pad_ib = amdgpu_ring_generic_pad_ib,
880ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.begin_use = amdgpu_vce_ring_begin_use,
881ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.end_use = amdgpu_vce_ring_end_use,
882ea4a8c1dSMaruthi Srinivas Bayyavarapu };
883ea4a8c1dSMaruthi Srinivas Bayyavarapu 
884aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev)
885aaa36a97SAlex Deucher {
88675c65480SAlex Deucher 	int i;
88775c65480SAlex Deucher 
888ea4a8c1dSMaruthi Srinivas Bayyavarapu 	if (adev->asic_type >= CHIP_STONEY) {
88975c65480SAlex Deucher 		for (i = 0; i < adev->vce.num_rings; i++)
890ea4a8c1dSMaruthi Srinivas Bayyavarapu 			adev->vce.ring[i].funcs = &vce_v3_0_ring_vm_funcs;
891ea4a8c1dSMaruthi Srinivas Bayyavarapu 		DRM_INFO("VCE enabled in VM mode\n");
892ea4a8c1dSMaruthi Srinivas Bayyavarapu 	} else {
893ea4a8c1dSMaruthi Srinivas Bayyavarapu 		for (i = 0; i < adev->vce.num_rings; i++)
894ea4a8c1dSMaruthi Srinivas Bayyavarapu 			adev->vce.ring[i].funcs = &vce_v3_0_ring_phys_funcs;
895ea4a8c1dSMaruthi Srinivas Bayyavarapu 		DRM_INFO("VCE enabled in physical mode\n");
896ea4a8c1dSMaruthi Srinivas Bayyavarapu 	}
897aaa36a97SAlex Deucher }
898aaa36a97SAlex Deucher 
899aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = {
900aaa36a97SAlex Deucher 	.set = vce_v3_0_set_interrupt_state,
901aaa36a97SAlex Deucher 	.process = vce_v3_0_process_interrupt,
902aaa36a97SAlex Deucher };
903aaa36a97SAlex Deucher 
904aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev)
905aaa36a97SAlex Deucher {
906aaa36a97SAlex Deucher 	adev->vce.irq.num_types = 1;
907aaa36a97SAlex Deucher 	adev->vce.irq.funcs = &vce_v3_0_irq_funcs;
908aaa36a97SAlex Deucher };
909a1255107SAlex Deucher 
910a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_0_ip_block =
911a1255107SAlex Deucher {
912a1255107SAlex Deucher 	.type = AMD_IP_BLOCK_TYPE_VCE,
913a1255107SAlex Deucher 	.major = 3,
914a1255107SAlex Deucher 	.minor = 0,
915a1255107SAlex Deucher 	.rev = 0,
916a1255107SAlex Deucher 	.funcs = &vce_v3_0_ip_funcs,
917a1255107SAlex Deucher };
918a1255107SAlex Deucher 
919a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_1_ip_block =
920a1255107SAlex Deucher {
921a1255107SAlex Deucher 	.type = AMD_IP_BLOCK_TYPE_VCE,
922a1255107SAlex Deucher 	.major = 3,
923a1255107SAlex Deucher 	.minor = 1,
924a1255107SAlex Deucher 	.rev = 0,
925a1255107SAlex Deucher 	.funcs = &vce_v3_0_ip_funcs,
926a1255107SAlex Deucher };
927a1255107SAlex Deucher 
928a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_4_ip_block =
929a1255107SAlex Deucher {
930a1255107SAlex Deucher 	.type = AMD_IP_BLOCK_TYPE_VCE,
931a1255107SAlex Deucher 	.major = 3,
932a1255107SAlex Deucher 	.minor = 4,
933a1255107SAlex Deucher 	.rev = 0,
934a1255107SAlex Deucher 	.funcs = &vce_v3_0_ip_funcs,
935a1255107SAlex Deucher };
936