Implementation of TDM_HWC
[platform/adaptation/nexell/libtdm-nexell.git] / src / tdm_nexell_display.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include <drm_fourcc.h>
6 #include <tdm_helper.h>
7
8 #include "tdm_nexell.h"
9 #include "tdm_nexell_pp.h"
10
11 #define MIN_WIDTH   32
12
13 static drmModeModeInfoPtr
14 _tdm_nexell_display_get_mode(tdm_nexell_output_data *output_data)
15 {
16         int i;
17
18         if (!output_data->current_mode) {
19                 TDM_ERR("no output_data->current_mode");
20                 return NULL;
21         }
22
23         for (i = 0; i < output_data->count_modes; i++) {
24                 drmModeModeInfoPtr drm_mode = &output_data->drm_modes[i];
25                 if ((drm_mode->hdisplay == output_data->current_mode->hdisplay) &&
26                     (drm_mode->vdisplay == output_data->current_mode->vdisplay) &&
27                     (drm_mode->vrefresh == output_data->current_mode->vrefresh) &&
28                     (drm_mode->flags == output_data->current_mode->flags) &&
29                     (drm_mode->type == output_data->current_mode->type) &&
30                     !(strncmp(drm_mode->name, output_data->current_mode->name, TDM_NAME_LEN)))
31                         return drm_mode;
32         }
33
34         return NULL;
35 }
36
37 static void
38 _tdm_nexell_display_to_tdm_mode(drmModeModeInfoPtr drm_mode,
39                              tdm_output_mode *tdm_mode)
40 {
41         tdm_mode->clock = drm_mode->clock;
42         tdm_mode->hdisplay = drm_mode->hdisplay;
43         tdm_mode->hsync_start = drm_mode->hsync_start;
44         tdm_mode->hsync_end = drm_mode->hsync_end;
45         tdm_mode->htotal = drm_mode->htotal;
46         tdm_mode->hskew = drm_mode->hskew;
47         tdm_mode->vdisplay = drm_mode->vdisplay;
48         tdm_mode->vsync_start = drm_mode->vsync_start;
49         tdm_mode->vsync_end = drm_mode->vsync_end;
50         tdm_mode->vtotal = drm_mode->vtotal;
51         tdm_mode->vscan = drm_mode->vscan;
52         tdm_mode->vrefresh = drm_mode->vrefresh;
53         tdm_mode->flags = drm_mode->flags;
54         tdm_mode->type = drm_mode->type;
55         snprintf(tdm_mode->name, TDM_NAME_LEN, "%s", drm_mode->name);
56 }
57
58 static tdm_error
59 _tdm_nexell_display_get_cur_msc (int fd, int pipe, uint *msc)
60 {
61         drmVBlank vbl;
62
63         vbl.request.type = DRM_VBLANK_RELATIVE;
64         if (pipe == 1)
65                 vbl.request.type |= DRM_VBLANK_SECONDARY;
66         else if (pipe > 1)
67                 vbl.request.type |= pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
68
69         vbl.request.sequence = 0;
70         if (drmWaitVBlank(fd, &vbl)) {
71                 TDM_ERR("get vblank counter failed: %m");
72                 *msc = 0;
73                 return TDM_ERROR_OPERATION_FAILED;
74         }
75
76         *msc = vbl.reply.sequence;
77
78         return TDM_ERROR_NONE;
79 }
80
81 static tdm_error
82 _tdm_nexell_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data)
83 {
84         drmVBlank vbl;
85
86         vbl.request.type =  DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
87         if (pipe == 1)
88                 vbl.request.type |= DRM_VBLANK_SECONDARY;
89         else if (pipe > 1)
90                 vbl.request.type |= pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
91
92         vbl.request.sequence = *target_msc;
93         vbl.request.signal = (unsigned long)(uintptr_t)data;
94
95         if (drmWaitVBlank(fd, &vbl)) {
96                 TDM_ERR("wait vblank failed: %m");
97                 *target_msc = 0;
98                 return TDM_ERROR_OPERATION_FAILED;
99         }
100
101         *target_msc = vbl.reply.sequence;
102
103         return TDM_ERROR_NONE;
104 }
105
106 static tdm_error
107 _tdm_nexell_display_set_fb(tdm_nexell_data *nexell_data, tbm_surface_h buffer, unsigned int *id)
108 {
109         unsigned int width;
110         unsigned int height;
111         unsigned int format;
112         unsigned int handles[4] = {0,};
113         unsigned int pitches[4] = {0,};
114         unsigned int offsets[4] = {0,};
115         unsigned int size;
116         unsigned int fb_id;
117         int ret, count, i;
118
119         width = tbm_surface_get_width(buffer);
120         height = tbm_surface_get_height(buffer);
121         format = tbm_surface_get_format(buffer);
122         count = tbm_surface_internal_get_num_bos(buffer);
123         for (i = 0; i < count; i++) {
124                 tbm_bo bo = tbm_surface_internal_get_bo(buffer, i);
125                 handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
126         }
127         count = tbm_surface_internal_get_num_planes(format);
128         for (i = 0; i < count; i++)
129                 tbm_surface_internal_get_plane_data(buffer, i, &size, &offsets[i], &pitches[i]);
130
131         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)",
132                         nexell_data->drm_fd, width, height, FOURCC_STR(format),
133                         handles[0], handles[1], handles[2], pitches[0], pitches[1], pitches[2],
134                         offsets[0], offsets[1], offsets[2], buffer);
135
136         ret = drmModeAddFB2(nexell_data->drm_fd, width, height, format,
137                                                 handles, pitches, offsets, &fb_id, 0);
138         if (ret < 0) {
139                 TDM_ERR("add fb failed: %m");
140                 return TDM_ERROR_OPERATION_FAILED;
141         }
142         TDM_DBG("AddFB2 success: drm_fd(%d) fb_id(%u)", nexell_data->drm_fd, fb_id);
143
144         *id = fb_id;
145         return TDM_ERROR_NONE;
146 }
147
148 static tdm_error
149 _tdm_nexell_output_update_status(tdm_nexell_output_data *output_data,
150                               tdm_output_conn_status status)
151 {
152         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
153
154         if (output_data->status == status)
155                 return TDM_ERROR_NONE;
156
157         output_data->status = status;
158
159         if (output_data->status_func)
160                 output_data->status_func(output_data, status,
161                                          output_data->status_user_data);
162
163         return TDM_ERROR_NONE;
164 }
165
166 static tdm_error
167 _tdm_nexell_display_set_crtc(tdm_nexell_data *nexell_data, tdm_nexell_output_data *output_data, int set)
168 {
169         int ret;
170
171         output_data->mode_changed = 0;
172
173         if (set) {
174                 tbm_surface_h buffer = NULL;
175                 tbm_surface_info_s info;
176                 drmModeModeInfoPtr mode;
177                 unsigned int fb_id = 0;
178
179                 if (!output_data->current_mode)
180                         return TDM_ERROR_OPERATION_FAILED;
181
182                 mode = _tdm_nexell_display_get_mode(output_data);
183                 if (!mode) {
184                         TDM_ERR("couldn't find proper mode");
185                         return TDM_ERROR_BAD_REQUEST;
186                 }
187
188                 /* A buffer which is set to crtc should has TBM_BO_SCANOUT flag */
189                 buffer = tbm_surface_internal_create_with_flags(output_data->current_mode->hdisplay,
190                                                                                         output_data->current_mode->vdisplay,
191                                                                                         TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
192                 RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_OPERATION_FAILED);
193
194                 if (tbm_surface_map(buffer, TBM_SURF_OPTION_WRITE, &info) != TBM_ERROR_NONE) {
195                         tbm_surface_destroy(buffer);
196                         return TDM_ERROR_OPERATION_FAILED;
197                 }
198                 memset(info.planes[0].ptr, 0x0, info.size);
199
200                 tbm_surface_unmap(buffer);
201
202                 if (_tdm_nexell_display_set_fb(nexell_data, buffer, &fb_id) != TDM_ERROR_NONE) {
203                         tbm_surface_destroy(buffer);
204                         return TDM_ERROR_OPERATION_FAILED;
205                 }
206
207                 TDM_DBG("drmModeSetCrtc drm_fd(%d) crtc_id(%u) fb_id(%u) mode(%u,%u)",
208                                 nexell_data->drm_fd, output_data->crtc_id, fb_id,
209                                 mode->hdisplay, mode->vdisplay);
210
211                 if (drmModeSetCrtc(nexell_data->drm_fd, output_data->crtc_id,
212                                                    fb_id, 0, 0,
213                                                    &output_data->connector_id, 1, mode)) {
214                         TDM_ERR("set crtc failed: %m");
215                         ret = drmModeRmFB(nexell_data->drm_fd, fb_id);
216                         if (ret < 0)
217                                 TDM_ERR("rm fb failed fb_id(%u)", fb_id);
218                         tbm_surface_destroy(buffer);
219                         return TDM_ERROR_OPERATION_FAILED;
220                 }
221
222                 _tdm_nexell_output_update_status(output_data, TDM_OUTPUT_CONN_STATUS_MODE_SETTED);
223
224                 if (output_data->crtc_buffer) {
225                         ret = drmModeRmFB(nexell_data->drm_fd, output_data->crtc_fb_id);
226                         if (ret < 0)
227                                 TDM_ERR("rm fb failed fb_id(%u)", output_data->crtc_fb_id);
228                         tbm_surface_destroy(output_data->crtc_buffer);
229                 }
230
231                 output_data->crtc_buffer = buffer;
232                 output_data->crtc_fb_id = fb_id;
233         } else {
234                 TDM_DBG("drmModeSetCrtc unset drm_fd(%d) crtc_id(%u)",
235                                 nexell_data->drm_fd, output_data->crtc_id);
236
237                 if (drmModeSetCrtc(nexell_data->drm_fd, output_data->crtc_id,
238                                                    0, 0, 0, NULL, 0, NULL)) {
239                         TDM_ERR("unset crtc failed: %m");
240                         return TDM_ERROR_OPERATION_FAILED;
241                 }
242
243                 if (output_data->crtc_buffer) {
244                         ret = drmModeRmFB(nexell_data->drm_fd, output_data->crtc_fb_id);
245                         if (ret < 0)
246                                 TDM_ERR("rm fb failed fb_id(%u)", output_data->crtc_fb_id);
247                         tbm_surface_destroy(output_data->crtc_buffer);
248                 }
249                 output_data->crtc_buffer = NULL;
250                 output_data->crtc_fb_id = 0;
251         }
252
253         return TDM_ERROR_NONE;
254 }
255
256 static tdm_error
257 _tdm_nexell_display_commit_layer(tdm_nexell_layer_data *layer_data)
258 {
259         tdm_nexell_data *nexell_data = layer_data->nexell_data;
260         tdm_nexell_output_data *output_data = layer_data->output_data;
261         uint32_t fx, fy, fw, fh;
262         int crtc_w;
263
264         if (!layer_data->display_buffer_changed && !layer_data->info_changed)
265                 return TDM_ERROR_NONE;
266
267         // set crtc if crtc is not available and if mode is changed.
268         if (!output_data->crtc_enabled || output_data->mode_changed) {
269                 if (_tdm_nexell_display_set_crtc(nexell_data, output_data, 1) != TDM_ERROR_NONE)
270                         return TDM_ERROR_OPERATION_FAILED;
271
272                 output_data->crtc_enabled = 1;
273
274                 return TDM_ERROR_NONE;
275         }
276
277         // check if the crtc is available
278         if (output_data->current_mode)
279                 crtc_w = output_data->current_mode->hdisplay;
280         else {
281                 drmModeCrtcPtr crtc = drmModeGetCrtc(nexell_data->drm_fd, output_data->crtc_id);
282                 if (!crtc) {
283                         TDM_ERR("getting crtc failed");
284                         return TDM_ERROR_OPERATION_FAILED;
285                 }
286                 crtc_w = crtc->width;
287                 if (crtc_w == 0) {
288                         TDM_ERR("getting crtc width failed");
289                         drmModeFreeCrtc(crtc);
290                         return TDM_ERROR_OPERATION_FAILED;
291                 }
292                 drmModeFreeCrtc(crtc);
293         }
294
295         // reset the changed flags
296         layer_data->display_buffer_changed = 0;
297         layer_data->info_changed = 0;
298
299         if (layer_data->display_buffer) { // set plane
300                 /* Source values are 16.16 fixed point */
301                 fx = ((unsigned int)layer_data->info.src_config.pos.x) << 16;
302                 fy = ((unsigned int)layer_data->info.src_config.pos.y) << 16;
303                 fw = ((unsigned int)layer_data->info.src_config.pos.w) << 16;
304                 fh = ((unsigned int)layer_data->info.src_config.pos.h) << 16;
305
306                 TDM_DBG("plane(%d) crtc(%d) pos(%d) on: fb(%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n",
307                                 layer_data->plane_id, output_data->crtc_id, layer_data->zpos,
308                                 layer_data->display_buffer->fb_id,
309                                 layer_data->info.src_config.pos.x, layer_data->info.src_config.pos.y,
310                                 layer_data->info.src_config.pos.w, layer_data->info.src_config.pos.h,
311                                 layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
312                                 layer_data->info.dst_pos.w, layer_data->info.dst_pos.h);
313
314                 if (drmModeSetPlane(nexell_data->drm_fd, layer_data->plane_id,
315                                     output_data->crtc_id, layer_data->display_buffer->fb_id, 0,
316                                     layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
317                                     layer_data->info.dst_pos.w, layer_data->info.dst_pos.h,
318                                     fx, fy, fw, fh) < 0) {
319                         TDM_ERR("set plane(%d) failed: %m", layer_data->plane_id);
320                         return TDM_ERROR_OPERATION_FAILED;
321                 }
322         } else { // unset plane
323                 TDM_DBG("plane(%d) crtc(%d) pos(%d) : unset plane\n",
324                         layer_data->plane_id, output_data->crtc_id, layer_data->zpos);
325
326                 if (drmModeSetPlane(nexell_data->drm_fd, layer_data->plane_id,
327                                     output_data->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
328                         TDM_ERR("unset plane(%d) filed: %m", layer_data->plane_id);
329         }
330
331         return TDM_ERROR_NONE;
332 }
333
334 static void
335 _tdm_nexell_display_cb_event(int fd, unsigned int sequence,
336                           unsigned int tv_sec, unsigned int tv_usec,
337                           void *user_data)
338 {
339         tdm_nexell_event_data *event_data = user_data;
340         tdm_nexell_output_data *output_data;
341         tdm_nexell_hwc_data *hwc_data;
342
343         if (!event_data) {
344                 TDM_ERR("no event data");
345                 return;
346         }
347
348         output_data = event_data->output_data;
349
350         switch (event_data->type) {
351         case TDM_NEXELL_EVENT_TYPE_PAGEFLIP:
352                 if (output_data->commit_func)
353                         output_data->commit_func(output_data, sequence, tv_sec, tv_usec,
354                                                  event_data->user_data);
355                 break;
356         case TDM_NEXELL_EVENT_TYPE_WAIT:
357                 if (output_data->vblank_func)
358                         output_data->vblank_func(output_data, sequence, tv_sec, tv_usec,
359                                                  event_data->user_data);
360                 break;
361         case TDM_NEXELL_EVENT_TYPE_COMMIT:
362                 if (output_data->hwc_enable) {
363                         hwc_data = output_data->hwc_data;
364                         if (!hwc_data) {
365                                 TDM_ERR("no hwc_data");
366                                 break;
367                         }
368
369                         TDM_DBG("crtc_enable(%d), mode_changed(%d)\n", output_data->crtc_enabled, output_data->mode_changed);
370
371                         if (hwc_data->commit_func)
372                                 hwc_data->commit_func(hwc_data, sequence, tv_sec, tv_usec,
373                                                                                  event_data->user_data);
374                 } else {
375                         if (output_data->commit_func)
376                                 output_data->commit_func(output_data, sequence, tv_sec, tv_usec,
377                                                                                  event_data->user_data);
378                 }
379                 break;
380         default:
381                 break;
382         }
383
384         free(event_data);
385 }
386
387 static tdm_error
388 _tdm_nexell_display_create_layer_list(tdm_nexell_data *nexell_data)
389 {
390         tdm_nexell_output_data *output_data = NULL;
391         int i;
392
393         if (LIST_IS_EMPTY(&nexell_data->output_list)) {
394                 TDM_ERR("no output");
395                 return TDM_ERROR_OPERATION_FAILED;
396         }
397
398         /* The TDM drm backend only support one output. */
399         LIST_FOR_EACH_ENTRY(output_data, &nexell_data->output_list, link) {
400                 break;
401         }
402
403         if (nexell_data->plane_res->count_planes == 0) {
404                 TDM_ERR("no layer error");
405                 return TDM_ERROR_OPERATION_FAILED;
406         }
407
408         for (i = 0; i < nexell_data->plane_res->count_planes; i++) {
409                 tdm_nexell_layer_data *layer_data;
410                 drmModePlanePtr plane;
411
412                 plane = drmModeGetPlane(nexell_data->drm_fd, nexell_data->plane_res->planes[i]);
413                 if (!plane) {
414                         TDM_ERR("no plane");
415                         continue;
416                 }
417
418                 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
419                         drmModeFreePlane(plane);
420                         continue;
421                 }
422
423                 layer_data = calloc(1, sizeof(tdm_nexell_layer_data));
424                 if (!layer_data) {
425                         TDM_ERR("alloc failed");
426                         drmModeFreePlane(plane);
427                         continue;
428                 }
429
430                 layer_data->nexell_data = nexell_data;
431                 layer_data->output_data = output_data;
432                 layer_data->plane_id = nexell_data->plane_res->planes[i];
433
434                 layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
435                                            TDM_LAYER_CAPABILITY_GRAPHIC;
436                 output_data->primary_layer = layer_data;
437
438                 TDM_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) capabilities(%x)",
439                          layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
440                          layer_data->capabilities);
441
442                 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
443
444                 drmModeFreePlane(plane);
445
446                 /* can't take care of other planes for various hardware devices */
447                 break;
448         }
449
450         return TDM_ERROR_NONE;
451 }
452
453 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4  && LIBDRM_MICRO_VERSION >= 47
454
455 static tdm_error
456 _tdm_nexell_display_get_property(tdm_nexell_data *nexell_data,
457                               unsigned int obj_id, unsigned int obj_type,
458                               const char *name, unsigned int *value,
459                               int *is_immutable)
460 {
461         drmModeObjectPropertiesPtr props = NULL;
462         int i;
463
464         props = drmModeObjectGetProperties(nexell_data->drm_fd, obj_id, obj_type);
465         if (!props)
466                 return TDM_ERROR_OPERATION_FAILED;
467
468         for (i = 0; i < props->count_props; i++) {
469                 drmModePropertyPtr prop = drmModeGetProperty(nexell_data->drm_fd,
470                                           props->props[i]);
471
472                 if (!prop)
473                         continue;
474
475                 if (!strcmp(prop->name, name)) {
476                         if (is_immutable)
477                                 *is_immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
478                         if (value)
479                                 *value = (unsigned int)props->prop_values[i];
480                         drmModeFreeProperty(prop);
481                         drmModeFreeObjectProperties(props);
482                         return TDM_ERROR_NONE;
483                 }
484
485                 drmModeFreeProperty(prop);
486         }
487         drmModeFreeObjectProperties(props);
488         TDM_DBG("coundn't find '%s' property", name);
489         return TDM_ERROR_OPERATION_FAILED;
490 }
491
492 static tdm_error
493 _tdm_nexell_display_create_layer_list_type(tdm_nexell_data *nexell_data)
494 {
495         tdm_nexell_output_data *output_data = NULL;
496         drmModePlanePtr *planes = NULL;
497         unsigned int *types = NULL;
498         unsigned int type = 0;
499         int plane_cnt, primary_cnt, ovl_cnt, cursor_cnt;
500         int opos_next, cpos_next;
501         tdm_error ret;
502         int i;
503
504         if (LIST_IS_EMPTY(&nexell_data->output_list)) {
505                 TDM_ERR("no output");
506                 return TDM_ERROR_OPERATION_FAILED;
507         }
508
509         /* The TDM drm backend only support one output. */
510         LIST_FOR_EACH_ENTRY(output_data, &nexell_data->output_list, link) {
511                 break;
512         }
513
514         ret = _tdm_nexell_display_get_property(nexell_data,
515                                             nexell_data->plane_res->planes[0],
516                                             DRM_MODE_OBJECT_PLANE, "type", &type,
517                                             NULL);
518         if (ret != TDM_ERROR_NONE) {
519                 TDM_ERR("plane doesn't have 'type' property. Call a fallback function");
520
521                 /* if a plane doesn't have "type" property, we call a fallback function
522                  * as default
523                  */
524                 return _tdm_nexell_display_create_layer_list(nexell_data);
525         }
526
527         planes = calloc(nexell_data->plane_res->count_planes, sizeof(drmModePlanePtr));
528         if (!planes) {
529                 TDM_ERR("alloc failed");
530                 goto failed;
531         }
532
533         types = calloc(nexell_data->plane_res->count_planes, sizeof(unsigned int));
534         if (!types) {
535                 TDM_ERR("alloc failed");
536                 goto failed;
537         }
538
539         plane_cnt = 0;
540         for (i = 0; i < nexell_data->plane_res->count_planes; i++) {
541                 drmModePlanePtr plane;
542
543                 plane = drmModeGetPlane(nexell_data->drm_fd, nexell_data->plane_res->planes[i]);
544                 if (!plane) {
545                         TDM_ERR("no plane(%d)", nexell_data->plane_res->planes[i]);
546                         goto failed;
547                 }
548
549                 if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
550                         drmModeFreePlane(plane);
551                         continue;
552                 }
553
554                 ret = _tdm_nexell_display_get_property(nexell_data,
555                                                     nexell_data->plane_res->planes[i],
556                                                     DRM_MODE_OBJECT_PLANE, "type", &type,
557                                                     NULL);
558                 if (ret != TDM_ERROR_NONE) {
559                         drmModeFreePlane(plane);
560                         TDM_ERR("plane(%d) doesn't have 'type' info",
561                                 nexell_data->plane_res->planes[i]);
562                         goto failed;
563                 }
564
565                 planes[plane_cnt] = plane;
566                 types[plane_cnt] = type;
567                 plane_cnt++;
568         }
569
570         primary_cnt = ovl_cnt = cursor_cnt = 0;
571         for (i = 0; i < plane_cnt; i++) {
572                 if (types[i] == DRM_PLANE_TYPE_CURSOR)
573                         cursor_cnt++;
574                 else if (types[i] == DRM_PLANE_TYPE_OVERLAY)
575                         ovl_cnt++;
576                 else if (types[i] == DRM_PLANE_TYPE_PRIMARY)
577                         primary_cnt++;
578                 else
579                         TDM_ERR("invalid type(%d)", types[i]);
580         }
581
582         if (primary_cnt != 1) {
583                 TDM_ERR("primary layer count(%d) should be one", primary_cnt);
584                 goto failed;
585         }
586
587         opos_next = 0;
588         cpos_next = ovl_cnt;
589         if (plane_cnt < 1) {
590                 TDM_ERR("plane count(%d) should be over 1", plane_cnt);
591                 goto failed;
592         }
593
594         for (i = plane_cnt - 1; i >= 0; i--) {
595                 tdm_nexell_layer_data *layer_data;
596
597                 layer_data = calloc(1, sizeof(tdm_nexell_layer_data));
598                 if (!layer_data) {
599                         TDM_ERR("alloc failed");
600                         goto failed;
601                 }
602
603                 layer_data->nexell_data = nexell_data;
604                 layer_data->output_data = output_data;
605                 layer_data->plane_id = planes[i]->plane_id;
606
607                 if (types[i] == DRM_PLANE_TYPE_CURSOR) {
608                         layer_data->capabilities = TDM_LAYER_CAPABILITY_CURSOR |
609                                                                            TDM_LAYER_CAPABILITY_GRAPHIC |
610                                                                            TDM_LAYER_CAPABILITY_SCANOUT;
611                         layer_data->zpos = cpos_next++;
612                         TDM_INFO("layer_data(%p): cursor zpos(%d)", layer_data, layer_data->zpos);
613                 } else if (types[i] == DRM_PLANE_TYPE_OVERLAY) {
614                         if (opos_next == 0) {
615                                 layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY |
616                                                                                    TDM_LAYER_CAPABILITY_SCALE |
617                                                                                    TDM_LAYER_CAPABILITY_SCANOUT;
618                         } else {
619                                 layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY |
620                                                                                    TDM_LAYER_CAPABILITY_GRAPHIC |
621                                                                                    TDM_LAYER_CAPABILITY_RESEVED_MEMORY |
622                                                                                    TDM_LAYER_CAPABILITY_SCANOUT;
623                         }
624                         if (opos_next == 1) {
625                                 layer_data->zpos = 2;
626                                 opos_next = 2;
627                         } else {
628                                 layer_data->zpos = opos_next++;
629                         }
630
631                         TDM_INFO("layer_data(%p): overlay zpos(%d)", layer_data, layer_data->zpos);
632                 } else if (types[i] == DRM_PLANE_TYPE_PRIMARY) {
633                         layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
634                                                                            TDM_LAYER_CAPABILITY_GRAPHIC |
635                                                                            TDM_LAYER_CAPABILITY_RESEVED_MEMORY |
636                                                                            TDM_LAYER_CAPABILITY_SCANOUT;
637                         layer_data->zpos = 1;
638                         output_data->primary_layer = layer_data;
639
640                         TDM_INFO("layer_data(%p): primary zpos(%d)", layer_data, layer_data->zpos);
641                 } else {
642                         free(layer_data);
643                         continue;
644                 }
645
646                 TDM_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) zpos(%d) capabilities(%x)",
647                                  layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
648                                  layer_data->zpos, layer_data->capabilities);
649
650                 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
651         }
652
653         for (i = 0; i < plane_cnt; i++)
654                 if (planes[i])
655                         drmModeFreePlane(planes[i]);
656
657         free(planes);
658         free(types);
659
660         return TDM_ERROR_NONE;
661
662 failed:
663         if (planes) {
664                 for (i = 0; i < nexell_data->plane_res->count_planes; i++)
665                         if (planes[i])
666                                 drmModeFreePlane(planes[i]);
667                 free(planes);
668         }
669
670         free(types);
671
672         return TDM_ERROR_OPERATION_FAILED;
673 }
674 #endif
675
676 tdm_error
677 tdm_nexell_display_create_layer_list(tdm_nexell_data *nexell_data)
678 {
679         tdm_nexell_output_data *output_data = NULL;
680         tdm_error ret;
681
682 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4  && LIBDRM_MICRO_VERSION >= 47
683         if (nexell_data->has_universal_plane)
684                 ret = _tdm_nexell_display_create_layer_list_type(nexell_data);
685         else
686 #endif
687                 ret = _tdm_nexell_display_create_layer_list(nexell_data);
688
689         if (ret != TDM_ERROR_NONE)
690                 return ret;
691
692         LIST_FOR_EACH_ENTRY(output_data, &nexell_data->output_list, link) {
693                 if (!output_data->primary_layer) {
694                         TDM_ERR("output(%d) no primary layer", output_data->pipe);
695                         return TDM_ERROR_OPERATION_FAILED;
696                 }
697         }
698
699         return TDM_ERROR_NONE;
700 }
701
702 void
703 tdm_nexell_display_destroy_output_list(tdm_nexell_data *nexell_data)
704 {
705         tdm_nexell_output_data *o = NULL, *oo = NULL;
706         tdm_nexell_hwc_data *hwc_data = NULL;
707
708         if (LIST_IS_EMPTY(&nexell_data->output_list))
709                 return;
710
711         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &nexell_data->output_list, link) {
712                 hwc_data = o->hwc_data;
713                 if (hwc_data && hwc_data->target_hwc_window)
714                         nexell_hwc_window_destroy(hwc_data->target_hwc_window);
715
716                 if (o->crtc_enabled) {
717                         _tdm_nexell_display_set_crtc(nexell_data, o, 0);
718                         o->crtc_enabled = 0;
719                 }
720
721                 LIST_DEL(&o->link);
722                 if (!LIST_IS_EMPTY(&o->layer_list)) {
723                         tdm_nexell_layer_data *l = NULL, *ll = NULL;
724                         LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
725                                 LIST_DEL(&l->link);
726                                 if (l->display_buffer)
727                                         tbm_surface_internal_unref(l->display_buffer->buffer);
728                                 free(l);
729                         }
730                 }
731                 free(o->drm_modes);
732                 free(o->output_modes);
733                 free(o);
734         }
735 }
736
737 void
738 tdm_nexell_display_update_output_status(tdm_nexell_data *nexell_data)
739 {
740         tdm_nexell_output_data *output_data = NULL;
741
742         if (LIST_IS_EMPTY(&nexell_data->output_list))
743                 return;
744
745         LIST_FOR_EACH_ENTRY(output_data, &nexell_data->output_list, link) {
746                 drmModeConnectorPtr connector;
747                 tdm_output_conn_status new_status;
748
749                 connector = drmModeGetConnector(nexell_data->drm_fd,
750                                                 output_data->connector_id);
751                 if (!connector) {
752                         TDM_ERR("no connector: %d", output_data->connector_id);
753                         continue;
754                 }
755
756                 if (connector->connection == DRM_MODE_CONNECTED)
757                         new_status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
758                 else
759                         new_status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
760
761                 _tdm_nexell_output_update_status(output_data, new_status);
762
763                 drmModeFreeConnector(connector);
764         }
765 }
766
767 tdm_error
768 tdm_nexell_display_create_output_list(tdm_nexell_data *nexell_data)
769 {
770         tdm_nexell_output_data *output_data;
771         int i;
772         tdm_error ret;
773         int allocated = 0;
774         drmModeConnectorPtr connector;
775         drmModeEncoderPtr encoder;
776         int conn_idx = -1;
777         int hdmia_idx = -1, hdmib_idx = -1;
778         int crtc_id = 0, c, j;
779
780         RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&nexell_data->output_list),
781                            TDM_ERROR_OPERATION_FAILED);
782
783         /* check if there is a connected output */
784         for (i = 0; i < nexell_data->mode_res->count_connectors; i++) {
785                 connector = drmModeGetConnector(nexell_data->drm_fd,
786                                                 nexell_data->mode_res->connectors[i]);
787                 if (!connector) {
788                         TDM_ERR("no connector");
789                         return TDM_ERROR_OPERATION_FAILED;
790                 }
791
792                 /* The TDM drm backend considers only 1 connector because it is the TDM
793                  * reference backend and can't take care of all hardware devices.
794                  * To support various connectors, planes and crtcs, the new TDM backend
795                  * should be implemented.
796                  */
797                 if (connector->connection == DRM_MODE_CONNECTED) {
798                         conn_idx = i;
799                         drmModeFreeConnector(connector);
800                         break;
801                 }
802
803                 if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)
804                         hdmia_idx = i;
805                 if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIB)
806                         hdmib_idx = i;
807
808                 drmModeFreeConnector(connector);
809         }
810
811         /* use the hdmi connector if there is no connected connector. */
812         /* if there is no hdmi connector, use first connector. */
813         if (conn_idx == -1) {
814                 if (hdmia_idx != -1)
815                         conn_idx = hdmia_idx;
816                 else if (hdmib_idx != -1)
817                         conn_idx = hdmib_idx;
818                 else
819                         conn_idx = 0;
820         }
821
822         /* The TDM drm backend considers only 1 connector because it is the TDM
823          * reference backend and can't take care of all hardware devices.
824          * To support various connectors, planes and crtcs, the new TDM backend
825          * should be implemented.
826          */
827         connector = drmModeGetConnector(nexell_data->drm_fd,
828                                         nexell_data->mode_res->connectors[conn_idx]);
829         if (!connector) {
830                 TDM_ERR("no connector");
831                 ret = TDM_ERROR_OPERATION_FAILED;
832                 goto failed_create;
833         }
834
835         if (connector->count_encoders != 1) {
836                 TDM_ERR("too many encoders: %d", connector->count_encoders);
837                 drmModeFreeConnector(connector);
838                 ret = TDM_ERROR_OPERATION_FAILED;
839                 goto failed_create;
840         }
841
842         encoder = drmModeGetEncoder(nexell_data->drm_fd, connector->encoders[0]);
843         if (!encoder) {
844                 TDM_ERR("no encoder");
845                 drmModeFreeConnector(connector);
846                 ret = TDM_ERROR_OPERATION_FAILED;
847                 goto failed_create;
848         }
849
850         for (c = 0; c < nexell_data->mode_res->count_crtcs; c++) {
851                 if ((encoder->possible_crtcs & (1 << c)) == 0)
852                         continue;
853
854                 crtc_id = nexell_data->mode_res->crtcs[c];
855                 allocated |= (1 << c);
856                 break;
857         }
858
859         if (crtc_id == 0) {
860                 TDM_ERR("no possible crtc");
861                 drmModeFreeConnector(connector);
862                 drmModeFreeEncoder(encoder);
863                 ret = TDM_ERROR_OPERATION_FAILED;
864                 goto failed_create;
865         }
866
867         output_data = calloc(1, sizeof(tdm_nexell_output_data));
868         if (!output_data) {
869                 TDM_ERR("alloc failed");
870                 drmModeFreeConnector(connector);
871                 drmModeFreeEncoder(encoder);
872                 ret = TDM_ERROR_OUT_OF_MEMORY;
873                 goto failed_create;
874         }
875
876         LIST_INITHEAD(&output_data->layer_list);
877
878         output_data->nexell_data = nexell_data;
879         output_data->connector_id = nexell_data->mode_res->connectors[conn_idx];
880         output_data->encoder_id = encoder->encoder_id;
881         output_data->crtc_id = crtc_id;
882         output_data->pipe = c;
883         output_data->connector_type = connector->connector_type;
884         output_data->connector_type_id = connector->connector_type_id;
885
886         if (connector->connection == DRM_MODE_CONNECTED)
887                 output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
888         else
889                 output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
890
891         for (j = 0; j < connector->count_props; j++) {
892                 drmModePropertyPtr prop = drmModeGetProperty(nexell_data->drm_fd,
893                                           connector->props[j]);
894                 if (!prop)
895                         continue;
896                 if (!strcmp(prop->name, "DPMS")) {
897                         output_data->dpms_prop_id = connector->props[j];
898                         drmModeFreeProperty(prop);
899                         break;
900                 }
901                 drmModeFreeProperty(prop);
902         }
903
904         if (output_data->dpms_prop_id == 0)
905                 TDM_WRN("not support DPMS");
906
907         output_data->count_modes = connector->count_modes;
908         output_data->drm_modes = calloc(connector->count_modes,
909                                         sizeof(drmModeModeInfo));
910         if (!output_data->drm_modes) {
911                 TDM_ERR("alloc failed");
912                 free(output_data);
913                 drmModeFreeConnector(connector);
914                 drmModeFreeEncoder(encoder);
915                 ret = TDM_ERROR_OUT_OF_MEMORY;
916                 goto failed_create;
917         }
918         output_data->output_modes = calloc(connector->count_modes,
919                                            sizeof(tdm_output_mode));
920         if (!output_data->output_modes) {
921                 TDM_ERR("alloc failed");
922                 free(output_data->drm_modes);
923                 free(output_data);
924                 drmModeFreeConnector(connector);
925                 drmModeFreeEncoder(encoder);
926                 ret = TDM_ERROR_OUT_OF_MEMORY;
927                 goto failed_create;
928         }
929         for (j = 0; j < connector->count_modes; j++) {
930                 output_data->drm_modes[j] = connector->modes[j];
931                 _tdm_nexell_display_to_tdm_mode(&output_data->drm_modes[j],
932                                              &output_data->output_modes[j]);
933         }
934
935         if (nexell_data->hwc_mode)
936                 output_data->hwc_enable = 1;
937
938         LIST_ADDTAIL(&output_data->link, &nexell_data->output_list);
939
940         TDM_DBG("output_data(%p) connector_id(%d:%d:%d-%d) encoder_id(%d) crtc_id(%d) pipe(%d) dpms_id(%d)",
941                 output_data, output_data->connector_id, output_data->status,
942                 output_data->connector_type,
943                 output_data->connector_type_id, output_data->encoder_id, output_data->crtc_id,
944                 output_data->pipe, output_data->dpms_prop_id);
945
946         drmModeFreeEncoder(encoder);
947         drmModeFreeConnector(connector);
948
949         TDM_DBG("output count: %d", nexell_data->mode_res->count_connectors);
950
951         return TDM_ERROR_NONE;
952 failed_create:
953         tdm_nexell_display_destroy_output_list(nexell_data);
954         return ret;
955 }
956
957 tdm_error
958 nexell_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps)
959 {
960         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
961
962         caps->max_layer_count = -1; /* not defined */
963
964         return TDM_ERROR_NONE;
965 }
966
967 tdm_error
968 nexell_display_get_pp_capability(tdm_backend_data *bdata, tdm_caps_pp *caps)
969 {
970         return tdm_nexell_pp_get_capability(bdata, caps);
971 }
972
973 tdm_output **
974 nexell_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error)
975 {
976         tdm_nexell_data *nexell_data = bdata;
977         tdm_nexell_output_data *output_data = NULL;
978         tdm_output **outputs;
979         tdm_error ret;
980         int i;
981
982         RETURN_VAL_IF_FAIL(nexell_data, NULL);
983         RETURN_VAL_IF_FAIL(count, NULL);
984
985         *count = 0;
986         LIST_FOR_EACH_ENTRY(output_data, &nexell_data->output_list, link)
987         (*count)++;
988
989         if (*count == 0) {
990                 ret = TDM_ERROR_NONE;
991                 goto failed_get;
992         }
993
994         /* will be freed in frontend */
995         outputs = calloc(*count, sizeof(tdm_nexell_output_data *));
996         if (!outputs) {
997                 TDM_ERR("failed: alloc memory");
998                 *count = 0;
999                 ret = TDM_ERROR_OUT_OF_MEMORY;
1000                 goto failed_get;
1001         }
1002
1003         i = 0;
1004         LIST_FOR_EACH_ENTRY(output_data, &nexell_data->output_list, link)
1005         outputs[i++] = output_data;
1006
1007         if (error)
1008                 *error = TDM_ERROR_NONE;
1009
1010         return outputs;
1011 failed_get:
1012         if (error)
1013                 *error = ret;
1014         return NULL;
1015 }
1016
1017 tdm_error
1018 nexell_display_get_fd(tdm_backend_data *bdata, int *fd)
1019 {
1020         tdm_nexell_data *nexell_data = bdata;
1021
1022         RETURN_VAL_IF_FAIL(nexell_data, TDM_ERROR_INVALID_PARAMETER);
1023         RETURN_VAL_IF_FAIL(fd, TDM_ERROR_INVALID_PARAMETER);
1024
1025         *fd = nexell_data->drm_fd;
1026
1027         return TDM_ERROR_NONE;
1028 }
1029
1030 tdm_error
1031 nexell_display_handle_events(tdm_backend_data *bdata)
1032 {
1033         tdm_nexell_data *nexell_data = bdata;
1034         drmEventContext ctx;
1035
1036         RETURN_VAL_IF_FAIL(nexell_data, TDM_ERROR_INVALID_PARAMETER);
1037
1038         memset(&ctx, 0, sizeof(drmEventContext));
1039
1040         ctx.version = DRM_EVENT_CONTEXT_VERSION;
1041         ctx.page_flip_handler = _tdm_nexell_display_cb_event;
1042         ctx.vblank_handler = _tdm_nexell_display_cb_event;
1043
1044         drmHandleEvent(nexell_data->drm_fd, &ctx);
1045
1046         return TDM_ERROR_NONE;
1047 }
1048
1049 tdm_pp *
1050 nexell_display_create_pp(tdm_backend_data *bdata, tdm_error *error)
1051 {
1052         tdm_nexell_data *nexell_data = bdata;
1053
1054         RETURN_VAL_IF_FAIL(nexell_data, NULL);
1055
1056         return tdm_nexell_pp_create(nexell_data, error);
1057 }
1058
1059 tdm_error
1060 nexell_output_get_capability(tdm_output *output, tdm_caps_output *caps)
1061 {
1062         tdm_nexell_output_data *output_data = output;
1063         tdm_nexell_data *nexell_data;
1064         drmModeConnectorPtr connector = NULL;
1065         drmModeCrtcPtr crtc = NULL;
1066         drmModeObjectPropertiesPtr props = NULL;
1067         int i;
1068         tdm_error ret;
1069
1070         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1071         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1072
1073         memset(caps, 0, sizeof(tdm_caps_output));
1074
1075         nexell_data = output_data->nexell_data;
1076
1077         snprintf(caps->maker, TDM_NAME_LEN, "unknown");
1078         snprintf(caps->model, TDM_NAME_LEN, "unknown");
1079         snprintf(caps->name, TDM_NAME_LEN, "unknown");
1080
1081         caps->status = output_data->status;
1082         caps->type = output_data->connector_type;
1083         caps->type_id = output_data->connector_type_id;
1084
1085         connector = drmModeGetConnector(nexell_data->drm_fd, output_data->connector_id);
1086         RETURN_VAL_IF_FAIL(connector, TDM_ERROR_OPERATION_FAILED);
1087
1088         caps->mode_count = connector->count_modes;
1089         caps->modes = calloc(1, sizeof(tdm_output_mode) * caps->mode_count);
1090         if (!caps->modes) {
1091                 ret = TDM_ERROR_OUT_OF_MEMORY;
1092                 TDM_ERR("alloc failed\n");
1093                 goto failed_get;
1094         }
1095
1096         if (caps->mode_count != output_data->count_modes) {
1097                 drmModeModeInfoPtr new_drm_modes;
1098                 tdm_output_mode *new_output_modes;
1099
1100                 new_drm_modes = calloc(connector->count_modes,
1101                                                 sizeof(drmModeModeInfo));
1102                 if (!new_drm_modes) {
1103                         ret = TDM_ERROR_OUT_OF_MEMORY;
1104                         TDM_ERR("alloc failed drm_modes\n");
1105                         goto failed_get;
1106                 }
1107                 new_output_modes = calloc(connector->count_modes,
1108                                                 sizeof(tdm_output_mode));
1109                 if (!new_output_modes) {
1110                         ret = TDM_ERROR_OUT_OF_MEMORY;
1111                         TDM_ERR("alloc failed output_modes\n");
1112                         free(new_drm_modes);
1113                         goto failed_get;
1114                 }
1115                 free(output_data->drm_modes);
1116                 free(output_data->output_modes);
1117
1118                 output_data->drm_modes = new_drm_modes;
1119                 output_data->output_modes = new_output_modes;
1120                 output_data->count_modes = caps->mode_count;
1121         }
1122
1123         for (i = 0; i < caps->mode_count; i++) {
1124                 output_data->drm_modes[i] = connector->modes[i];
1125                 _tdm_nexell_display_to_tdm_mode(&output_data->drm_modes[i],
1126                                                                                 &output_data->output_modes[i]);
1127                 caps->modes[i] = output_data->output_modes[i];
1128         }
1129
1130         caps->mmWidth = connector->mmWidth;
1131         caps->mmHeight = connector->mmHeight;
1132         caps->subpixel = connector->subpixel;
1133
1134         caps->min_w = nexell_data->mode_res->min_width;
1135         caps->min_h = nexell_data->mode_res->min_height;
1136         caps->max_w = nexell_data->mode_res->max_width;
1137         caps->max_h = nexell_data->mode_res->max_height;
1138         caps->preferred_align = -1;
1139
1140         crtc = drmModeGetCrtc(nexell_data->drm_fd, output_data->crtc_id);
1141         if (!crtc) {
1142                 ret = TDM_ERROR_OPERATION_FAILED;
1143                 TDM_ERR("get crtc failed: %m\n");
1144                 goto failed_get;
1145         }
1146
1147         props = drmModeObjectGetProperties(nexell_data->drm_fd, output_data->crtc_id,
1148                                            DRM_MODE_OBJECT_CRTC);
1149         if (!props) {
1150                 ret = TDM_ERROR_OPERATION_FAILED;
1151                 TDM_ERR("get crtc properties failed: %m\n");
1152                 goto failed_get;
1153         }
1154
1155         caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
1156         if (!caps->props) {
1157                 ret = TDM_ERROR_OUT_OF_MEMORY;
1158                 TDM_ERR("alloc failed\n");
1159                 goto failed_get;
1160         }
1161
1162         caps->prop_count = 0;
1163         for (i = 0; i < props->count_props; i++) {
1164                 drmModePropertyPtr prop = drmModeGetProperty(nexell_data->drm_fd, props->props[i]);
1165                 if (!prop)
1166                         continue;
1167                 snprintf(caps->props[caps->prop_count].name, TDM_NAME_LEN, "%s", prop->name);
1168                 caps->props[caps->prop_count].id = props->props[i];
1169                 caps->prop_count++;
1170                 drmModeFreeProperty(prop);
1171         }
1172
1173         if (output_data->hwc_enable) {
1174                 caps->capabilities |= TDM_OUTPUT_CAPABILITY_HWC;
1175         }
1176
1177         drmModeFreeObjectProperties(props);
1178         drmModeFreeCrtc(crtc);
1179         drmModeFreeConnector(connector);
1180
1181         return TDM_ERROR_NONE;
1182 failed_get:
1183         drmModeFreeCrtc(crtc);
1184         drmModeFreeObjectProperties(props);
1185         drmModeFreeConnector(connector);
1186         free(caps->modes);
1187         free(caps->props);
1188         memset(caps, 0, sizeof(tdm_caps_output));
1189         return ret;
1190 }
1191
1192 tdm_layer **
1193 nexell_output_get_layers(tdm_output *output,  int *count, tdm_error *error)
1194 {
1195         tdm_nexell_output_data *output_data = output;
1196         tdm_nexell_layer_data *layer_data = NULL;
1197         tdm_layer **layers;
1198         tdm_error ret;
1199         int i;
1200
1201         RETURN_VAL_IF_FAIL(output_data, NULL);
1202         RETURN_VAL_IF_FAIL(count, NULL);
1203
1204         *count = 0;
1205         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1206         (*count)++;
1207
1208         if (output_data->hwc_enable) {
1209                 *count = 0;
1210                 ret = TDM_ERROR_NONE;
1211                 goto failed_get;
1212         }
1213
1214         if (*count == 0) {
1215                 ret = TDM_ERROR_NONE;
1216                 goto failed_get;
1217         }
1218
1219         /* will be freed in frontend */
1220         layers = calloc(*count, sizeof(tdm_nexell_layer_data *));
1221         if (!layers) {
1222                 TDM_ERR("failed: alloc memory");
1223                 *count = 0;
1224                 ret = TDM_ERROR_OUT_OF_MEMORY;
1225                 goto failed_get;
1226         }
1227
1228         i = 0;
1229         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
1230         layers[i++] = layer_data;
1231
1232         if (error)
1233                 *error = TDM_ERROR_NONE;
1234
1235         return layers;
1236 failed_get:
1237         if (error)
1238                 *error = ret;
1239         return NULL;
1240 }
1241
1242 tdm_error
1243 nexell_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
1244 {
1245         tdm_nexell_output_data *output_data = output;
1246         tdm_nexell_data *nexell_data;
1247         int ret;
1248
1249         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1250         RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1251
1252         nexell_data = output_data->nexell_data;
1253         ret = drmModeObjectSetProperty(nexell_data->drm_fd,
1254                                        output_data->crtc_id, DRM_MODE_OBJECT_CRTC,
1255                                        id, value.u32);
1256         if (ret < 0) {
1257                 TDM_ERR("set property failed: %m");
1258                 return TDM_ERROR_OPERATION_FAILED;
1259         }
1260
1261         return TDM_ERROR_NONE;
1262 }
1263
1264 tdm_error
1265 nexell_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
1266 {
1267         tdm_nexell_output_data *output_data = output;
1268         tdm_nexell_data *nexell_data;
1269         drmModeObjectPropertiesPtr props;
1270         int i;
1271
1272         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1273         RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
1274         RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
1275
1276         nexell_data = output_data->nexell_data;
1277         props = drmModeObjectGetProperties(nexell_data->drm_fd, output_data->crtc_id,
1278                                            DRM_MODE_OBJECT_CRTC);
1279         if (props == NULL) {
1280                 TDM_ERR("get property failed: %m");
1281                 return TDM_ERROR_OPERATION_FAILED;
1282         }
1283
1284         for (i = 0; i < props->count_props; i++)
1285                 if (props->props[i] == id) {
1286                         (*value).u32 = (uint)props->prop_values[i];
1287                         break;
1288                 }
1289
1290         drmModeFreeObjectProperties(props);
1291
1292         return TDM_ERROR_NONE;
1293 }
1294
1295 tdm_error
1296 nexell_output_wait_vblank(tdm_output *output, int interval, int sync,
1297                        void *user_data)
1298 {
1299         tdm_nexell_output_data *output_data = output;
1300         tdm_nexell_data *nexell_data;
1301         tdm_nexell_event_data *event_data;
1302         uint target_msc;
1303         tdm_error ret;
1304
1305         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1306
1307         event_data = calloc(1, sizeof(tdm_nexell_event_data));
1308         if (!event_data) {
1309                 TDM_ERR("alloc failed");
1310                 return TDM_ERROR_OUT_OF_MEMORY;
1311         }
1312
1313         nexell_data = output_data->nexell_data;
1314
1315         ret = _tdm_nexell_display_get_cur_msc(nexell_data->drm_fd, output_data->pipe,
1316                                            &target_msc);
1317         if (ret != TDM_ERROR_NONE)
1318                 goto failed_vblank;
1319
1320         target_msc += interval;
1321
1322         event_data->type = TDM_NEXELL_EVENT_TYPE_WAIT;
1323         event_data->output_data = output_data;
1324         event_data->user_data = user_data;
1325
1326         ret = _tdm_nexell_display_wait_vblank(nexell_data->drm_fd, output_data->pipe,
1327                                            &target_msc, event_data);
1328         if (ret != TDM_ERROR_NONE)
1329                 goto failed_vblank;
1330
1331         return TDM_ERROR_NONE;
1332 failed_vblank:
1333         free(event_data);
1334         return ret;
1335 }
1336
1337 tdm_error
1338 nexell_output_set_vblank_handler(tdm_output *output,
1339                               tdm_output_vblank_handler func)
1340 {
1341         tdm_nexell_output_data *output_data = output;
1342
1343         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1344         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1345
1346         output_data->vblank_func = func;
1347
1348         return TDM_ERROR_NONE;
1349 }
1350
1351 tdm_error
1352 nexell_output_commit(tdm_output *output, int sync, void *user_data)
1353 {
1354         tdm_nexell_output_data *output_data = output;
1355         tdm_nexell_data *nexell_data;
1356         tdm_nexell_layer_data *layer_data = NULL;
1357         tdm_error ret;
1358         int do_waitvblank = 1;
1359
1360         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1361
1362         nexell_data = output_data->nexell_data;
1363
1364 #if 0
1365         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1366                 if (layer_data == output_data->primary_layer) {
1367                         ret = _tdm_nexell_display_commit_primary_layer(layer_data, user_data,
1368                                         &do_waitvblank);
1369                         if (ret != TDM_ERROR_NONE)
1370                                 return ret;
1371                 } else {
1372                         ret = _tdm_nexell_display_commit_layer(layer_data);
1373                         if (ret != TDM_ERROR_NONE)
1374                                 return ret;
1375                 }
1376         }
1377 #else
1378         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1379                 ret = _tdm_nexell_display_commit_layer(layer_data);
1380                 if (ret != TDM_ERROR_NONE)
1381                         return ret;
1382         }
1383 #endif
1384
1385         if (do_waitvblank == 1) {
1386                 tdm_nexell_event_data *event_data = calloc(1, sizeof(tdm_nexell_event_data));
1387                 uint target_msc;
1388
1389                 if (!event_data) {
1390                         TDM_ERR("alloc failed");
1391                         return TDM_ERROR_OUT_OF_MEMORY;
1392                 }
1393
1394                 ret = _tdm_nexell_display_get_cur_msc(nexell_data->drm_fd, output_data->pipe,
1395                                                    &target_msc);
1396                 if (ret != TDM_ERROR_NONE) {
1397                         free(event_data);
1398                         return ret;
1399                 }
1400
1401                 target_msc++;
1402
1403                 event_data->type = TDM_NEXELL_EVENT_TYPE_COMMIT;
1404                 event_data->output_data = output_data;
1405                 event_data->user_data = user_data;
1406
1407                 ret = _tdm_nexell_display_wait_vblank(nexell_data->drm_fd, output_data->pipe,
1408                                                    &target_msc, event_data);
1409                 if (ret != TDM_ERROR_NONE) {
1410                         free(event_data);
1411                         return ret;
1412                 }
1413         }
1414
1415         return TDM_ERROR_NONE;
1416 }
1417
1418 tdm_error
1419 nexell_output_set_commit_handler(tdm_output *output,
1420                               tdm_output_commit_handler func)
1421 {
1422         tdm_nexell_output_data *output_data = output;
1423
1424         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1425         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1426
1427         output_data->commit_func = func;
1428
1429         return TDM_ERROR_NONE;
1430 }
1431
1432 tdm_error
1433 nexell_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
1434 {
1435         tdm_nexell_output_data *output_data = output;
1436         tdm_nexell_data *nexell_data;
1437         int ret;
1438
1439         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1440
1441         if (output_data->dpms_prop_id == 0) {
1442                 TDM_WRN("not support DPMS");
1443                 return TDM_ERROR_OPERATION_FAILED;
1444         }
1445
1446         nexell_data = output_data->nexell_data;
1447         ret = drmModeObjectSetProperty(nexell_data->drm_fd,
1448                                        output_data->connector_id, DRM_MODE_OBJECT_CONNECTOR,
1449                                        output_data->dpms_prop_id, dpms_value);
1450         if (ret < 0) {
1451                 TDM_ERR("set dpms failed: %m");
1452                 return TDM_ERROR_OPERATION_FAILED;
1453         }
1454
1455         return TDM_ERROR_NONE;
1456 }
1457
1458 tdm_error
1459 nexell_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
1460 {
1461         tdm_nexell_output_data *output_data = output;
1462         tdm_nexell_data *nexell_data;
1463         drmModeObjectPropertiesPtr props;
1464         int i;
1465
1466         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1467         RETURN_VAL_IF_FAIL(dpms_value, TDM_ERROR_INVALID_PARAMETER);
1468
1469         nexell_data = output_data->nexell_data;
1470         props = drmModeObjectGetProperties(nexell_data->drm_fd, output_data->connector_id,
1471                                            DRM_MODE_OBJECT_CONNECTOR);
1472         if (props == NULL) {
1473                 TDM_ERR("get property failed: %m");
1474                 return TDM_ERROR_OPERATION_FAILED;
1475         }
1476
1477         for (i = 0; i < props->count_props; i++)
1478                 if (props->props[i] == output_data->dpms_prop_id) {
1479                         *dpms_value = (uint)props->prop_values[i];
1480                         break;
1481                 }
1482
1483         drmModeFreeObjectProperties(props);
1484
1485         return TDM_ERROR_NONE;
1486 }
1487
1488 tdm_error
1489 nexell_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
1490 {
1491         tdm_nexell_output_data *output_data = output;
1492         tdm_error ret = TDM_ERROR_NONE;
1493
1494         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1495         RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1496
1497         /* create or replace the target_window when the output mode is set */
1498         if (output_data->hwc_enable) {
1499                 ret = nexell_hwc_target_window_set_info(output_data->hwc_data, mode->hdisplay, mode->vdisplay);
1500                 if (ret != TDM_ERROR_NONE) {
1501                         TDM_ERR("set info target hwc window failed (%d)", ret);
1502                         return ret;
1503                 }
1504         }
1505
1506         output_data->current_mode = mode;
1507         output_data->mode_changed = 1;
1508
1509         TDM_INFO("Set the output mode: %s, %d, %d, %d, %d, %d",
1510                          mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags, mode->type);
1511
1512         return TDM_ERROR_NONE;
1513 }
1514
1515 tdm_error
1516 nexell_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
1517 {
1518         tdm_nexell_output_data *output_data = output;
1519
1520         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1521         RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
1522
1523         *mode = output_data->current_mode;
1524
1525         return TDM_ERROR_NONE;
1526 }
1527
1528 tdm_hwc *
1529 nexell_output_get_hwc(tdm_output *output, tdm_error *error)
1530 {
1531         tdm_nexell_hwc_data *hwc_data = NULL;
1532         tdm_nexell_output_data *output_data = output;
1533         tdm_error ret = TDM_ERROR_NONE;
1534
1535         if (!output_data) {
1536                 TDM_ERR("invalid params");
1537                 if (error)
1538                         *error = TDM_ERROR_INVALID_PARAMETER;
1539                 return NULL;
1540         }
1541
1542         if (output_data->hwc_data) {
1543                 TDM_INFO("hwc_data already exists");
1544                 if (error)
1545                         *error = TDM_ERROR_NONE;
1546                 return output_data->hwc_data;
1547         }
1548
1549         hwc_data = calloc(1, sizeof(tdm_nexell_hwc_data));
1550         if (!hwc_data) {
1551                 TDM_ERR("alloc failed");
1552                 if (error)
1553                         *error = TDM_ERROR_OUT_OF_MEMORY;
1554                 return NULL;
1555         }
1556         for (int i = 0; i < NUM_LAYERS; i++) {
1557                 hwc_data->ui_buffer_queue[i].tqueue = NULL;
1558                 hwc_data->ui_buffer_queue[i].ref_cnt= 0;
1559         }
1560         hwc_data->output_data = output_data;
1561
1562         LIST_INITHEAD(&hwc_data->hwc_window_list);
1563
1564         output_data->hwc_data = hwc_data;
1565
1566         ret = nexell_hwc_initailize_target_window(output_data->hwc_data);
1567         if (ret != TDM_ERROR_NONE) {
1568                 TDM_ERR("create target hwc window failed (%d)", ret);
1569                 free(hwc_data);
1570                 if (error)
1571                         *error = ret;
1572                 return NULL;
1573         }
1574
1575         if (error)
1576                 *error = TDM_ERROR_NONE;
1577
1578         return hwc_data;
1579 }
1580
1581 tdm_error
1582 nexell_output_set_status_handler(tdm_output *output,
1583                               tdm_output_status_handler func,
1584                               void *user_data)
1585 {
1586         tdm_nexell_output_data *output_data = output;
1587
1588         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
1589         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
1590
1591         output_data->status_func = func;
1592         output_data->status_user_data = user_data;
1593
1594         return TDM_ERROR_NONE;
1595 }
1596
1597 tdm_error
1598 nexell_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
1599 {
1600         tdm_nexell_layer_data *layer_data = layer;
1601         tdm_nexell_data *nexell_data;
1602         drmModePlanePtr plane = NULL;
1603         drmModeObjectPropertiesPtr props = NULL;
1604         int i, format_count = 0;
1605         tdm_error ret;
1606
1607         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1608         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
1609
1610         memset(caps, 0, sizeof(tdm_caps_layer));
1611
1612         nexell_data = layer_data->nexell_data;
1613         plane = drmModeGetPlane(nexell_data->drm_fd, layer_data->plane_id);
1614         if (!plane) {
1615                 TDM_ERR("get plane failed: %m");
1616                 ret = TDM_ERROR_OPERATION_FAILED;
1617                 goto failed_get;
1618         }
1619
1620         caps->capabilities = layer_data->capabilities;
1621         caps->zpos = layer_data->zpos;  /* if VIDEO layer, zpos is -1 */
1622
1623         caps->format_count = plane->count_formats;
1624         caps->formats = calloc(1, sizeof(tbm_format) * caps->format_count);
1625         if (!caps->formats) {
1626                 ret = TDM_ERROR_OUT_OF_MEMORY;
1627                 TDM_ERR("alloc failed\n");
1628                 goto failed_get;
1629         }
1630
1631         for (i = 0; i < caps->format_count; i++) {
1632                 /* TODO: kernel reports wrong formats */
1633                 if (plane->formats[i] != DRM_FORMAT_XRGB8888 &&
1634                     plane->formats[i] != DRM_FORMAT_ARGB8888 &&
1635                     plane->formats[i] != DRM_FORMAT_YUV420) {
1636                         TDM_WRN("plane(%d) zpos(%d) %c%c%c%c skipped",
1637                                         layer_data->plane_id, layer_data->zpos, FOURCC_STR(plane->formats[i]));
1638                         continue;
1639                 }
1640                 caps->formats[format_count] = tdm_nexell_format_to_tbm_format(plane->formats[i]);
1641                 format_count++;
1642         }
1643
1644         caps->format_count = format_count;
1645
1646         props = drmModeObjectGetProperties(nexell_data->drm_fd, layer_data->plane_id,
1647                                            DRM_MODE_OBJECT_PLANE);
1648         if (!props) {
1649                 ret = TDM_ERROR_OPERATION_FAILED;
1650                 TDM_ERR("get plane properties failed: %m\n");
1651                 goto failed_get;
1652         }
1653
1654         caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
1655         if (!caps->props) {
1656                 ret = TDM_ERROR_OUT_OF_MEMORY;
1657                 TDM_ERR("alloc failed\n");
1658                 goto failed_get;
1659         }
1660
1661         caps->prop_count = 0;
1662         for (i = 0; i < props->count_props; i++) {
1663                 drmModePropertyPtr prop = drmModeGetProperty(nexell_data->drm_fd, props->props[i]);
1664                 if (!prop)
1665                         continue;
1666                 if (!strncmp(prop->name, "type", TDM_NAME_LEN)) {
1667                         drmModeFreeProperty(prop);
1668                         continue;
1669                 }
1670                 if (!strncmp(prop->name, "zpos", TDM_NAME_LEN)) {
1671                         drmModeFreeProperty(prop);
1672                         continue;
1673                 }
1674                 snprintf(caps->props[caps->prop_count].name, TDM_NAME_LEN, "%s", prop->name);
1675                 caps->props[caps->prop_count].id = props->props[i];
1676                 caps->prop_count++;
1677                 drmModeFreeProperty(prop);
1678         }
1679
1680         drmModeFreeObjectProperties(props);
1681         drmModeFreePlane(plane);
1682
1683         return TDM_ERROR_NONE;
1684 failed_get:
1685         drmModeFreeObjectProperties(props);
1686         drmModeFreePlane(plane);
1687         free(caps->formats);
1688         free(caps->props);
1689         memset(caps, 0, sizeof(tdm_caps_layer));
1690         return ret;
1691 }
1692
1693 tdm_error
1694 nexell_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value)
1695 {
1696         tdm_nexell_layer_data *layer_data = layer;
1697         tdm_nexell_data *nexell_data;
1698         int ret;
1699
1700         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1701         RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
1702
1703         nexell_data = layer_data->nexell_data;
1704         ret = drmModeObjectSetProperty(nexell_data->drm_fd,
1705                                        layer_data->plane_id, DRM_MODE_OBJECT_PLANE,
1706                                        id, value.u32);
1707         if (ret < 0) {
1708                 TDM_ERR("set property failed: %m");
1709                 return TDM_ERROR_OPERATION_FAILED;
1710         }
1711
1712         return TDM_ERROR_NONE;
1713 }
1714
1715 tdm_error
1716 nexell_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value)
1717 {
1718         tdm_nexell_layer_data *layer_data = layer;
1719         tdm_nexell_data *nexell_data;
1720         drmModeObjectPropertiesPtr props;
1721         int i;
1722
1723         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1724         RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
1725         RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
1726
1727         nexell_data = layer_data->nexell_data;
1728         props = drmModeObjectGetProperties(nexell_data->drm_fd, layer_data->plane_id,
1729                                            DRM_MODE_OBJECT_PLANE);
1730         if (props == NULL) {
1731                 TDM_ERR("get property failed: %m");
1732                 return TDM_ERROR_OPERATION_FAILED;
1733         }
1734
1735         for (i = 0; i < props->count_props; i++)
1736                 if (props->props[i] == id) {
1737                         (*value).u32 = (uint)props->prop_values[i];
1738                         break;
1739                 }
1740
1741         drmModeFreeObjectProperties(props);
1742
1743         return TDM_ERROR_NONE;
1744 }
1745
1746 tdm_error
1747 nexell_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
1748 {
1749         tdm_nexell_layer_data *layer_data = layer;
1750
1751         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1752         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
1753
1754         layer_data->info = *info;
1755         layer_data->info_changed = 1;
1756
1757         return TDM_ERROR_NONE;
1758 }
1759
1760 tdm_error
1761 nexell_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
1762 {
1763         tdm_nexell_layer_data *layer_data = layer;
1764
1765         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1766         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
1767
1768         *info = layer_data->info;
1769
1770         return TDM_ERROR_NONE;
1771 }
1772
1773 static tdm_nexell_display_buffer *
1774 _tdm_nexell_display_find_buffer(tdm_nexell_data *nexell_data, tbm_surface_h buffer)
1775 {
1776         tdm_nexell_display_buffer *display_buffer = NULL;
1777
1778         LIST_FOR_EACH_ENTRY(display_buffer, &nexell_data->buffer_list, link) {
1779                 if (display_buffer->buffer == buffer)
1780                         return display_buffer;
1781         }
1782
1783         return NULL;
1784 }
1785
1786 static void
1787 _tdm_nexell_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
1788 {
1789         tdm_nexell_data *nexell_data;
1790         tdm_nexell_display_buffer *display_buffer;
1791         tdm_nexell_layer_data *layer_data = NULL;
1792         tdm_nexell_output_data *output_data = NULL;
1793         char buf[256] = {0,};
1794         char *ret_tmp;
1795
1796         if (!user_data) {
1797                 TDM_ERR("no user_data");
1798                 return;
1799         }
1800         if (!buffer) {
1801                 TDM_ERR("no buffer");
1802                 return;
1803         }
1804
1805         nexell_data = (tdm_nexell_data *) user_data;
1806
1807         display_buffer = _tdm_nexell_display_find_buffer(nexell_data, buffer);
1808         if (!display_buffer) {
1809                 TDM_ERR("no display_buffer");
1810                 return;
1811         }
1812
1813         LIST_FOR_EACH_ENTRY(output_data, &nexell_data->output_list, link) {
1814                 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1815                         if (display_buffer == layer_data->display_buffer)
1816                                 layer_data->display_buffer = NULL;
1817                 }
1818         }
1819
1820         if (display_buffer->fb_id > 0) {
1821                 if (drmModeRmFB(nexell_data->drm_fd, display_buffer->fb_id) < 0) {
1822                         ret_tmp = strerror_r(errno, buf, sizeof(buf));
1823                         TDM_ERR("rm fb failed: %d(%s,%s)\n", errno, buf, ret_tmp);
1824                 }
1825         }
1826
1827         TDM_DBG("destroy buffer:%p", display_buffer->buffer);
1828
1829         LIST_DEL(&display_buffer->link);
1830         free(display_buffer);
1831 }
1832
1833 static tdm_nexell_display_buffer *
1834 _tdm_nexell_display_create_buffer(tdm_nexell_data *nexell_data, tbm_surface_h buffer, tdm_error *err)
1835 {
1836         tdm_nexell_display_buffer *display_buffer = NULL;
1837         tdm_error res = TDM_ERROR_NONE;
1838         int count, i, ret;
1839
1840         display_buffer = calloc(1, sizeof(tdm_nexell_display_buffer));
1841         if (!display_buffer) {
1842                 TDM_ERR("alloc failed");
1843                 if (err)
1844                         *err = TDM_ERROR_OUT_OF_MEMORY;
1845                 return NULL;
1846         }
1847
1848         display_buffer->buffer = buffer;
1849
1850         res = tdm_buffer_add_destroy_handler(buffer, _tdm_nexell_display_cb_destroy_buffer, nexell_data);
1851         if (res != TDM_ERROR_NONE) {
1852                 TDM_ERR("add destroy handler fail");
1853                 free(display_buffer);
1854                 if (err)
1855                         *err = res;
1856                 return NULL;
1857         }
1858
1859         display_buffer->width = tbm_surface_get_width(buffer);
1860         display_buffer->height = tbm_surface_get_height(buffer);
1861         display_buffer->format = tbm_surface_get_format(buffer);
1862         display_buffer->count = tbm_surface_internal_get_num_bos(buffer);
1863         count = tbm_surface_internal_get_num_planes(display_buffer->format);
1864         TDM_DBG(" display_buffer:%p %dx%d %c%c%c%c bo_num:%d plane_num:%d",
1865                         buffer, display_buffer->width, display_buffer->height,
1866                         FOURCC_STR(display_buffer->format), display_buffer->count, count);
1867
1868         for (i = 0; i < count; i++) {
1869                 int bo_idx = 0;
1870                 tbm_bo bo = NULL;
1871
1872                 bo_idx = tbm_surface_internal_get_plane_bo_idx(buffer, i);
1873                 bo = tbm_surface_internal_get_bo(buffer, bo_idx);
1874                 display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
1875
1876                 tbm_surface_internal_get_plane_data(buffer, i, &display_buffer->size,
1877                                                                                         &display_buffer->offsets[i],
1878                                                                                         &display_buffer->pitches[i]);
1879                 TDM_DBG("\tplane%d(size:%d offset:%d pitch:%d) bo%d(handle:%d)",
1880                                 i, display_buffer->size, display_buffer->offsets[i],
1881                                 display_buffer->pitches[i], bo_idx, display_buffer->handles[i]);
1882         }
1883
1884         ret = drmModeAddFB2(nexell_data->drm_fd, display_buffer->width, display_buffer->height,
1885                                 display_buffer->format, display_buffer->handles, display_buffer->pitches,
1886                                 display_buffer->offsets, &display_buffer->fb_id, 0);
1887         if (ret < 0) {
1888                 TDM_ERR("add fb failed: %m");
1889                 free(display_buffer);
1890                 if (err)
1891                         *err = TDM_ERROR_OPERATION_FAILED;
1892                 return NULL;
1893         }
1894
1895         TDM_DBG("nexell_data->drm_fd : %d, display_buffer->fb_id:%u", nexell_data->drm_fd,
1896                         display_buffer->fb_id);
1897
1898         if (IS_RGB(display_buffer->format))
1899                 display_buffer->width = display_buffer->pitches[0] >> 2;
1900         else
1901                 display_buffer->width = display_buffer->pitches[0];
1902
1903         LIST_ADDTAIL(&display_buffer->link, &nexell_data->buffer_list);
1904
1905         if (err)
1906                 *err = TDM_ERROR_NONE;
1907
1908         return display_buffer;
1909 }
1910
1911 void
1912 tdm_nexell_data_destroy_buffer_list(tdm_nexell_data *nexell_data)
1913 {
1914         tdm_nexell_display_buffer *b = NULL, *bb = NULL;
1915
1916         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &nexell_data->buffer_list, link) {
1917                 tdm_buffer_remove_destroy_handler(b->buffer, _tdm_nexell_display_cb_destroy_buffer, nexell_data);
1918                 _tdm_nexell_display_cb_destroy_buffer(b->buffer, nexell_data);
1919         }
1920 }
1921
1922 tdm_error
1923 nexell_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
1924 {
1925         tdm_nexell_layer_data *layer_data = layer;
1926         tdm_nexell_data *nexell_data;
1927         tdm_nexell_display_buffer *display_buffer;
1928         tdm_error err = TDM_ERROR_NONE;
1929
1930         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1931         RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
1932
1933         nexell_data = layer_data->nexell_data;
1934         display_buffer = _tdm_nexell_display_find_buffer(nexell_data, buffer);
1935         if (!display_buffer) {
1936                 display_buffer = _tdm_nexell_display_create_buffer(nexell_data, buffer, &err);
1937                 RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
1938         }
1939
1940         if (layer_data->display_buffer != display_buffer) {
1941                 if (layer_data->display_buffer)
1942                         tbm_surface_internal_unref(layer_data->display_buffer->buffer);
1943
1944                 layer_data->display_buffer = display_buffer;
1945                 tbm_surface_internal_ref(layer_data->display_buffer->buffer);
1946                 layer_data->display_buffer_changed = 1;
1947         }
1948
1949         return TDM_ERROR_NONE;
1950 }
1951
1952 tdm_error
1953 nexell_layer_unset_buffer(tdm_layer *layer)
1954 {
1955         tdm_nexell_layer_data *layer_data = layer;
1956
1957         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
1958
1959         if (!(layer_data->capabilities & TDM_LAYER_CAPABILITY_PRIMARY) && layer_data->display_buffer) {
1960                 tbm_surface_internal_unref(layer_data->display_buffer->buffer);
1961                 layer_data->display_buffer = NULL;
1962         }
1963
1964         layer_data->display_buffer_changed = 1;
1965
1966         return TDM_ERROR_NONE;
1967 }
1968
1969 tdm_nexell_layer_data *
1970 nexell_output_data_get_layer_data(tdm_nexell_output_data *output_data, int layer_zpos)
1971 {
1972         tdm_nexell_layer_data *l = NULL;
1973
1974         RETURN_VAL_IF_FAIL(output_data, NULL);
1975
1976         LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link) {
1977                 if (l->zpos == layer_zpos)
1978                         return l;
1979         }
1980
1981         return NULL;
1982 }