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