blob: 6ee177c32e1fd609e5aea9b40222751a90445e19 [file] [log] [blame]
limin.tian79bf2b12023-02-24 10:28:26 +00001 /*
2 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
Ao Xu6747bbd2020-09-28 20:02:09 +08003 *
limin.tian79bf2b12023-02-24 10:28:26 +00004 * 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:
Ao Xu6747bbd2020-09-28 20:02:09 +08008 */
9
limin.tian79bf2b12023-02-24 10:28:26 +000010
Ao Xu6747bbd2020-09-28 20:02:09 +080011#include <stdio.h>
12#include <fcntl.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <stddef.h>
16#include <drm_fourcc.h>
17#include "meson_drm_util.h"
18
19#define MAX_OSD_PLANE 6
20#define MAX_VIDEO_PLANE 4
21#define MAX_CONNECTOR 3
22#define MAX_CRTC 3
23
24struct kms_display;
25
chen.wang1bace1312023-01-18 16:13:54 +080026
Ao Xu6747bbd2020-09-28 20:02:09 +080027#define VOID2U64(x) ((uint64_t)(unsigned long)(x))
28#define container_of(ptr, type, member) \
29 (type *)((char *)(ptr) - (char *) &((type *)0)->member)
30
31#define to_kms_display(x) container_of(x, struct kms_display, base)
32
33struct property {
34 uint32_t id;
35 uint64_t value;
36};
37
38struct crtc_state {
39 uint32_t id;
40
41 struct property mode_id;
42 struct property active;
43 struct property out_fence;
44 struct property video_out_fence;
45};
46
47struct connector_state {
48 uint32_t id;
49 uint32_t crtc_mask;
50 drmModeModeInfo mode;
51
52 struct property crtc_id;
53};
54
55struct plane_state {
56 uint32_t id;
57 uint32_t crtc_mask;
58
59 struct property crtc_id;
60 struct property crtc_x;
61 struct property crtc_y;
62 struct property crtc_w;
63 struct property crtc_h;
64 struct property fb_id;
65 struct property src_x;
66 struct property src_y;
67 struct property src_w;
68 struct property src_h;
Ao Xu6747bbd2020-09-28 20:02:09 +080069 struct property type;
70 struct property in_fence_fd;
71 struct property in_formats;
72};
73
Ao Xu6747bbd2020-09-28 20:02:09 +080074struct kms_display {
75 struct drm_display base;
76
Ao Xu6747bbd2020-09-28 20:02:09 +080077 int num_crtc;
78 struct crtc_state *crtc_states[MAX_CRTC];
79 int num_connector;
80 struct connector_state *conn_states[MAX_CONNECTOR];
81 int num_osd_plane;
82 struct plane_state *osd_states[MAX_OSD_PLANE];
83 int num_vid_plane;
84 struct plane_state *vid_states[MAX_OSD_PLANE];
85
86 int mode_set;
87};
88
89static void kms_destroy_display(struct drm_display *drm_disp)
90{
Ao Xu70554242020-10-15 15:19:48 +080091 int i;
Ao Xu6747bbd2020-09-28 20:02:09 +080092 struct kms_display *disp = to_kms_display(drm_disp);
Ao Xu70554242020-10-15 15:19:48 +080093 close(drm_disp->drm_fd);
limin.tian79bf2b12023-02-24 10:28:26 +000094 close(drm_disp->dev->render_fd);
Ao Xu70554242020-10-15 15:19:48 +080095 meson_device_destroy(drm_disp->dev);
96
97 for (i = 0; i < MAX_CRTC; i++) {
98 if (disp->crtc_states[i])
99 free(disp->crtc_states[i]);
100 }
101
102 for (i = 0; i < MAX_CONNECTOR; i++) {
103 if (disp->conn_states[i])
104 free(disp->conn_states[i]);
105 }
106
107 for (i = 0; i < MAX_OSD_PLANE; i++) {
108 if (disp->osd_states[i])
109 free(disp->osd_states[i]);
110 }
111
112 for (i = 0; i < MAX_OSD_PLANE; i++) {
113 if (disp->vid_states[i])
114 free(disp->vid_states[i]);
115 }
116
Ao Xu6747bbd2020-09-28 20:02:09 +0800117 free(disp);
118}
119
Ao Xu6747bbd2020-09-28 20:02:09 +0800120static int free_buf(struct drm_display *drm_disp, struct drm_buf *buf)
121{
wenlong.zhanga71a2e02022-06-14 15:58:53 +0800122 int i, fd, ret;
Ao Xu6747bbd2020-09-28 20:02:09 +0800123 struct drm_mode_destroy_dumb destroy_dumb;
124
125 for ( i = 0; i < buf->nbo; i++)
126 close(buf->fd[i]);
127
chen.wang1bace1312023-01-18 16:13:54 +0800128 fd = drm_disp->alloc_only ? drm_disp->dev->render_fd : drm_disp->dev->fd;
Ao Xu6747bbd2020-09-28 20:02:09 +0800129 drmModeRmFB(drm_disp->drm_fd, buf->fb_id);
130 memset(&destroy_dumb, 0, sizeof(destroy_dumb));
131
132 for ( i = 0; i < buf->nbo; i++) {
133 destroy_dumb.handle = meson_bo_handle(buf->bos[i]);
134
wenlong.zhanga71a2e02022-06-14 15:58:53 +0800135 ret = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
Ao Xu6747bbd2020-09-28 20:02:09 +0800136 if (ret < 0) {
137 /* If handle was from drmPrimeFDToHandle, then fd is connected
138 * as render, we have to use drm_gem_close to release it.
139 */
140 if (errno == EACCES) {
141 struct drm_gem_close close_req;
142 close_req.handle = destroy_dumb.handle;
wenlong.zhanga71a2e02022-06-14 15:58:53 +0800143 ret = drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close_req);
Ao Xu6747bbd2020-09-28 20:02:09 +0800144 if (ret < 0) {
145 fprintf(stderr, "Unable to destroy buffer: %s\n",
146 strerror(errno));
147 return -1;
148 }
149 }
150 }
chen.wang1bace1312023-01-18 16:13:54 +0800151 meson_bo_destroy(buf->bos[i]);
Ao Xu6747bbd2020-09-28 20:02:09 +0800152 }
chen.wang1bace1312023-01-18 16:13:54 +0800153 free(buf);
Ao Xu6747bbd2020-09-28 20:02:09 +0800154 return 0;
155}
156static int kms_free_bufs(struct drm_display *drm_disp)
157{
158 int i;
159 struct drm_buf *buf;
Ao Xu6747bbd2020-09-28 20:02:09 +0800160 for ( i = 0; i < drm_disp->nbuf; i++ ) {
161 buf = &drm_disp->bufs[i];
162 free_buf(drm_disp, buf);
163 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800164 return 0;
165}
166
167static int kms_free_buf(struct drm_buf *buf)
168{
169 free_buf(buf->disp, buf);
170 return 0;
171}
172
Ao Xu70554242020-10-15 15:19:48 +0800173static struct meson_bo *alloc_bo(struct drm_display *drm_disp, struct drm_buf *buf, uint32_t bpp, uint32_t width,
174 uint32_t height, uint32_t *bo_handle, uint32_t *pitch)
175{
176 uint32_t size;
177 struct meson_bo *bo;
178
179 size = width * height * bpp / 8;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800180 bo = meson_bo_create(drm_disp->dev, size, buf->flags, drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800181 if (bo) {
182 *bo_handle = meson_bo_handle(bo);
183 *pitch = width * bpp / 8;
184 return bo;
185 } else {
186 fprintf(stderr, "meson_bo_create fail\n");
187 return NULL;
188 }
189}
190
191static int alloc_bos(struct drm_display *drm_disp, struct drm_buf *buf, uint32_t *bo_handles)
192{
193 uint32_t width = buf->width;
194 uint32_t height = buf->height;
195
196 switch (buf->fourcc) {
197 case DRM_FORMAT_ARGB8888:
198 buf->nbo = 1;
199 buf->bos[0] = alloc_bo(drm_disp, buf, 32, width, height, &bo_handles[0], &buf->pitches[0]);
200 if (!buf->bos[0]) {
201 fprintf(stderr, "alloc_bo argb888 fail\n");
202 return -1;
203 }
204
205 buf->size = width * height * 4;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800206 buf->fd[0] = meson_bo_dmabuf(buf->bos[0], drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800207 break;
208 case DRM_FORMAT_UYVY:
209 case DRM_FORMAT_YUYV:
210 buf->nbo = 1;
211 buf->bos[0] = alloc_bo(drm_disp, buf, 16, width, height, &bo_handles[0], &buf->pitches[0]);
212 if (!buf->bos[0]) {
213 fprintf(stderr, "alloc_bo yuyv or uyvy fail\n");
214 return -1;
215 }
216
217 buf->size = width * height * 2;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800218 buf->fd[0] = meson_bo_dmabuf(buf->bos[0], drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800219 buf->commit_to_video = 1;
220 break;
221 case DRM_FORMAT_NV12:
222 case DRM_FORMAT_NV21:
223 buf->nbo = 2;
224 buf->bos[0] = alloc_bo(drm_disp, buf, 8, width, height, &bo_handles[0], &buf->pitches[0]);
225 if (!buf->bos[0]) {
226 fprintf(stderr, "alloc_bo nv12 or nv21 fail\n");
227 return -1;
228 }
229
wenlong.zhang4c011d42022-06-09 10:59:38 +0800230 buf->fd[0] = meson_bo_dmabuf(buf->bos[0], drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800231
232 buf->bos[1] = alloc_bo(drm_disp, buf, 16, width/2, height/2, &bo_handles[1], &buf->pitches[1]);
233 if (!buf->bos[1]) {
234 fprintf(stderr, "alloc_bo argb888 fail\n");
235 return -1;
236 }
wenlong.zhang4c011d42022-06-09 10:59:38 +0800237 buf->fd[1] = meson_bo_dmabuf(buf->bos[1], drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800238 buf->size = width * height * 3 / 2;
239 buf->commit_to_video = 1;
240 break;
241 default:
242 fprintf(stderr, "unsupport format: 0x%08x\n", buf->fourcc);
243 break;
244 }
245
246 return 0;
247}
248
249static int add_framebuffer(int fd, struct drm_buf *buf, uint32_t *bo_handles, uint64_t modifier)
250{
251 int i, ret;
252 uint64_t modifiers[4] = { 0, 0, 0, 0 };
253 uint32_t flags = 0;
254 uint32_t fb_id;
255
256 for ( i = 0; i < buf->nbo; i++) {
257 if (bo_handles[i] != 0 && modifier != DRM_FORMAT_MOD_NONE) {
258 flags |= DRM_MODE_FB_MODIFIERS;
259 modifiers[i] = modifier;
260 }
261 }
262
263 ret = drmModeAddFB2WithModifiers(fd, buf->width, buf->height, buf->fourcc,
264 bo_handles, buf->pitches, buf->offsets, modifiers, &fb_id, flags);
265 if (ret < 0) {
266 fprintf(stderr, "Unable to add framebuffer for plane: %s\n", strerror(errno));
267 return -1;
268 }
269
270 buf->fb_id = fb_id;
271 return 0;
272}
273
274static struct drm_buf *kms_alloc_buf(struct drm_display *drm_disp, struct drm_buf_metadata *info)
275{
276 int ret;
277 struct drm_buf *buf = NULL;
278 uint32_t bo_handles[4] = {0};
279
280 buf = calloc(1, sizeof(*buf));
281 buf->fourcc = info->fourcc;
282 buf->width = info->width;
283 buf->height = info->height;
284 buf->flags = info->flags;
285 buf->fence_fd = -1;
286 buf->disp = drm_disp;
287
288 ret = alloc_bos(drm_disp, buf, bo_handles);
289 if (ret) {
290 fprintf(stderr, "alloc_bos fail\n");
291 free(buf);
292 return NULL;
293 }
294
chen.wang1bace1312023-01-18 16:13:54 +0800295 /*for non-root users, just need alloc buf and don't need to add framebuffer*/
296 if (drm_disp->alloc_only)
297 return buf;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800298
Ao Xu70554242020-10-15 15:19:48 +0800299 ret = add_framebuffer(drm_disp->drm_fd, buf, bo_handles, DRM_FORMAT_MOD_NONE);
300 if (ret) {
chen.wang1bace1312023-01-18 16:13:54 +0800301 fprintf(stderr, "add_framebuffer fail, call free_buf\n");
Ao Xu70554242020-10-15 15:19:48 +0800302 free_buf(drm_disp, buf);
Ao Xu70554242020-10-15 15:19:48 +0800303 return NULL;
304 }
305
306 return buf;
307}
308
309static int kms_alloc_bufs(struct drm_display *drm_disp, int num, struct drm_buf_metadata *info)
310{
311 int i, ret;
312 struct drm_buf *buf;
313 uint32_t bo_handles[4] = {0};
314
315 drm_disp->bufs = calloc(num, sizeof(*drm_disp->bufs));
316 drm_disp->nbuf = num;
317
318 for ( i = 0; i < num; i++) {
319 buf = &drm_disp->bufs[i];
320 buf->fourcc = info->fourcc;
321 buf->width = info->width;
322 buf->height = info->height;
323 buf->flags = info->flags;
324 buf->fence_fd = -1;
325 buf->disp = drm_disp;
326
327 if (!info->fourcc)
328 buf->fourcc = DRM_FORMAT_ARGB8888;
329
330 switch (buf->fourcc) {
331 case DRM_FORMAT_ARGB8888:
332 buf->nbo = 1;
333 break;
334 case DRM_FORMAT_UYVY:
335 case DRM_FORMAT_YUYV:
336 buf->nbo = 1;
337 break;
338 case DRM_FORMAT_NV12:
339 case DRM_FORMAT_NV21:
340 buf->nbo = 2;
341 break;
342 default:
343 fprintf(stderr, "unsupport format: 0x%08x\n", buf->fourcc);
344 break;
345 }
346
347 ret = alloc_bos(drm_disp, buf, bo_handles);
348 if (ret) {
349 fprintf(stderr, "alloc_bos fail\n");
350 return -1;
351 }
352
353 ret = add_framebuffer(drm_disp->drm_fd, buf, bo_handles, DRM_FORMAT_MOD_NONE);
354 if (ret) {
355 fprintf(stderr, "add_framebuffer fail\n");
356 free_buf(drm_disp, buf);
357 return -1;
358 }
359 }
360 return 0;
361}
362
363static struct drm_buf *kms_import_buf(struct drm_display *disp, struct drm_buf_import *info)
364{
365 int i;
366 uint32_t size;
367 struct drm_buf *buf = NULL;
368 uint32_t bo_handles[4] = {0};
369
370 buf = calloc(1, sizeof(*buf));
371 buf->fourcc = info->fourcc;
372 buf->width = info->width;
373 buf->height = info->height;
374 buf->flags = info->flags;
375 buf->fence_fd = -1;
376 buf->disp = disp;
377
378 if (!info->fourcc)
379 buf->fourcc = DRM_FORMAT_ARGB8888;
380
381 switch (buf->fourcc) {
382 case DRM_FORMAT_ARGB8888:
383 buf->nbo = 1;
384 break;
385 case DRM_FORMAT_UYVY:
386 case DRM_FORMAT_YUYV:
387 buf->nbo = 1;
388 break;
389 case DRM_FORMAT_NV12:
390 case DRM_FORMAT_NV21:
391 buf->nbo = 2;
392 break;
393 default:
394 fprintf(stderr, "unsupport format: 0x%08x\n", buf->fourcc);
395 break;
396 }
397
398 for (i = 0; i < buf->nbo; i++) {
399 if ( i == 0 )
400 size = info->width * info->height;
401 else
402 size = info->width * info->height / 2;
403
404 buf->size += size;
405 buf->fd[i] = info->fd[i];
406 buf->pitches[i] = buf->width;
407 buf->bos[i] = meson_bo_import(disp->dev, info->fd[i], size, info->flags);
408 if (!buf->bos[i]) {
409 fprintf(stderr, "meson_bo_import fail\n");
410 return NULL;
411 }
412
413 bo_handles[i] = meson_bo_handle(buf->bos[i]);
414 }
415
416 add_framebuffer(disp->drm_fd, buf, bo_handles, DRM_FORMAT_MOD_NONE);
417
418 return buf;
419}
420
Ao Xu6747bbd2020-09-28 20:02:09 +0800421static int kms_post_buf(struct drm_display *drm_disp, struct drm_buf *buf)
422{
423 int ret;
424 drmModeAtomicReqPtr request;
Ao Xu6747bbd2020-09-28 20:02:09 +0800425 uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK;
426 struct kms_display *disp = to_kms_display(drm_disp);
427
428 struct plane_state *plane_state;
429 struct crtc_state *crtc_state;
430 struct connector_state *conn_state;
431
432 conn_state = disp->conn_states[0];
433 crtc_state = disp->crtc_states[0];
434
sky zhouf05ca462020-10-29 18:07:40 +0800435 if (buf->flags & MESON_USE_VD1)
Ao Xu6747bbd2020-09-28 20:02:09 +0800436 plane_state = disp->vid_states[0];
sky zhouf05ca462020-10-29 18:07:40 +0800437 else if (buf->flags & MESON_USE_VD2)
Ao Xu6747bbd2020-09-28 20:02:09 +0800438 plane_state = disp->vid_states[1];
439 else
440 plane_state = disp->osd_states[0];
441
442 request = drmModeAtomicAlloc();
443
sky zhouf05ca462020-10-29 18:07:40 +0800444#if 0
Ao Xu6747bbd2020-09-28 20:02:09 +0800445 if (!disp->mode_set) {
Ao Xu6747bbd2020-09-28 20:02:09 +0800446 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
447 drmModeAtomicAddProperty(request, conn_state->id, conn_state->crtc_id.id, crtc_state->id);
448
449 if (drmModeCreatePropertyBlob(drm_disp->drm_fd, &disp->conn_states[0]->mode,
450 sizeof(drmModeModeInfo), &blob_id) != 0 ) {
451 return -1;
452 }
453 drmModeAtomicAddProperty(request, crtc_state->id, crtc_state->mode_id.id, blob_id);
454 drmModeAtomicAddProperty(request, crtc_state->id, crtc_state->active.id, 1);
455
456 disp->mode_set = 1;
457 }
sky zhouf05ca462020-10-29 18:07:40 +0800458#else
459 /*No modeset needed in post buf, modeset will control by systemservice.*/
460#endif
Ao Xu6747bbd2020-09-28 20:02:09 +0800461
Ao Xub3689892020-11-09 18:57:56 +0800462 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_x.id, buf->crtc_x);
463 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_y.id, buf->crtc_y);
Ao Xu70554242020-10-15 15:19:48 +0800464 if (buf->crtc_w == 0) {
465 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_w.id, conn_state->mode.hdisplay);
466 } else {
467 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_w.id, buf->crtc_w);
468 }
469
470 if (buf->crtc_h == 0) {
471 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_h.id, conn_state->mode.vdisplay);
472 } else {
473 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_h.id, buf->crtc_h);
474 }
475
Ao Xu2b6aec52020-12-15 14:24:21 +0800476 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_x.id, buf->src_x << 16);
477 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_y.id, buf->src_y << 16);
yujun.zhang54c6eda2021-12-30 12:24:49 +0800478 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_w.id, buf->src_w << 16);
479 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_h.id, buf->src_h << 16);
Ao Xu6747bbd2020-09-28 20:02:09 +0800480 drmModeAtomicAddProperty(request, plane_state->id, plane_state->fb_id.id, buf->fb_id);
481 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_id.id, crtc_state->id);
482#if 0
483 if (buf->flags | (MESON_USE_VD2 | MESON_USE_VD1))
484 drmModeAtomicAddProperty(request, crtc_state->id, crtc_state->video_out_fence.id, VOID2U64(&buf->fence_fd));
485 else
486 drmModeAtomicAddProperty(request, crtc_state->id, crtc_state->out_fence.id, VOID2U64(&buf->fence_fd));
487#endif
sky zhouf05ca462020-10-29 18:07:40 +0800488
489 ret = drmModeAsyncAtomicCommit(drm_disp->drm_fd, request, flags, NULL);
Ao Xu6747bbd2020-09-28 20:02:09 +0800490 if (ret < 0) {
491 fprintf(stderr, "Unable to flip page: %s\n", strerror(errno));
492 goto error;
493 }
494
495 ret = 0;
496 goto complete;
497
498error:
499 ret = -1;
500complete:
501 drmModeAtomicFree(request);
502
503 return ret;
504}
505
506static void getproperty(int drm_fd, drmModeObjectProperties* props, const char *name,
507 struct property *p)
508{
509 int i;
510 drmModePropertyRes *res;
511 for (i = 0; i < props->count_props; i++) {
512 res = drmModeGetProperty(drm_fd, props->props[i]);
Ao Xu70554242020-10-15 15:19:48 +0800513 if (res && !strcmp(name, res->name)) {
514 p->id = res->prop_id;
515 p->value = props->prop_values[i];
516 //fprintf(stdout, "getproperty: %s, id: %u, value: %llu \n", res->name, p->id, p->value);
517 }
Ao Xu70554242020-10-15 15:19:48 +0800518 drmModeFreeProperty(res);
Ao Xu6747bbd2020-09-28 20:02:09 +0800519 }
520}
521
522static int populate_connectors(drmModeRes *resources, struct kms_display *disp)
523{
Ao Xu70554242020-10-15 15:19:48 +0800524 int i, j;
Ao Xu6747bbd2020-09-28 20:02:09 +0800525 int num_connector = 0;
526 struct connector_state *state;
527 drmModeConnector *connector;
528 drmModeEncoder *encoder;
529 drmModeObjectProperties *props;
530
531 for (i = 0; i < resources->count_connectors; i++) {
532 connector = drmModeGetConnector(disp->base.drm_fd, resources->connectors[i]);
Ao Xu70554242020-10-15 15:19:48 +0800533 if (!connector) {
534 fprintf(stderr, "drmModeGetConnector fail.\n");
535 continue;
536 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800537
chen.wang1bace1312023-01-18 16:13:54 +0800538 if (connector->connector_type == DRM_MODE_CONNECTOR_TV) {
539 drmModeFreeConnector(connector);
Ao Xu6747bbd2020-09-28 20:02:09 +0800540 continue;
chen.wang1bace1312023-01-18 16:13:54 +0800541 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800542 state = calloc(1, sizeof(*state));
543 disp->conn_states[num_connector++] = state;
544 state->id = resources->connectors[i];
545
546 for (j = 0; j < connector->count_encoders; j++) {
547 encoder = drmModeGetEncoder(disp->base.drm_fd, connector->encoders[j]);
Ao Xu70554242020-10-15 15:19:48 +0800548 if (encoder) {
549 state->crtc_mask |= encoder->possible_crtcs;
550 drmModeFreeEncoder(encoder);
551 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800552 }
553
554 if (connector->count_modes)
555 state->mode = connector->modes[0];
556
557 for (j = 0; j < connector->count_modes; j++) {
558 if (connector->modes[j].type & DRM_MODE_TYPE_PREFERRED) {
559 state->mode = connector->modes[j];
560 break;
561 }
562 }
563
564 disp->base.width = state->mode.hdisplay;
565 disp->base.height = state->mode.vdisplay;
566 disp->base.vrefresh = state->mode.vrefresh;
567
568 props = drmModeObjectGetProperties(disp->base.drm_fd, resources->connectors[i], DRM_MODE_OBJECT_CONNECTOR);
Ao Xu6747bbd2020-09-28 20:02:09 +0800569 getproperty(disp->base.drm_fd, props, "CRTC_ID", &state->crtc_id);
Ao Xu70554242020-10-15 15:19:48 +0800570
571 if (props)
572 drmModeFreeObjectProperties(props);
573
574 if (connector)
575 drmModeFreeConnector(connector);
Ao Xu6747bbd2020-09-28 20:02:09 +0800576 }
577
578 disp->num_connector = num_connector;
579 fprintf(stdout, "found %d connector\n", num_connector);
Ao Xu70554242020-10-15 15:19:48 +0800580 return 0;
Ao Xu6747bbd2020-09-28 20:02:09 +0800581}
582
583static int populate_crtcs(drmModeRes *resources, struct kms_display *disp)
584{
Ao Xu70554242020-10-15 15:19:48 +0800585 int i;
Ao Xu6747bbd2020-09-28 20:02:09 +0800586 int num_crtc = 0;
587 struct crtc_state *state;
588 drmModeObjectProperties *props;
589
590 for (i = 0; i < resources->count_crtcs; i++) {
591 state = calloc(1, sizeof(*state));
Ao Xu70554242020-10-15 15:19:48 +0800592 if (!state) {
593 fprintf(stderr, "calloc crtc state fail.\n");
594 return -1;
595 }
596
Ao Xu6747bbd2020-09-28 20:02:09 +0800597 disp->crtc_states[num_crtc++] = state;
598 state->id = resources->crtcs[i];
599
600 props = drmModeObjectGetProperties(disp->base.drm_fd, resources->crtcs[i], DRM_MODE_OBJECT_CRTC);
Ao Xu70554242020-10-15 15:19:48 +0800601 if (props) {
602 getproperty(disp->base.drm_fd, props, "MODE_ID", &state->mode_id);
603 getproperty(disp->base.drm_fd, props, "ACTIVE", &state->active);
604 getproperty(disp->base.drm_fd, props, "OUT_FENCE_PTR", &state->out_fence);
605 getproperty(disp->base.drm_fd, props, "VIDEO_OUT_FENCE_PTR", &state->video_out_fence);
Ao Xu70554242020-10-15 15:19:48 +0800606 drmModeFreeObjectProperties(props);
607 } else {
608 fprintf(stderr, "get crtc obj property fail\n");
609 return -1;
610 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800611 }
612
613 disp->num_crtc = num_crtc;
614
615 fprintf(stdout, "found %d crtc\n", num_crtc);
Ao Xu70554242020-10-15 15:19:48 +0800616 return 0;
Ao Xu6747bbd2020-09-28 20:02:09 +0800617}
618
619static int is_plane_support_yuv(drmModePlane * plane)
620{
621 int i;
622 for (i = 0; i < plane->count_formats; i++) {
623 switch (plane->formats[i]) {
624 case DRM_FORMAT_NV12:
625 case DRM_FORMAT_NV21:
626 return 1;
627 default:
628 return 0;
629 }
630 }
631
632 return 0;
633}
634
635static int populate_planes(drmModeRes *resources, struct kms_display *disp)
636{
Ao Xu70554242020-10-15 15:19:48 +0800637 int i;
Ao Xu6747bbd2020-09-28 20:02:09 +0800638 int num_osd_plane = 0;
639 int num_vid_plane = 0;
640 struct plane_state *state;
641 drmModePlane *plane;
642 drmModePlaneRes *plane_res;
643 drmModeObjectProperties *props;
644
645 plane_res = drmModeGetPlaneResources(disp->base.drm_fd);
Ao Xu70554242020-10-15 15:19:48 +0800646 if (!plane_res) {
647 fprintf(stderr, "drmModeGetPlaneResources fail.\n");
648 goto error;
649 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800650
651 for (i = 0; i < plane_res->count_planes; i++) {
652 state = calloc(1, sizeof(*state));
Ao Xu70554242020-10-15 15:19:48 +0800653 if (!state) {
654 fprintf(stderr, "calloc plane state fail.\n");
655 goto error;
656 }
657
Ao Xu6747bbd2020-09-28 20:02:09 +0800658 plane = drmModeGetPlane(disp->base.drm_fd, plane_res->planes[i]);
Ao Xu70554242020-10-15 15:19:48 +0800659 if (plane) {
660 if (is_plane_support_yuv(plane))
661 disp->vid_states[num_vid_plane++] = state;
662 else
663 disp->osd_states[num_osd_plane++] = state;
Ao Xu6747bbd2020-09-28 20:02:09 +0800664
Ao Xu70554242020-10-15 15:19:48 +0800665 state->id = plane_res->planes[i];
666 state->crtc_mask = plane->possible_crtcs;
Ao Xu6747bbd2020-09-28 20:02:09 +0800667
Ao Xu70554242020-10-15 15:19:48 +0800668 props = drmModeObjectGetProperties(disp->base.drm_fd, plane_res->planes[i], DRM_MODE_OBJECT_PLANE);
669 if (props) {
670 getproperty(disp->base.drm_fd, props, "CRTC_ID", &state->crtc_id);
671 getproperty(disp->base.drm_fd, props, "CRTC_X", &state->crtc_x);
672 getproperty(disp->base.drm_fd, props, "CRTC_Y", &state->crtc_y);
673 getproperty(disp->base.drm_fd, props, "CRTC_W", &state->crtc_w);
674 getproperty(disp->base.drm_fd, props, "CRTC_H", &state->crtc_h);
675 getproperty(disp->base.drm_fd, props, "FB_ID", &state->fb_id);
676 getproperty(disp->base.drm_fd, props, "SRC_X", &state->src_x);
677 getproperty(disp->base.drm_fd, props, "SRC_Y", &state->src_y);
678 getproperty(disp->base.drm_fd, props, "SRC_W", &state->src_w);
679 getproperty(disp->base.drm_fd, props, "SRC_H", &state->src_h);
680 getproperty(disp->base.drm_fd, props, "type", &state->type);
681 getproperty(disp->base.drm_fd, props, "IN_FENCE_FD", &state->in_fence_fd);
682 getproperty(disp->base.drm_fd, props, "IN_FORMATS", &state->in_formats);
683 }
684 }
685
686 if (props)
687 drmModeFreeObjectProperties(props);
688
689 if (plane)
690 drmModeFreePlane(plane);
Ao Xu6747bbd2020-09-28 20:02:09 +0800691 }
692
693 disp->num_osd_plane = num_osd_plane;
694 disp->num_vid_plane = num_vid_plane;
695
Ao Xu70554242020-10-15 15:19:48 +0800696 drmModeFreePlaneResources(plane_res);
697
Ao Xu6747bbd2020-09-28 20:02:09 +0800698 fprintf(stdout, "found %d osd, %d video\n", num_osd_plane, num_vid_plane);
Ao Xu70554242020-10-15 15:19:48 +0800699 return 0;
700
701error:
702 drmModeFreePlaneResources(plane_res);
703
704 return -1;
Ao Xu6747bbd2020-09-28 20:02:09 +0800705}
706
707static int drm_kms_init_resource(struct kms_display *disp)
708{
709 int ret;
limin.tian79bf2b12023-02-24 10:28:26 +0000710 int drm_fd = -1;
711 int render_fd = -1;
Ao Xu6747bbd2020-09-28 20:02:09 +0800712 drmModeRes *resources;
713
714 drm_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
715 if (drm_fd < 0) {
716 fprintf(stderr, "Unable to open DRM node: %s\n",
717 strerror(errno));
718 return -1;
719 }
chen.wang1f5503ea2023-04-12 07:36:24 +0000720 drmDropMaster(drm_fd);
wenlong.zhang4c011d42022-06-09 10:59:38 +0800721 render_fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC);
722 if (render_fd < 0) {
723 fprintf(stderr, "Unable to open renderD128 node: %s\n",
724 strerror(errno));
limin.tian79bf2b12023-02-24 10:28:26 +0000725 goto error3;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800726 }
727
Ao Xu6747bbd2020-09-28 20:02:09 +0800728 disp->base.drm_fd = drm_fd;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800729 disp->base.dev = meson_device_create(drm_fd, render_fd);
Ao Xu70554242020-10-15 15:19:48 +0800730 if (!disp->base.dev) {
731 fprintf(stderr, "meson_device_create fail\n");
732 goto error3;
733 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800734
735 ret = drmSetClientCap(drm_fd, DRM_CLIENT_CAP_ATOMIC, 1);
736 if (ret < 0) {
737 fprintf(stderr, "Unable to set DRM atomic capability: %s\n",
738 strerror(errno));
Ao Xu70554242020-10-15 15:19:48 +0800739 goto error2;
Ao Xu6747bbd2020-09-28 20:02:09 +0800740 }
741
742 ret = drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
743 if (ret < 0) {
744 fprintf(stderr, "Unable to set DRM universal planes capability: %s\n",
745 strerror(errno));
Ao Xu70554242020-10-15 15:19:48 +0800746 goto error2;
Ao Xu6747bbd2020-09-28 20:02:09 +0800747 }
748
749 resources = drmModeGetResources(drm_fd);
750 if (!resources) {
751 fprintf(stderr, "drmModeGetResources failed: %s\n", strerror(errno));
Ao Xu70554242020-10-15 15:19:48 +0800752 goto error2;
Ao Xu6747bbd2020-09-28 20:02:09 +0800753 }
754
Ao Xu70554242020-10-15 15:19:48 +0800755 ret = populate_connectors(resources, disp);
756 if (ret)
757 goto error1;
Ao Xu6747bbd2020-09-28 20:02:09 +0800758
Ao Xu70554242020-10-15 15:19:48 +0800759 ret = populate_crtcs(resources, disp);
760 if (ret)
761 goto error1;
762
763 ret = populate_planes(resources, disp);
764 if (ret)
765 goto error1;
chen.wang1bace1312023-01-18 16:13:54 +0800766 drmModeFreeResources(resources);
Ao Xu6747bbd2020-09-28 20:02:09 +0800767 return 0;
Ao Xu70554242020-10-15 15:19:48 +0800768
769error1:
770 drmModeFreeResources(resources);
771error2:
772 meson_device_destroy(disp->base.dev);
773error3:
limin.tian79bf2b12023-02-24 10:28:26 +0000774 if (drm_fd >= 0)
775 close(drm_fd);
776 if (render_fd >= 0)
777 close(render_fd);
Ao Xu70554242020-10-15 15:19:48 +0800778
779 return -1;
Ao Xu6747bbd2020-09-28 20:02:09 +0800780}
781
782struct drm_display *drm_kms_init(void)
783{
Ao Xu70554242020-10-15 15:19:48 +0800784 int ret;
Ao Xu6747bbd2020-09-28 20:02:09 +0800785 struct kms_display *display;
786 struct drm_display *base;
787 display = calloc(1, sizeof(*display));
Ao Xu70554242020-10-15 15:19:48 +0800788 if (!display) {
789 fprintf(stderr, "calloc kms_display fail\n");
790 return NULL;
791 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800792
793 base = &display->base;
794 base->destroy_display = kms_destroy_display;
795 base->alloc_bufs = kms_alloc_bufs;
796 base->free_bufs = kms_free_bufs;
797
798 base->alloc_buf = kms_alloc_buf;
Ao Xu70554242020-10-15 15:19:48 +0800799 base->import_buf = kms_import_buf;
Ao Xu6747bbd2020-09-28 20:02:09 +0800800 base->free_buf = kms_free_buf;
801 base->post_buf = kms_post_buf;
chen.wang1bace1312023-01-18 16:13:54 +0800802 base->alloc_only = 0;
Ao Xu6747bbd2020-09-28 20:02:09 +0800803
Ao Xu70554242020-10-15 15:19:48 +0800804 ret = drm_kms_init_resource(display);
805 if (ret) {
806 fprintf(stderr, "drm_kms_init_resource fail.\n");
807 free(display);
808 return NULL;
809 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800810
811 return base;
812}