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