9 #define MODE_WIDTH_LIMIT 1300
10 #define MODE_HEIGHT_LIMIT 1000
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 caps->modes = calloc(1, sizeof(tdm_output_mode) * caps->mode_count);
1199 ret = TDM_ERROR_OUT_OF_MEMORY;
1200 TDM_ERR("alloc failed\n");
1204 output_data->count_drm_modes = connector->count_modes;
1205 output_data->count_modes = caps->mode_count;
1207 if (caps->mode_count != output_data->count_modes) {
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 free(output_data->vc4_modes);
1227 free(output_data->output_modes);
1229 output_data->vc4_modes = new_drm_modes;
1230 output_data->output_modes = new_output_modes;
1234 for (i = 0; i < connector->count_modes; i++) {
1235 output_data->vc4_modes[i] = connector->modes[i];
1237 if ((connector->modes[i].hdisplay > MODE_WIDTH_LIMIT) ||
1238 (connector->modes[i].vdisplay > MODE_HEIGHT_LIMIT))
1240 if (connector->modes[i].vrefresh > MODE_REFRESH_LIMIT)
1243 _tdm_vc4_display_to_tdm_mode(&output_data->vc4_modes[i],
1244 &output_data->output_modes[count]);
1245 caps->modes[count] = output_data->output_modes[count];
1249 caps->mmWidth = connector->mmWidth;
1250 caps->mmHeight = connector->mmHeight;
1251 caps->subpixel = connector->subpixel;
1253 caps->min_w = vc4_data->mode_res->min_width;
1254 caps->min_h = vc4_data->mode_res->min_height;
1255 caps->max_w = vc4_data->mode_res->max_width;
1256 caps->max_h = vc4_data->mode_res->max_height;
1257 caps->preferred_align = -1;
1259 crtc = drmModeGetCrtc(vc4_data->drm_fd, output_data->crtc_id);
1261 ret = TDM_ERROR_OPERATION_FAILED;
1262 TDM_ERR("get crtc failed: %m\n");
1266 props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->crtc_id,
1267 DRM_MODE_OBJECT_CRTC);
1269 ret = TDM_ERROR_OPERATION_FAILED;
1270 TDM_ERR("get crtc properties failed: %m\n");
1274 caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
1276 ret = TDM_ERROR_OUT_OF_MEMORY;
1277 TDM_ERR("alloc failed\n");
1281 caps->prop_count = 0;
1282 for (i = 0; i < props->count_props; i++) {
1283 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd, props->props[i]);
1286 snprintf(caps->props[caps->prop_count].name, TDM_NAME_LEN, "%s", prop->name);
1287 caps->props[caps->prop_count].id = props->props[i];
1289 drmModeFreeProperty(prop);
1292 if (output_data->hwc_enable) {
1293 caps->capabilities |= TDM_OUTPUT_CAPABILITY_HWC;
1294 caps->capabilities |= TDM_OUTPUT_CAPABILITY_MIRROR;
1297 drmModeFreeObjectProperties(props);
1298 drmModeFreeCrtc(crtc);
1299 drmModeFreeConnector(connector);
1301 return TDM_ERROR_NONE;
1303 drmModeFreeCrtc(crtc);
1304 drmModeFreeObjectProperties(props);
1305 drmModeFreeConnector(connector);
1308 memset(caps, 0, sizeof(tdm_caps_output));
1313 vc4_output_get_layers(tdm_output *output, int *count, tdm_error *error)
1315 tdm_vc4_output_data *output_data = output;
1316 tdm_vc4_layer_data *layer_data = NULL;
1321 RETURN_VAL_IF_FAIL(output_data, NULL);
1322 RETURN_VAL_IF_FAIL(count, NULL);
1325 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1328 if (output_data->hwc_enable) {
1330 ret = TDM_ERROR_NONE;
1335 ret = TDM_ERROR_NONE;
1339 /* will be freed in frontend */
1340 layers = calloc(*count, sizeof(tdm_vc4_layer_data *));
1342 TDM_ERR("failed: alloc memory");
1344 ret = TDM_ERROR_OUT_OF_MEMORY;
1349 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1350 layers[i++] = layer_data;
1353 *error = TDM_ERROR_NONE;
1363 vc4_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
1365 tdm_vc4_output_data *output_data = output;
1366 tdm_vc4_data *vc4_data;
1369 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1370 RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1372 vc4_data = output_data->vc4_data;
1373 ret = drmModeObjectSetProperty(vc4_data->drm_fd,
1374 output_data->crtc_id, DRM_MODE_OBJECT_CRTC,
1377 TDM_ERR("set property failed: %m");
1378 return TDM_ERROR_OPERATION_FAILED;
1381 return TDM_ERROR_NONE;
1385 vc4_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
1387 tdm_vc4_output_data *output_data = output;
1388 tdm_vc4_data *vc4_data;
1389 drmModeObjectPropertiesPtr props;
1392 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1393 RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1394 RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
1396 vc4_data = output_data->vc4_data;
1397 props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->crtc_id,
1398 DRM_MODE_OBJECT_CRTC);
1399 if (props == NULL) {
1400 TDM_ERR("get property failed: %m");
1401 return TDM_ERROR_OPERATION_FAILED;
1404 for (i = 0; i < props->count_props; i++)
1405 if (props->props[i] == id) {
1406 (*value).u32 = (uint)props->prop_values[i];
1410 drmModeFreeObjectProperties(props);
1412 return TDM_ERROR_NONE;
1416 vc4_output_wait_vblank(tdm_output *output, int interval, int sync,
1419 tdm_vc4_output_data *output_data = output;
1420 tdm_vc4_data *vc4_data;
1421 tdm_vc4_event_data *event_data;
1425 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1427 event_data = calloc(1, sizeof(tdm_vc4_event_data));
1429 TDM_ERR("alloc failed");
1430 return TDM_ERROR_OUT_OF_MEMORY;
1433 vc4_data = output_data->vc4_data;
1435 ret = _tdm_vc4_display_get_cur_msc(vc4_data->drm_fd, output_data->pipe,
1437 if (ret != TDM_ERROR_NONE)
1440 target_msc += interval;
1442 event_data->type = TDM_DRM_EVENT_TYPE_WAIT;
1443 event_data->output_data = output_data;
1444 event_data->user_data = user_data;
1446 ret = _tdm_vc4_display_wait_vblank(vc4_data->drm_fd, output_data->pipe,
1447 &target_msc, event_data);
1448 if (ret != TDM_ERROR_NONE)
1451 return TDM_ERROR_NONE;
1458 vc4_output_set_vblank_handler(tdm_output *output,
1459 tdm_output_vblank_handler func)
1461 tdm_vc4_output_data *output_data = output;
1463 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1464 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1466 output_data->vblank_func = func;
1468 return TDM_ERROR_NONE;
1472 _vc4_layer_add_atomic_properties(tdm_vc4_layer_data *layer_data, drmModeAtomicReqPtr request,
1473 uint32_t fb_id, uint32_t crtc_id, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h,
1474 uint32_t crtc_x, uint32_t crtc_y, uint32_t crtc_w, uint32_t crtc_h, int acquire_fence)
1476 tdm_error ret = TDM_ERROR_NONE;
1478 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.fb_id, fb_id);
1480 TDM_ERR("fail to add the atomic prop. fb_id(%u)", fb_id);
1481 return TDM_ERROR_OPERATION_FAILED;
1484 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_id, crtc_id);
1486 TDM_ERR("fail to add the atomic prop. crtc_id(%u)", crtc_id);
1487 return TDM_ERROR_OPERATION_FAILED;
1490 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_x, src_x);
1492 TDM_ERR("fail to add the atomic prop. src_x(%u)", src_x);
1493 return TDM_ERROR_OPERATION_FAILED;
1496 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_y, src_y);
1498 TDM_ERR("fail to add the atomic prop. src_y(%u)", src_y);
1499 return TDM_ERROR_OPERATION_FAILED;
1502 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_w, src_w);
1504 TDM_ERR("fail to add the atomic prop. src_w(%u)", src_w);
1505 return TDM_ERROR_OPERATION_FAILED;
1508 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_h, src_h);
1510 TDM_ERR("fail to add the atomic prop. src_h(%u)", src_h);
1511 return TDM_ERROR_OPERATION_FAILED;
1514 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_x, crtc_x);
1516 TDM_ERR("fail to add the atomic prop. crtc_x(%u)", crtc_x);
1517 return TDM_ERROR_OPERATION_FAILED;
1520 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_y, crtc_y);
1522 TDM_ERR("fail to add the atomic prop. crtc_y(%u)", crtc_y);
1523 return TDM_ERROR_OPERATION_FAILED;
1526 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_w, crtc_w);
1528 TDM_ERR("fail to add the atomic prop. crtc_w(%u)", crtc_w);
1529 return TDM_ERROR_OPERATION_FAILED;
1532 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_h, crtc_h);
1534 TDM_ERR("fail to add the atomic prop. crtc_h(%u)", crtc_h);
1535 return TDM_ERROR_OPERATION_FAILED;
1538 ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.in_fence_fd, acquire_fence);
1540 TDM_ERR("fail to add the atomic prop. acquire_fence(%d)", acquire_fence);
1541 return TDM_ERROR_OPERATION_FAILED;
1544 return TDM_ERROR_NONE;
1548 _vc4_layer_make_atomic_request(tdm_vc4_layer_data *layer_data, drmModeAtomicReqPtr request)
1550 tdm_vc4_data *vc4_data = layer_data->vc4_data;
1551 tdm_vc4_output_data *output_data = layer_data->output_data;
1552 unsigned int new_src_x, new_src_w;
1553 unsigned int new_dst_x, new_dst_w;
1554 uint32_t fx, fy, fw, fh;
1556 tdm_info_layer layer_info = layer_data->info;
1557 tdm_error ret = TDM_ERROR_NONE;
1559 if (!layer_data->display_buffer_changed && !layer_data->info_changed)
1560 return TDM_ERROR_NONE;
1562 if (output_data->current_mode) {
1563 crtc_w = output_data->current_mode->hdisplay;
1564 crtc_h = output_data->current_mode->vdisplay;
1566 drmModeCrtcPtr crtc = drmModeGetCrtc(vc4_data->drm_fd, output_data->crtc_id);
1568 TDM_ERR("getting crtc failed");
1569 return TDM_ERROR_OPERATION_FAILED;
1571 crtc_w = crtc->width;
1572 crtc_h = crtc->height;
1574 TDM_ERR("getting crtc width failed");
1575 drmModeFreeCrtc(crtc);
1576 return TDM_ERROR_OPERATION_FAILED;
1578 drmModeFreeCrtc(crtc);
1581 layer_data->display_buffer_changed = 0;
1582 layer_data->info_changed = 0;
1584 if (!layer_data->display_buffer) {
1585 TDM_INFO("MakeAtomicRequest: drm_fd(%d) plane_id(%u) crtc_id(%u) off",
1586 vc4_data->drm_fd, layer_data->plane_id, output_data->crtc_id);
1588 ret = _vc4_layer_add_atomic_properties(layer_data, request, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1);
1589 if (ret != TDM_ERROR_NONE) {
1590 TDM_ERR("_vc4_layer_add_atomic_properties failed.");
1594 return TDM_ERROR_NONE;
1597 /* check hw restriction*/
1598 if (check_hw_restriction(crtc_w, crtc_h, layer_data->display_buffer->width,
1599 layer_info.src_config.pos.x,
1600 layer_info.src_config.pos.w,
1601 layer_info.dst_pos.x,
1602 layer_info.dst_pos.y,
1603 layer_info.dst_pos.w,
1604 &new_src_x, &new_src_w, &new_dst_x, &new_dst_w) != TDM_ERROR_NONE) {
1605 TDM_WRN("not going to set plane(%u)", layer_data->plane_id);
1606 return TDM_ERROR_NONE;
1609 if (layer_info.src_config.pos.x != new_src_x)
1610 TDM_DBG("src_x changed: %u => %u", layer_info.src_config.pos.x, new_src_x);
1611 if (layer_info.src_config.pos.w != new_src_w)
1612 TDM_DBG("src_w changed: %u => %u", layer_info.src_config.pos.w, new_src_w);
1613 if (layer_info.dst_pos.x != new_dst_x)
1614 TDM_DBG("dst_x changed: %u => %u", layer_info.dst_pos.x, new_dst_x);
1615 if (layer_info.dst_pos.w != new_dst_w)
1616 TDM_DBG("dst_w changed: %u => %u", layer_info.dst_pos.w, new_dst_w);
1618 /* Source values are 16.16 fixed point */
1619 fx = ((unsigned int)new_src_x) << 16;
1620 fy = ((unsigned int)layer_info.src_config.pos.y) << 16;
1621 fw = ((unsigned int)new_src_w) << 16;
1622 fh = ((unsigned int)layer_info.src_config.pos.h) << 16;
1624 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)",
1625 vc4_data->drm_fd, layer_data->plane_id, layer_data->zpos,
1626 output_data->crtc_id, layer_data->display_buffer->fb_id,
1627 new_src_x, layer_info.src_config.pos.y,
1628 new_src_w, layer_info.src_config.pos.h,
1629 layer_info.dst_pos.x, layer_info.dst_pos.y,
1630 layer_info.dst_pos.w, layer_info.dst_pos.h);
1632 ret = _vc4_layer_add_atomic_properties(layer_data, request,
1633 layer_data->display_buffer->fb_id, output_data->crtc_id,
1635 new_dst_x, layer_info.dst_pos.y,
1636 new_dst_w, layer_info.dst_pos.h, layer_data->acquire_fence);
1637 if (ret != TDM_ERROR_NONE) {
1638 TDM_ERR("MakeAtomicRequest failed");
1642 return TDM_ERROR_NONE;
1646 _vc4_output_atomic_commit(tdm_output *output, int sync, void *user_data)
1648 tdm_vc4_output_data *output_data = output;
1649 tdm_vc4_layer_data *layer_data = NULL;
1650 tdm_vc4_event_data *event_data;
1651 drmModeAtomicReqPtr request;
1654 int out_fence_fd = -1;
1656 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1658 if (!output_data->crtc_enabled || output_data->mode_changed) {
1659 ret = _tdm_vc4_display_set_crtc(output_data->vc4_data, output_data, 1);
1660 if (ret != TDM_ERROR_NONE) {
1661 TDM_ERR("fail to set crtc.");
1662 return TDM_ERROR_OPERATION_FAILED;
1665 output_data->crtc_enabled = 1;
1666 #if 0//TODO: do set crtc with atomic pageflip
1667 flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
1668 drmModeModeInfoPtr mode;
1671 mode = _tdm_vc4_display_get_mode(output_data);
1673 TDM_ERR("fail to find the drm mode.");
1674 return TDM_ERROR_OPERATION_FAILED;
1677 if (drmModeCreatePropertyBlob(output_data->vc4_data->drm_fd, mode, sizeof(*mode), &blob_id) != 0) {
1678 TDM_ERR("fail to create the Mode PropertyBlob.");
1679 return TDM_ERROR_OPERATION_FAILED;
1682 drmModeAtomicAddProperty(request, output_data->output_plane, output_data->props.plane_fb_id,
1683 layer_data->display_buffer->fb_id);
1685 output_data->crtc_enabled = 1;
1689 request = drmModeAtomicAlloc();
1691 TDM_ERR("drmModeAtomicAlloc failed.");
1692 return TDM_ERROR_OUT_OF_MEMORY;
1695 flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
1697 ret = drmModeAtomicAddProperty(request, output_data->crtc_id, output_data->atomic_props_ids.out_fence_ptr, (uintptr_t)&out_fence_fd);
1699 TDM_ERR("fail to out fence ptr error:%d", errno);
1703 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1704 ret = _vc4_layer_make_atomic_request(layer_data, request);
1705 if (ret != TDM_ERROR_NONE) {
1706 TDM_ERR("_vc4_layer_make_atomic_request failed.");
1707 drmModeAtomicFree(request);
1712 event_data = calloc(1, sizeof(tdm_vc4_event_data));
1714 TDM_ERR("fail to alloc event_data.");
1715 drmModeAtomicFree(request);
1716 return TDM_ERROR_OUT_OF_MEMORY;
1719 event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
1720 event_data->output_data = output_data;
1721 event_data->user_data = user_data;
1723 TDM_DBG("==== Atomic Commit pipe, %u, crtc_id, %u connector_id, %u",
1724 output_data->pipe, output_data->crtc_id, output_data->connector_id);
1726 if (drmModeAtomicCommit(output_data->vc4_data->drm_fd, request, flags, event_data) < 0) {
1727 TDM_ERR("drmModeAtomicCommit failed.");
1728 drmModeAtomicFree(request);
1729 return TDM_ERROR_OPERATION_FAILED;
1732 if (output_data->commit_fence >= 0)
1733 close(output_data->commit_fence);
1735 output_data->commit_fence = out_fence_fd;
1737 drmModeAtomicFree(request);
1739 return TDM_ERROR_NONE;
1743 _vc4_output_layers_commit(tdm_output *output, int sync, void *user_data)
1745 tdm_vc4_output_data *output_data = output;
1746 tdm_vc4_data *vc4_data;
1747 tdm_vc4_layer_data *layer_data = NULL;
1749 int do_waitvblank = 1;
1751 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1753 vc4_data = output_data->vc4_data;
1755 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1756 ret = _tdm_vc4_display_commit_layer(layer_data);
1757 if (ret != TDM_ERROR_NONE)
1761 if (do_waitvblank == 1) {
1762 tdm_vc4_event_data *event_data = calloc(1, sizeof(tdm_vc4_event_data));
1766 TDM_ERR("alloc failed");
1767 return TDM_ERROR_OUT_OF_MEMORY;
1770 ret = _tdm_vc4_display_get_cur_msc(vc4_data->drm_fd, output_data->pipe,
1772 if (ret != TDM_ERROR_NONE) {
1779 event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
1780 event_data->output_data = output_data;
1781 event_data->user_data = user_data;
1783 ret = _tdm_vc4_display_wait_vblank(vc4_data->drm_fd, output_data->pipe,
1784 &target_msc, event_data);
1785 if (ret != TDM_ERROR_NONE) {
1791 return TDM_ERROR_NONE;
1795 vc4_output_commit(tdm_output *output, int sync, void *user_data)
1797 tdm_vc4_output_data *output_data = output;
1798 tdm_vc4_data *vc4_data;
1799 tdm_error ret = TDM_ERROR_NONE;
1801 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1803 vc4_data = output_data->vc4_data;
1805 /* check the atomic pageflip */
1806 if (vc4_data->has_atomic) {
1807 ret = _vc4_output_atomic_commit(output, sync, user_data);
1808 if (ret != TDM_ERROR_NONE) {
1809 TDM_ERR("_vc4_output_atomic_commit failed.");
1813 ret = _vc4_output_layers_commit(output, sync, user_data);
1814 if (ret != TDM_ERROR_NONE) {
1815 TDM_ERR("_vc4_output_layers_commit failed.");
1820 return TDM_ERROR_NONE;
1824 vc4_output_set_commit_handler(tdm_output *output,
1825 tdm_output_commit_handler func)
1827 tdm_vc4_output_data *output_data = output;
1829 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1830 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1832 output_data->commit_func = func;
1834 return TDM_ERROR_NONE;
1838 vc4_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
1840 tdm_vc4_output_data *output_data = output;
1841 tdm_vc4_data *vc4_data;
1844 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1846 if (output_data->dpms_prop_id == 0) {
1847 TDM_WRN("not support DPMS");
1848 return TDM_ERROR_OPERATION_FAILED;
1851 vc4_data = output_data->vc4_data;
1852 ret = drmModeObjectSetProperty(vc4_data->drm_fd,
1853 output_data->connector_id, DRM_MODE_OBJECT_CONNECTOR,
1854 output_data->dpms_prop_id, dpms_value);
1856 TDM_ERR("set dpms failed: %m");
1857 return TDM_ERROR_OPERATION_FAILED;
1860 return TDM_ERROR_NONE;
1864 vc4_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
1866 tdm_vc4_output_data *output_data = output;
1867 tdm_vc4_data *vc4_data;
1868 drmModeObjectPropertiesPtr props;
1871 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1872 RETURN_VAL_IF_FAIL(dpms_value, TDM_ERROR_INVALID_PARAMETER);
1874 vc4_data = output_data->vc4_data;
1875 props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->connector_id,
1876 DRM_MODE_OBJECT_CONNECTOR);
1877 if (props == NULL) {
1878 TDM_ERR("get property failed: %m");
1879 return TDM_ERROR_OPERATION_FAILED;
1882 for (i = 0; i < props->count_props; i++)
1883 if (props->props[i] == output_data->dpms_prop_id) {
1884 *dpms_value = (uint)props->prop_values[i];
1888 drmModeFreeObjectProperties(props);
1890 return TDM_ERROR_NONE;
1894 vc4_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
1896 tdm_vc4_output_data *output_data = output;
1897 tdm_error ret = TDM_ERROR_NONE;
1899 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1900 RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1902 /* create or replace the target_window when the output mode is set */
1903 if (output_data->hwc_enable) {
1904 ret = vc4_hwc_target_window_set_info(output_data->hwc_data, mode->hdisplay, mode->vdisplay);
1905 if (ret != TDM_ERROR_NONE) {
1906 TDM_ERR("set info target hwc window failed (%d)", ret);
1911 output_data->current_mode = mode;
1912 output_data->mode_changed = 1;
1914 TDM_INFO("Set the output mode: %s, %d, %d, %d, %d, %d",
1915 mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags, mode->type);
1917 ret = _tdm_vc4_display_set_crtc(output_data->vc4_data, output_data, 1);
1918 if (ret != TDM_ERROR_NONE) {
1919 TDM_ERR("fail to set crtc.");
1920 return TDM_ERROR_OPERATION_FAILED;
1923 return TDM_ERROR_NONE;
1927 vc4_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
1929 tdm_vc4_output_data *output_data = output;
1931 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1932 RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1934 *mode = output_data->current_mode;
1936 return TDM_ERROR_NONE;
1940 vc4_output_set_mirror(tdm_output *output, tdm_output *src_output, tdm_transform transform)
1942 tdm_vc4_output_data *output_data = (tdm_vc4_output_data *)output;
1943 tdm_vc4_output_data *src_output_data = (tdm_vc4_output_data *)src_output;
1945 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1946 RETURN_VAL_IF_FAIL(src_output_data, TDM_ERROR_INVALID_PARAMETER);
1948 if (!output_data->hwc_enable) {
1949 TDM_ERR("Output Mirroring is not Implemented.");
1950 return TDM_ERROR_NOT_IMPLEMENTED;
1953 output_data->mirror_src_output_data = src_output_data;
1954 src_output_data->mirror_dst_output_data = output_data;
1955 src_output_data->mirror_dst_transform = transform;
1957 TDM_INFO("Set the mirror. transform(%d)", transform);
1959 return TDM_ERROR_NONE;
1963 vc4_output_unset_mirror(tdm_output *output)
1965 tdm_vc4_output_data *output_data = (tdm_vc4_output_data *)output;
1966 tdm_vc4_output_data *src_output_data;
1968 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1970 if (!output_data->hwc_enable) {
1971 TDM_ERR("Output Mirroring is not Implemented.");
1972 return TDM_ERROR_NOT_IMPLEMENTED;
1975 src_output_data = output_data->mirror_src_output_data;
1977 src_output_data->mirror_dst_transform = TDM_TRANSFORM_NORMAL;
1978 src_output_data->mirror_dst_output_data = NULL;
1979 output_data->mirror_src_output_data = NULL;
1981 TDM_INFO("Unet the mirror.");
1983 return TDM_ERROR_NONE;
1987 vc4_output_get_hwc(tdm_output *output, tdm_error *error)
1989 tdm_vc4_hwc_data *hwc_data = NULL;
1990 tdm_vc4_output_data *output_data = output;
1991 tdm_error ret = TDM_ERROR_NONE;
1994 TDM_ERR("invalid params");
1996 *error = TDM_ERROR_INVALID_PARAMETER;
2000 if (output_data->hwc_data) {
2001 TDM_INFO("hwc_data already exists");
2003 *error = TDM_ERROR_NONE;
2004 return output_data->hwc_data;
2007 hwc_data = calloc(1, sizeof(tdm_vc4_hwc_data));
2009 TDM_ERR("alloc failed");
2011 *error = TDM_ERROR_OUT_OF_MEMORY;
2014 hwc_data->output_data = output_data;
2016 LIST_INITHEAD(&hwc_data->hwc_window_list);
2018 output_data->hwc_data = hwc_data;
2020 ret = vc4_hwc_initailize_target_window(output_data->hwc_data);
2021 if (ret != TDM_ERROR_NONE) {
2022 TDM_ERR("create target hwc window failed (%d)", ret);
2030 *error = TDM_ERROR_NONE;
2037 vc4_output_set_status_handler(tdm_output *output,
2038 tdm_output_status_handler func,
2041 tdm_vc4_output_data *output_data = output;
2043 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
2044 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
2046 output_data->status_func = func;
2047 output_data->status_user_data = user_data;
2049 return TDM_ERROR_NONE;
2053 vc4_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
2055 tdm_vc4_layer_data *layer_data = layer;
2056 tdm_vc4_data *vc4_data;
2057 drmModePlanePtr plane = NULL;
2058 drmModeObjectPropertiesPtr props = NULL;
2059 int i, format_count = 0;
2060 int primary_zpos = _get_primary_layer_zpos(layer_data->output_data);
2063 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2064 RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
2066 memset(caps, 0, sizeof(tdm_caps_layer));
2068 vc4_data = layer_data->vc4_data;
2069 plane = drmModeGetPlane(vc4_data->drm_fd, layer_data->plane_id);
2071 TDM_ERR("get plane failed: %m");
2072 ret = TDM_ERROR_OPERATION_FAILED;
2076 caps->capabilities = layer_data->capabilities;
2077 caps->zpos = layer_data->zpos;
2079 caps->format_count = plane->count_formats;
2080 caps->formats = calloc(1, sizeof(tbm_format) * caps->format_count);
2081 if (!caps->formats) {
2082 ret = TDM_ERROR_OUT_OF_MEMORY;
2083 TDM_ERR("alloc failed\n");
2087 for (i = 0; i < caps->format_count; i++) {
2088 /* Changing between RGB and YUV format for a plane doesn't work properly
2089 * only support AR24, XR24 for primary, overlay
2091 if (layer_data->zpos >= primary_zpos) {
2092 if (plane->formats[i] != DRM_FORMAT_XRGB8888 && plane->formats[i] != DRM_FORMAT_ARGB8888)
2095 /* only support NV12 for underlay */
2096 if (plane->formats[i] != DRM_FORMAT_NV12)
2100 caps->formats[format_count] = tdm_vc4_format_to_tbm_format(plane->formats[i]);
2104 caps->format_count = format_count;
2106 props = drmModeObjectGetProperties(vc4_data->drm_fd, layer_data->plane_id,
2107 DRM_MODE_OBJECT_PLANE);
2109 ret = TDM_ERROR_OPERATION_FAILED;
2110 TDM_ERR("get plane properties failed: %m\n");
2114 caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
2116 ret = TDM_ERROR_OUT_OF_MEMORY;
2117 TDM_ERR("alloc failed\n");
2121 caps->prop_count = 0;
2122 for (i = 0; i < props->count_props; i++) {
2123 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd, props->props[i]);
2126 if (!strncmp(prop->name, "type", TDM_NAME_LEN)) {
2127 drmModeFreeProperty(prop);
2130 if (!strncmp(prop->name, "zpos", TDM_NAME_LEN)) {
2131 drmModeFreeProperty(prop);
2134 snprintf(caps->props[caps->prop_count].name, TDM_NAME_LEN, "%s", prop->name);
2135 caps->props[caps->prop_count].id = props->props[i];
2137 drmModeFreeProperty(prop);
2140 drmModeFreeObjectProperties(props);
2141 drmModeFreePlane(plane);
2143 return TDM_ERROR_NONE;
2145 drmModeFreeObjectProperties(props);
2146 drmModeFreePlane(plane);
2147 free(caps->formats);
2149 memset(caps, 0, sizeof(tdm_caps_layer));
2154 vc4_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value)
2156 tdm_vc4_layer_data *layer_data = layer;
2157 tdm_vc4_data *vc4_data;
2160 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2161 RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
2163 vc4_data = layer_data->vc4_data;
2164 ret = drmModeObjectSetProperty(vc4_data->drm_fd,
2165 layer_data->plane_id, DRM_MODE_OBJECT_PLANE,
2168 TDM_ERR("set property failed: %m");
2169 return TDM_ERROR_OPERATION_FAILED;
2172 return TDM_ERROR_NONE;
2176 vc4_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value)
2178 tdm_vc4_layer_data *layer_data = layer;
2179 tdm_vc4_data *vc4_data;
2180 drmModeObjectPropertiesPtr props;
2183 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2184 RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
2185 RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
2187 vc4_data = layer_data->vc4_data;
2188 props = drmModeObjectGetProperties(vc4_data->drm_fd, layer_data->plane_id,
2189 DRM_MODE_OBJECT_PLANE);
2190 if (props == NULL) {
2191 TDM_ERR("get property failed: %m");
2192 return TDM_ERROR_OPERATION_FAILED;
2195 for (i = 0; i < props->count_props; i++)
2196 if (props->props[i] == id) {
2197 (*value).u32 = (uint)props->prop_values[i];
2201 drmModeFreeObjectProperties(props);
2203 return TDM_ERROR_NONE;
2207 vc4_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
2209 tdm_vc4_layer_data *layer_data = layer;
2211 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2212 RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
2214 layer_data->info = *info;
2215 layer_data->info_changed = 1;
2217 return TDM_ERROR_NONE;
2221 vc4_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
2223 tdm_vc4_layer_data *layer_data = layer;
2225 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2226 RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
2228 *info = layer_data->info;
2230 return TDM_ERROR_NONE;
2233 static tdm_vc4_display_buffer *
2234 _tdm_vc4_display_find_buffer(tdm_vc4_data *vc4_data, tbm_surface_h buffer)
2236 tdm_vc4_display_buffer *display_buffer = NULL;
2238 LIST_FOR_EACH_ENTRY(display_buffer, &vc4_data->buffer_list, link) {
2239 if (display_buffer->buffer == buffer)
2240 return display_buffer;
2247 _tdm_vc4_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
2249 tdm_vc4_data *vc4_data;
2250 tdm_vc4_display_buffer *display_buffer;
2251 tdm_vc4_layer_data *layer_data = NULL;
2252 tdm_vc4_output_data *output_data = NULL;
2253 char buf[256] = {0,};
2257 TDM_ERR("no user_data");
2261 TDM_ERR("no buffer");
2265 vc4_data = (tdm_vc4_data *) user_data;
2267 display_buffer = _tdm_vc4_display_find_buffer(vc4_data, buffer);
2268 if (!display_buffer) {
2269 TDM_ERR("no display_buffer");
2273 LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
2274 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
2275 if (display_buffer == layer_data->display_buffer)
2276 layer_data->display_buffer = NULL;
2280 if (display_buffer->fb_id > 0) {
2281 if (drmModeRmFB(vc4_data->drm_fd, display_buffer->fb_id) < 0) {
2282 ret_tmp = strerror_r(errno, buf, sizeof(buf));
2283 TDM_ERR("rm fb failed: %d(%s,%s)\n", errno, buf, ret_tmp);
2287 TDM_DBG("destroy buffer:%p", display_buffer->buffer);
2289 LIST_DEL(&display_buffer->link);
2290 free(display_buffer);
2293 static tdm_vc4_display_buffer *
2294 _tdm_vc4_display_create_buffer(tdm_vc4_data *vc4_data, tbm_surface_h buffer, tdm_error *err)
2296 tdm_vc4_display_buffer *display_buffer = NULL;
2297 tdm_error res = TDM_ERROR_NONE;
2300 display_buffer = calloc(1, sizeof(tdm_vc4_display_buffer));
2301 if (!display_buffer) {
2302 TDM_ERR("alloc failed");
2304 *err = TDM_ERROR_OUT_OF_MEMORY;
2308 display_buffer->buffer = buffer;
2310 res = tdm_buffer_add_destroy_handler(buffer, _tdm_vc4_display_cb_destroy_buffer, vc4_data);
2311 if (res != TDM_ERROR_NONE) {
2312 TDM_ERR("add destroy handler fail");
2313 free(display_buffer);
2319 display_buffer->width = tbm_surface_get_width(buffer);
2320 display_buffer->height = tbm_surface_get_height(buffer);
2321 display_buffer->format = tbm_surface_get_format(buffer);
2322 display_buffer->count = tbm_surface_internal_get_num_bos(buffer);
2323 count = tbm_surface_internal_get_num_planes(display_buffer->format);
2324 TDM_DBG("create buffer:%p %dx%d %c%c%c%c bo_num:%d plane_num:%d",
2325 buffer, display_buffer->width, display_buffer->height,
2326 FOURCC_STR(display_buffer->format), display_buffer->count, count);
2328 for (i = 0; i < count; i++) {
2332 bo_idx = tbm_surface_internal_get_plane_bo_idx(buffer, i);
2333 bo = tbm_surface_internal_get_bo(buffer, bo_idx);
2334 display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
2336 tbm_surface_internal_get_plane_data(buffer, i, &display_buffer->size,
2337 &display_buffer->offsets[i],
2338 &display_buffer->pitches[i]);
2339 TDM_DBG(" create buffer:%p plane%d(size:%d offset:%d pitch:%d) bo%d(handle:%d)",
2340 buffer, i, display_buffer->size, display_buffer->offsets[i],
2341 display_buffer->pitches[i], bo_idx, display_buffer->handles[i]);
2344 ret = drmModeAddFB2(vc4_data->drm_fd, display_buffer->width, display_buffer->height,
2345 display_buffer->format, display_buffer->handles, display_buffer->pitches,
2346 display_buffer->offsets, &display_buffer->fb_id, 0);
2348 TDM_ERR("add fb failed: %m");
2349 free(display_buffer);
2351 *err = TDM_ERROR_OPERATION_FAILED;
2355 TDM_DBG("vc4_data->drm_fd : %d, display_buffer->fb_id:%u", vc4_data->drm_fd,
2356 display_buffer->fb_id);
2358 if (IS_RGB(display_buffer->format))
2359 display_buffer->width = display_buffer->pitches[0] >> 2;
2361 display_buffer->width = display_buffer->pitches[0];
2363 LIST_ADDTAIL(&display_buffer->link, &vc4_data->buffer_list);
2366 *err = TDM_ERROR_NONE;
2368 return display_buffer;
2372 tdm_vc4_data_destroy_buffer_list(tdm_vc4_data *vc4_data)
2374 tdm_vc4_display_buffer *b = NULL, *bb = NULL;
2376 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &vc4_data->buffer_list, link) {
2377 tdm_buffer_remove_destroy_handler(b->buffer, _tdm_vc4_display_cb_destroy_buffer, vc4_data);
2378 _tdm_vc4_display_cb_destroy_buffer(b->buffer, vc4_data);
2383 vc4_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
2385 tdm_vc4_layer_data *layer_data = layer;
2386 tdm_vc4_data *vc4_data;
2387 tdm_vc4_display_buffer *display_buffer;
2388 tdm_error err = TDM_ERROR_NONE;
2390 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2391 RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
2393 TDM_DBG("layer[%p]zpos[%d] buffer:%p", layer, layer_data->zpos, buffer);
2395 vc4_data = layer_data->vc4_data;
2396 display_buffer = _tdm_vc4_display_find_buffer(vc4_data, buffer);
2397 if (!display_buffer) {
2398 display_buffer = _tdm_vc4_display_create_buffer(vc4_data, buffer, &err);
2399 RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
2402 if (layer_data->display_buffer != display_buffer) {
2403 if (layer_data->display_buffer)
2404 tbm_surface_internal_unref(layer_data->display_buffer->buffer);
2406 layer_data->display_buffer = display_buffer;
2407 tbm_surface_internal_ref(layer_data->display_buffer->buffer);
2408 layer_data->display_buffer_changed = 1;
2411 return TDM_ERROR_NONE;
2415 vc4_layer_unset_buffer(tdm_layer *layer)
2417 tdm_vc4_layer_data *layer_data = layer;
2419 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2421 TDM_DBG("layer[%p]zpos[%d]", layer, layer_data->zpos);
2423 if (layer_data->display_buffer)
2424 tbm_surface_internal_unref(layer_data->display_buffer->buffer);
2426 layer_data->display_buffer = NULL;
2427 layer_data->display_buffer_changed = 1;
2429 return TDM_ERROR_NONE;
2432 tdm_vc4_layer_data *
2433 vc4_output_data_get_layer_data(tdm_vc4_output_data *output_data, int layer_zpos)
2435 tdm_vc4_layer_data *l = NULL;
2437 RETURN_VAL_IF_FAIL(output_data, NULL);
2439 LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link) {
2440 if (l->zpos == layer_zpos)
2448 _vc4_output_data_center_rect_get(int src_w, int src_h, int dst_w, int dst_h, tdm_pos *fit)
2452 if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0 || !fit)
2455 rh = (float) src_h / src_w;
2460 fit->h = dst_w * rh;
2462 //TDM_ERR("=###### (%d, %d, %d, %d) (%f)", fit->x, fit->y, fit->w, fit->h, rh);
2466 vc4_output_data_prepare_mirror_commit(tdm_vc4_output_data *output_data, tbm_surface_h surface)
2468 tdm_vc4_layer_data *layer_data = NULL;
2469 tdm_info_layer info;
2470 tbm_surface_info_s surf_info;
2474 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
2475 RETURN_VAL_IF_FAIL(surface, TDM_ERROR_INVALID_PARAMETER);
2477 RETURN_VAL_IF_FAIL(output_data->current_mode, TDM_ERROR_OPERATION_FAILED);
2479 layer_data = vc4_output_data_get_layer_data(output_data, 0);
2480 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_OPERATION_FAILED);
2482 memset(&dst_pos, 0, sizeof(tdm_pos));
2484 tbm_surface_get_info(surface, &surf_info);
2485 // TODO: NEED to fix the calculation of the dst_pos
2486 _vc4_output_data_center_rect_get(surf_info.width, surf_info.height,
2487 output_data->current_mode->hdisplay, output_data->current_mode->hdisplay,
2490 info.src_config.size.h = surf_info.width;
2491 info.src_config.size.v = surf_info.height;
2492 info.src_config.format = TBM_FORMAT_ARGB8888;
2493 info.src_config.pos.x = 0;
2494 info.src_config.pos.y = 0;
2495 info.src_config.pos.w = surf_info.width;
2496 info.src_config.pos.h = surf_info.height;
2497 info.dst_pos.x = dst_pos.x;
2498 info.dst_pos.y = dst_pos.y;
2499 info.dst_pos.w = output_data->current_mode->hdisplay;
2500 info.dst_pos.h = output_data->current_mode->vdisplay;
2501 info.transform = TDM_TRANSFORM_NORMAL;
2503 ret = vc4_layer_set_info((tdm_layer *)layer_data, &info);
2504 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
2506 ret = vc4_layer_set_buffer(layer_data, surface);
2507 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
2509 return TDM_ERROR_NONE;
2513 vc4_layer_set_acquire_fence(tdm_layer *layer, int acquire_fence)
2515 tdm_vc4_layer_data *layer_data = layer;
2517 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
2519 TDM_DBG("layer[%p]zpos[%d] acquire_fence:%d", layer, layer_data->zpos, acquire_fence);
2521 if (layer_data->acquire_fence != acquire_fence)
2522 layer_data->acquire_fence = acquire_fence;
2524 return TDM_ERROR_NONE;