Add missing boilerplate
[platform/adaptation/libtdm-drm.git] / src / libtdm-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 <drm_fourcc.h>
36 #include <tdm_helper.h>
37
38 #include "tdm_drm.h"
39 #include "tdm_drm_pp.h"
40
41 static drmModeModeInfoPtr
42 _tdm_drm_display_get_mode(tdm_drm_output_data *output_data)
43 {
44         int i;
45
46         if (!output_data->current_mode) {
47                 TDM_ERR("no output_data->current_mode");
48                 return NULL;
49         }
50
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)))
59                         return drm_mode;
60         }
61
62         return NULL;
63 }
64
65 static void
66 _tdm_drm_display_to_tdm_mode(drmModeModeInfoPtr drm_mode,
67                                                          tdm_output_mode *tdm_mode)
68 {
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);
84 }
85
86 static tdm_error
87 _tdm_drm_display_get_cur_msc(int fd, int pipe, uint *msc)
88 {
89         drmVBlank vbl;
90
91         vbl.request.type = DRM_VBLANK_RELATIVE;
92         if (pipe > 0)
93                 vbl.request.type |= DRM_VBLANK_SECONDARY;
94
95         vbl.request.sequence = 0;
96         if (drmWaitVBlank(fd, &vbl)) {
97                 TDM_ERR("get vblank counter failed: %m");
98                 *msc = 0;
99                 return TDM_ERROR_OPERATION_FAILED;
100         }
101
102         *msc = vbl.reply.sequence;
103
104         return TDM_ERROR_NONE;
105 }
106
107 static tdm_error
108 _tdm_drm_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data)
109 {
110         drmVBlank vbl;
111
112         vbl.request.type =  DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
113         if (pipe > 0)
114                 vbl.request.type |= DRM_VBLANK_SECONDARY;
115
116         vbl.request.sequence = *target_msc;
117         vbl.request.signal = (unsigned long)(uintptr_t)data;
118
119         if (drmWaitVBlank(fd, &vbl)) {
120                 *target_msc = 0;
121                 TDM_ERR("wait vblank failed: %m");
122                 return TDM_ERROR_OPERATION_FAILED;
123         }
124
125         *target_msc = vbl.reply.sequence;
126
127         return TDM_ERROR_NONE;
128 }
129
130 static tdm_error
131 _tdm_drm_output_update_status(tdm_drm_output_data *output_data,
132                                                           tdm_output_conn_status status)
133 {
134         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
135
136         if (output_data->status == status)
137                 return TDM_ERROR_NONE;
138
139         output_data->status = status;
140
141         if (output_data->status_func)
142                 output_data->status_func(output_data, status,
143                                                                  output_data->status_user_data);
144
145         return TDM_ERROR_NONE;
146 }
147
148 static tdm_error
149 _tdm_drm_display_commit_primary_layer(tdm_drm_layer_data *layer_data,
150                                                                           void *user_data, int *do_waitvblank)
151 {
152         tdm_drm_data *drm_data = layer_data->drm_data;
153         tdm_drm_output_data *output_data = layer_data->output_data;
154
155         if (output_data->mode_changed && layer_data->display_buffer_changed) {
156                 drmModeModeInfoPtr mode;
157
158                 if (!layer_data->display_buffer) {
159                         TDM_ERR("primary layer should have a buffer for modestting");
160                         return TDM_ERROR_BAD_REQUEST;
161                 }
162
163                 output_data->mode_changed = 0;
164                 layer_data->display_buffer_changed = 0;
165                 layer_data->info_changed = 0;
166
167                 mode = _tdm_drm_display_get_mode(output_data);
168                 if (!mode) {
169                         TDM_ERR("couldn't find proper mode");
170                         return TDM_ERROR_BAD_REQUEST;
171                 }
172
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;
178                 }
179
180                 _tdm_drm_output_update_status(output_data, TDM_OUTPUT_CONN_STATUS_MODE_SETTED);
181
182                 *do_waitvblank = 1;
183                 return TDM_ERROR_NONE;
184         } else if (layer_data->display_buffer_changed) {
185                 layer_data->display_buffer_changed = 0;
186
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;
192                         }
193
194                         if (output_data->status == TDM_OUTPUT_CONN_STATUS_MODE_SETTED)
195                                 _tdm_drm_output_update_status(output_data, TDM_OUTPUT_CONN_STATUS_CONNECTED);
196
197                         *do_waitvblank = 1;
198                 } else {
199                         tdm_drm_event_data *event_data = calloc(1, sizeof(tdm_drm_event_data));
200
201                         if (!event_data) {
202                                 TDM_ERR("alloc failed");
203                                 return TDM_ERROR_OUT_OF_MEMORY;
204                         }
205
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");
212                                 free(event_data);
213                                 return TDM_ERROR_OPERATION_FAILED;
214                         }
215                         *do_waitvblank = 0;
216                 }
217         }
218
219         return TDM_ERROR_NONE;
220 }
221
222 static tdm_error
223 _tdm_drm_display_commit_layer(tdm_drm_layer_data *layer_data)
224 {
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;
228         int crtc_w;
229
230         if (!layer_data->display_buffer_changed && !layer_data->info_changed)
231                 return TDM_ERROR_NONE;
232
233         if (output_data->current_mode)
234                 crtc_w = output_data->current_mode->hdisplay;
235         else {
236                 drmModeCrtcPtr crtc = drmModeGetCrtc(drm_data->drm_fd, output_data->crtc_id);
237                 if (!crtc) {
238                         TDM_ERR("getting crtc failed");
239                         return TDM_ERROR_OPERATION_FAILED;
240                 }
241                 crtc_w = crtc->width;
242                 if (crtc_w == 0) {
243                         TDM_ERR("getting crtc width failed");
244                         drmModeFreeCrtc(crtc);
245                         return TDM_ERROR_OPERATION_FAILED;
246                 }
247                 drmModeFreeCrtc(crtc);
248         }
249
250         layer_data->display_buffer_changed = 0;
251         layer_data->info_changed = 0;
252
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);
257
258                 return TDM_ERROR_NONE;
259         }
260
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;
266
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;
274         }
275
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);
283
284         return TDM_ERROR_NONE;
285 }
286
287 static void
288 _tdm_drm_display_cb_event(int fd, unsigned int sequence,
289                                                   unsigned int tv_sec, unsigned int tv_usec,
290                                                   void *user_data)
291 {
292         tdm_drm_event_data *event_data = user_data;
293         tdm_drm_output_data *output_data;
294         tdm_drm_hwc_data *hwc_data;
295
296         if (!event_data) {
297                 TDM_ERR("no event data");
298                 return;
299         }
300
301         output_data = event_data->output_data;
302
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;
307                         if (!hwc_data) {
308                                 TDM_ERR("no hwc_data");
309                                 break;
310                         }
311
312                         if (hwc_data->commit_func)
313                                 hwc_data->commit_func(hwc_data, sequence,
314                                                                                  tv_sec, tv_usec,
315                                                                                  event_data->user_data);
316                 } else {
317                         if (output_data->commit_func)
318                                 output_data->commit_func(output_data, sequence, tv_sec, tv_usec,
319                                                                                  event_data->user_data);
320                 }
321                 break;
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);
326                 break;
327         case TDM_DRM_EVENT_TYPE_COMMIT:
328                 if (output_data->hwc_enable) {
329                         hwc_data = output_data->hwc_data;
330                         if (!hwc_data) {
331                                 TDM_ERR("no hwc_data");
332                                 break;
333                         }
334
335                         if (hwc_data->commit_func)
336                                 hwc_data->commit_func(hwc_data, sequence,
337                                                                                  tv_sec, tv_usec,
338                                                                                  event_data->user_data);
339                 } else {
340                         if (output_data->commit_func)
341                                 output_data->commit_func(output_data, sequence,
342                                                                                  tv_sec, tv_usec,
343                                                                                  event_data->user_data);
344                 }
345                 break;
346         default:
347                 break;
348         }
349
350         free(event_data);
351 }
352
353 static tdm_error
354 _tdm_drm_display_create_layer_list(tdm_drm_data *drm_data)
355 {
356         tdm_drm_output_data *output_data = NULL;
357         int i;
358
359         if (LIST_IS_EMPTY(&drm_data->output_list)) {
360                 TDM_ERR("no output");
361                 return TDM_ERROR_OPERATION_FAILED;
362         }
363
364         /* The TDM drm backend only support one output. */
365         LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link) {
366                 break;
367         }
368
369         if (drm_data->plane_res->count_planes == 0) {
370                 TDM_ERR("no layer error");
371                 return TDM_ERROR_OPERATION_FAILED;
372         }
373
374         for (i = 0; i < drm_data->plane_res->count_planes; i++) {
375                 tdm_drm_layer_data *layer_data;
376                 drmModePlanePtr plane;
377
378                 plane = drmModeGetPlane(drm_data->drm_fd, drm_data->plane_res->planes[i]);
379                 if (!plane) {
380                         TDM_ERR("no plane");
381                         continue;
382                 }
383
384                 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
385                         drmModeFreePlane(plane);
386                         continue;
387                 }
388
389                 layer_data = calloc(1, sizeof(tdm_drm_layer_data));
390                 if (!layer_data) {
391                         TDM_ERR("alloc failed");
392                         drmModeFreePlane(plane);
393                         continue;
394                 }
395
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];
399
400                 layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
401                                                                    TDM_LAYER_CAPABILITY_GRAPHIC;
402                 output_data->primary_layer = layer_data;
403
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);
407
408                 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
409
410                 drmModeFreePlane(plane);
411
412                 /* can't take care of other planes for various hardware devices */
413                 break;
414         }
415
416         return TDM_ERROR_NONE;
417 }
418
419 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4  && LIBDRM_MICRO_VERSION >= 47
420
421 static tdm_error
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,
425                                                           int *is_immutable)
426 {
427         drmModeObjectPropertiesPtr props = NULL;
428         int i;
429
430         props = drmModeObjectGetProperties(drm_data->drm_fd, obj_id, obj_type);
431         if (!props)
432                 return TDM_ERROR_OPERATION_FAILED;
433
434         for (i = 0; i < props->count_props; i++) {
435                 drmModePropertyPtr prop = drmModeGetProperty(drm_data->drm_fd,
436                                                                   props->props[i]);
437
438                 if (!prop)
439                         continue;
440
441                 if (!strcmp(prop->name, name)) {
442                         if (is_immutable)
443                                 *is_immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
444                         if (value)
445                                 *value = (unsigned int)props->prop_values[i];
446                         drmModeFreeProperty(prop);
447                         drmModeFreeObjectProperties(props);
448                         return TDM_ERROR_NONE;
449                 }
450
451                 drmModeFreeProperty(prop);
452         }
453         drmModeFreeObjectProperties(props);
454         TDM_DBG("coundn't find '%s' property", name);
455         return TDM_ERROR_OPERATION_FAILED;
456 }
457
458 static tdm_error
459 _tdm_drm_display_create_layer_list_type(tdm_drm_data *drm_data)
460 {
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;
467         tdm_error ret;
468         int i;
469
470         if (LIST_IS_EMPTY(&drm_data->output_list)) {
471                 TDM_ERR("no output");
472                 return TDM_ERROR_OPERATION_FAILED;
473         }
474
475         /* The TDM drm backend only support one output. */
476         LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link) {
477                 break;
478         }
479
480         ret = _tdm_drm_display_get_property(drm_data,
481                                                                                 drm_data->plane_res->planes[0],
482                                                                                 DRM_MODE_OBJECT_PLANE, "type", &type,
483                                                                                 NULL);
484         if (ret != TDM_ERROR_NONE) {
485                 TDM_ERR("plane doesn't have 'type' property. Call a fallback function");
486
487                 /* if a plane doesn't have "type" property, we call a fallback function
488                  * as default
489                  */
490                 return _tdm_drm_display_create_layer_list(drm_data);
491         }
492
493         planes = calloc(drm_data->plane_res->count_planes, sizeof(drmModePlanePtr));
494         if (!planes) {
495                 TDM_ERR("alloc failed");
496                 goto failed;
497         }
498
499         types = calloc(drm_data->plane_res->count_planes, sizeof(unsigned int));
500         if (!types) {
501                 TDM_ERR("alloc failed");
502                 goto failed;
503         }
504
505         plane_cnt = 0;
506         for (i = 0; i < drm_data->plane_res->count_planes; i++) {
507                 drmModePlanePtr plane;
508
509                 plane = drmModeGetPlane(drm_data->drm_fd, drm_data->plane_res->planes[i]);
510                 if (!plane) {
511                         TDM_ERR("no plane(%d)", drm_data->plane_res->planes[i]);
512                         goto failed;
513                 }
514
515                 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
516                         drmModeFreePlane(plane);
517                         continue;
518                 }
519
520                 ret = _tdm_drm_display_get_property(drm_data,
521                                                                                         drm_data->plane_res->planes[i],
522                                                                                         DRM_MODE_OBJECT_PLANE, "type", &type,
523                                                                                         NULL);
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]);
528                         goto failed;
529                 }
530
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);
536                         continue;
537                 }
538
539                 planes[plane_cnt] = plane;
540                 types[plane_cnt] = type;
541                 plane_cnt++;
542         }
543
544         primary_cnt = ovl_cnt = cursor_cnt = 0;
545         for (i = 0; i < plane_cnt; i++) {
546                 if (types[i] == DRM_PLANE_TYPE_CURSOR)
547                         cursor_cnt++;
548                 else if (types[i] == DRM_PLANE_TYPE_OVERLAY)
549                         ovl_cnt++;
550                 else if (types[i] == DRM_PLANE_TYPE_PRIMARY)
551                         primary_cnt++;
552                 else
553                         TDM_ERR("invalid type(%d)", types[i]);
554         }
555
556         if (primary_cnt != 1) {
557                 TDM_ERR("primary layer count(%d) should be one", primary_cnt);
558                 goto failed;
559         }
560
561         opos_next = 1;
562         cpos_next = ovl_cnt;
563         for (i = 0; i < plane_cnt; i++) {
564                 tdm_drm_layer_data *layer_data;
565
566                 layer_data = calloc(1, sizeof(tdm_drm_layer_data));
567                 if (!layer_data) {
568                         TDM_ERR("alloc failed");
569                         goto failed;
570                 }
571
572                 layer_data->drm_data = drm_data;
573                 layer_data->output_data = output_data;
574                 layer_data->plane_id = planes[i]->plane_id;
575
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;
589                 } else {
590                         free(layer_data);
591                         continue;
592                 }
593
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);
597
598                 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
599         }
600
601         for (i = 0; i < plane_cnt; i++)
602                 if (planes[i])
603                         drmModeFreePlane(planes[i]);
604
605         free(planes);
606         free(types);
607
608         return TDM_ERROR_NONE;
609
610 failed:
611         if (planes) {
612                 for (i = 0; i < drm_data->plane_res->count_planes; i++)
613                         if (planes[i])
614                                 drmModeFreePlane(planes[i]);
615                 free(planes);
616         }
617
618         free(types);
619
620         return TDM_ERROR_OPERATION_FAILED;
621 }
622 #endif
623
624 tdm_error
625 tdm_drm_display_create_layer_list(tdm_drm_data *drm_data)
626 {
627         tdm_drm_output_data *output_data = NULL;
628         tdm_error ret;
629
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);
633         else
634 #endif
635                 ret = _tdm_drm_display_create_layer_list(drm_data);
636
637         if (ret != TDM_ERROR_NONE)
638                 return ret;
639
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;
644                 }
645         }
646
647         return TDM_ERROR_NONE;
648 }
649
650 void
651 tdm_drm_display_destroy_output_list(tdm_drm_data *drm_data)
652 {
653         tdm_drm_output_data *o = NULL, *oo = NULL;
654         tdm_drm_hwc_data *hwc_data = NULL;
655
656         if (LIST_IS_EMPTY(&drm_data->output_list))
657                 return;
658
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);
663
664                 LIST_DEL(&o->link);
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) {
668                                 LIST_DEL(&l->link);
669                                 if (l->display_buffer)
670                                         tbm_surface_internal_unref(l->display_buffer->buffer);
671                                 free(l);
672                         }
673                 }
674                 free(o->drm_modes);
675                 free(o->output_modes);
676                 free(o);
677         }
678 }
679
680 void
681 tdm_drm_display_update_output_status(tdm_drm_data *drm_data)
682 {
683         tdm_drm_output_data *output_data = NULL;
684
685         if (LIST_IS_EMPTY(&drm_data->output_list))
686                 return;
687
688         LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link) {
689                 drmModeConnectorPtr connector;
690                 tdm_output_conn_status new_status;
691
692                 connector = drmModeGetConnector(drm_data->drm_fd,
693                                                                                 output_data->connector_id);
694                 if (!connector) {
695                         TDM_ERR("no connector: %d", output_data->connector_id);
696                         continue;
697                 }
698
699                 if (connector->connection == DRM_MODE_CONNECTED)
700                         new_status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
701                 else
702                         new_status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
703
704                 _tdm_drm_output_update_status(output_data, new_status);
705
706                 drmModeFreeConnector(connector);
707         }
708 }
709
710 tdm_error
711 tdm_drm_display_create_output_list(tdm_drm_data *drm_data)
712 {
713         tdm_drm_output_data *output_data;
714         int i;
715         tdm_error ret;
716         int allocated = 0;
717         drmModeConnectorPtr connector;
718         drmModeEncoderPtr encoder;
719         int conn_idx = -1;
720         int crtc_id = 0, c, j;
721
722         RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&drm_data->output_list),
723                                            TDM_ERROR_OPERATION_FAILED);
724
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]);
729                 if (!connector) {
730                         TDM_ERR("no connector");
731                         return TDM_ERROR_OPERATION_FAILED;
732                 }
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                 if (connector->connection == DRM_MODE_CONNECTED) {
740                         conn_idx = i;
741                         drmModeFreeConnector(connector);
742                         break;
743                 }
744                 drmModeFreeConnector(connector);
745         }
746
747         /* use the first connecoct_id if there is not connector which is connected */
748         if (conn_idx == -1)
749                 conn_idx = 0;
750
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.
755          */
756         connector = drmModeGetConnector(drm_data->drm_fd,
757                                                                         drm_data->mode_res->connectors[conn_idx]);
758         if (!connector) {
759                 TDM_ERR("no connector");
760                 ret = TDM_ERROR_OPERATION_FAILED;
761                 goto failed_create;
762         }
763
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;
768                 goto failed_create;
769         }
770
771         encoder = drmModeGetEncoder(drm_data->drm_fd, connector->encoders[0]);
772         if (!encoder) {
773                 TDM_ERR("no encoder");
774                 drmModeFreeConnector(connector);
775                 ret = TDM_ERROR_OPERATION_FAILED;
776                 goto failed_create;
777         }
778
779         for (c = 0; c < drm_data->mode_res->count_crtcs; c++) {
780                 if (allocated & (1 << c))
781                         continue;
782
783                 if ((encoder->possible_crtcs & (1 << c)) == 0)
784                         continue;
785
786                 crtc_id = drm_data->mode_res->crtcs[c];
787                 allocated |= (1 << c);
788                 break;
789         }
790
791         if (crtc_id == 0) {
792                 TDM_ERR("no possible crtc");
793                 drmModeFreeConnector(connector);
794                 drmModeFreeEncoder(encoder);
795                 ret = TDM_ERROR_OPERATION_FAILED;
796                 goto failed_create;
797         }
798
799         output_data = calloc(1, sizeof(tdm_drm_output_data));
800         if (!output_data) {
801                 TDM_ERR("alloc failed");
802                 drmModeFreeConnector(connector);
803                 drmModeFreeEncoder(encoder);
804                 ret = TDM_ERROR_OUT_OF_MEMORY;
805                 goto failed_create;
806         }
807
808         LIST_INITHEAD(&output_data->layer_list);
809
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;
817
818         if (connector->connection == DRM_MODE_CONNECTED)
819                 output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
820         else
821                 output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
822
823         for (j = 0; j < connector->count_props; j++) {
824                 drmModePropertyPtr prop = drmModeGetProperty(drm_data->drm_fd,
825                                                                   connector->props[j]);
826                 if (!prop)
827                         continue;
828                 if (!strcmp(prop->name, "DPMS")) {
829                         output_data->dpms_prop_id = connector->props[j];
830                         drmModeFreeProperty(prop);
831                         break;
832                 }
833                 drmModeFreeProperty(prop);
834         }
835
836         if (output_data->dpms_prop_id == 0)
837                 TDM_WRN("not support DPMS");
838
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");
844                 free(output_data);
845                 drmModeFreeConnector(connector);
846                 drmModeFreeEncoder(encoder);
847                 ret = TDM_ERROR_OUT_OF_MEMORY;
848                 goto failed_create;
849         }
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);
855                 free(output_data);
856                 drmModeFreeConnector(connector);
857                 drmModeFreeEncoder(encoder);
858                 ret = TDM_ERROR_OUT_OF_MEMORY;
859                 goto failed_create;
860         }
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]);
865         }
866
867         if (drm_data->hwc_mode)
868                 output_data->hwc_enable = 1;
869
870         LIST_ADDTAIL(&output_data->link, &drm_data->output_list);
871
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);
877
878         drmModeFreeEncoder(encoder);
879         drmModeFreeConnector(connector);
880
881         TDM_DBG("output count: %d", drm_data->mode_res->count_connectors);
882
883         return TDM_ERROR_NONE;
884 failed_create:
885         tdm_drm_display_destroy_output_list(drm_data);
886         return ret;
887 }
888
889 tdm_error
890 drm_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps)
891 {
892         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
893
894         caps->max_layer_count = -1; /* not defined */
895
896         return TDM_ERROR_NONE;
897 }
898
899 tdm_error
900 drm_display_get_pp_capability(tdm_backend_data *bdata, tdm_caps_pp *caps)
901 {
902         return tdm_drm_pp_get_capability(bdata, caps);
903 }
904
905 tdm_output **
906 drm_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error)
907 {
908         tdm_drm_data *drm_data = bdata;
909         tdm_drm_output_data *output_data = NULL;
910         tdm_output **outputs;
911         tdm_error ret;
912         int i;
913
914         RETURN_VAL_IF_FAIL(drm_data, NULL);
915         RETURN_VAL_IF_FAIL(count, NULL);
916
917         *count = 0;
918         LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link)
919         (*count)++;
920
921         if (*count == 0) {
922                 ret = TDM_ERROR_NONE;
923                 goto failed_get;
924         }
925
926         /* will be freed in frontend */
927         outputs = calloc(*count, sizeof(tdm_drm_output_data *));
928         if (!outputs) {
929                 TDM_ERR("failed: alloc memory");
930                 *count = 0;
931                 ret = TDM_ERROR_OUT_OF_MEMORY;
932                 goto failed_get;
933         }
934
935         i = 0;
936         LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link)
937         outputs[i++] = output_data;
938
939         if (error)
940                 *error = TDM_ERROR_NONE;
941
942         return outputs;
943 failed_get:
944         if (error)
945                 *error = ret;
946         return NULL;
947 }
948
949 tdm_error
950 drm_display_get_fd(tdm_backend_data *bdata, int *fd)
951 {
952         tdm_drm_data *drm_data = bdata;
953
954         RETURN_VAL_IF_FAIL(drm_data, TDM_ERROR_INVALID_PARAMETER);
955         RETURN_VAL_IF_FAIL(fd, TDM_ERROR_INVALID_PARAMETER);
956
957         *fd = drm_data->drm_fd;
958
959         return TDM_ERROR_NONE;
960 }
961
962 tdm_error
963 drm_display_handle_events(tdm_backend_data *bdata)
964 {
965         tdm_drm_data *drm_data = bdata;
966         drmEventContext ctx;
967
968         RETURN_VAL_IF_FAIL(drm_data, TDM_ERROR_INVALID_PARAMETER);
969
970         memset(&ctx, 0, sizeof(drmEventContext));
971
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;
975
976         drmHandleEvent(drm_data->drm_fd, &ctx);
977
978         return TDM_ERROR_NONE;
979 }
980
981 tdm_pp *
982 drm_display_create_pp(tdm_backend_data *bdata, tdm_error *error)
983 {
984         tdm_drm_data *drm_data = bdata;
985
986         RETURN_VAL_IF_FAIL(drm_data, NULL);
987
988         return tdm_drm_pp_create(drm_data, error);
989 }
990
991 tdm_error
992 drm_output_get_capability(tdm_output *output, tdm_caps_output *caps)
993 {
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;
999         int i;
1000         tdm_error ret;
1001
1002         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1003         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1004
1005         memset(caps, 0, sizeof(tdm_caps_output));
1006
1007         drm_data = output_data->drm_data;
1008
1009         snprintf(caps->maker, TDM_NAME_LEN, "unknown");
1010         snprintf(caps->model, TDM_NAME_LEN, "unknown");
1011         snprintf(caps->name, TDM_NAME_LEN, "unknown");
1012
1013         caps->status = output_data->status;
1014         caps->type = output_data->connector_type;
1015         caps->type_id = output_data->connector_type_id;
1016
1017         connector = drmModeGetConnector(drm_data->drm_fd, output_data->connector_id);
1018         RETURN_VAL_IF_FAIL(connector, TDM_ERROR_OPERATION_FAILED);
1019
1020         caps->mode_count = connector->count_modes;
1021         caps->modes = calloc(1, sizeof(tdm_output_mode) * caps->mode_count);
1022         if (!caps->modes) {
1023                 ret = TDM_ERROR_OUT_OF_MEMORY;
1024                 TDM_ERR("alloc failed\n");
1025                 goto failed_get;
1026         }
1027         for (i = 0; i < caps->mode_count; i++)
1028                 caps->modes[i] = output_data->output_modes[i];
1029
1030         caps->mmWidth = connector->mmWidth;
1031         caps->mmHeight = connector->mmHeight;
1032         caps->subpixel = connector->subpixel;
1033
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;
1039
1040         crtc = drmModeGetCrtc(drm_data->drm_fd, output_data->crtc_id);
1041         if (!crtc) {
1042                 ret = TDM_ERROR_OPERATION_FAILED;
1043                 TDM_ERR("get crtc failed: %m\n");
1044                 goto failed_get;
1045         }
1046
1047         props = drmModeObjectGetProperties(drm_data->drm_fd, output_data->crtc_id,
1048                                                                            DRM_MODE_OBJECT_CRTC);
1049         if (!props) {
1050                 ret = TDM_ERROR_OPERATION_FAILED;
1051                 TDM_ERR("get crtc properties failed: %m\n");
1052                 goto failed_get;
1053         }
1054
1055         caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
1056         if (!caps->props) {
1057                 ret = TDM_ERROR_OUT_OF_MEMORY;
1058                 TDM_ERR("alloc failed\n");
1059                 goto failed_get;
1060         }
1061
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]);
1065                 if (!prop)
1066                         continue;
1067                 snprintf(caps->props[caps->prop_count].name, TDM_NAME_LEN, "%s", prop->name);
1068                 caps->props[caps->prop_count].id = props->props[i];
1069                 caps->prop_count++;
1070                 drmModeFreeProperty(prop);
1071         }
1072
1073         if (output_data->hwc_enable)
1074                 caps->capabilities |= TDM_OUTPUT_CAPABILITY_HWC;
1075
1076         drmModeFreeObjectProperties(props);
1077         drmModeFreeCrtc(crtc);
1078         drmModeFreeConnector(connector);
1079
1080         return TDM_ERROR_NONE;
1081 failed_get:
1082         drmModeFreeCrtc(crtc);
1083         drmModeFreeObjectProperties(props);
1084         drmModeFreeConnector(connector);
1085         free(caps->modes);
1086         free(caps->props);
1087         memset(caps, 0, sizeof(tdm_caps_output));
1088         return ret;
1089 }
1090
1091 tdm_layer **
1092 drm_output_get_layers(tdm_output *output,  int *count, tdm_error *error)
1093 {
1094         tdm_drm_output_data *output_data = output;
1095         tdm_drm_layer_data *layer_data = NULL;
1096         tdm_layer **layers;
1097         tdm_error ret;
1098         int i;
1099
1100         RETURN_VAL_IF_FAIL(output_data, NULL);
1101         RETURN_VAL_IF_FAIL(count, NULL);
1102
1103         *count = 0;
1104         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1105         (*count)++;
1106
1107         if (output_data->hwc_enable) {
1108                 *count = 0;
1109                 ret = TDM_ERROR_NONE;
1110                 goto failed_get;
1111         }
1112
1113         if (*count == 0) {
1114                 ret = TDM_ERROR_NONE;
1115                 goto failed_get;
1116         }
1117
1118         /* will be freed in frontend */
1119         layers = calloc(*count, sizeof(tdm_drm_layer_data *));
1120         if (!layers) {
1121                 TDM_ERR("failed: alloc memory");
1122                 *count = 0;
1123                 ret = TDM_ERROR_OUT_OF_MEMORY;
1124                 goto failed_get;
1125         }
1126
1127         i = 0;
1128         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1129         layers[i++] = layer_data;
1130
1131         if (error)
1132                 *error = TDM_ERROR_NONE;
1133
1134         return layers;
1135 failed_get:
1136         if (error)
1137                 *error = ret;
1138         return NULL;
1139 }
1140
1141 tdm_error
1142 drm_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
1143 {
1144         tdm_drm_output_data *output_data = output;
1145         tdm_drm_data *drm_data;
1146         int ret;
1147
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);
1150
1151         drm_data = output_data->drm_data;
1152         ret = drmModeObjectSetProperty(drm_data->drm_fd,
1153                                                                    output_data->crtc_id, DRM_MODE_OBJECT_CRTC,
1154                                                                    id, value.u32);
1155         if (ret < 0) {
1156                 TDM_ERR("set property failed: %m");
1157                 return TDM_ERROR_OPERATION_FAILED;
1158         }
1159
1160         return TDM_ERROR_NONE;
1161 }
1162
1163 tdm_error
1164 drm_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
1165 {
1166         tdm_drm_output_data *output_data = output;
1167         tdm_drm_data *drm_data;
1168         drmModeObjectPropertiesPtr props;
1169         int i;
1170
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);
1174
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;
1181         }
1182
1183         for (i = 0; i < props->count_props; i++)
1184                 if (props->props[i] == id) {
1185                         (*value).u32 = (uint)props->prop_values[i];
1186                         break;
1187                 }
1188
1189         drmModeFreeObjectProperties(props);
1190
1191         return TDM_ERROR_NONE;
1192 }
1193
1194 tdm_error
1195 drm_output_wait_vblank(tdm_output *output, int interval, int sync,
1196                                            void *user_data)
1197 {
1198         tdm_drm_output_data *output_data = output;
1199         tdm_drm_data *drm_data;
1200         tdm_drm_event_data *event_data;
1201         uint target_msc;
1202         tdm_error ret;
1203
1204         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1205
1206         event_data = calloc(1, sizeof(tdm_drm_event_data));
1207         if (!event_data) {
1208                 TDM_ERR("alloc failed");
1209                 return TDM_ERROR_OUT_OF_MEMORY;
1210         }
1211
1212         drm_data = output_data->drm_data;
1213
1214         ret = _tdm_drm_display_get_cur_msc(drm_data->drm_fd, output_data->pipe,
1215                                                                            &target_msc);
1216         if (ret != TDM_ERROR_NONE)
1217                 goto failed_vblank;
1218
1219         target_msc += interval;
1220
1221         event_data->type = TDM_DRM_EVENT_TYPE_WAIT;
1222         event_data->output_data = output_data;
1223         event_data->user_data = user_data;
1224
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)
1228                 goto failed_vblank;
1229
1230         return TDM_ERROR_NONE;
1231 failed_vblank:
1232         free(event_data);
1233         return ret;
1234 }
1235
1236 tdm_error
1237 drm_output_set_vblank_handler(tdm_output *output,
1238                                                           tdm_output_vblank_handler func)
1239 {
1240         tdm_drm_output_data *output_data = output;
1241
1242         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1243         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1244
1245         output_data->vblank_func = func;
1246
1247         return TDM_ERROR_NONE;
1248 }
1249
1250 tdm_error
1251 drm_output_commit(tdm_output *output, int sync, void *user_data)
1252 {
1253         tdm_drm_output_data *output_data = output;
1254         tdm_drm_data *drm_data;
1255         tdm_drm_layer_data *layer_data = NULL;
1256         tdm_error ret;
1257         int do_waitvblank = 1;
1258
1259         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1260
1261         drm_data = output_data->drm_data;
1262
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,
1266                                                         &do_waitvblank);
1267                         if (ret != TDM_ERROR_NONE)
1268                                 return ret;
1269                 } else {
1270                         ret = _tdm_drm_display_commit_layer(layer_data);
1271                         if (ret != TDM_ERROR_NONE)
1272                                 return ret;
1273                 }
1274         }
1275
1276         if (do_waitvblank == 1) {
1277                 tdm_drm_event_data *event_data = calloc(1, sizeof(tdm_drm_event_data));
1278                 uint target_msc;
1279
1280                 if (!event_data) {
1281                         TDM_ERR("alloc failed");
1282                         return TDM_ERROR_OUT_OF_MEMORY;
1283                 }
1284
1285                 ret = _tdm_drm_display_get_cur_msc(drm_data->drm_fd, output_data->pipe,
1286                                                                                    &target_msc);
1287                 if (ret != TDM_ERROR_NONE) {
1288                         free(event_data);
1289                         return ret;
1290                 }
1291
1292                 target_msc++;
1293
1294                 event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
1295                 event_data->output_data = output_data;
1296                 event_data->user_data = user_data;
1297
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) {
1301                         free(event_data);
1302                         return ret;
1303                 }
1304         }
1305
1306         return TDM_ERROR_NONE;
1307 }
1308
1309 tdm_error
1310 drm_output_set_commit_handler(tdm_output *output,
1311                                                           tdm_output_commit_handler func)
1312 {
1313         tdm_drm_output_data *output_data = output;
1314
1315         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1316         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1317
1318         output_data->commit_func = func;
1319
1320         return TDM_ERROR_NONE;
1321 }
1322
1323 tdm_error
1324 drm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
1325 {
1326         tdm_drm_output_data *output_data = output;
1327         tdm_drm_data *drm_data;
1328         int ret;
1329
1330         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1331
1332         if (output_data->dpms_prop_id == 0) {
1333                 TDM_WRN("not support DPMS");
1334                 return TDM_ERROR_OPERATION_FAILED;
1335         }
1336
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);
1341         if (ret < 0) {
1342                 TDM_ERR("set dpms failed: %m");
1343                 return TDM_ERROR_OPERATION_FAILED;
1344         }
1345
1346         output_data->current_dpms = dpms_value;
1347
1348         return TDM_ERROR_NONE;
1349 }
1350
1351 tdm_error
1352 drm_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
1353 {
1354         tdm_drm_output_data *output_data = output;
1355         tdm_drm_data *drm_data;
1356         drmModeObjectPropertiesPtr props;
1357         int i;
1358
1359         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1360         RETURN_VAL_IF_FAIL(dpms_value, TDM_ERROR_INVALID_PARAMETER);
1361
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;
1368         }
1369
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];
1373                         break;
1374                 }
1375
1376         drmModeFreeObjectProperties(props);
1377
1378         return TDM_ERROR_NONE;
1379 }
1380
1381 tdm_error
1382 drm_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
1383 {
1384         tdm_drm_output_data *output_data = output;
1385         tdm_error ret = TDM_ERROR_NONE;
1386
1387         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1388         RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1389
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);
1395                         return ret;
1396                 }
1397         }
1398
1399         output_data->current_mode = mode;
1400         output_data->mode_changed = 1;
1401
1402         return TDM_ERROR_NONE;
1403 }
1404
1405 tdm_error
1406 drm_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
1407 {
1408         tdm_drm_output_data *output_data = output;
1409
1410         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1411         RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1412
1413         *mode = output_data->current_mode;
1414
1415         return TDM_ERROR_NONE;
1416 }
1417
1418 tdm_hwc *
1419 drm_output_get_hwc(tdm_output *output, tdm_error *error)
1420 {
1421         tdm_drm_hwc_data *hwc_data = NULL;
1422         tdm_drm_output_data *output_data = output;
1423         tdm_error ret = TDM_ERROR_NONE;
1424
1425         if (!output_data) {
1426                 TDM_ERR("invalid params");
1427                 if (error)
1428                         *error = TDM_ERROR_INVALID_PARAMETER;
1429                 return NULL;
1430         }
1431
1432         if (output_data->hwc_data) {
1433                 TDM_INFO("hwc_data already exists");
1434                 if (error)
1435                         *error = TDM_ERROR_NONE;
1436                 return output_data->hwc_data;
1437         }
1438
1439         hwc_data = calloc(1, sizeof(tdm_drm_hwc_data));
1440         if (!hwc_data) {
1441                 TDM_ERR("alloc failed");
1442                 if (error)
1443                         *error = TDM_ERROR_OUT_OF_MEMORY;
1444                 return NULL;
1445         }
1446         hwc_data->output_data = output_data;
1447
1448         LIST_INITHEAD(&hwc_data->hwc_window_list);
1449
1450         output_data->hwc_data = hwc_data;
1451
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);
1455                 free(hwc_data);
1456                 if (error)
1457                         *error = ret;
1458                 return NULL;
1459         }
1460
1461         if (error)
1462                 *error = TDM_ERROR_NONE;
1463
1464         return hwc_data;
1465 }
1466
1467 tdm_error
1468 drm_output_set_status_handler(tdm_output *output,
1469                                                           tdm_output_status_handler func,
1470                                                           void *user_data)
1471 {
1472         tdm_drm_output_data *output_data = output;
1473
1474         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1475         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1476
1477         output_data->status_func = func;
1478         output_data->status_user_data = user_data;
1479
1480         return TDM_ERROR_NONE;
1481 }
1482
1483 tdm_error
1484 drm_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
1485 {
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;
1491         tdm_error ret;
1492
1493         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1494         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1495
1496         memset(caps, 0, sizeof(tdm_caps_layer));
1497
1498         drm_data = layer_data->drm_data;
1499         plane = drmModeGetPlane(drm_data->drm_fd, layer_data->plane_id);
1500         if (!plane) {
1501                 TDM_ERR("get plane failed: %m");
1502                 ret = TDM_ERROR_OPERATION_FAILED;
1503                 goto failed_get;
1504         }
1505
1506         caps->capabilities = layer_data->capabilities;
1507         caps->zpos = layer_data->zpos;  /* if VIDEO layer, zpos is -1 */
1508
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");
1514                 goto failed_get;
1515         }
1516
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]));
1523                         continue;
1524                 }
1525                 caps->formats[format_count] = tdm_drm_format_to_tbm_format(plane->formats[i]);
1526                 format_count++;
1527         }
1528
1529         caps->format_count = format_count;
1530
1531         props = drmModeObjectGetProperties(drm_data->drm_fd, layer_data->plane_id,
1532                                                                            DRM_MODE_OBJECT_PLANE);
1533         if (!props) {
1534                 ret = TDM_ERROR_OPERATION_FAILED;
1535                 TDM_ERR("get plane properties failed: %m\n");
1536                 goto failed_get;
1537         }
1538
1539         caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
1540         if (!caps->props) {
1541                 ret = TDM_ERROR_OUT_OF_MEMORY;
1542                 TDM_ERR("alloc failed\n");
1543                 goto failed_get;
1544         }
1545
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]);
1549                 if (!prop)
1550                         continue;
1551                 if (!strncmp(prop->name, "type", TDM_NAME_LEN)) {
1552                         drmModeFreeProperty(prop);
1553                         continue;
1554                 }
1555                 if (!strncmp(prop->name, "zpos", TDM_NAME_LEN)) {
1556                         drmModeFreeProperty(prop);
1557                         continue;
1558                 }
1559                 snprintf(caps->props[caps->prop_count].name, TDM_NAME_LEN, "%s", prop->name);
1560                 caps->props[caps->prop_count].id = props->props[i];
1561                 caps->prop_count++;
1562                 drmModeFreeProperty(prop);
1563         }
1564
1565         drmModeFreeObjectProperties(props);
1566         drmModeFreePlane(plane);
1567
1568         return TDM_ERROR_NONE;
1569 failed_get:
1570         drmModeFreeObjectProperties(props);
1571         drmModeFreePlane(plane);
1572         free(caps->formats);
1573         free(caps->props);
1574         memset(caps, 0, sizeof(tdm_caps_layer));
1575         return ret;
1576 }
1577
1578 tdm_error
1579 drm_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value)
1580 {
1581         tdm_drm_layer_data *layer_data = layer;
1582         tdm_drm_data *drm_data;
1583         int ret;
1584
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);
1587
1588         drm_data = layer_data->drm_data;
1589         ret = drmModeObjectSetProperty(drm_data->drm_fd,
1590                                                                    layer_data->plane_id, DRM_MODE_OBJECT_PLANE,
1591                                                                    id, value.u32);
1592         if (ret < 0) {
1593                 TDM_ERR("set property failed: %m");
1594                 return TDM_ERROR_OPERATION_FAILED;
1595         }
1596
1597         return TDM_ERROR_NONE;
1598 }
1599
1600 tdm_error
1601 drm_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value)
1602 {
1603         tdm_drm_layer_data *layer_data = layer;
1604         tdm_drm_data *drm_data;
1605         drmModeObjectPropertiesPtr props;
1606         int i;
1607
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);
1611
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;
1618         }
1619
1620         for (i = 0; i < props->count_props; i++)
1621                 if (props->props[i] == id) {
1622                         (*value).u32 = (uint)props->prop_values[i];
1623                         break;
1624                 }
1625
1626         drmModeFreeObjectProperties(props);
1627
1628         return TDM_ERROR_NONE;
1629 }
1630
1631 tdm_error
1632 drm_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
1633 {
1634         tdm_drm_layer_data *layer_data = layer;
1635
1636         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1637         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
1638
1639         layer_data->info = *info;
1640         layer_data->info_changed = 1;
1641
1642         return TDM_ERROR_NONE;
1643 }
1644
1645 tdm_error
1646 drm_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
1647 {
1648         tdm_drm_layer_data *layer_data = layer;
1649
1650         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1651         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
1652
1653         *info = layer_data->info;
1654
1655         return TDM_ERROR_NONE;
1656 }
1657
1658 static tdm_drm_display_buffer *
1659 _tdm_drm_display_find_buffer(tdm_drm_data *drm_data, tbm_surface_h buffer)
1660 {
1661         tdm_drm_display_buffer *display_buffer = NULL;
1662
1663         LIST_FOR_EACH_ENTRY(display_buffer, &drm_data->buffer_list, link) {
1664                 if (display_buffer->buffer == buffer)
1665                         return display_buffer;
1666         }
1667
1668         return NULL;
1669 }
1670
1671 static void
1672 _tdm_drm_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
1673 {
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,};
1679         char *ret_tmp;
1680
1681         if (!user_data) {
1682                 TDM_ERR("no user_data");
1683                 return;
1684         }
1685         if (!buffer) {
1686                 TDM_ERR("no buffer");
1687                 return;
1688         }
1689
1690         drm_data = (tdm_drm_data *) user_data;
1691
1692         display_buffer = _tdm_drm_display_find_buffer(drm_data, buffer);
1693         if (!display_buffer) {
1694                 TDM_ERR("no display_buffer");
1695                 return;
1696         }
1697
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;
1702                 }
1703         }
1704
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);
1709                 }
1710         }
1711
1712         TDM_DBG("destroy buffer:%p", display_buffer->buffer);
1713
1714         LIST_DEL(&display_buffer->link);
1715         free(display_buffer);
1716 }
1717
1718 static tdm_drm_display_buffer *
1719 _tdm_drm_display_create_buffer(tdm_drm_data *drm_data, tbm_surface_h buffer, tdm_error *err)
1720 {
1721         tdm_drm_display_buffer *display_buffer = NULL;
1722         tdm_error res = TDM_ERROR_NONE;
1723         int count, i, ret;
1724
1725         display_buffer = calloc(1, sizeof(tdm_drm_display_buffer));
1726         if (!display_buffer) {
1727                 TDM_ERR("alloc failed");
1728                 if (err)
1729                         *err = TDM_ERROR_OUT_OF_MEMORY;
1730                 return NULL;
1731         }
1732
1733         display_buffer->buffer = buffer;
1734
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);
1739                 if (err)
1740                         *err = res;
1741                 return NULL;
1742         }
1743
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);
1752
1753         for (i = 0; i < count; i++) {
1754                 int bo_idx = 0;
1755                 tbm_bo bo = NULL;
1756
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;
1760
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]);
1767         }
1768
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);
1772         if (ret < 0) {
1773                 TDM_ERR("add fb failed: %m");
1774                 free(display_buffer);
1775                 if (err)
1776                         *err = TDM_ERROR_OPERATION_FAILED;
1777                 return NULL;
1778         }
1779
1780         TDM_DBG("drm_data->drm_fd : %d, display_buffer->fb_id:%u", drm_data->drm_fd,
1781                         display_buffer->fb_id);
1782
1783         if (IS_RGB(display_buffer->format))
1784                 display_buffer->width = display_buffer->pitches[0] >> 2;
1785         else
1786                 display_buffer->width = display_buffer->pitches[0];
1787
1788         LIST_ADDTAIL(&display_buffer->link, &drm_data->buffer_list);
1789
1790         if (err)
1791                 *err = TDM_ERROR_NONE;
1792
1793         return display_buffer;
1794 }
1795
1796 void
1797 tdm_drm_data_destroy_buffer_list(tdm_drm_data *drm_data)
1798 {
1799         tdm_drm_display_buffer *b = NULL, *bb = NULL;
1800
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);
1804         }
1805 }
1806
1807 tdm_error
1808 drm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
1809 {
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;
1814
1815         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1816         RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
1817
1818         TDM_DBG("layer[%p]zpos[%d] buffer:%p", layer, layer_data->zpos, buffer);
1819
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);
1825         }
1826
1827         if (layer_data->display_buffer != display_buffer) {
1828                 if (layer_data->display_buffer)
1829                         tbm_surface_internal_unref(layer_data->display_buffer->buffer);
1830
1831                 layer_data->display_buffer = display_buffer;
1832                 tbm_surface_internal_ref(layer_data->display_buffer->buffer);
1833                 layer_data->display_buffer_changed = 1;
1834         }
1835
1836         return TDM_ERROR_NONE;
1837 }
1838
1839 tdm_error
1840 drm_layer_unset_buffer(tdm_layer *layer)
1841 {
1842         tdm_drm_layer_data *layer_data = layer;
1843
1844         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1845
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;
1849         }
1850
1851         layer_data->display_buffer_changed = 1;
1852
1853         return TDM_ERROR_NONE;
1854 }
1855
1856 tdm_drm_layer_data *
1857 drm_output_data_get_layer_data(tdm_drm_output_data *output_data, int layer_zpos)
1858 {
1859         tdm_drm_layer_data *l = NULL;
1860
1861         RETURN_VAL_IF_FAIL(output_data, NULL);
1862
1863         LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link) {
1864                 if (l->zpos == layer_zpos)
1865                         return l;
1866         }
1867
1868         return NULL;
1869 }