xref: /dflybsd-src/sys/dev/drm/amd/amdgpu/amdgpu_uvd.c (revision 809f38025e6f424cb8960d509d59de3ddc7d6b98)
1b843c749SSergey Zigachev /*
2b843c749SSergey Zigachev  * Copyright 2011 Advanced Micro Devices, Inc.
3b843c749SSergey Zigachev  * All Rights Reserved.
4b843c749SSergey Zigachev  *
5b843c749SSergey Zigachev  * Permission is hereby granted, free of charge, to any person obtaining a
6b843c749SSergey Zigachev  * copy of this software and associated documentation files (the
7b843c749SSergey Zigachev  * "Software"), to deal in the Software without restriction, including
8b843c749SSergey Zigachev  * without limitation the rights to use, copy, modify, merge, publish,
9b843c749SSergey Zigachev  * distribute, sub license, and/or sell copies of the Software, and to
10b843c749SSergey Zigachev  * permit persons to whom the Software is furnished to do so, subject to
11b843c749SSergey Zigachev  * the following conditions:
12b843c749SSergey Zigachev  *
13b843c749SSergey Zigachev  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14b843c749SSergey Zigachev  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15b843c749SSergey Zigachev  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
16b843c749SSergey Zigachev  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
17b843c749SSergey Zigachev  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18b843c749SSergey Zigachev  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19b843c749SSergey Zigachev  * USE OR OTHER DEALINGS IN THE SOFTWARE.
20b843c749SSergey Zigachev  *
21b843c749SSergey Zigachev  * The above copyright notice and this permission notice (including the
22b843c749SSergey Zigachev  * next paragraph) shall be included in all copies or substantial portions
23b843c749SSergey Zigachev  * of the Software.
24b843c749SSergey Zigachev  *
25b843c749SSergey Zigachev  */
26b843c749SSergey Zigachev /*
27b843c749SSergey Zigachev  * Authors:
28b843c749SSergey Zigachev  *    Christian König <deathsimple@vodafone.de>
29b843c749SSergey Zigachev  */
30b843c749SSergey Zigachev 
31b843c749SSergey Zigachev #include <linux/firmware.h>
32b843c749SSergey Zigachev #include <linux/module.h>
33b843c749SSergey Zigachev #include <drm/drmP.h>
34b843c749SSergey Zigachev #include <drm/drm.h>
35b843c749SSergey Zigachev 
36b843c749SSergey Zigachev #include "amdgpu.h"
37b843c749SSergey Zigachev #include "amdgpu_pm.h"
38b843c749SSergey Zigachev #include "amdgpu_uvd.h"
39b843c749SSergey Zigachev #include "cikd.h"
40b843c749SSergey Zigachev #include "uvd/uvd_4_2_d.h"
41b843c749SSergey Zigachev 
42b843c749SSergey Zigachev /* 1 second timeout */
43b843c749SSergey Zigachev #define UVD_IDLE_TIMEOUT	msecs_to_jiffies(1000)
44b843c749SSergey Zigachev 
45b843c749SSergey Zigachev /* Firmware versions for VI */
46b843c749SSergey Zigachev #define FW_1_65_10	((1 << 24) | (65 << 16) | (10 << 8))
47b843c749SSergey Zigachev #define FW_1_87_11	((1 << 24) | (87 << 16) | (11 << 8))
48b843c749SSergey Zigachev #define FW_1_87_12	((1 << 24) | (87 << 16) | (12 << 8))
49b843c749SSergey Zigachev #define FW_1_37_15	((1 << 24) | (37 << 16) | (15 << 8))
50b843c749SSergey Zigachev 
51b843c749SSergey Zigachev /* Polaris10/11 firmware version */
52b843c749SSergey Zigachev #define FW_1_66_16	((1 << 24) | (66 << 16) | (16 << 8))
53b843c749SSergey Zigachev 
54b843c749SSergey Zigachev /* Firmware Names */
55b843c749SSergey Zigachev #ifdef CONFIG_DRM_AMDGPU_CIK
56*809f3802SSergey Zigachev #define FIRMWARE_BONAIRE	"amdgpufw_bonaire_uvd"
57*809f3802SSergey Zigachev #define FIRMWARE_KABINI	"amdgpufw_kabini_uvd"
58*809f3802SSergey Zigachev #define FIRMWARE_KAVERI	"amdgpufw_kaveri_uvd"
59*809f3802SSergey Zigachev #define FIRMWARE_HAWAII	"amdgpufw_hawaii_uvd"
60*809f3802SSergey Zigachev #define FIRMWARE_MULLINS	"amdgpufw_mullins_uvd"
61b843c749SSergey Zigachev #endif
62*809f3802SSergey Zigachev #define FIRMWARE_TONGA		"amdgpufw_tonga_uvd"
63*809f3802SSergey Zigachev #define FIRMWARE_CARRIZO	"amdgpufw_carrizo_uvd"
64*809f3802SSergey Zigachev #define FIRMWARE_FIJI		"amdgpufw_fiji_uvd"
65*809f3802SSergey Zigachev #define FIRMWARE_STONEY		"amdgpufw_stoney_uvd"
66*809f3802SSergey Zigachev #define FIRMWARE_POLARIS10	"amdgpufw_polaris10_uvd"
67*809f3802SSergey Zigachev #define FIRMWARE_POLARIS11	"amdgpufw_polaris11_uvd"
68*809f3802SSergey Zigachev #define FIRMWARE_POLARIS12	"amdgpufw_polaris12_uvd"
69*809f3802SSergey Zigachev #define FIRMWARE_VEGAM		"amdgpufw_vegam_uvd"
70b843c749SSergey Zigachev 
71*809f3802SSergey Zigachev #define FIRMWARE_VEGA10		"amdgpufw_vega10_uvd"
72*809f3802SSergey Zigachev #define FIRMWARE_VEGA12		"amdgpufw_vega12_uvd"
73*809f3802SSergey Zigachev #define FIRMWARE_VEGA20		"amdgpufw_vega20_uvd"
74b843c749SSergey Zigachev 
75b843c749SSergey Zigachev /* These are common relative offsets for all asics, from uvd_7_0_offset.h,  */
76b843c749SSergey Zigachev #define UVD_GPCOM_VCPU_CMD		0x03c3
77b843c749SSergey Zigachev #define UVD_GPCOM_VCPU_DATA0	0x03c4
78b843c749SSergey Zigachev #define UVD_GPCOM_VCPU_DATA1	0x03c5
79b843c749SSergey Zigachev #define UVD_NO_OP				0x03ff
80b843c749SSergey Zigachev #define UVD_BASE_SI				0x3800
81b843c749SSergey Zigachev 
82b843c749SSergey Zigachev /**
83b843c749SSergey Zigachev  * amdgpu_uvd_cs_ctx - Command submission parser context
84b843c749SSergey Zigachev  *
85b843c749SSergey Zigachev  * Used for emulating virtual memory support on UVD 4.2.
86b843c749SSergey Zigachev  */
87b843c749SSergey Zigachev struct amdgpu_uvd_cs_ctx {
88b843c749SSergey Zigachev 	struct amdgpu_cs_parser *parser;
89b843c749SSergey Zigachev 	unsigned reg, count;
90b843c749SSergey Zigachev 	unsigned data0, data1;
91b843c749SSergey Zigachev 	unsigned idx;
92b843c749SSergey Zigachev 	unsigned ib_idx;
93b843c749SSergey Zigachev 
94b843c749SSergey Zigachev 	/* does the IB has a msg command */
95b843c749SSergey Zigachev 	bool has_msg_cmd;
96b843c749SSergey Zigachev 
97b843c749SSergey Zigachev 	/* minimum buffer sizes */
98b843c749SSergey Zigachev 	unsigned *buf_sizes;
99b843c749SSergey Zigachev };
100b843c749SSergey Zigachev 
101b843c749SSergey Zigachev #ifdef CONFIG_DRM_AMDGPU_CIK
102b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_BONAIRE);
103b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_KABINI);
104b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_KAVERI);
105b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_HAWAII);
106b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_MULLINS);
107b843c749SSergey Zigachev #endif
108b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_TONGA);
109b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_CARRIZO);
110b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_FIJI);
111b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_STONEY);
112b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_POLARIS10);
113b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_POLARIS11);
114b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_POLARIS12);
115b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_VEGAM);
116b843c749SSergey Zigachev 
117b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_VEGA10);
118b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_VEGA12);
119b843c749SSergey Zigachev MODULE_FIRMWARE(FIRMWARE_VEGA20);
120b843c749SSergey Zigachev 
121b843c749SSergey Zigachev static void amdgpu_uvd_idle_work_handler(struct work_struct *work);
122b843c749SSergey Zigachev 
amdgpu_uvd_sw_init(struct amdgpu_device * adev)123b843c749SSergey Zigachev int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
124b843c749SSergey Zigachev {
125b843c749SSergey Zigachev 	unsigned long bo_size;
126b843c749SSergey Zigachev 	const char *fw_name;
127b843c749SSergey Zigachev 	const struct common_firmware_header *hdr;
128b843c749SSergey Zigachev 	unsigned family_id;
129b843c749SSergey Zigachev 	int i, j, r;
130b843c749SSergey Zigachev 
131b843c749SSergey Zigachev 	INIT_DELAYED_WORK(&adev->uvd.idle_work, amdgpu_uvd_idle_work_handler);
132b843c749SSergey Zigachev 
133b843c749SSergey Zigachev 	switch (adev->asic_type) {
134b843c749SSergey Zigachev #ifdef CONFIG_DRM_AMDGPU_CIK
135b843c749SSergey Zigachev 	case CHIP_BONAIRE:
136b843c749SSergey Zigachev 		fw_name = FIRMWARE_BONAIRE;
137b843c749SSergey Zigachev 		break;
138b843c749SSergey Zigachev 	case CHIP_KABINI:
139b843c749SSergey Zigachev 		fw_name = FIRMWARE_KABINI;
140b843c749SSergey Zigachev 		break;
141b843c749SSergey Zigachev 	case CHIP_KAVERI:
142b843c749SSergey Zigachev 		fw_name = FIRMWARE_KAVERI;
143b843c749SSergey Zigachev 		break;
144b843c749SSergey Zigachev 	case CHIP_HAWAII:
145b843c749SSergey Zigachev 		fw_name = FIRMWARE_HAWAII;
146b843c749SSergey Zigachev 		break;
147b843c749SSergey Zigachev 	case CHIP_MULLINS:
148b843c749SSergey Zigachev 		fw_name = FIRMWARE_MULLINS;
149b843c749SSergey Zigachev 		break;
150b843c749SSergey Zigachev #endif
151b843c749SSergey Zigachev 	case CHIP_TONGA:
152b843c749SSergey Zigachev 		fw_name = FIRMWARE_TONGA;
153b843c749SSergey Zigachev 		break;
154b843c749SSergey Zigachev 	case CHIP_FIJI:
155b843c749SSergey Zigachev 		fw_name = FIRMWARE_FIJI;
156b843c749SSergey Zigachev 		break;
157b843c749SSergey Zigachev 	case CHIP_CARRIZO:
158b843c749SSergey Zigachev 		fw_name = FIRMWARE_CARRIZO;
159b843c749SSergey Zigachev 		break;
160b843c749SSergey Zigachev 	case CHIP_STONEY:
161b843c749SSergey Zigachev 		fw_name = FIRMWARE_STONEY;
162b843c749SSergey Zigachev 		break;
163b843c749SSergey Zigachev 	case CHIP_POLARIS10:
164b843c749SSergey Zigachev 		fw_name = FIRMWARE_POLARIS10;
165b843c749SSergey Zigachev 		break;
166b843c749SSergey Zigachev 	case CHIP_POLARIS11:
167b843c749SSergey Zigachev 		fw_name = FIRMWARE_POLARIS11;
168b843c749SSergey Zigachev 		break;
169b843c749SSergey Zigachev 	case CHIP_POLARIS12:
170b843c749SSergey Zigachev 		fw_name = FIRMWARE_POLARIS12;
171b843c749SSergey Zigachev 		break;
172b843c749SSergey Zigachev 	case CHIP_VEGA10:
173b843c749SSergey Zigachev 		fw_name = FIRMWARE_VEGA10;
174b843c749SSergey Zigachev 		break;
175b843c749SSergey Zigachev 	case CHIP_VEGA12:
176b843c749SSergey Zigachev 		fw_name = FIRMWARE_VEGA12;
177b843c749SSergey Zigachev 		break;
178b843c749SSergey Zigachev 	case CHIP_VEGAM:
179b843c749SSergey Zigachev 		fw_name = FIRMWARE_VEGAM;
180b843c749SSergey Zigachev 		break;
181b843c749SSergey Zigachev 	case CHIP_VEGA20:
182b843c749SSergey Zigachev 		fw_name = FIRMWARE_VEGA20;
183b843c749SSergey Zigachev 		break;
184b843c749SSergey Zigachev 	default:
185b843c749SSergey Zigachev 		return -EINVAL;
186b843c749SSergey Zigachev 	}
187b843c749SSergey Zigachev 
188b843c749SSergey Zigachev 	r = request_firmware(&adev->uvd.fw, fw_name, adev->dev);
189b843c749SSergey Zigachev 	if (r) {
190b843c749SSergey Zigachev 		dev_err(adev->dev, "amdgpu_uvd: Can't load firmware \"%s\"\n",
191b843c749SSergey Zigachev 			fw_name);
192b843c749SSergey Zigachev 		return r;
193b843c749SSergey Zigachev 	}
194b843c749SSergey Zigachev 
195b843c749SSergey Zigachev 	r = amdgpu_ucode_validate(adev->uvd.fw);
196b843c749SSergey Zigachev 	if (r) {
197b843c749SSergey Zigachev 		dev_err(adev->dev, "amdgpu_uvd: Can't validate firmware \"%s\"\n",
198b843c749SSergey Zigachev 			fw_name);
199b843c749SSergey Zigachev 		release_firmware(adev->uvd.fw);
200b843c749SSergey Zigachev 		adev->uvd.fw = NULL;
201b843c749SSergey Zigachev 		return r;
202b843c749SSergey Zigachev 	}
203b843c749SSergey Zigachev 
204b843c749SSergey Zigachev 	/* Set the default UVD handles that the firmware can handle */
205b843c749SSergey Zigachev 	adev->uvd.max_handles = AMDGPU_DEFAULT_UVD_HANDLES;
206b843c749SSergey Zigachev 
207b843c749SSergey Zigachev 	hdr = (const struct common_firmware_header *)adev->uvd.fw->data;
208b843c749SSergey Zigachev 	family_id = le32_to_cpu(hdr->ucode_version) & 0xff;
209b843c749SSergey Zigachev 
210b843c749SSergey Zigachev 	if (adev->asic_type < CHIP_VEGA20) {
211b843c749SSergey Zigachev 		unsigned version_major, version_minor;
212b843c749SSergey Zigachev 
213b843c749SSergey Zigachev 		version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff;
214b843c749SSergey Zigachev 		version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff;
215b843c749SSergey Zigachev 		DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n",
216b843c749SSergey Zigachev 			version_major, version_minor, family_id);
217b843c749SSergey Zigachev 
218b843c749SSergey Zigachev 		/*
219b843c749SSergey Zigachev 		 * Limit the number of UVD handles depending on microcode major
220b843c749SSergey Zigachev 		 * and minor versions. The firmware version which has 40 UVD
221b843c749SSergey Zigachev 		 * instances support is 1.80. So all subsequent versions should
222b843c749SSergey Zigachev 		 * also have the same support.
223b843c749SSergey Zigachev 		 */
224b843c749SSergey Zigachev 		if ((version_major > 0x01) ||
225b843c749SSergey Zigachev 		    ((version_major == 0x01) && (version_minor >= 0x50)))
226b843c749SSergey Zigachev 			adev->uvd.max_handles = AMDGPU_MAX_UVD_HANDLES;
227b843c749SSergey Zigachev 
228b843c749SSergey Zigachev 		adev->uvd.fw_version = ((version_major << 24) | (version_minor << 16) |
229b843c749SSergey Zigachev 					(family_id << 8));
230b843c749SSergey Zigachev 
231b843c749SSergey Zigachev 		if ((adev->asic_type == CHIP_POLARIS10 ||
232b843c749SSergey Zigachev 		     adev->asic_type == CHIP_POLARIS11) &&
233b843c749SSergey Zigachev 		    (adev->uvd.fw_version < FW_1_66_16))
234b843c749SSergey Zigachev 			DRM_ERROR("POLARIS10/11 UVD firmware version %u.%u is too old.\n",
235b843c749SSergey Zigachev 				  version_major, version_minor);
236b843c749SSergey Zigachev 	} else {
237b843c749SSergey Zigachev 		unsigned int enc_major, enc_minor, dec_minor;
238b843c749SSergey Zigachev 
239b843c749SSergey Zigachev 		dec_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff;
240b843c749SSergey Zigachev 		enc_minor = (le32_to_cpu(hdr->ucode_version) >> 24) & 0x3f;
241b843c749SSergey Zigachev 		enc_major = (le32_to_cpu(hdr->ucode_version) >> 30) & 0x3;
242b843c749SSergey Zigachev 		DRM_INFO("Found UVD firmware ENC: %hu.%hu DEC: .%hu Family ID: %hu\n",
243b843c749SSergey Zigachev 			enc_major, enc_minor, dec_minor, family_id);
244b843c749SSergey Zigachev 
245b843c749SSergey Zigachev 		adev->uvd.max_handles = AMDGPU_MAX_UVD_HANDLES;
246b843c749SSergey Zigachev 
247b843c749SSergey Zigachev 		adev->uvd.fw_version = le32_to_cpu(hdr->ucode_version);
248b843c749SSergey Zigachev 	}
249b843c749SSergey Zigachev 
250b843c749SSergey Zigachev 	bo_size = AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE
251b843c749SSergey Zigachev 		  +  AMDGPU_UVD_SESSION_SIZE * adev->uvd.max_handles;
252b843c749SSergey Zigachev 	if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
253b843c749SSergey Zigachev 		bo_size += AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
254b843c749SSergey Zigachev 
255b843c749SSergey Zigachev 	for (j = 0; j < adev->uvd.num_uvd_inst; j++) {
256b843c749SSergey Zigachev 		if (adev->uvd.harvest_config & (1 << j))
257b843c749SSergey Zigachev 			continue;
258b843c749SSergey Zigachev 		r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE,
259b843c749SSergey Zigachev 					    AMDGPU_GEM_DOMAIN_VRAM, &adev->uvd.inst[j].vcpu_bo,
26078973132SSergey Zigachev 					    (u64 *)&adev->uvd.inst[j].gpu_addr, &adev->uvd.inst[j].cpu_addr);
261b843c749SSergey Zigachev 		if (r) {
262b843c749SSergey Zigachev 			dev_err(adev->dev, "(%d) failed to allocate UVD bo\n", r);
263b843c749SSergey Zigachev 			return r;
264b843c749SSergey Zigachev 		}
265b843c749SSergey Zigachev 	}
266b843c749SSergey Zigachev 
267b843c749SSergey Zigachev 	for (i = 0; i < adev->uvd.max_handles; ++i) {
268b843c749SSergey Zigachev 		atomic_set(&adev->uvd.handles[i], 0);
269b843c749SSergey Zigachev 		adev->uvd.filp[i] = NULL;
270b843c749SSergey Zigachev 	}
271b843c749SSergey Zigachev 
272b843c749SSergey Zigachev 	/* from uvd v5.0 HW addressing capacity increased to 64 bits */
273b843c749SSergey Zigachev 	if (!amdgpu_device_ip_block_version_cmp(adev, AMD_IP_BLOCK_TYPE_UVD, 5, 0))
274b843c749SSergey Zigachev 		adev->uvd.address_64_bit = true;
275b843c749SSergey Zigachev 
276b843c749SSergey Zigachev 	switch (adev->asic_type) {
277b843c749SSergey Zigachev 	case CHIP_TONGA:
278b843c749SSergey Zigachev 		adev->uvd.use_ctx_buf = adev->uvd.fw_version >= FW_1_65_10;
279b843c749SSergey Zigachev 		break;
280b843c749SSergey Zigachev 	case CHIP_CARRIZO:
281b843c749SSergey Zigachev 		adev->uvd.use_ctx_buf = adev->uvd.fw_version >= FW_1_87_11;
282b843c749SSergey Zigachev 		break;
283b843c749SSergey Zigachev 	case CHIP_FIJI:
284b843c749SSergey Zigachev 		adev->uvd.use_ctx_buf = adev->uvd.fw_version >= FW_1_87_12;
285b843c749SSergey Zigachev 		break;
286b843c749SSergey Zigachev 	case CHIP_STONEY:
287b843c749SSergey Zigachev 		adev->uvd.use_ctx_buf = adev->uvd.fw_version >= FW_1_37_15;
288b843c749SSergey Zigachev 		break;
289b843c749SSergey Zigachev 	default:
290b843c749SSergey Zigachev 		adev->uvd.use_ctx_buf = adev->asic_type >= CHIP_POLARIS10;
291b843c749SSergey Zigachev 	}
292b843c749SSergey Zigachev 
293b843c749SSergey Zigachev 	return 0;
294b843c749SSergey Zigachev }
295b843c749SSergey Zigachev 
amdgpu_uvd_sw_fini(struct amdgpu_device * adev)296b843c749SSergey Zigachev int amdgpu_uvd_sw_fini(struct amdgpu_device *adev)
297b843c749SSergey Zigachev {
298b843c749SSergey Zigachev 	int i, j;
299b843c749SSergey Zigachev 
300b843c749SSergey Zigachev 	drm_sched_entity_destroy(&adev->uvd.entity);
301b843c749SSergey Zigachev 
302b843c749SSergey Zigachev 	for (j = 0; j < adev->uvd.num_uvd_inst; ++j) {
303b843c749SSergey Zigachev 		if (adev->uvd.harvest_config & (1 << j))
304b843c749SSergey Zigachev 			continue;
305b843c749SSergey Zigachev 		kvfree(adev->uvd.inst[j].saved_bo);
306b843c749SSergey Zigachev 
307b843c749SSergey Zigachev 		amdgpu_bo_free_kernel(&adev->uvd.inst[j].vcpu_bo,
30878973132SSergey Zigachev 				      (u64 *)&adev->uvd.inst[j].gpu_addr,
309b843c749SSergey Zigachev 				      (void **)&adev->uvd.inst[j].cpu_addr);
310b843c749SSergey Zigachev 
311b843c749SSergey Zigachev 		amdgpu_ring_fini(&adev->uvd.inst[j].ring);
312b843c749SSergey Zigachev 
313b843c749SSergey Zigachev 		for (i = 0; i < AMDGPU_MAX_UVD_ENC_RINGS; ++i)
314b843c749SSergey Zigachev 			amdgpu_ring_fini(&adev->uvd.inst[j].ring_enc[i]);
315b843c749SSergey Zigachev 	}
316b843c749SSergey Zigachev 	release_firmware(adev->uvd.fw);
317b843c749SSergey Zigachev 
318b843c749SSergey Zigachev 	return 0;
319b843c749SSergey Zigachev }
320b843c749SSergey Zigachev 
321b843c749SSergey Zigachev /**
322b843c749SSergey Zigachev  * amdgpu_uvd_entity_init - init entity
323b843c749SSergey Zigachev  *
324b843c749SSergey Zigachev  * @adev: amdgpu_device pointer
325b843c749SSergey Zigachev  *
326b843c749SSergey Zigachev  */
amdgpu_uvd_entity_init(struct amdgpu_device * adev)327b843c749SSergey Zigachev int amdgpu_uvd_entity_init(struct amdgpu_device *adev)
328b843c749SSergey Zigachev {
329b843c749SSergey Zigachev 	struct amdgpu_ring *ring;
330b843c749SSergey Zigachev 	struct drm_sched_rq *rq;
331b843c749SSergey Zigachev 	int r;
332b843c749SSergey Zigachev 
333b843c749SSergey Zigachev 	ring = &adev->uvd.inst[0].ring;
334b843c749SSergey Zigachev 	rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL];
335b843c749SSergey Zigachev 	r = drm_sched_entity_init(&adev->uvd.entity, &rq, 1, NULL);
336b843c749SSergey Zigachev 	if (r) {
337b843c749SSergey Zigachev 		DRM_ERROR("Failed setting up UVD kernel entity.\n");
338b843c749SSergey Zigachev 		return r;
339b843c749SSergey Zigachev 	}
340b843c749SSergey Zigachev 
341b843c749SSergey Zigachev 	return 0;
342b843c749SSergey Zigachev }
343b843c749SSergey Zigachev 
amdgpu_uvd_suspend(struct amdgpu_device * adev)344b843c749SSergey Zigachev int amdgpu_uvd_suspend(struct amdgpu_device *adev)
345b843c749SSergey Zigachev {
346b843c749SSergey Zigachev 	unsigned size;
347b843c749SSergey Zigachev 	void *ptr;
348b843c749SSergey Zigachev 	int i, j;
349b843c749SSergey Zigachev 
350b843c749SSergey Zigachev 	cancel_delayed_work_sync(&adev->uvd.idle_work);
351b843c749SSergey Zigachev 
352b843c749SSergey Zigachev 	/* only valid for physical mode */
353b843c749SSergey Zigachev 	if (adev->asic_type < CHIP_POLARIS10) {
354b843c749SSergey Zigachev 		for (i = 0; i < adev->uvd.max_handles; ++i)
355b843c749SSergey Zigachev 			if (atomic_read(&adev->uvd.handles[i]))
356b843c749SSergey Zigachev 				break;
357b843c749SSergey Zigachev 
358b843c749SSergey Zigachev 		if (i == adev->uvd.max_handles)
359b843c749SSergey Zigachev 			return 0;
360b843c749SSergey Zigachev 	}
361b843c749SSergey Zigachev 
362b843c749SSergey Zigachev 	for (j = 0; j < adev->uvd.num_uvd_inst; ++j) {
363b843c749SSergey Zigachev 		if (adev->uvd.harvest_config & (1 << j))
364b843c749SSergey Zigachev 			continue;
365b843c749SSergey Zigachev 		if (adev->uvd.inst[j].vcpu_bo == NULL)
366b843c749SSergey Zigachev 			continue;
367b843c749SSergey Zigachev 
368b843c749SSergey Zigachev 		size = amdgpu_bo_size(adev->uvd.inst[j].vcpu_bo);
369b843c749SSergey Zigachev 		ptr = adev->uvd.inst[j].cpu_addr;
370b843c749SSergey Zigachev 
37178973132SSergey Zigachev 		adev->uvd.inst[j].saved_bo = kmalloc(size, M_DRM, GFP_KERNEL);
372b843c749SSergey Zigachev 		if (!adev->uvd.inst[j].saved_bo)
373b843c749SSergey Zigachev 			return -ENOMEM;
374b843c749SSergey Zigachev 
375b843c749SSergey Zigachev 		memcpy_fromio(adev->uvd.inst[j].saved_bo, ptr, size);
376b843c749SSergey Zigachev 	}
377b843c749SSergey Zigachev 	return 0;
378b843c749SSergey Zigachev }
379b843c749SSergey Zigachev 
amdgpu_uvd_resume(struct amdgpu_device * adev)380b843c749SSergey Zigachev int amdgpu_uvd_resume(struct amdgpu_device *adev)
381b843c749SSergey Zigachev {
382b843c749SSergey Zigachev 	unsigned size;
383b843c749SSergey Zigachev 	void *ptr;
384b843c749SSergey Zigachev 	int i;
385b843c749SSergey Zigachev 
386b843c749SSergey Zigachev 	for (i = 0; i < adev->uvd.num_uvd_inst; i++) {
387b843c749SSergey Zigachev 		if (adev->uvd.harvest_config & (1 << i))
388b843c749SSergey Zigachev 			continue;
389b843c749SSergey Zigachev 		if (adev->uvd.inst[i].vcpu_bo == NULL)
390b843c749SSergey Zigachev 			return -EINVAL;
391b843c749SSergey Zigachev 
392b843c749SSergey Zigachev 		size = amdgpu_bo_size(adev->uvd.inst[i].vcpu_bo);
393b843c749SSergey Zigachev 		ptr = adev->uvd.inst[i].cpu_addr;
394b843c749SSergey Zigachev 
395b843c749SSergey Zigachev 		if (adev->uvd.inst[i].saved_bo != NULL) {
396b843c749SSergey Zigachev 			memcpy_toio(ptr, adev->uvd.inst[i].saved_bo, size);
397b843c749SSergey Zigachev 			kvfree(adev->uvd.inst[i].saved_bo);
398b843c749SSergey Zigachev 			adev->uvd.inst[i].saved_bo = NULL;
399b843c749SSergey Zigachev 		} else {
400b843c749SSergey Zigachev 			const struct common_firmware_header *hdr;
401b843c749SSergey Zigachev 			unsigned offset;
402b843c749SSergey Zigachev 
403b843c749SSergey Zigachev 			hdr = (const struct common_firmware_header *)adev->uvd.fw->data;
404b843c749SSergey Zigachev 			if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
405b843c749SSergey Zigachev 				offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
406b843c749SSergey Zigachev 				memcpy_toio(adev->uvd.inst[i].cpu_addr, adev->uvd.fw->data + offset,
407b843c749SSergey Zigachev 					    le32_to_cpu(hdr->ucode_size_bytes));
408b843c749SSergey Zigachev 				size -= le32_to_cpu(hdr->ucode_size_bytes);
409b843c749SSergey Zigachev 				ptr += le32_to_cpu(hdr->ucode_size_bytes);
410b843c749SSergey Zigachev 			}
411b843c749SSergey Zigachev 			memset_io(ptr, 0, size);
412b843c749SSergey Zigachev 			/* to restore uvd fence seq */
413b843c749SSergey Zigachev 			amdgpu_fence_driver_force_completion(&adev->uvd.inst[i].ring);
414b843c749SSergey Zigachev 		}
415b843c749SSergey Zigachev 	}
416b843c749SSergey Zigachev 	return 0;
417b843c749SSergey Zigachev }
418b843c749SSergey Zigachev 
amdgpu_uvd_free_handles(struct amdgpu_device * adev,struct drm_file * filp)419b843c749SSergey Zigachev void amdgpu_uvd_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
420b843c749SSergey Zigachev {
421b843c749SSergey Zigachev 	struct amdgpu_ring *ring = &adev->uvd.inst[0].ring;
422b843c749SSergey Zigachev 	int i, r;
423b843c749SSergey Zigachev 
424b843c749SSergey Zigachev 	for (i = 0; i < adev->uvd.max_handles; ++i) {
425b843c749SSergey Zigachev 		uint32_t handle = atomic_read(&adev->uvd.handles[i]);
426b843c749SSergey Zigachev 
427b843c749SSergey Zigachev 		if (handle != 0 && adev->uvd.filp[i] == filp) {
428b843c749SSergey Zigachev 			struct dma_fence *fence;
429b843c749SSergey Zigachev 
430b843c749SSergey Zigachev 			r = amdgpu_uvd_get_destroy_msg(ring, handle, false,
431b843c749SSergey Zigachev 						       &fence);
432b843c749SSergey Zigachev 			if (r) {
433b843c749SSergey Zigachev 				DRM_ERROR("Error destroying UVD %d!\n", r);
434b843c749SSergey Zigachev 				continue;
435b843c749SSergey Zigachev 			}
436b843c749SSergey Zigachev 
437b843c749SSergey Zigachev 			dma_fence_wait(fence, false);
438b843c749SSergey Zigachev 			dma_fence_put(fence);
439b843c749SSergey Zigachev 
440b843c749SSergey Zigachev 			adev->uvd.filp[i] = NULL;
441b843c749SSergey Zigachev 			atomic_set(&adev->uvd.handles[i], 0);
442b843c749SSergey Zigachev 		}
443b843c749SSergey Zigachev 	}
444b843c749SSergey Zigachev }
445b843c749SSergey Zigachev 
amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo * abo)446b843c749SSergey Zigachev static void amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo *abo)
447b843c749SSergey Zigachev {
448b843c749SSergey Zigachev 	int i;
449b843c749SSergey Zigachev 	for (i = 0; i < abo->placement.num_placement; ++i) {
450b843c749SSergey Zigachev 		abo->placements[i].fpfn = 0 >> PAGE_SHIFT;
451b843c749SSergey Zigachev 		abo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT;
452b843c749SSergey Zigachev 	}
453b843c749SSergey Zigachev }
454b843c749SSergey Zigachev 
amdgpu_uvd_get_addr_from_ctx(struct amdgpu_uvd_cs_ctx * ctx)455b843c749SSergey Zigachev static u64 amdgpu_uvd_get_addr_from_ctx(struct amdgpu_uvd_cs_ctx *ctx)
456b843c749SSergey Zigachev {
457b843c749SSergey Zigachev 	uint32_t lo, hi;
458b843c749SSergey Zigachev 	uint64_t addr;
459b843c749SSergey Zigachev 
460b843c749SSergey Zigachev 	lo = amdgpu_get_ib_value(ctx->parser, ctx->ib_idx, ctx->data0);
461b843c749SSergey Zigachev 	hi = amdgpu_get_ib_value(ctx->parser, ctx->ib_idx, ctx->data1);
462b843c749SSergey Zigachev 	addr = ((uint64_t)lo) | (((uint64_t)hi) << 32);
463b843c749SSergey Zigachev 
464b843c749SSergey Zigachev 	return addr;
465b843c749SSergey Zigachev }
466b843c749SSergey Zigachev 
467b843c749SSergey Zigachev /**
468b843c749SSergey Zigachev  * amdgpu_uvd_cs_pass1 - first parsing round
469b843c749SSergey Zigachev  *
470b843c749SSergey Zigachev  * @ctx: UVD parser context
471b843c749SSergey Zigachev  *
472b843c749SSergey Zigachev  * Make sure UVD message and feedback buffers are in VRAM and
473b843c749SSergey Zigachev  * nobody is violating an 256MB boundary.
474b843c749SSergey Zigachev  */
amdgpu_uvd_cs_pass1(struct amdgpu_uvd_cs_ctx * ctx)475b843c749SSergey Zigachev static int amdgpu_uvd_cs_pass1(struct amdgpu_uvd_cs_ctx *ctx)
476b843c749SSergey Zigachev {
477b843c749SSergey Zigachev 	struct ttm_operation_ctx tctx = { false, false };
478b843c749SSergey Zigachev 	struct amdgpu_bo_va_mapping *mapping;
479b843c749SSergey Zigachev 	struct amdgpu_bo *bo;
480b843c749SSergey Zigachev 	uint32_t cmd;
481b843c749SSergey Zigachev 	uint64_t addr = amdgpu_uvd_get_addr_from_ctx(ctx);
482b843c749SSergey Zigachev 	int r = 0;
483b843c749SSergey Zigachev 
484b843c749SSergey Zigachev 	r = amdgpu_cs_find_mapping(ctx->parser, addr, &bo, &mapping);
485b843c749SSergey Zigachev 	if (r) {
48678973132SSergey Zigachev 		DRM_ERROR("Can't find BO for addr 0x%08lx\n", addr);
487b843c749SSergey Zigachev 		return r;
488b843c749SSergey Zigachev 	}
489b843c749SSergey Zigachev 
490b843c749SSergey Zigachev 	if (!ctx->parser->adev->uvd.address_64_bit) {
491b843c749SSergey Zigachev 		/* check if it's a message or feedback command */
492b843c749SSergey Zigachev 		cmd = amdgpu_get_ib_value(ctx->parser, ctx->ib_idx, ctx->idx) >> 1;
493b843c749SSergey Zigachev 		if (cmd == 0x0 || cmd == 0x3) {
494b843c749SSergey Zigachev 			/* yes, force it into VRAM */
495b843c749SSergey Zigachev 			uint32_t domain = AMDGPU_GEM_DOMAIN_VRAM;
496b843c749SSergey Zigachev 			amdgpu_bo_placement_from_domain(bo, domain);
497b843c749SSergey Zigachev 		}
498b843c749SSergey Zigachev 		amdgpu_uvd_force_into_uvd_segment(bo);
499b843c749SSergey Zigachev 
500b843c749SSergey Zigachev 		r = ttm_bo_validate(&bo->tbo, &bo->placement, &tctx);
501b843c749SSergey Zigachev 	}
502b843c749SSergey Zigachev 
503b843c749SSergey Zigachev 	return r;
504b843c749SSergey Zigachev }
505b843c749SSergey Zigachev 
506b843c749SSergey Zigachev /**
507b843c749SSergey Zigachev  * amdgpu_uvd_cs_msg_decode - handle UVD decode message
508b843c749SSergey Zigachev  *
509b843c749SSergey Zigachev  * @msg: pointer to message structure
510b843c749SSergey Zigachev  * @buf_sizes: returned buffer sizes
511b843c749SSergey Zigachev  *
512b843c749SSergey Zigachev  * Peek into the decode message and calculate the necessary buffer sizes.
513b843c749SSergey Zigachev  */
amdgpu_uvd_cs_msg_decode(struct amdgpu_device * adev,uint32_t * msg,unsigned buf_sizes[])514b843c749SSergey Zigachev static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
515b843c749SSergey Zigachev 	unsigned buf_sizes[])
516b843c749SSergey Zigachev {
517b843c749SSergey Zigachev 	unsigned stream_type = msg[4];
518b843c749SSergey Zigachev 	unsigned width = msg[6];
519b843c749SSergey Zigachev 	unsigned height = msg[7];
520b843c749SSergey Zigachev 	unsigned dpb_size = msg[9];
521b843c749SSergey Zigachev 	unsigned pitch = msg[28];
522b843c749SSergey Zigachev 	unsigned level = msg[57];
523b843c749SSergey Zigachev 
524b843c749SSergey Zigachev 	unsigned width_in_mb = width / 16;
525b843c749SSergey Zigachev 	unsigned height_in_mb = ALIGN(height / 16, 2);
526b843c749SSergey Zigachev 	unsigned fs_in_mb = width_in_mb * height_in_mb;
527b843c749SSergey Zigachev 
528b843c749SSergey Zigachev 	unsigned image_size, tmp, min_dpb_size, num_dpb_buffer;
529b843c749SSergey Zigachev 	unsigned min_ctx_size = ~0;
530b843c749SSergey Zigachev 
531b843c749SSergey Zigachev 	image_size = width * height;
532b843c749SSergey Zigachev 	image_size += image_size / 2;
533b843c749SSergey Zigachev 	image_size = ALIGN(image_size, 1024);
534b843c749SSergey Zigachev 
535b843c749SSergey Zigachev 	switch (stream_type) {
536b843c749SSergey Zigachev 	case 0: /* H264 */
537b843c749SSergey Zigachev 		switch(level) {
538b843c749SSergey Zigachev 		case 30:
539b843c749SSergey Zigachev 			num_dpb_buffer = 8100 / fs_in_mb;
540b843c749SSergey Zigachev 			break;
541b843c749SSergey Zigachev 		case 31:
542b843c749SSergey Zigachev 			num_dpb_buffer = 18000 / fs_in_mb;
543b843c749SSergey Zigachev 			break;
544b843c749SSergey Zigachev 		case 32:
545b843c749SSergey Zigachev 			num_dpb_buffer = 20480 / fs_in_mb;
546b843c749SSergey Zigachev 			break;
547b843c749SSergey Zigachev 		case 41:
548b843c749SSergey Zigachev 			num_dpb_buffer = 32768 / fs_in_mb;
549b843c749SSergey Zigachev 			break;
550b843c749SSergey Zigachev 		case 42:
551b843c749SSergey Zigachev 			num_dpb_buffer = 34816 / fs_in_mb;
552b843c749SSergey Zigachev 			break;
553b843c749SSergey Zigachev 		case 50:
554b843c749SSergey Zigachev 			num_dpb_buffer = 110400 / fs_in_mb;
555b843c749SSergey Zigachev 			break;
556b843c749SSergey Zigachev 		case 51:
557b843c749SSergey Zigachev 			num_dpb_buffer = 184320 / fs_in_mb;
558b843c749SSergey Zigachev 			break;
559b843c749SSergey Zigachev 		default:
560b843c749SSergey Zigachev 			num_dpb_buffer = 184320 / fs_in_mb;
561b843c749SSergey Zigachev 			break;
562b843c749SSergey Zigachev 		}
563b843c749SSergey Zigachev 		num_dpb_buffer++;
564b843c749SSergey Zigachev 		if (num_dpb_buffer > 17)
565b843c749SSergey Zigachev 			num_dpb_buffer = 17;
566b843c749SSergey Zigachev 
567b843c749SSergey Zigachev 		/* reference picture buffer */
568b843c749SSergey Zigachev 		min_dpb_size = image_size * num_dpb_buffer;
569b843c749SSergey Zigachev 
570b843c749SSergey Zigachev 		/* macroblock context buffer */
571b843c749SSergey Zigachev 		min_dpb_size += width_in_mb * height_in_mb * num_dpb_buffer * 192;
572b843c749SSergey Zigachev 
573b843c749SSergey Zigachev 		/* IT surface buffer */
574b843c749SSergey Zigachev 		min_dpb_size += width_in_mb * height_in_mb * 32;
575b843c749SSergey Zigachev 		break;
576b843c749SSergey Zigachev 
577b843c749SSergey Zigachev 	case 1: /* VC1 */
578b843c749SSergey Zigachev 
579b843c749SSergey Zigachev 		/* reference picture buffer */
580b843c749SSergey Zigachev 		min_dpb_size = image_size * 3;
581b843c749SSergey Zigachev 
582b843c749SSergey Zigachev 		/* CONTEXT_BUFFER */
583b843c749SSergey Zigachev 		min_dpb_size += width_in_mb * height_in_mb * 128;
584b843c749SSergey Zigachev 
585b843c749SSergey Zigachev 		/* IT surface buffer */
586b843c749SSergey Zigachev 		min_dpb_size += width_in_mb * 64;
587b843c749SSergey Zigachev 
588b843c749SSergey Zigachev 		/* DB surface buffer */
589b843c749SSergey Zigachev 		min_dpb_size += width_in_mb * 128;
590b843c749SSergey Zigachev 
591b843c749SSergey Zigachev 		/* BP */
592b843c749SSergey Zigachev 		tmp = max(width_in_mb, height_in_mb);
593b843c749SSergey Zigachev 		min_dpb_size += ALIGN(tmp * 7 * 16, 64);
594b843c749SSergey Zigachev 		break;
595b843c749SSergey Zigachev 
596b843c749SSergey Zigachev 	case 3: /* MPEG2 */
597b843c749SSergey Zigachev 
598b843c749SSergey Zigachev 		/* reference picture buffer */
599b843c749SSergey Zigachev 		min_dpb_size = image_size * 3;
600b843c749SSergey Zigachev 		break;
601b843c749SSergey Zigachev 
602b843c749SSergey Zigachev 	case 4: /* MPEG4 */
603b843c749SSergey Zigachev 
604b843c749SSergey Zigachev 		/* reference picture buffer */
605b843c749SSergey Zigachev 		min_dpb_size = image_size * 3;
606b843c749SSergey Zigachev 
607b843c749SSergey Zigachev 		/* CM */
608b843c749SSergey Zigachev 		min_dpb_size += width_in_mb * height_in_mb * 64;
609b843c749SSergey Zigachev 
610b843c749SSergey Zigachev 		/* IT surface buffer */
611b843c749SSergey Zigachev 		min_dpb_size += ALIGN(width_in_mb * height_in_mb * 32, 64);
612b843c749SSergey Zigachev 		break;
613b843c749SSergey Zigachev 
614b843c749SSergey Zigachev 	case 7: /* H264 Perf */
615b843c749SSergey Zigachev 		switch(level) {
616b843c749SSergey Zigachev 		case 30:
617b843c749SSergey Zigachev 			num_dpb_buffer = 8100 / fs_in_mb;
618b843c749SSergey Zigachev 			break;
619b843c749SSergey Zigachev 		case 31:
620b843c749SSergey Zigachev 			num_dpb_buffer = 18000 / fs_in_mb;
621b843c749SSergey Zigachev 			break;
622b843c749SSergey Zigachev 		case 32:
623b843c749SSergey Zigachev 			num_dpb_buffer = 20480 / fs_in_mb;
624b843c749SSergey Zigachev 			break;
625b843c749SSergey Zigachev 		case 41:
626b843c749SSergey Zigachev 			num_dpb_buffer = 32768 / fs_in_mb;
627b843c749SSergey Zigachev 			break;
628b843c749SSergey Zigachev 		case 42:
629b843c749SSergey Zigachev 			num_dpb_buffer = 34816 / fs_in_mb;
630b843c749SSergey Zigachev 			break;
631b843c749SSergey Zigachev 		case 50:
632b843c749SSergey Zigachev 			num_dpb_buffer = 110400 / fs_in_mb;
633b843c749SSergey Zigachev 			break;
634b843c749SSergey Zigachev 		case 51:
635b843c749SSergey Zigachev 			num_dpb_buffer = 184320 / fs_in_mb;
636b843c749SSergey Zigachev 			break;
637b843c749SSergey Zigachev 		default:
638b843c749SSergey Zigachev 			num_dpb_buffer = 184320 / fs_in_mb;
639b843c749SSergey Zigachev 			break;
640b843c749SSergey Zigachev 		}
641b843c749SSergey Zigachev 		num_dpb_buffer++;
642b843c749SSergey Zigachev 		if (num_dpb_buffer > 17)
643b843c749SSergey Zigachev 			num_dpb_buffer = 17;
644b843c749SSergey Zigachev 
645b843c749SSergey Zigachev 		/* reference picture buffer */
646b843c749SSergey Zigachev 		min_dpb_size = image_size * num_dpb_buffer;
647b843c749SSergey Zigachev 
648b843c749SSergey Zigachev 		if (!adev->uvd.use_ctx_buf){
649b843c749SSergey Zigachev 			/* macroblock context buffer */
650b843c749SSergey Zigachev 			min_dpb_size +=
651b843c749SSergey Zigachev 				width_in_mb * height_in_mb * num_dpb_buffer * 192;
652b843c749SSergey Zigachev 
653b843c749SSergey Zigachev 			/* IT surface buffer */
654b843c749SSergey Zigachev 			min_dpb_size += width_in_mb * height_in_mb * 32;
655b843c749SSergey Zigachev 		} else {
656b843c749SSergey Zigachev 			/* macroblock context buffer */
657b843c749SSergey Zigachev 			min_ctx_size =
658b843c749SSergey Zigachev 				width_in_mb * height_in_mb * num_dpb_buffer * 192;
659b843c749SSergey Zigachev 		}
660b843c749SSergey Zigachev 		break;
661b843c749SSergey Zigachev 
662b843c749SSergey Zigachev 	case 8: /* MJPEG */
663b843c749SSergey Zigachev 		min_dpb_size = 0;
664b843c749SSergey Zigachev 		break;
665b843c749SSergey Zigachev 
666b843c749SSergey Zigachev 	case 16: /* H265 */
667b843c749SSergey Zigachev 		image_size = (ALIGN(width, 16) * ALIGN(height, 16) * 3) / 2;
668b843c749SSergey Zigachev 		image_size = ALIGN(image_size, 256);
669b843c749SSergey Zigachev 
670b843c749SSergey Zigachev 		num_dpb_buffer = (le32_to_cpu(msg[59]) & 0xff) + 2;
671b843c749SSergey Zigachev 		min_dpb_size = image_size * num_dpb_buffer;
672b843c749SSergey Zigachev 		min_ctx_size = ((width + 255) / 16) * ((height + 255) / 16)
673b843c749SSergey Zigachev 					   * 16 * num_dpb_buffer + 52 * 1024;
674b843c749SSergey Zigachev 		break;
675b843c749SSergey Zigachev 
676b843c749SSergey Zigachev 	default:
677b843c749SSergey Zigachev 		DRM_ERROR("UVD codec not handled %d!\n", stream_type);
678b843c749SSergey Zigachev 		return -EINVAL;
679b843c749SSergey Zigachev 	}
680b843c749SSergey Zigachev 
681b843c749SSergey Zigachev 	if (width > pitch) {
682b843c749SSergey Zigachev 		DRM_ERROR("Invalid UVD decoding target pitch!\n");
683b843c749SSergey Zigachev 		return -EINVAL;
684b843c749SSergey Zigachev 	}
685b843c749SSergey Zigachev 
686b843c749SSergey Zigachev 	if (dpb_size < min_dpb_size) {
687b843c749SSergey Zigachev 		DRM_ERROR("Invalid dpb_size in UVD message (%d / %d)!\n",
688b843c749SSergey Zigachev 			  dpb_size, min_dpb_size);
689b843c749SSergey Zigachev 		return -EINVAL;
690b843c749SSergey Zigachev 	}
691b843c749SSergey Zigachev 
692b843c749SSergey Zigachev 	buf_sizes[0x1] = dpb_size;
693b843c749SSergey Zigachev 	buf_sizes[0x2] = image_size;
694b843c749SSergey Zigachev 	buf_sizes[0x4] = min_ctx_size;
695b843c749SSergey Zigachev 	return 0;
696b843c749SSergey Zigachev }
697b843c749SSergey Zigachev 
698b843c749SSergey Zigachev /**
699b843c749SSergey Zigachev  * amdgpu_uvd_cs_msg - handle UVD message
700b843c749SSergey Zigachev  *
701b843c749SSergey Zigachev  * @ctx: UVD parser context
702b843c749SSergey Zigachev  * @bo: buffer object containing the message
703b843c749SSergey Zigachev  * @offset: offset into the buffer object
704b843c749SSergey Zigachev  *
705b843c749SSergey Zigachev  * Peek into the UVD message and extract the session id.
706b843c749SSergey Zigachev  * Make sure that we don't open up to many sessions.
707b843c749SSergey Zigachev  */
amdgpu_uvd_cs_msg(struct amdgpu_uvd_cs_ctx * ctx,struct amdgpu_bo * bo,unsigned offset)708b843c749SSergey Zigachev static int amdgpu_uvd_cs_msg(struct amdgpu_uvd_cs_ctx *ctx,
709b843c749SSergey Zigachev 			     struct amdgpu_bo *bo, unsigned offset)
710b843c749SSergey Zigachev {
711b843c749SSergey Zigachev 	struct amdgpu_device *adev = ctx->parser->adev;
712b843c749SSergey Zigachev 	int32_t *msg, msg_type, handle;
713b843c749SSergey Zigachev 	void *ptr;
714b843c749SSergey Zigachev 	long r;
715b843c749SSergey Zigachev 	int i;
716b843c749SSergey Zigachev 
717b843c749SSergey Zigachev 	if (offset & 0x3F) {
718b843c749SSergey Zigachev 		DRM_ERROR("UVD messages must be 64 byte aligned!\n");
719b843c749SSergey Zigachev 		return -EINVAL;
720b843c749SSergey Zigachev 	}
721b843c749SSergey Zigachev 
722b843c749SSergey Zigachev 	r = amdgpu_bo_kmap(bo, &ptr);
723b843c749SSergey Zigachev 	if (r) {
724b843c749SSergey Zigachev 		DRM_ERROR("Failed mapping the UVD) message (%ld)!\n", r);
725b843c749SSergey Zigachev 		return r;
726b843c749SSergey Zigachev 	}
727b843c749SSergey Zigachev 
728b843c749SSergey Zigachev 	msg = ptr + offset;
729b843c749SSergey Zigachev 
730b843c749SSergey Zigachev 	msg_type = msg[1];
731b843c749SSergey Zigachev 	handle = msg[2];
732b843c749SSergey Zigachev 
733b843c749SSergey Zigachev 	if (handle == 0) {
734b843c749SSergey Zigachev 		DRM_ERROR("Invalid UVD handle!\n");
735b843c749SSergey Zigachev 		return -EINVAL;
736b843c749SSergey Zigachev 	}
737b843c749SSergey Zigachev 
738b843c749SSergey Zigachev 	switch (msg_type) {
739b843c749SSergey Zigachev 	case 0:
740b843c749SSergey Zigachev 		/* it's a create msg, calc image size (width * height) */
741b843c749SSergey Zigachev 		amdgpu_bo_kunmap(bo);
742b843c749SSergey Zigachev 
743b843c749SSergey Zigachev 		/* try to alloc a new handle */
744b843c749SSergey Zigachev 		for (i = 0; i < adev->uvd.max_handles; ++i) {
745b843c749SSergey Zigachev 			if (atomic_read(&adev->uvd.handles[i]) == handle) {
746b843c749SSergey Zigachev 				DRM_ERROR(")Handle 0x%x already in use!\n",
747b843c749SSergey Zigachev 					  handle);
748b843c749SSergey Zigachev 				return -EINVAL;
749b843c749SSergey Zigachev 			}
750b843c749SSergey Zigachev 
751b843c749SSergey Zigachev 			if (!atomic_cmpxchg(&adev->uvd.handles[i], 0, handle)) {
752b843c749SSergey Zigachev 				adev->uvd.filp[i] = ctx->parser->filp;
753b843c749SSergey Zigachev 				return 0;
754b843c749SSergey Zigachev 			}
755b843c749SSergey Zigachev 		}
756b843c749SSergey Zigachev 
757b843c749SSergey Zigachev 		DRM_ERROR("No more free UVD handles!\n");
758b843c749SSergey Zigachev 		return -ENOSPC;
759b843c749SSergey Zigachev 
760b843c749SSergey Zigachev 	case 1:
761b843c749SSergey Zigachev 		/* it's a decode msg, calc buffer sizes */
762b843c749SSergey Zigachev 		r = amdgpu_uvd_cs_msg_decode(adev, msg, ctx->buf_sizes);
763b843c749SSergey Zigachev 		amdgpu_bo_kunmap(bo);
764b843c749SSergey Zigachev 		if (r)
765b843c749SSergey Zigachev 			return r;
766b843c749SSergey Zigachev 
767b843c749SSergey Zigachev 		/* validate the handle */
768b843c749SSergey Zigachev 		for (i = 0; i < adev->uvd.max_handles; ++i) {
769b843c749SSergey Zigachev 			if (atomic_read(&adev->uvd.handles[i]) == handle) {
770b843c749SSergey Zigachev 				if (adev->uvd.filp[i] != ctx->parser->filp) {
771b843c749SSergey Zigachev 					DRM_ERROR("UVD handle collision detected!\n");
772b843c749SSergey Zigachev 					return -EINVAL;
773b843c749SSergey Zigachev 				}
774b843c749SSergey Zigachev 				return 0;
775b843c749SSergey Zigachev 			}
776b843c749SSergey Zigachev 		}
777b843c749SSergey Zigachev 
778b843c749SSergey Zigachev 		DRM_ERROR("Invalid UVD handle 0x%x!\n", handle);
779b843c749SSergey Zigachev 		return -ENOENT;
780b843c749SSergey Zigachev 
781b843c749SSergey Zigachev 	case 2:
782b843c749SSergey Zigachev 		/* it's a destroy msg, free the handle */
783b843c749SSergey Zigachev 		for (i = 0; i < adev->uvd.max_handles; ++i)
784b843c749SSergey Zigachev 			atomic_cmpxchg(&adev->uvd.handles[i], handle, 0);
785b843c749SSergey Zigachev 		amdgpu_bo_kunmap(bo);
786b843c749SSergey Zigachev 		return 0;
787b843c749SSergey Zigachev 
788b843c749SSergey Zigachev 	default:
789b843c749SSergey Zigachev 		DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type);
790b843c749SSergey Zigachev 		return -EINVAL;
791b843c749SSergey Zigachev 	}
792b843c749SSergey Zigachev 	BUG();
793b843c749SSergey Zigachev 	return -EINVAL;
794b843c749SSergey Zigachev }
795b843c749SSergey Zigachev 
796b843c749SSergey Zigachev /**
797b843c749SSergey Zigachev  * amdgpu_uvd_cs_pass2 - second parsing round
798b843c749SSergey Zigachev  *
799b843c749SSergey Zigachev  * @ctx: UVD parser context
800b843c749SSergey Zigachev  *
801b843c749SSergey Zigachev  * Patch buffer addresses, make sure buffer sizes are correct.
802b843c749SSergey Zigachev  */
amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx * ctx)803b843c749SSergey Zigachev static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx)
804b843c749SSergey Zigachev {
805b843c749SSergey Zigachev 	struct amdgpu_bo_va_mapping *mapping;
806b843c749SSergey Zigachev 	struct amdgpu_bo *bo;
807b843c749SSergey Zigachev 	uint32_t cmd;
808b843c749SSergey Zigachev 	uint64_t start, end;
809b843c749SSergey Zigachev 	uint64_t addr = amdgpu_uvd_get_addr_from_ctx(ctx);
810b843c749SSergey Zigachev 	int r;
811b843c749SSergey Zigachev 
812b843c749SSergey Zigachev 	r = amdgpu_cs_find_mapping(ctx->parser, addr, &bo, &mapping);
813b843c749SSergey Zigachev 	if (r) {
81478973132SSergey Zigachev 		DRM_ERROR("Can't find BO for addr 0x%08lx\n", addr);
815b843c749SSergey Zigachev 		return r;
816b843c749SSergey Zigachev 	}
817b843c749SSergey Zigachev 
818b843c749SSergey Zigachev 	start = amdgpu_bo_gpu_offset(bo);
819b843c749SSergey Zigachev 
820b843c749SSergey Zigachev 	end = (mapping->last + 1 - mapping->start);
821b843c749SSergey Zigachev 	end = end * AMDGPU_GPU_PAGE_SIZE + start;
822b843c749SSergey Zigachev 
823b843c749SSergey Zigachev 	addr -= mapping->start * AMDGPU_GPU_PAGE_SIZE;
824b843c749SSergey Zigachev 	start += addr;
825b843c749SSergey Zigachev 
826b843c749SSergey Zigachev 	amdgpu_set_ib_value(ctx->parser, ctx->ib_idx, ctx->data0,
827b843c749SSergey Zigachev 			    lower_32_bits(start));
828b843c749SSergey Zigachev 	amdgpu_set_ib_value(ctx->parser, ctx->ib_idx, ctx->data1,
829b843c749SSergey Zigachev 			    upper_32_bits(start));
830b843c749SSergey Zigachev 
831b843c749SSergey Zigachev 	cmd = amdgpu_get_ib_value(ctx->parser, ctx->ib_idx, ctx->idx) >> 1;
832b843c749SSergey Zigachev 	if (cmd < 0x4) {
833b843c749SSergey Zigachev 		if ((end - start) < ctx->buf_sizes[cmd]) {
834b843c749SSergey Zigachev 			DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,
835b843c749SSergey Zigachev 				  (unsigned)(end - start),
836b843c749SSergey Zigachev 				  ctx->buf_sizes[cmd]);
837b843c749SSergey Zigachev 			return -EINVAL;
838b843c749SSergey Zigachev 		}
839b843c749SSergey Zigachev 
840b843c749SSergey Zigachev 	} else if (cmd == 0x206) {
841b843c749SSergey Zigachev 		if ((end - start) < ctx->buf_sizes[4]) {
842b843c749SSergey Zigachev 			DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,
843b843c749SSergey Zigachev 					  (unsigned)(end - start),
844b843c749SSergey Zigachev 					  ctx->buf_sizes[4]);
845b843c749SSergey Zigachev 			return -EINVAL;
846b843c749SSergey Zigachev 		}
847b843c749SSergey Zigachev 	} else if ((cmd != 0x100) && (cmd != 0x204)) {
848b843c749SSergey Zigachev 		DRM_ERROR("invalid UVD command %X!\n", cmd);
849b843c749SSergey Zigachev 		return -EINVAL;
850b843c749SSergey Zigachev 	}
851b843c749SSergey Zigachev 
852b843c749SSergey Zigachev 	if (!ctx->parser->adev->uvd.address_64_bit) {
853b843c749SSergey Zigachev 		if ((start >> 28) != ((end - 1) >> 28)) {
85478973132SSergey Zigachev 			DRM_ERROR("reloc %lX-%lX crossing 256MB boundary!\n",
855b843c749SSergey Zigachev 				  start, end);
856b843c749SSergey Zigachev 			return -EINVAL;
857b843c749SSergey Zigachev 		}
858b843c749SSergey Zigachev 
859b843c749SSergey Zigachev 		if ((cmd == 0 || cmd == 0x3) &&
860b843c749SSergey Zigachev 		    (start >> 28) != (ctx->parser->adev->uvd.inst->gpu_addr >> 28)) {
86178973132SSergey Zigachev 			DRM_ERROR("msg/fb buffer %lX-%lX out of 256MB segment!\n",
862b843c749SSergey Zigachev 				  start, end);
863b843c749SSergey Zigachev 			return -EINVAL;
864b843c749SSergey Zigachev 		}
865b843c749SSergey Zigachev 	}
866b843c749SSergey Zigachev 
867b843c749SSergey Zigachev 	if (cmd == 0) {
868b843c749SSergey Zigachev 		ctx->has_msg_cmd = true;
869b843c749SSergey Zigachev 		r = amdgpu_uvd_cs_msg(ctx, bo, addr);
870b843c749SSergey Zigachev 		if (r)
871b843c749SSergey Zigachev 			return r;
872b843c749SSergey Zigachev 	} else if (!ctx->has_msg_cmd) {
873b843c749SSergey Zigachev 		DRM_ERROR("Message needed before other commands are send!\n");
874b843c749SSergey Zigachev 		return -EINVAL;
875b843c749SSergey Zigachev 	}
876b843c749SSergey Zigachev 
877b843c749SSergey Zigachev 	return 0;
878b843c749SSergey Zigachev }
879b843c749SSergey Zigachev 
880b843c749SSergey Zigachev /**
881b843c749SSergey Zigachev  * amdgpu_uvd_cs_reg - parse register writes
882b843c749SSergey Zigachev  *
883b843c749SSergey Zigachev  * @ctx: UVD parser context
884b843c749SSergey Zigachev  * @cb: callback function
885b843c749SSergey Zigachev  *
886b843c749SSergey Zigachev  * Parse the register writes, call cb on each complete command.
887b843c749SSergey Zigachev  */
amdgpu_uvd_cs_reg(struct amdgpu_uvd_cs_ctx * ctx,int (* cb)(struct amdgpu_uvd_cs_ctx * ctx))888b843c749SSergey Zigachev static int amdgpu_uvd_cs_reg(struct amdgpu_uvd_cs_ctx *ctx,
889b843c749SSergey Zigachev 			     int (*cb)(struct amdgpu_uvd_cs_ctx *ctx))
890b843c749SSergey Zigachev {
891b843c749SSergey Zigachev 	struct amdgpu_ib *ib = &ctx->parser->job->ibs[ctx->ib_idx];
892b843c749SSergey Zigachev 	int i, r;
893b843c749SSergey Zigachev 
894b843c749SSergey Zigachev 	ctx->idx++;
895b843c749SSergey Zigachev 	for (i = 0; i <= ctx->count; ++i) {
896b843c749SSergey Zigachev 		unsigned reg = ctx->reg + i;
897b843c749SSergey Zigachev 
898b843c749SSergey Zigachev 		if (ctx->idx >= ib->length_dw) {
899b843c749SSergey Zigachev 			DRM_ERROR("Register command after end of CS!\n");
900b843c749SSergey Zigachev 			return -EINVAL;
901b843c749SSergey Zigachev 		}
902b843c749SSergey Zigachev 
903b843c749SSergey Zigachev 		switch (reg) {
904b843c749SSergey Zigachev 		case mmUVD_GPCOM_VCPU_DATA0:
905b843c749SSergey Zigachev 			ctx->data0 = ctx->idx;
906b843c749SSergey Zigachev 			break;
907b843c749SSergey Zigachev 		case mmUVD_GPCOM_VCPU_DATA1:
908b843c749SSergey Zigachev 			ctx->data1 = ctx->idx;
909b843c749SSergey Zigachev 			break;
910b843c749SSergey Zigachev 		case mmUVD_GPCOM_VCPU_CMD:
911b843c749SSergey Zigachev 			r = cb(ctx);
912b843c749SSergey Zigachev 			if (r)
913b843c749SSergey Zigachev 				return r;
914b843c749SSergey Zigachev 			break;
915b843c749SSergey Zigachev 		case mmUVD_ENGINE_CNTL:
916b843c749SSergey Zigachev 		case mmUVD_NO_OP:
917b843c749SSergey Zigachev 			break;
918b843c749SSergey Zigachev 		default:
919b843c749SSergey Zigachev 			DRM_ERROR("Invalid reg 0x%X!\n", reg);
920b843c749SSergey Zigachev 			return -EINVAL;
921b843c749SSergey Zigachev 		}
922b843c749SSergey Zigachev 		ctx->idx++;
923b843c749SSergey Zigachev 	}
924b843c749SSergey Zigachev 	return 0;
925b843c749SSergey Zigachev }
926b843c749SSergey Zigachev 
927b843c749SSergey Zigachev /**
928b843c749SSergey Zigachev  * amdgpu_uvd_cs_packets - parse UVD packets
929b843c749SSergey Zigachev  *
930b843c749SSergey Zigachev  * @ctx: UVD parser context
931b843c749SSergey Zigachev  * @cb: callback function
932b843c749SSergey Zigachev  *
933b843c749SSergey Zigachev  * Parse the command stream packets.
934b843c749SSergey Zigachev  */
amdgpu_uvd_cs_packets(struct amdgpu_uvd_cs_ctx * ctx,int (* cb)(struct amdgpu_uvd_cs_ctx * ctx))935b843c749SSergey Zigachev static int amdgpu_uvd_cs_packets(struct amdgpu_uvd_cs_ctx *ctx,
936b843c749SSergey Zigachev 				 int (*cb)(struct amdgpu_uvd_cs_ctx *ctx))
937b843c749SSergey Zigachev {
938b843c749SSergey Zigachev 	struct amdgpu_ib *ib = &ctx->parser->job->ibs[ctx->ib_idx];
939b843c749SSergey Zigachev 	int r;
940b843c749SSergey Zigachev 
941b843c749SSergey Zigachev 	for (ctx->idx = 0 ; ctx->idx < ib->length_dw; ) {
942b843c749SSergey Zigachev 		uint32_t cmd = amdgpu_get_ib_value(ctx->parser, ctx->ib_idx, ctx->idx);
943b843c749SSergey Zigachev 		unsigned type = CP_PACKET_GET_TYPE(cmd);
944b843c749SSergey Zigachev 		switch (type) {
945b843c749SSergey Zigachev 		case PACKET_TYPE0:
946b843c749SSergey Zigachev 			ctx->reg = CP_PACKET0_GET_REG(cmd);
947b843c749SSergey Zigachev 			ctx->count = CP_PACKET_GET_COUNT(cmd);
948b843c749SSergey Zigachev 			r = amdgpu_uvd_cs_reg(ctx, cb);
949b843c749SSergey Zigachev 			if (r)
950b843c749SSergey Zigachev 				return r;
951b843c749SSergey Zigachev 			break;
952b843c749SSergey Zigachev 		case PACKET_TYPE2:
953b843c749SSergey Zigachev 			++ctx->idx;
954b843c749SSergey Zigachev 			break;
955b843c749SSergey Zigachev 		default:
956b843c749SSergey Zigachev 			DRM_ERROR("Unknown packet type %d !\n", type);
957b843c749SSergey Zigachev 			return -EINVAL;
958b843c749SSergey Zigachev 		}
959b843c749SSergey Zigachev 	}
960b843c749SSergey Zigachev 	return 0;
961b843c749SSergey Zigachev }
962b843c749SSergey Zigachev 
963b843c749SSergey Zigachev /**
964b843c749SSergey Zigachev  * amdgpu_uvd_ring_parse_cs - UVD command submission parser
965b843c749SSergey Zigachev  *
966b843c749SSergey Zigachev  * @parser: Command submission parser context
967b843c749SSergey Zigachev  *
968b843c749SSergey Zigachev  * Parse the command stream, patch in addresses as necessary.
969b843c749SSergey Zigachev  */
amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser * parser,uint32_t ib_idx)970b843c749SSergey Zigachev int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx)
971b843c749SSergey Zigachev {
972b843c749SSergey Zigachev 	struct amdgpu_uvd_cs_ctx ctx = {};
973b843c749SSergey Zigachev 	unsigned buf_sizes[] = {
974b843c749SSergey Zigachev 		[0x00000000]	=	2048,
975b843c749SSergey Zigachev 		[0x00000001]	=	0xFFFFFFFF,
976b843c749SSergey Zigachev 		[0x00000002]	=	0xFFFFFFFF,
977b843c749SSergey Zigachev 		[0x00000003]	=	2048,
978b843c749SSergey Zigachev 		[0x00000004]	=	0xFFFFFFFF,
979b843c749SSergey Zigachev 	};
980b843c749SSergey Zigachev 	struct amdgpu_ib *ib = &parser->job->ibs[ib_idx];
981b843c749SSergey Zigachev 	int r;
982b843c749SSergey Zigachev 
983b843c749SSergey Zigachev 	parser->job->vm = NULL;
984b843c749SSergey Zigachev 	ib->gpu_addr = amdgpu_sa_bo_gpu_addr(ib->sa_bo);
985b843c749SSergey Zigachev 
986b843c749SSergey Zigachev 	if (ib->length_dw % 16) {
987b843c749SSergey Zigachev 		DRM_ERROR("UVD IB length (%d) not 16 dwords aligned!\n",
988b843c749SSergey Zigachev 			  ib->length_dw);
989b843c749SSergey Zigachev 		return -EINVAL;
990b843c749SSergey Zigachev 	}
991b843c749SSergey Zigachev 
992b843c749SSergey Zigachev 	ctx.parser = parser;
993b843c749SSergey Zigachev 	ctx.buf_sizes = buf_sizes;
994b843c749SSergey Zigachev 	ctx.ib_idx = ib_idx;
995b843c749SSergey Zigachev 
996b843c749SSergey Zigachev 	/* first round only required on chips without UVD 64 bit address support */
997b843c749SSergey Zigachev 	if (!parser->adev->uvd.address_64_bit) {
998b843c749SSergey Zigachev 		/* first round, make sure the buffers are actually in the UVD segment */
999b843c749SSergey Zigachev 		r = amdgpu_uvd_cs_packets(&ctx, amdgpu_uvd_cs_pass1);
1000b843c749SSergey Zigachev 		if (r)
1001b843c749SSergey Zigachev 			return r;
1002b843c749SSergey Zigachev 	}
1003b843c749SSergey Zigachev 
1004b843c749SSergey Zigachev 	/* second round, patch buffer addresses into the command stream */
1005b843c749SSergey Zigachev 	r = amdgpu_uvd_cs_packets(&ctx, amdgpu_uvd_cs_pass2);
1006b843c749SSergey Zigachev 	if (r)
1007b843c749SSergey Zigachev 		return r;
1008b843c749SSergey Zigachev 
1009b843c749SSergey Zigachev 	if (!ctx.has_msg_cmd) {
1010b843c749SSergey Zigachev 		DRM_ERROR("UVD-IBs need a msg command!\n");
1011b843c749SSergey Zigachev 		return -EINVAL;
1012b843c749SSergey Zigachev 	}
1013b843c749SSergey Zigachev 
1014b843c749SSergey Zigachev 	return 0;
1015b843c749SSergey Zigachev }
1016b843c749SSergey Zigachev 
amdgpu_uvd_send_msg(struct amdgpu_ring * ring,struct amdgpu_bo * bo,bool direct,struct dma_fence ** fence)1017b843c749SSergey Zigachev static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo,
1018b843c749SSergey Zigachev 			       bool direct, struct dma_fence **fence)
1019b843c749SSergey Zigachev {
1020b843c749SSergey Zigachev 	struct amdgpu_device *adev = ring->adev;
1021b843c749SSergey Zigachev 	struct dma_fence *f = NULL;
1022b843c749SSergey Zigachev 	struct amdgpu_job *job;
1023b843c749SSergey Zigachev 	struct amdgpu_ib *ib;
1024b843c749SSergey Zigachev 	uint32_t data[4];
1025b843c749SSergey Zigachev 	uint64_t addr;
1026b843c749SSergey Zigachev 	long r;
1027b843c749SSergey Zigachev 	int i;
1028b843c749SSergey Zigachev 	unsigned offset_idx = 0;
1029b843c749SSergey Zigachev 	unsigned offset[3] = { UVD_BASE_SI, 0, 0 };
1030b843c749SSergey Zigachev 
1031b843c749SSergey Zigachev 	amdgpu_bo_kunmap(bo);
1032b843c749SSergey Zigachev 	amdgpu_bo_unpin(bo);
1033b843c749SSergey Zigachev 
1034b843c749SSergey Zigachev 	if (!ring->adev->uvd.address_64_bit) {
1035b843c749SSergey Zigachev 		struct ttm_operation_ctx ctx = { true, false };
1036b843c749SSergey Zigachev 
1037b843c749SSergey Zigachev 		amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_VRAM);
1038b843c749SSergey Zigachev 		amdgpu_uvd_force_into_uvd_segment(bo);
1039b843c749SSergey Zigachev 		r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
1040b843c749SSergey Zigachev 		if (r)
1041b843c749SSergey Zigachev 			goto err;
1042b843c749SSergey Zigachev 	}
1043b843c749SSergey Zigachev 
1044b843c749SSergey Zigachev 	r = amdgpu_job_alloc_with_ib(adev, 64, &job);
1045b843c749SSergey Zigachev 	if (r)
1046b843c749SSergey Zigachev 		goto err;
1047b843c749SSergey Zigachev 
1048b843c749SSergey Zigachev 	if (adev->asic_type >= CHIP_VEGA10) {
1049b843c749SSergey Zigachev 		offset_idx = 1 + ring->me;
1050b843c749SSergey Zigachev 		offset[1] = adev->reg_offset[UVD_HWIP][0][1];
1051b843c749SSergey Zigachev 		offset[2] = adev->reg_offset[UVD_HWIP][1][1];
1052b843c749SSergey Zigachev 	}
1053b843c749SSergey Zigachev 
1054b843c749SSergey Zigachev 	data[0] = PACKET0(offset[offset_idx] + UVD_GPCOM_VCPU_DATA0, 0);
1055b843c749SSergey Zigachev 	data[1] = PACKET0(offset[offset_idx] + UVD_GPCOM_VCPU_DATA1, 0);
1056b843c749SSergey Zigachev 	data[2] = PACKET0(offset[offset_idx] + UVD_GPCOM_VCPU_CMD, 0);
1057b843c749SSergey Zigachev 	data[3] = PACKET0(offset[offset_idx] + UVD_NO_OP, 0);
1058b843c749SSergey Zigachev 
1059b843c749SSergey Zigachev 	ib = &job->ibs[0];
1060b843c749SSergey Zigachev 	addr = amdgpu_bo_gpu_offset(bo);
1061b843c749SSergey Zigachev 	ib->ptr[0] = data[0];
1062b843c749SSergey Zigachev 	ib->ptr[1] = addr;
1063b843c749SSergey Zigachev 	ib->ptr[2] = data[1];
1064b843c749SSergey Zigachev 	ib->ptr[3] = addr >> 32;
1065b843c749SSergey Zigachev 	ib->ptr[4] = data[2];
1066b843c749SSergey Zigachev 	ib->ptr[5] = 0;
1067b843c749SSergey Zigachev 	for (i = 6; i < 16; i += 2) {
1068b843c749SSergey Zigachev 		ib->ptr[i] = data[3];
1069b843c749SSergey Zigachev 		ib->ptr[i+1] = 0;
1070b843c749SSergey Zigachev 	}
1071b843c749SSergey Zigachev 	ib->length_dw = 16;
1072b843c749SSergey Zigachev 
1073b843c749SSergey Zigachev 	if (direct) {
1074b843c749SSergey Zigachev 		r = reservation_object_wait_timeout_rcu(bo->tbo.resv,
1075b843c749SSergey Zigachev 							true, false,
1076b843c749SSergey Zigachev 							msecs_to_jiffies(10));
1077b843c749SSergey Zigachev 		if (r == 0)
1078b843c749SSergey Zigachev 			r = -ETIMEDOUT;
1079b843c749SSergey Zigachev 		if (r < 0)
1080b843c749SSergey Zigachev 			goto err_free;
1081b843c749SSergey Zigachev 
1082b843c749SSergey Zigachev 		r = amdgpu_job_submit_direct(job, ring, &f);
1083b843c749SSergey Zigachev 		if (r)
1084b843c749SSergey Zigachev 			goto err_free;
1085b843c749SSergey Zigachev 	} else {
1086b843c749SSergey Zigachev 		r = amdgpu_sync_resv(adev, &job->sync, bo->tbo.resv,
1087b843c749SSergey Zigachev 				     AMDGPU_FENCE_OWNER_UNDEFINED, false);
1088b843c749SSergey Zigachev 		if (r)
1089b843c749SSergey Zigachev 			goto err_free;
1090b843c749SSergey Zigachev 
1091b843c749SSergey Zigachev 		r = amdgpu_job_submit(job, &adev->uvd.entity,
1092b843c749SSergey Zigachev 				      AMDGPU_FENCE_OWNER_UNDEFINED, &f);
1093b843c749SSergey Zigachev 		if (r)
1094b843c749SSergey Zigachev 			goto err_free;
1095b843c749SSergey Zigachev 	}
1096b843c749SSergey Zigachev 
1097b843c749SSergey Zigachev 	amdgpu_bo_fence(bo, f, false);
1098b843c749SSergey Zigachev 	amdgpu_bo_unreserve(bo);
1099b843c749SSergey Zigachev 	amdgpu_bo_unref(&bo);
1100b843c749SSergey Zigachev 
1101b843c749SSergey Zigachev 	if (fence)
1102b843c749SSergey Zigachev 		*fence = dma_fence_get(f);
1103b843c749SSergey Zigachev 	dma_fence_put(f);
1104b843c749SSergey Zigachev 
1105b843c749SSergey Zigachev 	return 0;
1106b843c749SSergey Zigachev 
1107b843c749SSergey Zigachev err_free:
1108b843c749SSergey Zigachev 	amdgpu_job_free(job);
1109b843c749SSergey Zigachev 
1110b843c749SSergey Zigachev err:
1111b843c749SSergey Zigachev 	amdgpu_bo_unreserve(bo);
1112b843c749SSergey Zigachev 	amdgpu_bo_unref(&bo);
1113b843c749SSergey Zigachev 	return r;
1114b843c749SSergey Zigachev }
1115b843c749SSergey Zigachev 
1116b843c749SSergey Zigachev /* multiple fence commands without any stream commands in between can
1117b843c749SSergey Zigachev    crash the vcpu so just try to emmit a dummy create/destroy msg to
1118b843c749SSergey Zigachev    avoid this */
amdgpu_uvd_get_create_msg(struct amdgpu_ring * ring,uint32_t handle,struct dma_fence ** fence)1119b843c749SSergey Zigachev int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
1120b843c749SSergey Zigachev 			      struct dma_fence **fence)
1121b843c749SSergey Zigachev {
1122b843c749SSergey Zigachev 	struct amdgpu_device *adev = ring->adev;
1123b843c749SSergey Zigachev 	struct amdgpu_bo *bo = NULL;
1124b843c749SSergey Zigachev 	uint32_t *msg;
1125b843c749SSergey Zigachev 	int r, i;
1126b843c749SSergey Zigachev 
1127b843c749SSergey Zigachev 	r = amdgpu_bo_create_reserved(adev, 1024, PAGE_SIZE,
1128b843c749SSergey Zigachev 				      AMDGPU_GEM_DOMAIN_VRAM,
1129b843c749SSergey Zigachev 				      &bo, NULL, (void **)&msg);
1130b843c749SSergey Zigachev 	if (r)
1131b843c749SSergey Zigachev 		return r;
1132b843c749SSergey Zigachev 
1133b843c749SSergey Zigachev 	/* stitch together an UVD create msg */
1134b843c749SSergey Zigachev 	msg[0] = cpu_to_le32(0x00000de4);
1135b843c749SSergey Zigachev 	msg[1] = cpu_to_le32(0x00000000);
1136b843c749SSergey Zigachev 	msg[2] = cpu_to_le32(handle);
1137b843c749SSergey Zigachev 	msg[3] = cpu_to_le32(0x00000000);
1138b843c749SSergey Zigachev 	msg[4] = cpu_to_le32(0x00000000);
1139b843c749SSergey Zigachev 	msg[5] = cpu_to_le32(0x00000000);
1140b843c749SSergey Zigachev 	msg[6] = cpu_to_le32(0x00000000);
1141b843c749SSergey Zigachev 	msg[7] = cpu_to_le32(0x00000780);
1142b843c749SSergey Zigachev 	msg[8] = cpu_to_le32(0x00000440);
1143b843c749SSergey Zigachev 	msg[9] = cpu_to_le32(0x00000000);
1144b843c749SSergey Zigachev 	msg[10] = cpu_to_le32(0x01b37000);
1145b843c749SSergey Zigachev 	for (i = 11; i < 1024; ++i)
1146b843c749SSergey Zigachev 		msg[i] = cpu_to_le32(0x0);
1147b843c749SSergey Zigachev 
1148b843c749SSergey Zigachev 	return amdgpu_uvd_send_msg(ring, bo, true, fence);
1149b843c749SSergey Zigachev }
1150b843c749SSergey Zigachev 
amdgpu_uvd_get_destroy_msg(struct amdgpu_ring * ring,uint32_t handle,bool direct,struct dma_fence ** fence)1151b843c749SSergey Zigachev int amdgpu_uvd_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
1152b843c749SSergey Zigachev 			       bool direct, struct dma_fence **fence)
1153b843c749SSergey Zigachev {
1154b843c749SSergey Zigachev 	struct amdgpu_device *adev = ring->adev;
1155b843c749SSergey Zigachev 	struct amdgpu_bo *bo = NULL;
1156b843c749SSergey Zigachev 	uint32_t *msg;
1157b843c749SSergey Zigachev 	int r, i;
1158b843c749SSergey Zigachev 
1159b843c749SSergey Zigachev 	r = amdgpu_bo_create_reserved(adev, 1024, PAGE_SIZE,
1160b843c749SSergey Zigachev 				      AMDGPU_GEM_DOMAIN_VRAM,
1161b843c749SSergey Zigachev 				      &bo, NULL, (void **)&msg);
1162b843c749SSergey Zigachev 	if (r)
1163b843c749SSergey Zigachev 		return r;
1164b843c749SSergey Zigachev 
1165b843c749SSergey Zigachev 	/* stitch together an UVD destroy msg */
1166b843c749SSergey Zigachev 	msg[0] = cpu_to_le32(0x00000de4);
1167b843c749SSergey Zigachev 	msg[1] = cpu_to_le32(0x00000002);
1168b843c749SSergey Zigachev 	msg[2] = cpu_to_le32(handle);
1169b843c749SSergey Zigachev 	msg[3] = cpu_to_le32(0x00000000);
1170b843c749SSergey Zigachev 	for (i = 4; i < 1024; ++i)
1171b843c749SSergey Zigachev 		msg[i] = cpu_to_le32(0x0);
1172b843c749SSergey Zigachev 
1173b843c749SSergey Zigachev 	return amdgpu_uvd_send_msg(ring, bo, direct, fence);
1174b843c749SSergey Zigachev }
1175b843c749SSergey Zigachev 
amdgpu_uvd_idle_work_handler(struct work_struct * work)1176b843c749SSergey Zigachev static void amdgpu_uvd_idle_work_handler(struct work_struct *work)
1177b843c749SSergey Zigachev {
1178b843c749SSergey Zigachev 	struct amdgpu_device *adev =
1179b843c749SSergey Zigachev 		container_of(work, struct amdgpu_device, uvd.idle_work.work);
1180b843c749SSergey Zigachev 	unsigned fences = 0, i, j;
1181b843c749SSergey Zigachev 
1182b843c749SSergey Zigachev 	for (i = 0; i < adev->uvd.num_uvd_inst; ++i) {
1183b843c749SSergey Zigachev 		if (adev->uvd.harvest_config & (1 << i))
1184b843c749SSergey Zigachev 			continue;
1185b843c749SSergey Zigachev 		fences += amdgpu_fence_count_emitted(&adev->uvd.inst[i].ring);
1186b843c749SSergey Zigachev 		for (j = 0; j < adev->uvd.num_enc_rings; ++j) {
1187b843c749SSergey Zigachev 			fences += amdgpu_fence_count_emitted(&adev->uvd.inst[i].ring_enc[j]);
1188b843c749SSergey Zigachev 		}
1189b843c749SSergey Zigachev 	}
1190b843c749SSergey Zigachev 
1191b843c749SSergey Zigachev 	if (fences == 0) {
1192b843c749SSergey Zigachev 		if (adev->pm.dpm_enabled) {
1193b843c749SSergey Zigachev 			amdgpu_dpm_enable_uvd(adev, false);
1194b843c749SSergey Zigachev 		} else {
1195b843c749SSergey Zigachev 			amdgpu_asic_set_uvd_clocks(adev, 0, 0);
1196b843c749SSergey Zigachev 			/* shutdown the UVD block */
1197b843c749SSergey Zigachev 			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
1198b843c749SSergey Zigachev 							       AMD_PG_STATE_GATE);
1199b843c749SSergey Zigachev 			amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
1200b843c749SSergey Zigachev 							       AMD_CG_STATE_GATE);
1201b843c749SSergey Zigachev 		}
1202b843c749SSergey Zigachev 	} else {
1203b843c749SSergey Zigachev 		schedule_delayed_work(&adev->uvd.idle_work, UVD_IDLE_TIMEOUT);
1204b843c749SSergey Zigachev 	}
1205b843c749SSergey Zigachev }
1206b843c749SSergey Zigachev 
amdgpu_uvd_ring_begin_use(struct amdgpu_ring * ring)1207b843c749SSergey Zigachev void amdgpu_uvd_ring_begin_use(struct amdgpu_ring *ring)
1208b843c749SSergey Zigachev {
1209b843c749SSergey Zigachev 	struct amdgpu_device *adev = ring->adev;
1210b843c749SSergey Zigachev 	bool set_clocks;
1211b843c749SSergey Zigachev 
1212b843c749SSergey Zigachev 	if (amdgpu_sriov_vf(adev))
1213b843c749SSergey Zigachev 		return;
1214b843c749SSergey Zigachev 
1215b843c749SSergey Zigachev 	set_clocks = !cancel_delayed_work_sync(&adev->uvd.idle_work);
1216b843c749SSergey Zigachev 	if (set_clocks) {
1217b843c749SSergey Zigachev 		if (adev->pm.dpm_enabled) {
1218b843c749SSergey Zigachev 			amdgpu_dpm_enable_uvd(adev, true);
1219b843c749SSergey Zigachev 		} else {
1220b843c749SSergey Zigachev 			amdgpu_asic_set_uvd_clocks(adev, 53300, 40000);
1221b843c749SSergey Zigachev 			amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
1222b843c749SSergey Zigachev 							       AMD_CG_STATE_UNGATE);
1223b843c749SSergey Zigachev 			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
1224b843c749SSergey Zigachev 							       AMD_PG_STATE_UNGATE);
1225b843c749SSergey Zigachev 		}
1226b843c749SSergey Zigachev 	}
1227b843c749SSergey Zigachev }
1228b843c749SSergey Zigachev 
amdgpu_uvd_ring_end_use(struct amdgpu_ring * ring)1229b843c749SSergey Zigachev void amdgpu_uvd_ring_end_use(struct amdgpu_ring *ring)
1230b843c749SSergey Zigachev {
1231b843c749SSergey Zigachev 	if (!amdgpu_sriov_vf(ring->adev))
1232b843c749SSergey Zigachev 		schedule_delayed_work(&ring->adev->uvd.idle_work, UVD_IDLE_TIMEOUT);
1233b843c749SSergey Zigachev }
1234b843c749SSergey Zigachev 
1235b843c749SSergey Zigachev /**
1236b843c749SSergey Zigachev  * amdgpu_uvd_ring_test_ib - test ib execution
1237b843c749SSergey Zigachev  *
1238b843c749SSergey Zigachev  * @ring: amdgpu_ring pointer
1239b843c749SSergey Zigachev  *
1240b843c749SSergey Zigachev  * Test if we can successfully execute an IB
1241b843c749SSergey Zigachev  */
amdgpu_uvd_ring_test_ib(struct amdgpu_ring * ring,long timeout)1242b843c749SSergey Zigachev int amdgpu_uvd_ring_test_ib(struct amdgpu_ring *ring, long timeout)
1243b843c749SSergey Zigachev {
1244b843c749SSergey Zigachev 	struct dma_fence *fence;
1245b843c749SSergey Zigachev 	long r;
1246b843c749SSergey Zigachev 	uint32_t ip_instance = ring->me;
1247b843c749SSergey Zigachev 
1248b843c749SSergey Zigachev 	r = amdgpu_uvd_get_create_msg(ring, 1, NULL);
1249b843c749SSergey Zigachev 	if (r) {
1250b843c749SSergey Zigachev 		DRM_ERROR("amdgpu: (%d)failed to get create msg (%ld).\n", ip_instance, r);
1251b843c749SSergey Zigachev 		goto error;
1252b843c749SSergey Zigachev 	}
1253b843c749SSergey Zigachev 
1254b843c749SSergey Zigachev 	r = amdgpu_uvd_get_destroy_msg(ring, 1, true, &fence);
1255b843c749SSergey Zigachev 	if (r) {
1256b843c749SSergey Zigachev 		DRM_ERROR("amdgpu: (%d)failed to get destroy ib (%ld).\n", ip_instance, r);
1257b843c749SSergey Zigachev 		goto error;
1258b843c749SSergey Zigachev 	}
1259b843c749SSergey Zigachev 
1260b843c749SSergey Zigachev 	r = dma_fence_wait_timeout(fence, false, timeout);
1261b843c749SSergey Zigachev 	if (r == 0) {
1262b843c749SSergey Zigachev 		DRM_ERROR("amdgpu: (%d)IB test timed out.\n", ip_instance);
1263b843c749SSergey Zigachev 		r = -ETIMEDOUT;
1264b843c749SSergey Zigachev 	} else if (r < 0) {
1265b843c749SSergey Zigachev 		DRM_ERROR("amdgpu: (%d)fence wait failed (%ld).\n", ip_instance, r);
1266b843c749SSergey Zigachev 	} else {
1267b843c749SSergey Zigachev 		DRM_DEBUG("ib test on (%d)ring %d succeeded\n", ip_instance, ring->idx);
1268b843c749SSergey Zigachev 		r = 0;
1269b843c749SSergey Zigachev 	}
1270b843c749SSergey Zigachev 
1271b843c749SSergey Zigachev 	dma_fence_put(fence);
1272b843c749SSergey Zigachev 
1273b843c749SSergey Zigachev error:
1274b843c749SSergey Zigachev 	return r;
1275b843c749SSergey Zigachev }
1276b843c749SSergey Zigachev 
1277b843c749SSergey Zigachev /**
1278b843c749SSergey Zigachev  * amdgpu_uvd_used_handles - returns used UVD handles
1279b843c749SSergey Zigachev  *
1280b843c749SSergey Zigachev  * @adev: amdgpu_device pointer
1281b843c749SSergey Zigachev  *
1282b843c749SSergey Zigachev  * Returns the number of UVD handles in use
1283b843c749SSergey Zigachev  */
amdgpu_uvd_used_handles(struct amdgpu_device * adev)1284b843c749SSergey Zigachev uint32_t amdgpu_uvd_used_handles(struct amdgpu_device *adev)
1285b843c749SSergey Zigachev {
1286b843c749SSergey Zigachev 	unsigned i;
1287b843c749SSergey Zigachev 	uint32_t used_handles = 0;
1288b843c749SSergey Zigachev 
1289b843c749SSergey Zigachev 	for (i = 0; i < adev->uvd.max_handles; ++i) {
1290b843c749SSergey Zigachev 		/*
1291b843c749SSergey Zigachev 		 * Handles can be freed in any order, and not
1292b843c749SSergey Zigachev 		 * necessarily linear. So we need to count
1293b843c749SSergey Zigachev 		 * all non-zero handles.
1294b843c749SSergey Zigachev 		 */
1295b843c749SSergey Zigachev 		if (atomic_read(&adev->uvd.handles[i]))
1296b843c749SSergey Zigachev 			used_handles++;
1297b843c749SSergey Zigachev 	}
1298b843c749SSergey Zigachev 
1299b843c749SSergey Zigachev 	return used_handles;
1300b843c749SSergey Zigachev }
1301