1 /**************************************************************************
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
7 Contact: SooChan Lim <sc1.lim@samsung.com>
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 **************************************************************************/
35 #include <drm_fourcc.h>
36 #include <tdm_helper.h>
39 #include "tdm_drm_pp.h"
41 static drmModeModeInfoPtr
42 _tdm_drm_display_get_mode(tdm_drm_output_data *output_data)
46 if (!output_data->current_mode) {
47 TDM_ERR("no output_data->current_mode");
51 for (i = 0; i < output_data->count_modes; i++) {
52 drmModeModeInfoPtr drm_mode = &output_data->drm_modes[i];
53 if ((drm_mode->hdisplay == output_data->current_mode->hdisplay) &&
54 (drm_mode->vdisplay == output_data->current_mode->vdisplay) &&
55 (drm_mode->vrefresh == output_data->current_mode->vrefresh) &&
56 (drm_mode->flags == output_data->current_mode->flags) &&
57 (drm_mode->type == output_data->current_mode->type) &&
58 !(strncmp(drm_mode->name, output_data->current_mode->name, TDM_NAME_LEN)))
66 _tdm_drm_display_to_tdm_mode(drmModeModeInfoPtr drm_mode,
67 tdm_output_mode *tdm_mode)
69 tdm_mode->clock = drm_mode->clock;
70 tdm_mode->hdisplay = drm_mode->hdisplay;
71 tdm_mode->hsync_start = drm_mode->hsync_start;
72 tdm_mode->hsync_end = drm_mode->hsync_end;
73 tdm_mode->htotal = drm_mode->htotal;
74 tdm_mode->hskew = drm_mode->hskew;
75 tdm_mode->vdisplay = drm_mode->vdisplay;
76 tdm_mode->vsync_start = drm_mode->vsync_start;
77 tdm_mode->vsync_end = drm_mode->vsync_end;
78 tdm_mode->vtotal = drm_mode->vtotal;
79 tdm_mode->vscan = drm_mode->vscan;
80 tdm_mode->vrefresh = drm_mode->vrefresh;
81 tdm_mode->flags = drm_mode->flags;
82 tdm_mode->type = drm_mode->type;
83 snprintf(tdm_mode->name, TDM_NAME_LEN, "%s", drm_mode->name);
87 _tdm_drm_display_get_cur_msc(int fd, int pipe, uint *msc)
91 vbl.request.type = DRM_VBLANK_RELATIVE;
93 vbl.request.type |= DRM_VBLANK_SECONDARY;
95 vbl.request.sequence = 0;
96 if (drmWaitVBlank(fd, &vbl)) {
97 TDM_ERR("get vblank counter failed: %m");
99 return TDM_ERROR_OPERATION_FAILED;
102 *msc = vbl.reply.sequence;
104 return TDM_ERROR_NONE;
108 _tdm_drm_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data)
112 vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
114 vbl.request.type |= DRM_VBLANK_SECONDARY;
116 vbl.request.sequence = *target_msc;
117 vbl.request.signal = (unsigned long)(uintptr_t)data;
119 if (drmWaitVBlank(fd, &vbl)) {
121 TDM_ERR("wait vblank failed: %m");
122 return TDM_ERROR_OPERATION_FAILED;
125 *target_msc = vbl.reply.sequence;
127 return TDM_ERROR_NONE;
131 _tdm_drm_output_update_status(tdm_drm_output_data *output_data,
132 tdm_output_conn_status status)
134 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
136 if (output_data->status == status)
137 return TDM_ERROR_NONE;
139 output_data->status = status;
141 if (output_data->status_func)
142 output_data->status_func(output_data, status,
143 output_data->status_user_data);
145 return TDM_ERROR_NONE;
149 _tdm_drm_display_commit_primary_layer(tdm_drm_layer_data *layer_data,
150 void *user_data, int *do_waitvblank)
152 tdm_drm_data *drm_data = layer_data->drm_data;
153 tdm_drm_output_data *output_data = layer_data->output_data;
155 if (output_data->mode_changed && layer_data->display_buffer_changed) {
156 drmModeModeInfoPtr mode;
158 if (!layer_data->display_buffer) {
159 TDM_ERR("primary layer should have a buffer for modestting");
160 return TDM_ERROR_BAD_REQUEST;
163 output_data->mode_changed = 0;
164 layer_data->display_buffer_changed = 0;
165 layer_data->info_changed = 0;
167 mode = _tdm_drm_display_get_mode(output_data);
169 TDM_ERR("couldn't find proper mode");
170 return TDM_ERROR_BAD_REQUEST;
173 if (drmModeSetCrtc(drm_data->drm_fd, output_data->crtc_id,
174 layer_data->display_buffer->fb_id, 0, 0,
175 &output_data->connector_id, 1, mode)) {
176 TDM_ERR("set crtc failed: %m");
177 return TDM_ERROR_OPERATION_FAILED;
180 _tdm_drm_output_update_status(output_data, TDM_OUTPUT_CONN_STATUS_MODE_SETTED);
183 return TDM_ERROR_NONE;
184 } else if (layer_data->display_buffer_changed) {
185 layer_data->display_buffer_changed = 0;
187 if (!layer_data->display_buffer) {
188 if (drmModeSetCrtc(drm_data->drm_fd, output_data->crtc_id,
189 0, 0, 0, NULL, 0, NULL)) {
190 TDM_ERR("unset crtc failed: %m");
191 return TDM_ERROR_OPERATION_FAILED;
194 if (output_data->status == TDM_OUTPUT_CONN_STATUS_MODE_SETTED)
195 _tdm_drm_output_update_status(output_data, TDM_OUTPUT_CONN_STATUS_CONNECTED);
199 tdm_drm_event_data *event_data = calloc(1, sizeof(tdm_drm_event_data));
202 TDM_ERR("alloc failed");
203 return TDM_ERROR_OUT_OF_MEMORY;
206 event_data->type = TDM_DRM_EVENT_TYPE_PAGEFLIP;
207 event_data->output_data = output_data;
208 event_data->user_data = user_data;
209 if (drmModePageFlip(drm_data->drm_fd, output_data->crtc_id,
210 layer_data->display_buffer->fb_id, DRM_MODE_PAGE_FLIP_EVENT, event_data)) {
211 TDM_ERR("pageflip failed: %m");
213 return TDM_ERROR_OPERATION_FAILED;
219 return TDM_ERROR_NONE;
223 _tdm_drm_display_commit_layer(tdm_drm_layer_data *layer_data)
225 tdm_drm_data *drm_data = layer_data->drm_data;
226 tdm_drm_output_data *output_data = layer_data->output_data;
227 uint32_t fx, fy, fw, fh;
230 if (!layer_data->display_buffer_changed && !layer_data->info_changed)
231 return TDM_ERROR_NONE;
233 if (output_data->current_mode)
234 crtc_w = output_data->current_mode->hdisplay;
236 drmModeCrtcPtr crtc = drmModeGetCrtc(drm_data->drm_fd, output_data->crtc_id);
238 TDM_ERR("getting crtc failed");
239 return TDM_ERROR_OPERATION_FAILED;
241 crtc_w = crtc->width;
243 TDM_ERR("getting crtc width failed");
244 drmModeFreeCrtc(crtc);
245 return TDM_ERROR_OPERATION_FAILED;
247 drmModeFreeCrtc(crtc);
250 layer_data->display_buffer_changed = 0;
251 layer_data->info_changed = 0;
253 if (!layer_data->display_buffer) {
254 if (drmModeSetPlane(drm_data->drm_fd, layer_data->plane_id,
255 output_data->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
256 TDM_ERR("unset plane(%d) filed: %m", layer_data->plane_id);
258 return TDM_ERROR_NONE;
261 /* Source values are 16.16 fixed point */
262 fx = ((unsigned int)layer_data->info.src_config.pos.x) << 16;
263 fy = ((unsigned int)layer_data->info.src_config.pos.y) << 16;
264 fw = ((unsigned int)layer_data->info.src_config.pos.w) << 16;
265 fh = ((unsigned int)layer_data->info.src_config.pos.h) << 16;
267 if (drmModeSetPlane(drm_data->drm_fd, layer_data->plane_id,
268 output_data->crtc_id, layer_data->display_buffer->fb_id, 0,
269 layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
270 layer_data->info.dst_pos.w, layer_data->info.dst_pos.h,
271 fx, fy, fw, fh) < 0) {
272 TDM_ERR("set plane(%d) failed: %m", layer_data->plane_id);
273 return TDM_ERROR_OPERATION_FAILED;
276 TDM_INFO("plane(%d) crtc(%d) pos(%d) on: fb(%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n",
277 layer_data->plane_id, output_data->crtc_id, layer_data->zpos,
278 layer_data->display_buffer->fb_id,
279 layer_data->info.src_config.pos.x, layer_data->info.src_config.pos.y,
280 layer_data->info.src_config.pos.w, layer_data->info.src_config.pos.h,
281 layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
282 layer_data->info.dst_pos.w, layer_data->info.dst_pos.h);
284 return TDM_ERROR_NONE;
288 _tdm_drm_display_cb_event(int fd, unsigned int sequence,
289 unsigned int tv_sec, unsigned int tv_usec,
292 tdm_drm_event_data *event_data = user_data;
293 tdm_drm_output_data *output_data;
294 tdm_drm_hwc_data *hwc_data;
297 TDM_ERR("no event data");
301 output_data = event_data->output_data;
303 switch (event_data->type) {
304 case TDM_DRM_EVENT_TYPE_PAGEFLIP:
305 if (output_data->hwc_enable) {
306 hwc_data = output_data->hwc_data;
308 TDM_ERR("no hwc_data");
312 if (hwc_data->commit_func)
313 hwc_data->commit_func(hwc_data, sequence,
315 event_data->user_data);
317 if (output_data->commit_func)
318 output_data->commit_func(output_data, sequence, tv_sec, tv_usec,
319 event_data->user_data);
322 case TDM_DRM_EVENT_TYPE_WAIT:
323 if (output_data->vblank_func)
324 output_data->vblank_func(output_data, sequence, tv_sec, tv_usec,
325 event_data->user_data);
327 case TDM_DRM_EVENT_TYPE_COMMIT:
328 if (output_data->hwc_enable) {
329 hwc_data = output_data->hwc_data;
331 TDM_ERR("no hwc_data");
335 if (hwc_data->commit_func)
336 hwc_data->commit_func(hwc_data, sequence,
338 event_data->user_data);
340 if (output_data->commit_func)
341 output_data->commit_func(output_data, sequence,
343 event_data->user_data);
354 _tdm_drm_display_create_layer_list(tdm_drm_data *drm_data)
356 tdm_drm_output_data *output_data = NULL;
359 if (LIST_IS_EMPTY(&drm_data->output_list)) {
360 TDM_ERR("no output");
361 return TDM_ERROR_OPERATION_FAILED;
364 /* The TDM drm backend only support one output. */
365 LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link) {
369 if (drm_data->plane_res->count_planes == 0) {
370 TDM_ERR("no layer error");
371 return TDM_ERROR_OPERATION_FAILED;
374 for (i = 0; i < drm_data->plane_res->count_planes; i++) {
375 tdm_drm_layer_data *layer_data;
376 drmModePlanePtr plane;
378 plane = drmModeGetPlane(drm_data->drm_fd, drm_data->plane_res->planes[i]);
384 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
385 drmModeFreePlane(plane);
389 layer_data = calloc(1, sizeof(tdm_drm_layer_data));
391 TDM_ERR("alloc failed");
392 drmModeFreePlane(plane);
396 layer_data->drm_data = drm_data;
397 layer_data->output_data = output_data;
398 layer_data->plane_id = drm_data->plane_res->planes[i];
400 layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
401 TDM_LAYER_CAPABILITY_GRAPHIC;
402 output_data->primary_layer = layer_data;
404 TDM_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) capabilities(%x)",
405 layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
406 layer_data->capabilities);
408 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
410 drmModeFreePlane(plane);
412 /* can't take care of other planes for various hardware devices */
416 return TDM_ERROR_NONE;
419 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
422 _tdm_drm_display_get_property(tdm_drm_data *drm_data,
423 unsigned int obj_id, unsigned int obj_type,
424 const char *name, unsigned int *value,
427 drmModeObjectPropertiesPtr props = NULL;
430 props = drmModeObjectGetProperties(drm_data->drm_fd, obj_id, obj_type);
432 return TDM_ERROR_OPERATION_FAILED;
434 for (i = 0; i < props->count_props; i++) {
435 drmModePropertyPtr prop = drmModeGetProperty(drm_data->drm_fd,
441 if (!strcmp(prop->name, name)) {
443 *is_immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
445 *value = (unsigned int)props->prop_values[i];
446 drmModeFreeProperty(prop);
447 drmModeFreeObjectProperties(props);
448 return TDM_ERROR_NONE;
451 drmModeFreeProperty(prop);
453 drmModeFreeObjectProperties(props);
454 TDM_DBG("coundn't find '%s' property", name);
455 return TDM_ERROR_OPERATION_FAILED;
459 _tdm_drm_display_create_layer_list_type(tdm_drm_data *drm_data)
461 tdm_drm_output_data *output_data = NULL;
462 drmModePlanePtr *planes = NULL;
463 unsigned int *types = NULL;
464 unsigned int type = 0;
465 int plane_cnt, primary_cnt, ovl_cnt, cursor_cnt;
466 int opos_next, cpos_next;
470 if (LIST_IS_EMPTY(&drm_data->output_list)) {
471 TDM_ERR("no output");
472 return TDM_ERROR_OPERATION_FAILED;
475 /* The TDM drm backend only support one output. */
476 LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link) {
480 ret = _tdm_drm_display_get_property(drm_data,
481 drm_data->plane_res->planes[0],
482 DRM_MODE_OBJECT_PLANE, "type", &type,
484 if (ret != TDM_ERROR_NONE) {
485 TDM_ERR("plane doesn't have 'type' property. Call a fallback function");
487 /* if a plane doesn't have "type" property, we call a fallback function
490 return _tdm_drm_display_create_layer_list(drm_data);
493 planes = calloc(drm_data->plane_res->count_planes, sizeof(drmModePlanePtr));
495 TDM_ERR("alloc failed");
499 types = calloc(drm_data->plane_res->count_planes, sizeof(unsigned int));
501 TDM_ERR("alloc failed");
506 for (i = 0; i < drm_data->plane_res->count_planes; i++) {
507 drmModePlanePtr plane;
509 plane = drmModeGetPlane(drm_data->drm_fd, drm_data->plane_res->planes[i]);
511 TDM_ERR("no plane(%d)", drm_data->plane_res->planes[i]);
515 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
516 drmModeFreePlane(plane);
520 ret = _tdm_drm_display_get_property(drm_data,
521 drm_data->plane_res->planes[i],
522 DRM_MODE_OBJECT_PLANE, "type", &type,
524 if (ret != TDM_ERROR_NONE) {
525 drmModeFreePlane(plane);
526 TDM_ERR("plane(%d) doesn't have 'type' info",
527 drm_data->plane_res->planes[i]);
531 /* The TDM drm backend only support a primary layer. */
532 if (type != DRM_PLANE_TYPE_PRIMARY) {
533 TDM_INFO("The TDM drm backend only support a primary layer. plane(%d) type(%d)",
534 plane->plane_id, type);
535 drmModeFreePlane(plane);
539 planes[plane_cnt] = plane;
540 types[plane_cnt] = type;
544 primary_cnt = ovl_cnt = cursor_cnt = 0;
545 for (i = 0; i < plane_cnt; i++) {
546 if (types[i] == DRM_PLANE_TYPE_CURSOR)
548 else if (types[i] == DRM_PLANE_TYPE_OVERLAY)
550 else if (types[i] == DRM_PLANE_TYPE_PRIMARY)
553 TDM_ERR("invalid type(%d)", types[i]);
556 if (primary_cnt != 1) {
557 TDM_ERR("primary layer count(%d) should be one", primary_cnt);
563 for (i = 0; i < plane_cnt; i++) {
564 tdm_drm_layer_data *layer_data;
566 layer_data = calloc(1, sizeof(tdm_drm_layer_data));
568 TDM_ERR("alloc failed");
572 layer_data->drm_data = drm_data;
573 layer_data->output_data = output_data;
574 layer_data->plane_id = planes[i]->plane_id;
576 if (types[i] == DRM_PLANE_TYPE_CURSOR) {
577 layer_data->capabilities = TDM_LAYER_CAPABILITY_CURSOR |
578 TDM_LAYER_CAPABILITY_GRAPHIC;
579 layer_data->zpos = cpos_next++;
580 } else if (types[i] == DRM_PLANE_TYPE_OVERLAY) {
581 layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY |
582 TDM_LAYER_CAPABILITY_GRAPHIC;
583 layer_data->zpos = opos_next++;
584 } else if (types[i] == DRM_PLANE_TYPE_PRIMARY) {
585 layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
586 TDM_LAYER_CAPABILITY_GRAPHIC;
587 layer_data->zpos = 0;
588 output_data->primary_layer = layer_data;
594 TDM_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) zpos(%d) capabilities(%x)",
595 layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
596 layer_data->zpos, layer_data->capabilities);
598 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
601 for (i = 0; i < plane_cnt; i++)
603 drmModeFreePlane(planes[i]);
608 return TDM_ERROR_NONE;
612 for (i = 0; i < drm_data->plane_res->count_planes; i++)
614 drmModeFreePlane(planes[i]);
620 return TDM_ERROR_OPERATION_FAILED;
625 tdm_drm_display_create_layer_list(tdm_drm_data *drm_data)
627 tdm_drm_output_data *output_data = NULL;
630 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
631 if (drm_data->has_universal_plane)
632 ret = _tdm_drm_display_create_layer_list_type(drm_data);
635 ret = _tdm_drm_display_create_layer_list(drm_data);
637 if (ret != TDM_ERROR_NONE)
640 LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link) {
641 if (!output_data->primary_layer) {
642 TDM_ERR("output(%d) no primary layer", output_data->pipe);
643 return TDM_ERROR_OPERATION_FAILED;
647 return TDM_ERROR_NONE;
651 tdm_drm_display_destroy_output_list(tdm_drm_data *drm_data)
653 tdm_drm_output_data *o = NULL, *oo = NULL;
654 tdm_drm_hwc_data *hwc_data = NULL;
656 if (LIST_IS_EMPTY(&drm_data->output_list))
659 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &drm_data->output_list, link) {
660 hwc_data = o->hwc_data;
661 if (hwc_data && hwc_data->target_hwc_window)
662 drm_hwc_window_destroy(hwc_data->target_hwc_window);
665 if (!LIST_IS_EMPTY(&o->layer_list)) {
666 tdm_drm_layer_data *l = NULL, *ll = NULL;
667 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
669 if (l->display_buffer)
670 tbm_surface_internal_unref(l->display_buffer->buffer);
675 free(o->output_modes);
681 tdm_drm_display_update_output_status(tdm_drm_data *drm_data)
683 tdm_drm_output_data *output_data = NULL;
685 if (LIST_IS_EMPTY(&drm_data->output_list))
688 LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link) {
689 drmModeConnectorPtr connector;
690 tdm_output_conn_status new_status;
692 connector = drmModeGetConnector(drm_data->drm_fd,
693 output_data->connector_id);
695 TDM_ERR("no connector: %d", output_data->connector_id);
699 if (connector->connection == DRM_MODE_CONNECTED)
700 new_status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
702 new_status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
704 _tdm_drm_output_update_status(output_data, new_status);
706 drmModeFreeConnector(connector);
711 tdm_drm_display_create_output_list(tdm_drm_data *drm_data)
713 tdm_drm_output_data *output_data;
717 drmModeConnectorPtr connector;
718 drmModeEncoderPtr encoder;
720 int crtc_id = 0, c, j;
722 RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&drm_data->output_list),
723 TDM_ERROR_OPERATION_FAILED);
725 /* check if there is a connected output */
726 for (i = 0; i < drm_data->mode_res->count_connectors; i++) {
727 connector = drmModeGetConnector(drm_data->drm_fd,
728 drm_data->mode_res->connectors[i]);
730 TDM_ERR("no connector");
731 return TDM_ERROR_OPERATION_FAILED;
734 /* The TDM drm backend considers only 1 connector because it is the TDM
735 * reference backend and can't take care of all hardware devices.
736 * To support various connectors, planes and crtcs, the new TDM backend
737 * should be implemented.
739 if (connector->connection == DRM_MODE_CONNECTED) {
741 drmModeFreeConnector(connector);
744 drmModeFreeConnector(connector);
747 /* use the first connecoct_id if there is not connector which is connected */
751 /* The TDM drm backend considers only 1 connector because it is the TDM
752 * reference backend and can't take care of all hardware devices.
753 * To support various connectors, planes and crtcs, the new TDM backend
754 * should be implemented.
756 connector = drmModeGetConnector(drm_data->drm_fd,
757 drm_data->mode_res->connectors[conn_idx]);
759 TDM_ERR("no connector");
760 ret = TDM_ERROR_OPERATION_FAILED;
764 if (connector->count_encoders != 1) {
765 TDM_ERR("too many encoders: %d", connector->count_encoders);
766 drmModeFreeConnector(connector);
767 ret = TDM_ERROR_OPERATION_FAILED;
771 encoder = drmModeGetEncoder(drm_data->drm_fd, connector->encoders[0]);
773 TDM_ERR("no encoder");
774 drmModeFreeConnector(connector);
775 ret = TDM_ERROR_OPERATION_FAILED;
779 for (c = 0; c < drm_data->mode_res->count_crtcs; c++) {
780 if (allocated & (1 << c))
783 if ((encoder->possible_crtcs & (1 << c)) == 0)
786 crtc_id = drm_data->mode_res->crtcs[c];
787 allocated |= (1 << c);
792 TDM_ERR("no possible crtc");
793 drmModeFreeConnector(connector);
794 drmModeFreeEncoder(encoder);
795 ret = TDM_ERROR_OPERATION_FAILED;
799 output_data = calloc(1, sizeof(tdm_drm_output_data));
801 TDM_ERR("alloc failed");
802 drmModeFreeConnector(connector);
803 drmModeFreeEncoder(encoder);
804 ret = TDM_ERROR_OUT_OF_MEMORY;
808 LIST_INITHEAD(&output_data->layer_list);
810 output_data->drm_data = drm_data;
811 output_data->connector_id = drm_data->mode_res->connectors[conn_idx];
812 output_data->encoder_id = encoder->encoder_id;
813 output_data->crtc_id = crtc_id;
814 output_data->pipe = c;
815 output_data->connector_type = connector->connector_type;
816 output_data->connector_type_id = connector->connector_type_id;
818 if (connector->connection == DRM_MODE_CONNECTED)
819 output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
821 output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
823 for (j = 0; j < connector->count_props; j++) {
824 drmModePropertyPtr prop = drmModeGetProperty(drm_data->drm_fd,
825 connector->props[j]);
828 if (!strcmp(prop->name, "DPMS")) {
829 output_data->dpms_prop_id = connector->props[j];
830 drmModeFreeProperty(prop);
833 drmModeFreeProperty(prop);
836 if (output_data->dpms_prop_id == 0)
837 TDM_WRN("not support DPMS");
839 output_data->count_modes = connector->count_modes;
840 output_data->drm_modes = calloc(connector->count_modes,
841 sizeof(drmModeModeInfo));
842 if (!output_data->drm_modes) {
843 TDM_ERR("alloc failed");
845 drmModeFreeConnector(connector);
846 drmModeFreeEncoder(encoder);
847 ret = TDM_ERROR_OUT_OF_MEMORY;
850 output_data->output_modes = calloc(connector->count_modes,
851 sizeof(tdm_output_mode));
852 if (!output_data->output_modes) {
853 TDM_ERR("alloc failed");
854 free(output_data->drm_modes);
856 drmModeFreeConnector(connector);
857 drmModeFreeEncoder(encoder);
858 ret = TDM_ERROR_OUT_OF_MEMORY;
861 for (j = 0; j < connector->count_modes; j++) {
862 output_data->drm_modes[j] = connector->modes[j];
863 _tdm_drm_display_to_tdm_mode(&output_data->drm_modes[j],
864 &output_data->output_modes[j]);
867 if (drm_data->hwc_mode)
868 output_data->hwc_enable = 1;
870 LIST_ADDTAIL(&output_data->link, &drm_data->output_list);
872 TDM_DBG("output_data(%p) connector_id(%d:%d:%d-%d) encoder_id(%d) crtc_id(%d) pipe(%d) dpms_id(%d)",
873 output_data, output_data->connector_id, output_data->status,
874 output_data->connector_type,
875 output_data->connector_type_id, output_data->encoder_id, output_data->crtc_id,
876 output_data->pipe, output_data->dpms_prop_id);
878 drmModeFreeEncoder(encoder);
879 drmModeFreeConnector(connector);
881 TDM_DBG("output count: %d", drm_data->mode_res->count_connectors);
883 return TDM_ERROR_NONE;
885 tdm_drm_display_destroy_output_list(drm_data);
890 drm_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps)
892 RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
894 caps->max_layer_count = -1; /* not defined */
896 return TDM_ERROR_NONE;
900 drm_display_get_pp_capability(tdm_backend_data *bdata, tdm_caps_pp *caps)
902 return tdm_drm_pp_get_capability(bdata, caps);
906 drm_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error)
908 tdm_drm_data *drm_data = bdata;
909 tdm_drm_output_data *output_data = NULL;
910 tdm_output **outputs;
914 RETURN_VAL_IF_FAIL(drm_data, NULL);
915 RETURN_VAL_IF_FAIL(count, NULL);
918 LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link)
922 ret = TDM_ERROR_NONE;
926 /* will be freed in frontend */
927 outputs = calloc(*count, sizeof(tdm_drm_output_data *));
929 TDM_ERR("failed: alloc memory");
931 ret = TDM_ERROR_OUT_OF_MEMORY;
936 LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link)
937 outputs[i++] = output_data;
940 *error = TDM_ERROR_NONE;
950 drm_display_get_fd(tdm_backend_data *bdata, int *fd)
952 tdm_drm_data *drm_data = bdata;
954 RETURN_VAL_IF_FAIL(drm_data, TDM_ERROR_INVALID_PARAMETER);
955 RETURN_VAL_IF_FAIL(fd, TDM_ERROR_INVALID_PARAMETER);
957 *fd = drm_data->drm_fd;
959 return TDM_ERROR_NONE;
963 drm_display_handle_events(tdm_backend_data *bdata)
965 tdm_drm_data *drm_data = bdata;
968 RETURN_VAL_IF_FAIL(drm_data, TDM_ERROR_INVALID_PARAMETER);
970 memset(&ctx, 0, sizeof(drmEventContext));
972 ctx.version = DRM_EVENT_CONTEXT_VERSION;
973 ctx.page_flip_handler = _tdm_drm_display_cb_event;
974 ctx.vblank_handler = _tdm_drm_display_cb_event;
976 drmHandleEvent(drm_data->drm_fd, &ctx);
978 return TDM_ERROR_NONE;
982 drm_display_create_pp(tdm_backend_data *bdata, tdm_error *error)
984 tdm_drm_data *drm_data = bdata;
986 RETURN_VAL_IF_FAIL(drm_data, NULL);
988 return tdm_drm_pp_create(drm_data, error);
992 drm_output_get_capability(tdm_output *output, tdm_caps_output *caps)
994 tdm_drm_output_data *output_data = output;
995 tdm_drm_data *drm_data;
996 drmModeConnectorPtr connector = NULL;
997 drmModeCrtcPtr crtc = NULL;
998 drmModeObjectPropertiesPtr props = NULL;
1002 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1003 RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1005 memset(caps, 0, sizeof(tdm_caps_output));
1007 drm_data = output_data->drm_data;
1009 snprintf(caps->maker, TDM_NAME_LEN, "unknown");
1010 snprintf(caps->model, TDM_NAME_LEN, "unknown");
1011 snprintf(caps->name, TDM_NAME_LEN, "unknown");
1013 caps->status = output_data->status;
1014 caps->type = output_data->connector_type;
1015 caps->type_id = output_data->connector_type_id;
1017 connector = drmModeGetConnector(drm_data->drm_fd, output_data->connector_id);
1018 RETURN_VAL_IF_FAIL(connector, TDM_ERROR_OPERATION_FAILED);
1020 caps->mode_count = connector->count_modes;
1021 caps->modes = calloc(1, sizeof(tdm_output_mode) * caps->mode_count);
1023 ret = TDM_ERROR_OUT_OF_MEMORY;
1024 TDM_ERR("alloc failed\n");
1027 for (i = 0; i < caps->mode_count; i++)
1028 caps->modes[i] = output_data->output_modes[i];
1030 caps->mmWidth = connector->mmWidth;
1031 caps->mmHeight = connector->mmHeight;
1032 caps->subpixel = connector->subpixel;
1034 caps->min_w = drm_data->mode_res->min_width;
1035 caps->min_h = drm_data->mode_res->min_height;
1036 caps->max_w = drm_data->mode_res->max_width;
1037 caps->max_h = drm_data->mode_res->max_height;
1038 caps->preferred_align = -1;
1040 crtc = drmModeGetCrtc(drm_data->drm_fd, output_data->crtc_id);
1042 ret = TDM_ERROR_OPERATION_FAILED;
1043 TDM_ERR("get crtc failed: %m\n");
1047 props = drmModeObjectGetProperties(drm_data->drm_fd, output_data->crtc_id,
1048 DRM_MODE_OBJECT_CRTC);
1050 ret = TDM_ERROR_OPERATION_FAILED;
1051 TDM_ERR("get crtc properties failed: %m\n");
1055 caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
1057 ret = TDM_ERROR_OUT_OF_MEMORY;
1058 TDM_ERR("alloc failed\n");
1062 caps->prop_count = 0;
1063 for (i = 0; i < props->count_props; i++) {
1064 drmModePropertyPtr prop = drmModeGetProperty(drm_data->drm_fd, props->props[i]);
1067 snprintf(caps->props[caps->prop_count].name, TDM_NAME_LEN, "%s", prop->name);
1068 caps->props[caps->prop_count].id = props->props[i];
1070 drmModeFreeProperty(prop);
1073 if (output_data->hwc_enable)
1074 caps->capabilities |= TDM_OUTPUT_CAPABILITY_HWC;
1076 drmModeFreeObjectProperties(props);
1077 drmModeFreeCrtc(crtc);
1078 drmModeFreeConnector(connector);
1080 return TDM_ERROR_NONE;
1082 drmModeFreeCrtc(crtc);
1083 drmModeFreeObjectProperties(props);
1084 drmModeFreeConnector(connector);
1087 memset(caps, 0, sizeof(tdm_caps_output));
1092 drm_output_get_layers(tdm_output *output, int *count, tdm_error *error)
1094 tdm_drm_output_data *output_data = output;
1095 tdm_drm_layer_data *layer_data = NULL;
1100 RETURN_VAL_IF_FAIL(output_data, NULL);
1101 RETURN_VAL_IF_FAIL(count, NULL);
1104 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1107 if (output_data->hwc_enable) {
1109 ret = TDM_ERROR_NONE;
1114 ret = TDM_ERROR_NONE;
1118 /* will be freed in frontend */
1119 layers = calloc(*count, sizeof(tdm_drm_layer_data *));
1121 TDM_ERR("failed: alloc memory");
1123 ret = TDM_ERROR_OUT_OF_MEMORY;
1128 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1129 layers[i++] = layer_data;
1132 *error = TDM_ERROR_NONE;
1142 drm_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
1144 tdm_drm_output_data *output_data = output;
1145 tdm_drm_data *drm_data;
1148 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1149 RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1151 drm_data = output_data->drm_data;
1152 ret = drmModeObjectSetProperty(drm_data->drm_fd,
1153 output_data->crtc_id, DRM_MODE_OBJECT_CRTC,
1156 TDM_ERR("set property failed: %m");
1157 return TDM_ERROR_OPERATION_FAILED;
1160 return TDM_ERROR_NONE;
1164 drm_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
1166 tdm_drm_output_data *output_data = output;
1167 tdm_drm_data *drm_data;
1168 drmModeObjectPropertiesPtr props;
1171 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1172 RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1173 RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
1175 drm_data = output_data->drm_data;
1176 props = drmModeObjectGetProperties(drm_data->drm_fd, output_data->crtc_id,
1177 DRM_MODE_OBJECT_CRTC);
1178 if (props == NULL) {
1179 TDM_ERR("get property failed: %m");
1180 return TDM_ERROR_OPERATION_FAILED;
1183 for (i = 0; i < props->count_props; i++)
1184 if (props->props[i] == id) {
1185 (*value).u32 = (uint)props->prop_values[i];
1189 drmModeFreeObjectProperties(props);
1191 return TDM_ERROR_NONE;
1195 drm_output_wait_vblank(tdm_output *output, int interval, int sync,
1198 tdm_drm_output_data *output_data = output;
1199 tdm_drm_data *drm_data;
1200 tdm_drm_event_data *event_data;
1204 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1206 event_data = calloc(1, sizeof(tdm_drm_event_data));
1208 TDM_ERR("alloc failed");
1209 return TDM_ERROR_OUT_OF_MEMORY;
1212 drm_data = output_data->drm_data;
1214 ret = _tdm_drm_display_get_cur_msc(drm_data->drm_fd, output_data->pipe,
1216 if (ret != TDM_ERROR_NONE)
1219 target_msc += interval;
1221 event_data->type = TDM_DRM_EVENT_TYPE_WAIT;
1222 event_data->output_data = output_data;
1223 event_data->user_data = user_data;
1225 ret = _tdm_drm_display_wait_vblank(drm_data->drm_fd, output_data->pipe,
1226 &target_msc, event_data);
1227 if (ret != TDM_ERROR_NONE)
1230 return TDM_ERROR_NONE;
1237 drm_output_set_vblank_handler(tdm_output *output,
1238 tdm_output_vblank_handler func)
1240 tdm_drm_output_data *output_data = output;
1242 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1243 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1245 output_data->vblank_func = func;
1247 return TDM_ERROR_NONE;
1251 drm_output_commit(tdm_output *output, int sync, void *user_data)
1253 tdm_drm_output_data *output_data = output;
1254 tdm_drm_data *drm_data;
1255 tdm_drm_layer_data *layer_data = NULL;
1257 int do_waitvblank = 1;
1259 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1261 drm_data = output_data->drm_data;
1263 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1264 if (layer_data == output_data->primary_layer) {
1265 ret = _tdm_drm_display_commit_primary_layer(layer_data, user_data,
1267 if (ret != TDM_ERROR_NONE)
1270 ret = _tdm_drm_display_commit_layer(layer_data);
1271 if (ret != TDM_ERROR_NONE)
1276 if (do_waitvblank == 1) {
1277 tdm_drm_event_data *event_data = calloc(1, sizeof(tdm_drm_event_data));
1281 TDM_ERR("alloc failed");
1282 return TDM_ERROR_OUT_OF_MEMORY;
1285 ret = _tdm_drm_display_get_cur_msc(drm_data->drm_fd, output_data->pipe,
1287 if (ret != TDM_ERROR_NONE) {
1294 event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
1295 event_data->output_data = output_data;
1296 event_data->user_data = user_data;
1298 ret = _tdm_drm_display_wait_vblank(drm_data->drm_fd, output_data->pipe,
1299 &target_msc, event_data);
1300 if (ret != TDM_ERROR_NONE) {
1306 return TDM_ERROR_NONE;
1310 drm_output_set_commit_handler(tdm_output *output,
1311 tdm_output_commit_handler func)
1313 tdm_drm_output_data *output_data = output;
1315 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1316 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1318 output_data->commit_func = func;
1320 return TDM_ERROR_NONE;
1324 drm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
1326 tdm_drm_output_data *output_data = output;
1327 tdm_drm_data *drm_data;
1330 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1332 if (output_data->dpms_prop_id == 0) {
1333 TDM_WRN("not support DPMS");
1334 return TDM_ERROR_OPERATION_FAILED;
1337 drm_data = output_data->drm_data;
1338 ret = drmModeObjectSetProperty(drm_data->drm_fd,
1339 output_data->connector_id, DRM_MODE_OBJECT_CONNECTOR,
1340 output_data->dpms_prop_id, dpms_value);
1342 TDM_ERR("set dpms failed: %m");
1343 return TDM_ERROR_OPERATION_FAILED;
1346 output_data->current_dpms = dpms_value;
1348 return TDM_ERROR_NONE;
1352 drm_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
1354 tdm_drm_output_data *output_data = output;
1355 tdm_drm_data *drm_data;
1356 drmModeObjectPropertiesPtr props;
1359 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1360 RETURN_VAL_IF_FAIL(dpms_value, TDM_ERROR_INVALID_PARAMETER);
1362 drm_data = output_data->drm_data;
1363 props = drmModeObjectGetProperties(drm_data->drm_fd, output_data->connector_id,
1364 DRM_MODE_OBJECT_CONNECTOR);
1365 if (props == NULL) {
1366 TDM_ERR("get property failed: %m");
1367 return TDM_ERROR_OPERATION_FAILED;
1370 for (i = 0; i < props->count_props; i++)
1371 if (props->props[i] == output_data->dpms_prop_id) {
1372 *dpms_value = (uint)props->prop_values[i];
1376 drmModeFreeObjectProperties(props);
1378 return TDM_ERROR_NONE;
1382 drm_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
1384 tdm_drm_output_data *output_data = output;
1385 tdm_error ret = TDM_ERROR_NONE;
1387 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1388 RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1390 /* create or replace the target_window when the output mode is set */
1391 if (output_data->hwc_enable) {
1392 ret = drm_hwc_target_window_set_info(output_data->hwc_data, mode->hdisplay, mode->vdisplay);
1393 if (ret != TDM_ERROR_NONE) {
1394 TDM_ERR("set info target hwc window failed (%d)", ret);
1399 output_data->current_mode = mode;
1400 output_data->mode_changed = 1;
1402 return TDM_ERROR_NONE;
1406 drm_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
1408 tdm_drm_output_data *output_data = output;
1410 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1411 RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1413 *mode = output_data->current_mode;
1415 return TDM_ERROR_NONE;
1419 drm_output_get_hwc(tdm_output *output, tdm_error *error)
1421 tdm_drm_hwc_data *hwc_data = NULL;
1422 tdm_drm_output_data *output_data = output;
1423 tdm_error ret = TDM_ERROR_NONE;
1426 TDM_ERR("invalid params");
1428 *error = TDM_ERROR_INVALID_PARAMETER;
1432 if (output_data->hwc_data) {
1433 TDM_INFO("hwc_data already exists");
1435 *error = TDM_ERROR_NONE;
1436 return output_data->hwc_data;
1439 hwc_data = calloc(1, sizeof(tdm_drm_hwc_data));
1441 TDM_ERR("alloc failed");
1443 *error = TDM_ERROR_OUT_OF_MEMORY;
1446 hwc_data->output_data = output_data;
1448 LIST_INITHEAD(&hwc_data->hwc_window_list);
1450 output_data->hwc_data = hwc_data;
1452 ret = drm_hwc_initailize_target_window(output_data->hwc_data);
1453 if (ret != TDM_ERROR_NONE) {
1454 TDM_ERR("create target hwc window failed (%d)", ret);
1462 *error = TDM_ERROR_NONE;
1468 drm_output_set_status_handler(tdm_output *output,
1469 tdm_output_status_handler func,
1472 tdm_drm_output_data *output_data = output;
1474 RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1475 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1477 output_data->status_func = func;
1478 output_data->status_user_data = user_data;
1480 return TDM_ERROR_NONE;
1484 drm_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
1486 tdm_drm_layer_data *layer_data = layer;
1487 tdm_drm_data *drm_data;
1488 drmModePlanePtr plane = NULL;
1489 drmModeObjectPropertiesPtr props = NULL;
1490 int i, format_count = 0;
1493 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1494 RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1496 memset(caps, 0, sizeof(tdm_caps_layer));
1498 drm_data = layer_data->drm_data;
1499 plane = drmModeGetPlane(drm_data->drm_fd, layer_data->plane_id);
1501 TDM_ERR("get plane failed: %m");
1502 ret = TDM_ERROR_OPERATION_FAILED;
1506 caps->capabilities = layer_data->capabilities;
1507 caps->zpos = layer_data->zpos; /* if VIDEO layer, zpos is -1 */
1509 caps->format_count = plane->count_formats;
1510 caps->formats = calloc(1, sizeof(tbm_format) * caps->format_count);
1511 if (!caps->formats) {
1512 ret = TDM_ERROR_OUT_OF_MEMORY;
1513 TDM_ERR("alloc failed\n");
1517 for (i = 0; i < caps->format_count; i++) {
1518 /* TODO: kernel reports wrong formats */
1519 if (plane->formats[i] != DRM_FORMAT_XRGB8888 &&
1520 plane->formats[i] != DRM_FORMAT_ARGB8888) {
1521 TDM_WRN("plane(%d) zpos(%d) %c%c%c%c skipped",
1522 layer_data->plane_id, layer_data->zpos, FOURCC_STR(plane->formats[i]));
1525 caps->formats[format_count] = tdm_drm_format_to_tbm_format(plane->formats[i]);
1529 caps->format_count = format_count;
1531 props = drmModeObjectGetProperties(drm_data->drm_fd, layer_data->plane_id,
1532 DRM_MODE_OBJECT_PLANE);
1534 ret = TDM_ERROR_OPERATION_FAILED;
1535 TDM_ERR("get plane properties failed: %m\n");
1539 caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
1541 ret = TDM_ERROR_OUT_OF_MEMORY;
1542 TDM_ERR("alloc failed\n");
1546 caps->prop_count = 0;
1547 for (i = 0; i < props->count_props; i++) {
1548 drmModePropertyPtr prop = drmModeGetProperty(drm_data->drm_fd, props->props[i]);
1551 if (!strncmp(prop->name, "type", TDM_NAME_LEN)) {
1552 drmModeFreeProperty(prop);
1555 if (!strncmp(prop->name, "zpos", TDM_NAME_LEN)) {
1556 drmModeFreeProperty(prop);
1559 snprintf(caps->props[caps->prop_count].name, TDM_NAME_LEN, "%s", prop->name);
1560 caps->props[caps->prop_count].id = props->props[i];
1562 drmModeFreeProperty(prop);
1565 drmModeFreeObjectProperties(props);
1566 drmModeFreePlane(plane);
1568 return TDM_ERROR_NONE;
1570 drmModeFreeObjectProperties(props);
1571 drmModeFreePlane(plane);
1572 free(caps->formats);
1574 memset(caps, 0, sizeof(tdm_caps_layer));
1579 drm_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value)
1581 tdm_drm_layer_data *layer_data = layer;
1582 tdm_drm_data *drm_data;
1585 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1586 RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
1588 drm_data = layer_data->drm_data;
1589 ret = drmModeObjectSetProperty(drm_data->drm_fd,
1590 layer_data->plane_id, DRM_MODE_OBJECT_PLANE,
1593 TDM_ERR("set property failed: %m");
1594 return TDM_ERROR_OPERATION_FAILED;
1597 return TDM_ERROR_NONE;
1601 drm_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value)
1603 tdm_drm_layer_data *layer_data = layer;
1604 tdm_drm_data *drm_data;
1605 drmModeObjectPropertiesPtr props;
1608 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1609 RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
1610 RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
1612 drm_data = layer_data->drm_data;
1613 props = drmModeObjectGetProperties(drm_data->drm_fd, layer_data->plane_id,
1614 DRM_MODE_OBJECT_PLANE);
1615 if (props == NULL) {
1616 TDM_ERR("get property failed: %m");
1617 return TDM_ERROR_OPERATION_FAILED;
1620 for (i = 0; i < props->count_props; i++)
1621 if (props->props[i] == id) {
1622 (*value).u32 = (uint)props->prop_values[i];
1626 drmModeFreeObjectProperties(props);
1628 return TDM_ERROR_NONE;
1632 drm_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
1634 tdm_drm_layer_data *layer_data = layer;
1636 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1637 RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
1639 layer_data->info = *info;
1640 layer_data->info_changed = 1;
1642 return TDM_ERROR_NONE;
1646 drm_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
1648 tdm_drm_layer_data *layer_data = layer;
1650 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1651 RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
1653 *info = layer_data->info;
1655 return TDM_ERROR_NONE;
1658 static tdm_drm_display_buffer *
1659 _tdm_drm_display_find_buffer(tdm_drm_data *drm_data, tbm_surface_h buffer)
1661 tdm_drm_display_buffer *display_buffer = NULL;
1663 LIST_FOR_EACH_ENTRY(display_buffer, &drm_data->buffer_list, link) {
1664 if (display_buffer->buffer == buffer)
1665 return display_buffer;
1672 _tdm_drm_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
1674 tdm_drm_data *drm_data;
1675 tdm_drm_display_buffer *display_buffer;
1676 tdm_drm_layer_data *layer_data = NULL;
1677 tdm_drm_output_data *output_data = NULL;
1678 char buf[256] = {0,};
1682 TDM_ERR("no user_data");
1686 TDM_ERR("no buffer");
1690 drm_data = (tdm_drm_data *) user_data;
1692 display_buffer = _tdm_drm_display_find_buffer(drm_data, buffer);
1693 if (!display_buffer) {
1694 TDM_ERR("no display_buffer");
1698 LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link) {
1699 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1700 if (display_buffer == layer_data->display_buffer)
1701 layer_data->display_buffer = NULL;
1705 if (display_buffer->fb_id > 0) {
1706 if (drmModeRmFB(drm_data->drm_fd, display_buffer->fb_id) < 0) {
1707 ret_tmp = strerror_r(errno, buf, sizeof(buf));
1708 TDM_ERR("rm fb failed: %d(%s,%s)\n", errno, buf, ret_tmp);
1712 TDM_DBG("destroy buffer:%p", display_buffer->buffer);
1714 LIST_DEL(&display_buffer->link);
1715 free(display_buffer);
1718 static tdm_drm_display_buffer *
1719 _tdm_drm_display_create_buffer(tdm_drm_data *drm_data, tbm_surface_h buffer, tdm_error *err)
1721 tdm_drm_display_buffer *display_buffer = NULL;
1722 tdm_error res = TDM_ERROR_NONE;
1725 display_buffer = calloc(1, sizeof(tdm_drm_display_buffer));
1726 if (!display_buffer) {
1727 TDM_ERR("alloc failed");
1729 *err = TDM_ERROR_OUT_OF_MEMORY;
1733 display_buffer->buffer = buffer;
1735 res = tdm_buffer_add_destroy_handler(buffer, _tdm_drm_display_cb_destroy_buffer, drm_data);
1736 if (res != TDM_ERROR_NONE) {
1737 TDM_ERR("add destroy handler fail");
1738 free(display_buffer);
1744 display_buffer->width = tbm_surface_get_width(buffer);
1745 display_buffer->height = tbm_surface_get_height(buffer);
1746 display_buffer->format = tbm_surface_get_format(buffer);
1747 display_buffer->count = tbm_surface_internal_get_num_bos(buffer);
1748 count = tbm_surface_internal_get_num_planes(display_buffer->format);
1749 TDM_DBG("create buffer:%p %dx%d %c%c%c%c bo_num:%d plane_num:%d",
1750 buffer, display_buffer->width, display_buffer->height,
1751 FOURCC_STR(display_buffer->format), display_buffer->count, count);
1753 for (i = 0; i < count; i++) {
1757 bo_idx = tbm_surface_internal_get_plane_bo_idx(buffer, i);
1758 bo = tbm_surface_internal_get_bo(buffer, bo_idx);
1759 display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
1761 tbm_surface_internal_get_plane_data(buffer, i, &display_buffer->size,
1762 &display_buffer->offsets[i],
1763 &display_buffer->pitches[i]);
1764 TDM_DBG(" create buffer:%p plane%d(size:%d offset:%d pitch:%d) bo%d(handle:%d)",
1765 buffer, i, display_buffer->size, display_buffer->offsets[i],
1766 display_buffer->pitches[i], bo_idx, display_buffer->handles[i]);
1769 ret = drmModeAddFB2(drm_data->drm_fd, display_buffer->width, display_buffer->height,
1770 display_buffer->format, display_buffer->handles, display_buffer->pitches,
1771 display_buffer->offsets, &display_buffer->fb_id, 0);
1773 TDM_ERR("add fb failed: %m");
1774 free(display_buffer);
1776 *err = TDM_ERROR_OPERATION_FAILED;
1780 TDM_DBG("drm_data->drm_fd : %d, display_buffer->fb_id:%u", drm_data->drm_fd,
1781 display_buffer->fb_id);
1783 if (IS_RGB(display_buffer->format))
1784 display_buffer->width = display_buffer->pitches[0] >> 2;
1786 display_buffer->width = display_buffer->pitches[0];
1788 LIST_ADDTAIL(&display_buffer->link, &drm_data->buffer_list);
1791 *err = TDM_ERROR_NONE;
1793 return display_buffer;
1797 tdm_drm_data_destroy_buffer_list(tdm_drm_data *drm_data)
1799 tdm_drm_display_buffer *b = NULL, *bb = NULL;
1801 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &drm_data->buffer_list, link) {
1802 tdm_buffer_remove_destroy_handler(b->buffer, _tdm_drm_display_cb_destroy_buffer, drm_data);
1803 _tdm_drm_display_cb_destroy_buffer(b->buffer, drm_data);
1808 drm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
1810 tdm_drm_layer_data *layer_data = layer;
1811 tdm_drm_data *drm_data;
1812 tdm_drm_display_buffer *display_buffer;
1813 tdm_error err = TDM_ERROR_NONE;
1815 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1816 RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
1818 TDM_DBG("layer[%p]zpos[%d] buffer:%p", layer, layer_data->zpos, buffer);
1820 drm_data = layer_data->drm_data;
1821 display_buffer = _tdm_drm_display_find_buffer(drm_data, buffer);
1822 if (!display_buffer) {
1823 display_buffer = _tdm_drm_display_create_buffer(drm_data, buffer, &err);
1824 RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
1827 if (layer_data->display_buffer != display_buffer) {
1828 if (layer_data->display_buffer)
1829 tbm_surface_internal_unref(layer_data->display_buffer->buffer);
1831 layer_data->display_buffer = display_buffer;
1832 tbm_surface_internal_ref(layer_data->display_buffer->buffer);
1833 layer_data->display_buffer_changed = 1;
1836 return TDM_ERROR_NONE;
1840 drm_layer_unset_buffer(tdm_layer *layer)
1842 tdm_drm_layer_data *layer_data = layer;
1844 RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1846 if (!(layer_data->capabilities & TDM_LAYER_CAPABILITY_PRIMARY) && layer_data->display_buffer) {
1847 tbm_surface_internal_unref(layer_data->display_buffer->buffer);
1848 layer_data->display_buffer = NULL;
1851 layer_data->display_buffer_changed = 1;
1853 return TDM_ERROR_NONE;
1856 tdm_drm_layer_data *
1857 drm_output_data_get_layer_data(tdm_drm_output_data *output_data, int layer_zpos)
1859 tdm_drm_layer_data *l = NULL;
1861 RETURN_VAL_IF_FAIL(output_data, NULL);
1863 LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link) {
1864 if (l->zpos == layer_zpos)