9 #define LIST_INSERT_AFTER(__after, __item) \
10 (__item)->prev = (__after); \
11 (__item)->next = (__after)->next; \
12 (__after)->next->prev = (__item); \
13 (__after)->next = (__item);
16 check_hw_restriction(unsigned int crtc_w, unsigned int crtc_h, unsigned int buf_w,
17 unsigned int src_x, unsigned int src_w,
18 unsigned int dst_x, unsigned int dst_y, unsigned int dst_w,
19 unsigned int *new_src_x, unsigned int *new_src_w,
20 unsigned int *new_dst_x, unsigned int *new_dst_w)
30 if (buf_w < MIN_WIDTH || buf_w % 2) {
31 TDM_ERR("buf_w(%u) not 2's multiple or less than %u", buf_w, MIN_WIDTH);
32 return TDM_ERROR_BAD_REQUEST;
35 if (dst_x > crtc_w || dst_y > crtc_h) {
36 TDM_ERR("dst_pos(%u,%u) is out of crtc(%ux%u)", dst_x, dst_y, crtc_w, crtc_h);
37 return TDM_ERROR_BAD_REQUEST;
40 if (src_x > dst_x || ((dst_x - src_x) + buf_w) > crtc_w)
46 end = ((dst_x + dst_w) > crtc_w) ? crtc_w : (dst_x + dst_w);
48 /* check window minimun width */
49 if ((end - start) < MIN_WIDTH) {
50 TDM_ERR("visible_w(%d) less than %u", end - start, MIN_WIDTH);
51 return TDM_ERROR_BAD_REQUEST;
54 if (!virtual_screen) {
55 /* Pagewidth of window (= 8 byte align / bytes-per-pixel ) */
56 if ((end - start) % 2)
59 /* You should align the sum of PAGEWIDTH_F and OFFSIZE_F double-word (8 byte) boundary. */
65 *new_dst_w = end - start;
67 RETURN_VAL_IF_FAIL(*new_src_w > 0, TDM_ERROR_BAD_REQUEST);
68 RETURN_VAL_IF_FAIL(*new_dst_w > 0, TDM_ERROR_BAD_REQUEST);
70 if (src_x != *new_src_x || src_w != *new_src_w || dst_x != *new_dst_x ||
72 TDM_INFO("=> buf_w(%d) src(%d,%d) dst(%d,%d), virt(%d) start(%d) end(%d)",
73 buf_w, *new_src_x, *new_src_w, *new_dst_x, *new_dst_w, virtual_screen, start,
76 return TDM_ERROR_NONE;
79 static drmModeModeInfoPtr
80 _tdm_vc4_display_get_mode(tdm_vc4_output_data *output_data)
84 if (!output_data->current_mode) {
85 TDM_ERR("no output_data->current_mode");
89 const tdm_output_mode *mode;
91 mode = output_data->current_mode;
92 TDM_INFO("Current mode: %s, %d, %d, %d, %d, %d",
93 mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags, mode->type);
96 TDM_INFO(" Count modes: %d %d", output_data->count_drm_modes, output_data->count_modes);
98 for (i = 0; i < output_data->count_drm_modes; i++) {
99 drmModeModeInfoPtr vc4_mode = &output_data->vc4_modes[i];
101 TDM_INFO(" DRM mode: %s, %d, %d, %d, %d, %d",
102 vc4_mode->name, vc4_mode->hdisplay, vc4_mode->vdisplay, vc4_mode->vrefresh, vc4_mode->flags, vc4_mode->type);
104 if ((vc4_mode->hdisplay == output_data->current_mode->hdisplay) &&
105 (vc4_mode->hsync_start == output_data->current_mode->hsync_start) &&
106 (vc4_mode->hsync_end == output_data->current_mode->hsync_end) &&
107 (vc4_mode->htotal == output_data->current_mode->htotal) &&
108 (vc4_mode->hskew == output_data->current_mode->hskew) &&
109 (vc4_mode->vdisplay == output_data->current_mode->vdisplay) &&
110 (vc4_mode->vsync_start == output_data->current_mode->vsync_start) &&
111 (vc4_mode->vsync_end == output_data->current_mode->vsync_end) &&
112 (vc4_mode->vtotal == output_data->current_mode->vtotal) &&
113 (vc4_mode->vscan == output_data->current_mode->vscan) &&
114 (vc4_mode->clock == output_data->current_mode->clock) &&
115 (vc4_mode->vrefresh == output_data->current_mode->vrefresh) &&
116 (vc4_mode->flags == output_data->current_mode->flags) &&
117 (vc4_mode->type == output_data->current_mode->type) &&
118 !(strncmp(vc4_mode->name, output_data->current_mode->name, TDM_NAME_LEN)))
126 _tdm_vc4_display_set_fb(tdm_vc4_data *vc4_data, tbm_surface_h buffer, unsigned int *id)
131 unsigned int handles[4] = {0,};
132 unsigned int pitches[4] = {0,};
133 unsigned int offsets[4] = {0,};
138 width = tbm_surface_get_width(buffer);
139 height = tbm_surface_get_height(buffer);
140 format = tbm_surface_get_format(buffer);
141 count = tbm_surface_internal_get_num_bos(buffer);
142 for (i = 0; i < count; i++) {
143 tbm_bo bo = tbm_surface_internal_get_bo(buffer, i);
144 handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
146 count = tbm_surface_internal_get_num_planes(format);
147 for (i = 0; i < count; i++)
148 tbm_surface_internal_get_plane_data(buffer, i, &size, &offsets[i], &pitches[i]);
150 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)",
151 vc4_data->drm_fd, width, height, FOURCC_STR(format),
152 handles[0], handles[1], handles[2], pitches[0], pitches[1], pitches[2],
153 offsets[0], offsets[1], offsets[2], buffer);
155 ret = drmModeAddFB2(vc4_data->drm_fd, width, height, format,
156 handles, pitches, offsets, &fb_id, 0);
158 TDM_ERR("add fb failed: %m");
159 return TDM_ERROR_OPERATION_FAILED;
161 TDM_DBG("AddFB2 success: drm_fd(%d) fb_id(%u)", vc4_data->drm_fd, fb_id);
164 return TDM_ERROR_NONE;
168 _tdm_vc4_output_update_status(tdm_vc4_output_data *output_data,
169 tdm_output_conn_status status)
171 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
173 if (output_data->status == status)
174 return TDM_ERROR_NONE;
176 output_data->status = status;
178 if (output_data->status_func)
179 output_data->status_func(output_data, status,
180 output_data->status_user_data);
182 return TDM_ERROR_NONE;
186 _tdm_vc4_display_set_crtc(tdm_vc4_data *vc4_data, tdm_vc4_output_data *output_data, int set)
190 output_data->mode_changed = 0;
193 tbm_surface_h buffer = NULL;
194 tbm_surface_info_s info;
195 drmModeModeInfoPtr mode;
196 unsigned int fb_id = 0;
198 if (!output_data->current_mode)
199 return TDM_ERROR_OPERATION_FAILED;
201 mode = _tdm_vc4_display_get_mode(output_data);
203 TDM_ERR("couldn't find proper mode");
204 return TDM_ERROR_BAD_REQUEST;
207 buffer = tbm_surface_create(output_data->current_mode->hdisplay,
208 output_data->current_mode->vdisplay,
209 TBM_FORMAT_XRGB8888);
210 RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_OPERATION_FAILED);
212 if (tbm_surface_map(buffer, TBM_SURF_OPTION_WRITE, &info) != TBM_ERROR_NONE) {
213 tbm_surface_destroy(buffer);
214 return TDM_ERROR_OPERATION_FAILED;
216 memset(info.planes[0].ptr, 0x0, info.size);
218 tbm_surface_unmap(buffer);
220 if (_tdm_vc4_display_set_fb(vc4_data, buffer, &fb_id) != TDM_ERROR_NONE) {
221 tbm_surface_destroy(buffer);
222 return TDM_ERROR_OPERATION_FAILED;
225 TDM_DBG("drmModeSetCrtc drm_fd(%d) crtc_id(%u) fb_id(%u) mode(%u,%u)",
226 vc4_data->drm_fd, output_data->crtc_id, fb_id,
227 mode->hdisplay, mode->vdisplay);
229 if (drmModeSetCrtc(vc4_data->drm_fd, output_data->crtc_id,
231 &output_data->connector_id, 1, mode)) {
232 TDM_ERR("set crtc failed: %m");
233 ret = drmModeRmFB(vc4_data->drm_fd, fb_id);
235 TDM_ERR("rm fb failed fb_id(%u)", fb_id);
236 tbm_surface_destroy(buffer);
237 return TDM_ERROR_OPERATION_FAILED;
240 _tdm_vc4_output_update_status(output_data, TDM_OUTPUT_CONN_STATUS_MODE_SETTED);
242 if (output_data->crtc_buffer) {
243 ret = drmModeRmFB(vc4_data->drm_fd, output_data->crtc_fb_id);
245 TDM_ERR("rm fb failed fb_id(%u)", output_data->crtc_fb_id);
246 tbm_surface_destroy(output_data->crtc_buffer);
248 output_data->crtc_buffer = buffer;
249 output_data->crtc_fb_id = fb_id;
251 TDM_DBG("drmModeSetCrtc unset drm_fd(%d) crtc_id(%u)",
252 vc4_data->drm_fd, output_data->crtc_id);
254 if (drmModeSetCrtc(vc4_data->drm_fd, output_data->crtc_id,
255 0, 0, 0, NULL, 0, NULL)) {
256 TDM_ERR("unset crtc failed: %m");
257 return TDM_ERROR_OPERATION_FAILED;
260 if (output_data->crtc_buffer) {
261 ret = drmModeRmFB(vc4_data->drm_fd, output_data->crtc_fb_id);
263 TDM_ERR("rm fb failed fb_id(%u)", output_data->crtc_fb_id);
264 tbm_surface_destroy(output_data->crtc_buffer);
266 output_data->crtc_buffer = NULL;
267 output_data->crtc_fb_id = 0;
270 return TDM_ERROR_NONE;
274 _tdm_vc4_display_to_tdm_mode(drmModeModeInfoPtr vc4_mode,
275 tdm_output_mode *tdm_mode)
277 tdm_mode->clock = vc4_mode->clock;
278 tdm_mode->hdisplay = vc4_mode->hdisplay;
279 tdm_mode->hsync_start = vc4_mode->hsync_start;
280 tdm_mode->hsync_end = vc4_mode->hsync_end;
281 tdm_mode->htotal = vc4_mode->htotal;
282 tdm_mode->hskew = vc4_mode->hskew;
283 tdm_mode->vdisplay = vc4_mode->vdisplay;
284 tdm_mode->vsync_start = vc4_mode->vsync_start;
285 tdm_mode->vsync_end = vc4_mode->vsync_end;
286 tdm_mode->vtotal = vc4_mode->vtotal;
287 tdm_mode->vscan = vc4_mode->vscan;
288 tdm_mode->vrefresh = vc4_mode->vrefresh;
289 tdm_mode->flags = vc4_mode->flags;
290 tdm_mode->type = vc4_mode->type;
291 snprintf(tdm_mode->name, TDM_NAME_LEN, "%s", vc4_mode->name);
295 _tdm_vc4_display_get_cur_msc(int fd, int pipe, uint *msc)
299 vbl.request.type = DRM_VBLANK_RELATIVE;
301 vbl.request.type |= DRM_VBLANK_SECONDARY;
303 vbl.request.type |= pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
305 vbl.request.sequence = 0;
306 if (drmWaitVBlank(fd, &vbl)) {
307 TDM_ERR("get vblank counter failed: %m");
309 return TDM_ERROR_OPERATION_FAILED;
312 *msc = vbl.reply.sequence;
314 return TDM_ERROR_NONE;
318 _tdm_vc4_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data)
322 vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
324 vbl.request.type |= DRM_VBLANK_SECONDARY;
326 vbl.request.type |= pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
328 vbl.request.sequence = *target_msc;
329 vbl.request.signal = (unsigned long)(uintptr_t)data;
331 if (drmWaitVBlank(fd, &vbl)) {
332 TDM_ERR("wait vblank failed: %m");
334 return TDM_ERROR_OPERATION_FAILED;
337 *target_msc = vbl.reply.sequence;
339 return TDM_ERROR_NONE;
343 _tdm_vc4_display_commit_layer(tdm_vc4_layer_data *layer_data)
345 tdm_vc4_data *vc4_data = layer_data->vc4_data;
346 tdm_vc4_output_data *output_data = layer_data->output_data;
347 uint32_t fx, fy, fw, fh;
350 if (!layer_data->display_buffer_changed && !layer_data->info_changed)
351 return TDM_ERROR_NONE;
353 if (!output_data->crtc_enabled || output_data->mode_changed) {
354 if (_tdm_vc4_display_set_crtc(vc4_data, output_data, 1) != TDM_ERROR_NONE)
355 return TDM_ERROR_OPERATION_FAILED;
357 output_data->crtc_enabled = 1;
360 if (output_data->current_mode)
361 crtc_w = output_data->current_mode->hdisplay;
363 drmModeCrtcPtr crtc = drmModeGetCrtc(vc4_data->drm_fd, output_data->crtc_id);
365 TDM_ERR("getting crtc failed");
366 return TDM_ERROR_OPERATION_FAILED;
368 crtc_w = crtc->width;
370 TDM_ERR("getting crtc width failed");
371 drmModeFreeCrtc(crtc);
372 return TDM_ERROR_OPERATION_FAILED;
374 drmModeFreeCrtc(crtc);
377 layer_data->display_buffer_changed = 0;
378 layer_data->info_changed = 0;
380 if (!layer_data->display_buffer) {
381 if (drmModeSetPlane(vc4_data->drm_fd, layer_data->plane_id,
382 output_data->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
383 TDM_ERR("unset plane(%d) filed: %m", layer_data->plane_id);
385 return TDM_ERROR_NONE;
388 /* Source values are 16.16 fixed point */
389 fx = ((unsigned int)layer_data->info.src_config.pos.x) << 16;
390 fy = ((unsigned int)layer_data->info.src_config.pos.y) << 16;
391 fw = ((unsigned int)layer_data->info.src_config.pos.w) << 16;
392 fh = ((unsigned int)layer_data->info.src_config.pos.h) << 16;
394 if (drmModeSetPlane(vc4_data->drm_fd, layer_data->plane_id,
395 output_data->crtc_id, layer_data->display_buffer->fb_id, 0,
396 layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
397 layer_data->info.dst_pos.w, layer_data->info.dst_pos.h,
398 fx, fy, fw, fh) < 0) {
399 TDM_ERR("set plane(%d) failed: %m", layer_data->plane_id);
400 return TDM_ERROR_OPERATION_FAILED;
403 TDM_DBG("plane(%d) crtc(%d) pos(%d) on: fb(%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n",
404 layer_data->plane_id, output_data->crtc_id, layer_data->zpos,
405 layer_data->display_buffer->fb_id,
406 layer_data->info.src_config.pos.x, layer_data->info.src_config.pos.y,
407 layer_data->info.src_config.pos.w, layer_data->info.src_config.pos.h,
408 layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
409 layer_data->info.dst_pos.w, layer_data->info.dst_pos.h);
411 return TDM_ERROR_NONE;
415 _tdm_vc4_display_cb_event(int fd, unsigned int sequence,
416 unsigned int tv_sec, unsigned int tv_usec,
419 tdm_vc4_event_data *event_data = user_data;
420 tdm_vc4_output_data *output_data;
421 tdm_vc4_hwc_data *hwc_data;
425 TDM_ERR("no event data");
429 output_data = event_data->output_data;
432 TDM_DBG("==== Atomic Commit Handler pipe, %u, crtc_id, %u connector_id, %u",
433 output_data->pipe, output_data->crtc_id, output_data->connector_id);
435 switch (event_data->type) {
436 case TDM_DRM_EVENT_TYPE_PAGEFLIP:
437 if (output_data->commit_func)
438 output_data->commit_func(output_data, sequence, tv_sec, tv_usec,
439 event_data->user_data);
441 case TDM_DRM_EVENT_TYPE_WAIT:
442 if (output_data->vblank_func)
443 output_data->vblank_func(output_data, sequence, tv_sec, tv_usec,
444 event_data->user_data);
446 case TDM_DRM_EVENT_TYPE_COMMIT:
447 if (output_data->hwc_enable) {
448 hwc_data = output_data->hwc_data;
450 TDM_ERR("no hwc_data");
454 if (hwc_data->commit_func)
455 hwc_data->commit_func(hwc_data, sequence,
457 event_data->user_data);
459 if (output_data->commit_func)
460 output_data->commit_func(output_data, sequence,
462 event_data->user_data);
473 _vc4_output_get_atomic_prop_id(int drm_fd, uint32_t object_id, uint32_t object_type, const char *name, uint32_t *id)
475 drmModeObjectPropertiesPtr properties = NULL;
476 drmModePropertyPtr property = NULL;
479 properties = drmModeObjectGetProperties(drm_fd, object_id, object_type);
480 if (properties == NULL) {
481 TDM_ERR("drmModeObjectGetProperties failed");
482 return TDM_ERROR_OPERATION_FAILED;
485 for (i = 0; i < properties->count_props; i++) {
486 property = drmModeGetProperty(drm_fd, properties->props[i]);
487 if (property == NULL) {
491 if (strcmp(property->name, name) == 0) {
492 *id = property->prop_id;
493 drmModeFreeProperty(property);
496 drmModeFreeProperty(property);
499 drmModeFreeObjectProperties(properties);
501 return TDM_ERROR_NONE;
505 _tdm_vc4_display_create_layer_list(tdm_vc4_data *vc4_data)
507 tdm_vc4_output_data *output_data = NULL;
510 if (LIST_IS_EMPTY(&vc4_data->output_list)) {
511 TDM_ERR("no output");
512 return TDM_ERROR_OPERATION_FAILED;
515 /* The TDM drm backend only support one output. */
516 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
520 if (vc4_data->plane_res->count_planes == 0) {
521 TDM_ERR("no layer error");
522 return TDM_ERROR_OPERATION_FAILED;
525 for (i = 0; i < vc4_data->plane_res->count_planes; i++) {
526 tdm_vc4_layer_data *layer_data;
527 drmModePlanePtr plane;
529 plane = drmModeGetPlane(vc4_data->drm_fd, vc4_data->plane_res->planes[i]);
535 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
536 drmModeFreePlane(plane);
540 layer_data = calloc(1, sizeof(tdm_vc4_layer_data));
542 TDM_ERR("alloc failed");
543 drmModeFreePlane(plane);
547 layer_data->vc4_data = vc4_data;
548 layer_data->output_data = output_data;
549 layer_data->plane_id = vc4_data->plane_res->planes[i];
550 layer_data->acquire_fence = -1;
552 layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
553 TDM_LAYER_CAPABILITY_GRAPHIC;
554 output_data->primary_layer = layer_data;
556 TDM_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) capabilities(%x)",
557 layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
558 layer_data->capabilities);
560 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
562 drmModeFreePlane(plane);
564 /* can't take care of other planes for various hardware devices */
568 return TDM_ERROR_NONE;
571 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
574 _tdm_vc4_display_get_property(tdm_vc4_data *vc4_data,
575 unsigned int obj_id, unsigned int obj_type,
576 const char *name, unsigned int *value,
579 drmModeObjectPropertiesPtr props = NULL;
582 props = drmModeObjectGetProperties(vc4_data->drm_fd, obj_id, obj_type);
584 return TDM_ERROR_OPERATION_FAILED;
586 for (i = 0; i < props->count_props; i++) {
587 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd,
593 if (!strcmp(prop->name, name)) {
595 *is_immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
597 *value = (unsigned int)props->prop_values[i];
598 drmModeFreeProperty(prop);
599 drmModeFreeObjectProperties(props);
600 return TDM_ERROR_NONE;
603 drmModeFreeProperty(prop);
605 drmModeFreeObjectProperties(props);
606 TDM_DBG("coundn't find '%s' property", name);
607 return TDM_ERROR_OPERATION_FAILED;
611 _tdm_vc4_display_create_layer_list_type(tdm_vc4_data *vc4_data)
613 drmModePlanePtr plane;
617 for (i = 0; i < vc4_data->plane_res->count_planes; i++) {
618 tdm_vc4_output_data *output_data = NULL;
619 tdm_vc4_layer_data *layer_data;
620 unsigned int type = 0;
623 plane = drmModeGetPlane(vc4_data->drm_fd, vc4_data->plane_res->planes[i]);
629 ret = _tdm_vc4_display_get_property(vc4_data,
630 vc4_data->plane_res->planes[i],
631 DRM_MODE_OBJECT_PLANE, "type", &type, NULL);
632 if (ret != TDM_ERROR_NONE) {
633 TDM_ERR("plane(%d) doesn't have 'type' info",
634 vc4_data->plane_res->planes[i]);
635 drmModeFreePlane(plane);
639 layer_data = calloc(1, sizeof(tdm_vc4_layer_data));
641 TDM_ERR("alloc failed");
642 drmModeFreePlane(plane);
646 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
647 if (plane->possible_crtcs & (1 << output_data->pipe)) {
654 TDM_ERR("plane(%d) couldn't found proper output", plane->plane_id);
655 drmModeFreePlane(plane);
660 layer_data->vc4_data = vc4_data;
661 layer_data->output_data = output_data;
662 layer_data->plane_id = vc4_data->plane_res->planes[i];
663 layer_data->acquire_fence = -1;
665 if (type == DRM_PLANE_TYPE_CURSOR) {
666 layer_data->capabilities = TDM_LAYER_CAPABILITY_CURSOR |
667 TDM_LAYER_CAPABILITY_GRAPHIC;
668 layer_data->zpos = 2;
669 } else if (type == DRM_PLANE_TYPE_OVERLAY) {
670 layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY |
671 TDM_LAYER_CAPABILITY_GRAPHIC;
672 layer_data->zpos = 1;
673 } else if (type == DRM_PLANE_TYPE_PRIMARY) {
674 layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
675 TDM_LAYER_CAPABILITY_GRAPHIC;
676 layer_data->zpos = 0;
677 output_data->primary_layer = layer_data;
679 drmModeFreePlane(plane);
684 TDM_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) zpos(%d) capabilities(%x)",
685 layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
686 layer_data->zpos, layer_data->capabilities);
688 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
690 /* get the atomic prop ids*/
691 if (vc4_data->has_atomic) {
692 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
693 DRM_MODE_OBJECT_PLANE, "FB_ID", &layer_data->atomic_props_ids.fb_id);
694 if (ret != TDM_ERROR_NONE) {
696 goto failed_atomic_prop_id;
699 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
700 DRM_MODE_OBJECT_PLANE, "CRTC_ID", &layer_data->atomic_props_ids.crtc_id);
701 if (ret != TDM_ERROR_NONE) {
703 goto failed_atomic_prop_id;
706 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
707 DRM_MODE_OBJECT_PLANE, "SRC_X", &layer_data->atomic_props_ids.src_x);
708 if (ret != TDM_ERROR_NONE) {
710 goto failed_atomic_prop_id;
713 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
714 DRM_MODE_OBJECT_PLANE, "SRC_Y", &layer_data->atomic_props_ids.src_y);
715 if (ret != TDM_ERROR_NONE) {
717 goto failed_atomic_prop_id;
720 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
721 DRM_MODE_OBJECT_PLANE, "SRC_W", &layer_data->atomic_props_ids.src_w);
722 if (ret != TDM_ERROR_NONE) {
724 goto failed_atomic_prop_id;
727 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
728 DRM_MODE_OBJECT_PLANE, "SRC_H", &layer_data->atomic_props_ids.src_h);
729 if (ret != TDM_ERROR_NONE) {
731 goto failed_atomic_prop_id;
734 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
735 DRM_MODE_OBJECT_PLANE, "CRTC_X", &layer_data->atomic_props_ids.crtc_x);
736 if (ret != TDM_ERROR_NONE) {
738 goto failed_atomic_prop_id;
741 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
742 DRM_MODE_OBJECT_PLANE, "CRTC_Y", &layer_data->atomic_props_ids.crtc_y);
743 if (ret != TDM_ERROR_NONE) {
745 goto failed_atomic_prop_id;
748 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
749 DRM_MODE_OBJECT_PLANE, "CRTC_W", &layer_data->atomic_props_ids.crtc_w);
750 if (ret != TDM_ERROR_NONE) {
752 goto failed_atomic_prop_id;
755 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
756 DRM_MODE_OBJECT_PLANE, "CRTC_H", &layer_data->atomic_props_ids.crtc_h);
757 if (ret != TDM_ERROR_NONE) {
759 goto failed_atomic_prop_id;
762 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
763 DRM_MODE_OBJECT_PLANE, "IN_FENCE_FD", &layer_data->atomic_props_ids.in_fence_fd);
764 if (ret != TDM_ERROR_NONE) {
766 goto failed_atomic_prop_id;
770 drmModeFreePlane(plane);
773 return TDM_ERROR_NONE;
775 failed_atomic_prop_id:
777 drmModeFreePlane(plane);
779 return TDM_ERROR_OPERATION_FAILED;
784 _get_primary_layer_zpos(tdm_vc4_output_data *output_data)
786 tdm_vc4_layer_data *layer_data = NULL;
788 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
789 if (layer_data->capabilities & TDM_LAYER_CAPABILITY_PRIMARY)
790 return layer_data->zpos;
797 tdm_vc4_display_create_layer_list(tdm_vc4_data *vc4_data)
799 tdm_vc4_output_data *output_data = NULL;
802 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
803 if (vc4_data->has_universal_plane)
804 ret = _tdm_vc4_display_create_layer_list_type(vc4_data);
807 ret = _tdm_vc4_display_create_layer_list(vc4_data);
809 if (ret != TDM_ERROR_NONE)
812 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
813 if (!output_data->primary_layer) {
814 TDM_ERR("output(%d) no primary layer", output_data->pipe);
815 return TDM_ERROR_OPERATION_FAILED;
819 return TDM_ERROR_NONE;
823 tdm_vc4_display_destroy_output_list(tdm_vc4_data *vc4_data)
825 tdm_vc4_output_data *o = NULL, *oo = NULL;
826 tdm_vc4_hwc_data *hwc_data = NULL;
828 if (LIST_IS_EMPTY(&vc4_data->output_list))
831 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &vc4_data->output_list, link) {
832 hwc_data = o->hwc_data;
833 if (hwc_data && hwc_data->target_hwc_window)
834 vc4_hwc_window_destroy(hwc_data->target_hwc_window);
836 if (o->crtc_enabled) {
837 _tdm_vc4_display_set_crtc(vc4_data, o, 0);
842 if (!LIST_IS_EMPTY(&o->layer_list)) {
843 tdm_vc4_layer_data *l = NULL, *ll = NULL;
844 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
846 if (l->display_buffer)
847 tbm_surface_internal_unref(l->display_buffer->buffer);
852 free(o->output_modes);
858 tdm_vc4_display_update_output_status(tdm_vc4_data *vc4_data)
860 tdm_vc4_output_data *output_data = NULL;
862 if (LIST_IS_EMPTY(&vc4_data->output_list))
865 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
866 drmModeConnectorPtr connector;
867 tdm_output_conn_status new_status;
869 connector = drmModeGetConnector(vc4_data->drm_fd,
870 output_data->connector_id);
872 TDM_ERR("no connector: %d", output_data->connector_id);
876 if (connector->connection == DRM_MODE_CONNECTED)
877 new_status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
879 new_status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
881 _tdm_vc4_output_update_status(output_data, new_status);
883 drmModeFreeConnector(connector);
888 tdm_vc4_display_create_output_list(tdm_vc4_data *vc4_data)
890 tdm_vc4_output_data *output_data;
895 RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&vc4_data->output_list),
896 TDM_ERROR_OPERATION_FAILED);
898 for (i = 0; i < vc4_data->mode_res->count_connectors; i++) {
899 drmModeConnectorPtr connector;
900 drmModeEncoderPtr encoder;
901 int crtc_id = 0, c, j;
903 connector = drmModeGetConnector(vc4_data->drm_fd,
904 vc4_data->mode_res->connectors[i]);
906 TDM_ERR("no connector");
907 ret = TDM_ERROR_OPERATION_FAILED;
911 if (connector->count_encoders != 1) {
912 TDM_ERR("too many encoders: %d", connector->count_encoders);
913 drmModeFreeConnector(connector);
914 ret = TDM_ERROR_OPERATION_FAILED;
918 encoder = drmModeGetEncoder(vc4_data->drm_fd, connector->encoders[0]);
920 TDM_ERR("no encoder");
921 drmModeFreeConnector(connector);
922 ret = TDM_ERROR_OPERATION_FAILED;
926 for (c = 0; c < vc4_data->mode_res->count_crtcs; c++) {
927 if (allocated & (1 << c))
930 if ((encoder->possible_crtcs & (1 << c)) == 0)
933 crtc_id = vc4_data->mode_res->crtcs[c];
934 allocated |= (1 << c);
939 TDM_ERR("no possible crtc");
940 drmModeFreeConnector(connector);
941 drmModeFreeEncoder(encoder);
942 ret = TDM_ERROR_OPERATION_FAILED;
946 output_data = calloc(1, sizeof(tdm_vc4_output_data));
948 TDM_ERR("alloc failed");
949 drmModeFreeConnector(connector);
950 drmModeFreeEncoder(encoder);
951 ret = TDM_ERROR_OUT_OF_MEMORY;
955 LIST_INITHEAD(&output_data->layer_list);
957 output_data->vc4_data = vc4_data;
958 output_data->connector_id = vc4_data->mode_res->connectors[i];
959 output_data->encoder_id = encoder->encoder_id;
960 output_data->crtc_id = crtc_id;
961 output_data->pipe = c;
962 output_data->connector_type = connector->connector_type;
963 output_data->connector_type_id = connector->connector_type_id;
964 output_data->commit_fence = -1;
966 if (connector->connection == DRM_MODE_CONNECTED)
967 output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
969 output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
971 for (j = 0; j < connector->count_props; j++) {
972 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd,
973 connector->props[j]);
976 if (!strcmp(prop->name, "DPMS")) {
977 output_data->dpms_prop_id = connector->props[j];
978 drmModeFreeProperty(prop);
981 drmModeFreeProperty(prop);
984 output_data->count_modes = connector->count_modes;
985 output_data->vc4_modes = calloc(connector->count_modes, sizeof(drmModeModeInfo));
986 if (!output_data->vc4_modes) {
987 TDM_ERR("alloc failed");
989 drmModeFreeConnector(connector);
990 drmModeFreeEncoder(encoder);
991 ret = TDM_ERROR_OUT_OF_MEMORY;
995 output_data->output_modes = calloc(connector->count_modes, sizeof(tdm_output_mode));
996 if (!output_data->output_modes) {
997 TDM_ERR("alloc failed");
998 free(output_data->vc4_modes);
1000 drmModeFreeConnector(connector);
1001 drmModeFreeEncoder(encoder);
1002 ret = TDM_ERROR_OUT_OF_MEMORY;
1006 for (j = 0; j < connector->count_modes; j++) {
1007 output_data->vc4_modes[j] = connector->modes[j];
1008 _tdm_vc4_display_to_tdm_mode(&output_data->vc4_modes[j],
1009 &output_data->output_modes[j]);
1012 if (vc4_data->hwc_mode)
1013 output_data->hwc_enable = 1;
1015 LIST_ADDTAIL(&output_data->link, &vc4_data->output_list);
1017 TDM_INFO("output_data(%p) connector_id(%d:%d:%d-%d) encoder_id(%d) crtc_id(%d) pipe(%d) dpms_id(%d) count_modes(%d)",
1018 output_data, output_data->connector_id, output_data->status,
1019 output_data->connector_type,
1020 output_data->connector_type_id, output_data->encoder_id, output_data->crtc_id,
1021 output_data->pipe, output_data->dpms_prop_id, output_data->count_modes);
1023 drmModeFreeEncoder(encoder);
1024 drmModeFreeConnector(connector);
1026 /* get the atomic prop ids*/
1027 if (vc4_data->has_atomic) {
1028 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, output_data->connector_id,
1029 DRM_MODE_OBJECT_CONNECTOR, "CRTC_ID", &output_data->atomic_props_ids.crtc_id);
1030 if (ret != TDM_ERROR_NONE)
1031 goto failed_atomic_prop_id;
1033 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, output_data->crtc_id,
1034 DRM_MODE_OBJECT_CRTC, "MODE_ID", &output_data->atomic_props_ids.crtc_mode_id);
1035 if (ret != TDM_ERROR_NONE)
1036 goto failed_atomic_prop_id;
1038 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, output_data->crtc_id,
1039 DRM_MODE_OBJECT_CRTC, "ACTIVE", &output_data->atomic_props_ids.crtc_active);
1040 if (ret != TDM_ERROR_NONE)
1041 goto failed_atomic_prop_id;
1043 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, output_data->crtc_id,
1044 DRM_MODE_OBJECT_CRTC, "OUT_FENCE_PTR", &output_data->atomic_props_ids.out_fence_ptr);
1045 if (ret != TDM_ERROR_NONE)
1046 goto failed_atomic_prop_id;
1050 TDM_INFO("output count: %d", vc4_data->mode_res->count_connectors);
1052 return TDM_ERROR_NONE;
1053 failed_atomic_prop_id:
1055 tdm_vc4_display_destroy_output_list(vc4_data);
1060 vc4_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps)
1062 RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1064 caps->max_layer_count = -1; /* not defined */
1066 return TDM_ERROR_NONE;
1070 vc4_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error)
1072 tdm_vc4_data *vc4_data = bdata;
1073 tdm_vc4_output_data *output_data = NULL;
1074 tdm_output **outputs;
1078 RETURN_VAL_IF_FAIL(vc4_data, NULL);
1079 RETURN_VAL_IF_FAIL(count, NULL);
1082 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link)
1086 ret = TDM_ERROR_NONE;
1090 /* will be freed in frontend */
1091 outputs = calloc(*count, sizeof(tdm_vc4_output_data *));
1093 TDM_ERR("failed: alloc memory");
1095 ret = TDM_ERROR_OUT_OF_MEMORY;
1100 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link)
1101 outputs[i++] = output_data;
1104 *error = TDM_ERROR_NONE;
1114 vc4_display_get_fd(tdm_backend_data *bdata, int *fd)
1116 tdm_vc4_data *vc4_data = bdata;
1118 RETURN_VAL_IF_FAIL(vc4_data, TDM_ERROR_INVALID_PARAMETER);
1119 RETURN_VAL_IF_FAIL(fd, TDM_ERROR_INVALID_PARAMETER);
1121 *fd = vc4_data->drm_fd;
1123 return TDM_ERROR_NONE;
1127 vc4_display_handle_events(tdm_backend_data *bdata)
1129 tdm_vc4_data *vc4_data = bdata;
1130 drmEventContext ctx;
1132 RETURN_VAL_IF_FAIL(vc4_data, TDM_ERROR_INVALID_PARAMETER);
1134 memset(&ctx, 0, sizeof(drmEventContext));
1136 ctx.version = DRM_EVENT_CONTEXT_VERSION;
1137 ctx.page_flip_handler = _tdm_vc4_display_cb_event;
1138 ctx.vblank_handler = _tdm_vc4_display_cb_event;
1140 drmHandleEvent(vc4_data->drm_fd, &ctx);
1142 return TDM_ERROR_NONE;
1146 vc4_output_get_capability(tdm_output *output, tdm_caps_output *caps)
1148 tdm_vc4_output_data *output_data = output;
1149 tdm_vc4_data *vc4_data;
1150 drmModeConnectorPtr connector = NULL;
1151 drmModeCrtcPtr crtc = NULL;
1152 drmModeObjectPropertiesPtr props = NULL;
1156 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1157 RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1159 memset(caps, 0, sizeof(tdm_caps_output));
1161 vc4_data = output_data->vc4_data;
1163 snprintf(caps->maker, TDM_NAME_LEN, "unknown");
1164 snprintf(caps->model, TDM_NAME_LEN, "unknown");
1165 snprintf(caps->name, TDM_NAME_LEN, "unknown");
1167 caps->status = output_data->status;
1168 caps->type = output_data->connector_type;
1169 caps->type_id = output_data->connector_type_id;
1171 connector = drmModeGetConnector(vc4_data->drm_fd, output_data->connector_id);
1172 RETURN_VAL_IF_FAIL(connector, TDM_ERROR_OPERATION_FAILED);
1174 caps->mode_count = connector->count_modes;
1175 if (caps->mode_count != 0) {
1176 caps->modes = calloc(1, sizeof(tdm_output_mode) * caps->mode_count);
1178 ret = TDM_ERROR_OUT_OF_MEMORY;
1179 TDM_ERR("alloc failed\n");
1183 output_data->count_drm_modes = connector->count_modes;
1184 output_data->count_modes = caps->mode_count;
1186 drmModeModeInfoPtr new_drm_modes;
1187 tdm_output_mode *new_output_modes;
1189 new_drm_modes = calloc(connector->count_modes,
1190 sizeof(drmModeModeInfo));
1191 if (!new_drm_modes) {
1192 ret = TDM_ERROR_OUT_OF_MEMORY;
1193 TDM_ERR("alloc failed drm_modes\n");
1196 new_output_modes = calloc(caps->mode_count,
1197 sizeof(tdm_output_mode));
1198 if (!new_output_modes) {
1199 ret = TDM_ERROR_OUT_OF_MEMORY;
1200 TDM_ERR("alloc failed output_modes\n");
1201 free(new_drm_modes);
1204 if (output_data->vc4_modes)
1205 free(output_data->vc4_modes);
1206 if (output_data->output_modes)
1207 free(output_data->output_modes);
1209 output_data->vc4_modes = new_drm_modes;
1210 output_data->output_modes = new_output_modes;
1212 for (i = 0; i < connector->count_modes; i++) {
1213 output_data->vc4_modes[i] = connector->modes[i];
1214 _tdm_vc4_display_to_tdm_mode(&output_data->vc4_modes[i],
1215 &output_data->output_modes[i]);
1216 caps->modes[i] = output_data->output_modes[i];
1220 output_data->count_drm_modes = connector->count_modes;
1221 output_data->count_modes = caps->mode_count;
1223 if (output_data->vc4_modes)
1224 free(output_data->vc4_modes);
1225 if (output_data->output_modes)
1226 free(output_data->output_modes);
1228 output_data->vc4_modes = NULL;
1229 output_data->output_modes = NULL;
1232 caps->mmWidth = connector->mmWidth;
1233 caps->mmHeight = connector->mmHeight;
1234 caps->subpixel = connector->subpixel;
1236 caps->min_w = vc4_data->mode_res->min_width;
1237 caps->min_h = vc4_data->mode_res->min_height;
1238 caps->max_w = vc4_data->mode_res->max_width;
1239 caps->max_h = vc4_data->mode_res->max_height;
1240 caps->preferred_align = -1;
1242 crtc = drmModeGetCrtc(vc4_data->drm_fd, output_data->crtc_id);
1244 ret = TDM_ERROR_OPERATION_FAILED;
1245 TDM_ERR("get crtc failed: %m\n");
1249 props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->crtc_id,
1250 DRM_MODE_OBJECT_CRTC);
1252 ret = TDM_ERROR_OPERATION_FAILED;
1253 TDM_ERR("get crtc properties failed: %m\n");
1257 caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
1259 ret = TDM_ERROR_OUT_OF_MEMORY;
1260 TDM_ERR("alloc failed\n");
1264 caps->prop_count = 0;
1265 for (i = 0; i < props->count_props; i++) {
1266 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd, props->props[i]);
1269 snprintf(caps->props[caps->prop_count].name, TDM_NAME_LEN, "%s", prop->name);
1270 caps->props[caps->prop_count].id = props->props[i];
1272 drmModeFreeProperty(prop);
1275 if (output_data->hwc_enable) {
1276 caps->capabilities |= TDM_OUTPUT_CAPABILITY_HWC;
1277 caps->capabilities |= TDM_OUTPUT_CAPABILITY_MIRROR;
1280 drmModeFreeObjectProperties(props);
1281 drmModeFreeCrtc(crtc);
1282 drmModeFreeConnector(connector);
1284 return TDM_ERROR_NONE;
1286 drmModeFreeCrtc(crtc);
1287 drmModeFreeObjectProperties(props);
1288 drmModeFreeConnector(connector);
1291 memset(caps, 0, sizeof(tdm_caps_output));
1296 vc4_output_get_layers(tdm_output *output, int *count, tdm_error *error)
1298 tdm_vc4_output_data *output_data = output;
1299 tdm_vc4_layer_data *layer_data = NULL;
1304 RETURN_VAL_IF_FAIL(output_data, NULL);
1305 RETURN_VAL_IF_FAIL(count, NULL);
1308 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1311 if (output_data->hwc_enable) {
1313 ret = TDM_ERROR_NONE;
1318 ret = TDM_ERROR_NONE;
1322 /* will be freed in frontend */
1323 layers = calloc(*count, sizeof(tdm_vc4_layer_data *));
1325 TDM_ERR("failed: alloc memory");
1327 ret = TDM_ERROR_OUT_OF_MEMORY;
1332 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1333 layers[i++] = layer_data;
1336 *error = TDM_ERROR_NONE;
1346 vc4_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
1348 tdm_vc4_output_data *output_data = output;
1349 tdm_vc4_data *vc4_data;
1352 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1353 RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1355 vc4_data = output_data->vc4_data;
1356 ret = drmModeObjectSetProperty(vc4_data->drm_fd,
1357 output_data->crtc_id, DRM_MODE_OBJECT_CRTC,
1360 TDM_ERR("set property failed: %m");
1361 return TDM_ERROR_OPERATION_FAILED;
1364 return TDM_ERROR_NONE;
1368 vc4_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
1370 tdm_vc4_output_data *output_data = output;
1371 tdm_vc4_data *vc4_data;
1372 drmModeObjectPropertiesPtr props;
1375 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1376 RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1377 RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
1379 vc4_data = output_data->vc4_data;
1380 props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->crtc_id,
1381 DRM_MODE_OBJECT_CRTC);
1382 if (props == NULL) {
1383 TDM_ERR("get property failed: %m");
1384 return TDM_ERROR_OPERATION_FAILED;
1387 for (i = 0; i < props->count_props; i++)
1388 if (props->props[i] == id) {
1389 (*value).u32 = (uint)props->prop_values[i];
1393 drmModeFreeObjectProperties(props);
1395 return TDM_ERROR_NONE;
1399 vc4_output_wait_vblank(tdm_output *output, int interval, int sync,
1402 tdm_vc4_output_data *output_data = output;
1403 tdm_vc4_data *vc4_data;
1404 tdm_vc4_event_data *event_data;
1408 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1410 event_data = calloc(1, sizeof(tdm_vc4_event_data));
1412 TDM_ERR("alloc failed");
1413 return TDM_ERROR_OUT_OF_MEMORY;
1416 vc4_data = output_data->vc4_data;
1418 ret = _tdm_vc4_display_get_cur_msc(vc4_data->drm_fd, output_data->pipe,
1420 if (ret != TDM_ERROR_NONE)
1423 target_msc += interval;
1425 event_data->type = TDM_DRM_EVENT_TYPE_WAIT;
1426 event_data->output_data = output_data;
1427 event_data->user_data = user_data;
1429 ret = _tdm_vc4_display_wait_vblank(vc4_data->drm_fd, output_data->pipe,
1430 &target_msc, event_data);
1431 if (ret != TDM_ERROR_NONE)
1434 return TDM_ERROR_NONE;
1441 vc4_output_set_vblank_handler(tdm_output *output,
1442 tdm_output_vblank_handler func)
1444 tdm_vc4_output_data *output_data = output;
1446 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1447 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1449 output_data->vblank_func = func;
1451 return TDM_ERROR_NONE;
1455 _vc4_layer_add_atomic_properties(tdm_vc4_layer_data *layer_data, drmModeAtomicReqPtr request,
1456 uint32_t fb_id, uint32_t crtc_id, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h,
1457 uint32_t crtc_x, uint32_t crtc_y, uint32_t crtc_w, uint32_t crtc_h, int acquire_fence)
1459 tdm_error ret = TDM_ERROR_NONE;
1461 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.fb_id, fb_id);
1463 TDM_ERR("fail to add the atomic prop. fb_id(%u)", fb_id);
1464 return TDM_ERROR_OPERATION_FAILED;
1467 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_id, crtc_id);
1469 TDM_ERR("fail to add the atomic prop. crtc_id(%u)", crtc_id);
1470 return TDM_ERROR_OPERATION_FAILED;
1473 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_x, src_x);
1475 TDM_ERR("fail to add the atomic prop. src_x(%u)", src_x);
1476 return TDM_ERROR_OPERATION_FAILED;
1479 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_y, src_y);
1481 TDM_ERR("fail to add the atomic prop. src_y(%u)", src_y);
1482 return TDM_ERROR_OPERATION_FAILED;
1485 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_w, src_w);
1487 TDM_ERR("fail to add the atomic prop. src_w(%u)", src_w);
1488 return TDM_ERROR_OPERATION_FAILED;
1491 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_h, src_h);
1493 TDM_ERR("fail to add the atomic prop. src_h(%u)", src_h);
1494 return TDM_ERROR_OPERATION_FAILED;
1497 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_x, crtc_x);
1499 TDM_ERR("fail to add the atomic prop. crtc_x(%u)", crtc_x);
1500 return TDM_ERROR_OPERATION_FAILED;
1503 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_y, crtc_y);
1505 TDM_ERR("fail to add the atomic prop. crtc_y(%u)", crtc_y);
1506 return TDM_ERROR_OPERATION_FAILED;
1509 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_w, crtc_w);
1511 TDM_ERR("fail to add the atomic prop. crtc_w(%u)", crtc_w);
1512 return TDM_ERROR_OPERATION_FAILED;
1515 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_h, crtc_h);
1517 TDM_ERR("fail to add the atomic prop. crtc_h(%u)", crtc_h);
1518 return TDM_ERROR_OPERATION_FAILED;
1521 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.in_fence_fd, acquire_fence);
1523 TDM_ERR("fail to add the atomic prop. acquire_fence(%d)", acquire_fence);
1524 return TDM_ERROR_OPERATION_FAILED;
1527 return TDM_ERROR_NONE;
1531 _vc4_layer_make_atomic_request(tdm_vc4_layer_data *layer_data, drmModeAtomicReqPtr request)
1533 tdm_vc4_data *vc4_data = layer_data->vc4_data;
1534 tdm_vc4_output_data *output_data = layer_data->output_data;
1535 unsigned int new_src_x, new_src_w;
1536 unsigned int new_dst_x, new_dst_w;
1537 uint32_t fx, fy, fw, fh;
1539 tdm_info_layer layer_info = layer_data->info;
1540 tdm_error ret = TDM_ERROR_NONE;
1542 if (!layer_data->display_buffer_changed && !layer_data->info_changed)
1543 return TDM_ERROR_NONE;
1545 if (output_data->current_mode) {
1546 crtc_w = output_data->current_mode->hdisplay;
1547 crtc_h = output_data->current_mode->vdisplay;
1549 drmModeCrtcPtr crtc = drmModeGetCrtc(vc4_data->drm_fd, output_data->crtc_id);
1551 TDM_ERR("getting crtc failed");
1552 return TDM_ERROR_OPERATION_FAILED;
1554 crtc_w = crtc->width;
1555 crtc_h = crtc->height;
1557 TDM_ERR("getting crtc width failed");
1558 drmModeFreeCrtc(crtc);
1559 return TDM_ERROR_OPERATION_FAILED;
1561 drmModeFreeCrtc(crtc);
1564 layer_data->display_buffer_changed = 0;
1565 layer_data->info_changed = 0;
1567 if (!layer_data->display_buffer) {
1568 TDM_INFO("MakeAtomicRequest: drm_fd(%d) plane_id(%u) crtc_id(%u) off",
1569 vc4_data->drm_fd, layer_data->plane_id, output_data->crtc_id);
1571 ret = _vc4_layer_add_atomic_properties(layer_data, request, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1);
1572 if (ret != TDM_ERROR_NONE) {
1573 TDM_ERR("_vc4_layer_add_atomic_properties failed.");
1577 return TDM_ERROR_NONE;
1580 /* check hw restriction*/
1581 if (check_hw_restriction(crtc_w, crtc_h, layer_data->display_buffer->width,
1582 layer_info.src_config.pos.x,
1583 layer_info.src_config.pos.w,
1584 layer_info.dst_pos.x,
1585 layer_info.dst_pos.y,
1586 layer_info.dst_pos.w,
1587 &new_src_x, &new_src_w, &new_dst_x, &new_dst_w) != TDM_ERROR_NONE) {
1588 TDM_WRN("not going to set plane(%u)", layer_data->plane_id);
1589 return TDM_ERROR_NONE;
1592 if (layer_info.src_config.pos.x != new_src_x)
1593 TDM_DBG("src_x changed: %u => %u", layer_info.src_config.pos.x, new_src_x);
1594 if (layer_info.src_config.pos.w != new_src_w)
1595 TDM_DBG("src_w changed: %u => %u", layer_info.src_config.pos.w, new_src_w);
1596 if (layer_info.dst_pos.x != new_dst_x)
1597 TDM_DBG("dst_x changed: %u => %u", layer_info.dst_pos.x, new_dst_x);
1598 if (layer_info.dst_pos.w != new_dst_w)
1599 TDM_DBG("dst_w changed: %u => %u", layer_info.dst_pos.w, new_dst_w);
1601 /* Source values are 16.16 fixed point */
1602 fx = ((unsigned int)new_src_x) << 16;
1603 fy = ((unsigned int)layer_info.src_config.pos.y) << 16;
1604 fw = ((unsigned int)new_src_w) << 16;
1605 fh = ((unsigned int)layer_info.src_config.pos.h) << 16;
1607 TDM_INFO("MakeAtomicRequest: drm_fd(%d) plane_id(%u) zpos(%d) crtc_id(%u) fb_id(%u) src(%u,%u %ux%u) dst(%u,%u %ux%u)",
1608 vc4_data->drm_fd, layer_data->plane_id, layer_data->zpos,
1609 output_data->crtc_id, layer_data->display_buffer->fb_id,
1610 new_src_x, layer_info.src_config.pos.y,
1611 new_src_w, layer_info.src_config.pos.h,
1612 layer_info.dst_pos.x, layer_info.dst_pos.y,
1613 layer_info.dst_pos.w, layer_info.dst_pos.h);
1615 ret = _vc4_layer_add_atomic_properties(layer_data, request,
1616 layer_data->display_buffer->fb_id, output_data->crtc_id,
1618 new_dst_x, layer_info.dst_pos.y,
1619 new_dst_w, layer_info.dst_pos.h, layer_data->acquire_fence);
1620 if (ret != TDM_ERROR_NONE) {
1621 TDM_ERR("MakeAtomicRequest failed");
1625 return TDM_ERROR_NONE;
1629 _vc4_output_atomic_commit(tdm_output *output, int sync, void *user_data)
1631 tdm_vc4_output_data *output_data = output;
1632 tdm_vc4_layer_data *layer_data = NULL;
1633 tdm_vc4_event_data *event_data;
1634 drmModeAtomicReqPtr request;
1637 int out_fence_fd = -1;
1639 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1641 if (!output_data->crtc_enabled || output_data->mode_changed) {
1642 ret = _tdm_vc4_display_set_crtc(output_data->vc4_data, output_data, 1);
1643 if (ret != TDM_ERROR_NONE) {
1644 TDM_ERR("fail to set crtc.");
1645 return TDM_ERROR_OPERATION_FAILED;
1648 output_data->crtc_enabled = 1;
1649 #if 0//TODO: do set crtc with atomic pageflip
1650 flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
1651 drmModeModeInfoPtr mode;
1654 mode = _tdm_vc4_display_get_mode(output_data);
1656 TDM_ERR("fail to find the drm mode.");
1657 return TDM_ERROR_OPERATION_FAILED;
1660 if (drmModeCreatePropertyBlob(output_data->vc4_data->drm_fd, mode, sizeof(*mode), &blob_id) != 0) {
1661 TDM_ERR("fail to create the Mode PropertyBlob.");
1662 return TDM_ERROR_OPERATION_FAILED;
1665 drmModeAtomicAddProperty(request, output_data->output_plane, output_data->props.plane_fb_id,
1666 layer_data->display_buffer->fb_id);
1668 output_data->crtc_enabled = 1;
1672 request = drmModeAtomicAlloc();
1674 TDM_ERR("drmModeAtomicAlloc failed.");
1675 return TDM_ERROR_OUT_OF_MEMORY;
1678 flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
1680 ret = drmModeAtomicAddProperty(request, output_data->crtc_id, output_data->atomic_props_ids.out_fence_ptr, (uintptr_t)&out_fence_fd);
1682 TDM_ERR("fail to out fence ptr error:%d", errno);
1683 drmModeAtomicFree(request);
1687 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1688 ret = _vc4_layer_make_atomic_request(layer_data, request);
1689 if (ret != TDM_ERROR_NONE) {
1690 TDM_ERR("_vc4_layer_make_atomic_request failed.");
1691 drmModeAtomicFree(request);
1696 event_data = calloc(1, sizeof(tdm_vc4_event_data));
1698 TDM_ERR("fail to alloc event_data.");
1699 drmModeAtomicFree(request);
1700 return TDM_ERROR_OUT_OF_MEMORY;
1703 event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
1704 event_data->output_data = output_data;
1705 event_data->user_data = user_data;
1707 TDM_DBG("==== Atomic Commit pipe, %u, crtc_id, %u connector_id, %u",
1708 output_data->pipe, output_data->crtc_id, output_data->connector_id);
1710 if (drmModeAtomicCommit(output_data->vc4_data->drm_fd, request, flags, event_data) < 0) {
1711 TDM_ERR("drmModeAtomicCommit failed.");
1712 drmModeAtomicFree(request);
1713 return TDM_ERROR_OPERATION_FAILED;
1716 if (output_data->commit_fence >= 0)
1717 close(output_data->commit_fence);
1719 output_data->commit_fence = out_fence_fd;
1721 drmModeAtomicFree(request);
1723 return TDM_ERROR_NONE;
1727 _vc4_output_layers_commit(tdm_output *output, int sync, void *user_data)
1729 tdm_vc4_output_data *output_data = output;
1730 tdm_vc4_data *vc4_data;
1731 tdm_vc4_layer_data *layer_data = NULL;
1733 int do_waitvblank = 1;
1735 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1737 vc4_data = output_data->vc4_data;
1739 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1740 ret = _tdm_vc4_display_commit_layer(layer_data);
1741 if (ret != TDM_ERROR_NONE)
1745 if (do_waitvblank == 1) {
1746 tdm_vc4_event_data *event_data = calloc(1, sizeof(tdm_vc4_event_data));
1750 TDM_ERR("alloc failed");
1751 return TDM_ERROR_OUT_OF_MEMORY;
1754 ret = _tdm_vc4_display_get_cur_msc(vc4_data->drm_fd, output_data->pipe,
1756 if (ret != TDM_ERROR_NONE) {
1763 event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
1764 event_data->output_data = output_data;
1765 event_data->user_data = user_data;
1767 ret = _tdm_vc4_display_wait_vblank(vc4_data->drm_fd, output_data->pipe,
1768 &target_msc, event_data);
1769 if (ret != TDM_ERROR_NONE) {
1775 return TDM_ERROR_NONE;
1779 vc4_output_commit(tdm_output *output, int sync, void *user_data)
1781 tdm_vc4_output_data *output_data = output;
1782 tdm_vc4_data *vc4_data;
1783 tdm_error ret = TDM_ERROR_NONE;
1785 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1787 vc4_data = output_data->vc4_data;
1789 /* check the atomic pageflip */
1790 if (vc4_data->has_atomic) {
1791 ret = _vc4_output_atomic_commit(output, sync, user_data);
1792 if (ret != TDM_ERROR_NONE) {
1793 TDM_ERR("_vc4_output_atomic_commit failed.");
1797 ret = _vc4_output_layers_commit(output, sync, user_data);
1798 if (ret != TDM_ERROR_NONE) {
1799 TDM_ERR("_vc4_output_layers_commit failed.");
1804 return TDM_ERROR_NONE;
1808 vc4_output_set_commit_handler(tdm_output *output,
1809 tdm_output_commit_handler func)
1811 tdm_vc4_output_data *output_data = output;
1813 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1814 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1816 output_data->commit_func = func;
1818 return TDM_ERROR_NONE;
1822 vc4_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
1824 tdm_vc4_output_data *output_data = output;
1825 tdm_vc4_data *vc4_data;
1828 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1830 if (output_data->dpms_prop_id == 0) {
1831 TDM_WRN("not support DPMS");
1832 return TDM_ERROR_OPERATION_FAILED;
1835 vc4_data = output_data->vc4_data;
1836 ret = drmModeObjectSetProperty(vc4_data->drm_fd,
1837 output_data->connector_id, DRM_MODE_OBJECT_CONNECTOR,
1838 output_data->dpms_prop_id, dpms_value);
1840 TDM_ERR("set dpms failed: %m");
1841 return TDM_ERROR_OPERATION_FAILED;
1844 return TDM_ERROR_NONE;
1848 vc4_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
1850 tdm_vc4_output_data *output_data = output;
1851 tdm_vc4_data *vc4_data;
1852 drmModeObjectPropertiesPtr props;
1855 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1856 RETURN_VAL_IF_FAIL(dpms_value, TDM_ERROR_INVALID_PARAMETER);
1858 vc4_data = output_data->vc4_data;
1859 props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->connector_id,
1860 DRM_MODE_OBJECT_CONNECTOR);
1861 if (props == NULL) {
1862 TDM_ERR("get property failed: %m");
1863 return TDM_ERROR_OPERATION_FAILED;
1866 for (i = 0; i < props->count_props; i++)
1867 if (props->props[i] == output_data->dpms_prop_id) {
1868 *dpms_value = (uint)props->prop_values[i];
1872 drmModeFreeObjectProperties(props);
1874 return TDM_ERROR_NONE;
1878 vc4_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
1880 tdm_vc4_output_data *output_data = output;
1881 tdm_error ret = TDM_ERROR_NONE;
1883 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1884 RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1886 /* create or replace the target_window when the output mode is set */
1887 if (output_data->hwc_enable) {
1888 ret = vc4_hwc_target_window_set_info(output_data->hwc_data, mode->hdisplay, mode->vdisplay);
1889 if (ret != TDM_ERROR_NONE) {
1890 TDM_ERR("set info target hwc window failed (%d)", ret);
1895 output_data->current_mode = mode;
1896 output_data->mode_changed = 1;
1898 TDM_INFO("Set the output mode: %s, %d, %d, %d, %d, %d",
1899 mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags, mode->type);
1901 ret = _tdm_vc4_display_set_crtc(output_data->vc4_data, output_data, 1);
1902 if (ret != TDM_ERROR_NONE) {
1903 TDM_ERR("fail to set crtc.");
1904 return TDM_ERROR_OPERATION_FAILED;
1907 return TDM_ERROR_NONE;
1911 vc4_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
1913 tdm_vc4_output_data *output_data = output;
1915 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1916 RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1918 *mode = output_data->current_mode;
1920 return TDM_ERROR_NONE;
1924 vc4_output_set_mirror(tdm_output *output, tdm_output *src_output, tdm_transform transform)
1926 tdm_vc4_output_data *output_data = (tdm_vc4_output_data *)output;
1927 tdm_vc4_output_data *src_output_data = (tdm_vc4_output_data *)src_output;
1929 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1930 RETURN_VAL_IF_FAIL(src_output_data, TDM_ERROR_INVALID_PARAMETER);
1932 if (!output_data->hwc_enable) {
1933 TDM_ERR("Output Mirroring is not Implemented.");
1934 return TDM_ERROR_NOT_IMPLEMENTED;
1937 output_data->mirror_src_output_data = src_output_data;
1938 src_output_data->mirror_dst_output_data = output_data;
1939 src_output_data->mirror_dst_transform = transform;
1941 TDM_INFO("Set the mirror. transform(%d)", transform);
1943 return TDM_ERROR_NONE;
1947 vc4_output_unset_mirror(tdm_output *output)
1949 tdm_vc4_output_data *output_data = (tdm_vc4_output_data *)output;
1950 tdm_vc4_output_data *src_output_data;
1952 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1954 if (!output_data->hwc_enable) {
1955 TDM_ERR("Output Mirroring is not Implemented.");
1956 return TDM_ERROR_NOT_IMPLEMENTED;
1959 src_output_data = output_data->mirror_src_output_data;
1961 src_output_data->mirror_dst_transform = TDM_TRANSFORM_NORMAL;
1962 src_output_data->mirror_dst_output_data = NULL;
1963 output_data->mirror_src_output_data = NULL;
1965 TDM_INFO("Unet the mirror.");
1967 return TDM_ERROR_NONE;
1971 vc4_output_get_hwc(tdm_output *output, tdm_error *error)
1973 tdm_vc4_hwc_data *hwc_data = NULL;
1974 tdm_vc4_output_data *output_data = output;
1975 tdm_error ret = TDM_ERROR_NONE;
1978 TDM_ERR("invalid params");
1980 *error = TDM_ERROR_INVALID_PARAMETER;
1984 if (output_data->hwc_data) {
1985 TDM_INFO("hwc_data already exists");
1987 *error = TDM_ERROR_NONE;
1988 return output_data->hwc_data;
1991 hwc_data = calloc(1, sizeof(tdm_vc4_hwc_data));
1993 TDM_ERR("alloc failed");
1995 *error = TDM_ERROR_OUT_OF_MEMORY;
1998 hwc_data->output_data = output_data;
2000 LIST_INITHEAD(&hwc_data->hwc_window_list);
2002 output_data->hwc_data = hwc_data;
2004 ret = vc4_hwc_initailize_target_window(output_data->hwc_data);
2005 if (ret != TDM_ERROR_NONE) {
2006 TDM_ERR("create target hwc window failed (%d)", ret);
2014 *error = TDM_ERROR_NONE;
2021 vc4_output_set_status_handler(tdm_output *output,
2022 tdm_output_status_handler func,
2025 tdm_vc4_output_data *output_data = output;
2027 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
2028 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
2030 output_data->status_func = func;
2031 output_data->status_user_data = user_data;
2033 return TDM_ERROR_NONE;
2037 vc4_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
2039 tdm_vc4_layer_data *layer_data = layer;
2040 tdm_vc4_data *vc4_data;
2041 drmModePlanePtr plane = NULL;
2042 drmModeObjectPropertiesPtr props = NULL;
2043 int i, format_count = 0;
2044 int primary_zpos = _get_primary_layer_zpos(layer_data->output_data);
2047 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2048 RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
2050 memset(caps, 0, sizeof(tdm_caps_layer));
2052 vc4_data = layer_data->vc4_data;
2053 plane = drmModeGetPlane(vc4_data->drm_fd, layer_data->plane_id);
2055 TDM_ERR("get plane failed: %m");
2056 ret = TDM_ERROR_OPERATION_FAILED;
2060 caps->capabilities = layer_data->capabilities;
2061 caps->zpos = layer_data->zpos;
2063 caps->format_count = plane->count_formats;
2064 caps->formats = calloc(1, sizeof(tbm_format) * caps->format_count);
2065 if (!caps->formats) {
2066 ret = TDM_ERROR_OUT_OF_MEMORY;
2067 TDM_ERR("alloc failed\n");
2071 for (i = 0; i < caps->format_count; i++) {
2072 /* Changing between RGB and YUV format for a plane doesn't work properly
2073 * only support AR24, XR24 for primary, overlay
2075 if (layer_data->zpos >= primary_zpos) {
2076 if (plane->formats[i] != DRM_FORMAT_XRGB8888 && plane->formats[i] != DRM_FORMAT_ARGB8888)
2079 /* only support NV12 for underlay */
2080 if (plane->formats[i] != DRM_FORMAT_NV12)
2084 caps->formats[format_count] = tdm_vc4_format_to_tbm_format(plane->formats[i]);
2088 caps->format_count = format_count;
2090 props = drmModeObjectGetProperties(vc4_data->drm_fd, layer_data->plane_id,
2091 DRM_MODE_OBJECT_PLANE);
2093 ret = TDM_ERROR_OPERATION_FAILED;
2094 TDM_ERR("get plane properties failed: %m\n");
2098 caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
2100 ret = TDM_ERROR_OUT_OF_MEMORY;
2101 TDM_ERR("alloc failed\n");
2105 caps->prop_count = 0;
2106 for (i = 0; i < props->count_props; i++) {
2107 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd, props->props[i]);
2110 if (!strncmp(prop->name, "type", TDM_NAME_LEN)) {
2111 drmModeFreeProperty(prop);
2114 if (!strncmp(prop->name, "zpos", TDM_NAME_LEN)) {
2115 drmModeFreeProperty(prop);
2118 snprintf(caps->props[caps->prop_count].name, TDM_NAME_LEN, "%s", prop->name);
2119 caps->props[caps->prop_count].id = props->props[i];
2121 drmModeFreeProperty(prop);
2124 drmModeFreeObjectProperties(props);
2125 drmModeFreePlane(plane);
2127 return TDM_ERROR_NONE;
2129 drmModeFreeObjectProperties(props);
2130 drmModeFreePlane(plane);
2131 free(caps->formats);
2133 memset(caps, 0, sizeof(tdm_caps_layer));
2138 vc4_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value)
2140 tdm_vc4_layer_data *layer_data = layer;
2141 tdm_vc4_data *vc4_data;
2144 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2145 RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
2147 vc4_data = layer_data->vc4_data;
2148 ret = drmModeObjectSetProperty(vc4_data->drm_fd,
2149 layer_data->plane_id, DRM_MODE_OBJECT_PLANE,
2152 TDM_ERR("set property failed: %m");
2153 return TDM_ERROR_OPERATION_FAILED;
2156 return TDM_ERROR_NONE;
2160 vc4_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value)
2162 tdm_vc4_layer_data *layer_data = layer;
2163 tdm_vc4_data *vc4_data;
2164 drmModeObjectPropertiesPtr props;
2167 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2168 RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
2169 RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
2171 vc4_data = layer_data->vc4_data;
2172 props = drmModeObjectGetProperties(vc4_data->drm_fd, layer_data->plane_id,
2173 DRM_MODE_OBJECT_PLANE);
2174 if (props == NULL) {
2175 TDM_ERR("get property failed: %m");
2176 return TDM_ERROR_OPERATION_FAILED;
2179 for (i = 0; i < props->count_props; i++)
2180 if (props->props[i] == id) {
2181 (*value).u32 = (uint)props->prop_values[i];
2185 drmModeFreeObjectProperties(props);
2187 return TDM_ERROR_NONE;
2191 vc4_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
2193 tdm_vc4_layer_data *layer_data = layer;
2195 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2196 RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
2198 layer_data->info = *info;
2199 layer_data->info_changed = 1;
2201 return TDM_ERROR_NONE;
2205 vc4_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
2207 tdm_vc4_layer_data *layer_data = layer;
2209 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2210 RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
2212 *info = layer_data->info;
2214 return TDM_ERROR_NONE;
2217 static tdm_vc4_display_buffer *
2218 _tdm_vc4_display_find_buffer(tdm_vc4_data *vc4_data, tbm_surface_h buffer)
2220 tdm_vc4_display_buffer *display_buffer = NULL;
2222 LIST_FOR_EACH_ENTRY(display_buffer, &vc4_data->buffer_list, link) {
2223 if (display_buffer->buffer == buffer)
2224 return display_buffer;
2231 _tdm_vc4_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
2233 tdm_vc4_data *vc4_data;
2234 tdm_vc4_display_buffer *display_buffer;
2235 tdm_vc4_layer_data *layer_data = NULL;
2236 tdm_vc4_output_data *output_data = NULL;
2237 char buf[256] = {0,};
2241 TDM_ERR("no user_data");
2245 TDM_ERR("no buffer");
2249 vc4_data = (tdm_vc4_data *) user_data;
2251 display_buffer = _tdm_vc4_display_find_buffer(vc4_data, buffer);
2252 if (!display_buffer) {
2253 TDM_ERR("no display_buffer");
2257 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
2258 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
2259 if (display_buffer == layer_data->display_buffer)
2260 layer_data->display_buffer = NULL;
2264 if (display_buffer->fb_id > 0) {
2265 if (drmModeRmFB(vc4_data->drm_fd, display_buffer->fb_id) < 0) {
2266 ret_tmp = strerror_r(errno, buf, sizeof(buf));
2267 TDM_ERR("rm fb failed: %d(%s,%s)\n", errno, buf, ret_tmp);
2271 TDM_DBG("destroy buffer:%p", display_buffer->buffer);
2273 LIST_DEL(&display_buffer->link);
2274 free(display_buffer);
2277 static tdm_vc4_display_buffer *
2278 _tdm_vc4_display_create_buffer(tdm_vc4_data *vc4_data, tbm_surface_h buffer, tdm_error *err)
2280 tdm_vc4_display_buffer *display_buffer = NULL;
2281 tdm_error res = TDM_ERROR_NONE;
2284 display_buffer = calloc(1, sizeof(tdm_vc4_display_buffer));
2285 if (!display_buffer) {
2286 TDM_ERR("alloc failed");
2288 *err = TDM_ERROR_OUT_OF_MEMORY;
2292 display_buffer->buffer = buffer;
2294 res = tdm_buffer_add_destroy_handler(buffer, _tdm_vc4_display_cb_destroy_buffer, vc4_data);
2295 if (res != TDM_ERROR_NONE) {
2296 TDM_ERR("add destroy handler fail");
2297 free(display_buffer);
2303 display_buffer->width = tbm_surface_get_width(buffer);
2304 display_buffer->height = tbm_surface_get_height(buffer);
2305 display_buffer->format = tbm_surface_get_format(buffer);
2306 display_buffer->count = tbm_surface_internal_get_num_bos(buffer);
2307 count = tbm_surface_internal_get_num_planes(display_buffer->format);
2308 TDM_DBG("create buffer:%p %dx%d %c%c%c%c bo_num:%d plane_num:%d",
2309 buffer, display_buffer->width, display_buffer->height,
2310 FOURCC_STR(display_buffer->format), display_buffer->count, count);
2312 for (i = 0; i < count; i++) {
2316 bo_idx = tbm_surface_internal_get_plane_bo_idx(buffer, i);
2317 bo = tbm_surface_internal_get_bo(buffer, bo_idx);
2318 display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
2320 tbm_surface_internal_get_plane_data(buffer, i, &display_buffer->size,
2321 &display_buffer->offsets[i],
2322 &display_buffer->pitches[i]);
2323 TDM_DBG(" create buffer:%p plane%d(size:%d offset:%d pitch:%d) bo%d(handle:%d)",
2324 buffer, i, display_buffer->size, display_buffer->offsets[i],
2325 display_buffer->pitches[i], bo_idx, display_buffer->handles[i]);
2328 ret = drmModeAddFB2(vc4_data->drm_fd, display_buffer->width, display_buffer->height,
2329 display_buffer->format, display_buffer->handles, display_buffer->pitches,
2330 display_buffer->offsets, &display_buffer->fb_id, 0);
2332 TDM_ERR("add fb failed: %m");
2333 free(display_buffer);
2335 *err = TDM_ERROR_OPERATION_FAILED;
2339 TDM_DBG("vc4_data->drm_fd : %d, display_buffer->fb_id:%u", vc4_data->drm_fd,
2340 display_buffer->fb_id);
2342 if (IS_RGB(display_buffer->format))
2343 display_buffer->width = display_buffer->pitches[0] >> 2;
2345 display_buffer->width = display_buffer->pitches[0];
2347 LIST_ADDTAIL(&display_buffer->link, &vc4_data->buffer_list);
2350 *err = TDM_ERROR_NONE;
2352 return display_buffer;
2356 tdm_vc4_data_destroy_buffer_list(tdm_vc4_data *vc4_data)
2358 tdm_vc4_display_buffer *b = NULL, *bb = NULL;
2360 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &vc4_data->buffer_list, link) {
2361 tdm_buffer_remove_destroy_handler(b->buffer, _tdm_vc4_display_cb_destroy_buffer, vc4_data);
2362 _tdm_vc4_display_cb_destroy_buffer(b->buffer, vc4_data);
2367 vc4_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
2369 tdm_vc4_layer_data *layer_data = layer;
2370 tdm_vc4_data *vc4_data;
2371 tdm_vc4_display_buffer *display_buffer;
2372 tdm_error err = TDM_ERROR_NONE;
2374 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2375 RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
2377 TDM_DBG("layer[%p]zpos[%d] buffer:%p", layer, layer_data->zpos, buffer);
2379 vc4_data = layer_data->vc4_data;
2380 display_buffer = _tdm_vc4_display_find_buffer(vc4_data, buffer);
2381 if (!display_buffer) {
2382 display_buffer = _tdm_vc4_display_create_buffer(vc4_data, buffer, &err);
2383 RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
2386 if (layer_data->display_buffer != display_buffer) {
2387 if (layer_data->display_buffer)
2388 tbm_surface_internal_unref(layer_data->display_buffer->buffer);
2390 layer_data->display_buffer = display_buffer;
2391 tbm_surface_internal_ref(layer_data->display_buffer->buffer);
2392 layer_data->display_buffer_changed = 1;
2395 return TDM_ERROR_NONE;
2399 vc4_layer_unset_buffer(tdm_layer *layer)
2401 tdm_vc4_layer_data *layer_data = layer;
2403 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2405 TDM_DBG("layer[%p]zpos[%d]", layer, layer_data->zpos);
2407 if (layer_data->display_buffer)
2408 tbm_surface_internal_unref(layer_data->display_buffer->buffer);
2410 layer_data->display_buffer = NULL;
2411 layer_data->display_buffer_changed = 1;
2413 return TDM_ERROR_NONE;
2416 tdm_vc4_layer_data *
2417 vc4_output_data_get_layer_data(tdm_vc4_output_data *output_data, int layer_zpos)
2419 tdm_vc4_layer_data *l = NULL;
2421 RETURN_VAL_IF_FAIL(output_data, NULL);
2423 LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link) {
2424 if (l->zpos == layer_zpos)
2432 _vc4_output_data_center_rect_get(int src_w, int src_h, int dst_w, int dst_h, tdm_pos *fit)
2436 if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0 || !fit)
2439 rh = (float) src_h / src_w;
2444 fit->h = dst_w * rh;
2446 //TDM_ERR("=###### (%d, %d, %d, %d) (%f)", fit->x, fit->y, fit->w, fit->h, rh);
2450 vc4_output_data_prepare_mirror_commit(tdm_vc4_output_data *output_data, tbm_surface_h surface)
2452 tdm_vc4_layer_data *layer_data = NULL;
2453 tdm_info_layer info;
2454 tbm_surface_info_s surf_info;
2458 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
2459 RETURN_VAL_IF_FAIL(surface, TDM_ERROR_INVALID_PARAMETER);
2461 RETURN_VAL_IF_FAIL(output_data->current_mode, TDM_ERROR_OPERATION_FAILED);
2463 layer_data = vc4_output_data_get_layer_data(output_data, 0);
2464 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_OPERATION_FAILED);
2466 memset(&dst_pos, 0, sizeof(tdm_pos));
2468 tbm_surface_get_info(surface, &surf_info);
2469 // TODO: NEED to fix the calculation of the dst_pos
2470 _vc4_output_data_center_rect_get(surf_info.width, surf_info.height,
2471 output_data->current_mode->hdisplay, output_data->current_mode->hdisplay,
2474 info.src_config.size.h = surf_info.width;
2475 info.src_config.size.v = surf_info.height;
2476 info.src_config.format = TBM_FORMAT_ARGB8888;
2477 info.src_config.pos.x = 0;
2478 info.src_config.pos.y = 0;
2479 info.src_config.pos.w = surf_info.width;
2480 info.src_config.pos.h = surf_info.height;
2481 info.dst_pos.x = dst_pos.x;
2482 info.dst_pos.y = dst_pos.y;
2483 info.dst_pos.w = output_data->current_mode->hdisplay;
2484 info.dst_pos.h = output_data->current_mode->vdisplay;
2485 info.transform = TDM_TRANSFORM_NORMAL;
2487 ret = vc4_layer_set_info((tdm_layer *)layer_data, &info);
2488 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
2490 ret = vc4_layer_set_buffer(layer_data, surface);
2491 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
2493 return TDM_ERROR_NONE;
2497 vc4_layer_set_acquire_fence(tdm_layer *layer, int acquire_fence)
2499 tdm_vc4_layer_data *layer_data = layer;
2501 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2503 TDM_DBG("layer[%p]zpos[%d] acquire_fence:%d", layer, layer_data->zpos, acquire_fence);
2505 if (layer_data->acquire_fence != acquire_fence)
2506 layer_data->acquire_fence = acquire_fence;
2508 return TDM_ERROR_NONE;