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