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