5 #include <drm_fourcc.h>
6 #include <tdm_helper.h>
12 typedef struct _tdm_vc4_output_data tdm_vc4_output_data;
13 typedef struct _tdm_vc4_layer_data tdm_vc4_layer_data;
14 typedef struct _tdm_vc4_event_data tdm_vc4_event_data;
17 TDM_DRM_EVENT_TYPE_WAIT,
18 TDM_DRM_EVENT_TYPE_COMMIT,
19 TDM_DRM_EVENT_TYPE_PAGEFLIP,
22 typedef struct _tdm_vc4_display_buffer {
23 struct list_head link;
28 } tdm_vc4_display_buffer;
30 struct _tdm_vc4_event_data {
31 tdm_vc4_event_type type;
32 tdm_vc4_output_data *output_data;
36 struct _tdm_vc4_output_data {
37 struct list_head link;
39 /* data which are fixed at initializing */
40 tdm_vc4_data *vc4_data;
41 uint32_t connector_id;
45 uint32_t dpms_prop_id;
47 drmModeModeInfoPtr vc4_modes;
48 tdm_output_mode *output_modes;
49 tdm_output_type connector_type;
50 unsigned int connector_type_id;
51 struct list_head layer_list;
52 tdm_vc4_layer_data *primary_layer;
54 /* not fixed data below */
55 tdm_output_vblank_handler vblank_func;
56 tdm_output_commit_handler commit_func;
58 tdm_output_conn_status status;
59 tdm_output_status_handler status_func;
60 void *status_user_data;
63 const tdm_output_mode *current_mode;
65 tbm_surface_h crtc_buffer;
67 unsigned int crtc_fb_id;
70 struct _tdm_vc4_layer_data {
71 struct list_head link;
73 /* data which are fixed at initializing */
74 tdm_vc4_data *vc4_data;
75 tdm_vc4_output_data *output_data;
77 tdm_layer_capability capabilities;
80 /* not fixed data below */
84 tdm_vc4_display_buffer *display_buffer;
85 int display_buffer_changed;
88 static drmModeModeInfoPtr
89 _tdm_vc4_display_get_mode(tdm_vc4_output_data *output_data)
93 if (!output_data->current_mode) {
94 TDM_ERR("no output_data->current_mode");
98 for (i = 0; i < output_data->count_modes; i++) {
99 drmModeModeInfoPtr vc4_mode = &output_data->vc4_modes[i];
100 if ((vc4_mode->hdisplay == output_data->current_mode->hdisplay) &&
101 (vc4_mode->vdisplay == output_data->current_mode->vdisplay) &&
102 (vc4_mode->vrefresh == output_data->current_mode->vrefresh) &&
103 (vc4_mode->flags == output_data->current_mode->flags) &&
104 (vc4_mode->type == output_data->current_mode->type) &&
105 !(strncmp(vc4_mode->name, output_data->current_mode->name, TDM_NAME_LEN)))
113 _tdm_vc4_display_set_fb(tdm_vc4_data *vc4_data, tbm_surface_h buffer, unsigned int *id)
118 unsigned int handles[4] = {0,};
119 unsigned int pitches[4] = {0,};
120 unsigned int offsets[4] = {0,};
125 width = tbm_surface_get_width(buffer);
126 height = tbm_surface_get_height(buffer);
127 format = tbm_surface_get_format(buffer);
128 count = tbm_surface_internal_get_num_bos(buffer);
129 for (i = 0; i < count; i++) {
130 tbm_bo bo = tbm_surface_internal_get_bo(buffer, i);
131 handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
133 count = tbm_surface_internal_get_num_planes(format);
134 for (i = 0; i < count; i++)
135 tbm_surface_internal_get_plane_data(buffer, i, &size, &offsets[i], &pitches[i]);
137 TDM_DBG("AddFB2: drm_fd(%d) size(%dx%d) format(%c%c%c%c) handles(%d,%d,%d) pitches(%d,%d,%d) offsets(%d,%d,%d) buffer(%p)",
138 vc4_data->drm_fd, width, height, FOURCC_STR(format),
139 handles[0], handles[1], handles[2], pitches[0], pitches[1], pitches[2],
140 offsets[0], offsets[1], offsets[2], buffer);
142 ret = drmModeAddFB2(vc4_data->drm_fd, width, height, format,
143 handles, pitches, offsets, &fb_id, 0);
145 TDM_ERR("add fb failed: %m");
146 return TDM_ERROR_OPERATION_FAILED;
148 TDM_DBG("AddFB2 success: drm_fd(%d) fb_id(%u)", vc4_data->drm_fd, fb_id);
151 return TDM_ERROR_NONE;
155 _tdm_vc4_display_set_crtc(tdm_vc4_data *vc4_data, tdm_vc4_output_data *output_data, int set)
159 output_data->mode_changed = 0;
162 tbm_surface_h buffer = NULL;
163 tbm_surface_info_s info;
164 drmModeModeInfoPtr mode;
165 unsigned int fb_id = 0;
167 if (!output_data->current_mode)
168 return TDM_ERROR_OPERATION_FAILED;
170 mode = _tdm_vc4_display_get_mode(output_data);
172 TDM_ERR("couldn't find proper mode");
173 return TDM_ERROR_BAD_REQUEST;
176 buffer = tbm_surface_create(output_data->current_mode->hdisplay,
177 output_data->current_mode->vdisplay,
178 TBM_FORMAT_XRGB8888);
179 RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_OPERATION_FAILED);
181 tbm_surface_map(buffer, TBM_SURF_OPTION_WRITE, &info);
182 memset(info.planes[0].ptr, 0x0, info.size);
184 tbm_surface_unmap(buffer);
186 if (_tdm_vc4_display_set_fb(vc4_data, buffer, &fb_id) != TDM_ERROR_NONE) {
187 tbm_surface_destroy(buffer);
188 return TDM_ERROR_OPERATION_FAILED;
191 TDM_DBG("drmModeSetCrtc drm_fd(%d) crtc_id(%u) fb_id(%u) mode(%u,%u)",
192 vc4_data->drm_fd, output_data->crtc_id, fb_id,
193 mode->hdisplay, mode->vdisplay);
194 if (drmModeSetCrtc(vc4_data->drm_fd, output_data->crtc_id,
196 &output_data->connector_id, 1, mode)) {
197 TDM_ERR("set crtc failed: %m");
198 ret = drmModeRmFB(vc4_data->drm_fd, fb_id);
200 TDM_ERR("rm fb failed fb_id(%u)", fb_id);
201 tbm_surface_destroy(buffer);
202 return TDM_ERROR_OPERATION_FAILED;
205 if (output_data->crtc_buffer) {
206 ret = drmModeRmFB(vc4_data->drm_fd, output_data->crtc_fb_id);
208 TDM_ERR("rm fb failed fb_id(%u)", output_data->crtc_fb_id);
209 tbm_surface_destroy(output_data->crtc_buffer);
211 output_data->crtc_buffer = buffer;
212 output_data->crtc_fb_id = fb_id;
214 TDM_DBG("drmModeSetCrtc unset drm_fd(%d) crtc_id(%u)",
215 vc4_data->drm_fd, output_data->crtc_id);
216 if (drmModeSetCrtc(vc4_data->drm_fd, output_data->crtc_id,
217 0, 0, 0, NULL, 0, NULL)) {
218 TDM_ERR("unset crtc failed: %m");
219 return TDM_ERROR_OPERATION_FAILED;
222 if (output_data->crtc_buffer) {
223 ret = drmModeRmFB(vc4_data->drm_fd, output_data->crtc_fb_id);
225 TDM_ERR("rm fb failed fb_id(%u)", output_data->crtc_fb_id);
226 tbm_surface_destroy(output_data->crtc_buffer);
228 output_data->crtc_buffer = NULL;
229 output_data->crtc_fb_id = 0;
232 return TDM_ERROR_NONE;
235 static tdm_vc4_display_buffer *
236 _tdm_vc4_display_find_buffer(tdm_vc4_data *vc4_data, tbm_surface_h buffer)
238 tdm_vc4_display_buffer *display_buffer = NULL;
240 LIST_FOR_EACH_ENTRY(display_buffer, &vc4_data->buffer_list, link) {
241 if (display_buffer->buffer == buffer)
242 return display_buffer;
249 _tdm_vc4_display_to_tdm_mode(drmModeModeInfoPtr vc4_mode,
250 tdm_output_mode *tdm_mode)
252 tdm_mode->clock = vc4_mode->clock;
253 tdm_mode->hdisplay = vc4_mode->hdisplay;
254 tdm_mode->hsync_start = vc4_mode->hsync_start;
255 tdm_mode->hsync_end = vc4_mode->hsync_end;
256 tdm_mode->htotal = vc4_mode->htotal;
257 tdm_mode->hskew = vc4_mode->hskew;
258 tdm_mode->vdisplay = vc4_mode->vdisplay;
259 tdm_mode->vsync_start = vc4_mode->vsync_start;
260 tdm_mode->vsync_end = vc4_mode->vsync_end;
261 tdm_mode->vtotal = vc4_mode->vtotal;
262 tdm_mode->vscan = vc4_mode->vscan;
263 tdm_mode->vrefresh = vc4_mode->vrefresh;
264 tdm_mode->flags = vc4_mode->flags;
265 tdm_mode->type = vc4_mode->type;
266 snprintf(tdm_mode->name, TDM_NAME_LEN, "%s", vc4_mode->name);
270 _tdm_vc4_display_get_cur_msc(int fd, int pipe, uint *msc)
274 vbl.request.type = DRM_VBLANK_RELATIVE;
276 vbl.request.type |= DRM_VBLANK_SECONDARY;
278 vbl.request.type |= pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
280 vbl.request.sequence = 0;
281 if (drmWaitVBlank(fd, &vbl)) {
282 TDM_ERR("get vblank counter failed: %m");
284 return TDM_ERROR_OPERATION_FAILED;
287 *msc = vbl.reply.sequence;
289 return TDM_ERROR_NONE;
293 _tdm_vc4_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data)
297 vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
299 vbl.request.type |= DRM_VBLANK_SECONDARY;
301 vbl.request.type |= pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
303 vbl.request.sequence = *target_msc;
304 vbl.request.signal = (unsigned long)(uintptr_t)data;
306 if (drmWaitVBlank(fd, &vbl)) {
307 TDM_ERR("wait vblank failed: %m");
309 return TDM_ERROR_OPERATION_FAILED;
312 *target_msc = vbl.reply.sequence;
314 return TDM_ERROR_NONE;
318 _tdm_vc4_output_update_status(tdm_vc4_output_data *output_data,
319 tdm_output_conn_status status)
321 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
323 if (output_data->status == status)
324 return TDM_ERROR_NONE;
326 output_data->status = status;
328 if (output_data->status_func)
329 output_data->status_func(output_data, status,
330 output_data->status_user_data);
332 return TDM_ERROR_NONE;
336 _tdm_vc4_display_commit_layer(tdm_vc4_layer_data *layer_data)
338 tdm_vc4_data *vc4_data = layer_data->vc4_data;
339 tdm_vc4_output_data *output_data = layer_data->output_data;
340 uint32_t fx, fy, fw, fh;
343 if (!layer_data->display_buffer_changed && !layer_data->info_changed)
344 return TDM_ERROR_NONE;
346 if (!output_data->crtc_enabled || output_data->mode_changed) {
347 if (_tdm_vc4_display_set_crtc(vc4_data, output_data, 1) != TDM_ERROR_NONE)
348 return TDM_ERROR_OPERATION_FAILED;
350 output_data->crtc_enabled = 1;
353 if (output_data->current_mode)
354 crtc_w = output_data->current_mode->hdisplay;
356 drmModeCrtcPtr crtc = drmModeGetCrtc(vc4_data->drm_fd, output_data->crtc_id);
358 TDM_ERR("getting crtc failed");
359 return TDM_ERROR_OPERATION_FAILED;
361 crtc_w = crtc->width;
363 TDM_ERR("getting crtc width failed");
364 drmModeFreeCrtc(crtc);
365 return TDM_ERROR_OPERATION_FAILED;
367 drmModeFreeCrtc(crtc);
370 layer_data->display_buffer_changed = 0;
371 layer_data->info_changed = 0;
373 if (!layer_data->display_buffer) {
374 if (drmModeSetPlane(vc4_data->drm_fd, layer_data->plane_id,
375 output_data->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
376 TDM_ERR("unset plane(%d) filed: %m", layer_data->plane_id);
378 return TDM_ERROR_NONE;
381 /* Source values are 16.16 fixed point */
382 fx = ((unsigned int)layer_data->info.src_config.pos.x) << 16;
383 fy = ((unsigned int)layer_data->info.src_config.pos.y) << 16;
384 fw = ((unsigned int)layer_data->info.src_config.pos.w) << 16;
385 fh = ((unsigned int)layer_data->info.src_config.pos.h) << 16;
387 if (drmModeSetPlane(vc4_data->drm_fd, layer_data->plane_id,
388 output_data->crtc_id, layer_data->display_buffer->fb_id, 0,
389 layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
390 layer_data->info.dst_pos.w, layer_data->info.dst_pos.h,
391 fx, fy, fw, fh) < 0) {
392 TDM_ERR("set plane(%d) failed: %m", layer_data->plane_id);
393 return TDM_ERROR_OPERATION_FAILED;
396 TDM_DBG("plane(%d) crtc(%d) pos(%d) on: fb(%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n",
397 layer_data->plane_id, output_data->crtc_id, layer_data->zpos,
398 layer_data->display_buffer->fb_id,
399 layer_data->info.src_config.pos.x, layer_data->info.src_config.pos.y,
400 layer_data->info.src_config.pos.w, layer_data->info.src_config.pos.h,
401 layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
402 layer_data->info.dst_pos.w, layer_data->info.dst_pos.h);
404 return TDM_ERROR_NONE;
408 _tdm_vc4_display_cb_event(int fd, unsigned int sequence,
409 unsigned int tv_sec, unsigned int tv_usec,
412 tdm_vc4_event_data *event_data = user_data;
413 tdm_vc4_output_data *output_data;
416 TDM_ERR("no event data");
420 output_data = event_data->output_data;
422 switch (event_data->type) {
423 case TDM_DRM_EVENT_TYPE_PAGEFLIP:
424 if (output_data->commit_func)
425 output_data->commit_func(output_data, sequence, tv_sec, tv_usec,
426 event_data->user_data);
428 case TDM_DRM_EVENT_TYPE_WAIT:
429 if (output_data->vblank_func)
430 output_data->vblank_func(output_data, sequence, tv_sec, tv_usec,
431 event_data->user_data);
433 case TDM_DRM_EVENT_TYPE_COMMIT:
434 if (output_data->commit_func)
435 output_data->commit_func(output_data, sequence, tv_sec, tv_usec,
436 event_data->user_data);
446 _tdm_vc4_display_create_layer_list(tdm_vc4_data *vc4_data)
448 tdm_vc4_output_data *output_data = NULL;
451 if (LIST_IS_EMPTY(&vc4_data->output_list)) {
452 TDM_ERR("no output");
453 return TDM_ERROR_OPERATION_FAILED;
456 /* The TDM drm backend only support one output. */
457 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
461 if (vc4_data->plane_res->count_planes == 0) {
462 TDM_ERR("no layer error");
463 return TDM_ERROR_OPERATION_FAILED;
466 for (i = 0; i < vc4_data->plane_res->count_planes; i++) {
467 tdm_vc4_layer_data *layer_data;
468 drmModePlanePtr plane;
470 plane = drmModeGetPlane(vc4_data->drm_fd, vc4_data->plane_res->planes[i]);
476 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
477 drmModeFreePlane(plane);
481 layer_data = calloc(1, sizeof(tdm_vc4_layer_data));
483 TDM_ERR("alloc failed");
484 drmModeFreePlane(plane);
488 layer_data->vc4_data = vc4_data;
489 layer_data->output_data = output_data;
490 layer_data->plane_id = vc4_data->plane_res->planes[i];
492 layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
493 TDM_LAYER_CAPABILITY_GRAPHIC;
494 output_data->primary_layer = layer_data;
496 TDM_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) capabilities(%x)",
497 layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
498 layer_data->capabilities);
500 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
502 drmModeFreePlane(plane);
504 /* can't take care of other planes for various hardware devices */
508 return TDM_ERROR_NONE;
511 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
514 _tdm_vc4_display_get_property(tdm_vc4_data *vc4_data,
515 unsigned int obj_id, unsigned int obj_type,
516 const char *name, unsigned int *value,
519 drmModeObjectPropertiesPtr props = NULL;
522 props = drmModeObjectGetProperties(vc4_data->drm_fd, obj_id, obj_type);
524 return TDM_ERROR_OPERATION_FAILED;
526 for (i = 0; i < props->count_props; i++) {
527 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd,
533 if (!strcmp(prop->name, name)) {
535 *is_immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
537 *value = (unsigned int)props->prop_values[i];
538 drmModeFreeProperty(prop);
539 drmModeFreeObjectProperties(props);
540 return TDM_ERROR_NONE;
543 drmModeFreeProperty(prop);
545 drmModeFreeObjectProperties(props);
546 TDM_DBG("coundn't find '%s' property", name);
547 return TDM_ERROR_OPERATION_FAILED;
551 _tdm_vc4_display_create_layer_list_type(tdm_vc4_data *vc4_data)
553 tdm_vc4_output_data *output_data = NULL;
554 drmModePlanePtr *planes = NULL;
555 unsigned int *types = NULL;
556 unsigned int type = 0;
557 int plane_cnt, primary_cnt, ovl_cnt, cursor_cnt;
558 int opos_next, cpos_next;
562 if (LIST_IS_EMPTY(&vc4_data->output_list)) {
563 TDM_ERR("no output");
564 return TDM_ERROR_OPERATION_FAILED;
567 /* The TDM drm backend only support one output. */
568 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
572 ret = _tdm_vc4_display_get_property(vc4_data,
573 vc4_data->plane_res->planes[0],
574 DRM_MODE_OBJECT_PLANE, "type", &type,
576 if (ret != TDM_ERROR_NONE) {
577 TDM_ERR("plane doesn't have 'type' property. Call a fallback function");
579 /* if a plane doesn't have "type" property, we call a fallback function
582 return _tdm_vc4_display_create_layer_list(vc4_data);
585 planes = calloc(vc4_data->plane_res->count_planes, sizeof(drmModePlanePtr));
587 TDM_ERR("alloc failed");
591 types = calloc(vc4_data->plane_res->count_planes, sizeof(unsigned int));
593 TDM_ERR("alloc failed");
598 for (i = 0; i < vc4_data->plane_res->count_planes; i++) {
599 drmModePlanePtr plane;
601 plane = drmModeGetPlane(vc4_data->drm_fd, vc4_data->plane_res->planes[i]);
603 TDM_ERR("no plane(%d)", vc4_data->plane_res->planes[i]);
607 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
608 drmModeFreePlane(plane);
612 ret = _tdm_vc4_display_get_property(vc4_data,
613 vc4_data->plane_res->planes[i],
614 DRM_MODE_OBJECT_PLANE, "type", &type,
616 if (ret != TDM_ERROR_NONE) {
617 drmModeFreePlane(plane);
618 TDM_ERR("plane(%d) doesn't have 'type' info",
619 vc4_data->plane_res->planes[i]);
623 planes[plane_cnt] = plane;
624 types[plane_cnt] = type;
628 primary_cnt = ovl_cnt = cursor_cnt = 0;
629 for (i = 0; i < plane_cnt; i++) {
630 if (types[i] == DRM_PLANE_TYPE_CURSOR)
632 else if (types[i] == DRM_PLANE_TYPE_OVERLAY)
634 else if (types[i] == DRM_PLANE_TYPE_PRIMARY)
637 TDM_ERR("invalid type(%d)", types[i]);
640 if (primary_cnt != 1) {
641 TDM_ERR("primary layer count(%d) should be one", primary_cnt);
645 /* do not use primary plane(0) because of yuv format displaying problem */
646 /* set 2nd overlay plane to primary, 1st plane is for video */
648 cpos_next = ovl_cnt - 1;
649 for (i = 1; i < plane_cnt; i++) {
650 tdm_vc4_layer_data *layer_data;
652 layer_data = calloc(1, sizeof(tdm_vc4_layer_data));
654 TDM_ERR("alloc failed");
658 layer_data->vc4_data = vc4_data;
659 layer_data->output_data = output_data;
660 layer_data->plane_id = planes[i]->plane_id;
662 if (types[i] == DRM_PLANE_TYPE_CURSOR) {
663 layer_data->capabilities = TDM_LAYER_CAPABILITY_CURSOR |
664 TDM_LAYER_CAPABILITY_GRAPHIC;
665 layer_data->zpos = cpos_next++;
666 } else if (types[i] == DRM_PLANE_TYPE_OVERLAY) {
668 layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY |
669 TDM_LAYER_CAPABILITY_GRAPHIC |
670 TDM_LAYER_CAPABILITY_SCALE;
672 layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
673 TDM_LAYER_CAPABILITY_GRAPHIC;
674 output_data->primary_layer = layer_data;
676 layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY |
677 TDM_LAYER_CAPABILITY_GRAPHIC;
679 layer_data->zpos = opos_next++;
685 TDM_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) zpos(%d) capabilities(%x)",
686 layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
687 layer_data->zpos, layer_data->capabilities);
689 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
692 for (i = 0; i < plane_cnt; i++)
694 drmModeFreePlane(planes[i]);
699 return TDM_ERROR_NONE;
703 for (i = 0; i < vc4_data->plane_res->count_planes; i++)
705 drmModeFreePlane(planes[i]);
711 return TDM_ERROR_OPERATION_FAILED;
716 _tdm_vc4_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
718 tdm_vc4_data *vc4_data;
719 tdm_vc4_display_buffer *display_buffer;
723 TDM_ERR("no user_data");
727 TDM_ERR("no buffer");
731 vc4_data = (tdm_vc4_data *)user_data;
733 display_buffer = _tdm_vc4_display_find_buffer(vc4_data, buffer);
734 if (!display_buffer) {
735 TDM_ERR("no display_buffer");
738 LIST_DEL(&display_buffer->link);
740 if (display_buffer->fb_id > 0) {
741 ret = drmModeRmFB(vc4_data->drm_fd, display_buffer->fb_id);
743 TDM_ERR("rm fb failed");
746 TDM_DBG("drmModeRmFB success!!! fb_id:%d", display_buffer->fb_id);
748 TDM_DBG("drmModeRmFB not called fb_id:%d", display_buffer->fb_id);
750 free(display_buffer);
754 tdm_vc4_display_create_layer_list(tdm_vc4_data *vc4_data)
756 tdm_vc4_output_data *output_data = NULL;
759 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
760 if (vc4_data->has_universal_plane)
761 ret = _tdm_vc4_display_create_layer_list_type(vc4_data);
764 ret = _tdm_vc4_display_create_layer_list(vc4_data);
766 if (ret != TDM_ERROR_NONE)
769 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
770 if (!output_data->primary_layer) {
771 TDM_ERR("output(%d) no primary layer", output_data->pipe);
772 return TDM_ERROR_OPERATION_FAILED;
776 return TDM_ERROR_NONE;
780 tdm_vc4_display_destroy_output_list(tdm_vc4_data *vc4_data)
782 tdm_vc4_output_data *o = NULL, *oo = NULL;
784 if (LIST_IS_EMPTY(&vc4_data->output_list))
787 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &vc4_data->output_list, link) {
788 if (o->crtc_enabled) {
789 _tdm_vc4_display_set_crtc(vc4_data, o, 0);
794 if (!LIST_IS_EMPTY(&o->layer_list)) {
795 tdm_vc4_layer_data *l = NULL, *ll = NULL;
796 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
802 free(o->output_modes);
808 tdm_vc4_display_update_output_status(tdm_vc4_data *vc4_data)
810 tdm_vc4_output_data *output_data = NULL;
812 if (LIST_IS_EMPTY(&vc4_data->output_list))
815 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
816 drmModeConnectorPtr connector;
817 tdm_output_conn_status new_status;
819 connector = drmModeGetConnector(vc4_data->drm_fd,
820 output_data->connector_id);
822 TDM_ERR("no connector: %d", output_data->connector_id);
826 if (connector->connection == DRM_MODE_CONNECTED)
827 new_status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
829 new_status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
831 _tdm_vc4_output_update_status(output_data, new_status);
833 drmModeFreeConnector(connector);
838 tdm_vc4_display_create_output_list(tdm_vc4_data *vc4_data)
840 tdm_vc4_output_data *output_data;
844 RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&vc4_data->output_list),
845 TDM_ERROR_OPERATION_FAILED);
847 for (i = 0; i < vc4_data->mode_res->count_connectors; i++) {
848 drmModeConnectorPtr connector;
849 drmModeEncoderPtr encoder;
850 int crtc_id = 0, c, j;
852 connector = drmModeGetConnector(vc4_data->drm_fd,
853 vc4_data->mode_res->connectors[i]);
855 TDM_ERR("no connector");
856 ret = TDM_ERROR_OPERATION_FAILED;
860 /* The TDM drm backend is not interested with disconnected connectors.
861 * And it only considers 1 connected connector because it is the TDM
862 * reference backend and can't take care of all hardware devices.
863 * To support various connectors, planes and crtcs, the new TDM backend
864 * should be implemented.
866 if (connector->connection != DRM_MODE_CONNECTED) {
867 drmModeFreeConnector(connector);
871 if (connector->count_encoders != 1) {
872 TDM_ERR("too many encoders: %d", connector->count_encoders);
873 drmModeFreeConnector(connector);
874 ret = TDM_ERROR_OPERATION_FAILED;
878 encoder = drmModeGetEncoder(vc4_data->drm_fd, connector->encoders[0]);
880 TDM_ERR("no encoder");
881 drmModeFreeConnector(connector);
882 ret = TDM_ERROR_OPERATION_FAILED;
886 for (c = 0; c < vc4_data->mode_res->count_crtcs; c++) {
887 if ((encoder->possible_crtcs & (1 << c)) == 0)
890 crtc_id = vc4_data->mode_res->crtcs[c];
895 TDM_ERR("no possible crtc");
896 drmModeFreeConnector(connector);
897 drmModeFreeEncoder(encoder);
898 ret = TDM_ERROR_OPERATION_FAILED;
902 output_data = calloc(1, sizeof(tdm_vc4_output_data));
904 TDM_ERR("alloc failed");
905 drmModeFreeConnector(connector);
906 drmModeFreeEncoder(encoder);
907 ret = TDM_ERROR_OUT_OF_MEMORY;
911 LIST_INITHEAD(&output_data->layer_list);
913 output_data->vc4_data = vc4_data;
914 output_data->connector_id = vc4_data->mode_res->connectors[i];
915 output_data->encoder_id = encoder->encoder_id;
916 output_data->crtc_id = crtc_id;
917 output_data->pipe = c;
918 output_data->connector_type = connector->connector_type;
919 output_data->connector_type_id = connector->connector_type_id;
921 if (connector->connection == DRM_MODE_CONNECTED)
922 output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
924 output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
926 for (j = 0; j < connector->count_props; j++) {
927 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd,
928 connector->props[j]);
931 if (!strcmp(prop->name, "DPMS")) {
932 output_data->dpms_prop_id = connector->props[j];
933 drmModeFreeProperty(prop);
936 drmModeFreeProperty(prop);
939 if (output_data->dpms_prop_id == 0)
940 TDM_WRN("not support DPMS");
942 output_data->count_modes = connector->count_modes;
943 output_data->vc4_modes = calloc(connector->count_modes,
944 sizeof(drmModeModeInfo));
945 if (!output_data->vc4_modes) {
946 TDM_ERR("alloc failed");
948 drmModeFreeConnector(connector);
949 drmModeFreeEncoder(encoder);
950 ret = TDM_ERROR_OUT_OF_MEMORY;
953 output_data->output_modes = calloc(connector->count_modes,
954 sizeof(tdm_output_mode));
955 if (!output_data->output_modes) {
956 TDM_ERR("alloc failed");
957 free(output_data->vc4_modes);
959 drmModeFreeConnector(connector);
960 drmModeFreeEncoder(encoder);
961 ret = TDM_ERROR_OUT_OF_MEMORY;
964 for (j = 0; j < connector->count_modes; j++) {
965 output_data->vc4_modes[j] = connector->modes[j];
966 _tdm_vc4_display_to_tdm_mode(&output_data->vc4_modes[j],
967 &output_data->output_modes[j]);
970 LIST_ADDTAIL(&output_data->link, &vc4_data->output_list);
972 TDM_DBG("output_data(%p) connector_id(%d:%d:%d-%d) encoder_id(%d) crtc_id(%d) pipe(%d) dpms_id(%d)",
973 output_data, output_data->connector_id, output_data->status,
974 output_data->connector_type,
975 output_data->connector_type_id, output_data->encoder_id, output_data->crtc_id,
976 output_data->pipe, output_data->dpms_prop_id);
978 drmModeFreeEncoder(encoder);
979 drmModeFreeConnector(connector);
981 /* The TDM drm backend is not interested with disconnected connectors.
982 * And it only considers 1 connected connector because it is the TDM
983 * reference backend and can't take care of all hardware devices.
984 * To support various connectors, planes and crtcs, the new TDM backend
985 * should be implemented.
990 TDM_DBG("output count: %d", vc4_data->mode_res->count_connectors);
992 return TDM_ERROR_NONE;
994 tdm_vc4_display_destroy_output_list(vc4_data);
999 vc4_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps)
1001 RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1003 caps->max_layer_count = -1; /* not defined */
1005 return TDM_ERROR_NONE;
1009 vc4_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error)
1011 tdm_vc4_data *vc4_data = bdata;
1012 tdm_vc4_output_data *output_data = NULL;
1013 tdm_output **outputs;
1017 RETURN_VAL_IF_FAIL(vc4_data, NULL);
1018 RETURN_VAL_IF_FAIL(count, NULL);
1021 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link)
1025 ret = TDM_ERROR_NONE;
1029 /* will be freed in frontend */
1030 outputs = calloc(*count, sizeof(tdm_vc4_output_data *));
1032 TDM_ERR("failed: alloc memory");
1034 ret = TDM_ERROR_OUT_OF_MEMORY;
1039 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link)
1040 outputs[i++] = output_data;
1043 *error = TDM_ERROR_NONE;
1053 vc4_display_get_fd(tdm_backend_data *bdata, int *fd)
1055 tdm_vc4_data *vc4_data = bdata;
1057 RETURN_VAL_IF_FAIL(vc4_data, TDM_ERROR_INVALID_PARAMETER);
1058 RETURN_VAL_IF_FAIL(fd, TDM_ERROR_INVALID_PARAMETER);
1060 *fd = vc4_data->drm_fd;
1062 return TDM_ERROR_NONE;
1066 vc4_display_handle_events(tdm_backend_data *bdata)
1068 tdm_vc4_data *vc4_data = bdata;
1069 drmEventContext ctx;
1071 RETURN_VAL_IF_FAIL(vc4_data, TDM_ERROR_INVALID_PARAMETER);
1073 memset(&ctx, 0, sizeof(drmEventContext));
1075 ctx.version = DRM_EVENT_CONTEXT_VERSION;
1076 ctx.page_flip_handler = _tdm_vc4_display_cb_event;
1077 ctx.vblank_handler = _tdm_vc4_display_cb_event;
1079 drmHandleEvent(vc4_data->drm_fd, &ctx);
1081 return TDM_ERROR_NONE;
1085 vc4_output_get_capability(tdm_output *output, tdm_caps_output *caps)
1087 tdm_vc4_output_data *output_data = output;
1088 tdm_vc4_data *vc4_data;
1089 drmModeConnectorPtr connector = NULL;
1090 drmModeCrtcPtr crtc = NULL;
1091 drmModeObjectPropertiesPtr props = NULL;
1095 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1096 RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1098 memset(caps, 0, sizeof(tdm_caps_output));
1100 vc4_data = output_data->vc4_data;
1102 snprintf(caps->maker, TDM_NAME_LEN, "unknown");
1103 snprintf(caps->model, TDM_NAME_LEN, "unknown");
1104 snprintf(caps->name, TDM_NAME_LEN, "unknown");
1106 caps->status = output_data->status;
1107 caps->type = output_data->connector_type;
1108 caps->type_id = output_data->connector_type_id;
1110 connector = drmModeGetConnector(vc4_data->drm_fd, output_data->connector_id);
1111 RETURN_VAL_IF_FAIL(connector, TDM_ERROR_OPERATION_FAILED);
1113 caps->mode_count = connector->count_modes;
1114 caps->modes = calloc(1, sizeof(tdm_output_mode) * caps->mode_count);
1116 ret = TDM_ERROR_OUT_OF_MEMORY;
1117 TDM_ERR("alloc failed\n");
1120 for (i = 0; i < caps->mode_count; i++)
1121 caps->modes[i] = output_data->output_modes[i];
1123 caps->mmWidth = connector->mmWidth;
1124 caps->mmHeight = connector->mmHeight;
1125 caps->subpixel = connector->subpixel;
1127 caps->min_w = vc4_data->mode_res->min_width;
1128 caps->min_h = vc4_data->mode_res->min_height;
1129 caps->max_w = vc4_data->mode_res->max_width;
1130 caps->max_h = vc4_data->mode_res->max_height;
1131 caps->preferred_align = -1;
1133 crtc = drmModeGetCrtc(vc4_data->drm_fd, output_data->crtc_id);
1135 ret = TDM_ERROR_OPERATION_FAILED;
1136 TDM_ERR("get crtc failed: %m\n");
1140 props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->crtc_id,
1141 DRM_MODE_OBJECT_CRTC);
1143 ret = TDM_ERROR_OPERATION_FAILED;
1144 TDM_ERR("get crtc properties failed: %m\n");
1148 caps->prop_count = props->count_props;
1149 caps->props = calloc(1, sizeof(tdm_prop) * caps->prop_count);
1151 ret = TDM_ERROR_OUT_OF_MEMORY;
1152 TDM_ERR("alloc failed\n");
1156 for (i = 0; i < caps->prop_count; i++) {
1157 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd, props->props[i]);
1160 snprintf(caps->props[i].name, TDM_NAME_LEN, "%s", prop->name);
1161 caps->props[i].id = props->props[i];
1162 drmModeFreeProperty(prop);
1165 drmModeFreeObjectProperties(props);
1166 drmModeFreeCrtc(crtc);
1167 drmModeFreeConnector(connector);
1169 return TDM_ERROR_NONE;
1171 drmModeFreeCrtc(crtc);
1172 drmModeFreeObjectProperties(props);
1173 drmModeFreeConnector(connector);
1176 memset(caps, 0, sizeof(tdm_caps_output));
1181 vc4_output_get_layers(tdm_output *output, int *count, tdm_error *error)
1183 tdm_vc4_output_data *output_data = output;
1184 tdm_vc4_layer_data *layer_data = NULL;
1189 RETURN_VAL_IF_FAIL(output_data, NULL);
1190 RETURN_VAL_IF_FAIL(count, NULL);
1193 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1197 ret = TDM_ERROR_NONE;
1201 /* will be freed in frontend */
1202 layers = calloc(*count, sizeof(tdm_vc4_layer_data *));
1204 TDM_ERR("failed: alloc memory");
1206 ret = TDM_ERROR_OUT_OF_MEMORY;
1211 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1212 layers[i++] = layer_data;
1215 *error = TDM_ERROR_NONE;
1225 vc4_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
1227 tdm_vc4_output_data *output_data = output;
1228 tdm_vc4_data *vc4_data;
1231 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1232 RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1234 vc4_data = output_data->vc4_data;
1235 ret = drmModeObjectSetProperty(vc4_data->drm_fd,
1236 output_data->crtc_id, DRM_MODE_OBJECT_CRTC,
1239 TDM_ERR("set property failed: %m");
1240 return TDM_ERROR_OPERATION_FAILED;
1243 return TDM_ERROR_NONE;
1247 vc4_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
1249 tdm_vc4_output_data *output_data = output;
1250 tdm_vc4_data *vc4_data;
1251 drmModeObjectPropertiesPtr props;
1254 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1255 RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1256 RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
1258 vc4_data = output_data->vc4_data;
1259 props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->crtc_id,
1260 DRM_MODE_OBJECT_CRTC);
1261 if (props == NULL) {
1262 TDM_ERR("get property failed: %m");
1263 return TDM_ERROR_OPERATION_FAILED;
1266 for (i = 0; i < props->count_props; i++)
1267 if (props->props[i] == id) {
1268 (*value).u32 = (uint)props->prop_values[i];
1272 drmModeFreeObjectProperties(props);
1274 return TDM_ERROR_NONE;
1278 vc4_output_wait_vblank(tdm_output *output, int interval, int sync,
1281 tdm_vc4_output_data *output_data = output;
1282 tdm_vc4_data *vc4_data;
1283 tdm_vc4_event_data *event_data;
1287 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1289 event_data = calloc(1, sizeof(tdm_vc4_event_data));
1291 TDM_ERR("alloc failed");
1292 return TDM_ERROR_OUT_OF_MEMORY;
1295 vc4_data = output_data->vc4_data;
1297 ret = _tdm_vc4_display_get_cur_msc(vc4_data->drm_fd, output_data->pipe,
1299 if (ret != TDM_ERROR_NONE)
1302 target_msc += interval;
1304 event_data->type = TDM_DRM_EVENT_TYPE_WAIT;
1305 event_data->output_data = output_data;
1306 event_data->user_data = user_data;
1308 ret = _tdm_vc4_display_wait_vblank(vc4_data->drm_fd, output_data->pipe,
1309 &target_msc, event_data);
1310 if (ret != TDM_ERROR_NONE)
1313 return TDM_ERROR_NONE;
1320 vc4_output_set_vblank_handler(tdm_output *output,
1321 tdm_output_vblank_handler func)
1323 tdm_vc4_output_data *output_data = output;
1325 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1326 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1328 output_data->vblank_func = func;
1330 return TDM_ERROR_NONE;
1334 vc4_output_commit(tdm_output *output, int sync, void *user_data)
1336 tdm_vc4_output_data *output_data = output;
1337 tdm_vc4_data *vc4_data;
1338 tdm_vc4_layer_data *layer_data = NULL;
1340 int do_waitvblank = 1;
1342 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1344 vc4_data = output_data->vc4_data;
1346 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1347 ret = _tdm_vc4_display_commit_layer(layer_data);
1348 if (ret != TDM_ERROR_NONE)
1352 if (do_waitvblank == 1) {
1353 tdm_vc4_event_data *event_data = calloc(1, sizeof(tdm_vc4_event_data));
1357 TDM_ERR("alloc failed");
1358 return TDM_ERROR_OUT_OF_MEMORY;
1361 ret = _tdm_vc4_display_get_cur_msc(vc4_data->drm_fd, output_data->pipe,
1363 if (ret != TDM_ERROR_NONE) {
1370 event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
1371 event_data->output_data = output_data;
1372 event_data->user_data = user_data;
1374 ret = _tdm_vc4_display_wait_vblank(vc4_data->drm_fd, output_data->pipe,
1375 &target_msc, event_data);
1376 if (ret != TDM_ERROR_NONE) {
1382 return TDM_ERROR_NONE;
1386 vc4_output_set_commit_handler(tdm_output *output,
1387 tdm_output_commit_handler func)
1389 tdm_vc4_output_data *output_data = output;
1391 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1392 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1394 output_data->commit_func = func;
1396 return TDM_ERROR_NONE;
1400 vc4_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
1402 tdm_vc4_output_data *output_data = output;
1403 tdm_vc4_data *vc4_data;
1406 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1408 if (output_data->dpms_prop_id == 0) {
1409 TDM_WRN("not support DPMS");
1410 return TDM_ERROR_OPERATION_FAILED;
1413 vc4_data = output_data->vc4_data;
1414 ret = drmModeObjectSetProperty(vc4_data->drm_fd,
1415 output_data->connector_id, DRM_MODE_OBJECT_CONNECTOR,
1416 output_data->dpms_prop_id, dpms_value);
1418 TDM_ERR("set dpms failed: %m");
1419 return TDM_ERROR_OPERATION_FAILED;
1422 return TDM_ERROR_NONE;
1426 vc4_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
1428 tdm_vc4_output_data *output_data = output;
1429 tdm_vc4_data *vc4_data;
1430 drmModeObjectPropertiesPtr props;
1433 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1434 RETURN_VAL_IF_FAIL(dpms_value, TDM_ERROR_INVALID_PARAMETER);
1436 vc4_data = output_data->vc4_data;
1437 props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->connector_id,
1438 DRM_MODE_OBJECT_CONNECTOR);
1439 if (props == NULL) {
1440 TDM_ERR("get property failed: %m");
1441 return TDM_ERROR_OPERATION_FAILED;
1444 for (i = 0; i < props->count_props; i++)
1445 if (props->props[i] == output_data->dpms_prop_id) {
1446 *dpms_value = (uint)props->prop_values[i];
1450 drmModeFreeObjectProperties(props);
1452 return TDM_ERROR_NONE;
1456 vc4_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
1458 tdm_vc4_output_data *output_data = output;
1460 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1461 RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1463 output_data->current_mode = mode;
1464 output_data->mode_changed = 1;
1466 return TDM_ERROR_NONE;
1470 vc4_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
1472 tdm_vc4_output_data *output_data = output;
1474 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1475 RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1477 *mode = output_data->current_mode;
1479 return TDM_ERROR_NONE;
1483 vc4_output_set_status_handler(tdm_output *output,
1484 tdm_output_status_handler func,
1487 tdm_vc4_output_data *output_data = output;
1489 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1490 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1492 output_data->status_func = func;
1493 output_data->status_user_data = user_data;
1495 return TDM_ERROR_NONE;
1499 vc4_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
1501 tdm_vc4_layer_data *layer_data = layer;
1502 tdm_vc4_data *vc4_data;
1503 drmModePlanePtr plane = NULL;
1504 drmModeObjectPropertiesPtr props = NULL;
1505 int i, format_count = 0;
1508 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1509 RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1511 memset(caps, 0, sizeof(tdm_caps_layer));
1513 vc4_data = layer_data->vc4_data;
1514 plane = drmModeGetPlane(vc4_data->drm_fd, layer_data->plane_id);
1516 TDM_ERR("get plane failed: %m");
1517 ret = TDM_ERROR_OPERATION_FAILED;
1521 caps->capabilities = layer_data->capabilities;
1522 caps->zpos = layer_data->zpos; /* if VIDEO layer, zpos is -1 */
1524 caps->format_count = plane->count_formats;
1525 caps->formats = calloc(1, sizeof(tbm_format) * caps->format_count);
1526 if (!caps->formats) {
1527 ret = TDM_ERROR_OUT_OF_MEMORY;
1528 TDM_ERR("alloc failed\n");
1532 for (i = 0; i < caps->format_count; i++) {
1533 /* TODO: kernel reports wrong formats */
1534 if (plane->formats[i] != DRM_FORMAT_XRGB8888 &&
1535 plane->formats[i] != DRM_FORMAT_ARGB8888 &&
1536 plane->formats[i] != DRM_FORMAT_NV12 &&
1537 plane->formats[i] != DRM_FORMAT_YUV420)
1539 caps->formats[format_count] = tdm_vc4_format_to_tbm_format(plane->formats[i]);
1543 caps->format_count = format_count;
1545 props = drmModeObjectGetProperties(vc4_data->drm_fd, layer_data->plane_id,
1546 DRM_MODE_OBJECT_PLANE);
1548 ret = TDM_ERROR_OPERATION_FAILED;
1549 TDM_ERR("get plane properties failed: %m\n");
1553 caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
1555 ret = TDM_ERROR_OUT_OF_MEMORY;
1556 TDM_ERR("alloc failed\n");
1560 caps->prop_count = 0;
1561 for (i = 0; i < props->count_props; i++) {
1562 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd, props->props[i]);
1565 if (!strncmp(prop->name, "type", TDM_NAME_LEN)) {
1566 drmModeFreeProperty(prop);
1569 if (!strncmp(prop->name, "zpos", TDM_NAME_LEN)) {
1570 drmModeFreeProperty(prop);
1573 snprintf(caps->props[i].name, TDM_NAME_LEN, "%s", prop->name);
1574 caps->props[i].id = props->props[i];
1576 drmModeFreeProperty(prop);
1579 drmModeFreeObjectProperties(props);
1580 drmModeFreePlane(plane);
1582 return TDM_ERROR_NONE;
1584 drmModeFreeObjectProperties(props);
1585 drmModeFreePlane(plane);
1586 free(caps->formats);
1588 memset(caps, 0, sizeof(tdm_caps_layer));
1593 vc4_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value)
1595 tdm_vc4_layer_data *layer_data = layer;
1596 tdm_vc4_data *vc4_data;
1599 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1600 RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
1602 vc4_data = layer_data->vc4_data;
1603 ret = drmModeObjectSetProperty(vc4_data->drm_fd,
1604 layer_data->plane_id, DRM_MODE_OBJECT_PLANE,
1607 TDM_ERR("set property failed: %m");
1608 return TDM_ERROR_OPERATION_FAILED;
1611 return TDM_ERROR_NONE;
1615 vc4_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value)
1617 tdm_vc4_layer_data *layer_data = layer;
1618 tdm_vc4_data *vc4_data;
1619 drmModeObjectPropertiesPtr props;
1622 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1623 RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
1624 RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
1626 vc4_data = layer_data->vc4_data;
1627 props = drmModeObjectGetProperties(vc4_data->drm_fd, layer_data->plane_id,
1628 DRM_MODE_OBJECT_PLANE);
1629 if (props == NULL) {
1630 TDM_ERR("get property failed: %m");
1631 return TDM_ERROR_OPERATION_FAILED;
1634 for (i = 0; i < props->count_props; i++)
1635 if (props->props[i] == id) {
1636 (*value).u32 = (uint)props->prop_values[i];
1640 drmModeFreeObjectProperties(props);
1642 return TDM_ERROR_NONE;
1646 vc4_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
1648 tdm_vc4_layer_data *layer_data = layer;
1650 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1651 RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
1653 layer_data->info = *info;
1654 layer_data->info_changed = 1;
1656 return TDM_ERROR_NONE;
1660 vc4_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
1662 tdm_vc4_layer_data *layer_data = layer;
1664 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1665 RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
1667 *info = layer_data->info;
1669 return TDM_ERROR_NONE;
1673 vc4_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
1675 tdm_vc4_layer_data *layer_data = layer;
1676 tdm_vc4_data *vc4_data;
1677 tdm_vc4_display_buffer *display_buffer;
1678 tdm_error err = TDM_ERROR_NONE;
1681 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1682 RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
1684 vc4_data = layer_data->vc4_data;
1686 display_buffer = _tdm_vc4_display_find_buffer(vc4_data, buffer);
1687 if (!display_buffer) {
1688 display_buffer = calloc(1, sizeof(tdm_vc4_display_buffer));
1689 if (!display_buffer) {
1690 TDM_ERR("alloc failed");
1691 return TDM_ERROR_OUT_OF_MEMORY;
1693 display_buffer->buffer = buffer;
1695 err = tdm_buffer_add_destroy_handler(buffer, _tdm_vc4_display_cb_destroy_buffer,
1697 if (err != TDM_ERROR_NONE) {
1698 TDM_ERR("add destroy handler fail");
1699 free(display_buffer);
1700 return TDM_ERROR_OPERATION_FAILED;
1703 LIST_ADDTAIL(&display_buffer->link, &vc4_data->buffer_list);
1706 if (display_buffer->fb_id == 0) {
1708 unsigned int height;
1709 unsigned int format;
1710 unsigned int handles[4] = {0,};
1711 unsigned int pitches[4] = {0,};
1712 unsigned int offsets[4] = {0,};
1716 width = tbm_surface_get_width(buffer);
1717 height = tbm_surface_get_height(buffer);
1718 format = tbm_surface_get_format(buffer);
1719 count = tbm_surface_internal_get_num_planes(format);
1721 bo = tbm_surface_internal_get_bo(buffer, 0);
1722 handles[0] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
1723 for (i = 1; i < count; i++)
1724 handles[i] = handles[0];
1726 for (i = 0; i < count; i++)
1727 tbm_surface_internal_get_plane_data(buffer, i, &size, &offsets[i], &pitches[i]);
1729 ret = drmModeAddFB2(vc4_data->drm_fd, width, height, format,
1730 handles, pitches, offsets, &display_buffer->fb_id, 0);
1732 TDM_ERR("add fb failed: %m");
1733 return TDM_ERROR_OPERATION_FAILED;
1735 TDM_DBG("vc4_data->drm_fd : %d, display_buffer->fb_id:%u", vc4_data->drm_fd,
1736 display_buffer->fb_id);
1739 display_buffer->width = pitches[0] >> 2;
1741 display_buffer->width = pitches[0];
1744 layer_data->display_buffer = display_buffer;
1745 layer_data->display_buffer_changed = 1;
1747 return TDM_ERROR_NONE;
1751 vc4_layer_unset_buffer(tdm_layer *layer)
1753 tdm_vc4_layer_data *layer_data = layer;
1755 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1757 layer_data->display_buffer = NULL;
1758 layer_data->display_buffer_changed = 1;
1760 return TDM_ERROR_NONE;