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