blob: d5e8637dc84b5daefb275c56ab8965f32b76ac55 [file] [log] [blame]
Song Zhao1b237602020-02-13 10:58:57 -08001/*
2 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
3 *
4 * This source code is subject to the terms and conditions defined in the
5 * file 'LICENSE' which is part of this source code package.
6 *
7 * Description:
8 */
9#include <stdio.h>
10#include <stdlib.h>
11#include <stdint.h>
12#include <stdbool.h>
13#include <unistd.h>
14#include <fcntl.h>
15#include <errno.h>
16#include <pthread.h>
17#include <string.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <sys/ioctl.h>
21#include <sys/mman.h>
22#include <sys/stat.h>
23
24#include <xf86drm.h>
25#include <xf86drmMode.h>
26#include <libsync.h>
27#include <drm_fourcc.h>
28#include <linux/videodev2.h>
29#include <meson_drm.h>
30
31#include "drm.h"
32#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
33#define MAX_BUF_SIZE 32
34
35static char* drm_master_dev_name = "/dev/dri/card0";
36static char* drm_cli_dev_name = "/dev/dri/renderD128";
37static int drm_fd, drm_cli_fd;
38static int drm_mode_set;
Song Zhao6c7d1f82020-04-06 23:22:49 -070039static int secure_mode;
Song Zhao1b237602020-02-13 10:58:57 -080040extern unsigned int global_plane_id;
Ao Xua3a929a2020-04-16 18:29:51 +080041extern char mode_str[16];
42extern unsigned int vfresh;
Song Zhao1b237602020-02-13 10:58:57 -080043
44struct gem_buffer {
45 uint32_t width;
46 uint32_t height;
47 unsigned int planes_count;
48 unsigned int size;
49 unsigned int handles[4];
50 unsigned int pitches[4];
51 unsigned int offsets[4];
52 int export_fds[4];
53
54 unsigned int framebuffer_id;
55};
56
57struct display_properties_ids {
58 uint32_t connector_crtc_id;
59 uint32_t crtc_mode_id;
60 uint32_t crtc_active;
61 uint32_t plane_fb_id;
62 uint32_t plane_crtc_id;
63 uint32_t plane_src_x;
64 uint32_t plane_src_y;
65 uint32_t plane_src_w;
66 uint32_t plane_src_h;
67 uint32_t plane_crtc_x;
68 uint32_t plane_crtc_y;
69 uint32_t plane_crtc_w;
70 uint32_t plane_crtc_h;
71 uint32_t plane_zpos;
72 uint32_t out_fence_ptr;
73};
74
75struct plane {
76 drmModePlane *plane;
77 drmModeObjectProperties *props;
78 drmModePropertyRes **props_info;
79};
80
81struct crtc {
82 drmModeCrtc *crtc;
83 drmModeObjectProperties *props;
84 drmModePropertyRes **props_info;
85};
86
87struct connector {
88 drmModeConnector *connector;
89 drmModeObjectProperties *props;
90 drmModePropertyRes **props_info;
91};
92
93struct display_setup {
94 unsigned int connector_id;
95 unsigned int encoder_id;
96 unsigned int crtc_id;
97 unsigned int plane_id;
98
99 unsigned int x;
100 unsigned int y;
101 unsigned int scaled_width;
102 unsigned int scaled_height;
103 unsigned int crtc_width;
104 unsigned int crtc_height;
105
106 struct display_properties_ids properties_ids;
107 drmModeModeInfo mode;
108
109 struct plane *plane;
110 struct crtc *crtc;
111 struct connector *connector;
112} setup;
113
114struct aml_display {
115 bool started;
116 pthread_t disp_t;
117 unsigned int q_len;
118 unsigned int ri; //read index
119 unsigned int wi; //write index
120 unsigned int total_num;
121 struct drm_frame *queue;
122};
123
124static struct gem_buffer *gem_buf;
125static struct gem_buffer osd_gem_buf;
126static displayed_cb_func display_cb;
127static struct aml_display aml_dis;
128
129static int create_meson_gem_buffer(int fd, enum frame_format fmt,
130 struct gem_buffer *buffer)
131{
132 struct drm_meson_gem_create gem_create;
133 int rc;
134 int i;
135 int width = buffer->width;
136 int height = buffer->height;
137
138 if (!buffer)
139 return -1;
140
141 for (i = 0; i < buffer->planes_count; i++) {
142 memset(&gem_create, 0, sizeof(gem_create));
143
144 if (fmt == FRAME_FMT_AFBC) {
145 gem_create.flags = MESON_USE_VIDEO_AFBC;
146 gem_create.size = width * height * 2;
147 buffer->pitches[i] = width*2;
148 } else {
149 gem_create.flags = MESON_USE_VIDEO_PLANE;
Song Zhao6c7d1f82020-04-06 23:22:49 -0700150 if (secure_mode)
151 gem_create.flags |= MESON_USE_PROTECTED;
Song Zhao1b237602020-02-13 10:58:57 -0800152 if (i == 0)
153 gem_create.size = width * height;
154 else
155 gem_create.size = width * height / 2;
156 buffer->pitches[i] = width;
157 }
158
159 rc = drmIoctl(fd, DRM_IOCTL_MESON_GEM_CREATE, &gem_create);
160 if (rc < 0) {
161 printf("Unable to create dumb buffer: %s\n",
162 strerror(errno));
163 return -1;
164 }
165
166 buffer->size += gem_create.size;
167 buffer->handles[i] = gem_create.handle;
168 buffer->offsets[i] = 0;
169
170 rc = drmPrimeHandleToFD(fd, buffer->handles[i], DRM_CLOEXEC | DRM_RDWR,
171 &buffer->export_fds[i]);
172 if (rc < 0) {
173 fprintf(stderr, "drmPirmeHandleToFD fail: %s\n", strerror(errno));
174 return -1;
175 }
176 }
177
178 return 0;
179}
180
181static int close_buffer(int fd, struct gem_buffer *buffer)
182{
183 int rc;
184 int i;
185 struct drm_mode_destroy_dumb destroy_dumb;
186
187 if (!buffer)
188 return -1;
189
190 for (i = 0; i < buffer->planes_count; i++)
191 close(buffer->export_fds[i]);
192
193 drmModeRmFB(fd, buffer->framebuffer_id);
194
195 memset(&destroy_dumb, 0, sizeof(destroy_dumb));
196 for (i = 0; i < buffer->planes_count; i++) {
197 destroy_dumb.handle = buffer->handles[i];
198
199 rc = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
200 if (rc < 0) {
Song Zhaoeab9c622020-05-05 21:27:00 -0700201 /* If handle was from drmPrimeFDToHandle, then fd is connected
202 * as render, we have to use drm_gem_close to release it.
203 */
204 if (errno == EACCES) {
205 struct drm_gem_close close_req;
206 close_req.handle = destroy_dumb.handle;
207 rc = drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close_req);
208 if (rc < 0) {
209 fprintf(stderr, "Unable to destroy buffer: %s\n",
210 strerror(errno));
211 return -1;
212 }
213 }
Song Zhao1b237602020-02-13 10:58:57 -0800214 }
215 }
216
217 return 0;
218}
219
220static int add_framebuffer(int fd, struct gem_buffer *buffer,
221 enum frame_format fmt, uint64_t modifier)
222{
223 uint64_t modifiers[4] = { 0, 0, 0, 0 };
224 uint32_t flags = 0;
225 unsigned int id;
226 unsigned int i;
227 int rc;
228 uint32_t drm_fmt;
229
230 if (fmt == FRAME_FMT_NV21)
231 drm_fmt = DRM_FORMAT_NV21;
232 else if (fmt == FRAME_FMT_NV12)
233 drm_fmt = DRM_FORMAT_NV12;
234 else if (fmt == FRAME_FMT_AFBC)
235 drm_fmt = DRM_FORMAT_YUYV;
236 else {
237 printf("ftm %d not supported\n", fmt);
238 return -1;
239 }
240
241 for (i = 0; i < buffer->planes_count; i++) {
242 if (buffer->handles[i] != 0 &&
243 modifier != DRM_FORMAT_MOD_NONE) {
244 flags |= DRM_MODE_FB_MODIFIERS;
245 modifiers[i] = modifier;
246 }
247 }
248
249 rc = drmModeAddFB2WithModifiers(fd, buffer->width,
250 buffer->height, drm_fmt,
251 buffer->handles, buffer->pitches,
252 buffer->offsets, modifiers, &id, flags);
253 if (rc < 0) {
254 fprintf(stderr, "Unable to add framebuffer for plane: %s\n",
255 strerror(errno));
256 return -1;
257 }
258
259 buffer->framebuffer_id = id;
260
261 return 0;
262}
263
264static int discover_properties(int fd, struct display_properties_ids *ids)
265{
266 //int connector_id = setup.connector_id;
267 int crtc_id = setup.crtc_id;
268 int plane_id = setup.plane_id;
269 drmModeObjectPropertiesPtr properties = NULL;
270 drmModePropertyPtr property = NULL;
271 struct {
272 uint32_t object_type;
273 uint32_t object_id;
274 char *name;
275 uint32_t *value;
276 } glue[] = {
277 { DRM_MODE_OBJECT_PLANE, plane_id, "FB_ID", &ids->plane_fb_id },
278 { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_ID", &ids->plane_crtc_id },
279 { DRM_MODE_OBJECT_PLANE, plane_id, "SRC_X", &ids->plane_src_x },
280 { DRM_MODE_OBJECT_PLANE, plane_id, "SRC_Y", &ids->plane_src_y },
281 { DRM_MODE_OBJECT_PLANE, plane_id, "SRC_W", &ids->plane_src_w },
282 { DRM_MODE_OBJECT_PLANE, plane_id, "SRC_H", &ids->plane_src_h },
283 { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_X", &ids->plane_crtc_x },
284 { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_Y", &ids->plane_crtc_y },
285 { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_W", &ids->plane_crtc_w },
286 { DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_H", &ids->plane_crtc_h },
287 { DRM_MODE_OBJECT_CRTC, crtc_id, "OUT_FENCE_PTR", &ids->out_fence_ptr},
288 };
289 unsigned int i, j;
290 int rc;
291
292 for (i = 0; i < ARRAY_SIZE(glue); i++) {
293 properties = drmModeObjectGetProperties(fd,
294 glue[i].object_id,
295 glue[i].object_type);
296 if (properties == NULL) {
297 fprintf(stderr, "Unable to get DRM properties(%s): %s\n",
298 glue[i].name, strerror(errno));
299 goto error;
300 }
301
302 for (j = 0; j < properties->count_props; j++) {
303 property = drmModeGetProperty(fd,
304 properties->props[j]);
305 if (property == NULL) {
306 fprintf(stderr, "Unable to get DRM property: %s\n",
307 strerror(errno));
308 goto error;
309 }
310
311 if (strcmp(property->name, glue[i].name) == 0) {
312 *glue[i].value = property->prop_id;
313 break;
314 }
315
316 drmModeFreeProperty(property);
317 property = NULL;
318 }
319
320 if (j == properties->count_props) {
321 fprintf(stderr, "Unable to find property for %s\n",
322 glue[i].name);
323 goto error;
324 }
325
326 drmModeFreeProperty(property);
327 property = NULL;
328
329 drmModeFreeObjectProperties(properties);
330 properties = NULL;
331 }
332
333 rc = 0;
334 goto complete;
335
336error:
337 rc = -1;
338
339complete:
340 if (property != NULL)
341 drmModeFreeProperty(property);
342
343 if (properties != NULL)
344 drmModeFreeObjectProperties(properties);
345
346 return rc;
347}
348
349static int add_connector_property(drmModeAtomicReq *req, uint32_t obj_id,
350 const char *name, uint64_t value, struct display_setup *setup)
351{
352 struct connector *obj = setup->connector;
353 unsigned int i;
354 int prop_id = 0;
355
356 for (i = 0 ; i < obj->props->count_props ; i++) {
357 if (strcmp(obj->props_info[i]->name, name) == 0) {
358 prop_id = obj->props_info[i]->prop_id;
359 break;
360 }
361 }
362
363 if (prop_id < 0) {
364 printf("no connector property: %s\n", name);
365 return -EINVAL;
366 }
367
368 return drmModeAtomicAddProperty(req, obj_id, prop_id, value);
369}
370
371static int add_crtc_property(drmModeAtomicReq *req, uint32_t obj_id,
372 const char *name, uint64_t value, struct display_setup *setup)
373{
374 struct crtc *obj = setup->crtc;
375 unsigned int i;
376 int prop_id = -1;
377
378 for (i = 0 ; i < obj->props->count_props ; i++) {
379 if (strcmp(obj->props_info[i]->name, name) == 0) {
380 prop_id = obj->props_info[i]->prop_id;
381 break;
382 }
383 }
384
385 if (prop_id < 0) {
386 printf("no crtc property: %s\n", name);
387 return -EINVAL;
388 }
389
390 return drmModeAtomicAddProperty(req, obj_id, prop_id, value);
391}
392
393int span(struct timeval* t1, struct timeval* t2)
394{
395 int64_t time = (t2->tv_sec - t1->tv_sec);
396 time *= 1000000;
397 time += t2->tv_usec - t1->tv_usec;
398 time /= 1000;
399 return (int)time;
400}
401
402static int page_flip(int fd, unsigned int crtc_id, unsigned int plane_id,
403 struct display_properties_ids *ids,
404 struct gem_buffer* gem_buf)
405{
406 drmModeAtomicReqPtr request;
407 uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK;
408 int rc;
409 int out_fence_fd = 0;
410 //struct timeval t1, t2;
411
412 request = drmModeAtomicAlloc();
413
414 if (!drm_mode_set) {
415 unsigned int connector_id = setup.connector_id;
416 uint32_t blob_id;
417
418 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
419 if (add_connector_property(request, connector_id, "CRTC_ID",
420 crtc_id, &setup) < 0)
421 return -1;
422
423 if (drmModeCreatePropertyBlob(fd, &setup.mode, sizeof(drmModeModeInfo),
424 &blob_id) != 0)
425 return -1;
426
427 if (add_crtc_property(request, crtc_id, "MODE_ID", blob_id, &setup) < 0)
428 return -1;
429
430 if (add_crtc_property(request, crtc_id, "ACTIVE", 1, &setup) < 0)
431 return -1;
432
433 drmModeAtomicAddProperty(request, plane_id, ids->plane_crtc_x, 0);
434 drmModeAtomicAddProperty(request, plane_id, ids->plane_crtc_y, 0);
435 drmModeAtomicAddProperty(request, plane_id, ids->plane_crtc_w,
436 setup.scaled_width);
437 drmModeAtomicAddProperty(request, plane_id, ids->plane_crtc_h,
438 setup.scaled_height);
439 drm_mode_set = 1;
440 }
441
442 drmModeAtomicAddProperty(request, plane_id, ids->plane_src_x, 0);
443 drmModeAtomicAddProperty(request, plane_id, ids->plane_src_y, 0);
444 drmModeAtomicAddProperty(request, plane_id, ids->plane_src_w,
445 gem_buf->width << 16);
446 drmModeAtomicAddProperty(request, plane_id, ids->plane_src_h,
447 gem_buf->height << 16);
448
449 drmModeAtomicAddProperty(request, plane_id, ids->plane_fb_id,
450 gem_buf->framebuffer_id);
451 drmModeAtomicAddProperty(request, plane_id, ids->plane_crtc_id,
452 crtc_id);
453 drmModeAtomicAddProperty(request, crtc_id, ids->out_fence_ptr, (unsigned long)&out_fence_fd);
454
455 rc = drmModeAtomicCommit(fd, request, flags, NULL);
456 if (rc < 0) {
457 fprintf(stderr, "Unable to flip page: %s\n", strerror(errno));
458 goto error;
459 }
460
461 //gettimeofday(&t1, NULL);
462 rc = sync_wait(out_fence_fd, 50);
463 if (rc < 0)
464 printf("wait out fence fail %d, %s\n", rc, strerror(errno));
465 else {
466 //gettimeofday(&t2, NULL);
467 //printf("%s %d span:%d\n", __func__, __LINE__, span(&t1, &t2));
468 }
469 close(out_fence_fd);
470 rc = 0;
471 goto complete;
472
473error:
474 rc = -1;
475
476complete:
477 drmModeAtomicFree(request);
478
479 return rc;
480}
481
482static uint32_t find_crtc_for_encoder(const drmModeRes *resources,
483 const drmModeEncoder *encoder) {
484 int i;
485
486 for (i = 0; i < resources->count_crtcs; i++) {
487 /* possible_crtcs is a bitmask as described here:
488 * https://dvdhrm.wordpress.com/2012/09/13/linux-drm-mode-setting-api
489 */
490 const uint32_t crtc_mask = 1 << i;
491 const uint32_t crtc_id = resources->crtcs[i];
492 if (encoder->possible_crtcs & crtc_mask) {
493 return crtc_id;
494 }
495 }
496
497 /* no match found */
498 return -1;
499}
500
501static uint32_t find_crtc_for_connector(int fd, const drmModeRes *resources,
502 const drmModeConnector *connector) {
503 int i;
504
505 for (i = 0; i < connector->count_encoders; i++) {
506 const uint32_t encoder_id = connector->encoders[i];
507 drmModeEncoder *encoder = drmModeGetEncoder(fd, encoder_id);
508
509 if (encoder) {
510 const uint32_t crtc_id = find_crtc_for_encoder(resources, encoder);
511
512 drmModeFreeEncoder(encoder);
513 if (crtc_id != 0) {
514 return crtc_id;
515 }
516 }
517 }
518
519 /* no match found */
520 return -1;
521}
522
523static int init_drm(int fd, drmModeModeInfo *mode)
524{
525 drmModeRes *resources;
526 drmModeConnector *connector = NULL;
527 drmModeEncoder *encoder = NULL;
528 int i, area;
Ao Xua3a929a2020-04-16 18:29:51 +0800529 drmModeModeInfo *curr_mode = NULL;
Song Zhao1b237602020-02-13 10:58:57 -0800530
531
532 resources = drmModeGetResources(fd);
533 if (!resources) {
534 printf("drmModeGetResources failed: %s\n", strerror(errno));
535 return -1;
536 }
537
538 /* find a connected connector: */
539 for (i = 0; i < resources->count_connectors; i++) {
540 connector = drmModeGetConnector(fd, resources->connectors[i]);
541 if (connector->connection == DRM_MODE_CONNECTED) {
542 /* it's connected, let's use this! */
543 break;
544 }
545 drmModeFreeConnector(connector);
546 connector = NULL;
547 }
548
549 if (!connector) {
550 /* we could be fancy and listen for hotplug events and wait for
551 * a connector..
552 */
553 printf("no connected connector!\n");
554 return -1;
555 }
556
557 setup.connector_id = connector->connector_id;
558
559 /* find preferred mode or the highest resolution mode: */
Song Zhao1b237602020-02-13 10:58:57 -0800560
Ao Xua3a929a2020-04-16 18:29:51 +0800561 if (*mode_str) {
562 for (i = 0; i < connector->count_modes; i++) {
563 drmModeModeInfo *current_mode = &connector->modes[i];
564
565 if (current_mode->name && strcmp(current_mode->name, mode_str) == 0) {
566 if (vfresh == 0 || current_mode->vrefresh == vfresh) {
567 curr_mode = current_mode;
568 printf("found the request mode: %s-%d.\n", current_mode->name,
569 current_mode->vrefresh);
570 break;
571 }
572 }
Song Zhao1b237602020-02-13 10:58:57 -0800573 }
Ao Xua3a929a2020-04-16 18:29:51 +0800574 }
Song Zhao1b237602020-02-13 10:58:57 -0800575
Ao Xua3a929a2020-04-16 18:29:51 +0800576 if (!curr_mode) {
577 printf("requested mode not found, using default mode!\n");
578 for (i = 0, area = 0; i < connector->count_modes; i++) {
579 drmModeModeInfo *current_mode = &connector->modes[i];
580
581 if (current_mode->type & DRM_MODE_TYPE_PREFERRED) {
582 curr_mode = current_mode;
583 break;
584 }
585
586 int current_area = current_mode->hdisplay * current_mode->vdisplay;
587 if (current_area > area) {
588 curr_mode = current_mode;
589 area = current_area;
590 }
Song Zhao1b237602020-02-13 10:58:57 -0800591 }
592 }
593
594 if (!curr_mode) {
595 printf("could not find mode!\n");
596 return -1;
597 }
598
599 memcpy(mode, curr_mode, sizeof(drmModeModeInfo));
600
601 /* find encoder: */
602 for (i = 0; i < resources->count_encoders; i++) {
603 encoder = drmModeGetEncoder(fd, resources->encoders[i]);
604 if (encoder->encoder_id == connector->encoder_id)
605 break;
606 drmModeFreeEncoder(encoder);
607 encoder = NULL;
608 }
609
610 if (encoder) {
611 setup.crtc_id = encoder->crtc_id;
612 } else {
613 uint32_t crtc_id1 = find_crtc_for_connector(fd, resources, connector);
614 setup.crtc_id = crtc_id1;
615 }
616
617 drmModeFreeResources(resources);
618
619 return 0;
620}
621
622static int OsdBufferCreate(int fd, uint32_t width,
623 uint32_t height, struct gem_buffer *buffer) {
624 int rc;
625 uint32_t flags = 0;
626 void *data;
627 struct drm_mode_create_dumb create_dumb;
628 uint64_t modifiers[4] = { 0, 0, 0, 0 };
629 struct drm_mode_map_dumb map_dumb;
630
631 memset(&create_dumb, 0, sizeof(create_dumb));
632 create_dumb.width = width;
633 create_dumb.height = height;
634 create_dumb.bpp = 32;
635
636 rc = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
637 if (rc < 0) {
638 printf("Unable to create dumb buffer: %s\n", strerror(errno));
639 return -1;
640 }
641
642 buffer->size = create_dumb.size;
643 buffer->pitches[0] = create_dumb.pitch;
644 buffer->offsets[0] = 0;
645 buffer->handles[0] = create_dumb.handle;
646
647 rc = drmModeAddFB2WithModifiers(fd, width, height, DRM_FORMAT_ARGB8888,
648 buffer->handles, buffer->pitches,
649 buffer->offsets, modifiers, &buffer->framebuffer_id, flags);
650 if (rc < 0) {
651 printf("Unable to add framebuffer for osd plane: %s\n", strerror(errno));
652 return -1;
653 }
654
655 memset(&map_dumb, 0, sizeof(map_dumb));
656 map_dumb.handle = buffer->handles[0];
657 rc = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb);
658 if (rc < 0) {
659 printf("Unable to map buffer: %s\n", strerror(errno));
660 return -1;
661 }
662
663 data = mmap(0, buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
664 map_dumb.offset);
665 if (data == MAP_FAILED) {
666 printf("Unable to mmap buffer: %s\n", strerror(errno));
667 return -1;
668 }
669
670 /* make it transparent */
671 memset(data, 0, buffer->size);
672
673 munmap(data, buffer->size);
674 return 0;
675}
676
677int config_sys_node(const char* path, const char* value)
678{
679 int fd;
680 /* enable video plane */
681 fd = open(path, O_RDWR);
682 if (fd < 0) {
683 printf("fail to open %s\n", path);
684 return -1;
685 }
686 if (write(fd, value, strlen(value)) != 1) {
687 printf("fail to write %s to %s\n", value, path);
688 return -1;
689 }
690 close(fd);
691
692 return 0;
693}
694
Song Zhao6c7d1f82020-04-06 23:22:49 -0700695int display_engine_start(int smode)
Song Zhao1b237602020-02-13 10:58:57 -0800696{
697 unsigned int plane_id;
698 drmModeModeInfo mode;
699 int rc;
700
Song Zhao6c7d1f82020-04-06 23:22:49 -0700701 secure_mode = smode;
702
Song Zhao1b237602020-02-13 10:58:57 -0800703 drm_fd = drmOpen("meson", drm_master_dev_name);
704 if (drm_fd < 0) {
705 printf("Unable to open DRM node: %s\n",
706 strerror(errno));
707 return -1;
708 }
709
710 drm_cli_fd = drmOpen("meson", drm_cli_dev_name);
711 if (drm_cli_fd < 0) {
712 printf("Unable to open client DRM node: %s\n",
713 strerror(errno));
714 return -1;
715 }
716
717 rc = drmSetClientCap(drm_fd, DRM_CLIENT_CAP_ATOMIC, 1);
718 if (rc < 0) {
719 fprintf(stderr, "Unable to set DRM atomic capability: %s\n",
720 strerror(errno));
721 return -1;
722 }
723
724 rc = drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
725 if (rc < 0) {
726 fprintf(stderr,
727 "Unable to set DRM universal planes capability: %s\n",
728 strerror(errno));
729 return -1;
730 }
731
732 /* prepare all connectors and CRTCs */
733 rc = init_drm(drm_fd, &mode);
734 if (rc) {
735 fprintf(stderr, "modeset_prepare fail\n");
736 return -1;
737 }
738
739 plane_id = global_plane_id;
740 if (rc < 0) {
741 printf("Unable to select DRM plane for CRTC %d\n",
742 setup.crtc_id);
743 return -1;
744 }
745
746 setup.crtc_width = mode.hdisplay;
747 setup.crtc_height = mode.vdisplay;
748 setup.scaled_width = mode.hdisplay;
749 setup.scaled_height = mode.vdisplay;
750
751 memcpy(&setup.mode, &mode, sizeof(drmModeModeInfo));
752 setup.plane_id = plane_id;
753
754 printf("plane: %u, crtc: %u, encoder:%u, connector: %u.\n",
755 setup.plane_id, setup.crtc_id,
756 setup.encoder_id, setup.connector_id);
757
758 rc = discover_properties(drm_fd, &setup.properties_ids);
759 if (rc < 0) {
760 fprintf(stderr, "Unable to discover DRM properties\n");
761 return -1;
762 }
763
764 setup.plane = calloc(1, sizeof(struct plane));
765 setup.crtc = calloc(1, sizeof(struct crtc));
766 setup.connector = calloc(1, sizeof(struct connector));
767
768#define get_resource(type, Type, id) do { \
769 setup.type->type = drmModeGet##Type(drm_fd, id); \
770 if (!setup.type->type) { \
771 printf("could not get %s %i: %s\n", \
772#type, id, strerror(errno)); \
773 return -1; \
774 } \
775} while (0)
776
777 get_resource(plane, Plane, setup.plane_id);
778 get_resource(crtc, Crtc, setup.crtc_id);
779 get_resource(connector, Connector, setup.connector_id);
780
781#define get_properties(type, TYPE, id) do { \
782 uint32_t i; \
783 setup.type->props = drmModeObjectGetProperties(drm_fd, \
784 id, DRM_MODE_OBJECT_##TYPE); \
785 if (!setup.type->props) { \
786 printf("could not get %s %u properties: %s\n", \
787#type, id, strerror(errno)); \
788 return -1; \
789 } \
790 setup.type->props_info = calloc(setup.type->props->count_props, \
791 sizeof(setup.type->props_info)); \
792 for (i = 0; i < setup.type->props->count_props; i++) { \
793 setup.type->props_info[i] = drmModeGetProperty(drm_fd, \
794 setup.type->props->props[i]); \
795 } \
796} while (0)
797
798 get_properties(plane, PLANE, setup.plane_id);
799 get_properties(crtc, CRTC, setup.crtc_id);
800 get_properties(connector, CONNECTOR, setup.connector_id);
801
Song Zhao1b237602020-02-13 10:58:57 -0800802 /* make osd transparent */
803 rc = OsdBufferCreate(drm_cli_fd, setup.crtc_width, setup.crtc_height, &osd_gem_buf);
804 if (rc) {
805 printf("OsdBufferCreate fail %d\n", rc);
806 return -1;
807 }
808 rc = drmModeSetCrtc(drm_fd, setup.crtc_id, osd_gem_buf.framebuffer_id, 0, 0,
809 &setup.connector_id, 1, &setup.mode);
810 if (rc) {
811 printf("drmModeSetCrtc fail %d\n", rc);
812 return -1;
813 }
814 return 0;
815}
816
817static int frame_destroy(struct drm_frame* drm_f)
818{
819 int rc;
820 struct gem_buffer *gem_buf = drm_f->gem;
821
822 rc = close_buffer(drm_cli_fd, gem_buf);
823 free(gem_buf);
824 free(drm_f);
825 return rc;
826}
827
828struct drm_frame* display_create_buffer(unsigned int width, unsigned int height,
829 enum frame_format format, int planes_count)
830{
831 int rc;
832 struct drm_frame* frame = calloc(1, sizeof(*frame));
833 struct gem_buffer *gem_buf = calloc(1, sizeof(*gem_buf));
834
835 if (!frame || !gem_buf) {
836 printf("oom\n");
837 return NULL;
838 }
839
840 gem_buf->width = width;
841 gem_buf->height = height;
842 frame->gem = gem_buf;
843 frame->destroy = frame_destroy;
844
845 gem_buf->planes_count = planes_count;
846
847 rc = create_meson_gem_buffer(drm_cli_fd, format, gem_buf);
848 if (rc < 0) {
849 printf("create_meson_gem_buffer fail %d\n", rc);
850 goto error;
851 }
852 if (planes_count == 2)
853 printf("export_fd: %d/%d\n",
854 gem_buf->export_fds[0],
855 gem_buf->export_fds[1]);
856 else
857 printf("export_fd: %d\n",
858 gem_buf->export_fds[0]);
859
860 rc = add_framebuffer(drm_cli_fd, gem_buf,
861 format, DRM_FORMAT_MOD_NONE);
862 if (rc < 0) {
863 printf("Unable to add DRM framebuffer\n");
864 goto error;
865 }
866
867 return frame;
868error:
869 close_buffer(drm_cli_fd, gem_buf);
870 if (frame) free(frame);
871 if (gem_buf) free(gem_buf);
872 return NULL;
873}
874
875int display_get_buffer_fds(struct drm_frame* drm_f, int *fd, int cnt)
876{
877 int i;
878 struct gem_buffer *gem_buf = drm_f->gem;
879
880 if (gem_buf->planes_count > cnt || !fd) {
881 return -1;
882 }
883 for (i = 0; i < gem_buf->planes_count; i++)
884 fd[i] = gem_buf->export_fds[i];
885 return 0;
886}
887
888int display_engine_stop()
889{
890 aml_dis.started = false;
891 pthread_join(aml_dis.disp_t, NULL);
892 close_buffer(drm_cli_fd, &osd_gem_buf);
893
894 if (aml_dis.queue)
895 free(aml_dis.queue);
896 if (gem_buf)
897 free(gem_buf);
898 if (setup.plane) {
899 if (setup.plane->props_info)
900 free(setup.plane->props_info);
901 free(setup.plane);
902 }
903 if (setup.crtc) {
904 if (setup.crtc->props_info)
905 free(setup.crtc->props_info);
906 free(setup.crtc);
907 }
908 if (setup.connector) {
909 if (setup.connector->props_info)
910 free(setup.connector->props_info);
911 free(setup.connector);
912 }
913 if (drm_fd >= 0)
914 drmClose(drm_fd);
915 if (drm_cli_fd >= 0)
916 drmClose(drm_cli_fd);
917
918 return 0;
919}
920
921static int queue_frame(struct drm_frame* frame)
922{
923 if (aml_dis.total_num == aml_dis.q_len)
924 return -1;
925 aml_dis.queue[aml_dis.wi] = *frame;
926 if (aml_dis.wi == aml_dis.q_len - 1)
927 aml_dis.wi = 0;
928 else
929 aml_dis.wi++;
930 aml_dis.total_num++;
931
932 return 0;
933}
934
935static int dequeue_frame(struct drm_frame* frame)
936{
937 if (!aml_dis.total_num)
938 return -1;
939 *frame = aml_dis.queue[aml_dis.ri];
940 if (aml_dis.ri == aml_dis.q_len - 1)
941 aml_dis.ri = 0;
942 else
943 aml_dis.ri++;
944 aml_dis.total_num--;
945
946 return 0;
947}
948
949static void * display_thread_func(void * arg)
950{
951 struct drm_frame f, f_p1, f_p2;
952 unsigned int fence_num;
953
954 f.pri_dec = NULL;
955 f_p1.pri_dec = NULL;
956 f_p2.pri_dec = NULL;
957
958 while (aml_dis.started) {
959 int rc;
960 struct gem_buffer* gem_buf;
961
962 rc = dequeue_frame(&f);
963 if (rc) {
964 usleep(10);
965 continue;
966 }
967 gem_buf = f.gem;
968
969 rc = page_flip(drm_fd, setup.crtc_id, setup.plane_id,
970 &setup.properties_ids, gem_buf);
971 if (rc) {
972 printf("page_flip error\n");
973 continue;
974 }
975 fence_num++;
976 /* 2 fence delay on video layer, 1 fence delay on osd */
977 if (f_p2.pri_dec) {
978 display_cb(f_p2.pri_dec);
979 }
980
981 f_p2 = f_p1;
982 f_p1 = f;
983 }
984 return NULL;
985}
986
987int display_engine_show(struct drm_frame* frame)
988{
989 int rc;
990
991 if (!aml_dis.started) {
992 aml_dis.queue = (struct drm_frame*)calloc(MAX_BUF_SIZE, sizeof(*aml_dis.queue));
993 if (!aml_dis.queue) {
994 printf("%s OOM\n", __func__);
995 return -1;
996 }
997 aml_dis.q_len = MAX_BUF_SIZE;
998 aml_dis.ri = aml_dis.wi = aml_dis.total_num = 0;
999 aml_dis.started = true;
1000
1001 rc = pthread_create(&aml_dis.disp_t, NULL, display_thread_func, NULL);
1002 if (rc) {
1003 printf("create dispay thread fails\n");
1004 return -1;
1005 }
1006 }
1007
1008 while (aml_dis.started) {
1009 if (queue_frame(frame)) {
1010 usleep(10);
1011 continue;
1012 } else
1013 break;
1014 }
1015
1016 return 0;
1017}
1018
1019int display_engine_register_cb(displayed_cb_func cb)
1020{
1021 display_cb = cb;
1022 return 0;
1023}
1024
1025int display_wait_for_display()
1026{
1027 while (aml_dis.started && aml_dis.total_num) {
1028 usleep(10);
1029 }
1030 if (!aml_dis.started)
1031 return -1;
1032
1033 return 0;
1034}