blob: 67ed569233e483f8f0e9e79ef9a534f0cb456767 [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
chen.wang1518f14f2023-04-12 09:53:10 +0000125 if (!buf)
126 return -1;
127
Ao Xu6747bbd2020-09-28 20:02:09 +0800128 for ( i = 0; i < buf->nbo; i++)
129 close(buf->fd[i]);
130
chen.wang1bace1312023-01-18 16:13:54 +0800131 fd = drm_disp->alloc_only ? drm_disp->dev->render_fd : drm_disp->dev->fd;
Ao Xu6747bbd2020-09-28 20:02:09 +0800132 drmModeRmFB(drm_disp->drm_fd, buf->fb_id);
133 memset(&destroy_dumb, 0, sizeof(destroy_dumb));
134
135 for ( i = 0; i < buf->nbo; i++) {
chen.wang1518f14f2023-04-12 09:53:10 +0000136 if (!buf->bos[i])
137 continue;
138
Ao Xu6747bbd2020-09-28 20:02:09 +0800139 destroy_dumb.handle = meson_bo_handle(buf->bos[i]);
140
wenlong.zhanga71a2e02022-06-14 15:58:53 +0800141 ret = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
Ao Xu6747bbd2020-09-28 20:02:09 +0800142 if (ret < 0) {
143 /* If handle was from drmPrimeFDToHandle, then fd is connected
144 * as render, we have to use drm_gem_close to release it.
145 */
146 if (errno == EACCES) {
147 struct drm_gem_close close_req;
148 close_req.handle = destroy_dumb.handle;
wenlong.zhanga71a2e02022-06-14 15:58:53 +0800149 ret = drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close_req);
Ao Xu6747bbd2020-09-28 20:02:09 +0800150 if (ret < 0) {
151 fprintf(stderr, "Unable to destroy buffer: %s\n",
152 strerror(errno));
153 return -1;
154 }
155 }
156 }
chen.wang1518f14f2023-04-12 09:53:10 +0000157 free(buf->bos[i]);
158 buf->bos[i] = NULL;
Ao Xu6747bbd2020-09-28 20:02:09 +0800159 }
chen.wang1bace1312023-01-18 16:13:54 +0800160 free(buf);
chen.wang1518f14f2023-04-12 09:53:10 +0000161 buf = NULL;
Ao Xu6747bbd2020-09-28 20:02:09 +0800162 return 0;
163}
164static int kms_free_bufs(struct drm_display *drm_disp)
165{
166 int i;
167 struct drm_buf *buf;
Ao Xu6747bbd2020-09-28 20:02:09 +0800168 for ( i = 0; i < drm_disp->nbuf; i++ ) {
169 buf = &drm_disp->bufs[i];
170 free_buf(drm_disp, buf);
171 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800172 return 0;
173}
174
175static int kms_free_buf(struct drm_buf *buf)
176{
177 free_buf(buf->disp, buf);
178 return 0;
179}
180
Ao Xu70554242020-10-15 15:19:48 +0800181static struct meson_bo *alloc_bo(struct drm_display *drm_disp, struct drm_buf *buf, uint32_t bpp, uint32_t width,
182 uint32_t height, uint32_t *bo_handle, uint32_t *pitch)
183{
184 uint32_t size;
185 struct meson_bo *bo;
186
187 size = width * height * bpp / 8;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800188 bo = meson_bo_create(drm_disp->dev, size, buf->flags, drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800189 if (bo) {
190 *bo_handle = meson_bo_handle(bo);
191 *pitch = width * bpp / 8;
192 return bo;
193 } else {
194 fprintf(stderr, "meson_bo_create fail\n");
195 return NULL;
196 }
197}
198
199static int alloc_bos(struct drm_display *drm_disp, struct drm_buf *buf, uint32_t *bo_handles)
200{
201 uint32_t width = buf->width;
202 uint32_t height = buf->height;
203
204 switch (buf->fourcc) {
205 case DRM_FORMAT_ARGB8888:
206 buf->nbo = 1;
207 buf->bos[0] = alloc_bo(drm_disp, buf, 32, width, height, &bo_handles[0], &buf->pitches[0]);
208 if (!buf->bos[0]) {
209 fprintf(stderr, "alloc_bo argb888 fail\n");
210 return -1;
211 }
212
213 buf->size = width * height * 4;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800214 buf->fd[0] = meson_bo_dmabuf(buf->bos[0], drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800215 break;
216 case DRM_FORMAT_UYVY:
217 case DRM_FORMAT_YUYV:
218 buf->nbo = 1;
219 buf->bos[0] = alloc_bo(drm_disp, buf, 16, width, height, &bo_handles[0], &buf->pitches[0]);
220 if (!buf->bos[0]) {
221 fprintf(stderr, "alloc_bo yuyv or uyvy fail\n");
222 return -1;
223 }
224
225 buf->size = width * height * 2;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800226 buf->fd[0] = meson_bo_dmabuf(buf->bos[0], drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800227 buf->commit_to_video = 1;
228 break;
229 case DRM_FORMAT_NV12:
230 case DRM_FORMAT_NV21:
231 buf->nbo = 2;
232 buf->bos[0] = alloc_bo(drm_disp, buf, 8, width, height, &bo_handles[0], &buf->pitches[0]);
233 if (!buf->bos[0]) {
234 fprintf(stderr, "alloc_bo nv12 or nv21 fail\n");
235 return -1;
236 }
237
wenlong.zhang4c011d42022-06-09 10:59:38 +0800238 buf->fd[0] = meson_bo_dmabuf(buf->bos[0], drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800239
240 buf->bos[1] = alloc_bo(drm_disp, buf, 16, width/2, height/2, &bo_handles[1], &buf->pitches[1]);
241 if (!buf->bos[1]) {
242 fprintf(stderr, "alloc_bo argb888 fail\n");
243 return -1;
244 }
wenlong.zhang4c011d42022-06-09 10:59:38 +0800245 buf->fd[1] = meson_bo_dmabuf(buf->bos[1], drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800246 buf->size = width * height * 3 / 2;
247 buf->commit_to_video = 1;
248 break;
249 default:
250 fprintf(stderr, "unsupport format: 0x%08x\n", buf->fourcc);
251 break;
252 }
253
254 return 0;
255}
256
257static int add_framebuffer(int fd, struct drm_buf *buf, uint32_t *bo_handles, uint64_t modifier)
258{
259 int i, ret;
260 uint64_t modifiers[4] = { 0, 0, 0, 0 };
261 uint32_t flags = 0;
262 uint32_t fb_id;
263
264 for ( i = 0; i < buf->nbo; i++) {
265 if (bo_handles[i] != 0 && modifier != DRM_FORMAT_MOD_NONE) {
266 flags |= DRM_MODE_FB_MODIFIERS;
267 modifiers[i] = modifier;
268 }
269 }
270
271 ret = drmModeAddFB2WithModifiers(fd, buf->width, buf->height, buf->fourcc,
272 bo_handles, buf->pitches, buf->offsets, modifiers, &fb_id, flags);
273 if (ret < 0) {
274 fprintf(stderr, "Unable to add framebuffer for plane: %s\n", strerror(errno));
275 return -1;
276 }
277
278 buf->fb_id = fb_id;
279 return 0;
280}
281
282static struct drm_buf *kms_alloc_buf(struct drm_display *drm_disp, struct drm_buf_metadata *info)
283{
284 int ret;
285 struct drm_buf *buf = NULL;
286 uint32_t bo_handles[4] = {0};
287
288 buf = calloc(1, sizeof(*buf));
289 buf->fourcc = info->fourcc;
290 buf->width = info->width;
291 buf->height = info->height;
292 buf->flags = info->flags;
293 buf->fence_fd = -1;
294 buf->disp = drm_disp;
295
296 ret = alloc_bos(drm_disp, buf, bo_handles);
297 if (ret) {
298 fprintf(stderr, "alloc_bos fail\n");
299 free(buf);
300 return NULL;
301 }
302
chen.wang1bace1312023-01-18 16:13:54 +0800303 /*for non-root users, just need alloc buf and don't need to add framebuffer*/
304 if (drm_disp->alloc_only)
305 return buf;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800306
Ao Xu70554242020-10-15 15:19:48 +0800307 ret = add_framebuffer(drm_disp->drm_fd, buf, bo_handles, DRM_FORMAT_MOD_NONE);
308 if (ret) {
chen.wang1bace1312023-01-18 16:13:54 +0800309 fprintf(stderr, "add_framebuffer fail, call free_buf\n");
Ao Xu70554242020-10-15 15:19:48 +0800310 free_buf(drm_disp, buf);
Ao Xu70554242020-10-15 15:19:48 +0800311 return NULL;
312 }
313
314 return buf;
315}
316
317static int kms_alloc_bufs(struct drm_display *drm_disp, int num, struct drm_buf_metadata *info)
318{
319 int i, ret;
320 struct drm_buf *buf;
321 uint32_t bo_handles[4] = {0};
322
323 drm_disp->bufs = calloc(num, sizeof(*drm_disp->bufs));
324 drm_disp->nbuf = num;
325
326 for ( i = 0; i < num; i++) {
327 buf = &drm_disp->bufs[i];
328 buf->fourcc = info->fourcc;
329 buf->width = info->width;
330 buf->height = info->height;
331 buf->flags = info->flags;
332 buf->fence_fd = -1;
333 buf->disp = drm_disp;
334
335 if (!info->fourcc)
336 buf->fourcc = DRM_FORMAT_ARGB8888;
337
338 switch (buf->fourcc) {
339 case DRM_FORMAT_ARGB8888:
340 buf->nbo = 1;
341 break;
342 case DRM_FORMAT_UYVY:
343 case DRM_FORMAT_YUYV:
344 buf->nbo = 1;
345 break;
346 case DRM_FORMAT_NV12:
347 case DRM_FORMAT_NV21:
348 buf->nbo = 2;
349 break;
350 default:
351 fprintf(stderr, "unsupport format: 0x%08x\n", buf->fourcc);
352 break;
353 }
354
355 ret = alloc_bos(drm_disp, buf, bo_handles);
356 if (ret) {
357 fprintf(stderr, "alloc_bos fail\n");
358 return -1;
359 }
360
361 ret = add_framebuffer(drm_disp->drm_fd, buf, bo_handles, DRM_FORMAT_MOD_NONE);
362 if (ret) {
363 fprintf(stderr, "add_framebuffer fail\n");
364 free_buf(drm_disp, buf);
365 return -1;
366 }
367 }
368 return 0;
369}
370
371static struct drm_buf *kms_import_buf(struct drm_display *disp, struct drm_buf_import *info)
372{
373 int i;
374 uint32_t size;
375 struct drm_buf *buf = NULL;
376 uint32_t bo_handles[4] = {0};
377
378 buf = calloc(1, sizeof(*buf));
379 buf->fourcc = info->fourcc;
380 buf->width = info->width;
381 buf->height = info->height;
382 buf->flags = info->flags;
383 buf->fence_fd = -1;
384 buf->disp = disp;
385
386 if (!info->fourcc)
387 buf->fourcc = DRM_FORMAT_ARGB8888;
388
389 switch (buf->fourcc) {
390 case DRM_FORMAT_ARGB8888:
391 buf->nbo = 1;
392 break;
393 case DRM_FORMAT_UYVY:
394 case DRM_FORMAT_YUYV:
395 buf->nbo = 1;
396 break;
397 case DRM_FORMAT_NV12:
398 case DRM_FORMAT_NV21:
399 buf->nbo = 2;
400 break;
401 default:
402 fprintf(stderr, "unsupport format: 0x%08x\n", buf->fourcc);
403 break;
404 }
405
406 for (i = 0; i < buf->nbo; i++) {
407 if ( i == 0 )
408 size = info->width * info->height;
409 else
410 size = info->width * info->height / 2;
411
412 buf->size += size;
413 buf->fd[i] = info->fd[i];
414 buf->pitches[i] = buf->width;
415 buf->bos[i] = meson_bo_import(disp->dev, info->fd[i], size, info->flags);
416 if (!buf->bos[i]) {
417 fprintf(stderr, "meson_bo_import fail\n");
418 return NULL;
419 }
420
421 bo_handles[i] = meson_bo_handle(buf->bos[i]);
422 }
423
424 add_framebuffer(disp->drm_fd, buf, bo_handles, DRM_FORMAT_MOD_NONE);
425
426 return buf;
427}
428
Ao Xu6747bbd2020-09-28 20:02:09 +0800429static int kms_post_buf(struct drm_display *drm_disp, struct drm_buf *buf)
430{
431 int ret;
432 drmModeAtomicReqPtr request;
Ao Xu6747bbd2020-09-28 20:02:09 +0800433 uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK;
434 struct kms_display *disp = to_kms_display(drm_disp);
435
436 struct plane_state *plane_state;
437 struct crtc_state *crtc_state;
438 struct connector_state *conn_state;
439
440 conn_state = disp->conn_states[0];
441 crtc_state = disp->crtc_states[0];
442
sky zhouf05ca462020-10-29 18:07:40 +0800443 if (buf->flags & MESON_USE_VD1)
Ao Xu6747bbd2020-09-28 20:02:09 +0800444 plane_state = disp->vid_states[0];
sky zhouf05ca462020-10-29 18:07:40 +0800445 else if (buf->flags & MESON_USE_VD2)
Ao Xu6747bbd2020-09-28 20:02:09 +0800446 plane_state = disp->vid_states[1];
447 else
448 plane_state = disp->osd_states[0];
449
450 request = drmModeAtomicAlloc();
451
sky zhouf05ca462020-10-29 18:07:40 +0800452#if 0
Ao Xu6747bbd2020-09-28 20:02:09 +0800453 if (!disp->mode_set) {
Ao Xu6747bbd2020-09-28 20:02:09 +0800454 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
455 drmModeAtomicAddProperty(request, conn_state->id, conn_state->crtc_id.id, crtc_state->id);
456
457 if (drmModeCreatePropertyBlob(drm_disp->drm_fd, &disp->conn_states[0]->mode,
458 sizeof(drmModeModeInfo), &blob_id) != 0 ) {
459 return -1;
460 }
461 drmModeAtomicAddProperty(request, crtc_state->id, crtc_state->mode_id.id, blob_id);
462 drmModeAtomicAddProperty(request, crtc_state->id, crtc_state->active.id, 1);
463
464 disp->mode_set = 1;
465 }
sky zhouf05ca462020-10-29 18:07:40 +0800466#else
467 /*No modeset needed in post buf, modeset will control by systemservice.*/
468#endif
Ao Xu6747bbd2020-09-28 20:02:09 +0800469
Ao Xub3689892020-11-09 18:57:56 +0800470 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_x.id, buf->crtc_x);
471 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_y.id, buf->crtc_y);
Ao Xu70554242020-10-15 15:19:48 +0800472 if (buf->crtc_w == 0) {
473 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_w.id, conn_state->mode.hdisplay);
474 } else {
475 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_w.id, buf->crtc_w);
476 }
477
478 if (buf->crtc_h == 0) {
479 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_h.id, conn_state->mode.vdisplay);
480 } else {
481 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_h.id, buf->crtc_h);
482 }
483
Ao Xu2b6aec52020-12-15 14:24:21 +0800484 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_x.id, buf->src_x << 16);
485 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_y.id, buf->src_y << 16);
yujun.zhang54c6eda2021-12-30 12:24:49 +0800486 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_w.id, buf->src_w << 16);
487 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_h.id, buf->src_h << 16);
Ao Xu6747bbd2020-09-28 20:02:09 +0800488 drmModeAtomicAddProperty(request, plane_state->id, plane_state->fb_id.id, buf->fb_id);
489 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_id.id, crtc_state->id);
490#if 0
491 if (buf->flags | (MESON_USE_VD2 | MESON_USE_VD1))
492 drmModeAtomicAddProperty(request, crtc_state->id, crtc_state->video_out_fence.id, VOID2U64(&buf->fence_fd));
493 else
494 drmModeAtomicAddProperty(request, crtc_state->id, crtc_state->out_fence.id, VOID2U64(&buf->fence_fd));
495#endif
sky zhouf05ca462020-10-29 18:07:40 +0800496
497 ret = drmModeAsyncAtomicCommit(drm_disp->drm_fd, request, flags, NULL);
Ao Xu6747bbd2020-09-28 20:02:09 +0800498 if (ret < 0) {
499 fprintf(stderr, "Unable to flip page: %s\n", strerror(errno));
500 goto error;
501 }
502
503 ret = 0;
504 goto complete;
505
506error:
507 ret = -1;
508complete:
509 drmModeAtomicFree(request);
510
511 return ret;
512}
513
514static void getproperty(int drm_fd, drmModeObjectProperties* props, const char *name,
515 struct property *p)
516{
517 int i;
518 drmModePropertyRes *res;
519 for (i = 0; i < props->count_props; i++) {
520 res = drmModeGetProperty(drm_fd, props->props[i]);
Ao Xu70554242020-10-15 15:19:48 +0800521 if (res && !strcmp(name, res->name)) {
522 p->id = res->prop_id;
523 p->value = props->prop_values[i];
524 //fprintf(stdout, "getproperty: %s, id: %u, value: %llu \n", res->name, p->id, p->value);
525 }
Ao Xu70554242020-10-15 15:19:48 +0800526 drmModeFreeProperty(res);
Ao Xu6747bbd2020-09-28 20:02:09 +0800527 }
528}
529
530static int populate_connectors(drmModeRes *resources, struct kms_display *disp)
531{
Ao Xu70554242020-10-15 15:19:48 +0800532 int i, j;
Ao Xu6747bbd2020-09-28 20:02:09 +0800533 int num_connector = 0;
534 struct connector_state *state;
535 drmModeConnector *connector;
536 drmModeEncoder *encoder;
537 drmModeObjectProperties *props;
538
539 for (i = 0; i < resources->count_connectors; i++) {
540 connector = drmModeGetConnector(disp->base.drm_fd, resources->connectors[i]);
Ao Xu70554242020-10-15 15:19:48 +0800541 if (!connector) {
542 fprintf(stderr, "drmModeGetConnector fail.\n");
543 continue;
544 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800545
chen.wang1bace1312023-01-18 16:13:54 +0800546 if (connector->connector_type == DRM_MODE_CONNECTOR_TV) {
547 drmModeFreeConnector(connector);
Ao Xu6747bbd2020-09-28 20:02:09 +0800548 continue;
chen.wang1bace1312023-01-18 16:13:54 +0800549 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800550 state = calloc(1, sizeof(*state));
551 disp->conn_states[num_connector++] = state;
552 state->id = resources->connectors[i];
553
554 for (j = 0; j < connector->count_encoders; j++) {
555 encoder = drmModeGetEncoder(disp->base.drm_fd, connector->encoders[j]);
Ao Xu70554242020-10-15 15:19:48 +0800556 if (encoder) {
557 state->crtc_mask |= encoder->possible_crtcs;
558 drmModeFreeEncoder(encoder);
559 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800560 }
561
562 if (connector->count_modes)
563 state->mode = connector->modes[0];
564
565 for (j = 0; j < connector->count_modes; j++) {
566 if (connector->modes[j].type & DRM_MODE_TYPE_PREFERRED) {
567 state->mode = connector->modes[j];
568 break;
569 }
570 }
571
572 disp->base.width = state->mode.hdisplay;
573 disp->base.height = state->mode.vdisplay;
574 disp->base.vrefresh = state->mode.vrefresh;
575
576 props = drmModeObjectGetProperties(disp->base.drm_fd, resources->connectors[i], DRM_MODE_OBJECT_CONNECTOR);
Ao Xu6747bbd2020-09-28 20:02:09 +0800577 getproperty(disp->base.drm_fd, props, "CRTC_ID", &state->crtc_id);
Ao Xu70554242020-10-15 15:19:48 +0800578
579 if (props)
580 drmModeFreeObjectProperties(props);
581
582 if (connector)
583 drmModeFreeConnector(connector);
Ao Xu6747bbd2020-09-28 20:02:09 +0800584 }
585
586 disp->num_connector = num_connector;
587 fprintf(stdout, "found %d connector\n", num_connector);
Ao Xu70554242020-10-15 15:19:48 +0800588 return 0;
Ao Xu6747bbd2020-09-28 20:02:09 +0800589}
590
591static int populate_crtcs(drmModeRes *resources, struct kms_display *disp)
592{
Ao Xu70554242020-10-15 15:19:48 +0800593 int i;
Ao Xu6747bbd2020-09-28 20:02:09 +0800594 int num_crtc = 0;
595 struct crtc_state *state;
596 drmModeObjectProperties *props;
597
598 for (i = 0; i < resources->count_crtcs; i++) {
599 state = calloc(1, sizeof(*state));
Ao Xu70554242020-10-15 15:19:48 +0800600 if (!state) {
601 fprintf(stderr, "calloc crtc state fail.\n");
602 return -1;
603 }
604
Ao Xu6747bbd2020-09-28 20:02:09 +0800605 disp->crtc_states[num_crtc++] = state;
606 state->id = resources->crtcs[i];
607
608 props = drmModeObjectGetProperties(disp->base.drm_fd, resources->crtcs[i], DRM_MODE_OBJECT_CRTC);
Ao Xu70554242020-10-15 15:19:48 +0800609 if (props) {
610 getproperty(disp->base.drm_fd, props, "MODE_ID", &state->mode_id);
611 getproperty(disp->base.drm_fd, props, "ACTIVE", &state->active);
612 getproperty(disp->base.drm_fd, props, "OUT_FENCE_PTR", &state->out_fence);
613 getproperty(disp->base.drm_fd, props, "VIDEO_OUT_FENCE_PTR", &state->video_out_fence);
Ao Xu70554242020-10-15 15:19:48 +0800614 drmModeFreeObjectProperties(props);
615 } else {
616 fprintf(stderr, "get crtc obj property fail\n");
617 return -1;
618 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800619 }
620
621 disp->num_crtc = num_crtc;
622
623 fprintf(stdout, "found %d crtc\n", num_crtc);
Ao Xu70554242020-10-15 15:19:48 +0800624 return 0;
Ao Xu6747bbd2020-09-28 20:02:09 +0800625}
626
627static int is_plane_support_yuv(drmModePlane * plane)
628{
629 int i;
630 for (i = 0; i < plane->count_formats; i++) {
631 switch (plane->formats[i]) {
632 case DRM_FORMAT_NV12:
633 case DRM_FORMAT_NV21:
634 return 1;
635 default:
636 return 0;
637 }
638 }
639
640 return 0;
641}
642
643static int populate_planes(drmModeRes *resources, struct kms_display *disp)
644{
Ao Xu70554242020-10-15 15:19:48 +0800645 int i;
Ao Xu6747bbd2020-09-28 20:02:09 +0800646 int num_osd_plane = 0;
647 int num_vid_plane = 0;
648 struct plane_state *state;
649 drmModePlane *plane;
650 drmModePlaneRes *plane_res;
651 drmModeObjectProperties *props;
652
653 plane_res = drmModeGetPlaneResources(disp->base.drm_fd);
Ao Xu70554242020-10-15 15:19:48 +0800654 if (!plane_res) {
655 fprintf(stderr, "drmModeGetPlaneResources fail.\n");
656 goto error;
657 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800658
659 for (i = 0; i < plane_res->count_planes; i++) {
660 state = calloc(1, sizeof(*state));
Ao Xu70554242020-10-15 15:19:48 +0800661 if (!state) {
662 fprintf(stderr, "calloc plane state fail.\n");
663 goto error;
664 }
665
Ao Xu6747bbd2020-09-28 20:02:09 +0800666 plane = drmModeGetPlane(disp->base.drm_fd, plane_res->planes[i]);
Ao Xu70554242020-10-15 15:19:48 +0800667 if (plane) {
668 if (is_plane_support_yuv(plane))
669 disp->vid_states[num_vid_plane++] = state;
670 else
671 disp->osd_states[num_osd_plane++] = state;
Ao Xu6747bbd2020-09-28 20:02:09 +0800672
Ao Xu70554242020-10-15 15:19:48 +0800673 state->id = plane_res->planes[i];
674 state->crtc_mask = plane->possible_crtcs;
Ao Xu6747bbd2020-09-28 20:02:09 +0800675
Ao Xu70554242020-10-15 15:19:48 +0800676 props = drmModeObjectGetProperties(disp->base.drm_fd, plane_res->planes[i], DRM_MODE_OBJECT_PLANE);
677 if (props) {
678 getproperty(disp->base.drm_fd, props, "CRTC_ID", &state->crtc_id);
679 getproperty(disp->base.drm_fd, props, "CRTC_X", &state->crtc_x);
680 getproperty(disp->base.drm_fd, props, "CRTC_Y", &state->crtc_y);
681 getproperty(disp->base.drm_fd, props, "CRTC_W", &state->crtc_w);
682 getproperty(disp->base.drm_fd, props, "CRTC_H", &state->crtc_h);
683 getproperty(disp->base.drm_fd, props, "FB_ID", &state->fb_id);
684 getproperty(disp->base.drm_fd, props, "SRC_X", &state->src_x);
685 getproperty(disp->base.drm_fd, props, "SRC_Y", &state->src_y);
686 getproperty(disp->base.drm_fd, props, "SRC_W", &state->src_w);
687 getproperty(disp->base.drm_fd, props, "SRC_H", &state->src_h);
688 getproperty(disp->base.drm_fd, props, "type", &state->type);
689 getproperty(disp->base.drm_fd, props, "IN_FENCE_FD", &state->in_fence_fd);
690 getproperty(disp->base.drm_fd, props, "IN_FORMATS", &state->in_formats);
691 }
692 }
693
694 if (props)
695 drmModeFreeObjectProperties(props);
696
697 if (plane)
698 drmModeFreePlane(plane);
Ao Xu6747bbd2020-09-28 20:02:09 +0800699 }
700
701 disp->num_osd_plane = num_osd_plane;
702 disp->num_vid_plane = num_vid_plane;
703
Ao Xu70554242020-10-15 15:19:48 +0800704 drmModeFreePlaneResources(plane_res);
705
Ao Xu6747bbd2020-09-28 20:02:09 +0800706 fprintf(stdout, "found %d osd, %d video\n", num_osd_plane, num_vid_plane);
Ao Xu70554242020-10-15 15:19:48 +0800707 return 0;
708
709error:
710 drmModeFreePlaneResources(plane_res);
711
712 return -1;
Ao Xu6747bbd2020-09-28 20:02:09 +0800713}
714
715static int drm_kms_init_resource(struct kms_display *disp)
716{
717 int ret;
limin.tian79bf2b12023-02-24 10:28:26 +0000718 int drm_fd = -1;
719 int render_fd = -1;
Ao Xu6747bbd2020-09-28 20:02:09 +0800720 drmModeRes *resources;
721
722 drm_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
723 if (drm_fd < 0) {
724 fprintf(stderr, "Unable to open DRM node: %s\n",
725 strerror(errno));
726 return -1;
727 }
chen.wang1f5503ea2023-04-12 07:36:24 +0000728 drmDropMaster(drm_fd);
wenlong.zhang4c011d42022-06-09 10:59:38 +0800729 render_fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC);
730 if (render_fd < 0) {
731 fprintf(stderr, "Unable to open renderD128 node: %s\n",
732 strerror(errno));
limin.tian79bf2b12023-02-24 10:28:26 +0000733 goto error3;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800734 }
735
Ao Xu6747bbd2020-09-28 20:02:09 +0800736 disp->base.drm_fd = drm_fd;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800737 disp->base.dev = meson_device_create(drm_fd, render_fd);
Ao Xu70554242020-10-15 15:19:48 +0800738 if (!disp->base.dev) {
739 fprintf(stderr, "meson_device_create fail\n");
740 goto error3;
741 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800742
743 ret = drmSetClientCap(drm_fd, DRM_CLIENT_CAP_ATOMIC, 1);
744 if (ret < 0) {
745 fprintf(stderr, "Unable to set DRM atomic capability: %s\n",
746 strerror(errno));
Ao Xu70554242020-10-15 15:19:48 +0800747 goto error2;
Ao Xu6747bbd2020-09-28 20:02:09 +0800748 }
749
750 ret = drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
751 if (ret < 0) {
752 fprintf(stderr, "Unable to set DRM universal planes capability: %s\n",
753 strerror(errno));
Ao Xu70554242020-10-15 15:19:48 +0800754 goto error2;
Ao Xu6747bbd2020-09-28 20:02:09 +0800755 }
756
757 resources = drmModeGetResources(drm_fd);
758 if (!resources) {
759 fprintf(stderr, "drmModeGetResources failed: %s\n", strerror(errno));
Ao Xu70554242020-10-15 15:19:48 +0800760 goto error2;
Ao Xu6747bbd2020-09-28 20:02:09 +0800761 }
762
Ao Xu70554242020-10-15 15:19:48 +0800763 ret = populate_connectors(resources, disp);
764 if (ret)
765 goto error1;
Ao Xu6747bbd2020-09-28 20:02:09 +0800766
Ao Xu70554242020-10-15 15:19:48 +0800767 ret = populate_crtcs(resources, disp);
768 if (ret)
769 goto error1;
770
771 ret = populate_planes(resources, disp);
772 if (ret)
773 goto error1;
chen.wang1bace1312023-01-18 16:13:54 +0800774 drmModeFreeResources(resources);
Ao Xu6747bbd2020-09-28 20:02:09 +0800775 return 0;
Ao Xu70554242020-10-15 15:19:48 +0800776
777error1:
778 drmModeFreeResources(resources);
779error2:
780 meson_device_destroy(disp->base.dev);
781error3:
limin.tian79bf2b12023-02-24 10:28:26 +0000782 if (drm_fd >= 0)
783 close(drm_fd);
784 if (render_fd >= 0)
785 close(render_fd);
Ao Xu70554242020-10-15 15:19:48 +0800786
787 return -1;
Ao Xu6747bbd2020-09-28 20:02:09 +0800788}
789
790struct drm_display *drm_kms_init(void)
791{
Ao Xu70554242020-10-15 15:19:48 +0800792 int ret;
Ao Xu6747bbd2020-09-28 20:02:09 +0800793 struct kms_display *display;
794 struct drm_display *base;
795 display = calloc(1, sizeof(*display));
Ao Xu70554242020-10-15 15:19:48 +0800796 if (!display) {
797 fprintf(stderr, "calloc kms_display fail\n");
798 return NULL;
799 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800800
801 base = &display->base;
802 base->destroy_display = kms_destroy_display;
803 base->alloc_bufs = kms_alloc_bufs;
804 base->free_bufs = kms_free_bufs;
805
806 base->alloc_buf = kms_alloc_buf;
Ao Xu70554242020-10-15 15:19:48 +0800807 base->import_buf = kms_import_buf;
Ao Xu6747bbd2020-09-28 20:02:09 +0800808 base->free_buf = kms_free_buf;
809 base->post_buf = kms_post_buf;
chen.wang1bace1312023-01-18 16:13:54 +0800810 base->alloc_only = 0;
Ao Xu6747bbd2020-09-28 20:02:09 +0800811
Ao Xu70554242020-10-15 15:19:48 +0800812 ret = drm_kms_init_resource(display);
813 if (ret) {
814 fprintf(stderr, "drm_kms_init_resource fail.\n");
815 free(display);
816 return NULL;
817 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800818
819 return base;
820}