9 #define MODE_WIDTH_LIMIT 1920
10 #define MODE_HEIGHT_LIMIT 1080
11 #define MODE_REFRESH_LIMIT 60
13 #define LIST_INSERT_AFTER(__after, __item) \
14 (__item)->prev = (__after); \
15 (__item)->next = (__after)->next; \
16 (__after)->next->prev = (__item); \
17 (__after)->next = (__item);
20 check_hw_restriction(unsigned int crtc_w, unsigned int crtc_h, unsigned int buf_w,
21 unsigned int src_x, unsigned int src_w,
22 unsigned int dst_x, unsigned int dst_y, unsigned int dst_w,
23 unsigned int *new_src_x, unsigned int *new_src_w,
24 unsigned int *new_dst_x, unsigned int *new_dst_w)
34 if (buf_w < MIN_WIDTH || buf_w % 2) {
35 TDM_ERR("buf_w(%u) not 2's multiple or less than %u", buf_w, MIN_WIDTH);
36 return TDM_ERROR_BAD_REQUEST;
39 if (dst_x > crtc_w || dst_y > crtc_h) {
40 TDM_ERR("dst_pos(%u,%u) is out of crtc(%ux%u)", dst_x, dst_y, crtc_w, crtc_h);
41 return TDM_ERROR_BAD_REQUEST;
44 if (src_x > dst_x || ((dst_x - src_x) + buf_w) > crtc_w)
50 end = ((dst_x + dst_w) > crtc_w) ? crtc_w : (dst_x + dst_w);
52 /* check window minimun width */
53 if ((end - start) < MIN_WIDTH) {
54 TDM_ERR("visible_w(%d) less than %u", end - start, MIN_WIDTH);
55 return TDM_ERROR_BAD_REQUEST;
58 if (!virtual_screen) {
59 /* Pagewidth of window (= 8 byte align / bytes-per-pixel ) */
60 if ((end - start) % 2)
63 /* You should align the sum of PAGEWIDTH_F and OFFSIZE_F double-word (8 byte) boundary. */
69 *new_dst_w = end - start;
71 RETURN_VAL_IF_FAIL(*new_src_w > 0, TDM_ERROR_BAD_REQUEST);
72 RETURN_VAL_IF_FAIL(*new_dst_w > 0, TDM_ERROR_BAD_REQUEST);
74 if (src_x != *new_src_x || src_w != *new_src_w || dst_x != *new_dst_x ||
76 TDM_INFO("=> buf_w(%d) src(%d,%d) dst(%d,%d), virt(%d) start(%d) end(%d)",
77 buf_w, *new_src_x, *new_src_w, *new_dst_x, *new_dst_w, virtual_screen, start,
80 return TDM_ERROR_NONE;
83 static drmModeModeInfoPtr
84 _tdm_vc4_display_get_mode(tdm_vc4_output_data *output_data)
88 if (!output_data->current_mode) {
89 TDM_ERR("no output_data->current_mode");
93 const tdm_output_mode *mode;
95 mode = output_data->current_mode;
96 TDM_INFO("Current mode: %s, %d, %d, %d, %d, %d",
97 mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags, mode->type);
100 TDM_INFO(" Count modes: %d %d", output_data->count_drm_modes, output_data->count_modes);
102 for (i = 0; i < output_data->count_drm_modes; i++) {
103 drmModeModeInfoPtr vc4_mode = &output_data->vc4_modes[i];
105 TDM_INFO(" DRM mode: %s, %d, %d, %d, %d, %d",
106 vc4_mode->name, vc4_mode->hdisplay, vc4_mode->vdisplay, vc4_mode->vrefresh, vc4_mode->flags, vc4_mode->type);
108 if ((vc4_mode->hdisplay == output_data->current_mode->hdisplay) &&
109 (vc4_mode->hsync_start == output_data->current_mode->hsync_start) &&
110 (vc4_mode->hsync_end == output_data->current_mode->hsync_end) &&
111 (vc4_mode->htotal == output_data->current_mode->htotal) &&
112 (vc4_mode->hskew == output_data->current_mode->hskew) &&
113 (vc4_mode->vdisplay == output_data->current_mode->vdisplay) &&
114 (vc4_mode->vsync_start == output_data->current_mode->vsync_start) &&
115 (vc4_mode->vsync_end == output_data->current_mode->vsync_end) &&
116 (vc4_mode->vtotal == output_data->current_mode->vtotal) &&
117 (vc4_mode->vscan == output_data->current_mode->vscan) &&
118 (vc4_mode->clock == output_data->current_mode->clock) &&
119 (vc4_mode->vrefresh == output_data->current_mode->vrefresh) &&
120 (vc4_mode->flags == output_data->current_mode->flags) &&
121 (vc4_mode->type == output_data->current_mode->type) &&
122 !(strncmp(vc4_mode->name, output_data->current_mode->name, TDM_NAME_LEN)))
130 _tdm_vc4_display_set_fb(tdm_vc4_data *vc4_data, tbm_surface_h buffer, unsigned int *id)
135 unsigned int handles[4] = {0,};
136 unsigned int pitches[4] = {0,};
137 unsigned int offsets[4] = {0,};
142 width = tbm_surface_get_width(buffer);
143 height = tbm_surface_get_height(buffer);
144 format = tbm_surface_get_format(buffer);
145 count = tbm_surface_internal_get_num_bos(buffer);
146 for (i = 0; i < count; i++) {
147 tbm_bo bo = tbm_surface_internal_get_bo(buffer, i);
148 handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
150 count = tbm_surface_internal_get_num_planes(format);
151 for (i = 0; i < count; i++)
152 tbm_surface_internal_get_plane_data(buffer, i, &size, &offsets[i], &pitches[i]);
154 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)",
155 vc4_data->drm_fd, width, height, FOURCC_STR(format),
156 handles[0], handles[1], handles[2], pitches[0], pitches[1], pitches[2],
157 offsets[0], offsets[1], offsets[2], buffer);
159 ret = drmModeAddFB2(vc4_data->drm_fd, width, height, format,
160 handles, pitches, offsets, &fb_id, 0);
162 TDM_ERR("add fb failed: %m");
163 return TDM_ERROR_OPERATION_FAILED;
165 TDM_DBG("AddFB2 success: drm_fd(%d) fb_id(%u)", vc4_data->drm_fd, fb_id);
168 return TDM_ERROR_NONE;
172 _tdm_vc4_output_update_status(tdm_vc4_output_data *output_data,
173 tdm_output_conn_status status)
175 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
177 if (output_data->status == status)
178 return TDM_ERROR_NONE;
180 output_data->status = status;
182 if (output_data->status_func)
183 output_data->status_func(output_data, status,
184 output_data->status_user_data);
186 return TDM_ERROR_NONE;
190 _tdm_vc4_display_set_crtc(tdm_vc4_data *vc4_data, tdm_vc4_output_data *output_data, int set)
194 output_data->mode_changed = 0;
197 tbm_surface_h buffer = NULL;
198 tbm_surface_info_s info;
199 drmModeModeInfoPtr mode;
200 unsigned int fb_id = 0;
202 if (!output_data->current_mode)
203 return TDM_ERROR_OPERATION_FAILED;
205 mode = _tdm_vc4_display_get_mode(output_data);
207 TDM_ERR("couldn't find proper mode");
208 return TDM_ERROR_BAD_REQUEST;
211 buffer = tbm_surface_create(output_data->current_mode->hdisplay,
212 output_data->current_mode->vdisplay,
213 TBM_FORMAT_XRGB8888);
214 RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_OPERATION_FAILED);
216 if (tbm_surface_map(buffer, TBM_SURF_OPTION_WRITE, &info) != TBM_ERROR_NONE) {
217 tbm_surface_destroy(buffer);
218 return TDM_ERROR_OPERATION_FAILED;
220 memset(info.planes[0].ptr, 0x0, info.size);
222 tbm_surface_unmap(buffer);
224 if (_tdm_vc4_display_set_fb(vc4_data, buffer, &fb_id) != TDM_ERROR_NONE) {
225 tbm_surface_destroy(buffer);
226 return TDM_ERROR_OPERATION_FAILED;
229 TDM_DBG("drmModeSetCrtc drm_fd(%d) crtc_id(%u) fb_id(%u) mode(%u,%u)",
230 vc4_data->drm_fd, output_data->crtc_id, fb_id,
231 mode->hdisplay, mode->vdisplay);
233 if (drmModeSetCrtc(vc4_data->drm_fd, output_data->crtc_id,
235 &output_data->connector_id, 1, mode)) {
236 TDM_ERR("set crtc failed: %m");
237 ret = drmModeRmFB(vc4_data->drm_fd, fb_id);
239 TDM_ERR("rm fb failed fb_id(%u)", fb_id);
240 tbm_surface_destroy(buffer);
241 return TDM_ERROR_OPERATION_FAILED;
244 _tdm_vc4_output_update_status(output_data, TDM_OUTPUT_CONN_STATUS_MODE_SETTED);
246 if (output_data->crtc_buffer) {
247 ret = drmModeRmFB(vc4_data->drm_fd, output_data->crtc_fb_id);
249 TDM_ERR("rm fb failed fb_id(%u)", output_data->crtc_fb_id);
250 tbm_surface_destroy(output_data->crtc_buffer);
252 output_data->crtc_buffer = buffer;
253 output_data->crtc_fb_id = fb_id;
255 TDM_DBG("drmModeSetCrtc unset drm_fd(%d) crtc_id(%u)",
256 vc4_data->drm_fd, output_data->crtc_id);
258 if (drmModeSetCrtc(vc4_data->drm_fd, output_data->crtc_id,
259 0, 0, 0, NULL, 0, NULL)) {
260 TDM_ERR("unset crtc failed: %m");
261 return TDM_ERROR_OPERATION_FAILED;
264 if (output_data->crtc_buffer) {
265 ret = drmModeRmFB(vc4_data->drm_fd, output_data->crtc_fb_id);
267 TDM_ERR("rm fb failed fb_id(%u)", output_data->crtc_fb_id);
268 tbm_surface_destroy(output_data->crtc_buffer);
270 output_data->crtc_buffer = NULL;
271 output_data->crtc_fb_id = 0;
274 return TDM_ERROR_NONE;
278 _tdm_vc4_display_to_tdm_mode(drmModeModeInfoPtr vc4_mode,
279 tdm_output_mode *tdm_mode)
281 tdm_mode->clock = vc4_mode->clock;
282 tdm_mode->hdisplay = vc4_mode->hdisplay;
283 tdm_mode->hsync_start = vc4_mode->hsync_start;
284 tdm_mode->hsync_end = vc4_mode->hsync_end;
285 tdm_mode->htotal = vc4_mode->htotal;
286 tdm_mode->hskew = vc4_mode->hskew;
287 tdm_mode->vdisplay = vc4_mode->vdisplay;
288 tdm_mode->vsync_start = vc4_mode->vsync_start;
289 tdm_mode->vsync_end = vc4_mode->vsync_end;
290 tdm_mode->vtotal = vc4_mode->vtotal;
291 tdm_mode->vscan = vc4_mode->vscan;
292 tdm_mode->vrefresh = vc4_mode->vrefresh;
293 tdm_mode->flags = vc4_mode->flags;
294 tdm_mode->type = vc4_mode->type;
295 snprintf(tdm_mode->name, TDM_NAME_LEN, "%s", vc4_mode->name);
299 _tdm_vc4_display_get_cur_msc(int fd, int pipe, uint *msc)
303 vbl.request.type = DRM_VBLANK_RELATIVE;
305 vbl.request.type |= DRM_VBLANK_SECONDARY;
307 vbl.request.type |= pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
309 vbl.request.sequence = 0;
310 if (drmWaitVBlank(fd, &vbl)) {
311 TDM_ERR("get vblank counter failed: %m");
313 return TDM_ERROR_OPERATION_FAILED;
316 *msc = vbl.reply.sequence;
318 return TDM_ERROR_NONE;
322 _tdm_vc4_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data)
326 vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
328 vbl.request.type |= DRM_VBLANK_SECONDARY;
330 vbl.request.type |= pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
332 vbl.request.sequence = *target_msc;
333 vbl.request.signal = (unsigned long)(uintptr_t)data;
335 if (drmWaitVBlank(fd, &vbl)) {
336 TDM_ERR("wait vblank failed: %m");
338 return TDM_ERROR_OPERATION_FAILED;
341 *target_msc = vbl.reply.sequence;
343 return TDM_ERROR_NONE;
347 _tdm_vc4_display_commit_layer(tdm_vc4_layer_data *layer_data)
349 tdm_vc4_data *vc4_data = layer_data->vc4_data;
350 tdm_vc4_output_data *output_data = layer_data->output_data;
351 uint32_t fx, fy, fw, fh;
354 if (!layer_data->display_buffer_changed && !layer_data->info_changed)
355 return TDM_ERROR_NONE;
357 if (!output_data->crtc_enabled || output_data->mode_changed) {
358 if (_tdm_vc4_display_set_crtc(vc4_data, output_data, 1) != TDM_ERROR_NONE)
359 return TDM_ERROR_OPERATION_FAILED;
361 output_data->crtc_enabled = 1;
364 if (output_data->current_mode)
365 crtc_w = output_data->current_mode->hdisplay;
367 drmModeCrtcPtr crtc = drmModeGetCrtc(vc4_data->drm_fd, output_data->crtc_id);
369 TDM_ERR("getting crtc failed");
370 return TDM_ERROR_OPERATION_FAILED;
372 crtc_w = crtc->width;
374 TDM_ERR("getting crtc width failed");
375 drmModeFreeCrtc(crtc);
376 return TDM_ERROR_OPERATION_FAILED;
378 drmModeFreeCrtc(crtc);
381 layer_data->display_buffer_changed = 0;
382 layer_data->info_changed = 0;
384 if (!layer_data->display_buffer) {
385 if (drmModeSetPlane(vc4_data->drm_fd, layer_data->plane_id,
386 output_data->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
387 TDM_ERR("unset plane(%d) filed: %m", layer_data->plane_id);
389 return TDM_ERROR_NONE;
392 /* Source values are 16.16 fixed point */
393 fx = ((unsigned int)layer_data->info.src_config.pos.x) << 16;
394 fy = ((unsigned int)layer_data->info.src_config.pos.y) << 16;
395 fw = ((unsigned int)layer_data->info.src_config.pos.w) << 16;
396 fh = ((unsigned int)layer_data->info.src_config.pos.h) << 16;
398 if (drmModeSetPlane(vc4_data->drm_fd, layer_data->plane_id,
399 output_data->crtc_id, layer_data->display_buffer->fb_id, 0,
400 layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
401 layer_data->info.dst_pos.w, layer_data->info.dst_pos.h,
402 fx, fy, fw, fh) < 0) {
403 TDM_ERR("set plane(%d) failed: %m", layer_data->plane_id);
404 return TDM_ERROR_OPERATION_FAILED;
407 TDM_DBG("plane(%d) crtc(%d) pos(%d) on: fb(%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n",
408 layer_data->plane_id, output_data->crtc_id, layer_data->zpos,
409 layer_data->display_buffer->fb_id,
410 layer_data->info.src_config.pos.x, layer_data->info.src_config.pos.y,
411 layer_data->info.src_config.pos.w, layer_data->info.src_config.pos.h,
412 layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
413 layer_data->info.dst_pos.w, layer_data->info.dst_pos.h);
415 return TDM_ERROR_NONE;
419 _tdm_vc4_display_cb_event(int fd, unsigned int sequence,
420 unsigned int tv_sec, unsigned int tv_usec,
423 tdm_vc4_event_data *event_data = user_data;
424 tdm_vc4_output_data *output_data;
425 tdm_vc4_hwc_data *hwc_data;
429 TDM_ERR("no event data");
433 output_data = event_data->output_data;
436 TDM_DBG("==== Atomic Commit Handler pipe, %u, crtc_id, %u connector_id, %u",
437 output_data->pipe, output_data->crtc_id, output_data->connector_id);
439 switch (event_data->type) {
440 case TDM_DRM_EVENT_TYPE_PAGEFLIP:
441 if (output_data->commit_func)
442 output_data->commit_func(output_data, sequence, tv_sec, tv_usec,
443 event_data->user_data);
445 case TDM_DRM_EVENT_TYPE_WAIT:
446 if (output_data->vblank_func)
447 output_data->vblank_func(output_data, sequence, tv_sec, tv_usec,
448 event_data->user_data);
450 case TDM_DRM_EVENT_TYPE_COMMIT:
451 if (output_data->hwc_enable) {
452 hwc_data = output_data->hwc_data;
454 TDM_ERR("no hwc_data");
458 if (hwc_data->commit_func)
459 hwc_data->commit_func(hwc_data, sequence,
461 event_data->user_data);
463 if (output_data->commit_func)
464 output_data->commit_func(output_data, sequence,
466 event_data->user_data);
477 _vc4_output_get_atomic_prop_id(int drm_fd, uint32_t object_id, uint32_t object_type, const char *name, uint32_t *id)
479 drmModeObjectPropertiesPtr properties = NULL;
480 drmModePropertyPtr property = NULL;
483 properties = drmModeObjectGetProperties(drm_fd, object_id, object_type);
484 if (properties == NULL) {
485 TDM_ERR("drmModeObjectGetProperties failed");
486 return TDM_ERROR_OPERATION_FAILED;
489 for (i = 0; i < properties->count_props; i++) {
490 property = drmModeGetProperty(drm_fd, properties->props[i]);
491 if (property == NULL) {
495 if (strcmp(property->name, name) == 0) {
496 *id = property->prop_id;
497 drmModeFreeProperty(property);
500 drmModeFreeProperty(property);
503 drmModeFreeObjectProperties(properties);
505 return TDM_ERROR_NONE;
509 _tdm_vc4_display_create_layer_list(tdm_vc4_data *vc4_data)
511 tdm_vc4_output_data *output_data = NULL;
514 if (LIST_IS_EMPTY(&vc4_data->output_list)) {
515 TDM_ERR("no output");
516 return TDM_ERROR_OPERATION_FAILED;
519 /* The TDM drm backend only support one output. */
520 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
524 if (vc4_data->plane_res->count_planes == 0) {
525 TDM_ERR("no layer error");
526 return TDM_ERROR_OPERATION_FAILED;
529 for (i = 0; i < vc4_data->plane_res->count_planes; i++) {
530 tdm_vc4_layer_data *layer_data;
531 drmModePlanePtr plane;
533 plane = drmModeGetPlane(vc4_data->drm_fd, vc4_data->plane_res->planes[i]);
539 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
540 drmModeFreePlane(plane);
544 layer_data = calloc(1, sizeof(tdm_vc4_layer_data));
546 TDM_ERR("alloc failed");
547 drmModeFreePlane(plane);
551 layer_data->vc4_data = vc4_data;
552 layer_data->output_data = output_data;
553 layer_data->plane_id = vc4_data->plane_res->planes[i];
554 layer_data->acquire_fence = -1;
556 layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
557 TDM_LAYER_CAPABILITY_GRAPHIC;
558 output_data->primary_layer = layer_data;
560 TDM_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) capabilities(%x)",
561 layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
562 layer_data->capabilities);
564 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
566 drmModeFreePlane(plane);
568 /* can't take care of other planes for various hardware devices */
572 return TDM_ERROR_NONE;
575 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
578 _tdm_vc4_display_get_property(tdm_vc4_data *vc4_data,
579 unsigned int obj_id, unsigned int obj_type,
580 const char *name, unsigned int *value,
583 drmModeObjectPropertiesPtr props = NULL;
586 props = drmModeObjectGetProperties(vc4_data->drm_fd, obj_id, obj_type);
588 return TDM_ERROR_OPERATION_FAILED;
590 for (i = 0; i < props->count_props; i++) {
591 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd,
597 if (!strcmp(prop->name, name)) {
599 *is_immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
601 *value = (unsigned int)props->prop_values[i];
602 drmModeFreeProperty(prop);
603 drmModeFreeObjectProperties(props);
604 return TDM_ERROR_NONE;
607 drmModeFreeProperty(prop);
609 drmModeFreeObjectProperties(props);
610 TDM_DBG("coundn't find '%s' property", name);
611 return TDM_ERROR_OPERATION_FAILED;
615 _tdm_vc4_display_create_layer_list_type(tdm_vc4_data *vc4_data)
617 drmModePlanePtr plane;
621 for (i = 0; i < vc4_data->plane_res->count_planes; i++) {
622 tdm_vc4_output_data *output_data = NULL;
623 tdm_vc4_layer_data *layer_data;
624 unsigned int type = 0;
627 plane = drmModeGetPlane(vc4_data->drm_fd, vc4_data->plane_res->planes[i]);
633 ret = _tdm_vc4_display_get_property(vc4_data,
634 vc4_data->plane_res->planes[i],
635 DRM_MODE_OBJECT_PLANE, "type", &type, NULL);
636 if (ret != TDM_ERROR_NONE) {
637 TDM_ERR("plane(%d) doesn't have 'type' info",
638 vc4_data->plane_res->planes[i]);
639 drmModeFreePlane(plane);
643 layer_data = calloc(1, sizeof(tdm_vc4_layer_data));
645 TDM_ERR("alloc failed");
646 drmModeFreePlane(plane);
650 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
651 if (plane->possible_crtcs & (1 << output_data->pipe)) {
658 TDM_ERR("plane(%d) couldn't found proper output", plane->plane_id);
659 drmModeFreePlane(plane);
664 layer_data->vc4_data = vc4_data;
665 layer_data->output_data = output_data;
666 layer_data->plane_id = vc4_data->plane_res->planes[i];
667 layer_data->acquire_fence = -1;
669 if (type == DRM_PLANE_TYPE_CURSOR) {
670 layer_data->capabilities = TDM_LAYER_CAPABILITY_CURSOR |
671 TDM_LAYER_CAPABILITY_GRAPHIC;
672 layer_data->zpos = 2;
673 } else if (type == DRM_PLANE_TYPE_OVERLAY) {
674 layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY |
675 TDM_LAYER_CAPABILITY_GRAPHIC;
676 layer_data->zpos = 1;
677 } else if (type == DRM_PLANE_TYPE_PRIMARY) {
678 layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
679 TDM_LAYER_CAPABILITY_GRAPHIC;
680 layer_data->zpos = 0;
681 output_data->primary_layer = layer_data;
683 drmModeFreePlane(plane);
688 TDM_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) zpos(%d) capabilities(%x)",
689 layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
690 layer_data->zpos, layer_data->capabilities);
692 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
694 /* get the atomic prop ids*/
695 if (vc4_data->has_atomic) {
696 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
697 DRM_MODE_OBJECT_PLANE, "FB_ID", &layer_data->atomic_props_ids.fb_id);
698 if (ret != TDM_ERROR_NONE) {
700 goto failed_atomic_prop_id;
703 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
704 DRM_MODE_OBJECT_PLANE, "CRTC_ID", &layer_data->atomic_props_ids.crtc_id);
705 if (ret != TDM_ERROR_NONE) {
707 goto failed_atomic_prop_id;
710 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
711 DRM_MODE_OBJECT_PLANE, "SRC_X", &layer_data->atomic_props_ids.src_x);
712 if (ret != TDM_ERROR_NONE) {
714 goto failed_atomic_prop_id;
717 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
718 DRM_MODE_OBJECT_PLANE, "SRC_Y", &layer_data->atomic_props_ids.src_y);
719 if (ret != TDM_ERROR_NONE) {
721 goto failed_atomic_prop_id;
724 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
725 DRM_MODE_OBJECT_PLANE, "SRC_W", &layer_data->atomic_props_ids.src_w);
726 if (ret != TDM_ERROR_NONE) {
728 goto failed_atomic_prop_id;
731 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
732 DRM_MODE_OBJECT_PLANE, "SRC_H", &layer_data->atomic_props_ids.src_h);
733 if (ret != TDM_ERROR_NONE) {
735 goto failed_atomic_prop_id;
738 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
739 DRM_MODE_OBJECT_PLANE, "CRTC_X", &layer_data->atomic_props_ids.crtc_x);
740 if (ret != TDM_ERROR_NONE) {
742 goto failed_atomic_prop_id;
745 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
746 DRM_MODE_OBJECT_PLANE, "CRTC_Y", &layer_data->atomic_props_ids.crtc_y);
747 if (ret != TDM_ERROR_NONE) {
749 goto failed_atomic_prop_id;
752 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
753 DRM_MODE_OBJECT_PLANE, "CRTC_W", &layer_data->atomic_props_ids.crtc_w);
754 if (ret != TDM_ERROR_NONE) {
756 goto failed_atomic_prop_id;
759 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
760 DRM_MODE_OBJECT_PLANE, "CRTC_H", &layer_data->atomic_props_ids.crtc_h);
761 if (ret != TDM_ERROR_NONE) {
763 goto failed_atomic_prop_id;
766 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, layer_data->plane_id,
767 DRM_MODE_OBJECT_PLANE, "IN_FENCE_FD", &layer_data->atomic_props_ids.in_fence_fd);
768 if (ret != TDM_ERROR_NONE) {
770 goto failed_atomic_prop_id;
774 drmModeFreePlane(plane);
777 return TDM_ERROR_NONE;
779 failed_atomic_prop_id:
781 drmModeFreePlane(plane);
783 return TDM_ERROR_OPERATION_FAILED;
788 _get_primary_layer_zpos(tdm_vc4_output_data *output_data)
790 tdm_vc4_layer_data *layer_data = NULL;
792 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
793 if (layer_data->capabilities & TDM_LAYER_CAPABILITY_PRIMARY)
794 return layer_data->zpos;
801 tdm_vc4_display_create_layer_list(tdm_vc4_data *vc4_data)
803 tdm_vc4_output_data *output_data = NULL;
806 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
807 if (vc4_data->has_universal_plane)
808 ret = _tdm_vc4_display_create_layer_list_type(vc4_data);
811 ret = _tdm_vc4_display_create_layer_list(vc4_data);
813 if (ret != TDM_ERROR_NONE)
816 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
817 if (!output_data->primary_layer) {
818 TDM_ERR("output(%d) no primary layer", output_data->pipe);
819 return TDM_ERROR_OPERATION_FAILED;
823 return TDM_ERROR_NONE;
827 tdm_vc4_display_destroy_output_list(tdm_vc4_data *vc4_data)
829 tdm_vc4_output_data *o = NULL, *oo = NULL;
830 tdm_vc4_hwc_data *hwc_data = NULL;
832 if (LIST_IS_EMPTY(&vc4_data->output_list))
835 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &vc4_data->output_list, link) {
836 hwc_data = o->hwc_data;
837 if (hwc_data && hwc_data->target_hwc_window)
838 vc4_hwc_window_destroy(hwc_data->target_hwc_window);
840 if (o->crtc_enabled) {
841 _tdm_vc4_display_set_crtc(vc4_data, o, 0);
846 if (!LIST_IS_EMPTY(&o->layer_list)) {
847 tdm_vc4_layer_data *l = NULL, *ll = NULL;
848 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
850 if (l->display_buffer)
851 tbm_surface_internal_unref(l->display_buffer->buffer);
856 free(o->output_modes);
862 tdm_vc4_display_update_output_status(tdm_vc4_data *vc4_data)
864 tdm_vc4_output_data *output_data = NULL;
866 if (LIST_IS_EMPTY(&vc4_data->output_list))
869 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
870 drmModeConnectorPtr connector;
871 tdm_output_conn_status new_status;
873 connector = drmModeGetConnector(vc4_data->drm_fd,
874 output_data->connector_id);
876 TDM_ERR("no connector: %d", output_data->connector_id);
880 if (connector->connection == DRM_MODE_CONNECTED)
881 new_status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
883 new_status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
885 _tdm_vc4_output_update_status(output_data, new_status);
887 drmModeFreeConnector(connector);
892 tdm_vc4_display_create_output_list(tdm_vc4_data *vc4_data)
894 tdm_vc4_output_data *output_data;
900 RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&vc4_data->output_list),
901 TDM_ERROR_OPERATION_FAILED);
903 for (i = 0; i < vc4_data->mode_res->count_connectors; i++) {
904 drmModeConnectorPtr connector;
905 drmModeEncoderPtr encoder;
906 int crtc_id = 0, c, j;
908 connector = drmModeGetConnector(vc4_data->drm_fd,
909 vc4_data->mode_res->connectors[i]);
911 TDM_ERR("no connector");
912 ret = TDM_ERROR_OPERATION_FAILED;
916 if (connector->count_encoders != 1) {
917 TDM_ERR("too many encoders: %d", connector->count_encoders);
918 drmModeFreeConnector(connector);
919 ret = TDM_ERROR_OPERATION_FAILED;
923 encoder = drmModeGetEncoder(vc4_data->drm_fd, connector->encoders[0]);
925 TDM_ERR("no encoder");
926 drmModeFreeConnector(connector);
927 ret = TDM_ERROR_OPERATION_FAILED;
931 for (c = 0; c < vc4_data->mode_res->count_crtcs; c++) {
932 if (allocated & (1 << c))
935 if ((encoder->possible_crtcs & (1 << c)) == 0)
938 crtc_id = vc4_data->mode_res->crtcs[c];
939 allocated |= (1 << c);
944 TDM_ERR("no possible crtc");
945 drmModeFreeConnector(connector);
946 drmModeFreeEncoder(encoder);
947 ret = TDM_ERROR_OPERATION_FAILED;
951 output_data = calloc(1, sizeof(tdm_vc4_output_data));
953 TDM_ERR("alloc failed");
954 drmModeFreeConnector(connector);
955 drmModeFreeEncoder(encoder);
956 ret = TDM_ERROR_OUT_OF_MEMORY;
960 LIST_INITHEAD(&output_data->layer_list);
962 output_data->vc4_data = vc4_data;
963 output_data->connector_id = vc4_data->mode_res->connectors[i];
964 output_data->encoder_id = encoder->encoder_id;
965 output_data->crtc_id = crtc_id;
966 output_data->pipe = c;
967 output_data->connector_type = connector->connector_type;
968 output_data->connector_type_id = connector->connector_type_id;
969 output_data->commit_fence = -1;
971 if (connector->connection == DRM_MODE_CONNECTED)
972 output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
974 output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
976 for (j = 0; j < connector->count_props; j++) {
977 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd,
978 connector->props[j]);
981 if (!strcmp(prop->name, "DPMS")) {
982 output_data->dpms_prop_id = connector->props[j];
983 drmModeFreeProperty(prop);
986 drmModeFreeProperty(prop);
989 output_data->count_modes = connector->count_modes;
990 output_data->vc4_modes = calloc(connector->count_modes, sizeof(drmModeModeInfo));
991 if (!output_data->vc4_modes) {
992 TDM_ERR("alloc failed");
994 drmModeFreeConnector(connector);
995 drmModeFreeEncoder(encoder);
996 ret = TDM_ERROR_OUT_OF_MEMORY;
1000 output_data->output_modes = calloc(connector->count_modes, sizeof(tdm_output_mode));
1001 if (!output_data->output_modes) {
1002 TDM_ERR("alloc failed");
1003 free(output_data->vc4_modes);
1005 drmModeFreeConnector(connector);
1006 drmModeFreeEncoder(encoder);
1007 ret = TDM_ERROR_OUT_OF_MEMORY;
1012 for (j = 0; j < connector->count_modes; j++) {
1013 output_data->vc4_modes[j] = connector->modes[j];
1014 if ((connector->modes[j].hdisplay > MODE_WIDTH_LIMIT) ||
1015 (connector->modes[j].vdisplay > MODE_HEIGHT_LIMIT))
1017 if (connector->modes[j].vrefresh > MODE_REFRESH_LIMIT)
1019 _tdm_vc4_display_to_tdm_mode(&output_data->vc4_modes[j],
1020 &output_data->output_modes[count]);
1024 if (vc4_data->hwc_mode)
1025 output_data->hwc_enable = 1;
1027 LIST_ADDTAIL(&output_data->link, &vc4_data->output_list);
1029 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)",
1030 output_data, output_data->connector_id, output_data->status,
1031 output_data->connector_type,
1032 output_data->connector_type_id, output_data->encoder_id, output_data->crtc_id,
1033 output_data->pipe, output_data->dpms_prop_id, output_data->count_modes);
1035 drmModeFreeEncoder(encoder);
1036 drmModeFreeConnector(connector);
1038 /* get the atomic prop ids*/
1039 if (vc4_data->has_atomic) {
1040 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, output_data->connector_id,
1041 DRM_MODE_OBJECT_CONNECTOR, "CRTC_ID", &output_data->atomic_props_ids.crtc_id);
1042 if (ret != TDM_ERROR_NONE)
1043 goto failed_atomic_prop_id;
1045 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, output_data->crtc_id,
1046 DRM_MODE_OBJECT_CRTC, "MODE_ID", &output_data->atomic_props_ids.crtc_mode_id);
1047 if (ret != TDM_ERROR_NONE)
1048 goto failed_atomic_prop_id;
1050 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, output_data->crtc_id,
1051 DRM_MODE_OBJECT_CRTC, "ACTIVE", &output_data->atomic_props_ids.crtc_active);
1052 if (ret != TDM_ERROR_NONE)
1053 goto failed_atomic_prop_id;
1055 ret = _vc4_output_get_atomic_prop_id(vc4_data->drm_fd, output_data->crtc_id,
1056 DRM_MODE_OBJECT_CRTC, "OUT_FENCE_PTR", &output_data->atomic_props_ids.out_fence_ptr);
1057 if (ret != TDM_ERROR_NONE)
1058 goto failed_atomic_prop_id;
1062 TDM_INFO("output count: %d", vc4_data->mode_res->count_connectors);
1064 return TDM_ERROR_NONE;
1065 failed_atomic_prop_id:
1067 tdm_vc4_display_destroy_output_list(vc4_data);
1072 vc4_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps)
1074 RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1076 caps->max_layer_count = -1; /* not defined */
1078 return TDM_ERROR_NONE;
1082 vc4_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error)
1084 tdm_vc4_data *vc4_data = bdata;
1085 tdm_vc4_output_data *output_data = NULL;
1086 tdm_output **outputs;
1090 RETURN_VAL_IF_FAIL(vc4_data, NULL);
1091 RETURN_VAL_IF_FAIL(count, NULL);
1094 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link)
1098 ret = TDM_ERROR_NONE;
1102 /* will be freed in frontend */
1103 outputs = calloc(*count, sizeof(tdm_vc4_output_data *));
1105 TDM_ERR("failed: alloc memory");
1107 ret = TDM_ERROR_OUT_OF_MEMORY;
1112 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link)
1113 outputs[i++] = output_data;
1116 *error = TDM_ERROR_NONE;
1126 vc4_display_get_fd(tdm_backend_data *bdata, int *fd)
1128 tdm_vc4_data *vc4_data = bdata;
1130 RETURN_VAL_IF_FAIL(vc4_data, TDM_ERROR_INVALID_PARAMETER);
1131 RETURN_VAL_IF_FAIL(fd, TDM_ERROR_INVALID_PARAMETER);
1133 *fd = vc4_data->drm_fd;
1135 return TDM_ERROR_NONE;
1139 vc4_display_handle_events(tdm_backend_data *bdata)
1141 tdm_vc4_data *vc4_data = bdata;
1142 drmEventContext ctx;
1144 RETURN_VAL_IF_FAIL(vc4_data, TDM_ERROR_INVALID_PARAMETER);
1146 memset(&ctx, 0, sizeof(drmEventContext));
1148 ctx.version = DRM_EVENT_CONTEXT_VERSION;
1149 ctx.page_flip_handler = _tdm_vc4_display_cb_event;
1150 ctx.vblank_handler = _tdm_vc4_display_cb_event;
1152 drmHandleEvent(vc4_data->drm_fd, &ctx);
1154 return TDM_ERROR_NONE;
1158 vc4_output_get_capability(tdm_output *output, tdm_caps_output *caps)
1160 tdm_vc4_output_data *output_data = output;
1161 tdm_vc4_data *vc4_data;
1162 drmModeConnectorPtr connector = NULL;
1163 drmModeCrtcPtr crtc = NULL;
1164 drmModeObjectPropertiesPtr props = NULL;
1168 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1169 RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1171 memset(caps, 0, sizeof(tdm_caps_output));
1173 vc4_data = output_data->vc4_data;
1175 snprintf(caps->maker, TDM_NAME_LEN, "unknown");
1176 snprintf(caps->model, TDM_NAME_LEN, "unknown");
1177 snprintf(caps->name, TDM_NAME_LEN, "unknown");
1179 caps->status = output_data->status;
1180 caps->type = output_data->connector_type;
1181 caps->type_id = output_data->connector_type_id;
1183 connector = drmModeGetConnector(vc4_data->drm_fd, output_data->connector_id);
1184 RETURN_VAL_IF_FAIL(connector, TDM_ERROR_OPERATION_FAILED);
1187 for (i = 0; i < connector->count_modes; i++) {
1188 if ((connector->modes[i].hdisplay > MODE_WIDTH_LIMIT) ||
1189 (connector->modes[i].vdisplay > MODE_HEIGHT_LIMIT))
1191 if (connector->modes[i].vrefresh > MODE_REFRESH_LIMIT)
1196 caps->mode_count = count;
1197 if (caps->mode_count != 0) {
1198 caps->modes = calloc(1, sizeof(tdm_output_mode) * caps->mode_count);
1200 ret = TDM_ERROR_OUT_OF_MEMORY;
1201 TDM_ERR("alloc failed\n");
1205 output_data->count_drm_modes = connector->count_modes;
1206 output_data->count_modes = caps->mode_count;
1208 drmModeModeInfoPtr new_drm_modes;
1209 tdm_output_mode *new_output_modes;
1211 new_drm_modes = calloc(connector->count_modes,
1212 sizeof(drmModeModeInfo));
1213 if (!new_drm_modes) {
1214 ret = TDM_ERROR_OUT_OF_MEMORY;
1215 TDM_ERR("alloc failed drm_modes\n");
1218 new_output_modes = calloc(caps->mode_count,
1219 sizeof(tdm_output_mode));
1220 if (!new_output_modes) {
1221 ret = TDM_ERROR_OUT_OF_MEMORY;
1222 TDM_ERR("alloc failed output_modes\n");
1223 free(new_drm_modes);
1226 if (output_data->vc4_modes)
1227 free(output_data->vc4_modes);
1228 if (output_data->output_modes)
1229 free(output_data->output_modes);
1231 output_data->vc4_modes = new_drm_modes;
1232 output_data->output_modes = new_output_modes;
1235 for (i = 0; i < connector->count_modes; i++) {
1236 output_data->vc4_modes[i] = connector->modes[i];
1238 if ((connector->modes[i].hdisplay > MODE_WIDTH_LIMIT) ||
1239 (connector->modes[i].vdisplay > MODE_HEIGHT_LIMIT))
1241 if (connector->modes[i].vrefresh > MODE_REFRESH_LIMIT)
1244 _tdm_vc4_display_to_tdm_mode(&output_data->vc4_modes[i],
1245 &output_data->output_modes[count]);
1246 caps->modes[count] = output_data->output_modes[count];
1251 output_data->count_drm_modes = connector->count_modes;
1252 output_data->count_modes = caps->mode_count;
1254 if (output_data->vc4_modes)
1255 free(output_data->vc4_modes);
1256 if (output_data->output_modes)
1257 free(output_data->output_modes);
1259 output_data->vc4_modes = NULL;
1260 output_data->output_modes = NULL;
1263 caps->mmWidth = connector->mmWidth;
1264 caps->mmHeight = connector->mmHeight;
1265 caps->subpixel = connector->subpixel;
1267 caps->min_w = vc4_data->mode_res->min_width;
1268 caps->min_h = vc4_data->mode_res->min_height;
1269 caps->max_w = vc4_data->mode_res->max_width;
1270 caps->max_h = vc4_data->mode_res->max_height;
1271 caps->preferred_align = -1;
1273 crtc = drmModeGetCrtc(vc4_data->drm_fd, output_data->crtc_id);
1275 ret = TDM_ERROR_OPERATION_FAILED;
1276 TDM_ERR("get crtc failed: %m\n");
1280 props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->crtc_id,
1281 DRM_MODE_OBJECT_CRTC);
1283 ret = TDM_ERROR_OPERATION_FAILED;
1284 TDM_ERR("get crtc properties failed: %m\n");
1288 caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
1290 ret = TDM_ERROR_OUT_OF_MEMORY;
1291 TDM_ERR("alloc failed\n");
1295 caps->prop_count = 0;
1296 for (i = 0; i < props->count_props; i++) {
1297 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd, props->props[i]);
1300 snprintf(caps->props[caps->prop_count].name, TDM_NAME_LEN, "%s", prop->name);
1301 caps->props[caps->prop_count].id = props->props[i];
1303 drmModeFreeProperty(prop);
1306 if (output_data->hwc_enable) {
1307 caps->capabilities |= TDM_OUTPUT_CAPABILITY_HWC;
1308 caps->capabilities |= TDM_OUTPUT_CAPABILITY_MIRROR;
1311 drmModeFreeObjectProperties(props);
1312 drmModeFreeCrtc(crtc);
1313 drmModeFreeConnector(connector);
1315 return TDM_ERROR_NONE;
1317 drmModeFreeCrtc(crtc);
1318 drmModeFreeObjectProperties(props);
1319 drmModeFreeConnector(connector);
1322 memset(caps, 0, sizeof(tdm_caps_output));
1327 vc4_output_get_layers(tdm_output *output, int *count, tdm_error *error)
1329 tdm_vc4_output_data *output_data = output;
1330 tdm_vc4_layer_data *layer_data = NULL;
1335 RETURN_VAL_IF_FAIL(output_data, NULL);
1336 RETURN_VAL_IF_FAIL(count, NULL);
1339 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1342 if (output_data->hwc_enable) {
1344 ret = TDM_ERROR_NONE;
1349 ret = TDM_ERROR_NONE;
1353 /* will be freed in frontend */
1354 layers = calloc(*count, sizeof(tdm_vc4_layer_data *));
1356 TDM_ERR("failed: alloc memory");
1358 ret = TDM_ERROR_OUT_OF_MEMORY;
1363 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1364 layers[i++] = layer_data;
1367 *error = TDM_ERROR_NONE;
1377 vc4_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
1379 tdm_vc4_output_data *output_data = output;
1380 tdm_vc4_data *vc4_data;
1383 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1384 RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1386 vc4_data = output_data->vc4_data;
1387 ret = drmModeObjectSetProperty(vc4_data->drm_fd,
1388 output_data->crtc_id, DRM_MODE_OBJECT_CRTC,
1391 TDM_ERR("set property failed: %m");
1392 return TDM_ERROR_OPERATION_FAILED;
1395 return TDM_ERROR_NONE;
1399 vc4_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
1401 tdm_vc4_output_data *output_data = output;
1402 tdm_vc4_data *vc4_data;
1403 drmModeObjectPropertiesPtr props;
1406 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1407 RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1408 RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
1410 vc4_data = output_data->vc4_data;
1411 props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->crtc_id,
1412 DRM_MODE_OBJECT_CRTC);
1413 if (props == NULL) {
1414 TDM_ERR("get property failed: %m");
1415 return TDM_ERROR_OPERATION_FAILED;
1418 for (i = 0; i < props->count_props; i++)
1419 if (props->props[i] == id) {
1420 (*value).u32 = (uint)props->prop_values[i];
1424 drmModeFreeObjectProperties(props);
1426 return TDM_ERROR_NONE;
1430 vc4_output_wait_vblank(tdm_output *output, int interval, int sync,
1433 tdm_vc4_output_data *output_data = output;
1434 tdm_vc4_data *vc4_data;
1435 tdm_vc4_event_data *event_data;
1439 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1441 event_data = calloc(1, sizeof(tdm_vc4_event_data));
1443 TDM_ERR("alloc failed");
1444 return TDM_ERROR_OUT_OF_MEMORY;
1447 vc4_data = output_data->vc4_data;
1449 ret = _tdm_vc4_display_get_cur_msc(vc4_data->drm_fd, output_data->pipe,
1451 if (ret != TDM_ERROR_NONE)
1454 target_msc += interval;
1456 event_data->type = TDM_DRM_EVENT_TYPE_WAIT;
1457 event_data->output_data = output_data;
1458 event_data->user_data = user_data;
1460 ret = _tdm_vc4_display_wait_vblank(vc4_data->drm_fd, output_data->pipe,
1461 &target_msc, event_data);
1462 if (ret != TDM_ERROR_NONE)
1465 return TDM_ERROR_NONE;
1472 vc4_output_set_vblank_handler(tdm_output *output,
1473 tdm_output_vblank_handler func)
1475 tdm_vc4_output_data *output_data = output;
1477 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1478 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1480 output_data->vblank_func = func;
1482 return TDM_ERROR_NONE;
1486 _vc4_layer_add_atomic_properties(tdm_vc4_layer_data *layer_data, drmModeAtomicReqPtr request,
1487 uint32_t fb_id, uint32_t crtc_id, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h,
1488 uint32_t crtc_x, uint32_t crtc_y, uint32_t crtc_w, uint32_t crtc_h, int acquire_fence)
1490 tdm_error ret = TDM_ERROR_NONE;
1492 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.fb_id, fb_id);
1494 TDM_ERR("fail to add the atomic prop. fb_id(%u)", fb_id);
1495 return TDM_ERROR_OPERATION_FAILED;
1498 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_id, crtc_id);
1500 TDM_ERR("fail to add the atomic prop. crtc_id(%u)", crtc_id);
1501 return TDM_ERROR_OPERATION_FAILED;
1504 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_x, src_x);
1506 TDM_ERR("fail to add the atomic prop. src_x(%u)", src_x);
1507 return TDM_ERROR_OPERATION_FAILED;
1510 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_y, src_y);
1512 TDM_ERR("fail to add the atomic prop. src_y(%u)", src_y);
1513 return TDM_ERROR_OPERATION_FAILED;
1516 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_w, src_w);
1518 TDM_ERR("fail to add the atomic prop. src_w(%u)", src_w);
1519 return TDM_ERROR_OPERATION_FAILED;
1522 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_h, src_h);
1524 TDM_ERR("fail to add the atomic prop. src_h(%u)", src_h);
1525 return TDM_ERROR_OPERATION_FAILED;
1528 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_x, crtc_x);
1530 TDM_ERR("fail to add the atomic prop. crtc_x(%u)", crtc_x);
1531 return TDM_ERROR_OPERATION_FAILED;
1534 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_y, crtc_y);
1536 TDM_ERR("fail to add the atomic prop. crtc_y(%u)", crtc_y);
1537 return TDM_ERROR_OPERATION_FAILED;
1540 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_w, crtc_w);
1542 TDM_ERR("fail to add the atomic prop. crtc_w(%u)", crtc_w);
1543 return TDM_ERROR_OPERATION_FAILED;
1546 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_h, crtc_h);
1548 TDM_ERR("fail to add the atomic prop. crtc_h(%u)", crtc_h);
1549 return TDM_ERROR_OPERATION_FAILED;
1552 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.in_fence_fd, acquire_fence);
1554 TDM_ERR("fail to add the atomic prop. acquire_fence(%d)", acquire_fence);
1555 return TDM_ERROR_OPERATION_FAILED;
1558 return TDM_ERROR_NONE;
1562 _vc4_layer_make_atomic_request(tdm_vc4_layer_data *layer_data, drmModeAtomicReqPtr request)
1564 tdm_vc4_data *vc4_data = layer_data->vc4_data;
1565 tdm_vc4_output_data *output_data = layer_data->output_data;
1566 unsigned int new_src_x, new_src_w;
1567 unsigned int new_dst_x, new_dst_w;
1568 uint32_t fx, fy, fw, fh;
1570 tdm_info_layer layer_info = layer_data->info;
1571 tdm_error ret = TDM_ERROR_NONE;
1573 if (!layer_data->display_buffer_changed && !layer_data->info_changed)
1574 return TDM_ERROR_NONE;
1576 if (output_data->current_mode) {
1577 crtc_w = output_data->current_mode->hdisplay;
1578 crtc_h = output_data->current_mode->vdisplay;
1580 drmModeCrtcPtr crtc = drmModeGetCrtc(vc4_data->drm_fd, output_data->crtc_id);
1582 TDM_ERR("getting crtc failed");
1583 return TDM_ERROR_OPERATION_FAILED;
1585 crtc_w = crtc->width;
1586 crtc_h = crtc->height;
1588 TDM_ERR("getting crtc width failed");
1589 drmModeFreeCrtc(crtc);
1590 return TDM_ERROR_OPERATION_FAILED;
1592 drmModeFreeCrtc(crtc);
1595 layer_data->display_buffer_changed = 0;
1596 layer_data->info_changed = 0;
1598 if (!layer_data->display_buffer) {
1599 TDM_INFO("MakeAtomicRequest: drm_fd(%d) plane_id(%u) crtc_id(%u) off",
1600 vc4_data->drm_fd, layer_data->plane_id, output_data->crtc_id);
1602 ret = _vc4_layer_add_atomic_properties(layer_data, request, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1);
1603 if (ret != TDM_ERROR_NONE) {
1604 TDM_ERR("_vc4_layer_add_atomic_properties failed.");
1608 return TDM_ERROR_NONE;
1611 /* check hw restriction*/
1612 if (check_hw_restriction(crtc_w, crtc_h, layer_data->display_buffer->width,
1613 layer_info.src_config.pos.x,
1614 layer_info.src_config.pos.w,
1615 layer_info.dst_pos.x,
1616 layer_info.dst_pos.y,
1617 layer_info.dst_pos.w,
1618 &new_src_x, &new_src_w, &new_dst_x, &new_dst_w) != TDM_ERROR_NONE) {
1619 TDM_WRN("not going to set plane(%u)", layer_data->plane_id);
1620 return TDM_ERROR_NONE;
1623 if (layer_info.src_config.pos.x != new_src_x)
1624 TDM_DBG("src_x changed: %u => %u", layer_info.src_config.pos.x, new_src_x);
1625 if (layer_info.src_config.pos.w != new_src_w)
1626 TDM_DBG("src_w changed: %u => %u", layer_info.src_config.pos.w, new_src_w);
1627 if (layer_info.dst_pos.x != new_dst_x)
1628 TDM_DBG("dst_x changed: %u => %u", layer_info.dst_pos.x, new_dst_x);
1629 if (layer_info.dst_pos.w != new_dst_w)
1630 TDM_DBG("dst_w changed: %u => %u", layer_info.dst_pos.w, new_dst_w);
1632 /* Source values are 16.16 fixed point */
1633 fx = ((unsigned int)new_src_x) << 16;
1634 fy = ((unsigned int)layer_info.src_config.pos.y) << 16;
1635 fw = ((unsigned int)new_src_w) << 16;
1636 fh = ((unsigned int)layer_info.src_config.pos.h) << 16;
1638 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)",
1639 vc4_data->drm_fd, layer_data->plane_id, layer_data->zpos,
1640 output_data->crtc_id, layer_data->display_buffer->fb_id,
1641 new_src_x, layer_info.src_config.pos.y,
1642 new_src_w, layer_info.src_config.pos.h,
1643 layer_info.dst_pos.x, layer_info.dst_pos.y,
1644 layer_info.dst_pos.w, layer_info.dst_pos.h);
1646 ret = _vc4_layer_add_atomic_properties(layer_data, request,
1647 layer_data->display_buffer->fb_id, output_data->crtc_id,
1649 new_dst_x, layer_info.dst_pos.y,
1650 new_dst_w, layer_info.dst_pos.h, layer_data->acquire_fence);
1651 if (ret != TDM_ERROR_NONE) {
1652 TDM_ERR("MakeAtomicRequest failed");
1656 return TDM_ERROR_NONE;
1660 _vc4_output_atomic_commit(tdm_output *output, int sync, void *user_data)
1662 tdm_vc4_output_data *output_data = output;
1663 tdm_vc4_layer_data *layer_data = NULL;
1664 tdm_vc4_event_data *event_data;
1665 drmModeAtomicReqPtr request;
1668 int out_fence_fd = -1;
1670 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1672 if (!output_data->crtc_enabled || output_data->mode_changed) {
1673 ret = _tdm_vc4_display_set_crtc(output_data->vc4_data, output_data, 1);
1674 if (ret != TDM_ERROR_NONE) {
1675 TDM_ERR("fail to set crtc.");
1676 return TDM_ERROR_OPERATION_FAILED;
1679 output_data->crtc_enabled = 1;
1680 #if 0//TODO: do set crtc with atomic pageflip
1681 flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
1682 drmModeModeInfoPtr mode;
1685 mode = _tdm_vc4_display_get_mode(output_data);
1687 TDM_ERR("fail to find the drm mode.");
1688 return TDM_ERROR_OPERATION_FAILED;
1691 if (drmModeCreatePropertyBlob(output_data->vc4_data->drm_fd, mode, sizeof(*mode), &blob_id) != 0) {
1692 TDM_ERR("fail to create the Mode PropertyBlob.");
1693 return TDM_ERROR_OPERATION_FAILED;
1696 drmModeAtomicAddProperty(request, output_data->output_plane, output_data->props.plane_fb_id,
1697 layer_data->display_buffer->fb_id);
1699 output_data->crtc_enabled = 1;
1703 request = drmModeAtomicAlloc();
1705 TDM_ERR("drmModeAtomicAlloc failed.");
1706 return TDM_ERROR_OUT_OF_MEMORY;
1709 flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
1711 ret = drmModeAtomicAddProperty(request, output_data->crtc_id, output_data->atomic_props_ids.out_fence_ptr, (uintptr_t)&out_fence_fd);
1713 TDM_ERR("fail to out fence ptr error:%d", errno);
1714 drmModeAtomicFree(request);
1718 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1719 ret = _vc4_layer_make_atomic_request(layer_data, request);
1720 if (ret != TDM_ERROR_NONE) {
1721 TDM_ERR("_vc4_layer_make_atomic_request failed.");
1722 drmModeAtomicFree(request);
1727 event_data = calloc(1, sizeof(tdm_vc4_event_data));
1729 TDM_ERR("fail to alloc event_data.");
1730 drmModeAtomicFree(request);
1731 return TDM_ERROR_OUT_OF_MEMORY;
1734 event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
1735 event_data->output_data = output_data;
1736 event_data->user_data = user_data;
1738 TDM_DBG("==== Atomic Commit pipe, %u, crtc_id, %u connector_id, %u",
1739 output_data->pipe, output_data->crtc_id, output_data->connector_id);
1741 if (drmModeAtomicCommit(output_data->vc4_data->drm_fd, request, flags, event_data) < 0) {
1742 TDM_ERR("drmModeAtomicCommit failed.");
1743 drmModeAtomicFree(request);
1744 return TDM_ERROR_OPERATION_FAILED;
1747 if (output_data->commit_fence >= 0)
1748 close(output_data->commit_fence);
1750 output_data->commit_fence = out_fence_fd;
1752 drmModeAtomicFree(request);
1754 return TDM_ERROR_NONE;
1758 _vc4_output_layers_commit(tdm_output *output, int sync, void *user_data)
1760 tdm_vc4_output_data *output_data = output;
1761 tdm_vc4_data *vc4_data;
1762 tdm_vc4_layer_data *layer_data = NULL;
1764 int do_waitvblank = 1;
1766 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1768 vc4_data = output_data->vc4_data;
1770 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1771 ret = _tdm_vc4_display_commit_layer(layer_data);
1772 if (ret != TDM_ERROR_NONE)
1776 if (do_waitvblank == 1) {
1777 tdm_vc4_event_data *event_data = calloc(1, sizeof(tdm_vc4_event_data));
1781 TDM_ERR("alloc failed");
1782 return TDM_ERROR_OUT_OF_MEMORY;
1785 ret = _tdm_vc4_display_get_cur_msc(vc4_data->drm_fd, output_data->pipe,
1787 if (ret != TDM_ERROR_NONE) {
1794 event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
1795 event_data->output_data = output_data;
1796 event_data->user_data = user_data;
1798 ret = _tdm_vc4_display_wait_vblank(vc4_data->drm_fd, output_data->pipe,
1799 &target_msc, event_data);
1800 if (ret != TDM_ERROR_NONE) {
1806 return TDM_ERROR_NONE;
1810 vc4_output_commit(tdm_output *output, int sync, void *user_data)
1812 tdm_vc4_output_data *output_data = output;
1813 tdm_vc4_data *vc4_data;
1814 tdm_error ret = TDM_ERROR_NONE;
1816 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1818 vc4_data = output_data->vc4_data;
1820 /* check the atomic pageflip */
1821 if (vc4_data->has_atomic) {
1822 ret = _vc4_output_atomic_commit(output, sync, user_data);
1823 if (ret != TDM_ERROR_NONE) {
1824 TDM_ERR("_vc4_output_atomic_commit failed.");
1828 ret = _vc4_output_layers_commit(output, sync, user_data);
1829 if (ret != TDM_ERROR_NONE) {
1830 TDM_ERR("_vc4_output_layers_commit failed.");
1835 return TDM_ERROR_NONE;
1839 vc4_output_set_commit_handler(tdm_output *output,
1840 tdm_output_commit_handler func)
1842 tdm_vc4_output_data *output_data = output;
1844 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1845 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1847 output_data->commit_func = func;
1849 return TDM_ERROR_NONE;
1853 vc4_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
1855 tdm_vc4_output_data *output_data = output;
1856 tdm_vc4_data *vc4_data;
1859 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1861 if (output_data->dpms_prop_id == 0) {
1862 TDM_WRN("not support DPMS");
1863 return TDM_ERROR_OPERATION_FAILED;
1866 vc4_data = output_data->vc4_data;
1867 ret = drmModeObjectSetProperty(vc4_data->drm_fd,
1868 output_data->connector_id, DRM_MODE_OBJECT_CONNECTOR,
1869 output_data->dpms_prop_id, dpms_value);
1871 TDM_ERR("set dpms failed: %m");
1872 return TDM_ERROR_OPERATION_FAILED;
1875 return TDM_ERROR_NONE;
1879 vc4_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
1881 tdm_vc4_output_data *output_data = output;
1882 tdm_vc4_data *vc4_data;
1883 drmModeObjectPropertiesPtr props;
1886 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1887 RETURN_VAL_IF_FAIL(dpms_value, TDM_ERROR_INVALID_PARAMETER);
1889 vc4_data = output_data->vc4_data;
1890 props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->connector_id,
1891 DRM_MODE_OBJECT_CONNECTOR);
1892 if (props == NULL) {
1893 TDM_ERR("get property failed: %m");
1894 return TDM_ERROR_OPERATION_FAILED;
1897 for (i = 0; i < props->count_props; i++)
1898 if (props->props[i] == output_data->dpms_prop_id) {
1899 *dpms_value = (uint)props->prop_values[i];
1903 drmModeFreeObjectProperties(props);
1905 return TDM_ERROR_NONE;
1909 vc4_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
1911 tdm_vc4_output_data *output_data = output;
1912 tdm_error ret = TDM_ERROR_NONE;
1914 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1915 RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1917 /* create or replace the target_window when the output mode is set */
1918 if (output_data->hwc_enable) {
1919 ret = vc4_hwc_target_window_set_info(output_data->hwc_data, mode->hdisplay, mode->vdisplay);
1920 if (ret != TDM_ERROR_NONE) {
1921 TDM_ERR("set info target hwc window failed (%d)", ret);
1926 output_data->current_mode = mode;
1927 output_data->mode_changed = 1;
1929 TDM_INFO("Set the output mode: %s, %d, %d, %d, %d, %d",
1930 mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags, mode->type);
1932 ret = _tdm_vc4_display_set_crtc(output_data->vc4_data, output_data, 1);
1933 if (ret != TDM_ERROR_NONE) {
1934 TDM_ERR("fail to set crtc.");
1935 return TDM_ERROR_OPERATION_FAILED;
1938 return TDM_ERROR_NONE;
1942 vc4_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
1944 tdm_vc4_output_data *output_data = output;
1946 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1947 RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1949 *mode = output_data->current_mode;
1951 return TDM_ERROR_NONE;
1955 vc4_output_set_mirror(tdm_output *output, tdm_output *src_output, tdm_transform transform)
1957 tdm_vc4_output_data *output_data = (tdm_vc4_output_data *)output;
1958 tdm_vc4_output_data *src_output_data = (tdm_vc4_output_data *)src_output;
1960 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1961 RETURN_VAL_IF_FAIL(src_output_data, TDM_ERROR_INVALID_PARAMETER);
1963 if (!output_data->hwc_enable) {
1964 TDM_ERR("Output Mirroring is not Implemented.");
1965 return TDM_ERROR_NOT_IMPLEMENTED;
1968 output_data->mirror_src_output_data = src_output_data;
1969 src_output_data->mirror_dst_output_data = output_data;
1970 src_output_data->mirror_dst_transform = transform;
1972 TDM_INFO("Set the mirror. transform(%d)", transform);
1974 return TDM_ERROR_NONE;
1978 vc4_output_unset_mirror(tdm_output *output)
1980 tdm_vc4_output_data *output_data = (tdm_vc4_output_data *)output;
1981 tdm_vc4_output_data *src_output_data;
1983 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1985 if (!output_data->hwc_enable) {
1986 TDM_ERR("Output Mirroring is not Implemented.");
1987 return TDM_ERROR_NOT_IMPLEMENTED;
1990 src_output_data = output_data->mirror_src_output_data;
1992 src_output_data->mirror_dst_transform = TDM_TRANSFORM_NORMAL;
1993 src_output_data->mirror_dst_output_data = NULL;
1994 output_data->mirror_src_output_data = NULL;
1996 TDM_INFO("Unet the mirror.");
1998 return TDM_ERROR_NONE;
2002 vc4_output_get_hwc(tdm_output *output, tdm_error *error)
2004 tdm_vc4_hwc_data *hwc_data = NULL;
2005 tdm_vc4_output_data *output_data = output;
2006 tdm_error ret = TDM_ERROR_NONE;
2009 TDM_ERR("invalid params");
2011 *error = TDM_ERROR_INVALID_PARAMETER;
2015 if (output_data->hwc_data) {
2016 TDM_INFO("hwc_data already exists");
2018 *error = TDM_ERROR_NONE;
2019 return output_data->hwc_data;
2022 hwc_data = calloc(1, sizeof(tdm_vc4_hwc_data));
2024 TDM_ERR("alloc failed");
2026 *error = TDM_ERROR_OUT_OF_MEMORY;
2029 hwc_data->output_data = output_data;
2031 LIST_INITHEAD(&hwc_data->hwc_window_list);
2033 output_data->hwc_data = hwc_data;
2035 ret = vc4_hwc_initailize_target_window(output_data->hwc_data);
2036 if (ret != TDM_ERROR_NONE) {
2037 TDM_ERR("create target hwc window failed (%d)", ret);
2045 *error = TDM_ERROR_NONE;
2052 vc4_output_set_status_handler(tdm_output *output,
2053 tdm_output_status_handler func,
2056 tdm_vc4_output_data *output_data = output;
2058 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
2059 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
2061 output_data->status_func = func;
2062 output_data->status_user_data = user_data;
2064 return TDM_ERROR_NONE;
2068 vc4_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
2070 tdm_vc4_layer_data *layer_data = layer;
2071 tdm_vc4_data *vc4_data;
2072 drmModePlanePtr plane = NULL;
2073 drmModeObjectPropertiesPtr props = NULL;
2074 int i, format_count = 0;
2075 int primary_zpos = _get_primary_layer_zpos(layer_data->output_data);
2078 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2079 RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
2081 memset(caps, 0, sizeof(tdm_caps_layer));
2083 vc4_data = layer_data->vc4_data;
2084 plane = drmModeGetPlane(vc4_data->drm_fd, layer_data->plane_id);
2086 TDM_ERR("get plane failed: %m");
2087 ret = TDM_ERROR_OPERATION_FAILED;
2091 caps->capabilities = layer_data->capabilities;
2092 caps->zpos = layer_data->zpos;
2094 caps->format_count = plane->count_formats;
2095 caps->formats = calloc(1, sizeof(tbm_format) * caps->format_count);
2096 if (!caps->formats) {
2097 ret = TDM_ERROR_OUT_OF_MEMORY;
2098 TDM_ERR("alloc failed\n");
2102 for (i = 0; i < caps->format_count; i++) {
2103 /* Changing between RGB and YUV format for a plane doesn't work properly
2104 * only support AR24, XR24 for primary, overlay
2106 if (layer_data->zpos >= primary_zpos) {
2107 if (plane->formats[i] != DRM_FORMAT_XRGB8888 && plane->formats[i] != DRM_FORMAT_ARGB8888)
2110 /* only support NV12 for underlay */
2111 if (plane->formats[i] != DRM_FORMAT_NV12)
2115 caps->formats[format_count] = tdm_vc4_format_to_tbm_format(plane->formats[i]);
2119 caps->format_count = format_count;
2121 props = drmModeObjectGetProperties(vc4_data->drm_fd, layer_data->plane_id,
2122 DRM_MODE_OBJECT_PLANE);
2124 ret = TDM_ERROR_OPERATION_FAILED;
2125 TDM_ERR("get plane properties failed: %m\n");
2129 caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
2131 ret = TDM_ERROR_OUT_OF_MEMORY;
2132 TDM_ERR("alloc failed\n");
2136 caps->prop_count = 0;
2137 for (i = 0; i < props->count_props; i++) {
2138 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd, props->props[i]);
2141 if (!strncmp(prop->name, "type", TDM_NAME_LEN)) {
2142 drmModeFreeProperty(prop);
2145 if (!strncmp(prop->name, "zpos", TDM_NAME_LEN)) {
2146 drmModeFreeProperty(prop);
2149 snprintf(caps->props[caps->prop_count].name, TDM_NAME_LEN, "%s", prop->name);
2150 caps->props[caps->prop_count].id = props->props[i];
2152 drmModeFreeProperty(prop);
2155 drmModeFreeObjectProperties(props);
2156 drmModeFreePlane(plane);
2158 return TDM_ERROR_NONE;
2160 drmModeFreeObjectProperties(props);
2161 drmModeFreePlane(plane);
2162 free(caps->formats);
2164 memset(caps, 0, sizeof(tdm_caps_layer));
2169 vc4_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value)
2171 tdm_vc4_layer_data *layer_data = layer;
2172 tdm_vc4_data *vc4_data;
2175 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2176 RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
2178 vc4_data = layer_data->vc4_data;
2179 ret = drmModeObjectSetProperty(vc4_data->drm_fd,
2180 layer_data->plane_id, DRM_MODE_OBJECT_PLANE,
2183 TDM_ERR("set property failed: %m");
2184 return TDM_ERROR_OPERATION_FAILED;
2187 return TDM_ERROR_NONE;
2191 vc4_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value)
2193 tdm_vc4_layer_data *layer_data = layer;
2194 tdm_vc4_data *vc4_data;
2195 drmModeObjectPropertiesPtr props;
2198 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2199 RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
2200 RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
2202 vc4_data = layer_data->vc4_data;
2203 props = drmModeObjectGetProperties(vc4_data->drm_fd, layer_data->plane_id,
2204 DRM_MODE_OBJECT_PLANE);
2205 if (props == NULL) {
2206 TDM_ERR("get property failed: %m");
2207 return TDM_ERROR_OPERATION_FAILED;
2210 for (i = 0; i < props->count_props; i++)
2211 if (props->props[i] == id) {
2212 (*value).u32 = (uint)props->prop_values[i];
2216 drmModeFreeObjectProperties(props);
2218 return TDM_ERROR_NONE;
2222 vc4_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
2224 tdm_vc4_layer_data *layer_data = layer;
2226 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2227 RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
2229 layer_data->info = *info;
2230 layer_data->info_changed = 1;
2232 return TDM_ERROR_NONE;
2236 vc4_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
2238 tdm_vc4_layer_data *layer_data = layer;
2240 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2241 RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
2243 *info = layer_data->info;
2245 return TDM_ERROR_NONE;
2248 static tdm_vc4_display_buffer *
2249 _tdm_vc4_display_find_buffer(tdm_vc4_data *vc4_data, tbm_surface_h buffer)
2251 tdm_vc4_display_buffer *display_buffer = NULL;
2253 LIST_FOR_EACH_ENTRY(display_buffer, &vc4_data->buffer_list, link) {
2254 if (display_buffer->buffer == buffer)
2255 return display_buffer;
2262 _tdm_vc4_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
2264 tdm_vc4_data *vc4_data;
2265 tdm_vc4_display_buffer *display_buffer;
2266 tdm_vc4_layer_data *layer_data = NULL;
2267 tdm_vc4_output_data *output_data = NULL;
2268 char buf[256] = {0,};
2272 TDM_ERR("no user_data");
2276 TDM_ERR("no buffer");
2280 vc4_data = (tdm_vc4_data *) user_data;
2282 display_buffer = _tdm_vc4_display_find_buffer(vc4_data, buffer);
2283 if (!display_buffer) {
2284 TDM_ERR("no display_buffer");
2288 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
2289 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
2290 if (display_buffer == layer_data->display_buffer)
2291 layer_data->display_buffer = NULL;
2295 if (display_buffer->fb_id > 0) {
2296 if (drmModeRmFB(vc4_data->drm_fd, display_buffer->fb_id) < 0) {
2297 ret_tmp = strerror_r(errno, buf, sizeof(buf));
2298 TDM_ERR("rm fb failed: %d(%s,%s)\n", errno, buf, ret_tmp);
2302 TDM_DBG("destroy buffer:%p", display_buffer->buffer);
2304 LIST_DEL(&display_buffer->link);
2305 free(display_buffer);
2308 static tdm_vc4_display_buffer *
2309 _tdm_vc4_display_create_buffer(tdm_vc4_data *vc4_data, tbm_surface_h buffer, tdm_error *err)
2311 tdm_vc4_display_buffer *display_buffer = NULL;
2312 tdm_error res = TDM_ERROR_NONE;
2315 display_buffer = calloc(1, sizeof(tdm_vc4_display_buffer));
2316 if (!display_buffer) {
2317 TDM_ERR("alloc failed");
2319 *err = TDM_ERROR_OUT_OF_MEMORY;
2323 display_buffer->buffer = buffer;
2325 res = tdm_buffer_add_destroy_handler(buffer, _tdm_vc4_display_cb_destroy_buffer, vc4_data);
2326 if (res != TDM_ERROR_NONE) {
2327 TDM_ERR("add destroy handler fail");
2328 free(display_buffer);
2334 display_buffer->width = tbm_surface_get_width(buffer);
2335 display_buffer->height = tbm_surface_get_height(buffer);
2336 display_buffer->format = tbm_surface_get_format(buffer);
2337 display_buffer->count = tbm_surface_internal_get_num_bos(buffer);
2338 count = tbm_surface_internal_get_num_planes(display_buffer->format);
2339 TDM_DBG("create buffer:%p %dx%d %c%c%c%c bo_num:%d plane_num:%d",
2340 buffer, display_buffer->width, display_buffer->height,
2341 FOURCC_STR(display_buffer->format), display_buffer->count, count);
2343 for (i = 0; i < count; i++) {
2347 bo_idx = tbm_surface_internal_get_plane_bo_idx(buffer, i);
2348 bo = tbm_surface_internal_get_bo(buffer, bo_idx);
2349 display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
2351 tbm_surface_internal_get_plane_data(buffer, i, &display_buffer->size,
2352 &display_buffer->offsets[i],
2353 &display_buffer->pitches[i]);
2354 TDM_DBG(" create buffer:%p plane%d(size:%d offset:%d pitch:%d) bo%d(handle:%d)",
2355 buffer, i, display_buffer->size, display_buffer->offsets[i],
2356 display_buffer->pitches[i], bo_idx, display_buffer->handles[i]);
2359 ret = drmModeAddFB2(vc4_data->drm_fd, display_buffer->width, display_buffer->height,
2360 display_buffer->format, display_buffer->handles, display_buffer->pitches,
2361 display_buffer->offsets, &display_buffer->fb_id, 0);
2363 TDM_ERR("add fb failed: %m");
2364 free(display_buffer);
2366 *err = TDM_ERROR_OPERATION_FAILED;
2370 TDM_DBG("vc4_data->drm_fd : %d, display_buffer->fb_id:%u", vc4_data->drm_fd,
2371 display_buffer->fb_id);
2373 if (IS_RGB(display_buffer->format))
2374 display_buffer->width = display_buffer->pitches[0] >> 2;
2376 display_buffer->width = display_buffer->pitches[0];
2378 LIST_ADDTAIL(&display_buffer->link, &vc4_data->buffer_list);
2381 *err = TDM_ERROR_NONE;
2383 return display_buffer;
2387 tdm_vc4_data_destroy_buffer_list(tdm_vc4_data *vc4_data)
2389 tdm_vc4_display_buffer *b = NULL, *bb = NULL;
2391 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &vc4_data->buffer_list, link) {
2392 tdm_buffer_remove_destroy_handler(b->buffer, _tdm_vc4_display_cb_destroy_buffer, vc4_data);
2393 _tdm_vc4_display_cb_destroy_buffer(b->buffer, vc4_data);
2398 vc4_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
2400 tdm_vc4_layer_data *layer_data = layer;
2401 tdm_vc4_data *vc4_data;
2402 tdm_vc4_display_buffer *display_buffer;
2403 tdm_error err = TDM_ERROR_NONE;
2405 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2406 RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
2408 TDM_DBG("layer[%p]zpos[%d] buffer:%p", layer, layer_data->zpos, buffer);
2410 vc4_data = layer_data->vc4_data;
2411 display_buffer = _tdm_vc4_display_find_buffer(vc4_data, buffer);
2412 if (!display_buffer) {
2413 display_buffer = _tdm_vc4_display_create_buffer(vc4_data, buffer, &err);
2414 RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
2417 if (layer_data->display_buffer != display_buffer) {
2418 if (layer_data->display_buffer)
2419 tbm_surface_internal_unref(layer_data->display_buffer->buffer);
2421 layer_data->display_buffer = display_buffer;
2422 tbm_surface_internal_ref(layer_data->display_buffer->buffer);
2423 layer_data->display_buffer_changed = 1;
2426 return TDM_ERROR_NONE;
2430 vc4_layer_unset_buffer(tdm_layer *layer)
2432 tdm_vc4_layer_data *layer_data = layer;
2434 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2436 TDM_DBG("layer[%p]zpos[%d]", layer, layer_data->zpos);
2438 if (layer_data->display_buffer)
2439 tbm_surface_internal_unref(layer_data->display_buffer->buffer);
2441 layer_data->display_buffer = NULL;
2442 layer_data->display_buffer_changed = 1;
2444 return TDM_ERROR_NONE;
2447 tdm_vc4_layer_data *
2448 vc4_output_data_get_layer_data(tdm_vc4_output_data *output_data, int layer_zpos)
2450 tdm_vc4_layer_data *l = NULL;
2452 RETURN_VAL_IF_FAIL(output_data, NULL);
2454 LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link) {
2455 if (l->zpos == layer_zpos)
2463 _vc4_output_data_center_rect_get(int src_w, int src_h, int dst_w, int dst_h, tdm_pos *fit)
2467 if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0 || !fit)
2470 rh = (float) src_h / src_w;
2475 fit->h = dst_w * rh;
2477 //TDM_ERR("=###### (%d, %d, %d, %d) (%f)", fit->x, fit->y, fit->w, fit->h, rh);
2481 vc4_output_data_prepare_mirror_commit(tdm_vc4_output_data *output_data, tbm_surface_h surface)
2483 tdm_vc4_layer_data *layer_data = NULL;
2484 tdm_info_layer info;
2485 tbm_surface_info_s surf_info;
2489 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
2490 RETURN_VAL_IF_FAIL(surface, TDM_ERROR_INVALID_PARAMETER);
2492 RETURN_VAL_IF_FAIL(output_data->current_mode, TDM_ERROR_OPERATION_FAILED);
2494 layer_data = vc4_output_data_get_layer_data(output_data, 0);
2495 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_OPERATION_FAILED);
2497 memset(&dst_pos, 0, sizeof(tdm_pos));
2499 tbm_surface_get_info(surface, &surf_info);
2500 // TODO: NEED to fix the calculation of the dst_pos
2501 _vc4_output_data_center_rect_get(surf_info.width, surf_info.height,
2502 output_data->current_mode->hdisplay, output_data->current_mode->hdisplay,
2505 info.src_config.size.h = surf_info.width;
2506 info.src_config.size.v = surf_info.height;
2507 info.src_config.format = TBM_FORMAT_ARGB8888;
2508 info.src_config.pos.x = 0;
2509 info.src_config.pos.y = 0;
2510 info.src_config.pos.w = surf_info.width;
2511 info.src_config.pos.h = surf_info.height;
2512 info.dst_pos.x = dst_pos.x;
2513 info.dst_pos.y = dst_pos.y;
2514 info.dst_pos.w = output_data->current_mode->hdisplay;
2515 info.dst_pos.h = output_data->current_mode->vdisplay;
2516 info.transform = TDM_TRANSFORM_NORMAL;
2518 ret = vc4_layer_set_info((tdm_layer *)layer_data, &info);
2519 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
2521 ret = vc4_layer_set_buffer(layer_data, surface);
2522 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
2524 return TDM_ERROR_NONE;
2528 vc4_layer_set_acquire_fence(tdm_layer *layer, int acquire_fence)
2530 tdm_vc4_layer_data *layer_data = layer;
2532 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2534 TDM_DBG("layer[%p]zpos[%d] acquire_fence:%d", layer, layer_data->zpos, acquire_fence);
2536 if (layer_data->acquire_fence != acquire_fence)
2537 layer_data->acquire_fence = acquire_fence;
2539 return TDM_ERROR_NONE;