xref: /openbmc/linux/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c (revision ecc2cf7c)
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);
1780689a570SEric Huang 		data &= ~0xffc00000;
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 
3232cc0c0b5SFlora Cui 	/* Fiji, Stoney, Polaris10, Polaris11 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) ||
3272cc0c0b5SFlora Cui 	    (adev->asic_type == CHIP_POLARIS11))
3281dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
329188a9bcdSAlex Deucher 
330188a9bcdSAlex Deucher 	/* Tonga and CZ are dual or single pipe */
3312f7d10b3SJammy Zhou 	if (adev->flags & AMD_IS_APU)
3326a585777SAlex Deucher 		tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) &
3336a585777SAlex Deucher 		       VCE_HARVEST_FUSE_MACRO__MASK) >>
3346a585777SAlex Deucher 			VCE_HARVEST_FUSE_MACRO__SHIFT;
3356a585777SAlex Deucher 	else
3366a585777SAlex Deucher 		tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) &
3376a585777SAlex Deucher 		       CC_HARVEST_FUSES__VCE_DISABLE_MASK) >>
3386a585777SAlex Deucher 			CC_HARVEST_FUSES__VCE_DISABLE__SHIFT;
3396a585777SAlex Deucher 
3406a585777SAlex Deucher 	switch (tmp) {
3416a585777SAlex Deucher 	case 1:
3421dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0;
3436a585777SAlex Deucher 	case 2:
3441dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE1;
3456a585777SAlex Deucher 	case 3:
3461dab5f06STom St Denis 		return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1;
3476a585777SAlex Deucher 	default:
3481dab5f06STom St Denis 		return 0;
3496a585777SAlex Deucher 	}
3506a585777SAlex Deucher }
3516a585777SAlex Deucher 
3525fc3aeebSyanyang1 static int vce_v3_0_early_init(void *handle)
353aaa36a97SAlex Deucher {
3545fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
3555fc3aeebSyanyang1 
3566a585777SAlex Deucher 	adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev);
3576a585777SAlex Deucher 
3586a585777SAlex Deucher 	if ((adev->vce.harvest_config &
3596a585777SAlex Deucher 	     (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) ==
3606a585777SAlex Deucher 	    (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1))
3616a585777SAlex Deucher 		return -ENOENT;
3626a585777SAlex Deucher 
3636f0359ffSAlex Deucher 	adev->vce.num_rings = 3;
36475c65480SAlex Deucher 
365aaa36a97SAlex Deucher 	vce_v3_0_set_ring_funcs(adev);
366aaa36a97SAlex Deucher 	vce_v3_0_set_irq_funcs(adev);
367aaa36a97SAlex Deucher 
368aaa36a97SAlex Deucher 	return 0;
369aaa36a97SAlex Deucher }
370aaa36a97SAlex Deucher 
3715fc3aeebSyanyang1 static int vce_v3_0_sw_init(void *handle)
372aaa36a97SAlex Deucher {
3735fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
374aaa36a97SAlex Deucher 	struct amdgpu_ring *ring;
37575c65480SAlex Deucher 	int r, i;
376aaa36a97SAlex Deucher 
377aaa36a97SAlex Deucher 	/* VCE */
378aaa36a97SAlex Deucher 	r = amdgpu_irq_add_id(adev, 167, &adev->vce.irq);
379aaa36a97SAlex Deucher 	if (r)
380aaa36a97SAlex Deucher 		return r;
381aaa36a97SAlex Deucher 
382e9822622SLeo Liu 	r = amdgpu_vce_sw_init(adev, VCE_V3_0_FW_SIZE +
383e9822622SLeo Liu 		(VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE) * 2);
384aaa36a97SAlex Deucher 	if (r)
385aaa36a97SAlex Deucher 		return r;
386aaa36a97SAlex Deucher 
387ef6239e0SAlex Deucher 	/* 52.8.3 required for 3 ring support */
388ef6239e0SAlex Deucher 	if (adev->vce.fw_version < FW_52_8_3)
389ef6239e0SAlex Deucher 		adev->vce.num_rings = 2;
390ef6239e0SAlex Deucher 
391aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
392aaa36a97SAlex Deucher 	if (r)
393aaa36a97SAlex Deucher 		return r;
394aaa36a97SAlex Deucher 
39575c65480SAlex Deucher 	for (i = 0; i < adev->vce.num_rings; i++) {
39675c65480SAlex Deucher 		ring = &adev->vce.ring[i];
39775c65480SAlex Deucher 		sprintf(ring->name, "vce%d", i);
39879887142SChristian König 		r = amdgpu_ring_init(adev, ring, 512, &adev->vce.irq, 0);
399aaa36a97SAlex Deucher 		if (r)
400aaa36a97SAlex Deucher 			return r;
40175c65480SAlex Deucher 	}
402aaa36a97SAlex Deucher 
403aaa36a97SAlex Deucher 	return r;
404aaa36a97SAlex Deucher }
405aaa36a97SAlex Deucher 
4065fc3aeebSyanyang1 static int vce_v3_0_sw_fini(void *handle)
407aaa36a97SAlex Deucher {
408aaa36a97SAlex Deucher 	int r;
4095fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
410aaa36a97SAlex Deucher 
411aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
412aaa36a97SAlex Deucher 	if (r)
413aaa36a97SAlex Deucher 		return r;
414aaa36a97SAlex Deucher 
415aaa36a97SAlex Deucher 	r = amdgpu_vce_sw_fini(adev);
416aaa36a97SAlex Deucher 	if (r)
417aaa36a97SAlex Deucher 		return r;
418aaa36a97SAlex Deucher 
419aaa36a97SAlex Deucher 	return r;
420aaa36a97SAlex Deucher }
421aaa36a97SAlex Deucher 
4225fc3aeebSyanyang1 static int vce_v3_0_hw_init(void *handle)
423aaa36a97SAlex Deucher {
424691ca86aSTom St Denis 	int r, i;
4255fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
426aaa36a97SAlex Deucher 
427aaa36a97SAlex Deucher 	r = vce_v3_0_start(adev);
428aaa36a97SAlex Deucher 	if (r)
429aaa36a97SAlex Deucher 		return r;
430aaa36a97SAlex Deucher 
43175c65480SAlex Deucher 	for (i = 0; i < adev->vce.num_rings; i++)
43275c65480SAlex Deucher 		adev->vce.ring[i].ready = false;
433aaa36a97SAlex Deucher 
43475c65480SAlex Deucher 	for (i = 0; i < adev->vce.num_rings; i++) {
435691ca86aSTom St Denis 		r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
436691ca86aSTom St Denis 		if (r)
437aaa36a97SAlex Deucher 			return r;
438691ca86aSTom St Denis 		else
439691ca86aSTom St Denis 			adev->vce.ring[i].ready = true;
440aaa36a97SAlex Deucher 	}
441aaa36a97SAlex Deucher 
442aaa36a97SAlex Deucher 	DRM_INFO("VCE initialized successfully.\n");
443aaa36a97SAlex Deucher 
444aaa36a97SAlex Deucher 	return 0;
445aaa36a97SAlex Deucher }
446aaa36a97SAlex Deucher 
4475fc3aeebSyanyang1 static int vce_v3_0_hw_fini(void *handle)
448aaa36a97SAlex Deucher {
449567e6e29Sjimqu 	int r;
450567e6e29Sjimqu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
451567e6e29Sjimqu 
452567e6e29Sjimqu 	r = vce_v3_0_wait_for_idle(handle);
453567e6e29Sjimqu 	if (r)
454567e6e29Sjimqu 		return r;
455567e6e29Sjimqu 
456567e6e29Sjimqu 	return vce_v3_0_stop(adev);
457aaa36a97SAlex Deucher }
458aaa36a97SAlex Deucher 
4595fc3aeebSyanyang1 static int vce_v3_0_suspend(void *handle)
460aaa36a97SAlex Deucher {
461aaa36a97SAlex Deucher 	int r;
4625fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
463aaa36a97SAlex Deucher 
464aaa36a97SAlex Deucher 	r = vce_v3_0_hw_fini(adev);
465aaa36a97SAlex Deucher 	if (r)
466aaa36a97SAlex Deucher 		return r;
467aaa36a97SAlex Deucher 
468aaa36a97SAlex Deucher 	r = amdgpu_vce_suspend(adev);
469aaa36a97SAlex Deucher 	if (r)
470aaa36a97SAlex Deucher 		return r;
471aaa36a97SAlex Deucher 
472aaa36a97SAlex Deucher 	return r;
473aaa36a97SAlex Deucher }
474aaa36a97SAlex Deucher 
4755fc3aeebSyanyang1 static int vce_v3_0_resume(void *handle)
476aaa36a97SAlex Deucher {
477aaa36a97SAlex Deucher 	int r;
4785fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
479aaa36a97SAlex Deucher 
480aaa36a97SAlex Deucher 	r = amdgpu_vce_resume(adev);
481aaa36a97SAlex Deucher 	if (r)
482aaa36a97SAlex Deucher 		return r;
483aaa36a97SAlex Deucher 
484aaa36a97SAlex Deucher 	r = vce_v3_0_hw_init(adev);
485aaa36a97SAlex Deucher 	if (r)
486aaa36a97SAlex Deucher 		return r;
487aaa36a97SAlex Deucher 
488aaa36a97SAlex Deucher 	return r;
489aaa36a97SAlex Deucher }
490aaa36a97SAlex Deucher 
4915bbc553aSLeo Liu static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx)
492aaa36a97SAlex Deucher {
493aaa36a97SAlex Deucher 	uint32_t offset, size;
494aaa36a97SAlex Deucher 
495aaa36a97SAlex Deucher 	WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16));
496aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000);
497aaa36a97SAlex Deucher 	WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F);
4986f906814STom St Denis 	WREG32(mmVCE_CLOCK_GATING_B, 0x1FF);
499aaa36a97SAlex Deucher 
500aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_CTRL, 0x00398000);
501aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1);
502aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL, 0);
503aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_SWAP_CNTL1, 0);
504aaa36a97SAlex Deucher 	WREG32(mmVCE_LMI_VM_CTRL, 0);
5053c0ff9f1SLeo Liu 	if (adev->asic_type >= CHIP_STONEY) {
5063c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8));
5073c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8));
5083c0ff9f1SLeo Liu 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8));
5093c0ff9f1SLeo Liu 	} else
510aaa36a97SAlex Deucher 		WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
511aaa36a97SAlex Deucher 	offset = AMDGPU_VCE_FIRMWARE_OFFSET;
512e9822622SLeo Liu 	size = VCE_V3_0_FW_SIZE;
513aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
514aaa36a97SAlex Deucher 	WREG32(mmVCE_VCPU_CACHE_SIZE0, size);
515aaa36a97SAlex Deucher 
5165bbc553aSLeo Liu 	if (idx == 0) {
517aaa36a97SAlex Deucher 		offset += size;
518e9822622SLeo Liu 		size = VCE_V3_0_STACK_SIZE;
519aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff);
520aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
521aaa36a97SAlex Deucher 		offset += size;
522e9822622SLeo Liu 		size = VCE_V3_0_DATA_SIZE;
523aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff);
524aaa36a97SAlex Deucher 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5255bbc553aSLeo Liu 	} else {
5265bbc553aSLeo Liu 		offset += size + VCE_V3_0_STACK_SIZE + VCE_V3_0_DATA_SIZE;
5275bbc553aSLeo Liu 		size = VCE_V3_0_STACK_SIZE;
5285bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0xfffffff);
5295bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
5305bbc553aSLeo Liu 		offset += size;
5315bbc553aSLeo Liu 		size = VCE_V3_0_DATA_SIZE;
5325bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0xfffffff);
5335bbc553aSLeo Liu 		WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
5345bbc553aSLeo Liu 	}
535aaa36a97SAlex Deucher 
536aaa36a97SAlex Deucher 	WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100);
537f3f0ea95STom St Denis 	WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1);
538aaa36a97SAlex Deucher }
539aaa36a97SAlex Deucher 
5405fc3aeebSyanyang1 static bool vce_v3_0_is_idle(void *handle)
541aaa36a97SAlex Deucher {
5425fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
543be4f38e2SAlex Deucher 	u32 mask = 0;
5445fc3aeebSyanyang1 
54574af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK;
54674af1276STom St Denis 	mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK;
547be4f38e2SAlex Deucher 
548be4f38e2SAlex Deucher 	return !(RREG32(mmSRBM_STATUS2) & mask);
549aaa36a97SAlex Deucher }
550aaa36a97SAlex Deucher 
5515fc3aeebSyanyang1 static int vce_v3_0_wait_for_idle(void *handle)
552aaa36a97SAlex Deucher {
553aaa36a97SAlex Deucher 	unsigned i;
5545fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
555be4f38e2SAlex Deucher 
55692988e60STom St Denis 	for (i = 0; i < adev->usec_timeout; i++)
55792988e60STom St Denis 		if (vce_v3_0_is_idle(handle))
558aaa36a97SAlex Deucher 			return 0;
55992988e60STom St Denis 
560aaa36a97SAlex Deucher 	return -ETIMEDOUT;
561aaa36a97SAlex Deucher }
562aaa36a97SAlex Deucher 
563ac8e3f30SRex Zhu #define  VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK  0x00000008L   /* AUTO_BUSY */
564ac8e3f30SRex Zhu #define  VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK   0x00000010L   /* RB0_BUSY */
565ac8e3f30SRex Zhu #define  VCE_STATUS_VCPU_REPORT_RB1_BUSY_MASK   0x00000020L   /* RB1_BUSY */
566ac8e3f30SRex Zhu #define  AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \
567ac8e3f30SRex Zhu 				      VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK)
568115933a5SChunming Zhou 
569da146d3bSAlex Deucher static bool vce_v3_0_check_soft_reset(void *handle)
570115933a5SChunming Zhou {
571115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
572115933a5SChunming Zhou 	u32 srbm_soft_reset = 0;
573115933a5SChunming Zhou 
574115933a5SChunming Zhou 	/* According to VCE team , we should use VCE_STATUS instead
575115933a5SChunming Zhou 	 * SRBM_STATUS.VCE_BUSY bit for busy status checking.
576115933a5SChunming Zhou 	 * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE
577115933a5SChunming Zhou 	 * instance's registers are accessed
578115933a5SChunming Zhou 	 * (0 for 1st instance, 10 for 2nd instance).
579115933a5SChunming Zhou 	 *
580115933a5SChunming Zhou 	 *VCE_STATUS
581115933a5SChunming Zhou 	 *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 |          |FW_LOADED|JOB |
582115933a5SChunming Zhou 	 *|----+----+-----------+----+----+----+----------+---------+----|
583115933a5SChunming Zhou 	 *|bit8|bit7|    bit6   |bit5|bit4|bit3|   bit2   |  bit1   |bit0|
584115933a5SChunming Zhou 	 *
585115933a5SChunming Zhou 	 * VCE team suggest use bit 3--bit 6 for busy status check
586115933a5SChunming Zhou 	 */
5879aeb774cSTom St Denis 	mutex_lock(&adev->grbm_idx_mutex);
588f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
589115933a5SChunming Zhou 	if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
590115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
591115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
592115933a5SChunming Zhou 	}
593f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10);
594115933a5SChunming Zhou 	if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
595115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
596115933a5SChunming Zhou 		srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
597115933a5SChunming Zhou 	}
598f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
599da146d3bSAlex Deucher 	mutex_unlock(&adev->grbm_idx_mutex);
600115933a5SChunming Zhou 
601115933a5SChunming Zhou 	if (srbm_soft_reset) {
602115933a5SChunming Zhou 		adev->vce.srbm_soft_reset = srbm_soft_reset;
603da146d3bSAlex Deucher 		return true;
604115933a5SChunming Zhou 	} else {
605115933a5SChunming Zhou 		adev->vce.srbm_soft_reset = 0;
606da146d3bSAlex Deucher 		return false;
607115933a5SChunming Zhou 	}
608115933a5SChunming Zhou }
609115933a5SChunming Zhou 
6105fc3aeebSyanyang1 static int vce_v3_0_soft_reset(void *handle)
611aaa36a97SAlex Deucher {
6125fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
613115933a5SChunming Zhou 	u32 srbm_soft_reset;
6145fc3aeebSyanyang1 
615da146d3bSAlex Deucher 	if (!adev->vce.srbm_soft_reset)
616115933a5SChunming Zhou 		return 0;
617115933a5SChunming Zhou 	srbm_soft_reset = adev->vce.srbm_soft_reset;
618be4f38e2SAlex Deucher 
619115933a5SChunming Zhou 	if (srbm_soft_reset) {
620115933a5SChunming Zhou 		u32 tmp;
621115933a5SChunming Zhou 
622115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
623115933a5SChunming Zhou 		tmp |= srbm_soft_reset;
624115933a5SChunming Zhou 		dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
625115933a5SChunming Zhou 		WREG32(mmSRBM_SOFT_RESET, tmp);
626115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
627115933a5SChunming Zhou 
628115933a5SChunming Zhou 		udelay(50);
629115933a5SChunming Zhou 
630115933a5SChunming Zhou 		tmp &= ~srbm_soft_reset;
631115933a5SChunming Zhou 		WREG32(mmSRBM_SOFT_RESET, tmp);
632115933a5SChunming Zhou 		tmp = RREG32(mmSRBM_SOFT_RESET);
633115933a5SChunming Zhou 
634115933a5SChunming Zhou 		/* Wait a little for things to settle down */
635115933a5SChunming Zhou 		udelay(50);
636115933a5SChunming Zhou 	}
637115933a5SChunming Zhou 
638115933a5SChunming Zhou 	return 0;
639115933a5SChunming Zhou }
640115933a5SChunming Zhou 
641115933a5SChunming Zhou static int vce_v3_0_pre_soft_reset(void *handle)
642115933a5SChunming Zhou {
643115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
644115933a5SChunming Zhou 
645da146d3bSAlex Deucher 	if (!adev->vce.srbm_soft_reset)
646115933a5SChunming Zhou 		return 0;
647115933a5SChunming Zhou 
648aaa36a97SAlex Deucher 	mdelay(5);
649aaa36a97SAlex Deucher 
650115933a5SChunming Zhou 	return vce_v3_0_suspend(adev);
651115933a5SChunming Zhou }
652115933a5SChunming Zhou 
653115933a5SChunming Zhou 
654115933a5SChunming Zhou static int vce_v3_0_post_soft_reset(void *handle)
655115933a5SChunming Zhou {
656115933a5SChunming Zhou 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
657115933a5SChunming Zhou 
658da146d3bSAlex Deucher 	if (!adev->vce.srbm_soft_reset)
659115933a5SChunming Zhou 		return 0;
660115933a5SChunming Zhou 
661115933a5SChunming Zhou 	mdelay(5);
662115933a5SChunming Zhou 
663115933a5SChunming Zhou 	return vce_v3_0_resume(adev);
664aaa36a97SAlex Deucher }
665aaa36a97SAlex Deucher 
666aaa36a97SAlex Deucher static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev,
667aaa36a97SAlex Deucher 					struct amdgpu_irq_src *source,
668aaa36a97SAlex Deucher 					unsigned type,
669aaa36a97SAlex Deucher 					enum amdgpu_interrupt_state state)
670aaa36a97SAlex Deucher {
671aaa36a97SAlex Deucher 	uint32_t val = 0;
672aaa36a97SAlex Deucher 
673aaa36a97SAlex Deucher 	if (state == AMDGPU_IRQ_STATE_ENABLE)
674aaa36a97SAlex Deucher 		val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK;
675aaa36a97SAlex Deucher 
676aaa36a97SAlex Deucher 	WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
677aaa36a97SAlex Deucher 	return 0;
678aaa36a97SAlex Deucher }
679aaa36a97SAlex Deucher 
680aaa36a97SAlex Deucher static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
681aaa36a97SAlex Deucher 				      struct amdgpu_irq_src *source,
682aaa36a97SAlex Deucher 				      struct amdgpu_iv_entry *entry)
683aaa36a97SAlex Deucher {
684aaa36a97SAlex Deucher 	DRM_DEBUG("IH: VCE\n");
685d6c29c30SLeo Liu 
686f3f0ea95STom St Denis 	WREG32_FIELD(VCE_SYS_INT_STATUS, VCE_SYS_INT_TRAP_INTERRUPT_INT, 1);
687d6c29c30SLeo Liu 
688aaa36a97SAlex Deucher 	switch (entry->src_data) {
689aaa36a97SAlex Deucher 	case 0:
690aaa36a97SAlex Deucher 	case 1:
6916f0359ffSAlex Deucher 	case 2:
69281da2edeSTom St Denis 		amdgpu_fence_process(&adev->vce.ring[entry->src_data]);
693aaa36a97SAlex Deucher 		break;
694aaa36a97SAlex Deucher 	default:
695aaa36a97SAlex Deucher 		DRM_ERROR("Unhandled interrupt: %d %d\n",
696aaa36a97SAlex Deucher 			  entry->src_id, entry->src_data);
697aaa36a97SAlex Deucher 		break;
698aaa36a97SAlex Deucher 	}
699aaa36a97SAlex Deucher 
700aaa36a97SAlex Deucher 	return 0;
701aaa36a97SAlex Deucher }
702aaa36a97SAlex Deucher 
7030174df4eSRex Zhu static void vce_v3_0_set_bypass_mode(struct amdgpu_device *adev, bool enable)
704ec38f188SRex Zhu {
705ec38f188SRex Zhu 	u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL);
706ec38f188SRex Zhu 
707ec38f188SRex Zhu 	if (enable)
708ec38f188SRex Zhu 		tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
709ec38f188SRex Zhu 	else
710ec38f188SRex Zhu 		tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK;
711ec38f188SRex Zhu 
712ec38f188SRex Zhu 	WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp);
713ec38f188SRex Zhu }
714ec38f188SRex Zhu 
7155fc3aeebSyanyang1 static int vce_v3_0_set_clockgating_state(void *handle,
7165fc3aeebSyanyang1 					  enum amd_clockgating_state state)
717aaa36a97SAlex Deucher {
7180689a570SEric Huang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
7190689a570SEric Huang 	bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
7200689a570SEric Huang 	int i;
7210689a570SEric Huang 
722c04399f1SRex Zhu 	if ((adev->asic_type == CHIP_POLARIS10) ||
7233374dcebSRex Zhu 		(adev->asic_type == CHIP_TONGA) ||
7243374dcebSRex Zhu 		(adev->asic_type == CHIP_FIJI))
7250174df4eSRex Zhu 		vce_v3_0_set_bypass_mode(adev, enable);
726ec38f188SRex Zhu 
727e3b04bc7SAlex Deucher 	if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG))
7280689a570SEric Huang 		return 0;
7290689a570SEric Huang 
7300689a570SEric Huang 	mutex_lock(&adev->grbm_idx_mutex);
7310689a570SEric Huang 	for (i = 0; i < 2; i++) {
7320689a570SEric Huang 		/* Program VCE Instance 0 or 1 if not harvested */
7330689a570SEric Huang 		if (adev->vce.harvest_config & (1 << i))
7340689a570SEric Huang 			continue;
7350689a570SEric Huang 
736f3f0ea95STom St Denis 		WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i);
7370689a570SEric Huang 
7380689a570SEric Huang 		if (enable) {
7390689a570SEric Huang 			/* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
7400689a570SEric Huang 			uint32_t data = RREG32(mmVCE_CLOCK_GATING_A);
7410689a570SEric Huang 			data &= ~(0xf | 0xff0);
7420689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
7430689a570SEric Huang 			WREG32(mmVCE_CLOCK_GATING_A, data);
7440689a570SEric Huang 
7450689a570SEric Huang 			/* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */
7460689a570SEric Huang 			data = RREG32(mmVCE_UENC_CLOCK_GATING);
7470689a570SEric Huang 			data &= ~(0xf | 0xff0);
7480689a570SEric Huang 			data |= ((0x0 << 0) | (0x04 << 4));
7490689a570SEric Huang 			WREG32(mmVCE_UENC_CLOCK_GATING, data);
7500689a570SEric Huang 		}
7510689a570SEric Huang 
7520689a570SEric Huang 		vce_v3_0_set_vce_sw_clock_gating(adev, enable);
7530689a570SEric Huang 	}
7540689a570SEric Huang 
755f3f0ea95STom St Denis 	WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
7560689a570SEric Huang 	mutex_unlock(&adev->grbm_idx_mutex);
7570689a570SEric Huang 
758aaa36a97SAlex Deucher 	return 0;
759aaa36a97SAlex Deucher }
760aaa36a97SAlex Deucher 
7615fc3aeebSyanyang1 static int vce_v3_0_set_powergating_state(void *handle,
7625fc3aeebSyanyang1 					  enum amd_powergating_state state)
763aaa36a97SAlex Deucher {
764aaa36a97SAlex Deucher 	/* This doesn't actually powergate the VCE block.
765aaa36a97SAlex Deucher 	 * That's done in the dpm code via the SMC.  This
766aaa36a97SAlex Deucher 	 * just re-inits the block as necessary.  The actual
767aaa36a97SAlex Deucher 	 * gating still happens in the dpm code.  We should
768aaa36a97SAlex Deucher 	 * revisit this when there is a cleaner line between
769aaa36a97SAlex Deucher 	 * the smc and the hw blocks
770aaa36a97SAlex Deucher 	 */
7715fc3aeebSyanyang1 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
7725fc3aeebSyanyang1 
773e3b04bc7SAlex Deucher 	if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE))
774808a934fSAlex Deucher 		return 0;
775808a934fSAlex Deucher 
7765fc3aeebSyanyang1 	if (state == AMD_PG_STATE_GATE)
777aaa36a97SAlex Deucher 		/* XXX do we need a vce_v3_0_stop()? */
778aaa36a97SAlex Deucher 		return 0;
779aaa36a97SAlex Deucher 	else
780aaa36a97SAlex Deucher 		return vce_v3_0_start(adev);
781aaa36a97SAlex Deucher }
782aaa36a97SAlex Deucher 
783ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring,
784ea4a8c1dSMaruthi Srinivas Bayyavarapu 		struct amdgpu_ib *ib, unsigned int vm_id, bool ctx_switch)
785ea4a8c1dSMaruthi Srinivas Bayyavarapu {
786ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_IB_VM);
787ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, vm_id);
788ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
789ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
790ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, ib->length_dw);
791ea4a8c1dSMaruthi Srinivas Bayyavarapu }
792ea4a8c1dSMaruthi Srinivas Bayyavarapu 
793ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring,
794ea4a8c1dSMaruthi Srinivas Bayyavarapu 			 unsigned int vm_id, uint64_t pd_addr)
795ea4a8c1dSMaruthi Srinivas Bayyavarapu {
796ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_UPDATE_PTB);
797ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, vm_id);
798ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, pd_addr >> 12);
799ea4a8c1dSMaruthi Srinivas Bayyavarapu 
800ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_FLUSH_TLB);
801ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, vm_id);
802ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_END);
803ea4a8c1dSMaruthi Srinivas Bayyavarapu }
804ea4a8c1dSMaruthi Srinivas Bayyavarapu 
805ea4a8c1dSMaruthi Srinivas Bayyavarapu static void vce_v3_0_emit_pipeline_sync(struct amdgpu_ring *ring)
806ea4a8c1dSMaruthi Srinivas Bayyavarapu {
807ea4a8c1dSMaruthi Srinivas Bayyavarapu 	uint32_t seq = ring->fence_drv.sync_seq;
808ea4a8c1dSMaruthi Srinivas Bayyavarapu 	uint64_t addr = ring->fence_drv.gpu_addr;
809ea4a8c1dSMaruthi Srinivas Bayyavarapu 
810ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, VCE_CMD_WAIT_GE);
811ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, lower_32_bits(addr));
812ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, upper_32_bits(addr));
813ea4a8c1dSMaruthi Srinivas Bayyavarapu 	amdgpu_ring_write(ring, seq);
814ea4a8c1dSMaruthi Srinivas Bayyavarapu }
815ea4a8c1dSMaruthi Srinivas Bayyavarapu 
816a1255107SAlex Deucher static const struct amd_ip_funcs vce_v3_0_ip_funcs = {
81788a907d6STom St Denis 	.name = "vce_v3_0",
818aaa36a97SAlex Deucher 	.early_init = vce_v3_0_early_init,
819aaa36a97SAlex Deucher 	.late_init = NULL,
820aaa36a97SAlex Deucher 	.sw_init = vce_v3_0_sw_init,
821aaa36a97SAlex Deucher 	.sw_fini = vce_v3_0_sw_fini,
822aaa36a97SAlex Deucher 	.hw_init = vce_v3_0_hw_init,
823aaa36a97SAlex Deucher 	.hw_fini = vce_v3_0_hw_fini,
824aaa36a97SAlex Deucher 	.suspend = vce_v3_0_suspend,
825aaa36a97SAlex Deucher 	.resume = vce_v3_0_resume,
826aaa36a97SAlex Deucher 	.is_idle = vce_v3_0_is_idle,
827aaa36a97SAlex Deucher 	.wait_for_idle = vce_v3_0_wait_for_idle,
828115933a5SChunming Zhou 	.check_soft_reset = vce_v3_0_check_soft_reset,
829115933a5SChunming Zhou 	.pre_soft_reset = vce_v3_0_pre_soft_reset,
830aaa36a97SAlex Deucher 	.soft_reset = vce_v3_0_soft_reset,
831115933a5SChunming Zhou 	.post_soft_reset = vce_v3_0_post_soft_reset,
832aaa36a97SAlex Deucher 	.set_clockgating_state = vce_v3_0_set_clockgating_state,
833aaa36a97SAlex Deucher 	.set_powergating_state = vce_v3_0_set_powergating_state,
834aaa36a97SAlex Deucher };
835aaa36a97SAlex Deucher 
836ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = {
83721cd942eSChristian König 	.type = AMDGPU_RING_TYPE_VCE,
83879887142SChristian König 	.align_mask = 0xf,
83979887142SChristian König 	.nop = VCE_CMD_NO_OP,
840aaa36a97SAlex Deucher 	.get_rptr = vce_v3_0_ring_get_rptr,
841aaa36a97SAlex Deucher 	.get_wptr = vce_v3_0_ring_get_wptr,
842aaa36a97SAlex Deucher 	.set_wptr = vce_v3_0_ring_set_wptr,
843aaa36a97SAlex Deucher 	.parse_cs = amdgpu_vce_ring_parse_cs,
844e12f3d7aSChristian König 	.emit_frame_size =
845e12f3d7aSChristian König 		4 + /* vce_v3_0_emit_pipeline_sync */
846e12f3d7aSChristian König 		6, /* amdgpu_vce_ring_emit_fence x1 no user fence */
847e12f3d7aSChristian König 	.emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */
848aaa36a97SAlex Deucher 	.emit_ib = amdgpu_vce_ring_emit_ib,
849aaa36a97SAlex Deucher 	.emit_fence = amdgpu_vce_ring_emit_fence,
850aaa36a97SAlex Deucher 	.test_ring = amdgpu_vce_ring_test_ring,
851aaa36a97SAlex Deucher 	.test_ib = amdgpu_vce_ring_test_ib,
852edff0e28SJammy Zhou 	.insert_nop = amdgpu_ring_insert_nop,
8539e5d5309SChristian König 	.pad_ib = amdgpu_ring_generic_pad_ib,
854ebff485eSChristian König 	.begin_use = amdgpu_vce_ring_begin_use,
855ebff485eSChristian König 	.end_use = amdgpu_vce_ring_end_use,
856aaa36a97SAlex Deucher };
857aaa36a97SAlex Deucher 
858ea4a8c1dSMaruthi Srinivas Bayyavarapu static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = {
85921cd942eSChristian König 	.type = AMDGPU_RING_TYPE_VCE,
86079887142SChristian König 	.align_mask = 0xf,
86179887142SChristian König 	.nop = VCE_CMD_NO_OP,
862ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.get_rptr = vce_v3_0_ring_get_rptr,
863ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.get_wptr = vce_v3_0_ring_get_wptr,
864ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.set_wptr = vce_v3_0_ring_set_wptr,
86598614701SChristian König 	.parse_cs = amdgpu_vce_ring_parse_cs_vm,
866e12f3d7aSChristian König 	.emit_frame_size =
867e12f3d7aSChristian König 		6 + /* vce_v3_0_emit_vm_flush */
868e12f3d7aSChristian König 		4 + /* vce_v3_0_emit_pipeline_sync */
869e12f3d7aSChristian König 		6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */
870e12f3d7aSChristian König 	.emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */
871ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.emit_ib = vce_v3_0_ring_emit_ib,
872ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.emit_vm_flush = vce_v3_0_emit_vm_flush,
873ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.emit_pipeline_sync = vce_v3_0_emit_pipeline_sync,
874ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.emit_fence = amdgpu_vce_ring_emit_fence,
875ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.test_ring = amdgpu_vce_ring_test_ring,
876ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.test_ib = amdgpu_vce_ring_test_ib,
877ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.insert_nop = amdgpu_ring_insert_nop,
878ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.pad_ib = amdgpu_ring_generic_pad_ib,
879ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.begin_use = amdgpu_vce_ring_begin_use,
880ea4a8c1dSMaruthi Srinivas Bayyavarapu 	.end_use = amdgpu_vce_ring_end_use,
881ea4a8c1dSMaruthi Srinivas Bayyavarapu };
882ea4a8c1dSMaruthi Srinivas Bayyavarapu 
883aaa36a97SAlex Deucher static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev)
884aaa36a97SAlex Deucher {
88575c65480SAlex Deucher 	int i;
88675c65480SAlex Deucher 
887ea4a8c1dSMaruthi Srinivas Bayyavarapu 	if (adev->asic_type >= CHIP_STONEY) {
88875c65480SAlex Deucher 		for (i = 0; i < adev->vce.num_rings; i++)
889ea4a8c1dSMaruthi Srinivas Bayyavarapu 			adev->vce.ring[i].funcs = &vce_v3_0_ring_vm_funcs;
890ea4a8c1dSMaruthi Srinivas Bayyavarapu 		DRM_INFO("VCE enabled in VM mode\n");
891ea4a8c1dSMaruthi Srinivas Bayyavarapu 	} else {
892ea4a8c1dSMaruthi Srinivas Bayyavarapu 		for (i = 0; i < adev->vce.num_rings; i++)
893ea4a8c1dSMaruthi Srinivas Bayyavarapu 			adev->vce.ring[i].funcs = &vce_v3_0_ring_phys_funcs;
894ea4a8c1dSMaruthi Srinivas Bayyavarapu 		DRM_INFO("VCE enabled in physical mode\n");
895ea4a8c1dSMaruthi Srinivas Bayyavarapu 	}
896aaa36a97SAlex Deucher }
897aaa36a97SAlex Deucher 
898aaa36a97SAlex Deucher static const struct amdgpu_irq_src_funcs vce_v3_0_irq_funcs = {
899aaa36a97SAlex Deucher 	.set = vce_v3_0_set_interrupt_state,
900aaa36a97SAlex Deucher 	.process = vce_v3_0_process_interrupt,
901aaa36a97SAlex Deucher };
902aaa36a97SAlex Deucher 
903aaa36a97SAlex Deucher static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev)
904aaa36a97SAlex Deucher {
905aaa36a97SAlex Deucher 	adev->vce.irq.num_types = 1;
906aaa36a97SAlex Deucher 	adev->vce.irq.funcs = &vce_v3_0_irq_funcs;
907aaa36a97SAlex Deucher };
908a1255107SAlex Deucher 
909a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_0_ip_block =
910a1255107SAlex Deucher {
911a1255107SAlex Deucher 	.type = AMD_IP_BLOCK_TYPE_VCE,
912a1255107SAlex Deucher 	.major = 3,
913a1255107SAlex Deucher 	.minor = 0,
914a1255107SAlex Deucher 	.rev = 0,
915a1255107SAlex Deucher 	.funcs = &vce_v3_0_ip_funcs,
916a1255107SAlex Deucher };
917a1255107SAlex Deucher 
918a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_1_ip_block =
919a1255107SAlex Deucher {
920a1255107SAlex Deucher 	.type = AMD_IP_BLOCK_TYPE_VCE,
921a1255107SAlex Deucher 	.major = 3,
922a1255107SAlex Deucher 	.minor = 1,
923a1255107SAlex Deucher 	.rev = 0,
924a1255107SAlex Deucher 	.funcs = &vce_v3_0_ip_funcs,
925a1255107SAlex Deucher };
926a1255107SAlex Deucher 
927a1255107SAlex Deucher const struct amdgpu_ip_block_version vce_v3_4_ip_block =
928a1255107SAlex Deucher {
929a1255107SAlex Deucher 	.type = AMD_IP_BLOCK_TYPE_VCE,
930a1255107SAlex Deucher 	.major = 3,
931a1255107SAlex Deucher 	.minor = 4,
932a1255107SAlex Deucher 	.rev = 0,
933a1255107SAlex Deucher 	.funcs = &vce_v3_0_ip_funcs,
934a1255107SAlex Deucher };
935