blob: d590e0940a596a711890edc75a93a7da37c69af0 [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"
chen.wang1d5483452024-02-28 06:18:16 +000018#include "meson_drm_log.h"
Ao Xu6747bbd2020-09-28 20:02:09 +080019
20#define MAX_OSD_PLANE 6
21#define MAX_VIDEO_PLANE 4
22#define MAX_CONNECTOR 3
23#define MAX_CRTC 3
24
25struct kms_display;
26
chen.wang1bace1312023-01-18 16:13:54 +080027
Ao Xu6747bbd2020-09-28 20:02:09 +080028#define VOID2U64(x) ((uint64_t)(unsigned long)(x))
29#define container_of(ptr, type, member) \
30 (type *)((char *)(ptr) - (char *) &((type *)0)->member)
31
32#define to_kms_display(x) container_of(x, struct kms_display, base)
33
34struct property {
35 uint32_t id;
36 uint64_t value;
37};
38
39struct crtc_state {
40 uint32_t id;
41
42 struct property mode_id;
43 struct property active;
44 struct property out_fence;
45 struct property video_out_fence;
46};
47
48struct connector_state {
49 uint32_t id;
50 uint32_t crtc_mask;
51 drmModeModeInfo mode;
52
53 struct property crtc_id;
54};
55
56struct plane_state {
57 uint32_t id;
58 uint32_t crtc_mask;
59
60 struct property crtc_id;
61 struct property crtc_x;
62 struct property crtc_y;
63 struct property crtc_w;
64 struct property crtc_h;
65 struct property fb_id;
66 struct property src_x;
67 struct property src_y;
68 struct property src_w;
69 struct property src_h;
Ao Xu6747bbd2020-09-28 20:02:09 +080070 struct property type;
71 struct property in_fence_fd;
72 struct property in_formats;
73};
74
Ao Xu6747bbd2020-09-28 20:02:09 +080075struct kms_display {
76 struct drm_display base;
77
Ao Xu6747bbd2020-09-28 20:02:09 +080078 int num_crtc;
79 struct crtc_state *crtc_states[MAX_CRTC];
80 int num_connector;
81 struct connector_state *conn_states[MAX_CONNECTOR];
82 int num_osd_plane;
83 struct plane_state *osd_states[MAX_OSD_PLANE];
84 int num_vid_plane;
85 struct plane_state *vid_states[MAX_OSD_PLANE];
86
87 int mode_set;
88};
89
90static void kms_destroy_display(struct drm_display *drm_disp)
91{
Ao Xu70554242020-10-15 15:19:48 +080092 int i;
Ao Xu6747bbd2020-09-28 20:02:09 +080093 struct kms_display *disp = to_kms_display(drm_disp);
Ao Xu70554242020-10-15 15:19:48 +080094 close(drm_disp->drm_fd);
limin.tian79bf2b12023-02-24 10:28:26 +000095 close(drm_disp->dev->render_fd);
Ao Xu70554242020-10-15 15:19:48 +080096 meson_device_destroy(drm_disp->dev);
97
98 for (i = 0; i < MAX_CRTC; i++) {
99 if (disp->crtc_states[i])
100 free(disp->crtc_states[i]);
101 }
102
103 for (i = 0; i < MAX_CONNECTOR; i++) {
104 if (disp->conn_states[i])
105 free(disp->conn_states[i]);
106 }
107
108 for (i = 0; i < MAX_OSD_PLANE; i++) {
109 if (disp->osd_states[i])
110 free(disp->osd_states[i]);
111 }
112
113 for (i = 0; i < MAX_OSD_PLANE; i++) {
114 if (disp->vid_states[i])
115 free(disp->vid_states[i]);
116 }
117
Ao Xu6747bbd2020-09-28 20:02:09 +0800118 free(disp);
119}
120
Ao Xu6747bbd2020-09-28 20:02:09 +0800121static int free_buf(struct drm_display *drm_disp, struct drm_buf *buf)
122{
wenlong.zhanga71a2e02022-06-14 15:58:53 +0800123 int i, fd, ret;
Ao Xu6747bbd2020-09-28 20:02:09 +0800124 struct drm_mode_destroy_dumb destroy_dumb;
125
chen.wang1518f14f2023-04-12 09:53:10 +0000126 if (!buf)
127 return -1;
128
Ao Xu6747bbd2020-09-28 20:02:09 +0800129 for ( i = 0; i < buf->nbo; i++)
130 close(buf->fd[i]);
131
chen.wang1bace1312023-01-18 16:13:54 +0800132 fd = drm_disp->alloc_only ? drm_disp->dev->render_fd : drm_disp->dev->fd;
wenlong.zhang7d32ed92023-04-12 06:08:17 +0000133 if (drm_disp->freeze) {
134 ret = drmIoctl(drm_disp->drm_fd, DRM_IOCTL_MESON_RMFB, &buf->fb_id);
135 if (ret < 0) {
chen.wang1d5483452024-02-28 06:18:16 +0000136 ERROR("%s %d Unable to rmfb: %s\n",__FUNCTION__,__LINE__,
wenlong.zhang7d32ed92023-04-12 06:08:17 +0000137 strerror(errno));
138 }
139 } else {
140 drmModeRmFB(drm_disp->drm_fd, buf->fb_id);
141 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800142 memset(&destroy_dumb, 0, sizeof(destroy_dumb));
143
144 for ( i = 0; i < buf->nbo; i++) {
chen.wang1518f14f2023-04-12 09:53:10 +0000145 if (!buf->bos[i])
146 continue;
147
Ao Xu6747bbd2020-09-28 20:02:09 +0800148 destroy_dumb.handle = meson_bo_handle(buf->bos[i]);
149
wenlong.zhanga71a2e02022-06-14 15:58:53 +0800150 ret = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
Ao Xu6747bbd2020-09-28 20:02:09 +0800151 if (ret < 0) {
152 /* If handle was from drmPrimeFDToHandle, then fd is connected
153 * as render, we have to use drm_gem_close to release it.
154 */
155 if (errno == EACCES) {
156 struct drm_gem_close close_req;
157 close_req.handle = destroy_dumb.handle;
wenlong.zhanga71a2e02022-06-14 15:58:53 +0800158 ret = drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close_req);
Ao Xu6747bbd2020-09-28 20:02:09 +0800159 if (ret < 0) {
chen.wang1d5483452024-02-28 06:18:16 +0000160 ERROR("%s %d Unable to destroy buffer: %s\n",__FUNCTION__,__LINE__,
Ao Xu6747bbd2020-09-28 20:02:09 +0800161 strerror(errno));
162 return -1;
163 }
164 }
165 }
chen.wang1518f14f2023-04-12 09:53:10 +0000166 free(buf->bos[i]);
167 buf->bos[i] = NULL;
Ao Xu6747bbd2020-09-28 20:02:09 +0800168 }
chen.wang1bace1312023-01-18 16:13:54 +0800169 free(buf);
chen.wang1518f14f2023-04-12 09:53:10 +0000170 buf = NULL;
Ao Xu6747bbd2020-09-28 20:02:09 +0800171 return 0;
172}
173static int kms_free_bufs(struct drm_display *drm_disp)
174{
175 int i;
176 struct drm_buf *buf;
Ao Xu6747bbd2020-09-28 20:02:09 +0800177 for ( i = 0; i < drm_disp->nbuf; i++ ) {
178 buf = &drm_disp->bufs[i];
179 free_buf(drm_disp, buf);
180 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800181 return 0;
182}
183
184static int kms_free_buf(struct drm_buf *buf)
185{
186 free_buf(buf->disp, buf);
187 return 0;
188}
189
Ao Xu70554242020-10-15 15:19:48 +0800190static struct meson_bo *alloc_bo(struct drm_display *drm_disp, struct drm_buf *buf, uint32_t bpp, uint32_t width,
191 uint32_t height, uint32_t *bo_handle, uint32_t *pitch)
192{
193 uint32_t size;
194 struct meson_bo *bo;
195
196 size = width * height * bpp / 8;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800197 bo = meson_bo_create(drm_disp->dev, size, buf->flags, drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800198 if (bo) {
199 *bo_handle = meson_bo_handle(bo);
200 *pitch = width * bpp / 8;
201 return bo;
202 } else {
chen.wang1d5483452024-02-28 06:18:16 +0000203 ERROR("%s %d meson_bo_create fail\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800204 return NULL;
205 }
206}
207
208static int alloc_bos(struct drm_display *drm_disp, struct drm_buf *buf, uint32_t *bo_handles)
209{
210 uint32_t width = buf->width;
211 uint32_t height = buf->height;
212
213 switch (buf->fourcc) {
214 case DRM_FORMAT_ARGB8888:
215 buf->nbo = 1;
216 buf->bos[0] = alloc_bo(drm_disp, buf, 32, width, height, &bo_handles[0], &buf->pitches[0]);
217 if (!buf->bos[0]) {
chen.wang1d5483452024-02-28 06:18:16 +0000218 ERROR("%s %d alloc_bo argb888 fail\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800219 return -1;
220 }
221
222 buf->size = width * height * 4;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800223 buf->fd[0] = meson_bo_dmabuf(buf->bos[0], drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800224 break;
225 case DRM_FORMAT_UYVY:
226 case DRM_FORMAT_YUYV:
227 buf->nbo = 1;
228 buf->bos[0] = alloc_bo(drm_disp, buf, 16, width, height, &bo_handles[0], &buf->pitches[0]);
229 if (!buf->bos[0]) {
chen.wang1d5483452024-02-28 06:18:16 +0000230 ERROR("%s %d alloc_bo yuyv or uyvy fail\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800231 return -1;
232 }
233
234 buf->size = width * height * 2;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800235 buf->fd[0] = meson_bo_dmabuf(buf->bos[0], drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800236 buf->commit_to_video = 1;
237 break;
238 case DRM_FORMAT_NV12:
239 case DRM_FORMAT_NV21:
240 buf->nbo = 2;
241 buf->bos[0] = alloc_bo(drm_disp, buf, 8, width, height, &bo_handles[0], &buf->pitches[0]);
242 if (!buf->bos[0]) {
chen.wang1d5483452024-02-28 06:18:16 +0000243 ERROR("%s %d alloc_bo nv12 or nv21 fail\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800244 return -1;
245 }
246
wenlong.zhang4c011d42022-06-09 10:59:38 +0800247 buf->fd[0] = meson_bo_dmabuf(buf->bos[0], drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800248
249 buf->bos[1] = alloc_bo(drm_disp, buf, 16, width/2, height/2, &bo_handles[1], &buf->pitches[1]);
250 if (!buf->bos[1]) {
chen.wang1d5483452024-02-28 06:18:16 +0000251 ERROR("%s %d alloc_bo argb888 fail\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800252 return -1;
253 }
wenlong.zhang4c011d42022-06-09 10:59:38 +0800254 buf->fd[1] = meson_bo_dmabuf(buf->bos[1], drm_disp->alloc_only);
Ao Xu70554242020-10-15 15:19:48 +0800255 buf->size = width * height * 3 / 2;
256 buf->commit_to_video = 1;
257 break;
258 default:
chen.wang1d5483452024-02-28 06:18:16 +0000259 ERROR("%s %d unsupport format: 0x%08x\n",__FUNCTION__,__LINE__,buf->fourcc);
Ao Xu70554242020-10-15 15:19:48 +0800260 break;
261 }
262
263 return 0;
264}
265
266static int add_framebuffer(int fd, struct drm_buf *buf, uint32_t *bo_handles, uint64_t modifier)
267{
268 int i, ret;
269 uint64_t modifiers[4] = { 0, 0, 0, 0 };
270 uint32_t flags = 0;
271 uint32_t fb_id;
272
273 for ( i = 0; i < buf->nbo; i++) {
274 if (bo_handles[i] != 0 && modifier != DRM_FORMAT_MOD_NONE) {
275 flags |= DRM_MODE_FB_MODIFIERS;
276 modifiers[i] = modifier;
277 }
278 }
279
280 ret = drmModeAddFB2WithModifiers(fd, buf->width, buf->height, buf->fourcc,
281 bo_handles, buf->pitches, buf->offsets, modifiers, &fb_id, flags);
282 if (ret < 0) {
chen.wang1d5483452024-02-28 06:18:16 +0000283 ERROR("%s %d Unable to add framebuffer for plane: %s\n",__FUNCTION__,__LINE__, strerror(errno));
Ao Xu70554242020-10-15 15:19:48 +0800284 return -1;
285 }
286
287 buf->fb_id = fb_id;
288 return 0;
289}
290
291static struct drm_buf *kms_alloc_buf(struct drm_display *drm_disp, struct drm_buf_metadata *info)
292{
293 int ret;
294 struct drm_buf *buf = NULL;
295 uint32_t bo_handles[4] = {0};
296
297 buf = calloc(1, sizeof(*buf));
298 buf->fourcc = info->fourcc;
299 buf->width = info->width;
300 buf->height = info->height;
301 buf->flags = info->flags;
302 buf->fence_fd = -1;
wenlong.zhangcf8a5462023-04-10 03:25:19 +0000303 buf->disable_plane = 0;
Ao Xu70554242020-10-15 15:19:48 +0800304 buf->disp = drm_disp;
305
306 ret = alloc_bos(drm_disp, buf, bo_handles);
307 if (ret) {
chen.wang1d5483452024-02-28 06:18:16 +0000308 ERROR("%s %d alloc_bos fail\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800309 free(buf);
310 return NULL;
311 }
312
chen.wang1bace1312023-01-18 16:13:54 +0800313 /*for non-root users, just need alloc buf and don't need to add framebuffer*/
314 if (drm_disp->alloc_only)
315 return buf;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800316
Ao Xu70554242020-10-15 15:19:48 +0800317 ret = add_framebuffer(drm_disp->drm_fd, buf, bo_handles, DRM_FORMAT_MOD_NONE);
318 if (ret) {
chen.wang1d5483452024-02-28 06:18:16 +0000319 ERROR("%s %d add_framebuffer fail, call free_buf\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800320 free_buf(drm_disp, buf);
Ao Xu70554242020-10-15 15:19:48 +0800321 return NULL;
322 }
323
324 return buf;
325}
326
327static int kms_alloc_bufs(struct drm_display *drm_disp, int num, struct drm_buf_metadata *info)
328{
329 int i, ret;
330 struct drm_buf *buf;
331 uint32_t bo_handles[4] = {0};
332
333 drm_disp->bufs = calloc(num, sizeof(*drm_disp->bufs));
334 drm_disp->nbuf = num;
335
336 for ( i = 0; i < num; i++) {
337 buf = &drm_disp->bufs[i];
338 buf->fourcc = info->fourcc;
339 buf->width = info->width;
340 buf->height = info->height;
341 buf->flags = info->flags;
342 buf->fence_fd = -1;
wenlong.zhangcf8a5462023-04-10 03:25:19 +0000343 buf->disable_plane = 0;
Ao Xu70554242020-10-15 15:19:48 +0800344 buf->disp = drm_disp;
345
346 if (!info->fourcc)
347 buf->fourcc = DRM_FORMAT_ARGB8888;
348
349 switch (buf->fourcc) {
350 case DRM_FORMAT_ARGB8888:
351 buf->nbo = 1;
352 break;
353 case DRM_FORMAT_UYVY:
354 case DRM_FORMAT_YUYV:
355 buf->nbo = 1;
356 break;
357 case DRM_FORMAT_NV12:
358 case DRM_FORMAT_NV21:
359 buf->nbo = 2;
360 break;
361 default:
chen.wang1d5483452024-02-28 06:18:16 +0000362 ERROR("%s %d unsupport format: 0x%08x\n",__FUNCTION__,__LINE__, buf->fourcc);
Ao Xu70554242020-10-15 15:19:48 +0800363 break;
364 }
365
366 ret = alloc_bos(drm_disp, buf, bo_handles);
367 if (ret) {
chen.wang1d5483452024-02-28 06:18:16 +0000368 ERROR("%s %d alloc_bos fail\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800369 return -1;
370 }
371
372 ret = add_framebuffer(drm_disp->drm_fd, buf, bo_handles, DRM_FORMAT_MOD_NONE);
373 if (ret) {
chen.wang1d5483452024-02-28 06:18:16 +0000374 ERROR("%s %d add_framebuffer fail\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800375 free_buf(drm_disp, buf);
376 return -1;
377 }
378 }
379 return 0;
380}
381
382static struct drm_buf *kms_import_buf(struct drm_display *disp, struct drm_buf_import *info)
383{
384 int i;
385 uint32_t size;
386 struct drm_buf *buf = NULL;
387 uint32_t bo_handles[4] = {0};
388
389 buf = calloc(1, sizeof(*buf));
390 buf->fourcc = info->fourcc;
391 buf->width = info->width;
392 buf->height = info->height;
393 buf->flags = info->flags;
394 buf->fence_fd = -1;
wenlong.zhangcf8a5462023-04-10 03:25:19 +0000395 buf->disable_plane = 0;
Ao Xu70554242020-10-15 15:19:48 +0800396 buf->disp = disp;
397
398 if (!info->fourcc)
399 buf->fourcc = DRM_FORMAT_ARGB8888;
400
401 switch (buf->fourcc) {
402 case DRM_FORMAT_ARGB8888:
403 buf->nbo = 1;
404 break;
405 case DRM_FORMAT_UYVY:
406 case DRM_FORMAT_YUYV:
407 buf->nbo = 1;
408 break;
409 case DRM_FORMAT_NV12:
410 case DRM_FORMAT_NV21:
411 buf->nbo = 2;
412 break;
413 default:
chen.wang1d5483452024-02-28 06:18:16 +0000414 ERROR("%s %d unsupport format: 0x%08x\n",__FUNCTION__,__LINE__,buf->fourcc);
Ao Xu70554242020-10-15 15:19:48 +0800415 break;
416 }
417
418 for (i = 0; i < buf->nbo; i++) {
419 if ( i == 0 )
420 size = info->width * info->height;
421 else
422 size = info->width * info->height / 2;
423
424 buf->size += size;
425 buf->fd[i] = info->fd[i];
426 buf->pitches[i] = buf->width;
427 buf->bos[i] = meson_bo_import(disp->dev, info->fd[i], size, info->flags);
428 if (!buf->bos[i]) {
chen.wang1d5483452024-02-28 06:18:16 +0000429 ERROR("%s %d meson_bo_import fail\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800430 return NULL;
431 }
432
433 bo_handles[i] = meson_bo_handle(buf->bos[i]);
434 }
435
436 add_framebuffer(disp->drm_fd, buf, bo_handles, DRM_FORMAT_MOD_NONE);
437
438 return buf;
439}
440
chen.wang1d5483452024-02-28 06:18:16 +0000441static int kms_set_plane(struct drm_display *drm_disp, struct drm_buf *buf)
442{
443 int ret;
444 uint32_t crtc_w, crtc_h;
445 struct kms_display *disp = to_kms_display(drm_disp);
446
447 struct plane_state *plane_state;
448 struct crtc_state *crtc_state;
449 struct connector_state *conn_state;
450
451 conn_state = disp->conn_states[0];
452 crtc_state = disp->crtc_states[0];
453
454 if (buf->flags & MESON_USE_VD1)
455 plane_state = disp->vid_states[0];
456 else if (buf->flags & MESON_USE_VD2)
457 plane_state = disp->vid_states[1];
458 else
459 plane_state = disp->osd_states[0];
460
461
462 if (buf->crtc_w == 0)
463 crtc_w = conn_state->mode.hdisplay;
464 else
465 crtc_w = buf->crtc_w;
466
467 if (buf->crtc_h == 0)
468 crtc_h = conn_state->mode.vdisplay;
469 else
470 crtc_h = buf->crtc_h;
471
472 if (drmModeSetPlane(drm_disp->drm_fd, plane_state->id, crtc_state->id, buf->fb_id,
473 0, buf->crtc_x, buf->crtc_y, crtc_w, crtc_h,
474 buf->src_x << 16, buf->src_y << 16, buf->src_w << 16, buf->src_h << 16)) {
475 ERROR("failed to set plane: %s\n",
476 strerror(errno));
477 return -1;
478 }
479
480 return ret;
481}
482
Ao Xu6747bbd2020-09-28 20:02:09 +0800483static int kms_post_buf(struct drm_display *drm_disp, struct drm_buf *buf)
484{
485 int ret;
486 drmModeAtomicReqPtr request;
Ao Xu6747bbd2020-09-28 20:02:09 +0800487 uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK;
488 struct kms_display *disp = to_kms_display(drm_disp);
489
490 struct plane_state *plane_state;
491 struct crtc_state *crtc_state;
492 struct connector_state *conn_state;
493
494 conn_state = disp->conn_states[0];
495 crtc_state = disp->crtc_states[0];
496
sky zhouf05ca462020-10-29 18:07:40 +0800497 if (buf->flags & MESON_USE_VD1)
Ao Xu6747bbd2020-09-28 20:02:09 +0800498 plane_state = disp->vid_states[0];
sky zhouf05ca462020-10-29 18:07:40 +0800499 else if (buf->flags & MESON_USE_VD2)
Ao Xu6747bbd2020-09-28 20:02:09 +0800500 plane_state = disp->vid_states[1];
501 else
502 plane_state = disp->osd_states[0];
503
504 request = drmModeAtomicAlloc();
505
wenlong.zhangcf8a5462023-04-10 03:25:19 +0000506 if (buf->disable_plane) {
507 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_x.id, 0);
508 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_y.id, 0);
509 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_w.id, 0);
510 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_h.id, 0);
511 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_x.id, 0);
512 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_y.id, 0);
513 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_w.id, 0);
514 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_h.id, 0);
515 drmModeAtomicAddProperty(request, plane_state->id, plane_state->fb_id.id, 0);
516 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_id.id, 0);
517 } else {
518 #if 0
519 if (!disp->mode_set) {
520 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
521 drmModeAtomicAddProperty(request, conn_state->id, conn_state->crtc_id.id, crtc_state->id);
Ao Xu6747bbd2020-09-28 20:02:09 +0800522
wenlong.zhangcf8a5462023-04-10 03:25:19 +0000523 if (drmModeCreatePropertyBlob(drm_disp->drm_fd, &disp->conn_states[0]->mode,
524 sizeof(drmModeModeInfo), &blob_id) != 0 ) {
525 return -1;
526 }
527 drmModeAtomicAddProperty(request, crtc_state->id, crtc_state->mode_id.id, blob_id);
528 drmModeAtomicAddProperty(request, crtc_state->id, crtc_state->active.id, 1);
529
530 disp->mode_set = 1;
Ao Xu6747bbd2020-09-28 20:02:09 +0800531 }
wenlong.zhangcf8a5462023-04-10 03:25:19 +0000532 #else
533 /*No modeset needed in post buf, modeset will control by systemservice.*/
534 #endif
Ao Xu6747bbd2020-09-28 20:02:09 +0800535
wenlong.zhangcf8a5462023-04-10 03:25:19 +0000536 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_x.id, buf->crtc_x);
537 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_y.id, buf->crtc_y);
538 if (buf->crtc_w == 0) {
539 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_w.id, conn_state->mode.hdisplay);
540 } else {
541 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_w.id, buf->crtc_w);
542 }
543
544 if (buf->crtc_h == 0) {
545 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_h.id, conn_state->mode.vdisplay);
546 } else {
547 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_h.id, buf->crtc_h);
548 }
549
550 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_x.id, buf->src_x << 16);
551 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_y.id, buf->src_y << 16);
552 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_w.id, buf->src_w << 16);
553 drmModeAtomicAddProperty(request, plane_state->id, plane_state->src_h.id, buf->src_h << 16);
554 drmModeAtomicAddProperty(request, plane_state->id, plane_state->fb_id.id, buf->fb_id);
555 drmModeAtomicAddProperty(request, plane_state->id, plane_state->crtc_id.id, crtc_state->id);
556 #if 0
557 if (buf->flags | (MESON_USE_VD2 | MESON_USE_VD1))
558 drmModeAtomicAddProperty(request, crtc_state->id, crtc_state->video_out_fence.id, VOID2U64(&buf->fence_fd));
559 else
560 drmModeAtomicAddProperty(request, crtc_state->id, crtc_state->out_fence.id, VOID2U64(&buf->fence_fd));
561 #endif
Ao Xu6747bbd2020-09-28 20:02:09 +0800562 }
sky zhouf05ca462020-10-29 18:07:40 +0800563
564 ret = drmModeAsyncAtomicCommit(drm_disp->drm_fd, request, flags, NULL);
Ao Xu6747bbd2020-09-28 20:02:09 +0800565 if (ret < 0) {
chen.wang1d5483452024-02-28 06:18:16 +0000566 ERROR("%s %d Unable to flip page: %s\n",__FUNCTION__,__LINE__,strerror(errno));
Ao Xu6747bbd2020-09-28 20:02:09 +0800567 goto error;
568 }
569
570 ret = 0;
571 goto complete;
572
573error:
574 ret = -1;
575complete:
576 drmModeAtomicFree(request);
577
578 return ret;
579}
580
581static void getproperty(int drm_fd, drmModeObjectProperties* props, const char *name,
582 struct property *p)
583{
584 int i;
585 drmModePropertyRes *res;
586 for (i = 0; i < props->count_props; i++) {
587 res = drmModeGetProperty(drm_fd, props->props[i]);
Ao Xu70554242020-10-15 15:19:48 +0800588 if (res && !strcmp(name, res->name)) {
589 p->id = res->prop_id;
590 p->value = props->prop_values[i];
591 //fprintf(stdout, "getproperty: %s, id: %u, value: %llu \n", res->name, p->id, p->value);
592 }
Ao Xu70554242020-10-15 15:19:48 +0800593 drmModeFreeProperty(res);
Ao Xu6747bbd2020-09-28 20:02:09 +0800594 }
595}
596
597static int populate_connectors(drmModeRes *resources, struct kms_display *disp)
598{
Ao Xu70554242020-10-15 15:19:48 +0800599 int i, j;
Ao Xu6747bbd2020-09-28 20:02:09 +0800600 int num_connector = 0;
601 struct connector_state *state;
602 drmModeConnector *connector;
603 drmModeEncoder *encoder;
604 drmModeObjectProperties *props;
605
606 for (i = 0; i < resources->count_connectors; i++) {
607 connector = drmModeGetConnector(disp->base.drm_fd, resources->connectors[i]);
Ao Xu70554242020-10-15 15:19:48 +0800608 if (!connector) {
chen.wang1d5483452024-02-28 06:18:16 +0000609 ERROR("%s %d drmModeGetConnector fail.\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800610 continue;
611 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800612
chen.wang1bace1312023-01-18 16:13:54 +0800613 if (connector->connector_type == DRM_MODE_CONNECTOR_TV) {
614 drmModeFreeConnector(connector);
Ao Xu6747bbd2020-09-28 20:02:09 +0800615 continue;
chen.wang1bace1312023-01-18 16:13:54 +0800616 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800617 state = calloc(1, sizeof(*state));
618 disp->conn_states[num_connector++] = state;
619 state->id = resources->connectors[i];
620
621 for (j = 0; j < connector->count_encoders; j++) {
622 encoder = drmModeGetEncoder(disp->base.drm_fd, connector->encoders[j]);
Ao Xu70554242020-10-15 15:19:48 +0800623 if (encoder) {
624 state->crtc_mask |= encoder->possible_crtcs;
625 drmModeFreeEncoder(encoder);
626 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800627 }
628
629 if (connector->count_modes)
630 state->mode = connector->modes[0];
631
632 for (j = 0; j < connector->count_modes; j++) {
633 if (connector->modes[j].type & DRM_MODE_TYPE_PREFERRED) {
634 state->mode = connector->modes[j];
635 break;
636 }
637 }
638
639 disp->base.width = state->mode.hdisplay;
640 disp->base.height = state->mode.vdisplay;
641 disp->base.vrefresh = state->mode.vrefresh;
642
643 props = drmModeObjectGetProperties(disp->base.drm_fd, resources->connectors[i], DRM_MODE_OBJECT_CONNECTOR);
Ao Xu6747bbd2020-09-28 20:02:09 +0800644 getproperty(disp->base.drm_fd, props, "CRTC_ID", &state->crtc_id);
Ao Xu70554242020-10-15 15:19:48 +0800645
646 if (props)
647 drmModeFreeObjectProperties(props);
648
649 if (connector)
650 drmModeFreeConnector(connector);
Ao Xu6747bbd2020-09-28 20:02:09 +0800651 }
652
653 disp->num_connector = num_connector;
chen.wang1d5483452024-02-28 06:18:16 +0000654 INFO("%s %d found %d connector\n",__FUNCTION__,__LINE__,num_connector);
Ao Xu70554242020-10-15 15:19:48 +0800655 return 0;
Ao Xu6747bbd2020-09-28 20:02:09 +0800656}
657
658static int populate_crtcs(drmModeRes *resources, struct kms_display *disp)
659{
Ao Xu70554242020-10-15 15:19:48 +0800660 int i;
Ao Xu6747bbd2020-09-28 20:02:09 +0800661 int num_crtc = 0;
662 struct crtc_state *state;
663 drmModeObjectProperties *props;
664
665 for (i = 0; i < resources->count_crtcs; i++) {
666 state = calloc(1, sizeof(*state));
Ao Xu70554242020-10-15 15:19:48 +0800667 if (!state) {
chen.wang1d5483452024-02-28 06:18:16 +0000668 ERROR("%s %d calloc crtc state fail.\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800669 return -1;
670 }
671
Ao Xu6747bbd2020-09-28 20:02:09 +0800672 disp->crtc_states[num_crtc++] = state;
673 state->id = resources->crtcs[i];
674
675 props = drmModeObjectGetProperties(disp->base.drm_fd, resources->crtcs[i], DRM_MODE_OBJECT_CRTC);
Ao Xu70554242020-10-15 15:19:48 +0800676 if (props) {
677 getproperty(disp->base.drm_fd, props, "MODE_ID", &state->mode_id);
678 getproperty(disp->base.drm_fd, props, "ACTIVE", &state->active);
679 getproperty(disp->base.drm_fd, props, "OUT_FENCE_PTR", &state->out_fence);
680 getproperty(disp->base.drm_fd, props, "VIDEO_OUT_FENCE_PTR", &state->video_out_fence);
Ao Xu70554242020-10-15 15:19:48 +0800681 drmModeFreeObjectProperties(props);
682 } else {
chen.wang1d5483452024-02-28 06:18:16 +0000683 ERROR("%s %d get crtc obj property fail\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800684 return -1;
685 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800686 }
687
688 disp->num_crtc = num_crtc;
689
chen.wang1d5483452024-02-28 06:18:16 +0000690 DEBUG("%s %d found %d crtc\n",__FUNCTION__,__LINE__,num_crtc);
Ao Xu70554242020-10-15 15:19:48 +0800691 return 0;
Ao Xu6747bbd2020-09-28 20:02:09 +0800692}
693
694static int is_plane_support_yuv(drmModePlane * plane)
695{
696 int i;
697 for (i = 0; i < plane->count_formats; i++) {
698 switch (plane->formats[i]) {
699 case DRM_FORMAT_NV12:
700 case DRM_FORMAT_NV21:
701 return 1;
702 default:
703 return 0;
704 }
705 }
706
707 return 0;
708}
709
710static int populate_planes(drmModeRes *resources, struct kms_display *disp)
711{
Ao Xu70554242020-10-15 15:19:48 +0800712 int i;
Ao Xu6747bbd2020-09-28 20:02:09 +0800713 int num_osd_plane = 0;
714 int num_vid_plane = 0;
715 struct plane_state *state;
716 drmModePlane *plane;
717 drmModePlaneRes *plane_res;
718 drmModeObjectProperties *props;
719
720 plane_res = drmModeGetPlaneResources(disp->base.drm_fd);
Ao Xu70554242020-10-15 15:19:48 +0800721 if (!plane_res) {
chen.wang1d5483452024-02-28 06:18:16 +0000722 ERROR("%s %d drmModeGetPlaneResources fail.\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800723 goto error;
724 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800725
726 for (i = 0; i < plane_res->count_planes; i++) {
727 state = calloc(1, sizeof(*state));
Ao Xu70554242020-10-15 15:19:48 +0800728 if (!state) {
chen.wang1d5483452024-02-28 06:18:16 +0000729 ERROR("%s %d calloc plane state fail.\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800730 goto error;
731 }
732
Ao Xu6747bbd2020-09-28 20:02:09 +0800733 plane = drmModeGetPlane(disp->base.drm_fd, plane_res->planes[i]);
Ao Xu70554242020-10-15 15:19:48 +0800734 if (plane) {
735 if (is_plane_support_yuv(plane))
736 disp->vid_states[num_vid_plane++] = state;
737 else
738 disp->osd_states[num_osd_plane++] = state;
Ao Xu6747bbd2020-09-28 20:02:09 +0800739
Ao Xu70554242020-10-15 15:19:48 +0800740 state->id = plane_res->planes[i];
741 state->crtc_mask = plane->possible_crtcs;
Ao Xu6747bbd2020-09-28 20:02:09 +0800742
Ao Xu70554242020-10-15 15:19:48 +0800743 props = drmModeObjectGetProperties(disp->base.drm_fd, plane_res->planes[i], DRM_MODE_OBJECT_PLANE);
744 if (props) {
745 getproperty(disp->base.drm_fd, props, "CRTC_ID", &state->crtc_id);
746 getproperty(disp->base.drm_fd, props, "CRTC_X", &state->crtc_x);
747 getproperty(disp->base.drm_fd, props, "CRTC_Y", &state->crtc_y);
748 getproperty(disp->base.drm_fd, props, "CRTC_W", &state->crtc_w);
749 getproperty(disp->base.drm_fd, props, "CRTC_H", &state->crtc_h);
750 getproperty(disp->base.drm_fd, props, "FB_ID", &state->fb_id);
751 getproperty(disp->base.drm_fd, props, "SRC_X", &state->src_x);
752 getproperty(disp->base.drm_fd, props, "SRC_Y", &state->src_y);
753 getproperty(disp->base.drm_fd, props, "SRC_W", &state->src_w);
754 getproperty(disp->base.drm_fd, props, "SRC_H", &state->src_h);
755 getproperty(disp->base.drm_fd, props, "type", &state->type);
756 getproperty(disp->base.drm_fd, props, "IN_FENCE_FD", &state->in_fence_fd);
757 getproperty(disp->base.drm_fd, props, "IN_FORMATS", &state->in_formats);
758 }
759 }
760
761 if (props)
762 drmModeFreeObjectProperties(props);
763
764 if (plane)
765 drmModeFreePlane(plane);
Ao Xu6747bbd2020-09-28 20:02:09 +0800766 }
767
768 disp->num_osd_plane = num_osd_plane;
769 disp->num_vid_plane = num_vid_plane;
770
Ao Xu70554242020-10-15 15:19:48 +0800771 drmModeFreePlaneResources(plane_res);
772
chen.wang1d5483452024-02-28 06:18:16 +0000773 INFO("%s %d found %d osd, %d video\n",__FUNCTION__,__LINE__,num_osd_plane, num_vid_plane);
Ao Xu70554242020-10-15 15:19:48 +0800774 return 0;
775
776error:
777 drmModeFreePlaneResources(plane_res);
778
779 return -1;
Ao Xu6747bbd2020-09-28 20:02:09 +0800780}
781
782static int drm_kms_init_resource(struct kms_display *disp)
783{
784 int ret;
limin.tian79bf2b12023-02-24 10:28:26 +0000785 int drm_fd = -1;
786 int render_fd = -1;
Ao Xu6747bbd2020-09-28 20:02:09 +0800787 drmModeRes *resources;
788
789 drm_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
790 if (drm_fd < 0) {
chen.wang1d5483452024-02-28 06:18:16 +0000791 ERROR("%s %d Unable to open DRM node: %s\n",__FUNCTION__,__LINE__,
Ao Xu6747bbd2020-09-28 20:02:09 +0800792 strerror(errno));
793 return -1;
794 }
chen.wang1f5503ea2023-04-12 07:36:24 +0000795 drmDropMaster(drm_fd);
wenlong.zhang4c011d42022-06-09 10:59:38 +0800796 render_fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC);
797 if (render_fd < 0) {
chen.wang1d5483452024-02-28 06:18:16 +0000798 ERROR("%s %d Unable to open renderD128 node: %s\n",__FUNCTION__,__LINE__,
wenlong.zhang4c011d42022-06-09 10:59:38 +0800799 strerror(errno));
limin.tian79bf2b12023-02-24 10:28:26 +0000800 goto error3;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800801 }
802
Ao Xu6747bbd2020-09-28 20:02:09 +0800803 disp->base.drm_fd = drm_fd;
wenlong.zhang4c011d42022-06-09 10:59:38 +0800804 disp->base.dev = meson_device_create(drm_fd, render_fd);
Ao Xu70554242020-10-15 15:19:48 +0800805 if (!disp->base.dev) {
chen.wang1d5483452024-02-28 06:18:16 +0000806 ERROR("%s %d meson_device_create fail\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800807 goto error3;
808 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800809
810 ret = drmSetClientCap(drm_fd, DRM_CLIENT_CAP_ATOMIC, 1);
811 if (ret < 0) {
chen.wang1d5483452024-02-28 06:18:16 +0000812 ERROR("%s %d Unable to set DRM atomic capability: %s\n",__FUNCTION__,__LINE__,
Ao Xu6747bbd2020-09-28 20:02:09 +0800813 strerror(errno));
Ao Xu70554242020-10-15 15:19:48 +0800814 goto error2;
Ao Xu6747bbd2020-09-28 20:02:09 +0800815 }
816
817 ret = drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
818 if (ret < 0) {
chen.wang1d5483452024-02-28 06:18:16 +0000819 ERROR("%s %d Unable to set DRM universal planes capability: %s\n",__FUNCTION__,__LINE__,
Ao Xu6747bbd2020-09-28 20:02:09 +0800820 strerror(errno));
Ao Xu70554242020-10-15 15:19:48 +0800821 goto error2;
Ao Xu6747bbd2020-09-28 20:02:09 +0800822 }
823
824 resources = drmModeGetResources(drm_fd);
825 if (!resources) {
chen.wang1d5483452024-02-28 06:18:16 +0000826 ERROR("%s %d drmModeGetResources failed: %s\n",__FUNCTION__,__LINE__, strerror(errno));
Ao Xu70554242020-10-15 15:19:48 +0800827 goto error2;
Ao Xu6747bbd2020-09-28 20:02:09 +0800828 }
829
Ao Xu70554242020-10-15 15:19:48 +0800830 ret = populate_connectors(resources, disp);
831 if (ret)
832 goto error1;
Ao Xu6747bbd2020-09-28 20:02:09 +0800833
Ao Xu70554242020-10-15 15:19:48 +0800834 ret = populate_crtcs(resources, disp);
835 if (ret)
836 goto error1;
837
838 ret = populate_planes(resources, disp);
839 if (ret)
840 goto error1;
chen.wang1bace1312023-01-18 16:13:54 +0800841 drmModeFreeResources(resources);
Ao Xu6747bbd2020-09-28 20:02:09 +0800842 return 0;
Ao Xu70554242020-10-15 15:19:48 +0800843
844error1:
845 drmModeFreeResources(resources);
846error2:
847 meson_device_destroy(disp->base.dev);
848error3:
limin.tian79bf2b12023-02-24 10:28:26 +0000849 if (drm_fd >= 0)
850 close(drm_fd);
851 if (render_fd >= 0)
852 close(render_fd);
Ao Xu70554242020-10-15 15:19:48 +0800853
854 return -1;
Ao Xu6747bbd2020-09-28 20:02:09 +0800855}
856
857struct drm_display *drm_kms_init(void)
858{
Ao Xu70554242020-10-15 15:19:48 +0800859 int ret;
Ao Xu6747bbd2020-09-28 20:02:09 +0800860 struct kms_display *display;
861 struct drm_display *base;
862 display = calloc(1, sizeof(*display));
Ao Xu70554242020-10-15 15:19:48 +0800863 if (!display) {
chen.wang1d5483452024-02-28 06:18:16 +0000864 ERROR("%s %d calloc kms_display fail\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800865 return NULL;
866 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800867
868 base = &display->base;
869 base->destroy_display = kms_destroy_display;
870 base->alloc_bufs = kms_alloc_bufs;
871 base->free_bufs = kms_free_bufs;
872
873 base->alloc_buf = kms_alloc_buf;
Ao Xu70554242020-10-15 15:19:48 +0800874 base->import_buf = kms_import_buf;
Ao Xu6747bbd2020-09-28 20:02:09 +0800875 base->free_buf = kms_free_buf;
876 base->post_buf = kms_post_buf;
chen.wang1bace1312023-01-18 16:13:54 +0800877 base->alloc_only = 0;
wenlong.zhang7d32ed92023-04-12 06:08:17 +0000878 base->freeze = 0;
Ao Xu6747bbd2020-09-28 20:02:09 +0800879
Ao Xu70554242020-10-15 15:19:48 +0800880 ret = drm_kms_init_resource(display);
881 if (ret) {
chen.wang1d5483452024-02-28 06:18:16 +0000882 ERROR("%s %d drm_kms_init_resource fail.\n",__FUNCTION__,__LINE__);
Ao Xu70554242020-10-15 15:19:48 +0800883 free(display);
884 return NULL;
885 }
Ao Xu6747bbd2020-09-28 20:02:09 +0800886
887 return base;
888}