hwc: implement the first draft of HWC based on exynos implamantation.
[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 #define LIST_INSERT_AFTER(__after, __item) \
13                 (__item)->prev = (__after); \
14                 (__item)->next = (__after)->next; \
15                 (__after)->next->prev = (__item); \
16                 (__after)->next = (__item);
17
18 typedef struct _tdm_vc4_output_data tdm_vc4_output_data;
19 typedef struct _tdm_vc4_layer_data tdm_vc4_layer_data;
20 typedef struct _tdm_vc4_hwc_window_data tdm_vc4_hwc_window_data;
21 typedef struct _tdm_vc4_event_data tdm_vc4_event_data;
22
23 typedef enum {
24         TDM_DRM_EVENT_TYPE_WAIT,
25         TDM_DRM_EVENT_TYPE_COMMIT,
26         TDM_DRM_EVENT_TYPE_PAGEFLIP,
27 } tdm_vc4_event_type;
28
29 typedef struct _tdm_vc4_display_buffer {
30         struct list_head link;
31
32         unsigned int fb_id;
33         tbm_surface_h buffer;
34         int width;
35 } tdm_vc4_display_buffer;
36
37 struct _tdm_vc4_event_data {
38         tdm_vc4_event_type type;
39         tdm_vc4_output_data *output_data;
40         void *user_data;
41 };
42
43 struct _tdm_vc4_output_data {
44         struct list_head link;
45
46         /* data which are fixed at initializing */
47         tdm_vc4_data *vc4_data;
48         uint32_t connector_id;
49         uint32_t encoder_id;
50         uint32_t crtc_id;
51         uint32_t pipe;
52         uint32_t dpms_prop_id;
53         int count_modes;
54         drmModeModeInfoPtr vc4_modes;
55         tdm_output_mode *output_modes;
56         tdm_output_type connector_type;
57         unsigned int connector_type_id;
58         struct list_head layer_list;
59         tdm_vc4_layer_data *primary_layer;
60
61         /* not fixed data below */
62         tdm_output_vblank_handler vblank_func;
63         tdm_output_commit_handler commit_func;
64
65         tdm_output_conn_status status;
66         tdm_output_status_handler status_func;
67         void *status_user_data;
68
69         int mode_changed;
70         const tdm_output_mode *current_mode;
71
72         tbm_surface_h crtc_buffer;
73         int crtc_enabled;
74         unsigned int crtc_fb_id;
75
76         tdm_vc4_hwc_window_data *target_hwc_window;
77
78         int need_validate;
79         int need_target_buffer;
80         int hw_layer_count;
81         int need_set_crtc;
82         int top_layer_idx;
83         int hwc_enable;
84
85         struct list_head hwc_window_list;
86 };
87
88 struct _tdm_vc4_layer_data {
89         struct list_head link;
90
91         /* data which are fixed at initializing */
92         tdm_vc4_data *vc4_data;
93         tdm_vc4_output_data *output_data;
94         uint32_t plane_id;
95         tdm_layer_capability capabilities;
96         int zpos;
97
98         /* not fixed data below */
99         tdm_info_layer info;
100         int info_changed;
101
102         tdm_vc4_display_buffer *display_buffer;
103         int display_buffer_changed;
104 };
105
106 struct _tdm_vc4_hwc_window_data {
107         struct list_head link;
108
109         /* data which are fixed at initializing */
110         tdm_vc4_data *vc4_data;
111         tdm_vc4_output_data *output_data;
112
113         /* not fixed data below */
114         int zpos;
115
116         tdm_hwc_window_info info;
117         int info_changed;
118
119         tbm_surface_h surface;
120         int display_buffer_changed;
121         int enabled_flag;
122
123         /* client_type stores the initial type given to us by client(compositor) */
124         tdm_hwc_window_composition client_type;
125         /* validated_type stores the type after running Validate */
126         tdm_hwc_window_composition validated_type;
127 };
128
129 tdm_hwc_window *
130 _vc4_output_hwc_window_create(tdm_output *output, tdm_hwc_window_info *info,
131                                                                 tdm_error *error);
132
133 static drmModeModeInfoPtr
134 _tdm_vc4_display_get_mode(tdm_vc4_output_data *output_data)
135 {
136         int i;
137
138         if (!output_data->current_mode) {
139                 TDM_ERR("no output_data->current_mode");
140                 return NULL;
141         }
142
143         for (i = 0; i < output_data->count_modes; i++) {
144                 drmModeModeInfoPtr vc4_mode = &output_data->vc4_modes[i];
145                 if ((vc4_mode->hdisplay == output_data->current_mode->hdisplay) &&
146                         (vc4_mode->vdisplay == output_data->current_mode->vdisplay) &&
147                         (vc4_mode->vrefresh == output_data->current_mode->vrefresh) &&
148                         (vc4_mode->flags == output_data->current_mode->flags) &&
149                         (vc4_mode->type == output_data->current_mode->type) &&
150                         !(strncmp(vc4_mode->name, output_data->current_mode->name, TDM_NAME_LEN)))
151                         return vc4_mode;
152         }
153
154         return NULL;
155 }
156
157 static tdm_error
158 _tdm_vc4_display_set_fb(tdm_vc4_data *vc4_data, tbm_surface_h buffer, unsigned int *id)
159 {
160         unsigned int width;
161         unsigned int height;
162         unsigned int format;
163         unsigned int handles[4] = {0,};
164         unsigned int pitches[4] = {0,};
165         unsigned int offsets[4] = {0,};
166         unsigned int size;
167         unsigned int fb_id;
168         int ret, count, i;
169
170         width = tbm_surface_get_width(buffer);
171         height = tbm_surface_get_height(buffer);
172         format = tbm_surface_get_format(buffer);
173         count = tbm_surface_internal_get_num_bos(buffer);
174         for (i = 0; i < count; i++) {
175                 tbm_bo bo = tbm_surface_internal_get_bo(buffer, i);
176                 handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
177         }
178         count = tbm_surface_internal_get_num_planes(format);
179         for (i = 0; i < count; i++)
180                 tbm_surface_internal_get_plane_data(buffer, i, &size, &offsets[i], &pitches[i]);
181
182         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)",
183                         vc4_data->drm_fd, width, height, FOURCC_STR(format),
184                         handles[0], handles[1], handles[2], pitches[0], pitches[1], pitches[2],
185                         offsets[0], offsets[1], offsets[2], buffer);
186
187         ret = drmModeAddFB2(vc4_data->drm_fd, width, height, format,
188                                                 handles, pitches, offsets, &fb_id, 0);
189         if (ret < 0) {
190                 TDM_ERR("add fb failed: %m");
191                 return TDM_ERROR_OPERATION_FAILED;
192         }
193         TDM_DBG("AddFB2 success: drm_fd(%d) fb_id(%u)", vc4_data->drm_fd, fb_id);
194
195         *id = fb_id;
196         return TDM_ERROR_NONE;
197 }
198
199 static tdm_error
200 _tdm_vc4_display_set_crtc(tdm_vc4_data *vc4_data, tdm_vc4_output_data *output_data, int set)
201 {
202         int ret;
203
204         output_data->mode_changed = 0;
205
206         if (set) {
207                 tbm_surface_h buffer = NULL;
208                 tbm_surface_info_s info;
209                 drmModeModeInfoPtr mode;
210                 unsigned int fb_id = 0;
211
212                 if (!output_data->current_mode)
213                         return TDM_ERROR_OPERATION_FAILED;
214
215                 mode = _tdm_vc4_display_get_mode(output_data);
216                 if (!mode) {
217                         TDM_ERR("couldn't find proper mode");
218                         return TDM_ERROR_BAD_REQUEST;
219                 }
220
221                 buffer = tbm_surface_create(output_data->current_mode->hdisplay,
222                                                                         output_data->current_mode->vdisplay,
223                                                                         TBM_FORMAT_XRGB8888);
224                 RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_OPERATION_FAILED);
225
226                 tbm_surface_map(buffer, TBM_SURF_OPTION_WRITE, &info);
227                 memset(info.planes[0].ptr, 0x0, info.size);
228
229                 tbm_surface_unmap(buffer);
230
231                 if (_tdm_vc4_display_set_fb(vc4_data, buffer, &fb_id) != TDM_ERROR_NONE) {
232                         tbm_surface_destroy(buffer);
233                         return TDM_ERROR_OPERATION_FAILED;
234                 }
235
236                 TDM_DBG("drmModeSetCrtc drm_fd(%d) crtc_id(%u) fb_id(%u) mode(%u,%u)",
237                                 vc4_data->drm_fd, output_data->crtc_id, fb_id,
238                                 mode->hdisplay, mode->vdisplay);
239                 if (drmModeSetCrtc(vc4_data->drm_fd, output_data->crtc_id,
240                                                    fb_id, 0, 0,
241                                                    &output_data->connector_id, 1, mode)) {
242                         TDM_ERR("set crtc failed: %m");
243                         ret = drmModeRmFB(vc4_data->drm_fd, fb_id);
244                         if (ret < 0)
245                                 TDM_ERR("rm fb failed fb_id(%u)", fb_id);
246                         tbm_surface_destroy(buffer);
247                         return TDM_ERROR_OPERATION_FAILED;
248                 }
249
250                 if (output_data->crtc_buffer) {
251                         ret = drmModeRmFB(vc4_data->drm_fd, output_data->crtc_fb_id);
252                         if (ret < 0)
253                                 TDM_ERR("rm fb failed fb_id(%u)", output_data->crtc_fb_id);
254                         tbm_surface_destroy(output_data->crtc_buffer);
255                 }
256                 output_data->crtc_buffer = buffer;
257                 output_data->crtc_fb_id = fb_id;
258         } else {
259                 TDM_DBG("drmModeSetCrtc unset drm_fd(%d) crtc_id(%u)",
260                                 vc4_data->drm_fd, output_data->crtc_id);
261                 if (drmModeSetCrtc(vc4_data->drm_fd, output_data->crtc_id,
262                                                    0, 0, 0, NULL, 0, NULL)) {
263                         TDM_ERR("unset crtc failed: %m");
264                         return TDM_ERROR_OPERATION_FAILED;
265                 }
266
267                 if (output_data->crtc_buffer) {
268                         ret = drmModeRmFB(vc4_data->drm_fd, output_data->crtc_fb_id);
269                         if (ret < 0)
270                                 TDM_ERR("rm fb failed fb_id(%u)", output_data->crtc_fb_id);
271                         tbm_surface_destroy(output_data->crtc_buffer);
272                 }
273                 output_data->crtc_buffer = NULL;
274                 output_data->crtc_fb_id = 0;
275         }
276
277         return TDM_ERROR_NONE;
278 }
279
280 static tdm_vc4_display_buffer *
281 _tdm_vc4_display_find_buffer(tdm_vc4_data *vc4_data, tbm_surface_h buffer)
282 {
283         tdm_vc4_display_buffer *display_buffer = NULL;
284
285         LIST_FOR_EACH_ENTRY(display_buffer, &vc4_data->buffer_list, link) {
286                 if (display_buffer->buffer == buffer)
287                         return display_buffer;
288         }
289
290         return NULL;
291 }
292
293 static void
294 _tdm_vc4_display_to_tdm_mode(drmModeModeInfoPtr vc4_mode,
295                                                          tdm_output_mode *tdm_mode)
296 {
297         tdm_mode->clock = vc4_mode->clock;
298         tdm_mode->hdisplay = vc4_mode->hdisplay;
299         tdm_mode->hsync_start = vc4_mode->hsync_start;
300         tdm_mode->hsync_end = vc4_mode->hsync_end;
301         tdm_mode->htotal = vc4_mode->htotal;
302         tdm_mode->hskew = vc4_mode->hskew;
303         tdm_mode->vdisplay = vc4_mode->vdisplay;
304         tdm_mode->vsync_start = vc4_mode->vsync_start;
305         tdm_mode->vsync_end = vc4_mode->vsync_end;
306         tdm_mode->vtotal = vc4_mode->vtotal;
307         tdm_mode->vscan = vc4_mode->vscan;
308         tdm_mode->vrefresh = vc4_mode->vrefresh;
309         tdm_mode->flags = vc4_mode->flags;
310         tdm_mode->type = vc4_mode->type;
311         snprintf(tdm_mode->name, TDM_NAME_LEN, "%s", vc4_mode->name);
312 }
313
314 static tdm_error
315 _tdm_vc4_display_get_cur_msc(int fd, int pipe, uint *msc)
316 {
317         drmVBlank vbl;
318
319         vbl.request.type = DRM_VBLANK_RELATIVE;
320         if (pipe == 1)
321                 vbl.request.type |= DRM_VBLANK_SECONDARY;
322         else if (pipe > 1)
323                 vbl.request.type |= pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
324
325         vbl.request.sequence = 0;
326         if (drmWaitVBlank(fd, &vbl)) {
327                 TDM_ERR("get vblank counter failed: %m");
328                 *msc = 0;
329                 return TDM_ERROR_OPERATION_FAILED;
330         }
331
332         *msc = vbl.reply.sequence;
333
334         return TDM_ERROR_NONE;
335 }
336
337 static tdm_error
338 _tdm_vc4_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data)
339 {
340         drmVBlank vbl;
341
342         vbl.request.type =  DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
343         if (pipe == 1)
344                 vbl.request.type |= DRM_VBLANK_SECONDARY;
345         else if (pipe > 1)
346                 vbl.request.type |= pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
347
348         vbl.request.sequence = *target_msc;
349         vbl.request.signal = (unsigned long)(uintptr_t)data;
350
351         if (drmWaitVBlank(fd, &vbl)) {
352                 TDM_ERR("wait vblank failed: %m");
353                 *target_msc = 0;
354                 return TDM_ERROR_OPERATION_FAILED;
355         }
356
357         *target_msc = vbl.reply.sequence;
358
359         return TDM_ERROR_NONE;
360 }
361
362 static tdm_error
363 _tdm_vc4_output_update_status(tdm_vc4_output_data *output_data,
364                                                           tdm_output_conn_status status)
365 {
366         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
367
368         if (output_data->status == status)
369                 return TDM_ERROR_NONE;
370
371         output_data->status = status;
372
373         if (output_data->status_func)
374                 output_data->status_func(output_data, status,
375                                                                  output_data->status_user_data);
376
377         return TDM_ERROR_NONE;
378 }
379
380 static tdm_error
381 _tdm_vc4_display_commit_layer(tdm_vc4_layer_data *layer_data)
382 {
383         tdm_vc4_data *vc4_data = layer_data->vc4_data;
384         tdm_vc4_output_data *output_data = layer_data->output_data;
385         uint32_t fx, fy, fw, fh;
386         int crtc_w;
387
388         if (!layer_data->display_buffer_changed && !layer_data->info_changed)
389                 return TDM_ERROR_NONE;
390
391         if (!output_data->crtc_enabled || output_data->mode_changed) {
392                 if (_tdm_vc4_display_set_crtc(vc4_data, output_data, 1) != TDM_ERROR_NONE)
393                         return TDM_ERROR_OPERATION_FAILED;
394
395                 output_data->crtc_enabled = 1;
396         }
397
398         if (output_data->current_mode)
399                 crtc_w = output_data->current_mode->hdisplay;
400         else {
401                 drmModeCrtcPtr crtc = drmModeGetCrtc(vc4_data->drm_fd, output_data->crtc_id);
402                 if (!crtc) {
403                         TDM_ERR("getting crtc failed");
404                         return TDM_ERROR_OPERATION_FAILED;
405                 }
406                 crtc_w = crtc->width;
407                 if (crtc_w == 0) {
408                         TDM_ERR("getting crtc width failed");
409                         drmModeFreeCrtc(crtc);
410                         return TDM_ERROR_OPERATION_FAILED;
411                 }
412                 drmModeFreeCrtc(crtc);
413         }
414
415         layer_data->display_buffer_changed = 0;
416         layer_data->info_changed = 0;
417
418         if (!layer_data->display_buffer) {
419                 if (drmModeSetPlane(vc4_data->drm_fd, layer_data->plane_id,
420                                                         output_data->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
421                         TDM_ERR("unset plane(%d) filed: %m", layer_data->plane_id);
422
423                 return TDM_ERROR_NONE;
424         }
425
426         /* Source values are 16.16 fixed point */
427         fx = ((unsigned int)layer_data->info.src_config.pos.x) << 16;
428         fy = ((unsigned int)layer_data->info.src_config.pos.y) << 16;
429         fw = ((unsigned int)layer_data->info.src_config.pos.w) << 16;
430         fh = ((unsigned int)layer_data->info.src_config.pos.h) << 16;
431
432         if (drmModeSetPlane(vc4_data->drm_fd, layer_data->plane_id,
433                                                 output_data->crtc_id, layer_data->display_buffer->fb_id, 0,
434                                                 layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
435                                                 layer_data->info.dst_pos.w, layer_data->info.dst_pos.h,
436                                                 fx, fy, fw, fh) < 0) {
437                 TDM_ERR("set plane(%d) failed: %m", layer_data->plane_id);
438                 return TDM_ERROR_OPERATION_FAILED;
439         }
440
441         TDM_DBG("plane(%d) crtc(%d) pos(%d) on: fb(%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n",
442                         layer_data->plane_id, output_data->crtc_id, layer_data->zpos,
443                         layer_data->display_buffer->fb_id,
444                         layer_data->info.src_config.pos.x, layer_data->info.src_config.pos.y,
445                         layer_data->info.src_config.pos.w, layer_data->info.src_config.pos.h,
446                         layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
447                         layer_data->info.dst_pos.w, layer_data->info.dst_pos.h);
448
449         return TDM_ERROR_NONE;
450 }
451
452 static void
453 _tdm_vc4_display_cb_event(int fd, unsigned int sequence,
454                                                   unsigned int tv_sec, unsigned int tv_usec,
455                                                   void *user_data)
456 {
457         tdm_vc4_event_data *event_data = user_data;
458         tdm_vc4_output_data *output_data;
459
460         if (!event_data) {
461                 TDM_ERR("no event data");
462                 return;
463         }
464
465         output_data = event_data->output_data;
466
467         switch (event_data->type) {
468         case TDM_DRM_EVENT_TYPE_PAGEFLIP:
469                 if (output_data->commit_func)
470                         output_data->commit_func(output_data, sequence, tv_sec, tv_usec,
471                                                                          event_data->user_data);
472                 break;
473         case TDM_DRM_EVENT_TYPE_WAIT:
474                 if (output_data->vblank_func)
475                         output_data->vblank_func(output_data, sequence, tv_sec, tv_usec,
476                                                                          event_data->user_data);
477                 break;
478         case TDM_DRM_EVENT_TYPE_COMMIT:
479                 if (output_data->commit_func)
480                         output_data->commit_func(output_data, sequence, tv_sec, tv_usec,
481                                                                          event_data->user_data);
482                 break;
483         default:
484                 break;
485         }
486
487         free(event_data);
488 }
489
490 static tdm_error
491 _tdm_vc4_display_create_layer_list(tdm_vc4_data *vc4_data)
492 {
493         tdm_vc4_output_data *output_data = NULL;
494         int i;
495
496         if (LIST_IS_EMPTY(&vc4_data->output_list)) {
497                 TDM_ERR("no output");
498                 return TDM_ERROR_OPERATION_FAILED;
499         }
500
501         /* The TDM drm backend only support one output. */
502         LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
503                 break;
504         }
505
506         if (vc4_data->plane_res->count_planes == 0) {
507                 TDM_ERR("no layer error");
508                 return TDM_ERROR_OPERATION_FAILED;
509         }
510
511         for (i = 0; i < vc4_data->plane_res->count_planes; i++) {
512                 tdm_vc4_layer_data *layer_data;
513                 drmModePlanePtr plane;
514
515                 plane = drmModeGetPlane(vc4_data->drm_fd, vc4_data->plane_res->planes[i]);
516                 if (!plane) {
517                         TDM_ERR("no plane");
518                         continue;
519                 }
520
521                 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
522                         drmModeFreePlane(plane);
523                         continue;
524                 }
525
526                 layer_data = calloc(1, sizeof(tdm_vc4_layer_data));
527                 if (!layer_data) {
528                         TDM_ERR("alloc failed");
529                         drmModeFreePlane(plane);
530                         continue;
531                 }
532
533                 layer_data->vc4_data = vc4_data;
534                 layer_data->output_data = output_data;
535                 layer_data->plane_id = vc4_data->plane_res->planes[i];
536
537                 layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
538                                                                    TDM_LAYER_CAPABILITY_GRAPHIC;
539                 output_data->primary_layer = layer_data;
540
541                 TDM_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) capabilities(%x)",
542                                  layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
543                                  layer_data->capabilities);
544
545                 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
546
547                 drmModeFreePlane(plane);
548
549                 /* can't take care of other planes for various hardware devices */
550                 break;
551         }
552
553         return TDM_ERROR_NONE;
554 }
555
556 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4  && LIBDRM_MICRO_VERSION >= 47
557
558 static tdm_error
559 _tdm_vc4_display_get_property(tdm_vc4_data *vc4_data,
560                                                           unsigned int obj_id, unsigned int obj_type,
561                                                           const char *name, unsigned int *value,
562                                                           int *is_immutable)
563 {
564         drmModeObjectPropertiesPtr props = NULL;
565         int i;
566
567         props = drmModeObjectGetProperties(vc4_data->drm_fd, obj_id, obj_type);
568         if (!props)
569                 return TDM_ERROR_OPERATION_FAILED;
570
571         for (i = 0; i < props->count_props; i++) {
572                 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd,
573                                                                   props->props[i]);
574
575                 if (!prop)
576                         continue;
577
578                 if (!strcmp(prop->name, name)) {
579                         if (is_immutable)
580                                 *is_immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
581                         if (value)
582                                 *value = (unsigned int)props->prop_values[i];
583                         drmModeFreeProperty(prop);
584                         drmModeFreeObjectProperties(props);
585                         return TDM_ERROR_NONE;
586                 }
587
588                 drmModeFreeProperty(prop);
589         }
590         drmModeFreeObjectProperties(props);
591         TDM_DBG("coundn't find '%s' property", name);
592         return TDM_ERROR_OPERATION_FAILED;
593 }
594
595 static tdm_error
596 _tdm_vc4_display_create_layer_list_type(tdm_vc4_data *vc4_data)
597 {
598         tdm_vc4_output_data *output_data = NULL;
599         drmModePlanePtr *planes = NULL;
600         unsigned int *types = NULL;
601         unsigned int type = 0;
602         int plane_cnt, primary_cnt, ovl_cnt, cursor_cnt;
603         int opos_next, cpos_next;
604         tdm_error ret;
605         int i;
606
607         if (LIST_IS_EMPTY(&vc4_data->output_list)) {
608                 TDM_ERR("no output");
609                 return TDM_ERROR_OPERATION_FAILED;
610         }
611
612         /* The TDM drm backend only support one output. */
613         LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
614                 break;
615         }
616
617         ret = _tdm_vc4_display_get_property(vc4_data,
618                                                                                 vc4_data->plane_res->planes[0],
619                                                                                 DRM_MODE_OBJECT_PLANE, "type", &type,
620                                                                                 NULL);
621         if (ret != TDM_ERROR_NONE) {
622                 TDM_ERR("plane doesn't have 'type' property. Call a fallback function");
623
624                 /* if a plane doesn't have "type" property, we call a fallback function
625                  * as default
626                  */
627                 return _tdm_vc4_display_create_layer_list(vc4_data);
628         }
629
630         planes = calloc(vc4_data->plane_res->count_planes, sizeof(drmModePlanePtr));
631         if (!planes) {
632                 TDM_ERR("alloc failed");
633                 goto failed;
634         }
635
636         types = calloc(vc4_data->plane_res->count_planes, sizeof(unsigned int));
637         if (!types) {
638                 TDM_ERR("alloc failed");
639                 goto failed;
640         }
641
642         plane_cnt = 0;
643         for (i = 0; i < vc4_data->plane_res->count_planes; i++) {
644                 drmModePlanePtr plane;
645
646                 plane = drmModeGetPlane(vc4_data->drm_fd, vc4_data->plane_res->planes[i]);
647                 if (!plane) {
648                         TDM_ERR("no plane(%d)", vc4_data->plane_res->planes[i]);
649                         goto failed;
650                 }
651
652                 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
653                         drmModeFreePlane(plane);
654                         continue;
655                 }
656
657                 ret = _tdm_vc4_display_get_property(vc4_data,
658                                                                                         vc4_data->plane_res->planes[i],
659                                                                                         DRM_MODE_OBJECT_PLANE, "type", &type,
660                                                                                         NULL);
661                 if (ret != TDM_ERROR_NONE) {
662                         drmModeFreePlane(plane);
663                         TDM_ERR("plane(%d) doesn't have 'type' info",
664                                         vc4_data->plane_res->planes[i]);
665                         goto failed;
666                 }
667
668                 planes[plane_cnt] = plane;
669                 types[plane_cnt] = type;
670                 plane_cnt++;
671         }
672
673         primary_cnt = ovl_cnt = cursor_cnt = 0;
674         for (i = 0; i < plane_cnt; i++) {
675                 if (types[i] == DRM_PLANE_TYPE_CURSOR)
676                         cursor_cnt++;
677                 else if (types[i] == DRM_PLANE_TYPE_OVERLAY)
678                         ovl_cnt++;
679                 else if (types[i] == DRM_PLANE_TYPE_PRIMARY)
680                         primary_cnt++;
681                 else
682                         TDM_ERR("invalid type(%d)", types[i]);
683         }
684
685         if (primary_cnt != 1) {
686                 TDM_ERR("primary layer count(%d) should be one", primary_cnt);
687                 goto failed;
688         }
689
690         /* do not use primary plane(0) because of yuv format displaying problem */
691         /* set 2nd overlay plane to primary, 1st plane is for video */
692         opos_next = 0;
693         cpos_next = ovl_cnt - 1;
694         for (i = 1; i < plane_cnt; i++) {
695                 tdm_vc4_layer_data *layer_data;
696
697                 layer_data = calloc(1, sizeof(tdm_vc4_layer_data));
698                 if (!layer_data) {
699                         TDM_ERR("alloc failed");
700                         goto failed;
701                 }
702
703                 layer_data->vc4_data = vc4_data;
704                 layer_data->output_data = output_data;
705                 layer_data->plane_id = planes[i]->plane_id;
706
707                 if (types[i] == DRM_PLANE_TYPE_CURSOR) {
708                         layer_data->capabilities = TDM_LAYER_CAPABILITY_CURSOR |
709                                                                            TDM_LAYER_CAPABILITY_GRAPHIC;
710                         layer_data->zpos = cpos_next++;
711                 } else if (types[i] == DRM_PLANE_TYPE_OVERLAY) {
712                         if (i == 1) {
713                                 layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY |
714                                                                                    TDM_LAYER_CAPABILITY_GRAPHIC |
715                                                                                    TDM_LAYER_CAPABILITY_SCALE;
716                         } else if (i == 2) {
717                                 layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
718                                                                                    TDM_LAYER_CAPABILITY_GRAPHIC;
719                                 output_data->primary_layer = layer_data;
720                         } else {
721                                 layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY |
722                                                                                    TDM_LAYER_CAPABILITY_GRAPHIC;
723                         }
724                         layer_data->zpos = opos_next++;
725                 } else {
726                         free(layer_data);
727                         continue;
728                 }
729
730                 TDM_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) zpos(%d) capabilities(%x)",
731                                  layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
732                                  layer_data->zpos, layer_data->capabilities);
733
734                 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
735         }
736
737         for (i = 0; i < plane_cnt; i++)
738                 if (planes[i])
739                         drmModeFreePlane(planes[i]);
740
741         free(planes);
742         free(types);
743
744         return TDM_ERROR_NONE;
745
746 failed:
747         if (planes) {
748                 for (i = 0; i < vc4_data->plane_res->count_planes; i++)
749                         if (planes[i])
750                                 drmModeFreePlane(planes[i]);
751                 free(planes);
752         }
753
754         free(types);
755
756         return TDM_ERROR_OPERATION_FAILED;
757 }
758 #endif
759
760 static void
761 _tdm_vc4_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
762 {
763         tdm_vc4_data *vc4_data;
764         tdm_vc4_display_buffer *display_buffer;
765         int ret;
766
767         if (!user_data) {
768                 TDM_ERR("no user_data");
769                 return;
770         }
771         if (!buffer) {
772                 TDM_ERR("no buffer");
773                 return;
774         }
775
776         vc4_data = (tdm_vc4_data *)user_data;
777
778         display_buffer = _tdm_vc4_display_find_buffer(vc4_data, buffer);
779         if (!display_buffer) {
780                 TDM_ERR("no display_buffer");
781                 return;
782         }
783         LIST_DEL(&display_buffer->link);
784
785         if (display_buffer->fb_id > 0) {
786                 ret = drmModeRmFB(vc4_data->drm_fd, display_buffer->fb_id);
787                 if (ret < 0) {
788                         TDM_ERR("rm fb failed");
789                         return;
790                 }
791                 TDM_DBG("drmModeRmFB success!!! fb_id:%d", display_buffer->fb_id);
792         } else
793                 TDM_DBG("drmModeRmFB not called fb_id:%d", display_buffer->fb_id);
794
795         free(display_buffer);
796 }
797
798 tdm_error
799 tdm_vc4_display_create_layer_list(tdm_vc4_data *vc4_data)
800 {
801         tdm_vc4_output_data *output_data = NULL;
802         tdm_error ret;
803
804 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4  && LIBDRM_MICRO_VERSION >= 47
805         if (vc4_data->has_universal_plane)
806                 ret = _tdm_vc4_display_create_layer_list_type(vc4_data);
807         else
808 #endif
809                 ret = _tdm_vc4_display_create_layer_list(vc4_data);
810
811         if (ret != TDM_ERROR_NONE)
812                 return ret;
813
814         LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
815                 if (!output_data->primary_layer) {
816                         TDM_ERR("output(%d) no primary layer", output_data->pipe);
817                         return TDM_ERROR_OPERATION_FAILED;
818                 }
819         }
820
821         return TDM_ERROR_NONE;
822 }
823
824 void
825 tdm_vc4_display_destroy_output_list(tdm_vc4_data *vc4_data)
826 {
827         tdm_vc4_output_data *o = NULL, *oo = NULL;
828
829         if (LIST_IS_EMPTY(&vc4_data->output_list))
830                 return;
831
832         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &vc4_data->output_list, link) {
833
834                 if (o->target_hwc_window)
835                         vc4_output_hwc_window_destroy(o, o->target_hwc_window);
836
837                 if (o->crtc_enabled) {
838                         _tdm_vc4_display_set_crtc(vc4_data, o, 0);
839                         o->crtc_enabled = 0;
840                 }
841
842                 LIST_DEL(&o->link);
843                 if (!LIST_IS_EMPTY(&o->layer_list)) {
844                         tdm_vc4_layer_data *l = NULL, *ll = NULL;
845                         LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
846                                 LIST_DEL(&l->link);
847                                 free(l);
848                         }
849                 }
850                 free(o->vc4_modes);
851                 free(o->output_modes);
852                 free(o);
853         }
854 }
855
856 void
857 tdm_vc4_display_update_output_status(tdm_vc4_data *vc4_data)
858 {
859         tdm_vc4_output_data *output_data = NULL;
860
861         if (LIST_IS_EMPTY(&vc4_data->output_list))
862                 return;
863
864         LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link) {
865                 drmModeConnectorPtr connector;
866                 tdm_output_conn_status new_status;
867
868                 connector = drmModeGetConnector(vc4_data->drm_fd,
869                                                                                 output_data->connector_id);
870                 if (!connector) {
871                         TDM_ERR("no connector: %d", output_data->connector_id);
872                         continue;
873                 }
874
875                 if (connector->connection == DRM_MODE_CONNECTED)
876                         new_status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
877                 else
878                         new_status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
879
880                 _tdm_vc4_output_update_status(output_data, new_status);
881
882                 drmModeFreeConnector(connector);
883         }
884 }
885
886 tdm_error
887 tdm_vc4_display_create_output_list(tdm_vc4_data *vc4_data)
888 {
889         tdm_vc4_output_data *output_data;
890         int i;
891         tdm_error ret;
892
893         RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&vc4_data->output_list),
894                                            TDM_ERROR_OPERATION_FAILED);
895
896         for (i = 0; i < vc4_data->mode_res->count_connectors; i++) {
897                 drmModeConnectorPtr connector;
898                 drmModeEncoderPtr encoder;
899                 int crtc_id = 0, c, j;
900
901                 connector = drmModeGetConnector(vc4_data->drm_fd,
902                                                                                 vc4_data->mode_res->connectors[i]);
903                 if (!connector) {
904                         TDM_ERR("no connector");
905                         ret = TDM_ERROR_OPERATION_FAILED;
906                         goto failed_create;
907                 }
908
909                 /* The TDM drm backend is not interested with disconnected connectors.
910                  * And it only considers 1 connected connector because it is the TDM
911                  * reference backend and can't take care of all hardware devices.
912                  * To support various connectors, planes and crtcs, the new TDM backend
913                  * should be implemented.
914                  */
915                 if (connector->connection != DRM_MODE_CONNECTED) {
916                         drmModeFreeConnector(connector);
917                         continue;
918                 }
919
920                 if (connector->count_encoders != 1) {
921                         TDM_ERR("too many encoders: %d", connector->count_encoders);
922                         drmModeFreeConnector(connector);
923                         ret = TDM_ERROR_OPERATION_FAILED;
924                         goto failed_create;
925                 }
926
927                 encoder = drmModeGetEncoder(vc4_data->drm_fd, connector->encoders[0]);
928                 if (!encoder) {
929                         TDM_ERR("no encoder");
930                         drmModeFreeConnector(connector);
931                         ret = TDM_ERROR_OPERATION_FAILED;
932                         goto failed_create;
933                 }
934
935                 for (c = 0; c < vc4_data->mode_res->count_crtcs; c++) {
936                         if ((encoder->possible_crtcs & (1 << c)) == 0)
937                                 continue;
938
939                         crtc_id = vc4_data->mode_res->crtcs[c];
940                         break;
941                 }
942
943                 if (crtc_id == 0) {
944                         TDM_ERR("no possible crtc");
945                         drmModeFreeConnector(connector);
946                         drmModeFreeEncoder(encoder);
947                         ret = TDM_ERROR_OPERATION_FAILED;
948                         goto failed_create;
949                 }
950
951                 output_data = calloc(1, sizeof(tdm_vc4_output_data));
952                 if (!output_data) {
953                         TDM_ERR("alloc failed");
954                         drmModeFreeConnector(connector);
955                         drmModeFreeEncoder(encoder);
956                         ret = TDM_ERROR_OUT_OF_MEMORY;
957                         goto failed_create;
958                 }
959
960                 LIST_INITHEAD(&output_data->layer_list);
961
962                 output_data->vc4_data = vc4_data;
963                 output_data->connector_id = vc4_data->mode_res->connectors[i];
964                 output_data->encoder_id = encoder->encoder_id;
965                 output_data->crtc_id = crtc_id;
966                 output_data->pipe = c;
967                 output_data->connector_type = connector->connector_type;
968                 output_data->connector_type_id = connector->connector_type_id;
969
970                 if (connector->connection == DRM_MODE_CONNECTED)
971                         output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
972                 else
973                         output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
974
975                 for (j = 0; j < connector->count_props; j++) {
976                         drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd,
977                                                                           connector->props[j]);
978                         if (!prop)
979                                 continue;
980                         if (!strcmp(prop->name, "DPMS")) {
981                                 output_data->dpms_prop_id = connector->props[j];
982                                 drmModeFreeProperty(prop);
983                                 break;
984                         }
985                         drmModeFreeProperty(prop);
986                 }
987
988                 if (output_data->dpms_prop_id == 0)
989                         TDM_WRN("not support DPMS");
990
991                 output_data->count_modes = connector->count_modes;
992                 output_data->vc4_modes = calloc(connector->count_modes,
993                                                                                 sizeof(drmModeModeInfo));
994                 if (!output_data->vc4_modes) {
995                         TDM_ERR("alloc failed");
996                         free(output_data);
997                         drmModeFreeConnector(connector);
998                         drmModeFreeEncoder(encoder);
999                         ret = TDM_ERROR_OUT_OF_MEMORY;
1000                         goto failed_create;
1001                 }
1002                 output_data->output_modes = calloc(connector->count_modes,
1003                                                                                    sizeof(tdm_output_mode));
1004                 if (!output_data->output_modes) {
1005                         TDM_ERR("alloc failed");
1006                         free(output_data->vc4_modes);
1007                         free(output_data);
1008                         drmModeFreeConnector(connector);
1009                         drmModeFreeEncoder(encoder);
1010                         ret = TDM_ERROR_OUT_OF_MEMORY;
1011                         goto failed_create;
1012                 }
1013                 for (j = 0; j < connector->count_modes; j++) {
1014                         output_data->vc4_modes[j] = connector->modes[j];
1015                         _tdm_vc4_display_to_tdm_mode(&output_data->vc4_modes[j],
1016                                                                                  &output_data->output_modes[j]);
1017                 }
1018
1019                 if (vc4_data->hwc_mode) {
1020                         output_data->hwc_enable = 1;
1021                         output_data->target_hwc_window = NULL;
1022                         LIST_INITHEAD(&output_data->hwc_window_list);
1023                 }
1024
1025                 LIST_ADDTAIL(&output_data->link, &vc4_data->output_list);
1026
1027                 TDM_DBG("output_data(%p) connector_id(%d:%d:%d-%d) encoder_id(%d) crtc_id(%d) pipe(%d) dpms_id(%d)",
1028                                 output_data, output_data->connector_id, output_data->status,
1029                                 output_data->connector_type,
1030                                 output_data->connector_type_id, output_data->encoder_id, output_data->crtc_id,
1031                                 output_data->pipe, output_data->dpms_prop_id);
1032
1033                 drmModeFreeEncoder(encoder);
1034                 drmModeFreeConnector(connector);
1035
1036                 /* The TDM drm backend is not interested with disconnected connectors.
1037                  * And it only considers 1 connected connector because it is the TDM
1038                  * reference backend and can't take care of all hardware devices.
1039                  * To support various connectors, planes and crtcs, the new TDM backend
1040                  * should be implemented.
1041                  */
1042                 break;
1043         }
1044
1045         TDM_DBG("output count: %d", vc4_data->mode_res->count_connectors);
1046
1047         return TDM_ERROR_NONE;
1048 failed_create:
1049         tdm_vc4_display_destroy_output_list(vc4_data);
1050         return ret;
1051 }
1052
1053 tdm_error
1054 vc4_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps)
1055 {
1056         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1057
1058         caps->max_layer_count = -1; /* not defined */
1059
1060         return TDM_ERROR_NONE;
1061 }
1062
1063 tdm_output **
1064 vc4_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error)
1065 {
1066         tdm_vc4_data *vc4_data = bdata;
1067         tdm_vc4_output_data *output_data = NULL;
1068         tdm_output **outputs;
1069         tdm_error ret;
1070         int i;
1071
1072         RETURN_VAL_IF_FAIL(vc4_data, NULL);
1073         RETURN_VAL_IF_FAIL(count, NULL);
1074
1075         *count = 0;
1076         LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link)
1077         (*count)++;
1078
1079         if (*count == 0) {
1080                 ret = TDM_ERROR_NONE;
1081                 goto failed_get;
1082         }
1083
1084         /* will be freed in frontend */
1085         outputs = calloc(*count, sizeof(tdm_vc4_output_data *));
1086         if (!outputs) {
1087                 TDM_ERR("failed: alloc memory");
1088                 *count = 0;
1089                 ret = TDM_ERROR_OUT_OF_MEMORY;
1090                 goto failed_get;
1091         }
1092
1093         i = 0;
1094         LIST_FOR_EACH_ENTRY(output_data, &vc4_data->output_list, link)
1095         outputs[i++] = output_data;
1096
1097         if (error)
1098                 *error = TDM_ERROR_NONE;
1099
1100         return outputs;
1101 failed_get:
1102         if (error)
1103                 *error = ret;
1104         return NULL;
1105 }
1106
1107 tdm_error
1108 vc4_display_get_fd(tdm_backend_data *bdata, int *fd)
1109 {
1110         tdm_vc4_data *vc4_data = bdata;
1111
1112         RETURN_VAL_IF_FAIL(vc4_data, TDM_ERROR_INVALID_PARAMETER);
1113         RETURN_VAL_IF_FAIL(fd, TDM_ERROR_INVALID_PARAMETER);
1114
1115         *fd = vc4_data->drm_fd;
1116
1117         return TDM_ERROR_NONE;
1118 }
1119
1120 tdm_error
1121 vc4_display_handle_events(tdm_backend_data *bdata)
1122 {
1123         tdm_vc4_data *vc4_data = bdata;
1124         drmEventContext ctx;
1125
1126         RETURN_VAL_IF_FAIL(vc4_data, TDM_ERROR_INVALID_PARAMETER);
1127
1128         memset(&ctx, 0, sizeof(drmEventContext));
1129
1130         ctx.version = DRM_EVENT_CONTEXT_VERSION;
1131         ctx.page_flip_handler = _tdm_vc4_display_cb_event;
1132         ctx.vblank_handler = _tdm_vc4_display_cb_event;
1133
1134         drmHandleEvent(vc4_data->drm_fd, &ctx);
1135
1136         return TDM_ERROR_NONE;
1137 }
1138
1139 tdm_error
1140 vc4_output_get_capability(tdm_output *output, tdm_caps_output *caps)
1141 {
1142         tdm_vc4_output_data *output_data = output;
1143         tdm_vc4_data *vc4_data;
1144         drmModeConnectorPtr connector = NULL;
1145         drmModeCrtcPtr crtc = NULL;
1146         drmModeObjectPropertiesPtr props = NULL;
1147         int i;
1148         tdm_error ret;
1149
1150         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1151         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1152
1153         memset(caps, 0, sizeof(tdm_caps_output));
1154
1155         vc4_data = output_data->vc4_data;
1156
1157         snprintf(caps->maker, TDM_NAME_LEN, "unknown");
1158         snprintf(caps->model, TDM_NAME_LEN, "unknown");
1159         snprintf(caps->name, TDM_NAME_LEN, "unknown");
1160
1161         caps->status = output_data->status;
1162         caps->type = output_data->connector_type;
1163         caps->type_id = output_data->connector_type_id;
1164
1165         connector = drmModeGetConnector(vc4_data->drm_fd, output_data->connector_id);
1166         RETURN_VAL_IF_FAIL(connector, TDM_ERROR_OPERATION_FAILED);
1167
1168         caps->mode_count = connector->count_modes;
1169         caps->modes = calloc(1, sizeof(tdm_output_mode) * caps->mode_count);
1170         if (!caps->modes) {
1171                 ret = TDM_ERROR_OUT_OF_MEMORY;
1172                 TDM_ERR("alloc failed\n");
1173                 goto failed_get;
1174         }
1175         for (i = 0; i < caps->mode_count; i++)
1176                 caps->modes[i] = output_data->output_modes[i];
1177
1178         caps->mmWidth = connector->mmWidth;
1179         caps->mmHeight = connector->mmHeight;
1180         caps->subpixel = connector->subpixel;
1181
1182         caps->min_w = vc4_data->mode_res->min_width;
1183         caps->min_h = vc4_data->mode_res->min_height;
1184         caps->max_w = vc4_data->mode_res->max_width;
1185         caps->max_h = vc4_data->mode_res->max_height;
1186         caps->preferred_align = -1;
1187
1188         crtc = drmModeGetCrtc(vc4_data->drm_fd, output_data->crtc_id);
1189         if (!crtc) {
1190                 ret = TDM_ERROR_OPERATION_FAILED;
1191                 TDM_ERR("get crtc failed: %m\n");
1192                 goto failed_get;
1193         }
1194
1195         props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->crtc_id,
1196                                                                            DRM_MODE_OBJECT_CRTC);
1197         if (!props) {
1198                 ret = TDM_ERROR_OPERATION_FAILED;
1199                 TDM_ERR("get crtc properties failed: %m\n");
1200                 goto failed_get;
1201         }
1202
1203         caps->prop_count = props->count_props;
1204         caps->props = calloc(1, sizeof(tdm_prop) * caps->prop_count);
1205         if (!caps->props) {
1206                 ret = TDM_ERROR_OUT_OF_MEMORY;
1207                 TDM_ERR("alloc failed\n");
1208                 goto failed_get;
1209         }
1210
1211         for (i = 0; i < caps->prop_count; i++) {
1212                 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd, props->props[i]);
1213                 if (!prop)
1214                         continue;
1215                 snprintf(caps->props[i].name, TDM_NAME_LEN, "%s", prop->name);
1216                 caps->props[i].id = props->props[i];
1217                 drmModeFreeProperty(prop);
1218         }
1219
1220         if (output_data->hwc_enable)
1221                 caps->capabilities |= TDM_OUTPUT_CAPABILITY_HWC;
1222
1223         drmModeFreeObjectProperties(props);
1224         drmModeFreeCrtc(crtc);
1225         drmModeFreeConnector(connector);
1226
1227         return TDM_ERROR_NONE;
1228 failed_get:
1229         drmModeFreeCrtc(crtc);
1230         drmModeFreeObjectProperties(props);
1231         drmModeFreeConnector(connector);
1232         free(caps->modes);
1233         free(caps->props);
1234         memset(caps, 0, sizeof(tdm_caps_output));
1235         return ret;
1236 }
1237
1238 tdm_layer **
1239 vc4_output_get_layers(tdm_output *output,  int *count, tdm_error *error)
1240 {
1241         tdm_vc4_output_data *output_data = output;
1242         tdm_vc4_layer_data *layer_data = NULL;
1243         tdm_layer **layers;
1244         tdm_error ret;
1245         int i;
1246
1247         RETURN_VAL_IF_FAIL(output_data, NULL);
1248         RETURN_VAL_IF_FAIL(count, NULL);
1249
1250         *count = 0;
1251         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1252         (*count)++;
1253
1254         if (*count == 0) {
1255                 ret = TDM_ERROR_NONE;
1256                 goto failed_get;
1257         }
1258
1259         /* will be freed in frontend */
1260         layers = calloc(*count, sizeof(tdm_vc4_layer_data *));
1261         if (!layers) {
1262                 TDM_ERR("failed: alloc memory");
1263                 *count = 0;
1264                 ret = TDM_ERROR_OUT_OF_MEMORY;
1265                 goto failed_get;
1266         }
1267
1268         i = 0;
1269         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1270         layers[i++] = layer_data;
1271
1272         if (error)
1273                 *error = TDM_ERROR_NONE;
1274
1275         return layers;
1276 failed_get:
1277         if (error)
1278                 *error = ret;
1279         return NULL;
1280 }
1281
1282 tdm_error
1283 vc4_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
1284 {
1285         tdm_vc4_output_data *output_data = output;
1286         tdm_vc4_data *vc4_data;
1287         int ret;
1288
1289         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1290         RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1291
1292         vc4_data = output_data->vc4_data;
1293         ret = drmModeObjectSetProperty(vc4_data->drm_fd,
1294                                                                    output_data->crtc_id, DRM_MODE_OBJECT_CRTC,
1295                                                                    id, value.u32);
1296         if (ret < 0) {
1297                 TDM_ERR("set property failed: %m");
1298                 return TDM_ERROR_OPERATION_FAILED;
1299         }
1300
1301         return TDM_ERROR_NONE;
1302 }
1303
1304 tdm_error
1305 vc4_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
1306 {
1307         tdm_vc4_output_data *output_data = output;
1308         tdm_vc4_data *vc4_data;
1309         drmModeObjectPropertiesPtr props;
1310         int i;
1311
1312         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1313         RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1314         RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
1315
1316         vc4_data = output_data->vc4_data;
1317         props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->crtc_id,
1318                                                                            DRM_MODE_OBJECT_CRTC);
1319         if (props == NULL) {
1320                 TDM_ERR("get property failed: %m");
1321                 return TDM_ERROR_OPERATION_FAILED;
1322         }
1323
1324         for (i = 0; i < props->count_props; i++)
1325                 if (props->props[i] == id) {
1326                         (*value).u32 = (uint)props->prop_values[i];
1327                         break;
1328                 }
1329
1330         drmModeFreeObjectProperties(props);
1331
1332         return TDM_ERROR_NONE;
1333 }
1334
1335 tdm_error
1336 vc4_output_wait_vblank(tdm_output *output, int interval, int sync,
1337                                            void *user_data)
1338 {
1339         tdm_vc4_output_data *output_data = output;
1340         tdm_vc4_data *vc4_data;
1341         tdm_vc4_event_data *event_data;
1342         uint target_msc;
1343         tdm_error ret;
1344
1345         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1346
1347         event_data = calloc(1, sizeof(tdm_vc4_event_data));
1348         if (!event_data) {
1349                 TDM_ERR("alloc failed");
1350                 return TDM_ERROR_OUT_OF_MEMORY;
1351         }
1352
1353         vc4_data = output_data->vc4_data;
1354
1355         ret = _tdm_vc4_display_get_cur_msc(vc4_data->drm_fd, output_data->pipe,
1356                                                                            &target_msc);
1357         if (ret != TDM_ERROR_NONE)
1358                 goto failed_vblank;
1359
1360         target_msc += interval;
1361
1362         event_data->type = TDM_DRM_EVENT_TYPE_WAIT;
1363         event_data->output_data = output_data;
1364         event_data->user_data = user_data;
1365
1366         ret = _tdm_vc4_display_wait_vblank(vc4_data->drm_fd, output_data->pipe,
1367                                                                            &target_msc, event_data);
1368         if (ret != TDM_ERROR_NONE)
1369                 goto failed_vblank;
1370
1371         return TDM_ERROR_NONE;
1372 failed_vblank:
1373         free(event_data);
1374         return ret;
1375 }
1376
1377 tdm_error
1378 vc4_output_set_vblank_handler(tdm_output *output,
1379                                                           tdm_output_vblank_handler func)
1380 {
1381         tdm_vc4_output_data *output_data = output;
1382
1383         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1384         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1385
1386         output_data->vblank_func = func;
1387
1388         return TDM_ERROR_NONE;
1389 }
1390
1391 tdm_vc4_layer_data *
1392 _vc4_output_get_layer(tdm_vc4_output_data *output_data, int index)
1393 {
1394         tdm_vc4_layer_data *l = NULL;
1395         LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link)
1396                 if (l->zpos == index)
1397                         return l;
1398
1399         return NULL;
1400 }
1401
1402 static tdm_error
1403 _vc4_layer_attach_window(tdm_vc4_layer_data *layer_data,
1404                                                         tdm_vc4_hwc_window_data *hwc_window_data)
1405 {
1406         tdm_error ret;
1407
1408         if (hwc_window_data == NULL || !hwc_window_data->surface) {
1409                 ret = vc4_layer_unset_buffer(layer_data);
1410                 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
1411         } else {
1412                 ret = vc4_layer_set_info((tdm_layer *)layer_data, (tdm_info_layer *)&(hwc_window_data->info));
1413                 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
1414                 RETURN_VAL_IF_FAIL(hwc_window_data->surface != NULL, TDM_ERROR_INVALID_PARAMETER);
1415                 ret = vc4_layer_set_buffer(layer_data, hwc_window_data->surface);
1416                 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
1417         }
1418
1419         return ret;
1420 }
1421
1422 static int
1423 _get_primary_layer_index(tdm_vc4_output_data *vc4_output)
1424 {
1425         int i = 0;
1426         tdm_vc4_layer_data *layer = NULL;
1427
1428         LIST_FOR_EACH_ENTRY(layer, &vc4_output->layer_list, link) {
1429                 if (layer->capabilities & TDM_LAYER_CAPABILITY_PRIMARY)
1430                         return i;
1431                 i++;
1432         }
1433
1434         return 0;
1435 }
1436
1437 static tdm_error
1438 _tdm_vc4_display_prepare_commit(tdm_vc4_output_data *output_data) {
1439
1440         tdm_vc4_layer_data * layer = NULL;
1441         tdm_vc4_hwc_window_data *hw = NULL;
1442         int num_hw_layer = 0;
1443         int i;
1444         int fb_idx = 0;
1445
1446         RETURN_VAL_IF_FAIL(output_data->need_validate == 0, TDM_ERROR_OPERATION_FAILED);
1447
1448         i = output_data->top_layer_idx;
1449         num_hw_layer = LIST_LENGTH(&output_data->layer_list);
1450         fb_idx = _get_primary_layer_index(output_data);
1451
1452         //set target hwc window
1453         if (output_data->need_target_buffer) {
1454                 layer = _vc4_output_get_layer(output_data, fb_idx);
1455                 _vc4_layer_attach_window(layer, output_data->target_hwc_window);
1456         }
1457
1458         //set hwc windows
1459         LIST_FOR_EACH_ENTRY_REV(hw, &output_data->hwc_window_list, link) {
1460                 if (output_data->need_target_buffer && i == fb_idx) {
1461                         i--;
1462                 }
1463                 if (hw->client_type != TDM_COMPOSITION_DEVICE)
1464                         continue;
1465                 RETURN_VAL_IF_FAIL(i >= 0, TDM_ERROR_OPERATION_FAILED);
1466                 layer = _vc4_output_get_layer(output_data, i--);
1467                 _vc4_layer_attach_window(layer, hw);
1468         }
1469
1470         //disable unused layer
1471         while (i >= 0) {
1472                 layer = _vc4_output_get_layer(output_data, i--);
1473                 _vc4_layer_attach_window(layer, NULL);
1474         }
1475
1476         i = output_data->top_layer_idx + 1;
1477         while (i < num_hw_layer) {
1478                 layer = _vc4_output_get_layer(output_data, i++);
1479                 _vc4_layer_attach_window(layer, NULL);
1480         }
1481
1482         return TDM_ERROR_NONE;
1483 }
1484
1485 tdm_error
1486 vc4_output_commit(tdm_output *output, int sync, void *user_data)
1487 {
1488         tdm_vc4_output_data *output_data = output;
1489         tdm_vc4_data *vc4_data;
1490         tdm_vc4_layer_data *layer_data = NULL;
1491         tdm_error ret;
1492         int do_waitvblank = 1;
1493
1494         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1495
1496         vc4_data = output_data->vc4_data;
1497
1498         if (output_data->hwc_enable) {
1499                 ret = _tdm_vc4_display_prepare_commit(output_data);
1500                 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
1501         }
1502
1503         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1504                 ret = _tdm_vc4_display_commit_layer(layer_data);
1505                 if (ret != TDM_ERROR_NONE)
1506                         return ret;
1507         }
1508
1509         if (do_waitvblank == 1) {
1510                 tdm_vc4_event_data *event_data = calloc(1, sizeof(tdm_vc4_event_data));
1511                 uint target_msc;
1512
1513                 if (!event_data) {
1514                         TDM_ERR("alloc failed");
1515                         return TDM_ERROR_OUT_OF_MEMORY;
1516                 }
1517
1518                 ret = _tdm_vc4_display_get_cur_msc(vc4_data->drm_fd, output_data->pipe,
1519                                                                                    &target_msc);
1520                 if (ret != TDM_ERROR_NONE) {
1521                         free(event_data);
1522                         return ret;
1523                 }
1524
1525                 target_msc++;
1526
1527                 event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
1528                 event_data->output_data = output_data;
1529                 event_data->user_data = user_data;
1530
1531                 ret = _tdm_vc4_display_wait_vblank(vc4_data->drm_fd, output_data->pipe,
1532                                                                                    &target_msc, event_data);
1533                 if (ret != TDM_ERROR_NONE) {
1534                         free(event_data);
1535                         return ret;
1536                 }
1537         }
1538
1539         return TDM_ERROR_NONE;
1540 }
1541
1542 tdm_error
1543 vc4_output_set_commit_handler(tdm_output *output,
1544                                                           tdm_output_commit_handler func)
1545 {
1546         tdm_vc4_output_data *output_data = output;
1547
1548         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1549         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1550
1551         output_data->commit_func = func;
1552
1553         return TDM_ERROR_NONE;
1554 }
1555
1556 tdm_error
1557 vc4_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
1558 {
1559         tdm_vc4_output_data *output_data = output;
1560         tdm_vc4_data *vc4_data;
1561         int ret;
1562
1563         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1564
1565         if (output_data->dpms_prop_id == 0) {
1566                 TDM_WRN("not support DPMS");
1567                 return TDM_ERROR_OPERATION_FAILED;
1568         }
1569
1570         vc4_data = output_data->vc4_data;
1571         ret = drmModeObjectSetProperty(vc4_data->drm_fd,
1572                                                                    output_data->connector_id, DRM_MODE_OBJECT_CONNECTOR,
1573                                                                    output_data->dpms_prop_id, dpms_value);
1574         if (ret < 0) {
1575                 TDM_ERR("set dpms failed: %m");
1576                 return TDM_ERROR_OPERATION_FAILED;
1577         }
1578
1579         return TDM_ERROR_NONE;
1580 }
1581
1582 tdm_error
1583 vc4_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
1584 {
1585         tdm_vc4_output_data *output_data = output;
1586         tdm_vc4_data *vc4_data;
1587         drmModeObjectPropertiesPtr props;
1588         int i;
1589
1590         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1591         RETURN_VAL_IF_FAIL(dpms_value, TDM_ERROR_INVALID_PARAMETER);
1592
1593         vc4_data = output_data->vc4_data;
1594         props = drmModeObjectGetProperties(vc4_data->drm_fd, output_data->connector_id,
1595                                                                            DRM_MODE_OBJECT_CONNECTOR);
1596         if (props == NULL) {
1597                 TDM_ERR("get property failed: %m");
1598                 return TDM_ERROR_OPERATION_FAILED;
1599         }
1600
1601         for (i = 0; i < props->count_props; i++)
1602                 if (props->props[i] == output_data->dpms_prop_id) {
1603                         *dpms_value = (uint)props->prop_values[i];
1604                         break;
1605                 }
1606
1607         drmModeFreeObjectProperties(props);
1608
1609         return TDM_ERROR_NONE;
1610 }
1611
1612 tdm_error
1613 vc4_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
1614 {
1615         tdm_vc4_output_data *output_data = output;
1616
1617         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1618         RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1619
1620         if (output_data->hwc_enable) {
1621
1622                 tdm_hwc_window_info info = {0};
1623                 tdm_error ret = TDM_ERROR_NONE;
1624                 tdm_vc4_hwc_window_data *target_hwc_window;
1625
1626                 info.dst_pos.x = 0;
1627                 info.dst_pos.y = 0;
1628                 info.dst_pos.h = mode->vdisplay;;
1629                 info.dst_pos.w = mode->hdisplay;
1630
1631                 info.src_config.pos.x = 0;
1632                 info.src_config.pos.y = 0;
1633                 info.src_config.pos.h = mode->vdisplay;
1634                 info.src_config.pos.w = mode->hdisplay;
1635
1636                 info.src_config.size.h = mode->hdisplay;
1637                 info.src_config.size.v = mode->vdisplay;
1638                 info.src_config.format = TBM_FORMAT_ARGB8888;
1639
1640                 target_hwc_window = _vc4_output_hwc_window_create(output_data, &info, &ret);
1641                 if (ret != TDM_ERROR_NONE) {
1642                         TDM_ERR("create target hwc window failed (%d)", ret);
1643                         return TDM_ERROR_OPERATION_FAILED;
1644                 }
1645
1646                 if (output_data->target_hwc_window)
1647                         vc4_output_hwc_window_destroy(output, output_data->target_hwc_window);
1648
1649                 output_data->target_hwc_window = target_hwc_window;
1650                 output_data->need_set_crtc = 1;
1651         }
1652
1653         output_data->current_mode = mode;
1654         output_data->mode_changed = 1;
1655         return TDM_ERROR_NONE;
1656 }
1657
1658 tdm_error
1659 vc4_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
1660 {
1661         tdm_vc4_output_data *output_data = output;
1662
1663         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1664         RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1665
1666         *mode = output_data->current_mode;
1667
1668         return TDM_ERROR_NONE;
1669 }
1670
1671 tdm_error
1672 vc4_output_set_status_handler(tdm_output *output,
1673                                                           tdm_output_status_handler func,
1674                                                           void *user_data)
1675 {
1676         tdm_vc4_output_data *output_data = output;
1677
1678         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1679         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1680
1681         output_data->status_func = func;
1682         output_data->status_user_data = user_data;
1683
1684         return TDM_ERROR_NONE;
1685 }
1686
1687 tdm_error
1688 vc4_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
1689 {
1690         tdm_vc4_layer_data *layer_data = layer;
1691         tdm_vc4_data *vc4_data;
1692         drmModePlanePtr plane = NULL;
1693         drmModeObjectPropertiesPtr props = NULL;
1694         int i, format_count = 0;
1695         tdm_error ret;
1696
1697         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1698         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1699
1700         memset(caps, 0, sizeof(tdm_caps_layer));
1701
1702         vc4_data = layer_data->vc4_data;
1703         plane = drmModeGetPlane(vc4_data->drm_fd, layer_data->plane_id);
1704         if (!plane) {
1705                 TDM_ERR("get plane failed: %m");
1706                 ret = TDM_ERROR_OPERATION_FAILED;
1707                 goto failed_get;
1708         }
1709
1710         caps->capabilities = layer_data->capabilities;
1711         caps->zpos = layer_data->zpos;  /* if VIDEO layer, zpos is -1 */
1712
1713         caps->format_count = plane->count_formats;
1714         caps->formats = calloc(1, sizeof(tbm_format) * caps->format_count);
1715         if (!caps->formats) {
1716                 ret = TDM_ERROR_OUT_OF_MEMORY;
1717                 TDM_ERR("alloc failed\n");
1718                 goto failed_get;
1719         }
1720
1721         for (i = 0; i < caps->format_count; i++) {
1722                 /* TODO: kernel reports wrong formats */
1723                 if (plane->formats[i] != DRM_FORMAT_XRGB8888 &&
1724                          plane->formats[i] != DRM_FORMAT_ARGB8888 &&
1725                          plane->formats[i] != DRM_FORMAT_NV12 &&
1726                          plane->formats[i] != DRM_FORMAT_YUV420)
1727                         continue;
1728                 caps->formats[format_count] = tdm_vc4_format_to_tbm_format(plane->formats[i]);
1729                 format_count++;
1730         }
1731
1732         caps->format_count = format_count;
1733
1734         props = drmModeObjectGetProperties(vc4_data->drm_fd, layer_data->plane_id,
1735                                                                            DRM_MODE_OBJECT_PLANE);
1736         if (!props) {
1737                 ret = TDM_ERROR_OPERATION_FAILED;
1738                 TDM_ERR("get plane properties failed: %m\n");
1739                 goto failed_get;
1740         }
1741
1742         caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
1743         if (!caps->props) {
1744                 ret = TDM_ERROR_OUT_OF_MEMORY;
1745                 TDM_ERR("alloc failed\n");
1746                 goto failed_get;
1747         }
1748
1749         caps->prop_count = 0;
1750         for (i = 0; i < props->count_props; i++) {
1751                 drmModePropertyPtr prop = drmModeGetProperty(vc4_data->drm_fd, props->props[i]);
1752                 if (!prop)
1753                         continue;
1754                 if (!strncmp(prop->name, "type", TDM_NAME_LEN)) {
1755                         drmModeFreeProperty(prop);
1756                         continue;
1757                 }
1758                 if (!strncmp(prop->name, "zpos", TDM_NAME_LEN)) {
1759                         drmModeFreeProperty(prop);
1760                         continue;
1761                 }
1762                 snprintf(caps->props[i].name, TDM_NAME_LEN, "%s", prop->name);
1763                 caps->props[i].id = props->props[i];
1764                 caps->prop_count++;
1765                 drmModeFreeProperty(prop);
1766         }
1767
1768         drmModeFreeObjectProperties(props);
1769         drmModeFreePlane(plane);
1770
1771         return TDM_ERROR_NONE;
1772 failed_get:
1773         drmModeFreeObjectProperties(props);
1774         drmModeFreePlane(plane);
1775         free(caps->formats);
1776         free(caps->props);
1777         memset(caps, 0, sizeof(tdm_caps_layer));
1778         return ret;
1779 }
1780
1781 tdm_error
1782 vc4_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value)
1783 {
1784         tdm_vc4_layer_data *layer_data = layer;
1785         tdm_vc4_data *vc4_data;
1786         int ret;
1787
1788         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1789         RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
1790
1791         vc4_data = layer_data->vc4_data;
1792         ret = drmModeObjectSetProperty(vc4_data->drm_fd,
1793                                                                    layer_data->plane_id, DRM_MODE_OBJECT_PLANE,
1794                                                                    id, value.u32);
1795         if (ret < 0) {
1796                 TDM_ERR("set property failed: %m");
1797                 return TDM_ERROR_OPERATION_FAILED;
1798         }
1799
1800         return TDM_ERROR_NONE;
1801 }
1802
1803 tdm_error
1804 vc4_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value)
1805 {
1806         tdm_vc4_layer_data *layer_data = layer;
1807         tdm_vc4_data *vc4_data;
1808         drmModeObjectPropertiesPtr props;
1809         int i;
1810
1811         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1812         RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
1813         RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
1814
1815         vc4_data = layer_data->vc4_data;
1816         props = drmModeObjectGetProperties(vc4_data->drm_fd, layer_data->plane_id,
1817                                                                            DRM_MODE_OBJECT_PLANE);
1818         if (props == NULL) {
1819                 TDM_ERR("get property failed: %m");
1820                 return TDM_ERROR_OPERATION_FAILED;
1821         }
1822
1823         for (i = 0; i < props->count_props; i++)
1824                 if (props->props[i] == id) {
1825                         (*value).u32 = (uint)props->prop_values[i];
1826                         break;
1827                 }
1828
1829         drmModeFreeObjectProperties(props);
1830
1831         return TDM_ERROR_NONE;
1832 }
1833
1834 tdm_error
1835 vc4_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
1836 {
1837         tdm_vc4_layer_data *layer_data = layer;
1838
1839         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1840         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
1841
1842         layer_data->info = *info;
1843         layer_data->info_changed = 1;
1844
1845         return TDM_ERROR_NONE;
1846 }
1847
1848 tdm_error
1849 vc4_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
1850 {
1851         tdm_vc4_layer_data *layer_data = layer;
1852
1853         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1854         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
1855
1856         *info = layer_data->info;
1857
1858         return TDM_ERROR_NONE;
1859 }
1860
1861 tdm_error
1862 vc4_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
1863 {
1864         tdm_vc4_layer_data *layer_data = layer;
1865         tdm_vc4_data *vc4_data;
1866         tdm_vc4_display_buffer *display_buffer;
1867         tdm_error err = TDM_ERROR_NONE;
1868         int ret, i, count;
1869
1870         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1871         RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
1872
1873         vc4_data = layer_data->vc4_data;
1874
1875         display_buffer = _tdm_vc4_display_find_buffer(vc4_data, buffer);
1876         if (!display_buffer) {
1877                 display_buffer = calloc(1, sizeof(tdm_vc4_display_buffer));
1878                 if (!display_buffer) {
1879                         TDM_ERR("alloc failed");
1880                         return TDM_ERROR_OUT_OF_MEMORY;
1881                 }
1882                 display_buffer->buffer = buffer;
1883
1884                 err = tdm_buffer_add_destroy_handler(buffer, _tdm_vc4_display_cb_destroy_buffer,
1885                                                                                          vc4_data);
1886                 if (err != TDM_ERROR_NONE) {
1887                         TDM_ERR("add destroy handler fail");
1888                         free(display_buffer);
1889                         return TDM_ERROR_OPERATION_FAILED;
1890                 }
1891
1892                 LIST_ADDTAIL(&display_buffer->link, &vc4_data->buffer_list);
1893         }
1894
1895         if (display_buffer->fb_id == 0) {
1896                 unsigned int width;
1897                 unsigned int height;
1898                 unsigned int format;
1899                 unsigned int handles[4] = {0,};
1900                 unsigned int pitches[4] = {0,};
1901                 unsigned int offsets[4] = {0,};
1902                 unsigned int size;
1903                 tbm_bo bo;
1904
1905                 width = tbm_surface_get_width(buffer);
1906                 height = tbm_surface_get_height(buffer);
1907                 format = tbm_surface_get_format(buffer);
1908                 count = tbm_surface_internal_get_num_planes(format);
1909
1910                 bo = tbm_surface_internal_get_bo(buffer, 0);
1911                 handles[0] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
1912                 for (i = 1; i < count; i++)
1913                         handles[i] = handles[0];
1914
1915                 for (i = 0; i < count; i++)
1916                         tbm_surface_internal_get_plane_data(buffer, i, &size, &offsets[i], &pitches[i]);
1917
1918                 ret = drmModeAddFB2(vc4_data->drm_fd, width, height, format,
1919                                                         handles, pitches, offsets, &display_buffer->fb_id, 0);
1920                 if (ret < 0) {
1921                         TDM_ERR("add fb failed: %m");
1922                         return TDM_ERROR_OPERATION_FAILED;
1923                 }
1924                 TDM_DBG("vc4_data->drm_fd : %d, display_buffer->fb_id:%u", vc4_data->drm_fd,
1925                                 display_buffer->fb_id);
1926
1927                 if (IS_RGB(format))
1928                         display_buffer->width = pitches[0] >> 2;
1929                 else
1930                         display_buffer->width = pitches[0];
1931         }
1932
1933         layer_data->display_buffer = display_buffer;
1934         layer_data->display_buffer_changed = 1;
1935
1936         return TDM_ERROR_NONE;
1937 }
1938
1939 tdm_error
1940 vc4_layer_unset_buffer(tdm_layer *layer)
1941 {
1942         tdm_vc4_layer_data *layer_data = layer;
1943
1944         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1945
1946         layer_data->display_buffer = NULL;
1947         layer_data->display_buffer_changed = 1;
1948
1949         return TDM_ERROR_NONE;
1950 }
1951
1952 tdm_error
1953 tdm_vc4_output_insert_hwc_window(tdm_vc4_output_data *output, tdm_vc4_hwc_window_data *hwc_window)
1954 {
1955         tdm_vc4_hwc_window_data *item = NULL;
1956         LIST_FOR_EACH_ENTRY_REV(item, &output->hwc_window_list, link) {
1957                 if (item == hwc_window)
1958                         return TDM_ERROR_OPERATION_FAILED;
1959
1960                 if (item->zpos <= hwc_window->zpos)
1961                         break;
1962         }
1963
1964         LIST_INSERT_AFTER(&item->link, &hwc_window->link);
1965
1966         return TDM_ERROR_NONE;
1967 }
1968
1969 int
1970 _vc4_output_get_changed_number(tdm_vc4_output_data *vc4_output)
1971 {
1972         int num = 0;
1973         tdm_vc4_hwc_window_data *hw = NULL;
1974
1975         LIST_FOR_EACH_ENTRY(hw, &vc4_output->hwc_window_list, link) {
1976                 if (hw->client_type != hw->validated_type)
1977                         num++;
1978         }
1979
1980         return num;
1981 }
1982
1983 tdm_hwc_window *
1984 _vc4_output_hwc_window_create(tdm_output *output, tdm_hwc_window_info *info, tdm_error *error)
1985 {
1986         tdm_vc4_hwc_window_data *vc4_hwc_window = NULL;
1987         tdm_vc4_output_data *vc4_output = output;
1988
1989         if (error)
1990                 *error = TDM_ERROR_NONE;
1991
1992         if (!vc4_output) {
1993                 TDM_ERR("invalid params");
1994                 if (error)
1995                         *error = TDM_ERROR_INVALID_PARAMETER;
1996                 return NULL;
1997         }
1998
1999         vc4_hwc_window = calloc(1, sizeof(tdm_vc4_hwc_window_data));
2000         if (!vc4_hwc_window) {
2001                 TDM_ERR("alloc failed");
2002                 if (error)
2003                         *error = TDM_ERROR_OUT_OF_MEMORY;
2004                 return NULL;
2005         }
2006
2007         if ((vc4_hwc_window->vc4_data = vc4_output->vc4_data) == NULL) {
2008                 TDM_ERR("invalid params");
2009                 if (error)
2010                         *error = TDM_ERROR_INVALID_PARAMETER;
2011                 goto fail;
2012         }
2013
2014         vc4_hwc_window->output_data = output;
2015         vc4_hwc_window->zpos = 0;
2016
2017         if (info)
2018                 memcpy(&vc4_hwc_window->info, info, sizeof(tdm_hwc_window_info));
2019
2020         return vc4_hwc_window;
2021 fail:
2022         if (vc4_hwc_window)
2023                 free(vc4_hwc_window);
2024
2025         return NULL;
2026 }
2027
2028 tdm_hwc_window *
2029 vc4_output_hwc_window_create(tdm_output *output, tdm_error *error)
2030 {
2031         tdm_vc4_hwc_window_data *vc4_hwc_window = NULL;
2032         tdm_vc4_output_data *vc4_output = output;
2033         tdm_error err;
2034
2035         vc4_hwc_window = _vc4_output_hwc_window_create(vc4_output, NULL, error);
2036         if (vc4_hwc_window == NULL)
2037                 return NULL;
2038
2039         err = tdm_vc4_output_insert_hwc_window(vc4_output, vc4_hwc_window);
2040         if (err != TDM_ERROR_NONE) {
2041                 if (error)
2042                         *error = err;
2043                 free(vc4_hwc_window);
2044                 return NULL;
2045         }
2046
2047         TDM_DBG("hwc_window(%p) create", vc4_hwc_window);
2048         if (error)
2049                 *error = TDM_ERROR_NONE;
2050
2051         return vc4_hwc_window;
2052 }
2053
2054 tdm_error
2055 vc4_output_hwc_window_destroy(tdm_output *output, tdm_hwc_window *hwc_window)
2056 {
2057         tdm_vc4_hwc_window_data *vc4_hwc_window = hwc_window;
2058
2059         LIST_DEL(&vc4_hwc_window->link);
2060
2061         free(vc4_hwc_window);
2062
2063         return TDM_ERROR_NONE;
2064 }
2065
2066 static const char *
2067 _comp_to_str(tdm_hwc_window_composition composition_type)
2068 {
2069         if (composition_type == TDM_COMPOSITION_CLIENT)
2070                 return "CLIENT";
2071         else if (composition_type == TDM_COMPOSITION_DEVICE_CANDIDATE)
2072                 return "DEVICE_CANDIDATE";
2073         else if (composition_type == TDM_COMPOSITION_DEVICE)
2074                 return "DEVICE";
2075         else if (composition_type == TDM_COMPOSITION_CURSOR)
2076                 return "CURSOR";
2077
2078         return "unknown";
2079 }
2080
2081 tdm_error
2082 vc4_output_hwc_validate(tdm_output *output, uint32_t *num_types)
2083 {
2084         tdm_vc4_output_data *vc4_output = output;
2085         tdm_vc4_data *vc4_data = NULL;
2086         RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER);
2087         RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
2088         tdm_vc4_hwc_window_data *hw = NULL;
2089         int hw_layer_count = 0;
2090         int need_target_buffer = 0;
2091         int max_hw_layer = LIST_LENGTH(&vc4_output->layer_list);
2092         int fb_index = _get_primary_layer_index(vc4_output);
2093         int i = 0;
2094         int top_layer_idx = fb_index;
2095
2096         vc4_data = vc4_output->vc4_data;
2097         RETURN_VAL_IF_FAIL(vc4_data != NULL, TDM_ERROR_INVALID_PARAMETER);
2098
2099         if (vc4_output->need_set_crtc) {
2100                 need_target_buffer = 1;
2101
2102                 LIST_FOR_EACH_ENTRY(hw, &vc4_output->hwc_window_list, link) {
2103                         hw->validated_type = TDM_COMPOSITION_CLIENT;
2104                 }
2105         } else {
2106                 int layer_idx;
2107                 int num_hwc_windows = LIST_LENGTH(&vc4_output->hwc_window_list);
2108
2109                 LIST_FOR_EACH_ENTRY(hw, &vc4_output->hwc_window_list, link) {
2110                         hw->validated_type = TDM_COMPOSITION_CLIENT;
2111                 }
2112
2113                 /* mark the top window */
2114                 if (num_hwc_windows > 1) {
2115                         layer_idx = max_hw_layer;
2116                         LIST_FOR_EACH_ENTRY_REV(hw, &vc4_output->hwc_window_list, link) {
2117                                 layer_idx--;
2118                                 if (hw->client_type == TDM_COMPOSITION_DEVICE && layer_idx != fb_index) {
2119                                         //check format
2120                                         if (IS_RGB(hw->info.src_config.format)) {
2121                                                 hw->validated_type = TDM_COMPOSITION_DEVICE;
2122                                                 hw_layer_count++;
2123                                                 top_layer_idx++;
2124                                                 continue;
2125                                         }
2126                                 }
2127                                 break;
2128                         }
2129                 }
2130
2131                 if ((num_hwc_windows - hw_layer_count) > (fb_index + 1))
2132                         need_target_buffer = 1;
2133
2134                 max_hw_layer = fb_index + 1;
2135                 if (need_target_buffer)
2136                         max_hw_layer--;
2137
2138                 /* mark the bottom windows */
2139                 layer_idx = -1;
2140                 LIST_FOR_EACH_ENTRY(hw, &vc4_output->hwc_window_list, link) {
2141                         layer_idx++;
2142                         /* break if the remaining windows are already marked */
2143                         if (hw->validated_type == TDM_COMPOSITION_DEVICE)
2144                                 break;
2145                         if (hw->client_type == TDM_COMPOSITION_DEVICE && layer_idx < max_hw_layer) {
2146                                 //check format
2147                                 if (IS_RGB(hw->info.src_config.format)) {
2148                                         hw->validated_type = TDM_COMPOSITION_DEVICE;
2149                                         hw_layer_count++;
2150                                         continue;
2151                                 }
2152                         }
2153
2154                         need_target_buffer = 1;
2155                         break;
2156                 }
2157         }
2158
2159         LIST_FOR_EACH_ENTRY(hw, &vc4_output->hwc_window_list, link) {
2160                 if (need_target_buffer && fb_index == i++)
2161                         TDM_DBG(" window(%p) target", vc4_output->target_hwc_window);
2162                 else
2163                         TDM_DBG(" window(%p) type: %s -> %s", hw,
2164                                         _comp_to_str(hw->client_type), _comp_to_str(hw->validated_type));
2165         }
2166
2167         if (need_target_buffer)
2168                 hw_layer_count++;
2169
2170         vc4_output->need_target_buffer = need_target_buffer;
2171         vc4_output->hw_layer_count = hw_layer_count;
2172         vc4_output->top_layer_idx = top_layer_idx;
2173
2174         *num_types = _vc4_output_get_changed_number(vc4_output);
2175
2176         if (*num_types == 0)
2177                 vc4_output->need_validate = 0;
2178
2179         return TDM_ERROR_NONE;
2180 }
2181
2182 tdm_error
2183 vc4_output_hwc_get_changed_composition_types(tdm_output *output,
2184                                                                                  uint32_t *num_elements,
2185                                                                                  tdm_hwc_window **hwc_window,
2186                                                                                  tdm_hwc_window_composition *composition_types)
2187 {
2188         tdm_vc4_output_data *vc4_output = output;
2189         int num = 0;
2190
2191         RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER);
2192         RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER);
2193
2194         if ((hwc_window == NULL) || (composition_types == NULL)) {
2195                 *num_elements = _vc4_output_get_changed_number(vc4_output);
2196                 return TDM_ERROR_NONE;
2197         }
2198
2199         tdm_vc4_hwc_window_data *hw = NULL;
2200         LIST_FOR_EACH_ENTRY_REV(hw, &vc4_output->hwc_window_list, link) {
2201
2202                 if (num >= *num_elements)
2203                         break;
2204
2205                 if (hw->client_type != hw->validated_type) {
2206                         composition_types[num] = hw->validated_type;
2207                         hwc_window[num] = hw;
2208                         num++;
2209                 }
2210         }
2211
2212         //set real num of changed composition types
2213         *num_elements = num;
2214
2215         return TDM_ERROR_NONE;
2216 }
2217
2218 tdm_error
2219 vc4_output_hwc_accept_changes(tdm_output *output)
2220 {
2221         tdm_vc4_output_data *vc4_output = output;
2222
2223         RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER);
2224
2225         tdm_vc4_hwc_window_data *hw = NULL;
2226         LIST_FOR_EACH_ENTRY_REV(hw, &vc4_output->hwc_window_list, link)
2227                 hw->client_type = hw->validated_type;
2228
2229         vc4_output->need_validate = 0;
2230
2231         return TDM_ERROR_NONE;
2232 }
2233
2234 tbm_surface_queue_h
2235 vc4_output_hwc_get_target_buffer_queue(tdm_output *output, tdm_error *error)
2236 {
2237         tdm_vc4_output_data *vc4_output = output;
2238         tbm_surface_queue_h tqueue = NULL;
2239
2240         if (error)
2241                 *error = TDM_ERROR_INVALID_PARAMETER;
2242
2243         RETURN_VAL_IF_FAIL(vc4_output != NULL, NULL);
2244
2245         if (vc4_output->target_hwc_window == NULL) {
2246                 if (error)
2247                         *error = TDM_ERROR_OPERATION_FAILED;
2248                 return NULL;
2249         }
2250
2251         tqueue = vc4_hwc_window_get_tbm_buffer_queue(vc4_output->target_hwc_window, error);
2252         RETURN_VAL_IF_FAIL(tqueue, NULL);
2253
2254         if (error)
2255                 *error = TDM_ERROR_NONE;
2256
2257         return tqueue;
2258 }
2259
2260 tdm_error
2261 vc4_output_hwc_set_client_target_buffer(tdm_output *output, tbm_surface_h buffer,
2262                                                                         tdm_hwc_region damage, tdm_hwc_window **composited_wnds,
2263                                                                         uint32_t num_wnds)
2264 {
2265         tdm_vc4_output_data *vc4_output = output;
2266         tdm_error err;
2267
2268         RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER);
2269         RETURN_VAL_IF_FAIL(vc4_output->target_hwc_window != NULL, TDM_ERROR_OPERATION_FAILED);
2270
2271         err = vc4_hwc_window_set_buffer(vc4_output->target_hwc_window, buffer);
2272         RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err);
2273
2274         err = vc4_hwc_window_set_buffer_damage(vc4_output->target_hwc_window, damage);
2275         RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err);
2276
2277         return TDM_ERROR_NONE;
2278 }
2279
2280
2281 tbm_surface_queue_h
2282 vc4_hwc_window_get_tbm_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error)
2283 {
2284         tdm_vc4_hwc_window_data *vc4_hwc_window = NULL;
2285         tdm_vc4_output_data *vc4_output = NULL;
2286         tbm_surface_queue_h tqueue = NULL;
2287         tbm_format format;
2288
2289         if (error)
2290                 *error = TDM_ERROR_INVALID_PARAMETER;
2291
2292         RETURN_VAL_IF_FAIL(hwc_window != NULL, NULL);
2293         vc4_hwc_window = hwc_window;
2294         vc4_output = vc4_hwc_window->output_data;
2295         RETURN_VAL_IF_FAIL(vc4_output != NULL, NULL);
2296
2297         int wight = vc4_hwc_window->info.src_config.size.h;
2298         int hight = vc4_hwc_window->info.src_config.size.v;
2299
2300         format = vc4_hwc_window->info.src_config.format;
2301
2302         tqueue = tbm_surface_queue_create(3, wight, hight, format, TBM_BO_SCANOUT);
2303         if (error)
2304                 *error = TDM_ERROR_OPERATION_FAILED;
2305         RETURN_VAL_IF_FAIL(tqueue != NULL, NULL);
2306
2307         if (error)
2308                 *error = TDM_ERROR_NONE;
2309
2310         return tqueue;
2311
2312 }
2313
2314 tdm_error
2315 vc4_hwc_window_set_zpos(tdm_hwc_window *hwc_window, uint32_t zpos)
2316 {
2317         tdm_vc4_hwc_window_data *vc4_hwc_window = hwc_window;
2318         tdm_vc4_output_data *vc4_output;
2319
2320         RETURN_VAL_IF_FAIL(vc4_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
2321         RETURN_VAL_IF_FAIL(zpos < 256, TDM_ERROR_INVALID_PARAMETER);
2322
2323         vc4_output = vc4_hwc_window->output_data;
2324         RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER);
2325
2326         if (vc4_hwc_window->zpos == zpos)
2327                 return TDM_ERROR_NONE;
2328
2329         LIST_DEL(&vc4_hwc_window->link);
2330
2331         vc4_hwc_window->zpos = zpos;
2332
2333         tdm_vc4_output_insert_hwc_window(vc4_output, vc4_hwc_window);
2334
2335         vc4_output->need_validate = 1;
2336
2337         return TDM_ERROR_NONE;
2338
2339 }
2340
2341 tdm_error
2342 vc4_hwc_window_set_composition_type(tdm_hwc_window *hwc_window,
2343                                                                         tdm_hwc_window_composition comp_type)
2344 {
2345         tdm_vc4_hwc_window_data *vc4_hwc_window = hwc_window;
2346         tdm_vc4_output_data *vc4_output = vc4_hwc_window->output_data;
2347
2348         RETURN_VAL_IF_FAIL(vc4_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
2349         RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER);
2350
2351         if (vc4_hwc_window->client_type == comp_type)
2352                 return TDM_ERROR_NONE;
2353
2354         vc4_hwc_window->client_type = comp_type;
2355         vc4_output->need_validate = 1;
2356
2357         return TDM_ERROR_NONE;
2358
2359 }
2360
2361 tdm_error
2362 vc4_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_hwc_region damage)
2363 {
2364         tdm_vc4_hwc_window_data *vc4_hwc_window = hwc_window;
2365         tdm_vc4_output_data *vc4_output = vc4_hwc_window->output_data;
2366
2367         RETURN_VAL_IF_FAIL(vc4_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
2368         RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER);
2369
2370         //TODO::
2371
2372         return TDM_ERROR_NONE;
2373 }
2374
2375 tdm_error
2376 vc4_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info)
2377 {
2378         tdm_vc4_hwc_window_data *vc4_hwc_window = hwc_window;
2379         tdm_vc4_output_data *vc4_output = vc4_hwc_window->output_data;
2380
2381         RETURN_VAL_IF_FAIL(vc4_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
2382         RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER);
2383
2384         if (!memcmp(&vc4_hwc_window->info, info, sizeof(tdm_hwc_window_info)))
2385                 return TDM_ERROR_NONE;
2386
2387         vc4_hwc_window->info = *info;
2388         vc4_output->need_validate = 1;
2389
2390         return TDM_ERROR_NONE;
2391 }
2392
2393 tdm_error
2394 vc4_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h surface)
2395 {
2396         tdm_vc4_hwc_window_data *vc4_hwc_window = hwc_window;
2397         tdm_vc4_output_data *vc4_output;
2398         tdm_vc4_data *vc4_data;
2399         tdm_error err = TDM_ERROR_OPERATION_FAILED;
2400
2401         RETURN_VAL_IF_FAIL(vc4_hwc_window != NULL, err);
2402
2403         vc4_output = vc4_hwc_window->output_data;
2404         vc4_data = vc4_hwc_window->vc4_data;
2405
2406         RETURN_VAL_IF_FAIL(vc4_output != NULL, err);
2407         RETURN_VAL_IF_FAIL(vc4_data != NULL, err);
2408
2409         if (vc4_hwc_window->surface == surface)
2410                 return TDM_ERROR_NONE;
2411
2412         vc4_hwc_window->surface = surface;
2413
2414         return TDM_ERROR_NONE;
2415 }