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