1fb4d8502Sjsg /*
2fb4d8502Sjsg  * Copyright 2013 Advanced Micro Devices, Inc.
3fb4d8502Sjsg  * All Rights Reserved.
4fb4d8502Sjsg  *
5fb4d8502Sjsg  * Permission is hereby granted, free of charge, to any person obtaining a
6fb4d8502Sjsg  * copy of this software and associated documentation files (the
7fb4d8502Sjsg  * "Software"), to deal in the Software without restriction, including
8fb4d8502Sjsg  * without limitation the rights to use, copy, modify, merge, publish,
9fb4d8502Sjsg  * distribute, sub license, and/or sell copies of the Software, and to
10fb4d8502Sjsg  * permit persons to whom the Software is furnished to do so, subject to
11fb4d8502Sjsg  * the following conditions:
12fb4d8502Sjsg  *
13fb4d8502Sjsg  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14fb4d8502Sjsg  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15fb4d8502Sjsg  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
16fb4d8502Sjsg  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
17fb4d8502Sjsg  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18fb4d8502Sjsg  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19fb4d8502Sjsg  * USE OR OTHER DEALINGS IN THE SOFTWARE.
20fb4d8502Sjsg  *
21fb4d8502Sjsg  * The above copyright notice and this permission notice (including the
22fb4d8502Sjsg  * next paragraph) shall be included in all copies or substantial portions
23fb4d8502Sjsg  * of the Software.
24fb4d8502Sjsg  *
25fb4d8502Sjsg  * Authors: Christian König <christian.koenig@amd.com>
26fb4d8502Sjsg  */
27fb4d8502Sjsg 
28fb4d8502Sjsg #include <linux/firmware.h>
29c349dbc7Sjsg 
30fb4d8502Sjsg #include "amdgpu.h"
31fb4d8502Sjsg #include "amdgpu_vce.h"
32fb4d8502Sjsg #include "cikd.h"
33fb4d8502Sjsg #include "vce/vce_2_0_d.h"
34fb4d8502Sjsg #include "vce/vce_2_0_sh_mask.h"
35fb4d8502Sjsg #include "smu/smu_7_0_1_d.h"
36fb4d8502Sjsg #include "smu/smu_7_0_1_sh_mask.h"
37fb4d8502Sjsg #include "oss/oss_2_0_d.h"
38fb4d8502Sjsg #include "oss/oss_2_0_sh_mask.h"
39fb4d8502Sjsg 
40fb4d8502Sjsg #define VCE_V2_0_FW_SIZE	(256 * 1024)
41fb4d8502Sjsg #define VCE_V2_0_STACK_SIZE	(64 * 1024)
42fb4d8502Sjsg #define VCE_V2_0_DATA_SIZE	(23552 * AMDGPU_MAX_VCE_HANDLES)
43fb4d8502Sjsg #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK	0x02
44fb4d8502Sjsg 
45fb4d8502Sjsg static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev);
46fb4d8502Sjsg static void vce_v2_0_set_irq_funcs(struct amdgpu_device *adev);
47fb4d8502Sjsg 
48fb4d8502Sjsg /**
49fb4d8502Sjsg  * vce_v2_0_ring_get_rptr - get read pointer
50fb4d8502Sjsg  *
51fb4d8502Sjsg  * @ring: amdgpu_ring pointer
52fb4d8502Sjsg  *
53fb4d8502Sjsg  * Returns the current hardware read pointer
54fb4d8502Sjsg  */
vce_v2_0_ring_get_rptr(struct amdgpu_ring * ring)55fb4d8502Sjsg static uint64_t vce_v2_0_ring_get_rptr(struct amdgpu_ring *ring)
56fb4d8502Sjsg {
57fb4d8502Sjsg 	struct amdgpu_device *adev = ring->adev;
58fb4d8502Sjsg 
59fb4d8502Sjsg 	if (ring->me == 0)
60fb4d8502Sjsg 		return RREG32(mmVCE_RB_RPTR);
61fb4d8502Sjsg 	else
62fb4d8502Sjsg 		return RREG32(mmVCE_RB_RPTR2);
63fb4d8502Sjsg }
64fb4d8502Sjsg 
65fb4d8502Sjsg /**
66fb4d8502Sjsg  * vce_v2_0_ring_get_wptr - get write pointer
67fb4d8502Sjsg  *
68fb4d8502Sjsg  * @ring: amdgpu_ring pointer
69fb4d8502Sjsg  *
70fb4d8502Sjsg  * Returns the current hardware write pointer
71fb4d8502Sjsg  */
vce_v2_0_ring_get_wptr(struct amdgpu_ring * ring)72fb4d8502Sjsg static uint64_t vce_v2_0_ring_get_wptr(struct amdgpu_ring *ring)
73fb4d8502Sjsg {
74fb4d8502Sjsg 	struct amdgpu_device *adev = ring->adev;
75fb4d8502Sjsg 
76fb4d8502Sjsg 	if (ring->me == 0)
77fb4d8502Sjsg 		return RREG32(mmVCE_RB_WPTR);
78fb4d8502Sjsg 	else
79fb4d8502Sjsg 		return RREG32(mmVCE_RB_WPTR2);
80fb4d8502Sjsg }
81fb4d8502Sjsg 
82fb4d8502Sjsg /**
83fb4d8502Sjsg  * vce_v2_0_ring_set_wptr - set write pointer
84fb4d8502Sjsg  *
85fb4d8502Sjsg  * @ring: amdgpu_ring pointer
86fb4d8502Sjsg  *
87fb4d8502Sjsg  * Commits the write pointer to the hardware
88fb4d8502Sjsg  */
vce_v2_0_ring_set_wptr(struct amdgpu_ring * ring)89fb4d8502Sjsg static void vce_v2_0_ring_set_wptr(struct amdgpu_ring *ring)
90fb4d8502Sjsg {
91fb4d8502Sjsg 	struct amdgpu_device *adev = ring->adev;
92fb4d8502Sjsg 
93fb4d8502Sjsg 	if (ring->me == 0)
94fb4d8502Sjsg 		WREG32(mmVCE_RB_WPTR, lower_32_bits(ring->wptr));
95fb4d8502Sjsg 	else
96fb4d8502Sjsg 		WREG32(mmVCE_RB_WPTR2, lower_32_bits(ring->wptr));
97fb4d8502Sjsg }
98fb4d8502Sjsg 
vce_v2_0_lmi_clean(struct amdgpu_device * adev)99fb4d8502Sjsg static int vce_v2_0_lmi_clean(struct amdgpu_device *adev)
100fb4d8502Sjsg {
101fb4d8502Sjsg 	int i, j;
102fb4d8502Sjsg 
103fb4d8502Sjsg 	for (i = 0; i < 10; ++i) {
104fb4d8502Sjsg 		for (j = 0; j < 100; ++j) {
105fb4d8502Sjsg 			uint32_t status = RREG32(mmVCE_LMI_STATUS);
106fb4d8502Sjsg 
107fb4d8502Sjsg 			if (status & 0x337f)
108fb4d8502Sjsg 				return 0;
109fb4d8502Sjsg 			mdelay(10);
110fb4d8502Sjsg 		}
111fb4d8502Sjsg 	}
112fb4d8502Sjsg 
113fb4d8502Sjsg 	return -ETIMEDOUT;
114fb4d8502Sjsg }
115fb4d8502Sjsg 
vce_v2_0_firmware_loaded(struct amdgpu_device * adev)116fb4d8502Sjsg static int vce_v2_0_firmware_loaded(struct amdgpu_device *adev)
117fb4d8502Sjsg {
118fb4d8502Sjsg 	int i, j;
119fb4d8502Sjsg 
120fb4d8502Sjsg 	for (i = 0; i < 10; ++i) {
121fb4d8502Sjsg 		for (j = 0; j < 100; ++j) {
122fb4d8502Sjsg 			uint32_t status = RREG32(mmVCE_STATUS);
123fb4d8502Sjsg 
124fb4d8502Sjsg 			if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK)
125fb4d8502Sjsg 				return 0;
126fb4d8502Sjsg 			mdelay(10);
127fb4d8502Sjsg 		}
128fb4d8502Sjsg 
129fb4d8502Sjsg 		DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
130fb4d8502Sjsg 		WREG32_P(mmVCE_SOFT_RESET,
131fb4d8502Sjsg 			VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
132fb4d8502Sjsg 			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
133fb4d8502Sjsg 		mdelay(10);
134fb4d8502Sjsg 		WREG32_P(mmVCE_SOFT_RESET, 0,
135fb4d8502Sjsg 			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
136fb4d8502Sjsg 		mdelay(10);
137fb4d8502Sjsg 	}
138fb4d8502Sjsg 
139fb4d8502Sjsg 	return -ETIMEDOUT;
140fb4d8502Sjsg }
141fb4d8502Sjsg 
vce_v2_0_disable_cg(struct amdgpu_device * adev)142fb4d8502Sjsg static void vce_v2_0_disable_cg(struct amdgpu_device *adev)
143fb4d8502Sjsg {
144fb4d8502Sjsg 	WREG32(mmVCE_CGTT_CLK_OVERRIDE, 7);
145fb4d8502Sjsg }
146fb4d8502Sjsg 
vce_v2_0_init_cg(struct amdgpu_device * adev)147fb4d8502Sjsg static void vce_v2_0_init_cg(struct amdgpu_device *adev)
148fb4d8502Sjsg {
149fb4d8502Sjsg 	u32 tmp;
150fb4d8502Sjsg 
151fb4d8502Sjsg 	tmp = RREG32(mmVCE_CLOCK_GATING_A);
152fb4d8502Sjsg 	tmp &= ~0xfff;
153fb4d8502Sjsg 	tmp |= ((0 << 0) | (4 << 4));
154fb4d8502Sjsg 	tmp |= 0x40000;
155fb4d8502Sjsg 	WREG32(mmVCE_CLOCK_GATING_A, tmp);
156fb4d8502Sjsg 
157fb4d8502Sjsg 	tmp = RREG32(mmVCE_UENC_CLOCK_GATING);
158fb4d8502Sjsg 	tmp &= ~0xfff;
159fb4d8502Sjsg 	tmp |= ((0 << 0) | (4 << 4));
160fb4d8502Sjsg 	WREG32(mmVCE_UENC_CLOCK_GATING, tmp);
161fb4d8502Sjsg 
162fb4d8502Sjsg 	tmp = RREG32(mmVCE_CLOCK_GATING_B);
163fb4d8502Sjsg 	tmp |= 0x10;
164fb4d8502Sjsg 	tmp &= ~0x100000;
165fb4d8502Sjsg 	WREG32(mmVCE_CLOCK_GATING_B, tmp);
166fb4d8502Sjsg }
167fb4d8502Sjsg 
vce_v2_0_mc_resume(struct amdgpu_device * adev)168fb4d8502Sjsg static void vce_v2_0_mc_resume(struct amdgpu_device *adev)
169fb4d8502Sjsg {
170fb4d8502Sjsg 	uint32_t size, offset;
171fb4d8502Sjsg 
172fb4d8502Sjsg 	WREG32_P(mmVCE_CLOCK_GATING_A, 0, ~(1 << 16));
173fb4d8502Sjsg 	WREG32_P(mmVCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000);
174fb4d8502Sjsg 	WREG32_P(mmVCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F);
175fb4d8502Sjsg 	WREG32(mmVCE_CLOCK_GATING_B, 0xf7);
176fb4d8502Sjsg 
177fb4d8502Sjsg 	WREG32(mmVCE_LMI_CTRL, 0x00398000);
178fb4d8502Sjsg 	WREG32_P(mmVCE_LMI_CACHE_CTRL, 0x0, ~0x1);
179fb4d8502Sjsg 	WREG32(mmVCE_LMI_SWAP_CNTL, 0);
180fb4d8502Sjsg 	WREG32(mmVCE_LMI_SWAP_CNTL1, 0);
181fb4d8502Sjsg 	WREG32(mmVCE_LMI_VM_CTRL, 0);
182fb4d8502Sjsg 
183fb4d8502Sjsg 	WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
184fb4d8502Sjsg 
185fb4d8502Sjsg 	offset = AMDGPU_VCE_FIRMWARE_OFFSET;
186fb4d8502Sjsg 	size = VCE_V2_0_FW_SIZE;
187fb4d8502Sjsg 	WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
188fb4d8502Sjsg 	WREG32(mmVCE_VCPU_CACHE_SIZE0, size);
189fb4d8502Sjsg 
190fb4d8502Sjsg 	offset += size;
191fb4d8502Sjsg 	size = VCE_V2_0_STACK_SIZE;
192fb4d8502Sjsg 	WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff);
193fb4d8502Sjsg 	WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
194fb4d8502Sjsg 
195fb4d8502Sjsg 	offset += size;
196fb4d8502Sjsg 	size = VCE_V2_0_DATA_SIZE;
197fb4d8502Sjsg 	WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff);
198fb4d8502Sjsg 	WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
199fb4d8502Sjsg 
200fb4d8502Sjsg 	WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100);
201fb4d8502Sjsg 	WREG32_FIELD(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 1);
202fb4d8502Sjsg }
203fb4d8502Sjsg 
vce_v2_0_is_idle(void * handle)204fb4d8502Sjsg static bool vce_v2_0_is_idle(void *handle)
205fb4d8502Sjsg {
206fb4d8502Sjsg 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
207fb4d8502Sjsg 
208fb4d8502Sjsg 	return !(RREG32(mmSRBM_STATUS2) & SRBM_STATUS2__VCE_BUSY_MASK);
209fb4d8502Sjsg }
210fb4d8502Sjsg 
vce_v2_0_wait_for_idle(void * handle)211fb4d8502Sjsg static int vce_v2_0_wait_for_idle(void *handle)
212fb4d8502Sjsg {
213fb4d8502Sjsg 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
214fb4d8502Sjsg 	unsigned i;
215fb4d8502Sjsg 
216fb4d8502Sjsg 	for (i = 0; i < adev->usec_timeout; i++) {
217fb4d8502Sjsg 		if (vce_v2_0_is_idle(handle))
218fb4d8502Sjsg 			return 0;
219fb4d8502Sjsg 	}
220fb4d8502Sjsg 	return -ETIMEDOUT;
221fb4d8502Sjsg }
222fb4d8502Sjsg 
223fb4d8502Sjsg /**
224fb4d8502Sjsg  * vce_v2_0_start - start VCE block
225fb4d8502Sjsg  *
226fb4d8502Sjsg  * @adev: amdgpu_device pointer
227fb4d8502Sjsg  *
228fb4d8502Sjsg  * Setup and start the VCE block
229fb4d8502Sjsg  */
vce_v2_0_start(struct amdgpu_device * adev)230fb4d8502Sjsg static int vce_v2_0_start(struct amdgpu_device *adev)
231fb4d8502Sjsg {
232fb4d8502Sjsg 	struct amdgpu_ring *ring;
233fb4d8502Sjsg 	int r;
234fb4d8502Sjsg 
235fb4d8502Sjsg 	/* set BUSY flag */
236fb4d8502Sjsg 	WREG32_P(mmVCE_STATUS, 1, ~1);
237fb4d8502Sjsg 
238fb4d8502Sjsg 	vce_v2_0_init_cg(adev);
239fb4d8502Sjsg 	vce_v2_0_disable_cg(adev);
240fb4d8502Sjsg 
241fb4d8502Sjsg 	vce_v2_0_mc_resume(adev);
242fb4d8502Sjsg 
243fb4d8502Sjsg 	ring = &adev->vce.ring[0];
244fb4d8502Sjsg 	WREG32(mmVCE_RB_RPTR, lower_32_bits(ring->wptr));
245fb4d8502Sjsg 	WREG32(mmVCE_RB_WPTR, lower_32_bits(ring->wptr));
246fb4d8502Sjsg 	WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr);
247fb4d8502Sjsg 	WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
248fb4d8502Sjsg 	WREG32(mmVCE_RB_SIZE, ring->ring_size / 4);
249fb4d8502Sjsg 
250fb4d8502Sjsg 	ring = &adev->vce.ring[1];
251fb4d8502Sjsg 	WREG32(mmVCE_RB_RPTR2, lower_32_bits(ring->wptr));
252fb4d8502Sjsg 	WREG32(mmVCE_RB_WPTR2, lower_32_bits(ring->wptr));
253fb4d8502Sjsg 	WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr);
254fb4d8502Sjsg 	WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
255fb4d8502Sjsg 	WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4);
256fb4d8502Sjsg 
257fb4d8502Sjsg 	WREG32_FIELD(VCE_VCPU_CNTL, CLK_EN, 1);
258fb4d8502Sjsg 	WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 1);
259fb4d8502Sjsg 	mdelay(100);
260fb4d8502Sjsg 	WREG32_FIELD(VCE_SOFT_RESET, ECPU_SOFT_RESET, 0);
261fb4d8502Sjsg 
262fb4d8502Sjsg 	r = vce_v2_0_firmware_loaded(adev);
263fb4d8502Sjsg 
264fb4d8502Sjsg 	/* clear BUSY flag */
265fb4d8502Sjsg 	WREG32_P(mmVCE_STATUS, 0, ~1);
266fb4d8502Sjsg 
267fb4d8502Sjsg 	if (r) {
268fb4d8502Sjsg 		DRM_ERROR("VCE not responding, giving up!!!\n");
269fb4d8502Sjsg 		return r;
270fb4d8502Sjsg 	}
271fb4d8502Sjsg 
272fb4d8502Sjsg 	return 0;
273fb4d8502Sjsg }
274fb4d8502Sjsg 
vce_v2_0_stop(struct amdgpu_device * adev)275fb4d8502Sjsg static int vce_v2_0_stop(struct amdgpu_device *adev)
276fb4d8502Sjsg {
277fb4d8502Sjsg 	int i;
278fb4d8502Sjsg 	int status;
279fb4d8502Sjsg 
280fb4d8502Sjsg 	if (vce_v2_0_lmi_clean(adev)) {
281fb4d8502Sjsg 		DRM_INFO("vce is not idle \n");
282fb4d8502Sjsg 		return 0;
283fb4d8502Sjsg 	}
284fb4d8502Sjsg 
285fb4d8502Sjsg 	if (vce_v2_0_wait_for_idle(adev)) {
286c349dbc7Sjsg 		DRM_INFO("VCE is busy, Can't set clock gating");
287fb4d8502Sjsg 		return 0;
288fb4d8502Sjsg 	}
289fb4d8502Sjsg 
290fb4d8502Sjsg 	/* Stall UMC and register bus before resetting VCPU */
291fb4d8502Sjsg 	WREG32_P(mmVCE_LMI_CTRL2, 1 << 8, ~(1 << 8));
292fb4d8502Sjsg 
293fb4d8502Sjsg 	for (i = 0; i < 100; ++i) {
294fb4d8502Sjsg 		status = RREG32(mmVCE_LMI_STATUS);
295fb4d8502Sjsg 		if (status & 0x240)
296fb4d8502Sjsg 			break;
297fb4d8502Sjsg 		mdelay(1);
298fb4d8502Sjsg 	}
299fb4d8502Sjsg 
300fb4d8502Sjsg 	WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x80001);
301fb4d8502Sjsg 
302fb4d8502Sjsg 	/* put LMI, VCPU, RBC etc... into reset */
303fb4d8502Sjsg 	WREG32_P(mmVCE_SOFT_RESET, 1, ~0x1);
304fb4d8502Sjsg 
305fb4d8502Sjsg 	WREG32(mmVCE_STATUS, 0);
306fb4d8502Sjsg 
307fb4d8502Sjsg 	return 0;
308fb4d8502Sjsg }
309fb4d8502Sjsg 
vce_v2_0_set_sw_cg(struct amdgpu_device * adev,bool gated)310fb4d8502Sjsg static void vce_v2_0_set_sw_cg(struct amdgpu_device *adev, bool gated)
311fb4d8502Sjsg {
312fb4d8502Sjsg 	u32 tmp;
313fb4d8502Sjsg 
314fb4d8502Sjsg 	if (gated) {
315fb4d8502Sjsg 		tmp = RREG32(mmVCE_CLOCK_GATING_B);
316fb4d8502Sjsg 		tmp |= 0xe70000;
317fb4d8502Sjsg 		WREG32(mmVCE_CLOCK_GATING_B, tmp);
318fb4d8502Sjsg 
319fb4d8502Sjsg 		tmp = RREG32(mmVCE_UENC_CLOCK_GATING);
320fb4d8502Sjsg 		tmp |= 0xff000000;
321fb4d8502Sjsg 		WREG32(mmVCE_UENC_CLOCK_GATING, tmp);
322fb4d8502Sjsg 
323fb4d8502Sjsg 		tmp = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
324fb4d8502Sjsg 		tmp &= ~0x3fc;
325fb4d8502Sjsg 		WREG32(mmVCE_UENC_REG_CLOCK_GATING, tmp);
326fb4d8502Sjsg 
327fb4d8502Sjsg 		WREG32(mmVCE_CGTT_CLK_OVERRIDE, 0);
328fb4d8502Sjsg 	} else {
329fb4d8502Sjsg 		tmp = RREG32(mmVCE_CLOCK_GATING_B);
330fb4d8502Sjsg 		tmp |= 0xe7;
331fb4d8502Sjsg 		tmp &= ~0xe70000;
332fb4d8502Sjsg 		WREG32(mmVCE_CLOCK_GATING_B, tmp);
333fb4d8502Sjsg 
334fb4d8502Sjsg 		tmp = RREG32(mmVCE_UENC_CLOCK_GATING);
335fb4d8502Sjsg 		tmp |= 0x1fe000;
336fb4d8502Sjsg 		tmp &= ~0xff000000;
337fb4d8502Sjsg 		WREG32(mmVCE_UENC_CLOCK_GATING, tmp);
338fb4d8502Sjsg 
339fb4d8502Sjsg 		tmp = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
340fb4d8502Sjsg 		tmp |= 0x3fc;
341fb4d8502Sjsg 		WREG32(mmVCE_UENC_REG_CLOCK_GATING, tmp);
342fb4d8502Sjsg 	}
343fb4d8502Sjsg }
344fb4d8502Sjsg 
vce_v2_0_set_dyn_cg(struct amdgpu_device * adev,bool gated)345fb4d8502Sjsg static void vce_v2_0_set_dyn_cg(struct amdgpu_device *adev, bool gated)
346fb4d8502Sjsg {
347fb4d8502Sjsg 	u32 orig, tmp;
348fb4d8502Sjsg 
349fb4d8502Sjsg /* LMI_MC/LMI_UMC always set in dynamic,
350fb4d8502Sjsg  * set {CGC_*_GATE_MODE, CGC_*_SW_GATE} = {0, 0}
351fb4d8502Sjsg  */
352fb4d8502Sjsg 	tmp = RREG32(mmVCE_CLOCK_GATING_B);
353fb4d8502Sjsg 	tmp &= ~0x00060006;
354fb4d8502Sjsg 
355fb4d8502Sjsg /* Exception for ECPU, IH, SEM, SYS blocks needs to be turned on/off by SW */
356fb4d8502Sjsg 	if (gated) {
357fb4d8502Sjsg 		tmp |= 0xe10000;
358fb4d8502Sjsg 		WREG32(mmVCE_CLOCK_GATING_B, tmp);
359fb4d8502Sjsg 	} else {
360fb4d8502Sjsg 		tmp |= 0xe1;
361fb4d8502Sjsg 		tmp &= ~0xe10000;
362fb4d8502Sjsg 		WREG32(mmVCE_CLOCK_GATING_B, tmp);
363fb4d8502Sjsg 	}
364fb4d8502Sjsg 
365fb4d8502Sjsg 	orig = tmp = RREG32(mmVCE_UENC_CLOCK_GATING);
366fb4d8502Sjsg 	tmp &= ~0x1fe000;
367fb4d8502Sjsg 	tmp &= ~0xff000000;
368fb4d8502Sjsg 	if (tmp != orig)
369fb4d8502Sjsg 		WREG32(mmVCE_UENC_CLOCK_GATING, tmp);
370fb4d8502Sjsg 
371fb4d8502Sjsg 	orig = tmp = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
372fb4d8502Sjsg 	tmp &= ~0x3fc;
373fb4d8502Sjsg 	if (tmp != orig)
374fb4d8502Sjsg 		WREG32(mmVCE_UENC_REG_CLOCK_GATING, tmp);
375fb4d8502Sjsg 
376fb4d8502Sjsg 	/* set VCE_UENC_REG_CLOCK_GATING always in dynamic mode */
377fb4d8502Sjsg 	WREG32(mmVCE_UENC_REG_CLOCK_GATING, 0x00);
378fb4d8502Sjsg 
379fb4d8502Sjsg 	if(gated)
380fb4d8502Sjsg 		WREG32(mmVCE_CGTT_CLK_OVERRIDE, 0);
381fb4d8502Sjsg }
382fb4d8502Sjsg 
vce_v2_0_enable_mgcg(struct amdgpu_device * adev,bool enable,bool sw_cg)383fb4d8502Sjsg static void vce_v2_0_enable_mgcg(struct amdgpu_device *adev, bool enable,
384fb4d8502Sjsg 								bool sw_cg)
385fb4d8502Sjsg {
386fb4d8502Sjsg 	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) {
387fb4d8502Sjsg 		if (sw_cg)
388fb4d8502Sjsg 			vce_v2_0_set_sw_cg(adev, true);
389fb4d8502Sjsg 		else
390fb4d8502Sjsg 			vce_v2_0_set_dyn_cg(adev, true);
391fb4d8502Sjsg 	} else {
392fb4d8502Sjsg 		vce_v2_0_disable_cg(adev);
393fb4d8502Sjsg 
394fb4d8502Sjsg 		if (sw_cg)
395fb4d8502Sjsg 			vce_v2_0_set_sw_cg(adev, false);
396fb4d8502Sjsg 		else
397fb4d8502Sjsg 			vce_v2_0_set_dyn_cg(adev, false);
398fb4d8502Sjsg 	}
399fb4d8502Sjsg }
400fb4d8502Sjsg 
vce_v2_0_early_init(void * handle)401fb4d8502Sjsg static int vce_v2_0_early_init(void *handle)
402fb4d8502Sjsg {
403fb4d8502Sjsg 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
404fb4d8502Sjsg 
405fb4d8502Sjsg 	adev->vce.num_rings = 2;
406fb4d8502Sjsg 
407fb4d8502Sjsg 	vce_v2_0_set_ring_funcs(adev);
408fb4d8502Sjsg 	vce_v2_0_set_irq_funcs(adev);
409fb4d8502Sjsg 
410fb4d8502Sjsg 	return 0;
411fb4d8502Sjsg }
412fb4d8502Sjsg 
vce_v2_0_sw_init(void * handle)413fb4d8502Sjsg static int vce_v2_0_sw_init(void *handle)
414fb4d8502Sjsg {
415fb4d8502Sjsg 	struct amdgpu_ring *ring;
416fb4d8502Sjsg 	int r, i;
417fb4d8502Sjsg 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
418fb4d8502Sjsg 
419fb4d8502Sjsg 	/* VCE */
420c349dbc7Sjsg 	r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, 167, &adev->vce.irq);
421fb4d8502Sjsg 	if (r)
422fb4d8502Sjsg 		return r;
423fb4d8502Sjsg 
424fb4d8502Sjsg 	r = amdgpu_vce_sw_init(adev, VCE_V2_0_FW_SIZE +
425fb4d8502Sjsg 		VCE_V2_0_STACK_SIZE + VCE_V2_0_DATA_SIZE);
426fb4d8502Sjsg 	if (r)
427fb4d8502Sjsg 		return r;
428fb4d8502Sjsg 
429fb4d8502Sjsg 	r = amdgpu_vce_resume(adev);
430fb4d8502Sjsg 	if (r)
431fb4d8502Sjsg 		return r;
432fb4d8502Sjsg 
433fb4d8502Sjsg 	for (i = 0; i < adev->vce.num_rings; i++) {
434*1bb76ff1Sjsg 		enum amdgpu_ring_priority_level hw_prio = amdgpu_vce_get_ring_prio(i);
435*1bb76ff1Sjsg 
436fb4d8502Sjsg 		ring = &adev->vce.ring[i];
437fb4d8502Sjsg 		snprintf(ring->name, sizeof(ring->name), "vce%d", i);
4385ca02815Sjsg 		r = amdgpu_ring_init(adev, ring, 512, &adev->vce.irq, 0,
439*1bb76ff1Sjsg 				     hw_prio, NULL);
440fb4d8502Sjsg 		if (r)
441fb4d8502Sjsg 			return r;
442fb4d8502Sjsg 	}
443fb4d8502Sjsg 
444fb4d8502Sjsg 	r = amdgpu_vce_entity_init(adev);
445fb4d8502Sjsg 
446fb4d8502Sjsg 	return r;
447fb4d8502Sjsg }
448fb4d8502Sjsg 
vce_v2_0_sw_fini(void * handle)449fb4d8502Sjsg static int vce_v2_0_sw_fini(void *handle)
450fb4d8502Sjsg {
451fb4d8502Sjsg 	int r;
452fb4d8502Sjsg 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
453fb4d8502Sjsg 
454fb4d8502Sjsg 	r = amdgpu_vce_suspend(adev);
455fb4d8502Sjsg 	if (r)
456fb4d8502Sjsg 		return r;
457fb4d8502Sjsg 
458fb4d8502Sjsg 	return amdgpu_vce_sw_fini(adev);
459fb4d8502Sjsg }
460fb4d8502Sjsg 
vce_v2_0_hw_init(void * handle)461fb4d8502Sjsg static int vce_v2_0_hw_init(void *handle)
462fb4d8502Sjsg {
463fb4d8502Sjsg 	int r, i;
464fb4d8502Sjsg 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
465fb4d8502Sjsg 
466fb4d8502Sjsg 	amdgpu_asic_set_vce_clocks(adev, 10000, 10000);
467fb4d8502Sjsg 	vce_v2_0_enable_mgcg(adev, true, false);
468fb4d8502Sjsg 
469fb4d8502Sjsg 	for (i = 0; i < adev->vce.num_rings; i++) {
470c349dbc7Sjsg 		r = amdgpu_ring_test_helper(&adev->vce.ring[i]);
471fb4d8502Sjsg 		if (r)
472fb4d8502Sjsg 			return r;
473fb4d8502Sjsg 	}
474fb4d8502Sjsg 
475fb4d8502Sjsg 	DRM_INFO("VCE initialized successfully.\n");
476fb4d8502Sjsg 
477fb4d8502Sjsg 	return 0;
478fb4d8502Sjsg }
479fb4d8502Sjsg 
vce_v2_0_hw_fini(void * handle)480fb4d8502Sjsg static int vce_v2_0_hw_fini(void *handle)
481fb4d8502Sjsg {
4825ca02815Sjsg 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
4835ca02815Sjsg 
4845ca02815Sjsg 	cancel_delayed_work_sync(&adev->vce.idle_work);
4855ca02815Sjsg 
486fb4d8502Sjsg 	return 0;
487fb4d8502Sjsg }
488fb4d8502Sjsg 
vce_v2_0_suspend(void * handle)489fb4d8502Sjsg static int vce_v2_0_suspend(void *handle)
490fb4d8502Sjsg {
491fb4d8502Sjsg 	int r;
492fb4d8502Sjsg 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
493fb4d8502Sjsg 
4945ca02815Sjsg 
4955ca02815Sjsg 	/*
4965ca02815Sjsg 	 * Proper cleanups before halting the HW engine:
4975ca02815Sjsg 	 *   - cancel the delayed idle work
4985ca02815Sjsg 	 *   - enable powergating
4995ca02815Sjsg 	 *   - enable clockgating
5005ca02815Sjsg 	 *   - disable dpm
5015ca02815Sjsg 	 *
5025ca02815Sjsg 	 * TODO: to align with the VCN implementation, move the
5035ca02815Sjsg 	 * jobs for clockgating/powergating/dpm setting to
5045ca02815Sjsg 	 * ->set_powergating_state().
5055ca02815Sjsg 	 */
5065ca02815Sjsg 	cancel_delayed_work_sync(&adev->vce.idle_work);
5075ca02815Sjsg 
5085ca02815Sjsg 	if (adev->pm.dpm_enabled) {
5095ca02815Sjsg 		amdgpu_dpm_enable_vce(adev, false);
5105ca02815Sjsg 	} else {
5115ca02815Sjsg 		amdgpu_asic_set_vce_clocks(adev, 0, 0);
5125ca02815Sjsg 		amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
5135ca02815Sjsg 						       AMD_PG_STATE_GATE);
5145ca02815Sjsg 		amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
5155ca02815Sjsg 						       AMD_CG_STATE_GATE);
5165ca02815Sjsg 	}
5175ca02815Sjsg 
518fb4d8502Sjsg 	r = vce_v2_0_hw_fini(adev);
519fb4d8502Sjsg 	if (r)
520fb4d8502Sjsg 		return r;
521fb4d8502Sjsg 
522fb4d8502Sjsg 	return amdgpu_vce_suspend(adev);
523fb4d8502Sjsg }
524fb4d8502Sjsg 
vce_v2_0_resume(void * handle)525fb4d8502Sjsg static int vce_v2_0_resume(void *handle)
526fb4d8502Sjsg {
527fb4d8502Sjsg 	int r;
528fb4d8502Sjsg 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
529fb4d8502Sjsg 
530fb4d8502Sjsg 	r = amdgpu_vce_resume(adev);
531fb4d8502Sjsg 	if (r)
532fb4d8502Sjsg 		return r;
533fb4d8502Sjsg 
534fb4d8502Sjsg 	return vce_v2_0_hw_init(adev);
535fb4d8502Sjsg }
536fb4d8502Sjsg 
vce_v2_0_soft_reset(void * handle)537fb4d8502Sjsg static int vce_v2_0_soft_reset(void *handle)
538fb4d8502Sjsg {
539fb4d8502Sjsg 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
540fb4d8502Sjsg 
541fb4d8502Sjsg 	WREG32_FIELD(SRBM_SOFT_RESET, SOFT_RESET_VCE, 1);
542fb4d8502Sjsg 	mdelay(5);
543fb4d8502Sjsg 
544fb4d8502Sjsg 	return vce_v2_0_start(adev);
545fb4d8502Sjsg }
546fb4d8502Sjsg 
vce_v2_0_set_interrupt_state(struct amdgpu_device * adev,struct amdgpu_irq_src * source,unsigned type,enum amdgpu_interrupt_state state)547fb4d8502Sjsg static int vce_v2_0_set_interrupt_state(struct amdgpu_device *adev,
548fb4d8502Sjsg 					struct amdgpu_irq_src *source,
549fb4d8502Sjsg 					unsigned type,
550fb4d8502Sjsg 					enum amdgpu_interrupt_state state)
551fb4d8502Sjsg {
552fb4d8502Sjsg 	uint32_t val = 0;
553fb4d8502Sjsg 
554fb4d8502Sjsg 	if (state == AMDGPU_IRQ_STATE_ENABLE)
555fb4d8502Sjsg 		val |= VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK;
556fb4d8502Sjsg 
557fb4d8502Sjsg 	WREG32_P(mmVCE_SYS_INT_EN, val, ~VCE_SYS_INT_EN__VCE_SYS_INT_TRAP_INTERRUPT_EN_MASK);
558fb4d8502Sjsg 	return 0;
559fb4d8502Sjsg }
560fb4d8502Sjsg 
vce_v2_0_process_interrupt(struct amdgpu_device * adev,struct amdgpu_irq_src * source,struct amdgpu_iv_entry * entry)561fb4d8502Sjsg static int vce_v2_0_process_interrupt(struct amdgpu_device *adev,
562fb4d8502Sjsg 				      struct amdgpu_irq_src *source,
563fb4d8502Sjsg 				      struct amdgpu_iv_entry *entry)
564fb4d8502Sjsg {
565fb4d8502Sjsg 	DRM_DEBUG("IH: VCE\n");
566fb4d8502Sjsg 	switch (entry->src_data[0]) {
567fb4d8502Sjsg 	case 0:
568fb4d8502Sjsg 	case 1:
569fb4d8502Sjsg 		amdgpu_fence_process(&adev->vce.ring[entry->src_data[0]]);
570fb4d8502Sjsg 		break;
571fb4d8502Sjsg 	default:
572fb4d8502Sjsg 		DRM_ERROR("Unhandled interrupt: %d %d\n",
573fb4d8502Sjsg 			  entry->src_id, entry->src_data[0]);
574fb4d8502Sjsg 		break;
575fb4d8502Sjsg 	}
576fb4d8502Sjsg 
577fb4d8502Sjsg 	return 0;
578fb4d8502Sjsg }
579fb4d8502Sjsg 
vce_v2_0_set_clockgating_state(void * handle,enum amd_clockgating_state state)580fb4d8502Sjsg static int vce_v2_0_set_clockgating_state(void *handle,
581fb4d8502Sjsg 					  enum amd_clockgating_state state)
582fb4d8502Sjsg {
583fb4d8502Sjsg 	bool gate = false;
584fb4d8502Sjsg 	bool sw_cg = false;
585fb4d8502Sjsg 
586fb4d8502Sjsg 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
587fb4d8502Sjsg 
588fb4d8502Sjsg 	if (state == AMD_CG_STATE_GATE) {
589fb4d8502Sjsg 		gate = true;
590fb4d8502Sjsg 		sw_cg = true;
591fb4d8502Sjsg 	}
592fb4d8502Sjsg 
593fb4d8502Sjsg 	vce_v2_0_enable_mgcg(adev, gate, sw_cg);
594fb4d8502Sjsg 
595fb4d8502Sjsg 	return 0;
596fb4d8502Sjsg }
597fb4d8502Sjsg 
vce_v2_0_set_powergating_state(void * handle,enum amd_powergating_state state)598fb4d8502Sjsg static int vce_v2_0_set_powergating_state(void *handle,
599fb4d8502Sjsg 					  enum amd_powergating_state state)
600fb4d8502Sjsg {
601fb4d8502Sjsg 	/* This doesn't actually powergate the VCE block.
602fb4d8502Sjsg 	 * That's done in the dpm code via the SMC.  This
603fb4d8502Sjsg 	 * just re-inits the block as necessary.  The actual
604fb4d8502Sjsg 	 * gating still happens in the dpm code.  We should
605fb4d8502Sjsg 	 * revisit this when there is a cleaner line between
606fb4d8502Sjsg 	 * the smc and the hw blocks
607fb4d8502Sjsg 	 */
608fb4d8502Sjsg 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
609fb4d8502Sjsg 
610fb4d8502Sjsg 	if (state == AMD_PG_STATE_GATE)
611fb4d8502Sjsg 		return vce_v2_0_stop(adev);
612fb4d8502Sjsg 	else
613fb4d8502Sjsg 		return vce_v2_0_start(adev);
614fb4d8502Sjsg }
615fb4d8502Sjsg 
616fb4d8502Sjsg static const struct amd_ip_funcs vce_v2_0_ip_funcs = {
617fb4d8502Sjsg 	.name = "vce_v2_0",
618fb4d8502Sjsg 	.early_init = vce_v2_0_early_init,
619fb4d8502Sjsg 	.late_init = NULL,
620fb4d8502Sjsg 	.sw_init = vce_v2_0_sw_init,
621fb4d8502Sjsg 	.sw_fini = vce_v2_0_sw_fini,
622fb4d8502Sjsg 	.hw_init = vce_v2_0_hw_init,
623fb4d8502Sjsg 	.hw_fini = vce_v2_0_hw_fini,
624fb4d8502Sjsg 	.suspend = vce_v2_0_suspend,
625fb4d8502Sjsg 	.resume = vce_v2_0_resume,
626fb4d8502Sjsg 	.is_idle = vce_v2_0_is_idle,
627fb4d8502Sjsg 	.wait_for_idle = vce_v2_0_wait_for_idle,
628fb4d8502Sjsg 	.soft_reset = vce_v2_0_soft_reset,
629fb4d8502Sjsg 	.set_clockgating_state = vce_v2_0_set_clockgating_state,
630fb4d8502Sjsg 	.set_powergating_state = vce_v2_0_set_powergating_state,
631fb4d8502Sjsg };
632fb4d8502Sjsg 
633fb4d8502Sjsg static const struct amdgpu_ring_funcs vce_v2_0_ring_funcs = {
634fb4d8502Sjsg 	.type = AMDGPU_RING_TYPE_VCE,
635fb4d8502Sjsg 	.align_mask = 0xf,
636fb4d8502Sjsg 	.nop = VCE_CMD_NO_OP,
637fb4d8502Sjsg 	.support_64bit_ptrs = false,
638c349dbc7Sjsg 	.no_user_fence = true,
639fb4d8502Sjsg 	.get_rptr = vce_v2_0_ring_get_rptr,
640fb4d8502Sjsg 	.get_wptr = vce_v2_0_ring_get_wptr,
641fb4d8502Sjsg 	.set_wptr = vce_v2_0_ring_set_wptr,
642fb4d8502Sjsg 	.parse_cs = amdgpu_vce_ring_parse_cs,
643fb4d8502Sjsg 	.emit_frame_size = 6, /* amdgpu_vce_ring_emit_fence  x1 no user fence */
644fb4d8502Sjsg 	.emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */
645fb4d8502Sjsg 	.emit_ib = amdgpu_vce_ring_emit_ib,
646fb4d8502Sjsg 	.emit_fence = amdgpu_vce_ring_emit_fence,
647fb4d8502Sjsg 	.test_ring = amdgpu_vce_ring_test_ring,
648fb4d8502Sjsg 	.test_ib = amdgpu_vce_ring_test_ib,
649fb4d8502Sjsg 	.insert_nop = amdgpu_ring_insert_nop,
650fb4d8502Sjsg 	.pad_ib = amdgpu_ring_generic_pad_ib,
651fb4d8502Sjsg 	.begin_use = amdgpu_vce_ring_begin_use,
652fb4d8502Sjsg 	.end_use = amdgpu_vce_ring_end_use,
653fb4d8502Sjsg };
654fb4d8502Sjsg 
vce_v2_0_set_ring_funcs(struct amdgpu_device * adev)655fb4d8502Sjsg static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev)
656fb4d8502Sjsg {
657fb4d8502Sjsg 	int i;
658fb4d8502Sjsg 
659fb4d8502Sjsg 	for (i = 0; i < adev->vce.num_rings; i++) {
660fb4d8502Sjsg 		adev->vce.ring[i].funcs = &vce_v2_0_ring_funcs;
661fb4d8502Sjsg 		adev->vce.ring[i].me = i;
662fb4d8502Sjsg 	}
663fb4d8502Sjsg }
664fb4d8502Sjsg 
665fb4d8502Sjsg static const struct amdgpu_irq_src_funcs vce_v2_0_irq_funcs = {
666fb4d8502Sjsg 	.set = vce_v2_0_set_interrupt_state,
667fb4d8502Sjsg 	.process = vce_v2_0_process_interrupt,
668fb4d8502Sjsg };
669fb4d8502Sjsg 
vce_v2_0_set_irq_funcs(struct amdgpu_device * adev)670fb4d8502Sjsg static void vce_v2_0_set_irq_funcs(struct amdgpu_device *adev)
671fb4d8502Sjsg {
672fb4d8502Sjsg 	adev->vce.irq.num_types = 1;
673fb4d8502Sjsg 	adev->vce.irq.funcs = &vce_v2_0_irq_funcs;
674fb4d8502Sjsg };
675fb4d8502Sjsg 
676fb4d8502Sjsg const struct amdgpu_ip_block_version vce_v2_0_ip_block =
677fb4d8502Sjsg {
678fb4d8502Sjsg 		.type = AMD_IP_BLOCK_TYPE_VCE,
679fb4d8502Sjsg 		.major = 2,
680fb4d8502Sjsg 		.minor = 0,
681fb4d8502Sjsg 		.rev = 0,
682fb4d8502Sjsg 		.funcs = &vce_v2_0_ip_funcs,
683fb4d8502Sjsg };
684