xref: /openbmc/linux/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c (revision c8a14396)
1b38f3e80SSonny Jiang /*
2b38f3e80SSonny Jiang  * Copyright 2020 Advanced Micro Devices, Inc.
3b38f3e80SSonny Jiang  *
4b38f3e80SSonny Jiang  * Permission is hereby granted, free of charge, to any person obtaining a
5b38f3e80SSonny Jiang  * copy of this software and associated documentation files (the "Software"),
6b38f3e80SSonny Jiang  * to deal in the Software without restriction, including without limitation
7b38f3e80SSonny Jiang  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b38f3e80SSonny Jiang  * and/or sell copies of the Software, and to permit persons to whom the
9b38f3e80SSonny Jiang  * Software is furnished to do so, subject to the following conditions:
10b38f3e80SSonny Jiang  *
11b38f3e80SSonny Jiang  * The above copyright notice and this permission notice shall be included in
12b38f3e80SSonny Jiang  * all copies or substantial portions of the Software.
13b38f3e80SSonny Jiang  *
14b38f3e80SSonny Jiang  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15b38f3e80SSonny Jiang  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16b38f3e80SSonny Jiang  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17b38f3e80SSonny Jiang  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18b38f3e80SSonny Jiang  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19b38f3e80SSonny Jiang  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20b38f3e80SSonny Jiang  * OTHER DEALINGS IN THE SOFTWARE.
21b38f3e80SSonny Jiang  *
22b38f3e80SSonny Jiang  * Authors: Sonny Jiang <sonny.jiang@amd.com>
23b38f3e80SSonny Jiang  */
24b38f3e80SSonny Jiang 
25b38f3e80SSonny Jiang #include <linux/firmware.h>
26b38f3e80SSonny Jiang 
27b38f3e80SSonny Jiang #include "amdgpu.h"
28b38f3e80SSonny Jiang #include "amdgpu_uvd.h"
29b38f3e80SSonny Jiang #include "sid.h"
30b38f3e80SSonny Jiang 
31b38f3e80SSonny Jiang #include "uvd/uvd_3_1_d.h"
32b38f3e80SSonny Jiang #include "uvd/uvd_3_1_sh_mask.h"
33b38f3e80SSonny Jiang 
34b38f3e80SSonny Jiang #include "oss/oss_1_0_d.h"
35b38f3e80SSonny Jiang #include "oss/oss_1_0_sh_mask.h"
36b38f3e80SSonny Jiang 
37b38f3e80SSonny Jiang /**
38b38f3e80SSonny Jiang  * uvd_v3_1_ring_get_rptr - get read pointer
39b38f3e80SSonny Jiang  *
40b38f3e80SSonny Jiang  * @ring: amdgpu_ring pointer
41b38f3e80SSonny Jiang  *
42b38f3e80SSonny Jiang  * Returns the current hardware read pointer
43b38f3e80SSonny Jiang  */
uvd_v3_1_ring_get_rptr(struct amdgpu_ring * ring)44b38f3e80SSonny Jiang static uint64_t uvd_v3_1_ring_get_rptr(struct amdgpu_ring *ring)
45b38f3e80SSonny Jiang {
46b38f3e80SSonny Jiang 	struct amdgpu_device *adev = ring->adev;
47b38f3e80SSonny Jiang 
48b38f3e80SSonny Jiang 	return RREG32(mmUVD_RBC_RB_RPTR);
49b38f3e80SSonny Jiang }
50b38f3e80SSonny Jiang 
51b38f3e80SSonny Jiang /**
52b38f3e80SSonny Jiang  * uvd_v3_1_ring_get_wptr - get write pointer
53b38f3e80SSonny Jiang  *
54b38f3e80SSonny Jiang  * @ring: amdgpu_ring pointer
55b38f3e80SSonny Jiang  *
56b38f3e80SSonny Jiang  * Returns the current hardware write pointer
57b38f3e80SSonny Jiang  */
uvd_v3_1_ring_get_wptr(struct amdgpu_ring * ring)58b38f3e80SSonny Jiang static uint64_t uvd_v3_1_ring_get_wptr(struct amdgpu_ring *ring)
59b38f3e80SSonny Jiang {
60b38f3e80SSonny Jiang 	struct amdgpu_device *adev = ring->adev;
61b38f3e80SSonny Jiang 
62b38f3e80SSonny Jiang 	return RREG32(mmUVD_RBC_RB_WPTR);
63b38f3e80SSonny Jiang }
64b38f3e80SSonny Jiang 
65b38f3e80SSonny Jiang /**
66b38f3e80SSonny Jiang  * uvd_v3_1_ring_set_wptr - set write pointer
67b38f3e80SSonny Jiang  *
68b38f3e80SSonny Jiang  * @ring: amdgpu_ring pointer
69b38f3e80SSonny Jiang  *
70b38f3e80SSonny Jiang  * Commits the write pointer to the hardware
71b38f3e80SSonny Jiang  */
uvd_v3_1_ring_set_wptr(struct amdgpu_ring * ring)72b38f3e80SSonny Jiang static void uvd_v3_1_ring_set_wptr(struct amdgpu_ring *ring)
73b38f3e80SSonny Jiang {
74b38f3e80SSonny Jiang 	struct amdgpu_device *adev = ring->adev;
75b38f3e80SSonny Jiang 
76b38f3e80SSonny Jiang 	WREG32(mmUVD_RBC_RB_WPTR, lower_32_bits(ring->wptr));
77b38f3e80SSonny Jiang }
78b38f3e80SSonny Jiang 
79b38f3e80SSonny Jiang /**
80b38f3e80SSonny Jiang  * uvd_v3_1_ring_emit_ib - execute indirect buffer
81b38f3e80SSonny Jiang  *
82b38f3e80SSonny Jiang  * @ring: amdgpu_ring pointer
83e4c980c3SLee Jones  * @job: iob associated with the indirect buffer
84b38f3e80SSonny Jiang  * @ib: indirect buffer to execute
85e4c980c3SLee Jones  * @flags: flags associated with the indirect buffer
86b38f3e80SSonny Jiang  *
87b38f3e80SSonny Jiang  * Write ring commands to execute the indirect buffer
88b38f3e80SSonny Jiang  */
uvd_v3_1_ring_emit_ib(struct amdgpu_ring * ring,struct amdgpu_job * job,struct amdgpu_ib * ib,uint32_t flags)89b38f3e80SSonny Jiang static void uvd_v3_1_ring_emit_ib(struct amdgpu_ring *ring,
90b38f3e80SSonny Jiang 				  struct amdgpu_job *job,
91b38f3e80SSonny Jiang 				  struct amdgpu_ib *ib,
92b38f3e80SSonny Jiang 				  uint32_t flags)
93b38f3e80SSonny Jiang {
94b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, PACKET0(mmUVD_RBC_IB_BASE, 0));
95b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, ib->gpu_addr);
96b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, PACKET0(mmUVD_RBC_IB_SIZE, 0));
97b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, ib->length_dw);
98b38f3e80SSonny Jiang }
99b38f3e80SSonny Jiang 
100b38f3e80SSonny Jiang /**
101b38f3e80SSonny Jiang  * uvd_v3_1_ring_emit_fence - emit an fence & trap command
102b38f3e80SSonny Jiang  *
103b38f3e80SSonny Jiang  * @ring: amdgpu_ring pointer
104e4c980c3SLee Jones  * @addr: address
105e4c980c3SLee Jones  * @seq: sequence number
106e4c980c3SLee Jones  * @flags: fence related flags
107b38f3e80SSonny Jiang  *
108b38f3e80SSonny Jiang  * Write a fence and a trap command to the ring.
109b38f3e80SSonny Jiang  */
uvd_v3_1_ring_emit_fence(struct amdgpu_ring * ring,u64 addr,u64 seq,unsigned flags)110b38f3e80SSonny Jiang static void uvd_v3_1_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
111b38f3e80SSonny Jiang 				 unsigned flags)
112b38f3e80SSonny Jiang {
113b38f3e80SSonny Jiang 	WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
114b38f3e80SSonny Jiang 
115b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, PACKET0(mmUVD_CONTEXT_ID, 0));
116b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, seq);
117b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0));
118b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, addr & 0xffffffff);
119b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_DATA1, 0));
120b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, upper_32_bits(addr) & 0xff);
121b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_CMD, 0));
122b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, 0);
123b38f3e80SSonny Jiang 
124b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0));
125b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, 0);
126b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_DATA1, 0));
127b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, 0);
128b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_CMD, 0));
129b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, 2);
130b38f3e80SSonny Jiang }
131b38f3e80SSonny Jiang 
132b38f3e80SSonny Jiang /**
133b38f3e80SSonny Jiang  * uvd_v3_1_ring_test_ring - register write test
134b38f3e80SSonny Jiang  *
135b38f3e80SSonny Jiang  * @ring: amdgpu_ring pointer
136b38f3e80SSonny Jiang  *
137b38f3e80SSonny Jiang  * Test if we can successfully write to the context register
138b38f3e80SSonny Jiang  */
uvd_v3_1_ring_test_ring(struct amdgpu_ring * ring)139b38f3e80SSonny Jiang static int uvd_v3_1_ring_test_ring(struct amdgpu_ring *ring)
140b38f3e80SSonny Jiang {
141b38f3e80SSonny Jiang 	struct amdgpu_device *adev = ring->adev;
142b38f3e80SSonny Jiang 	uint32_t tmp = 0;
143b38f3e80SSonny Jiang 	unsigned i;
144b38f3e80SSonny Jiang 	int r;
145b38f3e80SSonny Jiang 
146b38f3e80SSonny Jiang 	WREG32(mmUVD_CONTEXT_ID, 0xCAFEDEAD);
147b38f3e80SSonny Jiang 	r = amdgpu_ring_alloc(ring, 3);
148b38f3e80SSonny Jiang 	if (r)
149b38f3e80SSonny Jiang 		return r;
150b38f3e80SSonny Jiang 
151b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, PACKET0(mmUVD_CONTEXT_ID, 0));
152b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, 0xDEADBEEF);
153b38f3e80SSonny Jiang 	amdgpu_ring_commit(ring);
154b38f3e80SSonny Jiang 	for (i = 0; i < adev->usec_timeout; i++) {
155b38f3e80SSonny Jiang 		tmp = RREG32(mmUVD_CONTEXT_ID);
156b38f3e80SSonny Jiang 		if (tmp == 0xDEADBEEF)
157b38f3e80SSonny Jiang 			break;
158b38f3e80SSonny Jiang 		udelay(1);
159b38f3e80SSonny Jiang 	}
160b38f3e80SSonny Jiang 
161b38f3e80SSonny Jiang 	if (i >= adev->usec_timeout)
162b38f3e80SSonny Jiang 		r = -ETIMEDOUT;
163b38f3e80SSonny Jiang 
164b38f3e80SSonny Jiang 	return r;
165b38f3e80SSonny Jiang }
166b38f3e80SSonny Jiang 
uvd_v3_1_ring_insert_nop(struct amdgpu_ring * ring,uint32_t count)167b38f3e80SSonny Jiang static void uvd_v3_1_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
168b38f3e80SSonny Jiang {
169b38f3e80SSonny Jiang 	int i;
170b38f3e80SSonny Jiang 
171b38f3e80SSonny Jiang 	WARN_ON(ring->wptr % 2 || count % 2);
172b38f3e80SSonny Jiang 
173b38f3e80SSonny Jiang 	for (i = 0; i < count / 2; i++) {
174b38f3e80SSonny Jiang 		amdgpu_ring_write(ring, PACKET0(mmUVD_NO_OP, 0));
175b38f3e80SSonny Jiang 		amdgpu_ring_write(ring, 0);
176b38f3e80SSonny Jiang 	}
177b38f3e80SSonny Jiang }
178b38f3e80SSonny Jiang 
179b38f3e80SSonny Jiang static const struct amdgpu_ring_funcs uvd_v3_1_ring_funcs = {
180b38f3e80SSonny Jiang 	.type = AMDGPU_RING_TYPE_UVD,
181b38f3e80SSonny Jiang 	.align_mask = 0xf,
182b38f3e80SSonny Jiang 	.support_64bit_ptrs = false,
183b38f3e80SSonny Jiang 	.no_user_fence = true,
184b38f3e80SSonny Jiang 	.get_rptr = uvd_v3_1_ring_get_rptr,
185b38f3e80SSonny Jiang 	.get_wptr = uvd_v3_1_ring_get_wptr,
186b38f3e80SSonny Jiang 	.set_wptr = uvd_v3_1_ring_set_wptr,
187b38f3e80SSonny Jiang 	.parse_cs = amdgpu_uvd_ring_parse_cs,
188b38f3e80SSonny Jiang 	.emit_frame_size =
189b38f3e80SSonny Jiang 		14, /* uvd_v3_1_ring_emit_fence  x1 no user fence */
190b38f3e80SSonny Jiang 	.emit_ib_size = 4, /* uvd_v3_1_ring_emit_ib */
191b38f3e80SSonny Jiang 	.emit_ib = uvd_v3_1_ring_emit_ib,
192b38f3e80SSonny Jiang 	.emit_fence = uvd_v3_1_ring_emit_fence,
193b38f3e80SSonny Jiang 	.test_ring = uvd_v3_1_ring_test_ring,
194b38f3e80SSonny Jiang 	.test_ib = amdgpu_uvd_ring_test_ib,
195b38f3e80SSonny Jiang 	.insert_nop = uvd_v3_1_ring_insert_nop,
196b38f3e80SSonny Jiang 	.pad_ib = amdgpu_ring_generic_pad_ib,
197b38f3e80SSonny Jiang 	.begin_use = amdgpu_uvd_ring_begin_use,
198b38f3e80SSonny Jiang 	.end_use = amdgpu_uvd_ring_end_use,
199b38f3e80SSonny Jiang };
200b38f3e80SSonny Jiang 
uvd_v3_1_set_ring_funcs(struct amdgpu_device * adev)201b38f3e80SSonny Jiang static void uvd_v3_1_set_ring_funcs(struct amdgpu_device *adev)
202b38f3e80SSonny Jiang {
203b38f3e80SSonny Jiang 	adev->uvd.inst->ring.funcs = &uvd_v3_1_ring_funcs;
204b38f3e80SSonny Jiang }
205b38f3e80SSonny Jiang 
uvd_v3_1_set_dcm(struct amdgpu_device * adev,bool sw_mode)206b38f3e80SSonny Jiang static void uvd_v3_1_set_dcm(struct amdgpu_device *adev,
207b38f3e80SSonny Jiang 							 bool sw_mode)
208b38f3e80SSonny Jiang {
209b38f3e80SSonny Jiang 	u32 tmp, tmp2;
210b38f3e80SSonny Jiang 
211b38f3e80SSonny Jiang 	WREG32_FIELD(UVD_CGC_GATE, REGS, 0);
212b38f3e80SSonny Jiang 
213b38f3e80SSonny Jiang 	tmp = RREG32(mmUVD_CGC_CTRL);
214b38f3e80SSonny Jiang 	tmp &= ~(UVD_CGC_CTRL__CLK_OFF_DELAY_MASK | UVD_CGC_CTRL__CLK_GATE_DLY_TIMER_MASK);
215b38f3e80SSonny Jiang 	tmp |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK |
216b38f3e80SSonny Jiang 		(1 << UVD_CGC_CTRL__CLK_GATE_DLY_TIMER__SHIFT) |
217b38f3e80SSonny Jiang 		(4 << UVD_CGC_CTRL__CLK_OFF_DELAY__SHIFT);
218b38f3e80SSonny Jiang 
219b38f3e80SSonny Jiang 	if (sw_mode) {
220b38f3e80SSonny Jiang 		tmp &= ~0x7ffff800;
221b38f3e80SSonny Jiang 		tmp2 = UVD_CGC_CTRL2__DYN_OCLK_RAMP_EN_MASK |
222b38f3e80SSonny Jiang 			UVD_CGC_CTRL2__DYN_RCLK_RAMP_EN_MASK |
223b38f3e80SSonny Jiang 			(7 << UVD_CGC_CTRL2__GATER_DIV_ID__SHIFT);
224b38f3e80SSonny Jiang 	} else {
225b38f3e80SSonny Jiang 		tmp |= 0x7ffff800;
226b38f3e80SSonny Jiang 		tmp2 = 0;
227b38f3e80SSonny Jiang 	}
228b38f3e80SSonny Jiang 
229b38f3e80SSonny Jiang 	WREG32(mmUVD_CGC_CTRL, tmp);
230b38f3e80SSonny Jiang 	WREG32_UVD_CTX(ixUVD_CGC_CTRL2, tmp2);
231b38f3e80SSonny Jiang }
232b38f3e80SSonny Jiang 
233b38f3e80SSonny Jiang /**
234b38f3e80SSonny Jiang  * uvd_v3_1_mc_resume - memory controller programming
235b38f3e80SSonny Jiang  *
236b38f3e80SSonny Jiang  * @adev: amdgpu_device pointer
237b38f3e80SSonny Jiang  *
238b38f3e80SSonny Jiang  * Let the UVD memory controller know it's offsets
239b38f3e80SSonny Jiang  */
uvd_v3_1_mc_resume(struct amdgpu_device * adev)240b38f3e80SSonny Jiang static void uvd_v3_1_mc_resume(struct amdgpu_device *adev)
241b38f3e80SSonny Jiang {
242b38f3e80SSonny Jiang 	uint64_t addr;
243b38f3e80SSonny Jiang 	uint32_t size;
244b38f3e80SSonny Jiang 
245b38f3e80SSonny Jiang 	/* programm the VCPU memory controller bits 0-27 */
246b38f3e80SSonny Jiang 	addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3;
247b38f3e80SSonny Jiang 	size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3;
248b38f3e80SSonny Jiang 	WREG32(mmUVD_VCPU_CACHE_OFFSET0, addr);
249b38f3e80SSonny Jiang 	WREG32(mmUVD_VCPU_CACHE_SIZE0, size);
250b38f3e80SSonny Jiang 
251b38f3e80SSonny Jiang 	addr += size;
252b38f3e80SSonny Jiang 	size = AMDGPU_UVD_HEAP_SIZE >> 3;
253b38f3e80SSonny Jiang 	WREG32(mmUVD_VCPU_CACHE_OFFSET1, addr);
254b38f3e80SSonny Jiang 	WREG32(mmUVD_VCPU_CACHE_SIZE1, size);
255b38f3e80SSonny Jiang 
256b38f3e80SSonny Jiang 	addr += size;
257b38f3e80SSonny Jiang 	size = (AMDGPU_UVD_STACK_SIZE +
258b38f3e80SSonny Jiang 		(AMDGPU_UVD_SESSION_SIZE * adev->uvd.max_handles)) >> 3;
259b38f3e80SSonny Jiang 	WREG32(mmUVD_VCPU_CACHE_OFFSET2, addr);
260b38f3e80SSonny Jiang 	WREG32(mmUVD_VCPU_CACHE_SIZE2, size);
261b38f3e80SSonny Jiang 
262b38f3e80SSonny Jiang 	/* bits 28-31 */
263b38f3e80SSonny Jiang 	addr = (adev->uvd.inst->gpu_addr >> 28) & 0xF;
264b38f3e80SSonny Jiang 	WREG32(mmUVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0));
265b38f3e80SSonny Jiang 
266b38f3e80SSonny Jiang 	/* bits 32-39 */
267b38f3e80SSonny Jiang 	addr = (adev->uvd.inst->gpu_addr >> 32) & 0xFF;
268b38f3e80SSonny Jiang 	WREG32(mmUVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31));
269b38f3e80SSonny Jiang 
270b38f3e80SSonny Jiang 	WREG32(mmUVD_UDEC_ADDR_CONFIG, adev->gfx.config.gb_addr_config);
271b38f3e80SSonny Jiang 	WREG32(mmUVD_UDEC_DB_ADDR_CONFIG, adev->gfx.config.gb_addr_config);
272b38f3e80SSonny Jiang 	WREG32(mmUVD_UDEC_DBW_ADDR_CONFIG, adev->gfx.config.gb_addr_config);
273b38f3e80SSonny Jiang }
274b38f3e80SSonny Jiang 
275b38f3e80SSonny Jiang /**
276b38f3e80SSonny Jiang  * uvd_v3_1_fw_validate - FW validation operation
277b38f3e80SSonny Jiang  *
278b38f3e80SSonny Jiang  * @adev: amdgpu_device pointer
279b38f3e80SSonny Jiang  *
280b38f3e80SSonny Jiang  * Initialate and check UVD validation.
281b38f3e80SSonny Jiang  */
uvd_v3_1_fw_validate(struct amdgpu_device * adev)282b38f3e80SSonny Jiang static int uvd_v3_1_fw_validate(struct amdgpu_device *adev)
283b38f3e80SSonny Jiang {
284bb797811SSonny Jiang 	int i;
285bb797811SSonny Jiang 	uint32_t keysel = adev->uvd.keyselect;
286b38f3e80SSonny Jiang 
287b38f3e80SSonny Jiang 	WREG32(mmUVD_FW_START, keysel);
288b38f3e80SSonny Jiang 
289b38f3e80SSonny Jiang 	for (i = 0; i < 10; ++i) {
290b38f3e80SSonny Jiang 		mdelay(10);
291b38f3e80SSonny Jiang 		if (RREG32(mmUVD_FW_STATUS) & UVD_FW_STATUS__DONE_MASK)
292b38f3e80SSonny Jiang 			break;
293b38f3e80SSonny Jiang 	}
294b38f3e80SSonny Jiang 
295b38f3e80SSonny Jiang 	if (i == 10)
296b38f3e80SSonny Jiang 		return -ETIMEDOUT;
297b38f3e80SSonny Jiang 
298b38f3e80SSonny Jiang 	if (!(RREG32(mmUVD_FW_STATUS) & UVD_FW_STATUS__PASS_MASK))
299b38f3e80SSonny Jiang 		return -EINVAL;
300b38f3e80SSonny Jiang 
301b38f3e80SSonny Jiang 	for (i = 0; i < 10; ++i) {
302b38f3e80SSonny Jiang 		mdelay(10);
303b38f3e80SSonny Jiang 		if (!(RREG32(mmUVD_FW_STATUS) & UVD_FW_STATUS__BUSY_MASK))
304b38f3e80SSonny Jiang 			break;
305b38f3e80SSonny Jiang 	}
306b38f3e80SSonny Jiang 
307b38f3e80SSonny Jiang 	if (i == 10)
308b38f3e80SSonny Jiang 		return -ETIMEDOUT;
309b38f3e80SSonny Jiang 
310b38f3e80SSonny Jiang 	return 0;
311b38f3e80SSonny Jiang }
312b38f3e80SSonny Jiang 
313b38f3e80SSonny Jiang /**
314b38f3e80SSonny Jiang  * uvd_v3_1_start - start UVD block
315b38f3e80SSonny Jiang  *
316b38f3e80SSonny Jiang  * @adev: amdgpu_device pointer
317b38f3e80SSonny Jiang  *
318b38f3e80SSonny Jiang  * Setup and start the UVD block
319b38f3e80SSonny Jiang  */
uvd_v3_1_start(struct amdgpu_device * adev)320b38f3e80SSonny Jiang static int uvd_v3_1_start(struct amdgpu_device *adev)
321b38f3e80SSonny Jiang {
322b38f3e80SSonny Jiang 	struct amdgpu_ring *ring = &adev->uvd.inst->ring;
323b38f3e80SSonny Jiang 	uint32_t rb_bufsz;
324b38f3e80SSonny Jiang 	int i, j, r;
325b38f3e80SSonny Jiang 	u32 tmp;
326b38f3e80SSonny Jiang 	/* disable byte swapping */
327b38f3e80SSonny Jiang 	u32 lmi_swap_cntl = 0;
328b38f3e80SSonny Jiang 	u32 mp_swap_cntl = 0;
329b38f3e80SSonny Jiang 
330b38f3e80SSonny Jiang 	/* set uvd busy */
331b38f3e80SSonny Jiang 	WREG32_P(mmUVD_STATUS, 1<<2, ~(1<<2));
332b38f3e80SSonny Jiang 
333b38f3e80SSonny Jiang 	uvd_v3_1_set_dcm(adev, true);
334b38f3e80SSonny Jiang 	WREG32(mmUVD_CGC_GATE, 0);
335b38f3e80SSonny Jiang 
336b38f3e80SSonny Jiang 	/* take UVD block out of reset */
337b38f3e80SSonny Jiang 	WREG32_P(mmSRBM_SOFT_RESET, 0, ~SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK);
338b38f3e80SSonny Jiang 	mdelay(5);
339b38f3e80SSonny Jiang 
340b38f3e80SSonny Jiang 	/* enable VCPU clock */
341b38f3e80SSonny Jiang 	WREG32(mmUVD_VCPU_CNTL,  1 << 9);
342b38f3e80SSonny Jiang 
3430e9def21Stony.huang_cp 	/* disable interrupt */
344b38f3e80SSonny Jiang 	WREG32_P(mmUVD_MASTINT_EN, 0, ~(1 << 1));
345b38f3e80SSonny Jiang 
346b38f3e80SSonny Jiang #ifdef __BIG_ENDIAN
347b38f3e80SSonny Jiang 	/* swap (8 in 32) RB and IB */
348b38f3e80SSonny Jiang 	lmi_swap_cntl = 0xa;
349b38f3e80SSonny Jiang 	mp_swap_cntl = 0;
350b38f3e80SSonny Jiang #endif
351b38f3e80SSonny Jiang 	WREG32(mmUVD_LMI_SWAP_CNTL, lmi_swap_cntl);
352b38f3e80SSonny Jiang 	WREG32(mmUVD_MP_SWAP_CNTL, mp_swap_cntl);
353b38f3e80SSonny Jiang 
354b38f3e80SSonny Jiang 	/* initialize UVD memory controller */
355b38f3e80SSonny Jiang 	WREG32(mmUVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) |
356b38f3e80SSonny Jiang 		(1 << 21) | (1 << 9) | (1 << 20));
357b38f3e80SSonny Jiang 
358b38f3e80SSonny Jiang 	tmp = RREG32(mmUVD_MPC_CNTL);
359b38f3e80SSonny Jiang 	WREG32(mmUVD_MPC_CNTL, tmp | 0x10);
360b38f3e80SSonny Jiang 
361b38f3e80SSonny Jiang 	WREG32(mmUVD_MPC_SET_MUXA0, 0x40c2040);
362b38f3e80SSonny Jiang 	WREG32(mmUVD_MPC_SET_MUXA1, 0x0);
363b38f3e80SSonny Jiang 	WREG32(mmUVD_MPC_SET_MUXB0, 0x40c2040);
364b38f3e80SSonny Jiang 	WREG32(mmUVD_MPC_SET_MUXB1, 0x0);
365b38f3e80SSonny Jiang 	WREG32(mmUVD_MPC_SET_ALU, 0);
366b38f3e80SSonny Jiang 	WREG32(mmUVD_MPC_SET_MUX, 0x88);
367b38f3e80SSonny Jiang 
368b38f3e80SSonny Jiang 	tmp = RREG32_UVD_CTX(ixUVD_LMI_CACHE_CTRL);
369b38f3e80SSonny Jiang 	WREG32_UVD_CTX(ixUVD_LMI_CACHE_CTRL, tmp & (~0x10));
370b38f3e80SSonny Jiang 
371b38f3e80SSonny Jiang 	/* enable UMC */
372b38f3e80SSonny Jiang 	WREG32_P(mmUVD_LMI_CTRL2, 0, ~(1 << 8));
373b38f3e80SSonny Jiang 
374b38f3e80SSonny Jiang 	WREG32_P(mmUVD_SOFT_RESET, 0, ~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK);
375b38f3e80SSonny Jiang 
376b38f3e80SSonny Jiang 	WREG32_P(mmUVD_SOFT_RESET, 0, ~UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK);
377b38f3e80SSonny Jiang 
378b38f3e80SSonny Jiang 	WREG32_P(mmUVD_SOFT_RESET, 0, ~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK);
379b38f3e80SSonny Jiang 
380b38f3e80SSonny Jiang 	mdelay(10);
381b38f3e80SSonny Jiang 
382b38f3e80SSonny Jiang 	for (i = 0; i < 10; ++i) {
383b38f3e80SSonny Jiang 		uint32_t status;
384b38f3e80SSonny Jiang 		for (j = 0; j < 100; ++j) {
385b38f3e80SSonny Jiang 			status = RREG32(mmUVD_STATUS);
386b38f3e80SSonny Jiang 			if (status & 2)
387b38f3e80SSonny Jiang 				break;
388b38f3e80SSonny Jiang 			mdelay(10);
389b38f3e80SSonny Jiang 		}
390b38f3e80SSonny Jiang 		r = 0;
391b38f3e80SSonny Jiang 		if (status & 2)
392b38f3e80SSonny Jiang 			break;
393b38f3e80SSonny Jiang 
394b38f3e80SSonny Jiang 		DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n");
395b38f3e80SSonny Jiang 		WREG32_P(mmUVD_SOFT_RESET, UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK,
396b38f3e80SSonny Jiang 				 ~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK);
397b38f3e80SSonny Jiang 		mdelay(10);
398b38f3e80SSonny Jiang 		WREG32_P(mmUVD_SOFT_RESET, 0, ~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK);
399b38f3e80SSonny Jiang 		mdelay(10);
400b38f3e80SSonny Jiang 		r = -1;
401b38f3e80SSonny Jiang 	}
402b38f3e80SSonny Jiang 
403b38f3e80SSonny Jiang 	if (r) {
404b38f3e80SSonny Jiang 		DRM_ERROR("UVD not responding, giving up!!!\n");
405b38f3e80SSonny Jiang 		return r;
406b38f3e80SSonny Jiang 	}
407b38f3e80SSonny Jiang 
4080e9def21Stony.huang_cp 	/* enable interrupt */
409b38f3e80SSonny Jiang 	WREG32_P(mmUVD_MASTINT_EN, 3<<1, ~(3 << 1));
410b38f3e80SSonny Jiang 
411b38f3e80SSonny Jiang 	WREG32_P(mmUVD_STATUS, 0, ~(1<<2));
412b38f3e80SSonny Jiang 
413b38f3e80SSonny Jiang 	/* force RBC into idle state */
414b38f3e80SSonny Jiang 	WREG32(mmUVD_RBC_RB_CNTL, 0x11010101);
415b38f3e80SSonny Jiang 
416b38f3e80SSonny Jiang 	/* Set the write pointer delay */
417b38f3e80SSonny Jiang 	WREG32(mmUVD_RBC_RB_WPTR_CNTL, 0);
418b38f3e80SSonny Jiang 
419b38f3e80SSonny Jiang 	/* programm the 4GB memory segment for rptr and ring buffer */
420b38f3e80SSonny Jiang 	WREG32(mmUVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) |
421b38f3e80SSonny Jiang 		   (0x7 << 16) | (0x1 << 31));
422b38f3e80SSonny Jiang 
423b38f3e80SSonny Jiang 	/* Initialize the ring buffer's read and write pointers */
424b38f3e80SSonny Jiang 	WREG32(mmUVD_RBC_RB_RPTR, 0x0);
425b38f3e80SSonny Jiang 
426b38f3e80SSonny Jiang 	ring->wptr = RREG32(mmUVD_RBC_RB_RPTR);
427b38f3e80SSonny Jiang 	WREG32(mmUVD_RBC_RB_WPTR, lower_32_bits(ring->wptr));
428b38f3e80SSonny Jiang 
429b38f3e80SSonny Jiang 	/* set the ring address */
430b38f3e80SSonny Jiang 	WREG32(mmUVD_RBC_RB_BASE, ring->gpu_addr);
431b38f3e80SSonny Jiang 
432b38f3e80SSonny Jiang 	/* Set ring buffer size */
433b38f3e80SSonny Jiang 	rb_bufsz = order_base_2(ring->ring_size);
434b38f3e80SSonny Jiang 	rb_bufsz = (0x1 << 8) | rb_bufsz;
435b38f3e80SSonny Jiang 	WREG32_P(mmUVD_RBC_RB_CNTL, rb_bufsz, ~0x11f1f);
436b38f3e80SSonny Jiang 
437b38f3e80SSonny Jiang 	return 0;
438b38f3e80SSonny Jiang }
439b38f3e80SSonny Jiang 
440b38f3e80SSonny Jiang /**
441b38f3e80SSonny Jiang  * uvd_v3_1_stop - stop UVD block
442b38f3e80SSonny Jiang  *
443b38f3e80SSonny Jiang  * @adev: amdgpu_device pointer
444b38f3e80SSonny Jiang  *
445b38f3e80SSonny Jiang  * stop the UVD block
446b38f3e80SSonny Jiang  */
uvd_v3_1_stop(struct amdgpu_device * adev)447b38f3e80SSonny Jiang static void uvd_v3_1_stop(struct amdgpu_device *adev)
448b38f3e80SSonny Jiang {
449b38f3e80SSonny Jiang 	uint32_t i, j;
450b38f3e80SSonny Jiang 	uint32_t status;
451b38f3e80SSonny Jiang 
452b38f3e80SSonny Jiang 	WREG32(mmUVD_RBC_RB_CNTL, 0x11010101);
453b38f3e80SSonny Jiang 
454b38f3e80SSonny Jiang 	for (i = 0; i < 10; ++i) {
455b38f3e80SSonny Jiang 		for (j = 0; j < 100; ++j) {
456b38f3e80SSonny Jiang 			status = RREG32(mmUVD_STATUS);
457b38f3e80SSonny Jiang 			if (status & 2)
458b38f3e80SSonny Jiang 				break;
459b38f3e80SSonny Jiang 			mdelay(1);
460b38f3e80SSonny Jiang 		}
461b38f3e80SSonny Jiang 		if (status & 2)
462b38f3e80SSonny Jiang 			break;
463b38f3e80SSonny Jiang 	}
464b38f3e80SSonny Jiang 
465b38f3e80SSonny Jiang 	for (i = 0; i < 10; ++i) {
466b38f3e80SSonny Jiang 		for (j = 0; j < 100; ++j) {
467b38f3e80SSonny Jiang 			status = RREG32(mmUVD_LMI_STATUS);
468b38f3e80SSonny Jiang 			if (status & 0xf)
469b38f3e80SSonny Jiang 				break;
470b38f3e80SSonny Jiang 			mdelay(1);
471b38f3e80SSonny Jiang 		}
472b38f3e80SSonny Jiang 		if (status & 0xf)
473b38f3e80SSonny Jiang 			break;
474b38f3e80SSonny Jiang 	}
475b38f3e80SSonny Jiang 
476b38f3e80SSonny Jiang 	/* Stall UMC and register bus before resetting VCPU */
477b38f3e80SSonny Jiang 	WREG32_P(mmUVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
478b38f3e80SSonny Jiang 
479b38f3e80SSonny Jiang 	for (i = 0; i < 10; ++i) {
480b38f3e80SSonny Jiang 		for (j = 0; j < 100; ++j) {
481b38f3e80SSonny Jiang 			status = RREG32(mmUVD_LMI_STATUS);
482b38f3e80SSonny Jiang 			if (status & 0x240)
483b38f3e80SSonny Jiang 				break;
484b38f3e80SSonny Jiang 			mdelay(1);
485b38f3e80SSonny Jiang 		}
486b38f3e80SSonny Jiang 		if (status & 0x240)
487b38f3e80SSonny Jiang 			break;
488b38f3e80SSonny Jiang 	}
489b38f3e80SSonny Jiang 
490b38f3e80SSonny Jiang 	WREG32_P(0x3D49, 0, ~(1 << 2));
491b38f3e80SSonny Jiang 
492b38f3e80SSonny Jiang 	WREG32_P(mmUVD_VCPU_CNTL, 0, ~(1 << 9));
493b38f3e80SSonny Jiang 
494b38f3e80SSonny Jiang 	/* put LMI, VCPU, RBC etc... into reset */
495b38f3e80SSonny Jiang 	WREG32(mmUVD_SOFT_RESET, UVD_SOFT_RESET__LMI_SOFT_RESET_MASK |
496b38f3e80SSonny Jiang 		UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK |
497b38f3e80SSonny Jiang 		UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK);
498b38f3e80SSonny Jiang 
499b38f3e80SSonny Jiang 	WREG32(mmUVD_STATUS, 0);
500b38f3e80SSonny Jiang 
501b38f3e80SSonny Jiang 	uvd_v3_1_set_dcm(adev, false);
502b38f3e80SSonny Jiang }
503b38f3e80SSonny Jiang 
uvd_v3_1_set_interrupt_state(struct amdgpu_device * adev,struct amdgpu_irq_src * source,unsigned type,enum amdgpu_interrupt_state state)504b38f3e80SSonny Jiang static int uvd_v3_1_set_interrupt_state(struct amdgpu_device *adev,
505b38f3e80SSonny Jiang 					struct amdgpu_irq_src *source,
506b38f3e80SSonny Jiang 					unsigned type,
507b38f3e80SSonny Jiang 					enum amdgpu_interrupt_state state)
508b38f3e80SSonny Jiang {
509b38f3e80SSonny Jiang 	return 0;
510b38f3e80SSonny Jiang }
511b38f3e80SSonny Jiang 
uvd_v3_1_process_interrupt(struct amdgpu_device * adev,struct amdgpu_irq_src * source,struct amdgpu_iv_entry * entry)512b38f3e80SSonny Jiang static int uvd_v3_1_process_interrupt(struct amdgpu_device *adev,
513b38f3e80SSonny Jiang 				      struct amdgpu_irq_src *source,
514b38f3e80SSonny Jiang 				      struct amdgpu_iv_entry *entry)
515b38f3e80SSonny Jiang {
516b38f3e80SSonny Jiang 	DRM_DEBUG("IH: UVD TRAP\n");
517b38f3e80SSonny Jiang 	amdgpu_fence_process(&adev->uvd.inst->ring);
518b38f3e80SSonny Jiang 	return 0;
519b38f3e80SSonny Jiang }
520b38f3e80SSonny Jiang 
521b38f3e80SSonny Jiang 
522b38f3e80SSonny Jiang static const struct amdgpu_irq_src_funcs uvd_v3_1_irq_funcs = {
523b38f3e80SSonny Jiang 	.set = uvd_v3_1_set_interrupt_state,
524b38f3e80SSonny Jiang 	.process = uvd_v3_1_process_interrupt,
525b38f3e80SSonny Jiang };
526b38f3e80SSonny Jiang 
uvd_v3_1_set_irq_funcs(struct amdgpu_device * adev)527b38f3e80SSonny Jiang static void uvd_v3_1_set_irq_funcs(struct amdgpu_device *adev)
528b38f3e80SSonny Jiang {
529b38f3e80SSonny Jiang 	adev->uvd.inst->irq.num_types = 1;
530b38f3e80SSonny Jiang 	adev->uvd.inst->irq.funcs = &uvd_v3_1_irq_funcs;
531b38f3e80SSonny Jiang }
532b38f3e80SSonny Jiang 
533b38f3e80SSonny Jiang 
uvd_v3_1_early_init(void * handle)534b38f3e80SSonny Jiang static int uvd_v3_1_early_init(void *handle)
535b38f3e80SSonny Jiang {
536b38f3e80SSonny Jiang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
537b38f3e80SSonny Jiang 	adev->uvd.num_uvd_inst = 1;
538b38f3e80SSonny Jiang 
539b38f3e80SSonny Jiang 	uvd_v3_1_set_ring_funcs(adev);
540b38f3e80SSonny Jiang 	uvd_v3_1_set_irq_funcs(adev);
541b38f3e80SSonny Jiang 
542b38f3e80SSonny Jiang 	return 0;
543b38f3e80SSonny Jiang }
544b38f3e80SSonny Jiang 
uvd_v3_1_sw_init(void * handle)545b38f3e80SSonny Jiang static int uvd_v3_1_sw_init(void *handle)
546b38f3e80SSonny Jiang {
547b38f3e80SSonny Jiang 	struct amdgpu_ring *ring;
548b38f3e80SSonny Jiang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
549b38f3e80SSonny Jiang 	int r;
550bb797811SSonny Jiang 	void *ptr;
551bb797811SSonny Jiang 	uint32_t ucode_len;
552b38f3e80SSonny Jiang 
553b38f3e80SSonny Jiang 	/* UVD TRAP */
554b38f3e80SSonny Jiang 	r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, 124, &adev->uvd.inst->irq);
555b38f3e80SSonny Jiang 	if (r)
556b38f3e80SSonny Jiang 		return r;
557b38f3e80SSonny Jiang 
558b38f3e80SSonny Jiang 	r = amdgpu_uvd_sw_init(adev);
559b38f3e80SSonny Jiang 	if (r)
560b38f3e80SSonny Jiang 		return r;
561b38f3e80SSonny Jiang 
562b38f3e80SSonny Jiang 	ring = &adev->uvd.inst->ring;
563b38f3e80SSonny Jiang 	sprintf(ring->name, "uvd");
564b38f3e80SSonny Jiang 	r = amdgpu_ring_init(adev, ring, 512, &adev->uvd.inst->irq, 0,
565c107171bSChristian König 			 AMDGPU_RING_PRIO_DEFAULT, NULL);
566b38f3e80SSonny Jiang 	if (r)
567b38f3e80SSonny Jiang 		return r;
568b38f3e80SSonny Jiang 
569b38f3e80SSonny Jiang 	r = amdgpu_uvd_resume(adev);
570b38f3e80SSonny Jiang 	if (r)
571b38f3e80SSonny Jiang 		return r;
572b38f3e80SSonny Jiang 
5737203a2fdSSonny Jiang 	/* Retrieval firmware validate key */
5747203a2fdSSonny Jiang 	ptr = adev->uvd.inst[0].cpu_addr;
5757203a2fdSSonny Jiang 	ptr += 192 + 16;
5767203a2fdSSonny Jiang 	memcpy(&ucode_len, ptr, 4);
5777203a2fdSSonny Jiang 	ptr += ucode_len;
5787203a2fdSSonny Jiang 	memcpy(&adev->uvd.keyselect, ptr, 4);
5797203a2fdSSonny Jiang 
580b38f3e80SSonny Jiang 	r = amdgpu_uvd_entity_init(adev);
581b38f3e80SSonny Jiang 
582b38f3e80SSonny Jiang 	return r;
583b38f3e80SSonny Jiang }
584b38f3e80SSonny Jiang 
uvd_v3_1_sw_fini(void * handle)585b38f3e80SSonny Jiang static int uvd_v3_1_sw_fini(void *handle)
586b38f3e80SSonny Jiang {
587b38f3e80SSonny Jiang 	int r;
588b38f3e80SSonny Jiang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
589b38f3e80SSonny Jiang 
590b38f3e80SSonny Jiang 	r = amdgpu_uvd_suspend(adev);
591b38f3e80SSonny Jiang 	if (r)
592b38f3e80SSonny Jiang 		return r;
593b38f3e80SSonny Jiang 
594b38f3e80SSonny Jiang 	return amdgpu_uvd_sw_fini(adev);
595b38f3e80SSonny Jiang }
596b38f3e80SSonny Jiang 
uvd_v3_1_enable_mgcg(struct amdgpu_device * adev,bool enable)597b38f3e80SSonny Jiang static void uvd_v3_1_enable_mgcg(struct amdgpu_device *adev,
598b38f3e80SSonny Jiang 				 bool enable)
599b38f3e80SSonny Jiang {
600b38f3e80SSonny Jiang 	u32 orig, data;
601b38f3e80SSonny Jiang 
602b38f3e80SSonny Jiang 	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG)) {
603b38f3e80SSonny Jiang 		data = RREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL);
604b38f3e80SSonny Jiang 		data |= 0x3fff;
605b38f3e80SSonny Jiang 		WREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL, data);
606b38f3e80SSonny Jiang 
607b38f3e80SSonny Jiang 		orig = data = RREG32(mmUVD_CGC_CTRL);
608b38f3e80SSonny Jiang 		data |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
609b38f3e80SSonny Jiang 		if (orig != data)
610b38f3e80SSonny Jiang 			WREG32(mmUVD_CGC_CTRL, data);
611b38f3e80SSonny Jiang 	} else {
612b38f3e80SSonny Jiang 		data = RREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL);
613b38f3e80SSonny Jiang 		data &= ~0x3fff;
614b38f3e80SSonny Jiang 		WREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL, data);
615b38f3e80SSonny Jiang 
616b38f3e80SSonny Jiang 		orig = data = RREG32(mmUVD_CGC_CTRL);
617b38f3e80SSonny Jiang 		data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
618b38f3e80SSonny Jiang 		if (orig != data)
619b38f3e80SSonny Jiang 			WREG32(mmUVD_CGC_CTRL, data);
620b38f3e80SSonny Jiang 	}
621b38f3e80SSonny Jiang }
622b38f3e80SSonny Jiang 
623b38f3e80SSonny Jiang /**
624b38f3e80SSonny Jiang  * uvd_v3_1_hw_init - start and test UVD block
625b38f3e80SSonny Jiang  *
626e4c980c3SLee Jones  * @handle: handle used to pass amdgpu_device pointer
627b38f3e80SSonny Jiang  *
628b38f3e80SSonny Jiang  * Initialize the hardware, boot up the VCPU and do some testing
629b38f3e80SSonny Jiang  */
uvd_v3_1_hw_init(void * handle)630b38f3e80SSonny Jiang static int uvd_v3_1_hw_init(void *handle)
631b38f3e80SSonny Jiang {
632b38f3e80SSonny Jiang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
633b38f3e80SSonny Jiang 	struct amdgpu_ring *ring = &adev->uvd.inst->ring;
634b38f3e80SSonny Jiang 	uint32_t tmp;
635b38f3e80SSonny Jiang 	int r;
636b38f3e80SSonny Jiang 
637b38f3e80SSonny Jiang 	uvd_v3_1_mc_resume(adev);
638b38f3e80SSonny Jiang 
639b38f3e80SSonny Jiang 	r = uvd_v3_1_fw_validate(adev);
640b38f3e80SSonny Jiang 	if (r) {
641b38f3e80SSonny Jiang 		DRM_ERROR("amdgpu: UVD Firmware validate fail (%d).\n", r);
642b38f3e80SSonny Jiang 		return r;
643b38f3e80SSonny Jiang 	}
644b38f3e80SSonny Jiang 
645b38f3e80SSonny Jiang 	uvd_v3_1_enable_mgcg(adev, true);
646b38f3e80SSonny Jiang 	amdgpu_asic_set_uvd_clocks(adev, 53300, 40000);
647b38f3e80SSonny Jiang 
648b38f3e80SSonny Jiang 	uvd_v3_1_start(adev);
649b38f3e80SSonny Jiang 
650b38f3e80SSonny Jiang 	r = amdgpu_ring_test_helper(ring);
651b38f3e80SSonny Jiang 	if (r) {
652b38f3e80SSonny Jiang 		DRM_ERROR("amdgpu: UVD ring test fail (%d).\n", r);
653b38f3e80SSonny Jiang 		goto done;
654b38f3e80SSonny Jiang 	}
655b38f3e80SSonny Jiang 
656b38f3e80SSonny Jiang 	r = amdgpu_ring_alloc(ring, 10);
657b38f3e80SSonny Jiang 	if (r) {
658b38f3e80SSonny Jiang 		DRM_ERROR("amdgpu: ring failed to lock UVD ring (%d).\n", r);
659b38f3e80SSonny Jiang 		goto done;
660b38f3e80SSonny Jiang 	}
661b38f3e80SSonny Jiang 
662b38f3e80SSonny Jiang 	tmp = PACKET0(mmUVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0);
663b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, tmp);
664b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, 0xFFFFF);
665b38f3e80SSonny Jiang 
666b38f3e80SSonny Jiang 	tmp = PACKET0(mmUVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0);
667b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, tmp);
668b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, 0xFFFFF);
669b38f3e80SSonny Jiang 
670b38f3e80SSonny Jiang 	tmp = PACKET0(mmUVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0);
671b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, tmp);
672b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, 0xFFFFF);
673b38f3e80SSonny Jiang 
674b38f3e80SSonny Jiang 	/* Clear timeout status bits */
675b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, PACKET0(mmUVD_SEMA_TIMEOUT_STATUS, 0));
676b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, 0x8);
677b38f3e80SSonny Jiang 
678b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, PACKET0(mmUVD_SEMA_CNTL, 0));
679b38f3e80SSonny Jiang 	amdgpu_ring_write(ring, 3);
680b38f3e80SSonny Jiang 
681b38f3e80SSonny Jiang 	amdgpu_ring_commit(ring);
682b38f3e80SSonny Jiang 
683b38f3e80SSonny Jiang done:
684b38f3e80SSonny Jiang 	if (!r)
685b38f3e80SSonny Jiang 		DRM_INFO("UVD initialized successfully.\n");
686b38f3e80SSonny Jiang 
687b38f3e80SSonny Jiang 	return r;
688b38f3e80SSonny Jiang }
689b38f3e80SSonny Jiang 
690b38f3e80SSonny Jiang /**
691b38f3e80SSonny Jiang  * uvd_v3_1_hw_fini - stop the hardware block
692b38f3e80SSonny Jiang  *
693e4c980c3SLee Jones  * @handle: handle used to pass amdgpu_device pointer
694b38f3e80SSonny Jiang  *
695b38f3e80SSonny Jiang  * Stop the UVD block, mark ring as not ready any more
696b38f3e80SSonny Jiang  */
uvd_v3_1_hw_fini(void * handle)697b38f3e80SSonny Jiang static int uvd_v3_1_hw_fini(void *handle)
698b38f3e80SSonny Jiang {
699b38f3e80SSonny Jiang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
700b38f3e80SSonny Jiang 
701d82e2c24SAndrey Grodzovsky 	cancel_delayed_work_sync(&adev->uvd.idle_work);
702d82e2c24SAndrey Grodzovsky 
703d82e2c24SAndrey Grodzovsky 	if (RREG32(mmUVD_STATUS) != 0)
704d82e2c24SAndrey Grodzovsky 		uvd_v3_1_stop(adev);
705d82e2c24SAndrey Grodzovsky 
706d82e2c24SAndrey Grodzovsky 	return 0;
707d82e2c24SAndrey Grodzovsky }
708d82e2c24SAndrey Grodzovsky 
uvd_v3_1_suspend(void * handle)709d82e2c24SAndrey Grodzovsky static int uvd_v3_1_suspend(void *handle)
710d82e2c24SAndrey Grodzovsky {
711d82e2c24SAndrey Grodzovsky 	int r;
712d82e2c24SAndrey Grodzovsky 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
713d82e2c24SAndrey Grodzovsky 
714859e4659SEvan Quan 	/*
715859e4659SEvan Quan 	 * Proper cleanups before halting the HW engine:
716859e4659SEvan Quan 	 *   - cancel the delayed idle work
717859e4659SEvan Quan 	 *   - enable powergating
718859e4659SEvan Quan 	 *   - enable clockgating
719859e4659SEvan Quan 	 *   - disable dpm
720859e4659SEvan Quan 	 *
721859e4659SEvan Quan 	 * TODO: to align with the VCN implementation, move the
722859e4659SEvan Quan 	 * jobs for clockgating/powergating/dpm setting to
723859e4659SEvan Quan 	 * ->set_powergating_state().
724859e4659SEvan Quan 	 */
725859e4659SEvan Quan 	cancel_delayed_work_sync(&adev->uvd.idle_work);
726859e4659SEvan Quan 
727859e4659SEvan Quan 	if (adev->pm.dpm_enabled) {
728859e4659SEvan Quan 		amdgpu_dpm_enable_uvd(adev, false);
729859e4659SEvan Quan 	} else {
730859e4659SEvan Quan 		amdgpu_asic_set_uvd_clocks(adev, 0, 0);
731859e4659SEvan Quan 		/* shutdown the UVD block */
732859e4659SEvan Quan 		amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
733859e4659SEvan Quan 						       AMD_PG_STATE_GATE);
734859e4659SEvan Quan 		amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
735859e4659SEvan Quan 						       AMD_CG_STATE_GATE);
736859e4659SEvan Quan 	}
737859e4659SEvan Quan 
738b38f3e80SSonny Jiang 	r = uvd_v3_1_hw_fini(adev);
739b38f3e80SSonny Jiang 	if (r)
740b38f3e80SSonny Jiang 		return r;
741b38f3e80SSonny Jiang 
742b38f3e80SSonny Jiang 	return amdgpu_uvd_suspend(adev);
743b38f3e80SSonny Jiang }
744b38f3e80SSonny Jiang 
uvd_v3_1_resume(void * handle)745b38f3e80SSonny Jiang static int uvd_v3_1_resume(void *handle)
746b38f3e80SSonny Jiang {
747b38f3e80SSonny Jiang 	int r;
748b38f3e80SSonny Jiang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
749b38f3e80SSonny Jiang 
750b38f3e80SSonny Jiang 	r = amdgpu_uvd_resume(adev);
751b38f3e80SSonny Jiang 	if (r)
752b38f3e80SSonny Jiang 		return r;
753b38f3e80SSonny Jiang 
754b38f3e80SSonny Jiang 	return uvd_v3_1_hw_init(adev);
755b38f3e80SSonny Jiang }
756b38f3e80SSonny Jiang 
uvd_v3_1_is_idle(void * handle)757b38f3e80SSonny Jiang static bool uvd_v3_1_is_idle(void *handle)
758b38f3e80SSonny Jiang {
759b38f3e80SSonny Jiang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
760b38f3e80SSonny Jiang 
761b38f3e80SSonny Jiang 	return !(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK);
762b38f3e80SSonny Jiang }
763b38f3e80SSonny Jiang 
uvd_v3_1_wait_for_idle(void * handle)764b38f3e80SSonny Jiang static int uvd_v3_1_wait_for_idle(void *handle)
765b38f3e80SSonny Jiang {
766b38f3e80SSonny Jiang 	unsigned i;
767b38f3e80SSonny Jiang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
768b38f3e80SSonny Jiang 
769b38f3e80SSonny Jiang 	for (i = 0; i < adev->usec_timeout; i++) {
770b38f3e80SSonny Jiang 		if (!(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK))
771b38f3e80SSonny Jiang 			return 0;
772b38f3e80SSonny Jiang 	}
773b38f3e80SSonny Jiang 	return -ETIMEDOUT;
774b38f3e80SSonny Jiang }
775b38f3e80SSonny Jiang 
uvd_v3_1_soft_reset(void * handle)776b38f3e80SSonny Jiang static int uvd_v3_1_soft_reset(void *handle)
777b38f3e80SSonny Jiang {
778b38f3e80SSonny Jiang 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
779b38f3e80SSonny Jiang 
780b38f3e80SSonny Jiang 	uvd_v3_1_stop(adev);
781b38f3e80SSonny Jiang 
782b38f3e80SSonny Jiang 	WREG32_P(mmSRBM_SOFT_RESET, SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK,
783b38f3e80SSonny Jiang 			 ~SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK);
784b38f3e80SSonny Jiang 	mdelay(5);
785b38f3e80SSonny Jiang 
786b38f3e80SSonny Jiang 	return uvd_v3_1_start(adev);
787b38f3e80SSonny Jiang }
788b38f3e80SSonny Jiang 
uvd_v3_1_set_clockgating_state(void * handle,enum amd_clockgating_state state)789b38f3e80SSonny Jiang static int uvd_v3_1_set_clockgating_state(void *handle,
790b38f3e80SSonny Jiang 					  enum amd_clockgating_state state)
791b38f3e80SSonny Jiang {
792b38f3e80SSonny Jiang 	return 0;
793b38f3e80SSonny Jiang }
794b38f3e80SSonny Jiang 
uvd_v3_1_set_powergating_state(void * handle,enum amd_powergating_state state)795b38f3e80SSonny Jiang static int uvd_v3_1_set_powergating_state(void *handle,
796b38f3e80SSonny Jiang 					  enum amd_powergating_state state)
797b38f3e80SSonny Jiang {
798b38f3e80SSonny Jiang 	return 0;
799b38f3e80SSonny Jiang }
800b38f3e80SSonny Jiang 
801b38f3e80SSonny Jiang static const struct amd_ip_funcs uvd_v3_1_ip_funcs = {
802b38f3e80SSonny Jiang 	.name = "uvd_v3_1",
803b38f3e80SSonny Jiang 	.early_init = uvd_v3_1_early_init,
804b38f3e80SSonny Jiang 	.late_init = NULL,
805b38f3e80SSonny Jiang 	.sw_init = uvd_v3_1_sw_init,
806b38f3e80SSonny Jiang 	.sw_fini = uvd_v3_1_sw_fini,
807b38f3e80SSonny Jiang 	.hw_init = uvd_v3_1_hw_init,
808b38f3e80SSonny Jiang 	.hw_fini = uvd_v3_1_hw_fini,
809b38f3e80SSonny Jiang 	.suspend = uvd_v3_1_suspend,
810b38f3e80SSonny Jiang 	.resume = uvd_v3_1_resume,
811b38f3e80SSonny Jiang 	.is_idle = uvd_v3_1_is_idle,
812b38f3e80SSonny Jiang 	.wait_for_idle = uvd_v3_1_wait_for_idle,
813b38f3e80SSonny Jiang 	.soft_reset = uvd_v3_1_soft_reset,
814b38f3e80SSonny Jiang 	.set_clockgating_state = uvd_v3_1_set_clockgating_state,
815b38f3e80SSonny Jiang 	.set_powergating_state = uvd_v3_1_set_powergating_state,
816b38f3e80SSonny Jiang };
817b38f3e80SSonny Jiang 
818*c8a14396SRan Sun const struct amdgpu_ip_block_version uvd_v3_1_ip_block = {
819b38f3e80SSonny Jiang 	.type = AMD_IP_BLOCK_TYPE_UVD,
820b38f3e80SSonny Jiang 	.major = 3,
821b38f3e80SSonny Jiang 	.minor = 1,
822b38f3e80SSonny Jiang 	.rev = 0,
823b38f3e80SSonny Jiang 	.funcs = &uvd_v3_1_ip_funcs,
824b38f3e80SSonny Jiang };
825