2 * DRM based rotator test program
3 * Copyright 2012 Samsung Electronics
4 * YoungJun Cho <yj44.cho@samsung.com>
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
34 #include "exynos_drm.h"
39 #include "drm_fourcc.h"
41 static int exynos_drm_ipp_set_property(int fd,
42 struct drm_exynos_ipp_property *property,
43 struct drm_exynos_pos *src_pos,
44 struct drm_exynos_sz *src_sz,
45 struct drm_exynos_pos *dst_pos,
46 struct drm_exynos_sz *dst_sz)
50 memset(property, 0x00, sizeof(struct drm_exynos_ipp_property));
52 property->cmd = IPP_CMD_M2M;
54 property->config[EXYNOS_DRM_OPS_SRC].ops_id = EXYNOS_DRM_OPS_SRC;
55 property->config[EXYNOS_DRM_OPS_SRC].flip = EXYNOS_DRM_FLIP_NONE;
56 property->config[EXYNOS_DRM_OPS_SRC].degree = EXYNOS_DRM_DEGREE_0;
57 property->config[EXYNOS_DRM_OPS_SRC].fmt = DRM_FORMAT_XRGB8888;
58 property->config[EXYNOS_DRM_OPS_SRC].pos = *src_pos;
59 property->config[EXYNOS_DRM_OPS_SRC].sz = *src_sz;
61 property->config[EXYNOS_DRM_OPS_DST].ops_id = EXYNOS_DRM_OPS_DST;
62 property->config[EXYNOS_DRM_OPS_DST].flip = EXYNOS_DRM_FLIP_NONE;
63 property->config[EXYNOS_DRM_OPS_DST].degree = EXYNOS_DRM_DEGREE_90;
64 property->config[EXYNOS_DRM_OPS_DST].fmt = DRM_FORMAT_XRGB8888;
65 property->config[EXYNOS_DRM_OPS_DST].pos = *dst_pos;
66 property->config[EXYNOS_DRM_OPS_DST].sz = *dst_sz;
68 ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY, property);
71 "failed to DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY : %s\n",
77 static int exynos_drm_ipp_queue_buf(int fd, int prop_id,
78 struct drm_exynos_ipp_queue_buf *qbuf,
79 enum drm_exynos_ops_id ops_id,
80 enum drm_exynos_ipp_buf_type buf_type,
82 unsigned int gem_handle)
86 memset(qbuf, 0x00, sizeof(struct drm_exynos_ipp_queue_buf));
88 qbuf->ops_id = ops_id;
89 qbuf->buf_type = buf_type;
91 qbuf->prop_id = prop_id;
92 qbuf->buf_id = buf_id;
93 qbuf->handle[EXYNOS_DRM_PLANAR_Y] = gem_handle;
94 qbuf->handle[EXYNOS_DRM_PLANAR_CB] = 0;
95 qbuf->handle[EXYNOS_DRM_PLANAR_CR] = 0;
97 ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, qbuf);
100 "failed to DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF[prop_id:%d]"\
101 "[ops_id:%d][buf_id:%d][buf_type:%d] : %s\n",
102 prop_id, ops_id, buf_id, buf_type, strerror(errno));
107 static int exynos_drm_ipp_cmd_ctrl(int fd, int prop_id,
108 struct drm_exynos_ipp_cmd_ctrl *cmd_ctrl,
109 enum drm_exynos_ipp_ctrl ctrl)
113 memset(cmd_ctrl, 0x00, sizeof(struct drm_exynos_ipp_cmd_ctrl));
115 cmd_ctrl->prop_id = prop_id;
116 cmd_ctrl->ctrl = ctrl;
118 ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_CMD_CTRL, cmd_ctrl);
121 "failed to DRM_IOCTL_EXYNOS_IPP_CMD_CTRL[prop_id:%d]"\
122 "[ctrl:%d] : %s\n", prop_id, ctrl, strerror(errno));
127 static int rotator_set_mode_property(struct connector *c, int count,
128 unsigned int *width, unsigned int *height,
129 unsigned int *stride,
130 struct drm_exynos_ipp_property *property)
133 struct drm_exynos_pos src_pos = {0, 0, 720, 1280};
134 struct drm_exynos_sz src_sz = {720, 1280};
135 struct drm_exynos_pos dst_pos = {0, 0, 1280, 720};
136 struct drm_exynos_sz dst_sz = {1280, 720};
142 for (i = 0; i < count; i++) {
143 connector_find_mode(&c[i]);
144 if (c[i].mode == NULL)
147 *width += c[i].mode->hdisplay;
148 if (*height < c[i].mode->vdisplay)
149 *height = c[i].mode->vdisplay;
152 *stride = *width * 4;
154 /* For IPP setting property */
155 ret = exynos_drm_ipp_set_property(fd, property, &src_pos, &src_sz,
158 fprintf(stderr, "failed to ipp set property: %s\n",
164 static int rotator_event_handler(int fd, int idx, int prop_id,
165 struct drm_exynos_ipp_queue_buf *src_qbuf,
166 struct drm_exynos_gem_create *src_gem,
167 struct drm_exynos_ipp_queue_buf *dst_qbuf,
168 struct drm_exynos_gem_create *dst_gem,
169 void **usr_addr, unsigned int width,
170 unsigned int height, struct timeval *begin)
175 struct drm_exynos_ipp_event *ipp_event;
176 int src_buf_id, dst_buf_id;
179 len = read(fd, buffer, sizeof(buffer));
182 if (len < sizeof (*e))
187 e = (struct drm_event *)&buffer[i];
189 case DRM_EXYNOS_IPP_EVENT:
190 ipp_event = (struct drm_exynos_ipp_event *)e;
191 src_buf_id = ipp_event->buf_id[EXYNOS_DRM_OPS_SRC];
192 dst_buf_id = ipp_event->buf_id[EXYNOS_DRM_OPS_DST];
194 sprintf(filename, "/opt/media/rot_%d_%d.bmp", idx,
196 util_write_bmp(filename, usr_addr[dst_buf_id], width,
199 gettimeofday(begin, NULL);
200 ret = exynos_drm_ipp_queue_buf(fd, prop_id, src_qbuf,
206 fprintf(stderr, "failed to queue src_buf\n");
208 ret = exynos_drm_ipp_queue_buf(fd, prop_id,
209 &dst_qbuf[dst_buf_id],
211 IPP_BUF_ENQUEUE, dst_buf_id,
212 dst_gem[dst_buf_id].handle);
214 fprintf(stderr, "failed to queue dst_buf\n");
225 void rotator_1_N_set_mode(struct connector *c, int count, int page_flip,
228 struct drm_exynos_ipp_property property;
229 struct drm_exynos_ipp_queue_buf qbuf1, qbuf2[MAX_BUF];
230 struct drm_exynos_ipp_cmd_ctrl cmd_ctrl;
231 unsigned int width, height, stride;
233 struct drm_exynos_gem_create gem1, gem2[MAX_BUF];
234 struct drm_exynos_gem_mmap mmap1, mmap2[MAX_BUF];
235 void *usr_addr1, *usr_addr2[MAX_BUF];
236 struct timeval begin, end;
237 struct drm_gem_close args;
240 /* For setting mode / IPP setting property */
241 ret = rotator_set_mode_property(c, count, &width, &height, &stride,
244 fprintf(stderr, "failed to set mode property : %s\n",
249 /* For GEM create / mmap / draw buffer */
250 /* For source buffer */
251 ret = util_gem_create_mmap(fd, &gem1, &mmap1, &usr_addr1,
254 fprintf(stderr, "failed to gem create mmap: %s\n",
258 util_draw_buffer(usr_addr1, 1, width, height, stride, 0);
259 sprintf(filename, "/opt/media/rot_src.bmp");
260 util_write_bmp(filename, usr_addr1, width, height);
262 /* For destination buffer */
263 for (i = 0; i < MAX_BUF; i++) {
264 ret = util_gem_create_mmap(fd, &gem2[i], &mmap2[i],
265 &usr_addr2[i], stride * height);
267 fprintf(stderr, "failed to gem create mmap: %d : %s\n",
269 goto err_gem_create_mmap;
271 util_draw_buffer(usr_addr2[i], 0, 0, 0, 0, stride * height);
272 sprintf(filename, "/opt/media/rot_dst%d.bmp", i);
273 util_write_bmp(filename, usr_addr2[i], height, width);
276 /* For IPP queueing */
277 /* For source buffer */
278 ret = exynos_drm_ipp_queue_buf(fd, property.prop_id, &qbuf1,
279 EXYNOS_DRM_OPS_SRC, IPP_BUF_ENQUEUE,
282 fprintf(stderr, "failed to ipp queue buf src queue\n");
283 goto err_ipp_queue_buf;
286 /* For destination buffer */
287 for (i = 0; i < MAX_BUF; i++) {
288 ret = exynos_drm_ipp_queue_buf(fd, property.prop_id, &qbuf2[i],
289 EXYNOS_DRM_OPS_DST, IPP_BUF_ENQUEUE,
293 "failed to ipp queue buf dst queue : %d\n", i);
294 goto err_ipp_queue_buf;
298 /* For IPP starting */
299 gettimeofday(&begin, NULL);
300 ret = exynos_drm_ipp_cmd_ctrl(fd, property.prop_id, &cmd_ctrl,
303 fprintf(stderr, "failed to ipp cmd ctrl IPP_CMD_M2M start\n");
304 goto err_ipp_queue_buf;
307 /* For IPP handling event */
308 for (i = 0; i < MAX_LOOP; i++) {
312 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
318 ret = select(fd + 1, &fds, NULL, NULL, &timeout);
320 fprintf(stderr, "select timed out or error.\n");
322 } else if (FD_ISSET(0, &fds))
325 gettimeofday(&end, NULL);
326 usec[MAX_BUF * i + counter] =
327 (end.tv_sec - begin.tv_sec) * 1000000 +
328 (end.tv_usec - begin.tv_usec);
330 ret = rotator_event_handler(fd, i, property.prop_id,
331 &qbuf1, &gem1, qbuf2,
332 gem2, usr_addr2, height,
336 "failed to rotator_event_handler()\n");
337 goto err_rotator_event_handler;
339 if (++counter > MAX_BUF)
344 /* For IPP dequeing */
345 /* For source buffer */
346 ret = exynos_drm_ipp_queue_buf(fd, property.prop_id, &qbuf1,
347 EXYNOS_DRM_OPS_SRC, IPP_BUF_DEQUEUE, 0,
350 fprintf(stderr, "failed to ipp queue buf src dequeue\n");
351 goto err_rotator_event_handler;
354 /* For destination buffer */
355 for (i = 0; i < MAX_BUF; i++) {
356 ret = exynos_drm_ipp_queue_buf(fd, property.prop_id, &qbuf2[i],
357 EXYNOS_DRM_OPS_DST, IPP_BUF_DEQUEUE, i,
361 "failed to ipp queue buf dst queue : %d\n", i);
362 goto err_rotator_event_handler;
366 /* For IPP stopping */
367 ret = exynos_drm_ipp_cmd_ctrl(fd, property.prop_id, &cmd_ctrl,
370 fprintf(stderr, "failed to ipp cmd ctrl IPP_CMD_M2M stop\n");
373 /* For munmap / GEM close */
374 /* For destination buffer */
375 for (i = 0; i < MAX_BUF; i++) {
376 munmap(usr_addr2[i], mmap2[i].size);
377 memset(&args, 0x00, sizeof(struct drm_gem_close));
378 args.handle = gem2[i].handle;
379 exynos_gem_close(fd, &args);
382 /* For source buffer */
383 munmap(usr_addr1, mmap1.size);
384 memset(&args, 0x00, sizeof(struct drm_gem_close));
385 args.handle = gem1.handle;
386 exynos_gem_close(fd, &args);
390 err_rotator_event_handler:
391 exynos_drm_ipp_cmd_ctrl(fd, property.prop_id, &cmd_ctrl, IPP_CTRL_STOP);
393 for (i = 0; i < MAX_BUF; i++) {
394 exynos_drm_ipp_queue_buf(fd, property.prop_id, &qbuf2[i],
395 EXYNOS_DRM_OPS_DST, IPP_BUF_DEQUEUE, i,
398 exynos_drm_ipp_queue_buf(fd, property.prop_id, &qbuf1,
399 EXYNOS_DRM_OPS_SRC, IPP_BUF_DEQUEUE, 0, gem1.handle);
401 for (i = 0; i < MAX_BUF; i++) {
402 munmap(usr_addr2[i], mmap2[i].size);
403 memset(&args, 0x00, sizeof(struct drm_gem_close));
404 args.handle = gem2[i].handle;
405 exynos_gem_close(fd, &args);
408 munmap(usr_addr1, mmap1.size);
409 memset(&args, 0x00, sizeof(struct drm_gem_close));
410 args.handle = gem1.handle;
411 exynos_gem_close(fd, &args);
414 void rotator_N_N_set_mode(struct connector *c, int count, int page_flip,
417 struct drm_exynos_ipp_property property;
418 struct drm_exynos_ipp_queue_buf qbuf1[MAX_BUF], qbuf2[MAX_BUF];
419 struct drm_exynos_ipp_cmd_ctrl cmd_ctrl;
420 unsigned int width, height, stride;
422 struct drm_exynos_gem_create gem1[MAX_BUF], gem2[MAX_BUF];
423 struct drm_exynos_gem_mmap mmap1[MAX_BUF], mmap2[MAX_BUF];
424 void *usr_addr1[MAX_BUF], *usr_addr2[MAX_BUF];
425 struct timeval begin, end;
426 struct drm_gem_close args;
429 /* For setting mode / IPP setting property */
430 ret = rotator_set_mode_property(c, count, &width, &height, &stride,
433 fprintf(stderr, "failed to set mode property : %s\n",
438 /* For GEM create / mmap / draw buffer */
439 for (i = 0; i < MAX_BUF; i++) {
440 /* For source buffer */
441 ret = util_gem_create_mmap(fd, &gem1[i], &mmap1[i],
442 &usr_addr1[i], stride * height);
444 fprintf(stderr, "failed to gem create mmap: %d : %s\n",
446 goto err_gem_create_mmap;
448 util_draw_buffer(usr_addr1[i], 1, width, height, stride, 0);
449 sprintf(filename, "/opt/media/rot_src%d.bmp", i);
450 util_write_bmp(filename, usr_addr1[i], width, height);
452 /* For destination buffer */
453 ret = util_gem_create_mmap(fd, &gem2[i], &mmap2[i],
454 &usr_addr2[i], stride * height);
456 fprintf(stderr, "failed to gem create mmap: %d : %s\n",
458 goto err_gem_create_mmap;
460 util_draw_buffer(usr_addr2[i], 0, 0, 0, 0, stride * height);
461 sprintf(filename, "/opt/media/rot_dst%d.bmp", i);
462 util_write_bmp(filename, usr_addr2[i], height, width);
465 /* For IPP queueing */
466 for (i = 0; i < MAX_BUF; i++) {
467 /* For source buffer */
468 ret = exynos_drm_ipp_queue_buf(fd, property.prop_id, &qbuf1[i],
469 EXYNOS_DRM_OPS_SRC, IPP_BUF_ENQUEUE,
473 "failed to ipp queue buf src queue : %d\n", i);
474 goto err_ipp_queue_buf;
477 /* For destination buffer */
478 ret = exynos_drm_ipp_queue_buf(fd, property.prop_id, &qbuf2[i],
479 EXYNOS_DRM_OPS_DST, IPP_BUF_ENQUEUE,
483 "failed to ipp queue buf dst queue : %d\n", i);
484 goto err_ipp_queue_buf;
488 /* For IPP starting */
489 gettimeofday(&begin, NULL);
490 ret = exynos_drm_ipp_cmd_ctrl(fd, property.prop_id, &cmd_ctrl,
493 fprintf(stderr, "failed to ipp cmd ctrl IPP_CMD_M2M start\n");
494 goto err_ipp_queue_buf;
497 /* For IPP handling event */
498 for (i = 0; i < MAX_LOOP; i++) {
502 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
508 ret = select(fd + 1, &fds, NULL, NULL, &timeout);
510 fprintf(stderr, "select timed out or error.\n");
512 } else if (FD_ISSET(0, &fds))
515 gettimeofday(&end, NULL);
516 usec[MAX_BUF * i + counter] =
517 (end.tv_sec - begin.tv_sec) * 1000000 +
518 (end.tv_usec - begin.tv_usec);
520 ret = rotator_event_handler(fd, i, property.prop_id,
522 gem2, usr_addr2, height,
526 "failed to rotator_event_handler()\n");
527 goto err_rotator_event_handler;
529 if (++counter > MAX_BUF)
534 /* For IPP dequeing */
535 for (i = 0; i < MAX_BUF; i++) {
536 /* For destination buffer */
537 ret = exynos_drm_ipp_queue_buf(fd, property.prop_id, &qbuf2[i],
538 EXYNOS_DRM_OPS_DST, IPP_BUF_DEQUEUE, i,
542 "failed to ipp queue buf dst dequeue: %d\n", i);
543 goto err_rotator_event_handler;
546 /* For source buffer */
547 ret = exynos_drm_ipp_queue_buf(fd, property.prop_id, &qbuf1[i],
548 EXYNOS_DRM_OPS_SRC, IPP_BUF_DEQUEUE, i,
552 "failed to ipp queue buf src dequeue: %d\n", i);
553 goto err_rotator_event_handler;
557 /* For IPP stopping */
558 ret = exynos_drm_ipp_cmd_ctrl(fd, property.prop_id, &cmd_ctrl,
561 fprintf(stderr, "failed to ipp cmd ctrl IPP_CMD_M2M stop\n");
564 /* For munmap / GEM close */
565 for (i = 0; i < MAX_BUF; i++) {
566 /* For destination buffer */
567 munmap(usr_addr2[i], mmap2[i].size);
568 memset(&args, 0x00, sizeof(struct drm_gem_close));
569 args.handle = gem2[i].handle;
570 exynos_gem_close(fd, &args);
572 /* For source buffer */
573 munmap(usr_addr1[i], mmap1[i].size);
574 memset(&args, 0x00, sizeof(struct drm_gem_close));
575 args.handle = gem1[i].handle;
576 exynos_gem_close(fd, &args);
581 err_rotator_event_handler:
582 exynos_drm_ipp_cmd_ctrl(fd, property.prop_id, &cmd_ctrl, IPP_CTRL_STOP);
584 for (i = 0; i < MAX_BUF; i++) {
585 exynos_drm_ipp_queue_buf(fd, property.prop_id, &qbuf2[i],
586 EXYNOS_DRM_OPS_DST, IPP_BUF_DEQUEUE, i,
589 exynos_drm_ipp_queue_buf(fd, property.prop_id, &qbuf1[i],
590 EXYNOS_DRM_OPS_SRC, IPP_BUF_DEQUEUE, i,
594 for (i = 0; i < MAX_BUF; i++) {
595 munmap(usr_addr2[i], mmap2[i].size);
596 memset(&args, 0x00, sizeof(struct drm_gem_close));
597 args.handle = gem2[i].handle;
598 exynos_gem_close(fd, &args);
600 munmap(usr_addr1, mmap1[i].size);
601 memset(&args, 0x00, sizeof(struct drm_gem_close));
602 args.handle = gem1[i].handle;
603 exynos_gem_close(fd, &args);