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