1 /*
2  * Copyright © 2016 Broadcom
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 (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include <assert.h>
25 #include <string.h>
26 #include <signal.h>
27 #include <errno.h>
28 #include <sys/mman.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/ioctl.h>
32 #include <fcntl.h>
33 
34 #include "drmtest.h"
35 #include "igt_aux.h"
36 #include "igt_core.h"
37 #include "igt_fb.h"
38 #include "igt_vc4.h"
39 #include "ioctl_wrappers.h"
40 #include "intel_reg.h"
41 #include "intel_chipset.h"
42 #include "vc4_drm.h"
43 #include "vc4_packet.h"
44 
45 #if NEW_CONTEXT_PARAM_NO_ERROR_CAPTURE_API
46 #define LOCAL_CONTEXT_PARAM_NO_ERROR_CAPTURE 0x4
47 #endif
48 
49 /**
50  * SECTION:igt_vc4
51  * @short_description: VC4 support library
52  * @title: VC4
53  * @include: igt.h
54  *
55  * This library provides various auxiliary helper functions for writing VC4
56  * tests.
57  */
58 
igt_vc4_is_tiled(uint64_t modifier)59 bool igt_vc4_is_tiled(uint64_t modifier)
60 {
61 	if (modifier >> 56ULL != DRM_FORMAT_MOD_VENDOR_BROADCOM)
62 		return false;
63 
64 	switch (fourcc_mod_broadcom_mod(modifier)) {
65 	case DRM_FORMAT_MOD_BROADCOM_SAND32:
66 	case DRM_FORMAT_MOD_BROADCOM_SAND64:
67 	case DRM_FORMAT_MOD_BROADCOM_SAND128:
68 	case DRM_FORMAT_MOD_BROADCOM_SAND256:
69 	case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
70 		return true;
71 	default:
72 		return false;
73 	}
74 }
75 
76 /**
77  * igt_vc4_get_cleared_bo:
78  * @fd: device file descriptor
79  * @size: size of the BO in bytes
80  * @clearval: u32 value that the buffer should be completely cleared with
81  *
82  * This helper returns a new BO with the given size, which has just been
83  * cleared using the render engine.
84  */
igt_vc4_get_cleared_bo(int fd,size_t size,uint32_t clearval)85 uint32_t igt_vc4_get_cleared_bo(int fd, size_t size, uint32_t clearval)
86 {
87 	/* A single row will be a page. */
88 	uint32_t width = 1024;
89 	uint32_t height = size / (width * 4);
90 	uint32_t handle = igt_vc4_create_bo(fd, size);
91 	struct drm_vc4_submit_cl submit = {
92 		.color_write = {
93 			.hindex = 0,
94 			.bits = VC4_SET_FIELD(VC4_RENDER_CONFIG_FORMAT_RGBA8888,
95 					      VC4_RENDER_CONFIG_FORMAT),
96 		},
97 
98 		.color_read = { .hindex = ~0 },
99 		.zs_read = { .hindex = ~0 },
100 		.zs_write = { .hindex = ~0 },
101 		.msaa_color_write = { .hindex = ~0 },
102 		.msaa_zs_write = { .hindex = ~0 },
103 
104 		.bo_handles = to_user_pointer(&handle),
105 		.bo_handle_count = 1,
106 		.width = width,
107 		.height = height,
108 		.max_x_tile = ALIGN(width, 64) / 64 - 1,
109 		.max_y_tile = ALIGN(height, 64) / 64 - 1,
110 		.clear_color = { clearval, clearval },
111 		.flags = VC4_SUBMIT_CL_USE_CLEAR_COLOR,
112 	};
113 
114 	igt_assert_eq_u32(width * height * 4, size);
115 
116 	do_ioctl(fd, DRM_IOCTL_VC4_SUBMIT_CL, &submit);
117 
118 	return handle;
119 }
120 
121 int
igt_vc4_create_bo(int fd,size_t size)122 igt_vc4_create_bo(int fd, size_t size)
123 {
124 	struct drm_vc4_create_bo create = {
125 		.size = size,
126 	};
127 
128 	do_ioctl(fd, DRM_IOCTL_VC4_CREATE_BO, &create);
129 
130 	return create.handle;
131 }
132 
133 void *
igt_vc4_mmap_bo(int fd,uint32_t handle,uint32_t size,unsigned prot)134 igt_vc4_mmap_bo(int fd, uint32_t handle, uint32_t size, unsigned prot)
135 {
136 	struct drm_vc4_mmap_bo mmap_bo = {
137 		.handle = handle,
138 	};
139 	void *ptr;
140 
141 	do_ioctl(fd, DRM_IOCTL_VC4_MMAP_BO, &mmap_bo);
142 
143 	ptr = mmap(0, size, prot, MAP_SHARED, fd, mmap_bo.offset);
144 	if (ptr == MAP_FAILED)
145 		return NULL;
146 	else
147 		return ptr;
148 }
149 
igt_vc4_set_tiling(int fd,uint32_t handle,uint64_t modifier)150 void igt_vc4_set_tiling(int fd, uint32_t handle, uint64_t modifier)
151 {
152 	struct drm_vc4_set_tiling set = {
153 		.handle = handle,
154 		.modifier = modifier,
155 	};
156 
157 	do_ioctl(fd, DRM_IOCTL_VC4_SET_TILING, &set);
158 }
159 
igt_vc4_get_tiling(int fd,uint32_t handle)160 uint64_t igt_vc4_get_tiling(int fd, uint32_t handle)
161 {
162 	struct drm_vc4_get_tiling get = {
163 		.handle = handle,
164 	};
165 
166 	do_ioctl(fd, DRM_IOCTL_VC4_GET_TILING, &get);
167 
168 	return get.modifier;
169 }
170 
igt_vc4_get_param(int fd,uint32_t param,uint64_t * val)171 int igt_vc4_get_param(int fd, uint32_t param, uint64_t *val)
172 {
173 	struct drm_vc4_get_param arg = {
174 		.param = param,
175 	};
176 	int ret;
177 
178 	ret = igt_ioctl(fd, DRM_IOCTL_VC4_GET_PARAM, &arg);
179 	if (ret)
180 		return ret;
181 
182 	*val = arg.value;
183 	return 0;
184 }
185 
igt_vc4_purgeable_bo(int fd,int handle,bool purgeable)186 bool igt_vc4_purgeable_bo(int fd, int handle, bool purgeable)
187 {
188 	struct drm_vc4_gem_madvise arg = {
189 		.handle = handle,
190 		.madv = purgeable ? VC4_MADV_DONTNEED : VC4_MADV_WILLNEED,
191 	};
192 
193 	do_ioctl(fd, DRM_IOCTL_VC4_GEM_MADVISE, &arg);
194 
195 	return arg.retained;
196 }
197 
198 
199 /* Calculate the t-tile width so that size = width * height * bpp / 8. */
200 #define VC4_T_TILE_W(size, height, bpp) ((size) / (height) / ((bpp) / 8))
201 
igt_vc4_t_tiled_offset(size_t stride,size_t height,size_t bpp,size_t x,size_t y)202 static size_t igt_vc4_t_tiled_offset(size_t stride, size_t height, size_t bpp,
203 				     size_t x, size_t y)
204 {
205 	const size_t t1k_map_even[] = { 0, 3, 1, 2 };
206 	const size_t t1k_map_odd[] = { 2, 1, 3, 0 };
207 	const size_t t4k_t_h = 32;
208 	const size_t t1k_t_h = 16;
209 	const size_t t64_t_h = 4;
210 	size_t offset = 0;
211 	size_t t4k_t_w, t4k_w, t4k_x, t4k_y;
212 	size_t t1k_t_w, t1k_x, t1k_y;
213 	size_t t64_t_w, t64_x, t64_y;
214 	size_t pix_x, pix_y;
215 	unsigned int index;
216 
217 	/* T-tiling is only supported for 16 and 32 bpp. */
218 	igt_assert(bpp == 16 || bpp == 32);
219 
220 	/* T-tiling stride must be aligned to the 4K tiles strides. */
221 	igt_assert((stride % (4096 / t4k_t_h)) == 0);
222 
223 	/* Calculate the tile width for the bpp. */
224 	t4k_t_w = VC4_T_TILE_W(4096, t4k_t_h, bpp);
225 	t1k_t_w = VC4_T_TILE_W(1024, t1k_t_h, bpp);
226 	t64_t_w = VC4_T_TILE_W(64, t64_t_h, bpp);
227 
228 	/* Aligned total width in number of 4K tiles. */
229 	t4k_w = (stride / (bpp / 8)) / t4k_t_w;
230 
231 	/* X and y coordinates in number of 4K tiles. */
232 	t4k_x = x / t4k_t_w;
233 	t4k_y = y / t4k_t_h;
234 
235 	/* Increase offset to the beginning of the 4K tile row. */
236 	offset += t4k_y * t4k_w * 4096;
237 
238 	/* X and Y coordinates in number of 1K tiles within the 4K tile. */
239 	t1k_x = (x % t4k_t_w) / t1k_t_w;
240 	t1k_y = (y % t4k_t_h) / t1k_t_h;
241 
242 	/* Index for 1K tile map lookup. */
243 	index = 2 * t1k_y + t1k_x;
244 
245 	/* Odd rows start from the right, even rows from the left. */
246 	if (t4k_y % 2) {
247 		/* Increase offset to the 4K tile (starting from the right). */
248 		offset += (t4k_w - t4k_x - 1) * 4096;
249 
250 		/* Incrase offset to the beginning of the (odd) 1K tile. */
251 		offset += t1k_map_odd[index] * 1024;
252 	} else {
253 		/* Increase offset to the 4K tile (starting from the left). */
254 		offset += t4k_x * 4096;
255 
256 		/* Incrase offset to the beginning of the (even) 1K tile. */
257 		offset += t1k_map_even[index] * 1024;
258 	}
259 
260 	/* X and Y coordinates in number of 64 byte tiles within the 1K tile. */
261 	t64_x = (x % t1k_t_w) / t64_t_w;
262 	t64_y = (y % t1k_t_h) / t64_t_h;
263 
264 	/* Increase offset to the beginning of the 64-byte tile. */
265 	offset += (t64_y * (t1k_t_w / t64_t_w) + t64_x) * 64;
266 
267 	/* X and Y coordinates in number of pixels within the 64-byte tile. */
268 	pix_x = x % t64_t_w;
269 	pix_y = y % t64_t_h;
270 
271 	/* Increase offset to the correct pixel. */
272 	offset += (pix_y * t64_t_w + pix_x) * bpp / 8;
273 
274 	return offset;
275 }
276 
vc4_fb_convert_plane_to_t_tiled(struct igt_fb * dst,void * dst_buf,struct igt_fb * src,void * src_buf,unsigned int plane)277 static void vc4_fb_convert_plane_to_t_tiled(struct igt_fb *dst, void *dst_buf,
278 					    struct igt_fb *src, void *src_buf,
279 					    unsigned int plane)
280 {
281 	size_t bpp = src->plane_bpp[plane];
282 	unsigned int i, j;
283 
284 	for (i = 0; i < src->height; i++) {
285 		for (j = 0; j < src->width; j++) {
286 			size_t src_offset = src->offsets[plane];
287 			size_t dst_offset = dst->offsets[plane];
288 
289 			src_offset += src->strides[plane] * i + j * bpp / 8;
290 			dst_offset += igt_vc4_t_tiled_offset(dst->strides[plane],
291 							     dst->height,
292 							     bpp, j, i);
293 
294 			switch (bpp) {
295 			case 16:
296 				*(uint16_t *)(dst_buf + dst_offset) =
297 					*(uint16_t *)(src_buf + src_offset);
298 				break;
299 			case 32:
300 				*(uint32_t *)(dst_buf + dst_offset) =
301 					*(uint32_t *)(src_buf + src_offset);
302 				break;
303 			}
304 		}
305 	}
306 }
307 
vc4_fb_convert_plane_from_t_tiled(struct igt_fb * dst,void * dst_buf,struct igt_fb * src,void * src_buf,unsigned int plane)308 static void vc4_fb_convert_plane_from_t_tiled(struct igt_fb *dst, void *dst_buf,
309 					      struct igt_fb *src, void *src_buf,
310 					      unsigned int plane)
311 {
312 	size_t bpp = src->plane_bpp[plane];
313 	unsigned int i, j;
314 
315 	for (i = 0; i < src->height; i++) {
316 		for (j = 0; j < src->width; j++) {
317 			size_t src_offset = src->offsets[plane];
318 			size_t dst_offset = dst->offsets[plane];
319 
320 			src_offset += igt_vc4_t_tiled_offset(src->strides[plane],
321 							     src->height,
322 							     bpp, j, i);
323 			src_offset += dst->strides[plane] * i + j * bpp / 8;
324 
325 			switch (bpp) {
326 			case 16:
327 				*(uint16_t *)(dst_buf + dst_offset) =
328 					*(uint16_t *)(src_buf + src_offset);
329 				break;
330 			case 32:
331 				*(uint32_t *)(dst_buf + dst_offset) =
332 					*(uint32_t *)(src_buf + src_offset);
333 				break;
334 			}
335 		}
336 	}
337 }
338 
vc4_sand_tiled_offset(size_t column_width,size_t column_size,size_t x,size_t y,size_t bpp)339 static size_t vc4_sand_tiled_offset(size_t column_width, size_t column_size, size_t x,
340 				    size_t y, size_t bpp)
341 {
342 	size_t offset = 0;
343 	size_t cols_x;
344 	size_t pix_x;
345 
346 	/* Offset to the beginning of the relevant column. */
347 	cols_x = x / column_width;
348 	offset += cols_x * column_size;
349 
350 	/* Offset to the relevant pixel. */
351 	pix_x = x % column_width;
352 	offset += (column_width * y + pix_x) * bpp / 8;
353 
354 	return offset;
355 }
356 
vc4_fb_convert_plane_to_sand_tiled(struct igt_fb * dst,void * dst_buf,struct igt_fb * src,void * src_buf,unsigned int plane)357 static void vc4_fb_convert_plane_to_sand_tiled(struct igt_fb *dst, void *dst_buf,
358 					       struct igt_fb *src, void *src_buf,
359 					       unsigned int plane)
360 {
361 	uint64_t modifier_base = fourcc_mod_broadcom_mod(dst->modifier);
362 	uint32_t column_height = fourcc_mod_broadcom_param(dst->modifier);
363 	uint32_t column_width_bytes, column_width, column_size;
364 	size_t bpp = dst->plane_bpp[plane];
365 	unsigned int i, j;
366 
367 	switch (modifier_base) {
368 	case DRM_FORMAT_MOD_BROADCOM_SAND32:
369 		column_width_bytes = 32;
370 		break;
371 	case DRM_FORMAT_MOD_BROADCOM_SAND64:
372 		column_width_bytes = 64;
373 		break;
374 	case DRM_FORMAT_MOD_BROADCOM_SAND128:
375 		column_width_bytes = 128;
376 		break;
377 	case DRM_FORMAT_MOD_BROADCOM_SAND256:
378 		column_width_bytes = 256;
379 		break;
380 	default:
381 		igt_assert(false);
382 	}
383 
384 	column_width = column_width_bytes * dst->plane_width[plane] / dst->width;
385 	column_size = column_width_bytes * column_height;
386 
387 	for (i = 0; i < dst->plane_height[plane]; i++) {
388 		for (j = 0; j < src->plane_width[plane]; j++) {
389 			size_t src_offset = src->offsets[plane];
390 			size_t dst_offset = dst->offsets[plane];
391 
392 			src_offset += src->strides[plane] * i + j * bpp / 8;
393 			dst_offset += vc4_sand_tiled_offset(column_width,
394 							    column_size, j, i,
395 							    bpp);
396 
397 			switch (bpp) {
398 			case 8:
399 				*(uint8_t *)(dst_buf + dst_offset) =
400 					*(uint8_t *)(src_buf + src_offset);
401 				break;
402 			case 16:
403 				*(uint16_t *)(dst_buf + dst_offset) =
404 					*(uint16_t *)(src_buf + src_offset);
405 				break;
406 			default:
407 				igt_assert(false);
408 			}
409 		}
410 	}
411 }
412 
vc4_fb_convert_plane_from_sand_tiled(struct igt_fb * dst,void * dst_buf,struct igt_fb * src,void * src_buf,unsigned int plane)413 static void vc4_fb_convert_plane_from_sand_tiled(struct igt_fb *dst, void *dst_buf,
414 						 struct igt_fb *src, void *src_buf,
415 						 unsigned int plane)
416 {
417 	uint64_t modifier_base = fourcc_mod_broadcom_mod(src->modifier);
418 	uint32_t column_height = fourcc_mod_broadcom_param(src->modifier);
419 	uint32_t column_width_bytes, column_width, column_size;
420 	size_t bpp = src->plane_bpp[plane];
421 	unsigned int i, j;
422 
423 	switch (modifier_base) {
424 	case DRM_FORMAT_MOD_BROADCOM_SAND32:
425 		column_width_bytes = 32;
426 		break;
427 	case DRM_FORMAT_MOD_BROADCOM_SAND64:
428 		column_width_bytes = 64;
429 		break;
430 	case DRM_FORMAT_MOD_BROADCOM_SAND128:
431 		column_width_bytes = 128;
432 		break;
433 	case DRM_FORMAT_MOD_BROADCOM_SAND256:
434 		column_width_bytes = 256;
435 		break;
436 	default:
437 		igt_assert(false);
438 	}
439 
440 	column_width = column_width_bytes * src->plane_width[plane] / src->width;
441 	column_size = column_width_bytes * column_height;
442 
443 	for (i = 0; i < dst->plane_height[plane]; i++) {
444 		for (j = 0; j < src->plane_width[plane]; j++) {
445 			size_t src_offset = src->offsets[plane];
446 			size_t dst_offset = dst->offsets[plane];
447 
448 			src_offset += vc4_sand_tiled_offset(column_width,
449 							    column_size, j, i,
450 							    bpp);
451 			dst_offset += dst->strides[plane] * i + j * bpp / 8;
452 
453 			switch (bpp) {
454 			case 8:
455 				*(uint8_t *)(dst_buf + dst_offset) =
456 					*(uint8_t *)(src_buf + src_offset);
457 				break;
458 			case 16:
459 				*(uint16_t *)(dst_buf + dst_offset) =
460 					*(uint16_t *)(src_buf + src_offset);
461 				break;
462 			default:
463 				igt_assert(false);
464 			}
465 		}
466 	}
467 }
468 
vc4_fb_convert_plane_to_tiled(struct igt_fb * dst,void * dst_buf,struct igt_fb * src,void * src_buf)469 void vc4_fb_convert_plane_to_tiled(struct igt_fb *dst, void *dst_buf,
470 				     struct igt_fb *src, void *src_buf)
471 {
472 	unsigned int plane;
473 
474 	igt_assert(src->modifier == DRM_FORMAT_MOD_LINEAR);
475 	igt_assert(igt_vc4_is_tiled(dst->modifier));
476 
477 	for (plane = 0; plane < src->num_planes; plane++) {
478 		if (dst->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
479 			vc4_fb_convert_plane_to_t_tiled(dst, dst_buf, src, src_buf, plane);
480 		else
481 			vc4_fb_convert_plane_to_sand_tiled(dst, dst_buf, src, src_buf, plane);
482 	}
483 }
484 
vc4_fb_convert_plane_from_tiled(struct igt_fb * dst,void * dst_buf,struct igt_fb * src,void * src_buf)485 void vc4_fb_convert_plane_from_tiled(struct igt_fb *dst, void *dst_buf,
486 				       struct igt_fb *src, void *src_buf)
487 {
488 	unsigned int plane;
489 
490 	igt_assert(igt_vc4_is_tiled(src->modifier));
491 	igt_assert(dst->modifier == DRM_FORMAT_MOD_LINEAR);
492 
493 	for (plane = 0; plane < src->num_planes; plane++) {
494 		if (src->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
495 			vc4_fb_convert_plane_from_t_tiled(dst, dst_buf, src, src_buf, plane);
496 		else
497 			vc4_fb_convert_plane_from_sand_tiled(dst, dst_buf, src, src_buf, plane);
498 	}
499 }
500