1/*
2 * Copyright 2014 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22*/
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include <stdio.h>
29
30#include "CUnit/Basic.h"
31
32#include "util_math.h"
33
34#include "amdgpu_test.h"
35#include "uvd_messages.h"
36#include "amdgpu_drm.h"
37#include "amdgpu_internal.h"
38
39#define IB_SIZE		4096
40#define MAX_RESOURCES	16
41
42static amdgpu_device_handle device_handle;
43static uint32_t major_version;
44static uint32_t minor_version;
45static uint32_t family_id;
46
47static amdgpu_context_handle context_handle;
48static amdgpu_bo_handle ib_handle;
49static uint64_t ib_mc_address;
50static uint32_t *ib_cpu;
51static amdgpu_va_handle ib_va_handle;
52
53static amdgpu_bo_handle resources[MAX_RESOURCES];
54static unsigned num_resources;
55
56static void amdgpu_cs_uvd_create(void);
57static void amdgpu_cs_uvd_decode(void);
58static void amdgpu_cs_uvd_destroy(void);
59
60CU_TestInfo cs_tests[] = {
61	{ "UVD create",  amdgpu_cs_uvd_create },
62	{ "UVD decode",  amdgpu_cs_uvd_decode },
63	{ "UVD destroy",  amdgpu_cs_uvd_destroy },
64	CU_TEST_INFO_NULL,
65};
66
67int suite_cs_tests_init(void)
68{
69	amdgpu_bo_handle ib_result_handle;
70	void *ib_result_cpu;
71	uint64_t ib_result_mc_address;
72	amdgpu_va_handle ib_result_va_handle;
73	int r;
74
75	r = amdgpu_device_initialize(drm_amdgpu[0], &major_version,
76				     &minor_version, &device_handle);
77	if (r)
78		return CUE_SINIT_FAILED;
79
80	family_id = device_handle->info.family_id;
81
82	r = amdgpu_cs_ctx_create(device_handle, &context_handle);
83	if (r)
84		return CUE_SINIT_FAILED;
85
86	r = amdgpu_bo_alloc_and_map(device_handle, IB_SIZE, 4096,
87				    AMDGPU_GEM_DOMAIN_GTT, 0,
88				    &ib_result_handle, &ib_result_cpu,
89				    &ib_result_mc_address,
90				    &ib_result_va_handle);
91	if (r)
92		return CUE_SINIT_FAILED;
93
94	ib_handle = ib_result_handle;
95	ib_mc_address = ib_result_mc_address;
96	ib_cpu = ib_result_cpu;
97	ib_va_handle = ib_result_va_handle;
98
99	return CUE_SUCCESS;
100}
101
102int suite_cs_tests_clean(void)
103{
104	int r;
105
106	r = amdgpu_bo_unmap_and_free(ib_handle, ib_va_handle,
107				     ib_mc_address, IB_SIZE);
108	if (r)
109		return CUE_SCLEAN_FAILED;
110
111	r = amdgpu_cs_ctx_free(context_handle);
112	if (r)
113		return CUE_SCLEAN_FAILED;
114
115	r = amdgpu_device_deinitialize(device_handle);
116	if (r)
117		return CUE_SCLEAN_FAILED;
118
119	return CUE_SUCCESS;
120}
121
122static int submit(unsigned ndw, unsigned ip)
123{
124	struct amdgpu_cs_request ibs_request = {0};
125	struct amdgpu_cs_ib_info ib_info = {0};
126	struct amdgpu_cs_fence fence_status = {0};
127	uint32_t expired;
128	int r;
129
130	ib_info.ib_mc_address = ib_mc_address;
131	ib_info.size = ndw;
132
133	ibs_request.ip_type = ip;
134
135	r = amdgpu_bo_list_create(device_handle, num_resources, resources,
136				  NULL, &ibs_request.resources);
137	if (r)
138		return r;
139
140	ibs_request.number_of_ibs = 1;
141	ibs_request.ibs = &ib_info;
142	ibs_request.fence_info.handle = NULL;
143
144	r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1);
145	if (r)
146		return r;
147
148	r = amdgpu_bo_list_destroy(ibs_request.resources);
149	if (r)
150		return r;
151
152	fence_status.context = context_handle;
153	fence_status.ip_type = ip;
154	fence_status.fence = ibs_request.seq_no;
155
156	r = amdgpu_cs_query_fence_status(&fence_status,
157					 AMDGPU_TIMEOUT_INFINITE,
158					 0, &expired);
159	if (r)
160		return r;
161
162	return 0;
163}
164
165static void uvd_cmd(uint64_t addr, unsigned cmd, int *idx)
166{
167	ib_cpu[(*idx)++] = 0x3BC4;
168	ib_cpu[(*idx)++] = addr;
169	ib_cpu[(*idx)++] = 0x3BC5;
170	ib_cpu[(*idx)++] = addr >> 32;
171	ib_cpu[(*idx)++] = 0x3BC3;
172	ib_cpu[(*idx)++] = cmd << 1;
173}
174
175static void amdgpu_cs_uvd_create(void)
176{
177	struct amdgpu_bo_alloc_request req = {0};
178	amdgpu_bo_handle buf_handle;
179	uint64_t va = 0;
180	amdgpu_va_handle va_handle;
181	void *msg;
182	int i, r;
183
184	req.alloc_size = 4*1024;
185	req.preferred_heap = AMDGPU_GEM_DOMAIN_GTT;
186
187	r = amdgpu_bo_alloc(device_handle, &req, &buf_handle);
188	CU_ASSERT_EQUAL(r, 0);
189
190	r = amdgpu_va_range_alloc(device_handle,
191				  amdgpu_gpu_va_range_general,
192				  4096, 1, 0, &va,
193				  &va_handle, 0);
194	CU_ASSERT_EQUAL(r, 0);
195
196	r = amdgpu_bo_va_op(buf_handle, 0, 4096, va, 0, AMDGPU_VA_OP_MAP);
197	CU_ASSERT_EQUAL(r, 0);
198
199	r = amdgpu_bo_cpu_map(buf_handle, &msg);
200	CU_ASSERT_EQUAL(r, 0);
201
202	memcpy(msg, uvd_create_msg, sizeof(uvd_create_msg));
203	if (family_id >= AMDGPU_FAMILY_VI)
204		((uint8_t*)msg)[0x10] = 7;
205
206	r = amdgpu_bo_cpu_unmap(buf_handle);
207	CU_ASSERT_EQUAL(r, 0);
208
209	num_resources = 0;
210	resources[num_resources++] = buf_handle;
211	resources[num_resources++] = ib_handle;
212
213	i = 0;
214	uvd_cmd(va, 0x0, &i);
215	for (; i % 16; ++i)
216		ib_cpu[i] = 0x80000000;
217
218	r = submit(i, AMDGPU_HW_IP_UVD);
219	CU_ASSERT_EQUAL(r, 0);
220
221	r = amdgpu_bo_va_op(buf_handle, 0, 4096, va, 0, AMDGPU_VA_OP_UNMAP);
222	CU_ASSERT_EQUAL(r, 0);
223
224	r = amdgpu_va_range_free(va_handle);
225	CU_ASSERT_EQUAL(r, 0);
226
227	r = amdgpu_bo_free(buf_handle);
228	CU_ASSERT_EQUAL(r, 0);
229}
230
231static void amdgpu_cs_uvd_decode(void)
232{
233	const unsigned dpb_size = 15923584, dt_size = 737280;
234	uint64_t msg_addr, fb_addr, bs_addr, dpb_addr, dt_addr, it_addr;
235	struct amdgpu_bo_alloc_request req = {0};
236	amdgpu_bo_handle buf_handle;
237	amdgpu_va_handle va_handle;
238	uint64_t va = 0;
239	uint64_t sum;
240	uint8_t *ptr;
241	int i, r;
242
243	req.alloc_size = 4*1024; /* msg */
244	req.alloc_size += 4*1024; /* fb */
245	if (family_id >= AMDGPU_FAMILY_VI)
246		req.alloc_size += 4096; /*it_scaling_table*/
247	req.alloc_size += ALIGN(sizeof(uvd_bitstream), 4*1024);
248	req.alloc_size += ALIGN(dpb_size, 4*1024);
249	req.alloc_size += ALIGN(dt_size, 4*1024);
250
251	req.preferred_heap = AMDGPU_GEM_DOMAIN_GTT;
252
253	r = amdgpu_bo_alloc(device_handle, &req, &buf_handle);
254	CU_ASSERT_EQUAL(r, 0);
255
256	r = amdgpu_va_range_alloc(device_handle,
257				  amdgpu_gpu_va_range_general,
258				  req.alloc_size, 1, 0, &va,
259				  &va_handle, 0);
260	CU_ASSERT_EQUAL(r, 0);
261
262	r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0,
263			    AMDGPU_VA_OP_MAP);
264	CU_ASSERT_EQUAL(r, 0);
265
266	r = amdgpu_bo_cpu_map(buf_handle, (void **)&ptr);
267	CU_ASSERT_EQUAL(r, 0);
268
269	memcpy(ptr, uvd_decode_msg, sizeof(uvd_decode_msg));
270	if (family_id >= AMDGPU_FAMILY_VI)
271		ptr[0x10] = 7;
272
273	ptr += 4*1024;
274	memset(ptr, 0, 4*1024);
275	if (family_id >= AMDGPU_FAMILY_VI) {
276		ptr += 4*1024;
277		memcpy(ptr, uvd_it_scaling_table, sizeof(uvd_it_scaling_table));
278	}
279
280	ptr += 4*1024;
281	memcpy(ptr, uvd_bitstream, sizeof(uvd_bitstream));
282
283	ptr += ALIGN(sizeof(uvd_bitstream), 4*1024);
284	memset(ptr, 0, dpb_size);
285
286	ptr += ALIGN(dpb_size, 4*1024);
287	memset(ptr, 0, dt_size);
288
289	num_resources = 0;
290	resources[num_resources++] = buf_handle;
291	resources[num_resources++] = ib_handle;
292
293	msg_addr = va;
294	fb_addr = msg_addr + 4*1024;
295	if (family_id >= AMDGPU_FAMILY_VI) {
296		it_addr = fb_addr + 4*1024;
297		bs_addr = it_addr + 4*1024;
298	} else
299		bs_addr = fb_addr + 4*1024;
300	dpb_addr = ALIGN(bs_addr + sizeof(uvd_bitstream), 4*1024);
301	dt_addr = ALIGN(dpb_addr + dpb_size, 4*1024);
302
303	i = 0;
304	uvd_cmd(msg_addr, 0x0, &i);
305	uvd_cmd(dpb_addr, 0x1, &i);
306	uvd_cmd(dt_addr, 0x2, &i);
307	uvd_cmd(fb_addr, 0x3, &i);
308	uvd_cmd(bs_addr, 0x100, &i);
309	if (family_id >= AMDGPU_FAMILY_VI)
310		uvd_cmd(it_addr, 0x204, &i);
311	ib_cpu[i++] = 0x3BC6;
312	ib_cpu[i++] = 0x1;
313	for (; i % 16; ++i)
314		ib_cpu[i] = 0x80000000;
315
316	r = submit(i, AMDGPU_HW_IP_UVD);
317	CU_ASSERT_EQUAL(r, 0);
318
319	/* TODO: use a real CRC32 */
320	for (i = 0, sum = 0; i < dt_size; ++i)
321		sum += ptr[i];
322	CU_ASSERT_EQUAL(sum, 0x20345d8);
323
324	r = amdgpu_bo_cpu_unmap(buf_handle);
325	CU_ASSERT_EQUAL(r, 0);
326
327	r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0, AMDGPU_VA_OP_UNMAP);
328	CU_ASSERT_EQUAL(r, 0);
329
330	r = amdgpu_va_range_free(va_handle);
331	CU_ASSERT_EQUAL(r, 0);
332
333	r = amdgpu_bo_free(buf_handle);
334	CU_ASSERT_EQUAL(r, 0);
335}
336
337static void amdgpu_cs_uvd_destroy(void)
338{
339	struct amdgpu_bo_alloc_request req = {0};
340	amdgpu_bo_handle buf_handle;
341	amdgpu_va_handle va_handle;
342	uint64_t va = 0;
343	void *msg;
344	int i, r;
345
346	req.alloc_size = 4*1024;
347	req.preferred_heap = AMDGPU_GEM_DOMAIN_GTT;
348
349	r = amdgpu_bo_alloc(device_handle, &req, &buf_handle);
350	CU_ASSERT_EQUAL(r, 0);
351
352	r = amdgpu_va_range_alloc(device_handle,
353				  amdgpu_gpu_va_range_general,
354				  req.alloc_size, 1, 0, &va,
355				  &va_handle, 0);
356	CU_ASSERT_EQUAL(r, 0);
357
358	r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0,
359			    AMDGPU_VA_OP_MAP);
360	CU_ASSERT_EQUAL(r, 0);
361
362	r = amdgpu_bo_cpu_map(buf_handle, &msg);
363	CU_ASSERT_EQUAL(r, 0);
364
365	memcpy(msg, uvd_destroy_msg, sizeof(uvd_destroy_msg));
366	if (family_id >= AMDGPU_FAMILY_VI)
367		((uint8_t*)msg)[0x10] = 7;
368
369	r = amdgpu_bo_cpu_unmap(buf_handle);
370	CU_ASSERT_EQUAL(r, 0);
371
372	num_resources = 0;
373	resources[num_resources++] = buf_handle;
374	resources[num_resources++] = ib_handle;
375
376	i = 0;
377	uvd_cmd(va, 0x0, &i);
378	for (; i % 16; ++i)
379		ib_cpu[i] = 0x80000000;
380
381	r = submit(i, AMDGPU_HW_IP_UVD);
382	CU_ASSERT_EQUAL(r, 0);
383
384	r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0, AMDGPU_VA_OP_UNMAP);
385	CU_ASSERT_EQUAL(r, 0);
386
387	r = amdgpu_va_range_free(va_handle);
388	CU_ASSERT_EQUAL(r, 0);
389
390	r = amdgpu_bo_free(buf_handle);
391	CU_ASSERT_EQUAL(r, 0);
392}
393