Add missing boilerplate
[platform/adaptation/libtdm-drm.git] / src / libhal-backend-tdm-drm / tdm_drm_display.c
1 /**************************************************************************
2
3 libtdm_drm
4
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>
8
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:
16
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
19 of the Software.
20
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.
28
29 **************************************************************************/
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "tdm_backend_drm.h"
36
37 static drmModeModeInfoPtr
38 _tdm_drm_display_get_mode(tdm_drm_output *output_data)
39 {
40         int i;
41
42         if (!output_data->current_mode) {
43                 TDM_BACKEND_ERR("no output_data->current_mode");
44                 return NULL;
45         }
46
47         for (i = 0; i < output_data->count_modes; i++) {
48                 drmModeModeInfoPtr drm_mode = &output_data->drm_modes[i];
49                 if ((drm_mode->hdisplay == output_data->current_mode->hdisplay) &&
50                         (drm_mode->vdisplay == output_data->current_mode->vdisplay) &&
51                         (drm_mode->vrefresh == output_data->current_mode->vrefresh) &&
52                         (drm_mode->flags == output_data->current_mode->flags) &&
53                         (drm_mode->type == output_data->current_mode->type) &&
54                         !(strncmp(drm_mode->name, output_data->current_mode->name, HAL_TDM_NAME_LEN)))
55                         return drm_mode;
56         }
57
58         return NULL;
59 }
60
61 static void
62 _tdm_drm_display_to_tdm_mode(drmModeModeInfoPtr drm_mode,
63                                                          hal_tdm_output_mode *tdm_mode)
64 {
65         tdm_mode->clock = drm_mode->clock;
66         tdm_mode->hdisplay = drm_mode->hdisplay;
67         tdm_mode->hsync_start = drm_mode->hsync_start;
68         tdm_mode->hsync_end = drm_mode->hsync_end;
69         tdm_mode->htotal = drm_mode->htotal;
70         tdm_mode->hskew = drm_mode->hskew;
71         tdm_mode->vdisplay = drm_mode->vdisplay;
72         tdm_mode->vsync_start = drm_mode->vsync_start;
73         tdm_mode->vsync_end = drm_mode->vsync_end;
74         tdm_mode->vtotal = drm_mode->vtotal;
75         tdm_mode->vscan = drm_mode->vscan;
76         tdm_mode->vrefresh = drm_mode->vrefresh;
77         tdm_mode->flags = drm_mode->flags;
78         tdm_mode->type = drm_mode->type;
79         snprintf(tdm_mode->name, HAL_TDM_NAME_LEN, "%s", drm_mode->name);
80 }
81
82 static hal_tdm_error
83 _tdm_drm_display_get_cur_msc(int fd, int pipe, uint *msc)
84 {
85         drmVBlank vbl;
86
87         vbl.request.type = DRM_VBLANK_RELATIVE;
88         if (pipe > 0)
89                 vbl.request.type |= DRM_VBLANK_SECONDARY;
90
91         vbl.request.sequence = 0;
92         if (drmWaitVBlank(fd, &vbl)) {
93                 TDM_BACKEND_ERR("get vblank counter failed: %m");
94                 *msc = 0;
95                 return HAL_TDM_ERROR_OPERATION_FAILED;
96         }
97
98         *msc = vbl.reply.sequence;
99
100         return HAL_TDM_ERROR_NONE;
101 }
102
103 static hal_tdm_error
104 _tdm_drm_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data)
105 {
106         drmVBlank vbl;
107
108         vbl.request.type =  DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
109         if (pipe > 0)
110                 vbl.request.type |= DRM_VBLANK_SECONDARY;
111
112         vbl.request.sequence = *target_msc;
113         vbl.request.signal = (unsigned long)(uintptr_t)data;
114
115         if (drmWaitVBlank(fd, &vbl)) {
116                 *target_msc = 0;
117                 TDM_BACKEND_ERR("wait vblank failed: %m");
118                 return HAL_TDM_ERROR_OPERATION_FAILED;
119         }
120
121         *target_msc = vbl.reply.sequence;
122
123         return HAL_TDM_ERROR_NONE;
124 }
125
126 static hal_tdm_error
127 _tdm_drm_output_update_status(tdm_drm_output *output_data,
128                                                           hal_tdm_output_conn_status status)
129 {
130         RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
131
132         if (output_data->status == status)
133                 return HAL_TDM_ERROR_NONE;
134
135         output_data->status = status;
136
137         if (output_data->status_func)
138                 output_data->status_func(output_data, status,
139                                                                  output_data->status_user_data);
140
141         return HAL_TDM_ERROR_NONE;
142 }
143
144 static hal_tdm_error
145 _tdm_drm_display_commit_primary_layer(tdm_drm_layer *layer_data,
146                                                                           void *user_data, int *do_waitvblank)
147 {
148         tdm_drm_display *display_data = layer_data->display_data;
149         tdm_drm_output *output_data = layer_data->output_data;
150
151         if (output_data->mode_changed && layer_data->display_buffer_changed) {
152                 drmModeModeInfoPtr mode;
153
154                 if (!layer_data->display_buffer) {
155                         TDM_BACKEND_ERR("primary layer should have a buffer for modestting");
156                         return HAL_TDM_ERROR_BAD_REQUEST;
157                 }
158
159                 output_data->mode_changed = 0;
160                 layer_data->display_buffer_changed = 0;
161                 layer_data->info_changed = 0;
162
163                 mode = _tdm_drm_display_get_mode(output_data);
164                 if (!mode) {
165                         TDM_BACKEND_ERR("couldn't find proper mode");
166                         return HAL_TDM_ERROR_BAD_REQUEST;
167                 }
168
169                 if (drmModeSetCrtc(display_data->drm_fd, output_data->crtc_id,
170                                                    layer_data->display_buffer->fb_id, 0, 0,
171                                                    &output_data->connector_id, 1, mode)) {
172                         TDM_BACKEND_ERR("set crtc failed: %m");
173                         return HAL_TDM_ERROR_OPERATION_FAILED;
174                 }
175
176                 _tdm_drm_output_update_status(output_data, HAL_TDM_OUTPUT_CONN_STATUS_MODE_SETTED);
177
178                 *do_waitvblank = 1;
179                 return HAL_TDM_ERROR_NONE;
180         } else if (layer_data->display_buffer_changed) {
181                 layer_data->display_buffer_changed = 0;
182
183                 if (!layer_data->display_buffer) {
184                         if (drmModeSetCrtc(display_data->drm_fd, output_data->crtc_id,
185                                                            0, 0, 0, NULL, 0, NULL)) {
186                                 TDM_BACKEND_ERR("unset crtc failed: %m");
187                                 return HAL_TDM_ERROR_OPERATION_FAILED;
188                         }
189
190                         if (output_data->status == HAL_TDM_OUTPUT_CONN_STATUS_MODE_SETTED)
191                                 _tdm_drm_output_update_status(output_data, HAL_TDM_OUTPUT_CONN_STATUS_CONNECTED);
192
193                         *do_waitvblank = 1;
194                 } else {
195                         tdm_drm_event_data *event_data = calloc(1, sizeof(tdm_drm_event_data));
196
197                         if (!event_data) {
198                                 TDM_BACKEND_ERR("alloc failed");
199                                 return HAL_TDM_ERROR_OUT_OF_MEMORY;
200                         }
201
202                         event_data->type = TDM_DRM_EVENT_TYPE_PAGEFLIP;
203                         event_data->output_data = output_data;
204                         event_data->user_data = user_data;
205                         if (drmModePageFlip(display_data->drm_fd, output_data->crtc_id,
206                                                                 layer_data->display_buffer->fb_id, DRM_MODE_PAGE_FLIP_EVENT, event_data)) {
207                                 TDM_BACKEND_ERR("pageflip failed: %m");
208                                 free(event_data);
209                                 return HAL_TDM_ERROR_OPERATION_FAILED;
210                         }
211                         *do_waitvblank = 0;
212                 }
213         }
214
215         return HAL_TDM_ERROR_NONE;
216 }
217
218 static hal_tdm_error
219 _tdm_drm_display_commit_layer(tdm_drm_layer *layer_data)
220 {
221         tdm_drm_display *display_data = layer_data->display_data;
222         tdm_drm_output *output_data = layer_data->output_data;
223         uint32_t fx, fy, fw, fh;
224         int crtc_w;
225
226         if (!layer_data->display_buffer_changed && !layer_data->info_changed)
227                 return HAL_TDM_ERROR_NONE;
228
229         if (output_data->current_mode)
230                 crtc_w = output_data->current_mode->hdisplay;
231         else {
232                 drmModeCrtcPtr crtc = drmModeGetCrtc(display_data->drm_fd, output_data->crtc_id);
233                 if (!crtc) {
234                         TDM_BACKEND_ERR("getting crtc failed");
235                         return HAL_TDM_ERROR_OPERATION_FAILED;
236                 }
237                 crtc_w = crtc->width;
238                 if (crtc_w == 0) {
239                         TDM_BACKEND_ERR("getting crtc width failed");
240                         drmModeFreeCrtc(crtc);
241                         return HAL_TDM_ERROR_OPERATION_FAILED;
242                 }
243                 drmModeFreeCrtc(crtc);
244         }
245
246         layer_data->display_buffer_changed = 0;
247         layer_data->info_changed = 0;
248
249         if (!layer_data->display_buffer) {
250                 if (drmModeSetPlane(display_data->drm_fd, layer_data->plane_id,
251                                                         output_data->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
252                         TDM_BACKEND_ERR("unset plane(%d) filed: %m", layer_data->plane_id);
253
254                 return HAL_TDM_ERROR_NONE;
255         }
256
257         /* Source values are 16.16 fixed point */
258         fx = ((unsigned int)layer_data->info.src_config.pos.x) << 16;
259         fy = ((unsigned int)layer_data->info.src_config.pos.y) << 16;
260         fw = ((unsigned int)layer_data->info.src_config.pos.w) << 16;
261         fh = ((unsigned int)layer_data->info.src_config.pos.h) << 16;
262
263         if (drmModeSetPlane(display_data->drm_fd, layer_data->plane_id,
264                                                 output_data->crtc_id, layer_data->display_buffer->fb_id, 0,
265                                                 layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
266                                                 layer_data->info.dst_pos.w, layer_data->info.dst_pos.h,
267                                                 fx, fy, fw, fh) < 0) {
268                 TDM_BACKEND_ERR("set plane(%d) failed: %m", layer_data->plane_id);
269                 return HAL_TDM_ERROR_OPERATION_FAILED;
270         }
271
272         TDM_BACKEND_INFO("plane(%d) crtc(%d) pos(%d) on: fb(%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n",
273                         layer_data->plane_id, output_data->crtc_id, layer_data->zpos,
274                         layer_data->display_buffer->fb_id,
275                         layer_data->info.src_config.pos.x, layer_data->info.src_config.pos.y,
276                         layer_data->info.src_config.pos.w, layer_data->info.src_config.pos.h,
277                         layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
278                         layer_data->info.dst_pos.w, layer_data->info.dst_pos.h);
279
280         return HAL_TDM_ERROR_NONE;
281 }
282
283 static void
284 _tdm_drm_display_cb_event(int fd, unsigned int sequence,
285                                                   unsigned int tv_sec, unsigned int tv_usec,
286                                                   void *user_data)
287 {
288         tdm_drm_event_data *event_data = user_data;
289         tdm_drm_output *output_data;
290         tdm_drm_hwc *hwc_data;
291
292         if (!event_data) {
293                 TDM_BACKEND_ERR("no event data");
294                 return;
295         }
296
297         output_data = event_data->output_data;
298
299         switch (event_data->type) {
300         case TDM_DRM_EVENT_TYPE_PAGEFLIP:
301                 hwc_data = output_data->hwc_data;
302                 if (!hwc_data) {
303                         TDM_BACKEND_ERR("no hwc_data");
304                         break;
305                 }
306
307                 if (hwc_data->commit_func)
308                         hwc_data->commit_func(hwc_data, sequence,
309                                                                          tv_sec, tv_usec,
310                                                                          event_data->user_data);
311                 break;
312         case TDM_DRM_EVENT_TYPE_WAIT:
313                 if (output_data->vblank_func)
314                         output_data->vblank_func(output_data, sequence, tv_sec, tv_usec,
315                                                                          event_data->user_data);
316                 break;
317         case TDM_DRM_EVENT_TYPE_COMMIT:
318                 hwc_data = output_data->hwc_data;
319                 if (!hwc_data) {
320                         TDM_BACKEND_ERR("no hwc_data");
321                         break;
322                 }
323
324                 if (hwc_data->commit_func)
325                         hwc_data->commit_func(hwc_data, sequence,
326                                                                          tv_sec, tv_usec,
327                                                                          event_data->user_data);
328                 break;
329         default:
330                 break;
331         }
332
333         free(event_data);
334 }
335
336 static hal_tdm_error
337 _tdm_drm_display_create_layer_list(tdm_drm_display *display_data)
338 {
339         tdm_drm_output *output_data = NULL;
340         int i;
341
342         if (LIST_IS_EMPTY(&display_data->output_list)) {
343                 TDM_BACKEND_ERR("no output");
344                 return HAL_TDM_ERROR_OPERATION_FAILED;
345         }
346
347         /* The TDM drm backend only support one output. */
348         LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link) {
349                 break;
350         }
351
352         if (display_data->plane_res->count_planes == 0) {
353                 TDM_BACKEND_ERR("no layer error");
354                 return HAL_TDM_ERROR_OPERATION_FAILED;
355         }
356
357         for (i = 0; i < display_data->plane_res->count_planes; i++) {
358                 tdm_drm_layer *layer_data;
359                 drmModePlanePtr plane;
360
361                 plane = drmModeGetPlane(display_data->drm_fd, display_data->plane_res->planes[i]);
362                 if (!plane) {
363                         TDM_BACKEND_ERR("no plane");
364                         continue;
365                 }
366
367                 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
368                         drmModeFreePlane(plane);
369                         continue;
370                 }
371
372                 layer_data = calloc(1, sizeof(tdm_drm_layer));
373                 if (!layer_data) {
374                         TDM_BACKEND_ERR("alloc failed");
375                         drmModeFreePlane(plane);
376                         continue;
377                 }
378
379                 layer_data->display_data = display_data;
380                 layer_data->output_data = output_data;
381                 layer_data->plane_id = display_data->plane_res->planes[i];
382
383                 layer_data->capabilities = TDM_DRM_LAYER_CAPABILITY_PRIMARY |
384                                                                    TDM_DRM_LAYER_CAPABILITY_GRAPHIC;
385                 output_data->primary_layer = layer_data;
386
387                 TDM_BACKEND_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) capabilities(%x)",
388                                  layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
389                                  layer_data->capabilities);
390
391                 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
392
393                 drmModeFreePlane(plane);
394
395                 /* can't take care of other planes for various hardware devices */
396                 break;
397         }
398
399         return HAL_TDM_ERROR_NONE;
400 }
401
402 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4  && LIBDRM_MICRO_VERSION >= 47
403
404 static hal_tdm_error
405 _tdm_drm_display_get_property(tdm_drm_display *display_data,
406                                                           unsigned int obj_id, unsigned int obj_type,
407                                                           const char *name, unsigned int *value,
408                                                           int *is_immutable)
409 {
410         drmModeObjectPropertiesPtr props = NULL;
411         int i;
412
413         props = drmModeObjectGetProperties(display_data->drm_fd, obj_id, obj_type);
414         if (!props)
415                 return HAL_TDM_ERROR_OPERATION_FAILED;
416
417         for (i = 0; i < props->count_props; i++) {
418                 drmModePropertyPtr prop = drmModeGetProperty(display_data->drm_fd,
419                                                                   props->props[i]);
420
421                 if (!prop)
422                         continue;
423
424                 if (!strcmp(prop->name, name)) {
425                         if (is_immutable)
426                                 *is_immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
427                         if (value)
428                                 *value = (unsigned int)props->prop_values[i];
429                         drmModeFreeProperty(prop);
430                         drmModeFreeObjectProperties(props);
431                         return HAL_TDM_ERROR_NONE;
432                 }
433
434                 drmModeFreeProperty(prop);
435         }
436         drmModeFreeObjectProperties(props);
437         TDM_BACKEND_DBG("coundn't find '%s' property", name);
438         return HAL_TDM_ERROR_OPERATION_FAILED;
439 }
440
441 static hal_tdm_error
442 _tdm_drm_display_create_layer_list_type(tdm_drm_display *display_data)
443 {
444         tdm_drm_output *output_data = NULL;
445         drmModePlanePtr *planes = NULL;
446         unsigned int *types = NULL;
447         unsigned int type = 0;
448         int plane_cnt, primary_cnt, ovl_cnt, cursor_cnt;
449         int opos_next, cpos_next;
450         hal_tdm_error ret;
451         int i;
452
453         if (LIST_IS_EMPTY(&display_data->output_list)) {
454                 TDM_BACKEND_ERR("no output");
455                 return HAL_TDM_ERROR_OPERATION_FAILED;
456         }
457
458         /* The TDM drm backend only support one output. */
459         LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link) {
460                 break;
461         }
462
463         ret = _tdm_drm_display_get_property(display_data,
464                                                                                 display_data->plane_res->planes[0],
465                                                                                 DRM_MODE_OBJECT_PLANE, "type", &type,
466                                                                                 NULL);
467         if (ret != HAL_TDM_ERROR_NONE) {
468                 TDM_BACKEND_ERR("plane doesn't have 'type' property. Call a fallback function");
469
470                 /* if a plane doesn't have "type" property, we call a fallback function
471                  * as default
472                  */
473                 return _tdm_drm_display_create_layer_list(display_data);
474         }
475
476         planes = calloc(display_data->plane_res->count_planes, sizeof(drmModePlanePtr));
477         if (!planes) {
478                 TDM_BACKEND_ERR("alloc failed");
479                 goto failed;
480         }
481
482         types = calloc(display_data->plane_res->count_planes, sizeof(unsigned int));
483         if (!types) {
484                 TDM_BACKEND_ERR("alloc failed");
485                 goto failed;
486         }
487
488         plane_cnt = 0;
489         for (i = 0; i < display_data->plane_res->count_planes; i++) {
490                 drmModePlanePtr plane;
491
492                 plane = drmModeGetPlane(display_data->drm_fd, display_data->plane_res->planes[i]);
493                 if (!plane) {
494                         TDM_BACKEND_ERR("no plane(%d)", display_data->plane_res->planes[i]);
495                         goto failed;
496                 }
497
498                 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
499                         drmModeFreePlane(plane);
500                         continue;
501                 }
502
503                 ret = _tdm_drm_display_get_property(display_data,
504                                                                                         display_data->plane_res->planes[i],
505                                                                                         DRM_MODE_OBJECT_PLANE, "type", &type,
506                                                                                         NULL);
507                 if (ret != HAL_TDM_ERROR_NONE) {
508                         drmModeFreePlane(plane);
509                         TDM_BACKEND_ERR("plane(%d) doesn't have 'type' info",
510                                         display_data->plane_res->planes[i]);
511                         goto failed;
512                 }
513
514                 /* The TDM drm backend only support a primary layer. */
515                 if (type != DRM_PLANE_TYPE_PRIMARY) {
516                         TDM_BACKEND_INFO("The TDM drm backend only support a primary layer. plane(%d) type(%d)",
517                                          plane->plane_id, type);
518                         drmModeFreePlane(plane);
519                         continue;
520                 }
521
522                 planes[plane_cnt] = plane;
523                 types[plane_cnt] = type;
524                 plane_cnt++;
525         }
526
527         primary_cnt = ovl_cnt = cursor_cnt = 0;
528         for (i = 0; i < plane_cnt; i++) {
529                 if (types[i] == DRM_PLANE_TYPE_CURSOR)
530                         cursor_cnt++;
531                 else if (types[i] == DRM_PLANE_TYPE_OVERLAY)
532                         ovl_cnt++;
533                 else if (types[i] == DRM_PLANE_TYPE_PRIMARY)
534                         primary_cnt++;
535                 else
536                         TDM_BACKEND_ERR("invalid type(%d)", types[i]);
537         }
538
539         if (primary_cnt != 1) {
540                 TDM_BACKEND_ERR("primary layer count(%d) should be one", primary_cnt);
541                 goto failed;
542         }
543
544         opos_next = 1;
545         cpos_next = ovl_cnt;
546         for (i = 0; i < plane_cnt; i++) {
547                 tdm_drm_layer *layer_data;
548
549                 layer_data = calloc(1, sizeof(tdm_drm_layer));
550                 if (!layer_data) {
551                         TDM_BACKEND_ERR("alloc failed");
552                         goto failed;
553                 }
554
555                 layer_data->display_data = display_data;
556                 layer_data->output_data = output_data;
557                 layer_data->plane_id = planes[i]->plane_id;
558
559                 if (types[i] == DRM_PLANE_TYPE_CURSOR) {
560                         layer_data->capabilities = TDM_DRM_LAYER_CAPABILITY_CURSOR |
561                                                                            TDM_DRM_LAYER_CAPABILITY_GRAPHIC;
562                         layer_data->zpos = cpos_next++;
563                 } else if (types[i] == DRM_PLANE_TYPE_OVERLAY) {
564                         layer_data->capabilities = TDM_DRM_LAYER_CAPABILITY_OVERLAY |
565                                                                            TDM_DRM_LAYER_CAPABILITY_GRAPHIC;
566                         layer_data->zpos = opos_next++;
567                 } else if (types[i] == DRM_PLANE_TYPE_PRIMARY) {
568                         layer_data->capabilities = TDM_DRM_LAYER_CAPABILITY_PRIMARY |
569                                                                            TDM_DRM_LAYER_CAPABILITY_GRAPHIC;
570                         layer_data->zpos = 0;
571                         output_data->primary_layer = layer_data;
572                 } else {
573                         free(layer_data);
574                         continue;
575                 }
576
577                 TDM_BACKEND_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) zpos(%d) capabilities(%x)",
578                                  layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
579                                  layer_data->zpos, layer_data->capabilities);
580
581                 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
582         }
583
584         for (i = 0; i < plane_cnt; i++)
585                 if (planes[i])
586                         drmModeFreePlane(planes[i]);
587
588         free(planes);
589         free(types);
590
591         return HAL_TDM_ERROR_NONE;
592
593 failed:
594         if (planes) {
595                 for (i = 0; i < display_data->plane_res->count_planes; i++)
596                         if (planes[i])
597                                 drmModeFreePlane(planes[i]);
598                 free(planes);
599         }
600
601         free(types);
602
603         return HAL_TDM_ERROR_OPERATION_FAILED;
604 }
605 #endif
606
607 hal_tdm_error
608 tdm_drm_display_create_layer_list(tdm_drm_display *display_data)
609 {
610         tdm_drm_output *output_data = NULL;
611         hal_tdm_error ret;
612
613 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4  && LIBDRM_MICRO_VERSION >= 47
614         if (display_data->has_universal_plane)
615                 ret = _tdm_drm_display_create_layer_list_type(display_data);
616         else
617 #endif
618                 ret = _tdm_drm_display_create_layer_list(display_data);
619
620         if (ret != HAL_TDM_ERROR_NONE)
621                 return ret;
622
623         LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link) {
624                 if (!output_data->primary_layer) {
625                         TDM_BACKEND_ERR("output(%d) no primary layer", output_data->pipe);
626                         return HAL_TDM_ERROR_OPERATION_FAILED;
627                 }
628         }
629
630         return HAL_TDM_ERROR_NONE;
631 }
632
633 void
634 tdm_drm_display_destroy_output_list(tdm_drm_display *display_data)
635 {
636         tdm_drm_output *o = NULL, *oo = NULL;
637         tdm_drm_hwc *hwc_data = NULL;
638
639         if (LIST_IS_EMPTY(&display_data->output_list))
640                 return;
641
642         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &display_data->output_list, link) {
643                 hwc_data = o->hwc_data;
644                 if (hwc_data && hwc_data->target_hwc_window)
645                         drm_hwc_window_destroy(hwc_data->target_hwc_window);
646
647                 LIST_DEL(&o->link);
648                 if (!LIST_IS_EMPTY(&o->layer_list)) {
649                         tdm_drm_layer *l = NULL, *ll = NULL;
650                         LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
651                                 LIST_DEL(&l->link);
652                                 if (l->display_buffer)
653                                         tbm_surface_internal_unref(l->display_buffer->buffer);
654                                 free(l);
655                         }
656                 }
657                 free(o->drm_modes);
658                 free(o->output_modes);
659                 free(o);
660         }
661 }
662
663 void
664 tdm_drm_display_update_output_status(tdm_drm_display *display_data)
665 {
666         tdm_drm_output *output_data = NULL;
667
668         if (LIST_IS_EMPTY(&display_data->output_list))
669                 return;
670
671         LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link) {
672                 drmModeConnectorPtr connector;
673                 hal_tdm_output_conn_status new_status;
674
675                 connector = drmModeGetConnector(display_data->drm_fd,
676                                                                                 output_data->connector_id);
677                 if (!connector) {
678                         TDM_BACKEND_ERR("no connector: %d", output_data->connector_id);
679                         continue;
680                 }
681
682                 if (connector->connection == DRM_MODE_CONNECTED)
683                         new_status = HAL_TDM_OUTPUT_CONN_STATUS_CONNECTED;
684                 else
685                         new_status = HAL_TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
686
687                 _tdm_drm_output_update_status(output_data, new_status);
688
689                 drmModeFreeConnector(connector);
690         }
691 }
692
693 hal_tdm_error
694 tdm_drm_display_create_output_list(tdm_drm_display *display_data)
695 {
696         tdm_drm_output *output_data;
697         int i;
698         hal_tdm_error ret;
699         int allocated = 0;
700         drmModeConnectorPtr connector;
701         drmModeEncoderPtr encoder;
702         int conn_idx = -1;
703         int crtc_id = 0, c, j;
704
705         RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&display_data->output_list),
706                                            HAL_TDM_ERROR_OPERATION_FAILED);
707
708         /* check if there is a connected output */
709         for (i = 0; i < display_data->mode_res->count_connectors; i++) {
710                 connector = drmModeGetConnector(display_data->drm_fd,
711                                                                                 display_data->mode_res->connectors[i]);
712                 if (!connector) {
713                         TDM_BACKEND_ERR("no connector");
714                         return HAL_TDM_ERROR_OPERATION_FAILED;
715                 }
716
717                 /* The TDM drm backend considers only 1 connector because it is the TDM
718                  * reference backend and can't take care of all hardware devices.
719                  * To support various connectors, planes and crtcs, the new TDM backend
720                  * should be implemented.
721                  */
722                 if (connector->connection == DRM_MODE_CONNECTED) {
723                         conn_idx = i;
724                         drmModeFreeConnector(connector);
725                         break;
726                 }
727                 drmModeFreeConnector(connector);
728         }
729
730         /* use the first connecoct_id if there is not connector which is connected */
731         if (conn_idx == -1)
732                 conn_idx = 0;
733
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.
738          */
739         connector = drmModeGetConnector(display_data->drm_fd,
740                                                                         display_data->mode_res->connectors[conn_idx]);
741         if (!connector) {
742                 TDM_BACKEND_ERR("no connector");
743                 ret = HAL_TDM_ERROR_OPERATION_FAILED;
744                 goto failed_create;
745         }
746
747         if (connector->count_encoders != 1) {
748                 TDM_BACKEND_ERR("too many encoders: %d", connector->count_encoders);
749                 drmModeFreeConnector(connector);
750                 ret = HAL_TDM_ERROR_OPERATION_FAILED;
751                 goto failed_create;
752         }
753
754         encoder = drmModeGetEncoder(display_data->drm_fd, connector->encoders[0]);
755         if (!encoder) {
756                 TDM_BACKEND_ERR("no encoder");
757                 drmModeFreeConnector(connector);
758                 ret = HAL_TDM_ERROR_OPERATION_FAILED;
759                 goto failed_create;
760         }
761
762         for (c = 0; c < display_data->mode_res->count_crtcs; c++) {
763                 if (allocated & (1 << c))
764                         continue;
765
766                 if ((encoder->possible_crtcs & (1 << c)) == 0)
767                         continue;
768
769                 crtc_id = display_data->mode_res->crtcs[c];
770                 allocated |= (1 << c);
771                 break;
772         }
773
774         if (crtc_id == 0) {
775                 TDM_BACKEND_ERR("no possible crtc");
776                 drmModeFreeConnector(connector);
777                 drmModeFreeEncoder(encoder);
778                 ret = HAL_TDM_ERROR_OPERATION_FAILED;
779                 goto failed_create;
780         }
781
782         output_data = calloc(1, sizeof(tdm_drm_output));
783         if (!output_data) {
784                 TDM_BACKEND_ERR("alloc failed");
785                 drmModeFreeConnector(connector);
786                 drmModeFreeEncoder(encoder);
787                 ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
788                 goto failed_create;
789         }
790
791         LIST_INITHEAD(&output_data->layer_list);
792
793         output_data->display_data = display_data;
794         output_data->connector_id = display_data->mode_res->connectors[conn_idx];
795         output_data->encoder_id = encoder->encoder_id;
796         output_data->crtc_id = crtc_id;
797         output_data->pipe = c;
798         output_data->connector_type = connector->connector_type;
799         output_data->connector_type_id = connector->connector_type_id;
800
801         if (connector->connection == DRM_MODE_CONNECTED)
802                 output_data->status = HAL_TDM_OUTPUT_CONN_STATUS_CONNECTED;
803         else
804                 output_data->status = HAL_TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
805
806         for (j = 0; j < connector->count_props; j++) {
807                 drmModePropertyPtr prop = drmModeGetProperty(display_data->drm_fd,
808                                                                   connector->props[j]);
809                 if (!prop)
810                         continue;
811                 if (!strcmp(prop->name, "DPMS")) {
812                         output_data->dpms_prop_id = connector->props[j];
813                         drmModeFreeProperty(prop);
814                         break;
815                 }
816                 drmModeFreeProperty(prop);
817         }
818
819         if (output_data->dpms_prop_id == 0)
820                 TDM_BACKEND_WRN("not support DPMS");
821
822         output_data->count_modes = connector->count_modes;
823         output_data->drm_modes = calloc(connector->count_modes,
824                                                                         sizeof(drmModeModeInfo));
825         if (!output_data->drm_modes) {
826                 TDM_BACKEND_ERR("alloc failed");
827                 free(output_data);
828                 drmModeFreeConnector(connector);
829                 drmModeFreeEncoder(encoder);
830                 ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
831                 goto failed_create;
832         }
833         output_data->output_modes = calloc(connector->count_modes,
834                                                                            sizeof(hal_tdm_output_mode));
835         if (!output_data->output_modes) {
836                 TDM_BACKEND_ERR("alloc failed");
837                 free(output_data->drm_modes);
838                 free(output_data);
839                 drmModeFreeConnector(connector);
840                 drmModeFreeEncoder(encoder);
841                 ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
842                 goto failed_create;
843         }
844         for (j = 0; j < connector->count_modes; j++) {
845                 output_data->drm_modes[j] = connector->modes[j];
846                 _tdm_drm_display_to_tdm_mode(&output_data->drm_modes[j],
847                                                                          &output_data->output_modes[j]);
848         }
849
850         LIST_ADDTAIL(&output_data->link, &display_data->output_list);
851
852         TDM_BACKEND_DBG("output_data(%p) connector_id(%d:%d:%d-%d) encoder_id(%d) crtc_id(%d) pipe(%d) dpms_id(%d)",
853                         output_data, output_data->connector_id, output_data->status,
854                         output_data->connector_type,
855                         output_data->connector_type_id, output_data->encoder_id, output_data->crtc_id,
856                         output_data->pipe, output_data->dpms_prop_id);
857
858         drmModeFreeEncoder(encoder);
859         drmModeFreeConnector(connector);
860
861         TDM_BACKEND_DBG("output count: %d", display_data->mode_res->count_connectors);
862
863         return HAL_TDM_ERROR_NONE;
864 failed_create:
865         tdm_drm_display_destroy_output_list(display_data);
866         return ret;
867 }
868
869 hal_tdm_error
870 drm_display_get_capability(hal_tdm_display *display, hal_tdm_caps_display *caps)
871 {
872         RETURN_VAL_IF_FAIL(caps, HAL_TDM_ERROR_INVALID_PARAMETER);
873
874         caps->max_layer_count = -1; /* not defined */
875
876         return HAL_TDM_ERROR_NONE;
877 }
878
879 hal_tdm_error
880 drm_display_get_pp_capability(hal_tdm_display *display, hal_tdm_caps_pp *caps)
881 {
882         return tdm_drm_pp_get_capability(display, caps);
883 }
884
885 hal_tdm_output **
886 drm_display_get_outputs(hal_tdm_display *display, int *count, hal_tdm_error *error)
887 {
888         tdm_drm_display *display_data = display;
889         tdm_drm_output *output_data = NULL;
890         hal_tdm_output **outputs;
891         hal_tdm_error ret;
892         int i;
893
894         RETURN_VAL_IF_FAIL(display_data, NULL);
895         RETURN_VAL_IF_FAIL(count, NULL);
896
897         *count = 0;
898         LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link)
899         (*count)++;
900
901         if (*count == 0) {
902                 ret = HAL_TDM_ERROR_NONE;
903                 goto failed_get;
904         }
905
906         /* will be freed in frontend */
907         outputs = calloc(*count, sizeof(tdm_drm_output *));
908         if (!outputs) {
909                 TDM_BACKEND_ERR("failed: alloc memory");
910                 *count = 0;
911                 ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
912                 goto failed_get;
913         }
914
915         i = 0;
916         LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link)
917         outputs[i++] = output_data;
918
919         if (error)
920                 *error = HAL_TDM_ERROR_NONE;
921
922         return outputs;
923 failed_get:
924         if (error)
925                 *error = ret;
926         return NULL;
927 }
928
929 hal_tdm_error
930 drm_display_get_fd(hal_tdm_display *display, int *fd)
931 {
932         tdm_drm_display *display_data = display;
933
934         RETURN_VAL_IF_FAIL(display_data, HAL_TDM_ERROR_INVALID_PARAMETER);
935         RETURN_VAL_IF_FAIL(fd, HAL_TDM_ERROR_INVALID_PARAMETER);
936
937         *fd = display_data->drm_fd;
938
939         return HAL_TDM_ERROR_NONE;
940 }
941
942 hal_tdm_error
943 drm_display_handle_events(hal_tdm_display *display)
944 {
945         tdm_drm_display *display_data = display;
946         drmEventContext ctx;
947
948         RETURN_VAL_IF_FAIL(display_data, HAL_TDM_ERROR_INVALID_PARAMETER);
949
950         memset(&ctx, 0, sizeof(drmEventContext));
951
952         ctx.version = DRM_EVENT_CONTEXT_VERSION;
953         ctx.page_flip_handler = _tdm_drm_display_cb_event;
954         ctx.vblank_handler = _tdm_drm_display_cb_event;
955
956         drmHandleEvent(display_data->drm_fd, &ctx);
957
958         return HAL_TDM_ERROR_NONE;
959 }
960
961 hal_tdm_pp *
962 drm_display_create_pp(hal_tdm_display *display, hal_tdm_error *error)
963 {
964         tdm_drm_display *display_data = display;
965
966         RETURN_VAL_IF_FAIL(display_data, NULL);
967
968         return tdm_drm_pp_create(display_data, error);
969 }
970
971 hal_tdm_error
972 drm_output_get_capability(hal_tdm_output *output, hal_tdm_caps_output *caps)
973 {
974         tdm_drm_output *output_data = output;
975         tdm_drm_display *display_data;
976         drmModeConnectorPtr connector = NULL;
977         drmModeCrtcPtr crtc = NULL;
978         drmModeObjectPropertiesPtr props = NULL;
979         int i;
980         hal_tdm_error ret;
981
982         RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
983         RETURN_VAL_IF_FAIL(caps, HAL_TDM_ERROR_INVALID_PARAMETER);
984
985         memset(caps, 0, sizeof(hal_tdm_caps_output));
986
987         display_data = output_data->display_data;
988
989         snprintf(caps->maker, HAL_TDM_NAME_LEN, "unknown");
990         snprintf(caps->model, HAL_TDM_NAME_LEN, "unknown");
991         snprintf(caps->name, HAL_TDM_NAME_LEN, "unknown");
992
993         caps->status = output_data->status;
994         caps->type = output_data->connector_type;
995         caps->type_id = output_data->connector_type_id;
996
997         connector = drmModeGetConnector(display_data->drm_fd, output_data->connector_id);
998         RETURN_VAL_IF_FAIL(connector, HAL_TDM_ERROR_OPERATION_FAILED);
999
1000         caps->mode_count = connector->count_modes;
1001         caps->modes = calloc(1, sizeof(hal_tdm_output_mode) * caps->mode_count);
1002         if (!caps->modes) {
1003                 ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
1004                 TDM_BACKEND_ERR("alloc failed\n");
1005                 goto failed_get;
1006         }
1007         for (i = 0; i < caps->mode_count; i++)
1008                 caps->modes[i] = output_data->output_modes[i];
1009
1010         caps->mmWidth = connector->mmWidth;
1011         caps->mmHeight = connector->mmHeight;
1012         caps->subpixel = connector->subpixel;
1013
1014         caps->min_w = display_data->mode_res->min_width;
1015         caps->min_h = display_data->mode_res->min_height;
1016         caps->max_w = display_data->mode_res->max_width;
1017         caps->max_h = display_data->mode_res->max_height;
1018         caps->preferred_align = -1;
1019
1020         crtc = drmModeGetCrtc(display_data->drm_fd, output_data->crtc_id);
1021         if (!crtc) {
1022                 ret = HAL_TDM_ERROR_OPERATION_FAILED;
1023                 TDM_BACKEND_ERR("get crtc failed: %m\n");
1024                 goto failed_get;
1025         }
1026
1027         props = drmModeObjectGetProperties(display_data->drm_fd, output_data->crtc_id,
1028                                                                            DRM_MODE_OBJECT_CRTC);
1029         if (!props) {
1030                 ret = HAL_TDM_ERROR_OPERATION_FAILED;
1031                 TDM_BACKEND_ERR("get crtc properties failed: %m\n");
1032                 goto failed_get;
1033         }
1034
1035         caps->props = calloc(1, sizeof(hal_tdm_prop) * props->count_props);
1036         if (!caps->props) {
1037                 ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
1038                 TDM_BACKEND_ERR("alloc failed\n");
1039                 goto failed_get;
1040         }
1041
1042         caps->prop_count = 0;
1043         for (i = 0; i < props->count_props; i++) {
1044                 drmModePropertyPtr prop = drmModeGetProperty(display_data->drm_fd, props->props[i]);
1045                 if (!prop)
1046                         continue;
1047                 snprintf(caps->props[caps->prop_count].name, HAL_TDM_NAME_LEN, "%s", prop->name);
1048                 caps->props[caps->prop_count].id = props->props[i];
1049                 caps->prop_count++;
1050                 drmModeFreeProperty(prop);
1051         }
1052
1053         caps->capabilities |= HAL_TDM_OUTPUT_CAPABILITY_HWC;
1054
1055         drmModeFreeObjectProperties(props);
1056         drmModeFreeCrtc(crtc);
1057         drmModeFreeConnector(connector);
1058
1059         return HAL_TDM_ERROR_NONE;
1060 failed_get:
1061         drmModeFreeCrtc(crtc);
1062         drmModeFreeObjectProperties(props);
1063         drmModeFreeConnector(connector);
1064         free(caps->modes);
1065         free(caps->props);
1066         memset(caps, 0, sizeof(hal_tdm_caps_output));
1067         return ret;
1068 }
1069
1070 hal_tdm_error
1071 drm_output_set_property(hal_tdm_output *output, unsigned int id, hal_tdm_value value)
1072 {
1073         tdm_drm_output *output_data = output;
1074         tdm_drm_display *display_data;
1075         int ret;
1076
1077         RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1078         RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, HAL_TDM_ERROR_INVALID_PARAMETER);
1079
1080         display_data = output_data->display_data;
1081         ret = drmModeObjectSetProperty(display_data->drm_fd,
1082                                                                    output_data->crtc_id, DRM_MODE_OBJECT_CRTC,
1083                                                                    id, value.u32);
1084         if (ret < 0) {
1085                 TDM_BACKEND_ERR("set property failed: %m");
1086                 return HAL_TDM_ERROR_OPERATION_FAILED;
1087         }
1088
1089         return HAL_TDM_ERROR_NONE;
1090 }
1091
1092 hal_tdm_error
1093 drm_output_get_property(hal_tdm_output *output, unsigned int id, hal_tdm_value *value)
1094 {
1095         tdm_drm_output *output_data = output;
1096         tdm_drm_display *display_data;
1097         drmModeObjectPropertiesPtr props;
1098         int i;
1099
1100         RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1101         RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, HAL_TDM_ERROR_INVALID_PARAMETER);
1102         RETURN_VAL_IF_FAIL(value, HAL_TDM_ERROR_INVALID_PARAMETER);
1103
1104         display_data = output_data->display_data;
1105         props = drmModeObjectGetProperties(display_data->drm_fd, output_data->crtc_id,
1106                                                                            DRM_MODE_OBJECT_CRTC);
1107         if (props == NULL) {
1108                 TDM_BACKEND_ERR("get property failed: %m");
1109                 return HAL_TDM_ERROR_OPERATION_FAILED;
1110         }
1111
1112         for (i = 0; i < props->count_props; i++)
1113                 if (props->props[i] == id) {
1114                         (*value).u32 = (uint)props->prop_values[i];
1115                         break;
1116                 }
1117
1118         drmModeFreeObjectProperties(props);
1119
1120         return HAL_TDM_ERROR_NONE;
1121 }
1122
1123 hal_tdm_error
1124 drm_output_wait_vblank(hal_tdm_output *output, int interval, int sync,
1125                                            void *user_data)
1126 {
1127         tdm_drm_output *output_data = output;
1128         tdm_drm_display *display_data;
1129         tdm_drm_event_data *event_data;
1130         uint target_msc;
1131         hal_tdm_error ret;
1132
1133         RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1134
1135         event_data = calloc(1, sizeof(tdm_drm_event_data));
1136         if (!event_data) {
1137                 TDM_BACKEND_ERR("alloc failed");
1138                 return HAL_TDM_ERROR_OUT_OF_MEMORY;
1139         }
1140
1141         display_data = output_data->display_data;
1142
1143         ret = _tdm_drm_display_get_cur_msc(display_data->drm_fd, output_data->pipe,
1144                                                                            &target_msc);
1145         if (ret != HAL_TDM_ERROR_NONE)
1146                 goto failed_vblank;
1147
1148         target_msc += interval;
1149
1150         event_data->type = TDM_DRM_EVENT_TYPE_WAIT;
1151         event_data->output_data = output_data;
1152         event_data->user_data = user_data;
1153
1154         ret = _tdm_drm_display_wait_vblank(display_data->drm_fd, output_data->pipe,
1155                                                                            &target_msc, event_data);
1156         if (ret != HAL_TDM_ERROR_NONE)
1157                 goto failed_vblank;
1158
1159         return HAL_TDM_ERROR_NONE;
1160 failed_vblank:
1161         free(event_data);
1162         return ret;
1163 }
1164
1165 hal_tdm_error
1166 drm_output_set_vblank_handler(hal_tdm_output *output,
1167                                                           hal_tdm_output_vblank_handler func)
1168 {
1169         tdm_drm_output *output_data = output;
1170
1171         RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1172         RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
1173
1174         output_data->vblank_func = func;
1175
1176         return HAL_TDM_ERROR_NONE;
1177 }
1178
1179 hal_tdm_error
1180 drm_output_commit(hal_tdm_output *output, int sync, void *user_data)
1181 {
1182         tdm_drm_output *output_data = output;
1183         tdm_drm_display *display_data;
1184         tdm_drm_layer *layer_data = NULL;
1185         hal_tdm_error ret;
1186         int do_waitvblank = 1;
1187
1188         RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1189
1190         display_data = output_data->display_data;
1191
1192         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1193                 if (layer_data == output_data->primary_layer) {
1194                         ret = _tdm_drm_display_commit_primary_layer(layer_data, user_data,
1195                                                         &do_waitvblank);
1196                         if (ret != HAL_TDM_ERROR_NONE)
1197                                 return ret;
1198                 } else {
1199                         ret = _tdm_drm_display_commit_layer(layer_data);
1200                         if (ret != HAL_TDM_ERROR_NONE)
1201                                 return ret;
1202                 }
1203         }
1204
1205         if (do_waitvblank == 1) {
1206                 tdm_drm_event_data *event_data = calloc(1, sizeof(tdm_drm_event_data));
1207                 uint target_msc;
1208
1209                 if (!event_data) {
1210                         TDM_BACKEND_ERR("alloc failed");
1211                         return HAL_TDM_ERROR_OUT_OF_MEMORY;
1212                 }
1213
1214                 ret = _tdm_drm_display_get_cur_msc(display_data->drm_fd, output_data->pipe,
1215                                                                                    &target_msc);
1216                 if (ret != HAL_TDM_ERROR_NONE) {
1217                         free(event_data);
1218                         return ret;
1219                 }
1220
1221                 target_msc++;
1222
1223                 event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
1224                 event_data->output_data = output_data;
1225                 event_data->user_data = user_data;
1226
1227                 ret = _tdm_drm_display_wait_vblank(display_data->drm_fd, output_data->pipe,
1228                                                                                    &target_msc, event_data);
1229                 if (ret != HAL_TDM_ERROR_NONE) {
1230                         free(event_data);
1231                         return ret;
1232                 }
1233         }
1234
1235         return HAL_TDM_ERROR_NONE;
1236 }
1237
1238 hal_tdm_error
1239 drm_output_set_commit_handler(hal_tdm_output *output,
1240                                                           hal_tdm_output_commit_handler func)
1241 {
1242         tdm_drm_output *output_data = output;
1243
1244         RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1245         RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
1246
1247         output_data->commit_func = func;
1248
1249         return HAL_TDM_ERROR_NONE;
1250 }
1251
1252 hal_tdm_error
1253 drm_output_set_dpms(hal_tdm_output *output, hal_tdm_output_dpms dpms_value)
1254 {
1255         tdm_drm_output *output_data = output;
1256         tdm_drm_display *display_data;
1257         int ret;
1258
1259         RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1260
1261         if (output_data->dpms_prop_id == 0) {
1262                 TDM_BACKEND_WRN("not support DPMS");
1263                 return HAL_TDM_ERROR_OPERATION_FAILED;
1264         }
1265
1266         display_data = output_data->display_data;
1267         ret = drmModeObjectSetProperty(display_data->drm_fd,
1268                                                                    output_data->connector_id, DRM_MODE_OBJECT_CONNECTOR,
1269                                                                    output_data->dpms_prop_id, dpms_value);
1270         if (ret < 0) {
1271                 TDM_BACKEND_ERR("set dpms failed: %m");
1272                 return HAL_TDM_ERROR_OPERATION_FAILED;
1273         }
1274
1275         output_data->current_dpms = dpms_value;
1276
1277         return HAL_TDM_ERROR_NONE;
1278 }
1279
1280 hal_tdm_error
1281 drm_output_get_dpms(hal_tdm_output *output, hal_tdm_output_dpms *dpms_value)
1282 {
1283         tdm_drm_output *output_data = output;
1284         tdm_drm_display *display_data;
1285         drmModeObjectPropertiesPtr props;
1286         int i;
1287
1288         RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1289         RETURN_VAL_IF_FAIL(dpms_value, HAL_TDM_ERROR_INVALID_PARAMETER);
1290
1291         display_data = output_data->display_data;
1292         props = drmModeObjectGetProperties(display_data->drm_fd, output_data->connector_id,
1293                                                                            DRM_MODE_OBJECT_CONNECTOR);
1294         if (props == NULL) {
1295                 TDM_BACKEND_ERR("get property failed: %m");
1296                 return HAL_TDM_ERROR_OPERATION_FAILED;
1297         }
1298
1299         for (i = 0; i < props->count_props; i++)
1300                 if (props->props[i] == output_data->dpms_prop_id) {
1301                         *dpms_value = (uint)props->prop_values[i];
1302                         break;
1303                 }
1304
1305         drmModeFreeObjectProperties(props);
1306
1307         return HAL_TDM_ERROR_NONE;
1308 }
1309
1310 hal_tdm_error
1311 drm_output_set_mode(hal_tdm_output *output, const hal_tdm_output_mode *mode)
1312 {
1313         tdm_drm_output *output_data = output;
1314         hal_tdm_error ret = HAL_TDM_ERROR_NONE;
1315
1316         RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1317         RETURN_VAL_IF_FAIL(mode, HAL_TDM_ERROR_INVALID_PARAMETER);
1318
1319         /* create or replace the target_window when the output mode is set */
1320         ret = drm_hwc_target_window_set_info(output_data->hwc_data, mode->hdisplay, mode->vdisplay);
1321         if (ret != HAL_TDM_ERROR_NONE) {
1322                 TDM_BACKEND_ERR("set info target hwc window failed (%d)", ret);
1323                 return ret;
1324         }
1325
1326         output_data->current_mode = mode;
1327         output_data->mode_changed = 1;
1328
1329         return HAL_TDM_ERROR_NONE;
1330 }
1331
1332 hal_tdm_error
1333 drm_output_get_mode(hal_tdm_output *output, const hal_tdm_output_mode **mode)
1334 {
1335         tdm_drm_output *output_data = output;
1336
1337         RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1338         RETURN_VAL_IF_FAIL(mode, HAL_TDM_ERROR_INVALID_PARAMETER);
1339
1340         *mode = output_data->current_mode;
1341
1342         return HAL_TDM_ERROR_NONE;
1343 }
1344
1345 hal_tdm_hwc *
1346 drm_output_get_hwc(hal_tdm_output *output, hal_tdm_error *error)
1347 {
1348         tdm_drm_hwc *hwc_data = NULL;
1349         tdm_drm_output *output_data = output;
1350         hal_tdm_error ret = HAL_TDM_ERROR_NONE;
1351
1352         if (!output_data) {
1353                 TDM_BACKEND_ERR("invalid params");
1354                 if (error)
1355                         *error = HAL_TDM_ERROR_INVALID_PARAMETER;
1356                 return NULL;
1357         }
1358
1359         if (output_data->hwc_data) {
1360                 TDM_BACKEND_INFO("hwc_data already exists");
1361                 if (error)
1362                         *error = HAL_TDM_ERROR_NONE;
1363                 return output_data->hwc_data;
1364         }
1365
1366         hwc_data = calloc(1, sizeof(tdm_drm_hwc));
1367         if (!hwc_data) {
1368                 TDM_BACKEND_ERR("alloc failed");
1369                 if (error)
1370                         *error = HAL_TDM_ERROR_OUT_OF_MEMORY;
1371                 return NULL;
1372         }
1373         hwc_data->output_data = output_data;
1374
1375         LIST_INITHEAD(&hwc_data->hwc_window_list);
1376
1377         output_data->hwc_data = hwc_data;
1378
1379         ret = drm_hwc_initailize_target_window(output_data->hwc_data);
1380         if (ret != HAL_TDM_ERROR_NONE) {
1381                 TDM_BACKEND_ERR("create target hwc window failed (%d)", ret);
1382                 free(hwc_data);
1383                 if (error)
1384                         *error = ret;
1385                 return NULL;
1386         }
1387
1388         if (error)
1389                 *error = HAL_TDM_ERROR_NONE;
1390
1391         return hwc_data;
1392 }
1393
1394 hal_tdm_error
1395 drm_output_set_status_handler(hal_tdm_output *output,
1396                                                           hal_tdm_output_status_handler func,
1397                                                           void *user_data)
1398 {
1399         tdm_drm_output *output_data = output;
1400
1401         RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1402         RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
1403
1404         output_data->status_func = func;
1405         output_data->status_user_data = user_data;
1406
1407         return HAL_TDM_ERROR_NONE;
1408 }
1409
1410 hal_tdm_error
1411 drm_layer_get_capability(tdm_drm_layer *layer, tdm_drm_caps_layer *caps)
1412 {
1413         tdm_drm_layer *layer_data = layer;
1414         tdm_drm_display *display_data;
1415         drmModePlanePtr plane = NULL;
1416         drmModeObjectPropertiesPtr props = NULL;
1417         int i, format_count = 0;
1418         hal_tdm_error ret;
1419
1420         RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1421         RETURN_VAL_IF_FAIL(caps, HAL_TDM_ERROR_INVALID_PARAMETER);
1422
1423         memset(caps, 0, sizeof(tdm_drm_caps_layer));
1424
1425         display_data = layer_data->display_data;
1426         plane = drmModeGetPlane(display_data->drm_fd, layer_data->plane_id);
1427         if (!plane) {
1428                 TDM_BACKEND_ERR("get plane failed: %m");
1429                 ret = HAL_TDM_ERROR_OPERATION_FAILED;
1430                 goto failed_get;
1431         }
1432
1433         caps->capabilities = layer_data->capabilities;
1434         caps->zpos = layer_data->zpos;  /* if VIDEO layer, zpos is -1 */
1435
1436         caps->format_count = plane->count_formats;
1437         caps->formats = calloc(1, sizeof(tbm_format) * caps->format_count);
1438         if (!caps->formats) {
1439                 ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
1440                 TDM_BACKEND_ERR("alloc failed\n");
1441                 goto failed_get;
1442         }
1443
1444         for (i = 0; i < caps->format_count; i++) {
1445                 /* TODO: kernel reports wrong formats */
1446                 if (plane->formats[i] != DRM_FORMAT_XRGB8888 &&
1447                         plane->formats[i] != DRM_FORMAT_ARGB8888) {
1448                         TDM_BACKEND_WRN("plane(%d) zpos(%d) %c%c%c%c skipped",
1449                                         layer_data->plane_id, layer_data->zpos, FOURCC_STR(plane->formats[i]));
1450                         continue;
1451                 }
1452                 caps->formats[format_count] = tdm_drm_format_to_tbm_format(plane->formats[i]);
1453                 format_count++;
1454         }
1455
1456         caps->format_count = format_count;
1457
1458         props = drmModeObjectGetProperties(display_data->drm_fd, layer_data->plane_id,
1459                                                                            DRM_MODE_OBJECT_PLANE);
1460         if (!props) {
1461                 ret = HAL_TDM_ERROR_OPERATION_FAILED;
1462                 TDM_BACKEND_ERR("get plane properties failed: %m\n");
1463                 goto failed_get;
1464         }
1465
1466         caps->props = calloc(1, sizeof(hal_tdm_prop) * props->count_props);
1467         if (!caps->props) {
1468                 ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
1469                 TDM_BACKEND_ERR("alloc failed\n");
1470                 goto failed_get;
1471         }
1472
1473         caps->prop_count = 0;
1474         for (i = 0; i < props->count_props; i++) {
1475                 drmModePropertyPtr prop = drmModeGetProperty(display_data->drm_fd, props->props[i]);
1476                 if (!prop)
1477                         continue;
1478                 if (!strncmp(prop->name, "type", HAL_TDM_NAME_LEN)) {
1479                         drmModeFreeProperty(prop);
1480                         continue;
1481                 }
1482                 if (!strncmp(prop->name, "zpos", HAL_TDM_NAME_LEN)) {
1483                         drmModeFreeProperty(prop);
1484                         continue;
1485                 }
1486                 snprintf(caps->props[caps->prop_count].name, HAL_TDM_NAME_LEN, "%s", prop->name);
1487                 caps->props[caps->prop_count].id = props->props[i];
1488                 caps->prop_count++;
1489                 drmModeFreeProperty(prop);
1490         }
1491
1492         drmModeFreeObjectProperties(props);
1493         drmModeFreePlane(plane);
1494
1495         return HAL_TDM_ERROR_NONE;
1496 failed_get:
1497         drmModeFreeObjectProperties(props);
1498         drmModeFreePlane(plane);
1499         free(caps->formats);
1500         free(caps->props);
1501         memset(caps, 0, sizeof(tdm_drm_caps_layer));
1502         return ret;
1503 }
1504
1505 hal_tdm_error
1506 drm_layer_set_property(tdm_drm_layer *layer, unsigned int id, hal_tdm_value value)
1507 {
1508         tdm_drm_layer *layer_data = layer;
1509         tdm_drm_display *display_data;
1510         int ret;
1511
1512         RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1513         RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, HAL_TDM_ERROR_INVALID_PARAMETER);
1514
1515         display_data = layer_data->display_data;
1516         ret = drmModeObjectSetProperty(display_data->drm_fd,
1517                                                                    layer_data->plane_id, DRM_MODE_OBJECT_PLANE,
1518                                                                    id, value.u32);
1519         if (ret < 0) {
1520                 TDM_BACKEND_ERR("set property failed: %m");
1521                 return HAL_TDM_ERROR_OPERATION_FAILED;
1522         }
1523
1524         return HAL_TDM_ERROR_NONE;
1525 }
1526
1527 hal_tdm_error
1528 drm_layer_get_property(tdm_drm_layer *layer, unsigned int id, hal_tdm_value *value)
1529 {
1530         tdm_drm_layer *layer_data = layer;
1531         tdm_drm_display *display_data;
1532         drmModeObjectPropertiesPtr props;
1533         int i;
1534
1535         RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1536         RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, HAL_TDM_ERROR_INVALID_PARAMETER);
1537         RETURN_VAL_IF_FAIL(value, HAL_TDM_ERROR_INVALID_PARAMETER);
1538
1539         display_data = layer_data->display_data;
1540         props = drmModeObjectGetProperties(display_data->drm_fd, layer_data->plane_id,
1541                                                                            DRM_MODE_OBJECT_PLANE);
1542         if (props == NULL) {
1543                 TDM_BACKEND_ERR("get property failed: %m");
1544                 return HAL_TDM_ERROR_OPERATION_FAILED;
1545         }
1546
1547         for (i = 0; i < props->count_props; i++)
1548                 if (props->props[i] == id) {
1549                         (*value).u32 = (uint)props->prop_values[i];
1550                         break;
1551                 }
1552
1553         drmModeFreeObjectProperties(props);
1554
1555         return HAL_TDM_ERROR_NONE;
1556 }
1557
1558 hal_tdm_error
1559 drm_layer_set_info(tdm_drm_layer *layer, tdm_drm_layer_info *info)
1560 {
1561         tdm_drm_layer *layer_data = layer;
1562
1563         RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1564         RETURN_VAL_IF_FAIL(info, HAL_TDM_ERROR_INVALID_PARAMETER);
1565
1566         layer_data->info = *info;
1567         layer_data->info_changed = 1;
1568
1569         return HAL_TDM_ERROR_NONE;
1570 }
1571
1572 hal_tdm_error
1573 drm_layer_get_info(tdm_drm_layer *layer, tdm_drm_layer_info *info)
1574 {
1575         tdm_drm_layer *layer_data = layer;
1576
1577         RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1578         RETURN_VAL_IF_FAIL(info, HAL_TDM_ERROR_INVALID_PARAMETER);
1579
1580         *info = layer_data->info;
1581
1582         return HAL_TDM_ERROR_NONE;
1583 }
1584
1585 static tdm_drm_display_buffer *
1586 _tdm_drm_display_find_buffer(tdm_drm_display *display_data, tbm_surface_h buffer)
1587 {
1588         tdm_drm_display_buffer *display_buffer = NULL;
1589
1590         LIST_FOR_EACH_ENTRY(display_buffer, &display_data->buffer_list, link) {
1591                 if (display_buffer->buffer == buffer)
1592                         return display_buffer;
1593         }
1594
1595         return NULL;
1596 }
1597
1598 static void
1599 _tdm_drm_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
1600 {
1601         tdm_drm_display *display_data;
1602         tdm_drm_display_buffer *display_buffer;
1603         tdm_drm_layer *layer_data = NULL;
1604         tdm_drm_output *output_data = NULL;
1605         char buf[256] = {0,};
1606         char *ret_tmp;
1607
1608         if (!user_data) {
1609                 TDM_BACKEND_ERR("no user_data");
1610                 return;
1611         }
1612         if (!buffer) {
1613                 TDM_BACKEND_ERR("no buffer");
1614                 return;
1615         }
1616
1617         display_data = (tdm_drm_display *) user_data;
1618
1619         display_buffer = _tdm_drm_display_find_buffer(display_data, buffer);
1620         if (!display_buffer) {
1621                 TDM_BACKEND_ERR("no display_buffer");
1622                 return;
1623         }
1624
1625         LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link) {
1626                 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1627                         if (display_buffer == layer_data->display_buffer)
1628                                 layer_data->display_buffer = NULL;
1629                 }
1630         }
1631
1632         if (display_buffer->fb_id > 0) {
1633                 if (drmModeRmFB(display_data->drm_fd, display_buffer->fb_id) < 0) {
1634                         ret_tmp = strerror_r(errno, buf, sizeof(buf));
1635                         TDM_BACKEND_ERR("rm fb failed: %d(%s,%s)\n", errno, buf, ret_tmp);
1636                 }
1637         }
1638
1639         TDM_BACKEND_DBG("destroy buffer:%p", display_buffer->buffer);
1640
1641         LIST_DEL(&display_buffer->link);
1642         free(display_buffer);
1643 }
1644
1645 static tdm_drm_display_buffer *
1646 _tdm_drm_display_create_buffer(tdm_drm_display *display_data, tbm_surface_h buffer, hal_tdm_error *err)
1647 {
1648         tdm_drm_display_buffer *display_buffer = NULL;
1649         int count, i, ret;
1650
1651         display_buffer = calloc(1, sizeof(tdm_drm_display_buffer));
1652         if (!display_buffer) {
1653                 TDM_BACKEND_ERR("alloc failed");
1654                 if (err)
1655                         *err = HAL_TDM_ERROR_OUT_OF_MEMORY;
1656                 return NULL;
1657         }
1658
1659         display_buffer->buffer = buffer;
1660
1661         ret = tbm_surface_internal_add_destroy_handler(buffer, _tdm_drm_display_cb_destroy_buffer, display_data);
1662         if (ret == 0) {
1663                 TDM_BACKEND_ERR("add destroy handler fail");
1664                 free(display_buffer);
1665                 if (err)
1666                         *err = HAL_TDM_ERROR_OPERATION_FAILED;
1667                 return NULL;
1668         }
1669
1670         display_buffer->width = tbm_surface_get_width(buffer);
1671         display_buffer->height = tbm_surface_get_height(buffer);
1672         display_buffer->format = tbm_surface_get_format(buffer);
1673         display_buffer->count = tbm_surface_internal_get_num_bos(buffer);
1674         count = tbm_surface_internal_get_num_planes(display_buffer->format);
1675         TDM_BACKEND_DBG("create buffer:%p %dx%d %c%c%c%c bo_num:%d plane_num:%d",
1676                         buffer, display_buffer->width, display_buffer->height,
1677                         FOURCC_STR(display_buffer->format), display_buffer->count, count);
1678
1679         for (i = 0; i < count; i++) {
1680                 int bo_idx = 0;
1681                 tbm_bo bo = NULL;
1682
1683                 bo_idx = tbm_surface_internal_get_plane_bo_idx(buffer, i);
1684                 bo = tbm_surface_internal_get_bo(buffer, bo_idx);
1685                 display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
1686
1687                 tbm_surface_internal_get_plane_data(buffer, i, &display_buffer->size,
1688                                                                                         &display_buffer->offsets[i],
1689                                                                                         &display_buffer->pitches[i]);
1690                 TDM_BACKEND_DBG("  create buffer:%p plane%d(size:%d offset:%d pitch:%d) bo%d(handle:%d)",
1691                                 buffer, i, display_buffer->size, display_buffer->offsets[i],
1692                                 display_buffer->pitches[i], bo_idx, display_buffer->handles[i]);
1693         }
1694
1695         ret = drmModeAddFB2(display_data->drm_fd, display_buffer->width, display_buffer->height,
1696                                 display_buffer->format, display_buffer->handles, display_buffer->pitches,
1697                                 display_buffer->offsets, &display_buffer->fb_id, 0);
1698         if (ret < 0) {
1699                 TDM_BACKEND_ERR("add fb failed: %m");
1700                 free(display_buffer);
1701                 if (err)
1702                         *err = HAL_TDM_ERROR_OPERATION_FAILED;
1703                 tbm_surface_internal_remove_destroy_handler(buffer, _tdm_drm_display_cb_destroy_buffer, display_data);
1704                 return NULL;
1705         }
1706
1707         TDM_BACKEND_DBG("display_data->drm_fd : %d, display_buffer->fb_id:%u", display_data->drm_fd,
1708                         display_buffer->fb_id);
1709
1710         if (IS_RGB(display_buffer->format))
1711                 display_buffer->width = display_buffer->pitches[0] >> 2;
1712         else
1713                 display_buffer->width = display_buffer->pitches[0];
1714
1715         LIST_ADDTAIL(&display_buffer->link, &display_data->buffer_list);
1716
1717         if (err)
1718                 *err = HAL_TDM_ERROR_NONE;
1719
1720         return display_buffer;
1721 }
1722
1723 void
1724 _hal_tdm_display_destroy_buffer_list(tdm_drm_display *display_data)
1725 {
1726         tdm_drm_display_buffer *b = NULL, *bb = NULL;
1727
1728         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &display_data->buffer_list, link) {
1729                 tbm_surface_internal_remove_destroy_handler(b->buffer, _tdm_drm_display_cb_destroy_buffer, display_data);
1730                 _tdm_drm_display_cb_destroy_buffer(b->buffer, display_data);
1731         }
1732 }
1733
1734 hal_tdm_error
1735 drm_layer_set_buffer(tdm_drm_layer *layer, tbm_surface_h buffer)
1736 {
1737         tdm_drm_layer *layer_data = layer;
1738         tdm_drm_display *display_data;
1739         tdm_drm_display_buffer *display_buffer;
1740         hal_tdm_error err = HAL_TDM_ERROR_NONE;
1741
1742         RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1743         RETURN_VAL_IF_FAIL(buffer, HAL_TDM_ERROR_INVALID_PARAMETER);
1744
1745         TDM_BACKEND_DBG("layer[%p]zpos[%d] buffer:%p", layer, layer_data->zpos, buffer);
1746
1747         display_data = layer_data->display_data;
1748         display_buffer = _tdm_drm_display_find_buffer(display_data, buffer);
1749         if (!display_buffer) {
1750                 display_buffer = _tdm_drm_display_create_buffer(display_data, buffer, &err);
1751                 RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
1752         }
1753
1754         if (layer_data->display_buffer != display_buffer) {
1755                 if (layer_data->display_buffer)
1756                         tbm_surface_internal_unref(layer_data->display_buffer->buffer);
1757
1758                 layer_data->display_buffer = display_buffer;
1759                 tbm_surface_internal_ref(layer_data->display_buffer->buffer);
1760                 layer_data->display_buffer_changed = 1;
1761         }
1762
1763         return HAL_TDM_ERROR_NONE;
1764 }
1765
1766 hal_tdm_error
1767 drm_layer_unset_buffer(tdm_drm_layer *layer)
1768 {
1769         tdm_drm_layer *layer_data = layer;
1770
1771         RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1772
1773         if (!(layer_data->capabilities & TDM_DRM_LAYER_CAPABILITY_PRIMARY) && layer_data->display_buffer) {
1774                 tbm_surface_internal_unref(layer_data->display_buffer->buffer);
1775                 layer_data->display_buffer = NULL;
1776         }
1777
1778         layer_data->display_buffer_changed = 1;
1779
1780         return HAL_TDM_ERROR_NONE;
1781 }
1782
1783 tdm_drm_layer *
1784 drm_output_data_get_layer_data(tdm_drm_output *output_data, int layer_zpos)
1785 {
1786         tdm_drm_layer *l = NULL;
1787
1788         RETURN_VAL_IF_FAIL(output_data, NULL);
1789
1790         LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link) {
1791                 if (l->zpos == layer_zpos)
1792                         return l;
1793         }
1794
1795         return NULL;
1796 }