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