2 * DRM based fimc test program
3 * Copyright 2012 Samsung Electronics
4 * Eunchul Kim <chulspro.kim@sasmsung.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_sz *def_sz,
44 enum drm_exynos_ipp_cmd cmd,
45 enum drm_exynos_degree degree)
47 struct drm_exynos_pos crop_pos = {0, 0, def_sz->hsize, def_sz->vsize};
48 struct drm_exynos_pos scale_pos = {0, 0, def_sz->hsize, def_sz->vsize};
49 struct drm_exynos_sz src_sz = {def_sz->hsize, def_sz->vsize};
50 struct drm_exynos_sz dst_sz = {def_sz->hsize, def_sz->vsize};
53 memset(property, 0x00, sizeof(struct drm_exynos_ipp_property));
58 property->config[EXYNOS_DRM_OPS_SRC].ops_id = EXYNOS_DRM_OPS_SRC;
59 property->config[EXYNOS_DRM_OPS_SRC].flip = EXYNOS_DRM_FLIP_NONE;
60 property->config[EXYNOS_DRM_OPS_SRC].degree = EXYNOS_DRM_DEGREE_0;
61 property->config[EXYNOS_DRM_OPS_SRC].fmt = DRM_FORMAT_XRGB8888;
62 property->config[EXYNOS_DRM_OPS_SRC].pos = crop_pos;
63 property->config[EXYNOS_DRM_OPS_SRC].sz = src_sz;
65 property->config[EXYNOS_DRM_OPS_DST].ops_id = EXYNOS_DRM_OPS_DST;
66 property->config[EXYNOS_DRM_OPS_DST].flip = EXYNOS_DRM_FLIP_NONE;
67 property->config[EXYNOS_DRM_OPS_DST].degree = degree;
68 property->config[EXYNOS_DRM_OPS_DST].fmt = DRM_FORMAT_XRGB8888;
69 if (property->config[EXYNOS_DRM_OPS_DST].degree == EXYNOS_DRM_DEGREE_90) {
70 dst_sz.hsize = def_sz->vsize;
71 dst_sz.vsize = def_sz->hsize;
73 scale_pos.w = def_sz->vsize;
74 scale_pos.h = def_sz->hsize;
76 property->config[EXYNOS_DRM_OPS_DST].pos = scale_pos;
77 property->config[EXYNOS_DRM_OPS_DST].sz = dst_sz;
80 property->config[EXYNOS_DRM_OPS_SRC].ops_id = EXYNOS_DRM_OPS_SRC;
81 property->config[EXYNOS_DRM_OPS_SRC].flip = EXYNOS_DRM_FLIP_NONE;
82 property->config[EXYNOS_DRM_OPS_SRC].degree = EXYNOS_DRM_DEGREE_0;
83 property->config[EXYNOS_DRM_OPS_SRC].fmt = DRM_FORMAT_YUV444;
84 if (property->config[EXYNOS_DRM_OPS_SRC].degree == EXYNOS_DRM_DEGREE_90) {
85 src_sz.hsize = def_sz->vsize;
86 src_sz.vsize = def_sz->hsize;
88 crop_pos.w = def_sz->vsize;
89 crop_pos.h = def_sz->hsize;
91 property->config[EXYNOS_DRM_OPS_SRC].pos = crop_pos;
92 property->config[EXYNOS_DRM_OPS_SRC].sz = src_sz;
94 property->config[EXYNOS_DRM_OPS_DST].ops_id = EXYNOS_DRM_OPS_DST;
95 property->config[EXYNOS_DRM_OPS_DST].flip = EXYNOS_DRM_FLIP_NONE;
96 property->config[EXYNOS_DRM_OPS_DST].degree = degree;
97 property->config[EXYNOS_DRM_OPS_DST].fmt = DRM_FORMAT_XRGB8888;
98 if (property->config[EXYNOS_DRM_OPS_DST].degree == EXYNOS_DRM_DEGREE_90) {
99 dst_sz.hsize = def_sz->vsize;
100 dst_sz.vsize = def_sz->hsize;
102 scale_pos.w = def_sz->vsize;
103 scale_pos.h = def_sz->hsize;
105 property->config[EXYNOS_DRM_OPS_DST].pos = scale_pos;
106 property->config[EXYNOS_DRM_OPS_DST].sz = dst_sz;
114 ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY, property);
117 "failed to DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY : %s\n",
120 printf("DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY : prop_id[%d]\n",
126 static int exynos_drm_ipp_queue_buf(int fd, struct drm_exynos_ipp_queue_buf *qbuf,
127 enum drm_exynos_ops_id ops_id,
128 enum drm_exynos_ipp_buf_type buf_type,
131 unsigned int gem_handle)
135 memset(qbuf, 0x00, sizeof(struct drm_exynos_ipp_queue_buf));
137 qbuf->ops_id = ops_id;
138 qbuf->buf_type = buf_type;
140 qbuf->prop_id = prop_id;
141 qbuf->buf_id = buf_id;
142 qbuf->handle[EXYNOS_DRM_PLANAR_Y] = gem_handle;
143 qbuf->handle[EXYNOS_DRM_PLANAR_CB] = 0;
144 qbuf->handle[EXYNOS_DRM_PLANAR_CR] = 0;
146 ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, qbuf);
149 "failed to DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF[id:%d][buf_type:%d] : %s\n",
150 ops_id, buf_type, strerror(errno));
155 static int exynos_drm_ipp_cmd_ctrl(int fd, struct drm_exynos_ipp_cmd_ctrl *cmd_ctrl,
157 enum drm_exynos_ipp_ctrl ctrl)
161 memset(cmd_ctrl, 0x00, sizeof(struct drm_exynos_ipp_cmd_ctrl));
163 cmd_ctrl->prop_id = prop_id;
164 cmd_ctrl->ctrl = ctrl;
166 ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_CMD_CTRL, cmd_ctrl);
169 "failed to DRM_IOCTL_EXYNOS_IPP_CMD_CTRL[prop_id:%d][ctrl:%d] : %s\n",
170 prop_id, ctrl, strerror(errno));
175 int fimc_event_handler(struct drm_exynos_ipp_queue_buf *src_qbuf, struct drm_exynos_gem_create *src_gem,
176 struct drm_exynos_ipp_queue_buf *dst_qbuf, struct drm_exynos_gem_create *dst_gem,
177 struct drm_exynos_ipp_property *property, void **usr_addr,
178 unsigned int width, unsigned int height, enum drm_exynos_ipp_cmd cmd)
183 struct drm_exynos_ipp_event *ipp_event;
186 int src_buf_id, dst_buf_id;
189 len = read(fd, buffer, sizeof buffer);
197 e = (struct drm_event *) &buffer[i];
199 case DRM_EXYNOS_IPP_EVENT:
200 ipp_event = (struct drm_exynos_ipp_event *) e;
201 src_buf_id = ipp_event->buf_id[EXYNOS_DRM_OPS_SRC];
202 dst_buf_id = ipp_event->buf_id[EXYNOS_DRM_OPS_DST];
204 printf("%s:src_buf_id[%d]dst_buf_id[%d]bmp_idx[%d]\n", __func__, src_buf_id, dst_buf_id, bmp_idx++);
205 if (cmd == IPP_CMD_M2M) {
206 sprintf(filename, "/opt/media/fimc_m2m_dst%d.bmp", bmp_idx);
208 util_write_bmp(filename, usr_addr[dst_buf_id], width, height);
210 /* For source buffer queue to IPP */
211 ret = exynos_drm_ipp_queue_buf(fd, &src_qbuf[src_buf_id], EXYNOS_DRM_OPS_SRC,
212 IPP_BUF_ENQUEUE, property->prop_id,
213 src_buf_id, src_gem[src_buf_id].handle);
215 fprintf(stderr, "failed to ipp buf src queue\n");
216 goto err_ipp_ctrl_close;
219 /* For destination buffer queue to IPP */
220 ret = exynos_drm_ipp_queue_buf(fd, &dst_qbuf[dst_buf_id], EXYNOS_DRM_OPS_DST,
221 IPP_BUF_ENQUEUE, property->prop_id,
222 dst_buf_id, dst_gem[dst_buf_id].handle);
224 fprintf(stderr, "failed to ipp buf dst queue\n");
225 goto err_ipp_ctrl_close;
227 } else if (cmd == IPP_CMD_WB) {
228 sprintf(filename, "/opt/media/fimc_wb_%d.bmp", bmp_idx);
230 util_write_bmp(filename, usr_addr[dst_buf_id], width, height);
232 /* For destination buffer queue to IPP */
233 ret = exynos_drm_ipp_queue_buf(fd, &dst_qbuf[dst_buf_id], EXYNOS_DRM_OPS_DST,
234 IPP_BUF_ENQUEUE, property->prop_id,
235 dst_buf_id, dst_gem[dst_buf_id].handle);
237 fprintf(stderr, "failed to ipp buf dst queue\n");
238 goto err_ipp_ctrl_close;
252 void fimc_m2m_set_mode(struct connector *c, int count, int page_flip,
255 struct drm_exynos_ipp_property property;
256 struct drm_exynos_ipp_cmd_ctrl cmd_ctrl;
257 struct drm_exynos_sz def_sz = {720, 1280};
258 struct drm_exynos_ipp_queue_buf qbuf1[MAX_BUF], qbuf2[MAX_BUF];
259 unsigned int width=720, height=1280, stride;
261 struct drm_exynos_gem_create gem1[MAX_BUF], gem2[MAX_BUF];
262 struct drm_exynos_gem_mmap mmap1[MAX_BUF], mmap2[MAX_BUF];
263 void *usr_addr1[MAX_BUF], *usr_addr2[MAX_BUF];
264 struct timeval begin, end;
265 struct drm_gem_close args;
270 for (i = 0; i < count; i++) {
271 connector_find_mode(&c[i]);
272 if (c[i].mode == NULL) continue;
273 width += c[i].mode->hdisplay;
274 if (height < c[i].mode->vdisplay) height = c[i].mode->vdisplay;
279 def_sz.hsize = width;
280 def_sz.vsize = height;
283 ret = exynos_drm_ipp_set_property(fd, &property, &def_sz, IPP_CMD_M2M, EXYNOS_DRM_DEGREE_90);
285 fprintf(stderr, "failed to ipp property\n");
289 for (i = 0; i < MAX_BUF; i++) {
290 /* For source buffer */
291 ret = util_gem_create_mmap(fd, &gem1[i], &mmap1[i], stride * height);
293 fprintf(stderr, "failed to gem create mmap: %s\n",
299 goto err_ipp_ctrl_close;
301 usr_addr1[i] = (void *)(unsigned long)mmap1[i].mapped;
303 /* For source buffer map to IPP */
304 ret = exynos_drm_ipp_queue_buf(fd, &qbuf1[i], EXYNOS_DRM_OPS_SRC,
305 IPP_BUF_ENQUEUE, property.prop_id, i, gem1[i].handle);
307 fprintf(stderr, "failed to ipp buf src map\n");
308 goto err_ipp_ctrl_close;
311 util_draw_buffer(usr_addr1[i], 1, width, height, stride, 0);
312 sprintf(filename, "/opt/media/fimc_m2m_org_src%d.bmp", j);
313 util_write_bmp(filename, usr_addr1[i], width, height);
316 for (i = 0; i < MAX_BUF; i++) {
317 /* For destination buffer */
318 ret = util_gem_create_mmap(fd, &gem2[i], &mmap2[i], stride * height);
320 fprintf(stderr, "failed to gem create mmap: %s\n",
323 goto err_ipp_ctrl_close;
325 goto err_ipp_ctrl_close;
327 usr_addr2[i] = (void*)(unsigned long)mmap2[i].mapped;
329 /* For destination buffer map to IPP */
330 ret = exynos_drm_ipp_queue_buf(fd, &qbuf2[i], EXYNOS_DRM_OPS_DST,
331 IPP_BUF_ENQUEUE, property.prop_id, i, gem2[i].handle);
333 fprintf(stderr, "failed to ipp buf dst map\n");
334 goto err_ipp_ctrl_close;
337 util_draw_buffer(usr_addr2[i], 0, 0, 0, 0, mmap2[i].size);
338 sprintf(filename, "/opt/media/fimc_m2m_org_dst%d.bmp", j);
339 util_write_bmp(filename, usr_addr2[i], height, width);
343 gettimeofday(&begin, NULL);
344 ret = exynos_drm_ipp_cmd_ctrl(fd, &cmd_ctrl, property.prop_id, IPP_CTRL_PLAY);
347 "failed to ipp ctrl IPP_CMD_M2M start\n");
348 goto err_ipp_ctrl_close;
353 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
359 ret = select(fd + 1, &fds, NULL, NULL, &timeout);
361 fprintf(stderr, "select timed out or error.\n");
363 } else if (FD_ISSET(0, &fds)) {
367 gettimeofday(&end, NULL);
368 usec[j] = (end.tv_sec - begin.tv_sec) * 1000000 +
369 (end.tv_usec - begin.tv_usec);
371 if (property.config[EXYNOS_DRM_OPS_DST].degree == EXYNOS_DRM_DEGREE_90 ||
372 property.config[EXYNOS_DRM_OPS_DST].degree == EXYNOS_DRM_DEGREE_270) {
373 if(fimc_event_handler(qbuf1, gem1, qbuf2, gem2, &property, usr_addr2, height, width, IPP_CMD_M2M) < 0)
376 if(fimc_event_handler(qbuf1, gem1, qbuf2, gem2, &property, usr_addr2, width, height, IPP_CMD_M2M) < 0)
383 gettimeofday(&begin, NULL);
387 /* For source buffer dequeue to IPP */
388 for (i = 0; i < MAX_BUF; i++) {
389 ret = exynos_drm_ipp_queue_buf(fd, &qbuf1[i], EXYNOS_DRM_OPS_SRC,
390 IPP_BUF_DEQUEUE, property.prop_id, i, gem1[i].handle);
392 fprintf(stderr, "failed to ipp buf dst dequeue\n");
395 /* For destination buffer dequeue to IPP */
396 for (i = 0; i < MAX_BUF; i++) {
397 ret = exynos_drm_ipp_queue_buf(fd, &qbuf2[i], EXYNOS_DRM_OPS_DST,
398 IPP_BUF_DEQUEUE, property.prop_id, i, gem2[i].handle);
400 fprintf(stderr, "failed to ipp buf dst dequeue\n");
404 ret = exynos_drm_ipp_cmd_ctrl(fd, &cmd_ctrl, property.prop_id, IPP_CTRL_STOP);
406 fprintf(stderr, "failed to ipp ctrl IPP_CMD_WB stop\n");
408 /* Close source buffer */
409 for (i = 0; i < MAX_BUF; i++) {
410 munmap(usr_addr1[i], mmap1[i].size);
411 memset(&args, 0x00, sizeof(struct drm_gem_close));
412 args.handle = gem1[i].handle;
413 exynos_gem_close(fd, &args);
416 /* Close destination buffer */
417 for (i = 0; i < MAX_BUF; i++) {
418 munmap(usr_addr2[i], mmap2[i].size);
419 memset(&args, 0x00, sizeof(struct drm_gem_close));
420 args.handle = gem2[i].handle;
421 exynos_gem_close(fd, &args);
427 void fimc_wb_set_mode(struct connector *c, int count, int page_flip,
430 struct drm_exynos_pos def_pos = {0, 0, 720, 1280};
431 struct drm_exynos_sz def_sz = {720, 1280};
432 struct drm_exynos_ipp_property property;
433 struct drm_exynos_gem_create gem[MAX_BUF];
434 struct drm_exynos_gem_mmap mmap[MAX_BUF];
435 struct drm_exynos_ipp_queue_buf qbuf[MAX_BUF];
436 void *usr_addr[MAX_BUF];
437 struct drm_exynos_ipp_cmd_ctrl cmd_ctrl;
438 unsigned int width, height, stride;
440 struct timeval begin, end;
441 struct drm_gem_close args;
445 for (i = 0; i < count; i++) {
446 connector_find_mode(&c[i]);
447 if (c[i].mode == NULL) continue;
448 width += c[i].mode->hdisplay;
449 if (height < c[i].mode->vdisplay) height = c[i].mode->vdisplay;
453 def_sz.hsize = width;
454 def_sz.vsize = height;
457 ret = exynos_drm_ipp_set_property(fd, &property, &def_sz, IPP_CMD_WB, EXYNOS_DRM_DEGREE_0);
459 fprintf(stderr, "failed to ipp property\n");
463 /* For destination buffer */
464 for (i = 0; i < MAX_BUF; i++) {
465 ret = util_gem_create_mmap(fd, &gem[i], &mmap[i], stride * height);
467 fprintf(stderr, "failed to gem create mmap: %s\n",
469 if (ret == -1) return;
470 else if (ret == -2) goto err_ipp_ctrl_close;
472 usr_addr[i] = (void *)(unsigned long)mmap[i].mapped;
473 /* For destination buffer map to IPP */
474 ret = exynos_drm_ipp_queue_buf(fd, &qbuf[i], EXYNOS_DRM_OPS_DST,
475 IPP_BUF_ENQUEUE, property.prop_id, i, gem[i].handle);
477 fprintf(stderr, "failed to ipp buf dst map\n");
478 goto err_ipp_ctrl_close;
483 gettimeofday(&begin, NULL);
484 ret = exynos_drm_ipp_cmd_ctrl(fd, &cmd_ctrl, property.prop_id, IPP_CTRL_PLAY);
487 "failed to ipp ctrl IPP_CMD_WB start\n");
488 goto err_ipp_ctrl_close;
493 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
499 ret = select(fd + 1, &fds, NULL, NULL, &timeout);
501 fprintf(stderr, "select timed out or error.\n");
503 } else if (FD_ISSET(0, &fds)) {
504 fprintf(stderr, "select error.\n");
508 gettimeofday(&end, NULL);
509 usec[j] = (end.tv_sec - begin.tv_sec) * 1000000 +
510 (end.tv_usec - begin.tv_usec);
512 if (property.config[EXYNOS_DRM_OPS_DST].degree == EXYNOS_DRM_DEGREE_90 ||
513 property.config[EXYNOS_DRM_OPS_DST].degree == EXYNOS_DRM_DEGREE_270 ||
514 property.config[EXYNOS_DRM_OPS_SRC].degree == EXYNOS_DRM_DEGREE_90 ||
515 property.config[EXYNOS_DRM_OPS_SRC].degree == EXYNOS_DRM_DEGREE_270) {
516 if(fimc_event_handler(NULL, NULL, qbuf, gem, &property, usr_addr, height, width, IPP_CMD_WB) < 0)
519 if(fimc_event_handler(NULL, NULL, qbuf, gem, &property, usr_addr, width, height, IPP_CMD_WB) < 0)
526 if (j == HALF_LOOP) {
528 ret = exynos_drm_ipp_cmd_ctrl(fd, &cmd_ctrl, property.prop_id, IPP_CTRL_STOP);
530 fprintf(stderr, "failed to ipp ctrl IPP_CMD_WB stop\n");
531 goto err_ipp_ctrl_close;
535 ret = exynos_drm_ipp_set_property(fd, &property, &def_sz, IPP_CMD_WB, EXYNOS_DRM_DEGREE_90);
537 fprintf(stderr, "failed to ipp property\n");
538 goto err_ipp_ctrl_close;
541 /* For destination buffer */
542 for (i = 0; i < MAX_BUF; i++) {
543 /* For destination buffer map to IPP */
544 ret = exynos_drm_ipp_queue_buf(fd, &qbuf[i], EXYNOS_DRM_OPS_DST,
545 IPP_BUF_ENQUEUE, property.prop_id, i, gem[i].handle);
547 fprintf(stderr, "failed to ipp buf dst map\n");
548 goto err_ipp_ctrl_close;
553 ret = exynos_drm_ipp_cmd_ctrl(fd, &cmd_ctrl, property.prop_id, IPP_CTRL_PLAY);
556 "failed to ipp ctrl IPP_CMD_WB start\n");
557 goto err_ipp_ctrl_close;
561 gettimeofday(&begin, NULL);
565 /* For destination buffer dequeue to IPP */
566 for (i = 0; i < MAX_BUF; i++) {
567 ret = exynos_drm_ipp_queue_buf(fd, &qbuf[i], EXYNOS_DRM_OPS_DST,
568 IPP_BUF_DEQUEUE, property.prop_id, i, gem[i].handle);
570 fprintf(stderr, "failed to ipp buf dst dequeue\n");
574 ret = exynos_drm_ipp_cmd_ctrl(fd, &cmd_ctrl, property.prop_id, IPP_CTRL_STOP);
576 fprintf(stderr, "failed to ipp ctrl IPP_CMD_WB stop\n");
578 for (i = 0; i < MAX_BUF; i++) {
579 munmap(usr_addr[i], mmap[i].size);
580 memset(&args, 0x00, sizeof(struct drm_gem_close));
581 args.handle = gem[i].handle;
582 exynos_gem_close(fd, &args);
588 void fimc_output_set_mode(struct connector *c, int count, int page_flip,
591 fprintf(stderr, "not supported. please wait v2\n");