Free allocated memory if commit failed
[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                 free(event_data);
1554                 drmModeAtomicFree(request);
1555                 return HAL_TDM_ERROR_OPERATION_FAILED;
1556         }
1557
1558         drmModeAtomicFree(request);
1559
1560         return HAL_TDM_ERROR_NONE;
1561 }
1562
1563 static hal_tdm_error
1564 _nexell_output_layers_commit(hal_tdm_output *output, int sync, void *user_data)
1565 {
1566         tdm_nexell_output *output_data = output;
1567         tdm_nexell_display *display_data;
1568         tdm_nexell_layer *layer_data = NULL;
1569         hal_tdm_error ret;
1570         int do_waitvblank = 1;
1571
1572         TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1573
1574         display_data = output_data->display_data;
1575
1576         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
1577                 if (layer_data == output_data->primary_layer) {
1578                         ret = _tdm_nexell_display_commit_primary_layer(layer_data, user_data,
1579                                         &do_waitvblank);
1580                         if (ret != HAL_TDM_ERROR_NONE)
1581                                 return ret;
1582                 } else {
1583                         ret = _tdm_nexell_display_commit_layer(layer_data);
1584                         if (ret != HAL_TDM_ERROR_NONE)
1585                                 return ret;
1586                 }
1587         }
1588
1589         if (do_waitvblank == 1) {
1590                 tdm_nexell_event_data *event_data = calloc(1, sizeof(tdm_nexell_event_data));
1591                 uint target_msc;
1592
1593                 if (!event_data) {
1594                         TDM_BACKEND_ERR("alloc failed");
1595                         return HAL_TDM_ERROR_OUT_OF_MEMORY;
1596                 }
1597
1598                 ret = _tdm_nexell_display_get_cur_msc(display_data->drm_fd, output_data->pipe,
1599                                                    &target_msc);
1600                 if (ret != HAL_TDM_ERROR_NONE) {
1601                         free(event_data);
1602                         return ret;
1603                 }
1604
1605                 target_msc++;
1606
1607                 event_data->type = HAL_TDM_NEXELL_EVENT_TYPE_COMMIT;
1608                 event_data->output_data = output_data;
1609                 event_data->user_data = user_data;
1610
1611                 ret = _tdm_nexell_display_wait_vblank(display_data->drm_fd, output_data->pipe,
1612                                                    &target_msc, event_data);
1613                 if (ret != HAL_TDM_ERROR_NONE) {
1614                         free(event_data);
1615                         return ret;
1616                 }
1617         }
1618
1619         return HAL_TDM_ERROR_NONE;
1620 }
1621
1622 hal_tdm_error
1623 nexell_output_commit(hal_tdm_output *output, int sync, void *user_data)
1624 {
1625         tdm_nexell_output *output_data = output;
1626         tdm_nexell_display *display_data;
1627         hal_tdm_error ret;
1628
1629         TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1630
1631         display_data = output_data->display_data;
1632
1633         /* check the atomic pageflip */
1634         if (display_data->has_atomic) {
1635                 ret = _nexell_output_atomic_commit(output, sync, user_data);
1636                 if (ret != HAL_TDM_ERROR_NONE) {
1637                         TDM_BACKEND_ERR("_nexell_output_atomic_commit failed.");
1638                         return ret;
1639                 }
1640         } else {
1641                 ret = _nexell_output_layers_commit(output, sync, user_data);
1642                 if (ret != HAL_TDM_ERROR_NONE) {
1643                         TDM_BACKEND_ERR("_nexell_output_layers_commit failed.");
1644                         return ret;
1645                 }
1646         }
1647
1648         return HAL_TDM_ERROR_NONE;
1649 }
1650
1651 hal_tdm_error
1652 nexell_output_set_commit_handler(hal_tdm_output *output,
1653                               hal_tdm_output_commit_handler func)
1654 {
1655         tdm_nexell_output *output_data = output;
1656
1657         TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1658         TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
1659
1660         output_data->commit_func = func;
1661
1662         return HAL_TDM_ERROR_NONE;
1663 }
1664
1665 hal_tdm_error
1666 nexell_output_set_dpms(hal_tdm_output *output, hal_tdm_output_dpms dpms_value)
1667 {
1668         tdm_nexell_output *output_data = output;
1669         tdm_nexell_display *display_data;
1670         int ret;
1671
1672         TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1673
1674         if (output_data->dpms_prop_id == 0) {
1675                 TDM_BACKEND_WRN("not support DPMS");
1676                 return HAL_TDM_ERROR_OPERATION_FAILED;
1677         }
1678
1679         display_data = output_data->display_data;
1680         ret = drmModeObjectSetProperty(display_data->drm_fd,
1681                                        output_data->connector_id, DRM_MODE_OBJECT_CONNECTOR,
1682                                        output_data->dpms_prop_id, dpms_value);
1683         if (ret < 0) {
1684                 TDM_BACKEND_ERR("set dpms failed: %m");
1685                 return HAL_TDM_ERROR_OPERATION_FAILED;
1686         }
1687
1688         return HAL_TDM_ERROR_NONE;
1689 }
1690
1691 hal_tdm_error
1692 nexell_output_get_dpms(hal_tdm_output *output, hal_tdm_output_dpms *dpms_value)
1693 {
1694         tdm_nexell_output *output_data = output;
1695         tdm_nexell_display *display_data;
1696         drmModeObjectPropertiesPtr props;
1697         int i;
1698
1699         TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1700         TDM_BACKEND_RETURN_VAL_IF_FAIL(dpms_value, HAL_TDM_ERROR_INVALID_PARAMETER);
1701
1702         display_data = output_data->display_data;
1703         props = drmModeObjectGetProperties(display_data->drm_fd, output_data->connector_id,
1704                                            DRM_MODE_OBJECT_CONNECTOR);
1705         if (props == NULL) {
1706                 TDM_BACKEND_ERR("get property failed: %m");
1707                 return HAL_TDM_ERROR_OPERATION_FAILED;
1708         }
1709
1710         for (i = 0; i < props->count_props; i++)
1711                 if (props->props[i] == output_data->dpms_prop_id) {
1712                         *dpms_value = (uint)props->prop_values[i];
1713                         break;
1714                 }
1715
1716         drmModeFreeObjectProperties(props);
1717
1718         return HAL_TDM_ERROR_NONE;
1719 }
1720
1721 hal_tdm_error
1722 nexell_output_set_mode(hal_tdm_output *output, const hal_tdm_output_mode *mode)
1723 {
1724         tdm_nexell_output *output_data = output;
1725         hal_tdm_error ret = HAL_TDM_ERROR_NONE;
1726
1727         TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1728         TDM_BACKEND_RETURN_VAL_IF_FAIL(mode, HAL_TDM_ERROR_INVALID_PARAMETER);
1729
1730         /* create or replace the target_window when the output mode is set */
1731         ret = nexell_hwc_target_window_set_info(output_data->hwc_data, mode->hdisplay, mode->vdisplay);
1732         if (ret != HAL_TDM_ERROR_NONE) {
1733                 TDM_BACKEND_ERR("set info target hwc window failed (%d)", ret);
1734                 return ret;
1735         }
1736
1737         output_data->current_mode = mode;
1738         output_data->mode_changed = 1;
1739
1740         TDM_BACKEND_INFO("Set the output mode: %s, %d, %d, %d, %d, %d",
1741                          mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags, mode->type);
1742
1743         return HAL_TDM_ERROR_NONE;
1744 }
1745
1746 hal_tdm_error
1747 nexell_output_get_mode(hal_tdm_output *output, const hal_tdm_output_mode **mode)
1748 {
1749         tdm_nexell_output *output_data = output;
1750
1751         TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1752         TDM_BACKEND_RETURN_VAL_IF_FAIL(mode, HAL_TDM_ERROR_INVALID_PARAMETER);
1753
1754         *mode = output_data->current_mode;
1755
1756         return HAL_TDM_ERROR_NONE;
1757 }
1758
1759 hal_tdm_hwc *
1760 nexell_output_get_hwc(hal_tdm_output *output, hal_tdm_error *error)
1761 {
1762         tdm_nexell_hwc *hwc_data = NULL;
1763         tdm_nexell_output *output_data = output;
1764         hal_tdm_error ret = HAL_TDM_ERROR_NONE;
1765         int i;
1766
1767         if (!output_data) {
1768                 TDM_BACKEND_ERR("invalid params");
1769                 if (error)
1770                         *error = HAL_TDM_ERROR_INVALID_PARAMETER;
1771                 return NULL;
1772         }
1773
1774         if (output_data->hwc_data) {
1775                 TDM_BACKEND_INFO("hwc_data already exists");
1776                 if (error)
1777                         *error = HAL_TDM_ERROR_NONE;
1778                 return output_data->hwc_data;
1779         }
1780
1781         hwc_data = calloc(1, sizeof(tdm_nexell_hwc));
1782         if (!hwc_data) {
1783                 TDM_BACKEND_ERR("alloc failed");
1784                 if (error)
1785                         *error = HAL_TDM_ERROR_OUT_OF_MEMORY;
1786                 return NULL;
1787         }
1788
1789         for (i = 0; i < NUM_LAYERS; i++) {
1790                 hwc_data->ui_buffer_queue[i].tqueue = NULL;
1791                 hwc_data->ui_buffer_queue[i].ref_cnt = 0;
1792         }
1793
1794         hwc_data->output_data = output_data;
1795
1796         LIST_INITHEAD(&hwc_data->hwc_window_list);
1797
1798         output_data->hwc_data = hwc_data;
1799
1800         ret = tdm_nexell_hwc_initailize_target_window(output_data->hwc_data);
1801         if (ret != HAL_TDM_ERROR_NONE) {
1802                 TDM_BACKEND_ERR("create target hwc window failed (%d)", ret);
1803                 free(hwc_data);
1804                 if (error)
1805                         *error = ret;
1806                 return NULL;
1807         }
1808
1809         if (error)
1810                 *error = HAL_TDM_ERROR_NONE;
1811
1812         return hwc_data;
1813 }
1814
1815 hal_tdm_error
1816 nexell_output_set_status_handler(hal_tdm_output *output,
1817                               hal_tdm_output_status_handler func,
1818                               void *user_data)
1819 {
1820         tdm_nexell_output *output_data = output;
1821
1822         TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1823         TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
1824
1825         output_data->status_func = func;
1826         output_data->status_user_data = user_data;
1827
1828         return HAL_TDM_ERROR_NONE;
1829 }
1830
1831 hal_tdm_error
1832 nexell_layer_get_capability(tdm_nexell_layer *layer_data, tdm_nexell_caps_layer *caps)
1833 {
1834         tdm_nexell_display *display_data;
1835         drmModePlanePtr plane = NULL;
1836         drmModeObjectPropertiesPtr props = NULL;
1837         int i, format_count = 0;
1838         hal_tdm_error ret;
1839
1840         TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1841         TDM_BACKEND_RETURN_VAL_IF_FAIL(caps, HAL_TDM_ERROR_INVALID_PARAMETER);
1842
1843         memset(caps, 0, sizeof(tdm_nexell_caps_layer));
1844
1845         display_data = layer_data->display_data;
1846         plane = drmModeGetPlane(display_data->drm_fd, layer_data->plane_id);
1847         if (!plane) {
1848                 TDM_BACKEND_ERR("get plane failed: %m");
1849                 ret = HAL_TDM_ERROR_OPERATION_FAILED;
1850                 goto failed_get;
1851         }
1852
1853         caps->capabilities = layer_data->capabilities;
1854         caps->zpos = layer_data->zpos;  /* if VIDEO layer_data, zpos is -1 */
1855
1856         caps->format_count = plane->count_formats;
1857         caps->formats = calloc(1, sizeof(tbm_format) * caps->format_count);
1858         if (!caps->formats) {
1859                 ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
1860                 TDM_BACKEND_ERR("alloc failed\n");
1861                 goto failed_get;
1862         }
1863
1864         for (i = 0; i < caps->format_count; i++) {
1865                 /* TODO: kernel reports wrong formats */
1866                 if (plane->formats[i] != DRM_FORMAT_XRGB8888 &&
1867                     plane->formats[i] != DRM_FORMAT_ARGB8888 &&
1868                     plane->formats[i] != DRM_FORMAT_YUV420) {
1869                         TDM_BACKEND_WRN("plane(%d) zpos(%d) %c%c%c%c skipped",
1870                                         layer_data->plane_id, layer_data->zpos, FOURCC_STR(plane->formats[i]));
1871                         continue;
1872                 }
1873                 caps->formats[format_count] = tdm_nexell_format_to_tbm_format(plane->formats[i]);
1874                 format_count++;
1875         }
1876
1877         caps->format_count = format_count;
1878
1879         props = drmModeObjectGetProperties(display_data->drm_fd, layer_data->plane_id,
1880                                            DRM_MODE_OBJECT_PLANE);
1881         if (!props) {
1882                 ret = HAL_TDM_ERROR_OPERATION_FAILED;
1883                 TDM_BACKEND_ERR("get plane properties failed: %m\n");
1884                 goto failed_get;
1885         }
1886
1887         caps->props = calloc(1, sizeof(hal_tdm_prop) * props->count_props);
1888         if (!caps->props) {
1889                 ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
1890                 TDM_BACKEND_ERR("alloc failed\n");
1891                 goto failed_get;
1892         }
1893
1894         caps->prop_count = 0;
1895         for (i = 0; i < props->count_props; i++) {
1896                 drmModePropertyPtr prop = drmModeGetProperty(display_data->drm_fd, props->props[i]);
1897                 if (!prop)
1898                         continue;
1899                 if (!strncmp(prop->name, "type", HAL_TDM_NAME_LEN)) {
1900                         drmModeFreeProperty(prop);
1901                         continue;
1902                 }
1903                 if (!strncmp(prop->name, "zpos", HAL_TDM_NAME_LEN)) {
1904                         drmModeFreeProperty(prop);
1905                         continue;
1906                 }
1907                 snprintf(caps->props[caps->prop_count].name, HAL_TDM_NAME_LEN, "%s", prop->name);
1908                 caps->props[caps->prop_count].id = props->props[i];
1909                 caps->prop_count++;
1910                 drmModeFreeProperty(prop);
1911         }
1912
1913         drmModeFreeObjectProperties(props);
1914         drmModeFreePlane(plane);
1915
1916         return HAL_TDM_ERROR_NONE;
1917 failed_get:
1918         drmModeFreeObjectProperties(props);
1919         drmModeFreePlane(plane);
1920         free(caps->formats);
1921         free(caps->props);
1922         memset(caps, 0, sizeof(tdm_nexell_caps_layer));
1923         return ret;
1924 }
1925
1926 hal_tdm_error
1927 nexell_layer_set_property(tdm_nexell_layer *layer_data, unsigned int id, hal_tdm_value value)
1928 {
1929         tdm_nexell_display *display_data;
1930         int ret;
1931
1932         TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1933         TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, HAL_TDM_ERROR_INVALID_PARAMETER);
1934
1935         display_data = layer_data->display_data;
1936         ret = drmModeObjectSetProperty(display_data->drm_fd,
1937                                        layer_data->plane_id, DRM_MODE_OBJECT_PLANE,
1938                                        id, value.u32);
1939         if (ret < 0) {
1940                 TDM_BACKEND_ERR("set property failed: %m");
1941                 return HAL_TDM_ERROR_OPERATION_FAILED;
1942         }
1943
1944         return HAL_TDM_ERROR_NONE;
1945 }
1946
1947 hal_tdm_error
1948 nexell_layer_get_property(tdm_nexell_layer *layer_data, unsigned int id, hal_tdm_value *value)
1949 {
1950         tdm_nexell_display *display_data;
1951         drmModeObjectPropertiesPtr props;
1952         int i;
1953
1954         TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1955         TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, HAL_TDM_ERROR_INVALID_PARAMETER);
1956         TDM_BACKEND_RETURN_VAL_IF_FAIL(value, HAL_TDM_ERROR_INVALID_PARAMETER);
1957
1958         display_data = layer_data->display_data;
1959         props = drmModeObjectGetProperties(display_data->drm_fd, layer_data->plane_id,
1960                                            DRM_MODE_OBJECT_PLANE);
1961         if (props == NULL) {
1962                 TDM_BACKEND_ERR("get property failed: %m");
1963                 return HAL_TDM_ERROR_OPERATION_FAILED;
1964         }
1965
1966         for (i = 0; i < props->count_props; i++)
1967                 if (props->props[i] == id) {
1968                         (*value).u32 = (uint)props->prop_values[i];
1969                         break;
1970                 }
1971
1972         drmModeFreeObjectProperties(props);
1973
1974         return HAL_TDM_ERROR_NONE;
1975 }
1976
1977 hal_tdm_error
1978 nexell_layer_set_info(tdm_nexell_layer *layer_data, tdm_nexell_layer_info *info)
1979 {
1980         TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1981         TDM_BACKEND_RETURN_VAL_IF_FAIL(info, HAL_TDM_ERROR_INVALID_PARAMETER);
1982
1983         layer_data->info = *info;
1984         layer_data->info_changed = 1;
1985
1986         return HAL_TDM_ERROR_NONE;
1987 }
1988
1989 hal_tdm_error
1990 nexell_layer_get_info(tdm_nexell_layer *layer_data, tdm_nexell_layer_info *info)
1991 {
1992         TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
1993         TDM_BACKEND_RETURN_VAL_IF_FAIL(info, HAL_TDM_ERROR_INVALID_PARAMETER);
1994
1995         *info = layer_data->info;
1996
1997         return HAL_TDM_ERROR_NONE;
1998 }
1999
2000 static tdm_nexell_display_buffer *
2001 _tdm_nexell_display_find_buffer(tdm_nexell_display *display_data, tbm_surface_h buffer)
2002 {
2003         tdm_nexell_display_buffer *display_buffer = NULL;
2004
2005         LIST_FOR_EACH_ENTRY(display_buffer, &display_data->buffer_list, link) {
2006                 if (display_buffer->buffer == buffer)
2007                         return display_buffer;
2008         }
2009
2010         return NULL;
2011 }
2012
2013 static void
2014 _tdm_nexell_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
2015 {
2016         tdm_nexell_display *display_data;
2017         tdm_nexell_display_buffer *display_buffer;
2018         tdm_nexell_layer *layer_data = NULL;
2019         tdm_nexell_output *output_data = NULL;
2020         char buf[256] = {0,};
2021         char *ret_tmp;
2022
2023         if (!user_data) {
2024                 TDM_BACKEND_ERR("no user_data");
2025                 return;
2026         }
2027         if (!buffer) {
2028                 TDM_BACKEND_ERR("no buffer");
2029                 return;
2030         }
2031
2032         display_data = (tdm_nexell_display *) user_data;
2033
2034         display_buffer = _tdm_nexell_display_find_buffer(display_data, buffer);
2035         if (!display_buffer) {
2036                 TDM_BACKEND_ERR("no display_buffer");
2037                 return;
2038         }
2039
2040         LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link) {
2041                 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
2042                         if (display_buffer == layer_data->display_buffer)
2043                                 layer_data->display_buffer = NULL;
2044                 }
2045         }
2046
2047         if (display_buffer->fb_id > 0) {
2048                 if (drmModeRmFB(display_data->drm_fd, display_buffer->fb_id) < 0) {
2049                         ret_tmp = strerror_r(errno, buf, sizeof(buf));
2050                         TDM_BACKEND_ERR("rm fb failed: %d(%s,%s)\n", errno, buf, ret_tmp);
2051                 }
2052         }
2053
2054         TDM_BACKEND_DBG("destroy buffer:%p", display_buffer->buffer);
2055
2056         LIST_DEL(&display_buffer->link);
2057         free(display_buffer);
2058 }
2059
2060 static tdm_nexell_display_buffer *
2061 _tdm_nexell_display_create_buffer(tdm_nexell_display *display_data, tbm_surface_h buffer, hal_tdm_error *err)
2062 {
2063         tdm_nexell_display_buffer *display_buffer = NULL;
2064         int count, i, ret;
2065
2066         display_buffer = calloc(1, sizeof(tdm_nexell_display_buffer));
2067         if (!display_buffer) {
2068                 TDM_BACKEND_ERR("alloc failed");
2069                 if (err)
2070                         *err = HAL_TDM_ERROR_OUT_OF_MEMORY;
2071                 return NULL;
2072         }
2073
2074         display_buffer->buffer = buffer;
2075
2076         ret = tbm_surface_internal_add_destroy_handler(buffer, _tdm_nexell_display_cb_destroy_buffer, display_data);
2077         if (ret == 0) {
2078                 TDM_BACKEND_ERR("add destroy handler fail");
2079                 free(display_buffer);
2080                 if (err)
2081                         *err = HAL_TDM_ERROR_OPERATION_FAILED;
2082                 return NULL;
2083         }
2084
2085         display_buffer->width = tbm_surface_get_width(buffer);
2086         display_buffer->height = tbm_surface_get_height(buffer);
2087         display_buffer->format = tbm_surface_get_format(buffer);
2088         display_buffer->count = tbm_surface_internal_get_num_bos(buffer);
2089         count = tbm_surface_internal_get_num_planes(display_buffer->format);
2090         TDM_BACKEND_DBG(" display_buffer:%p %dx%d %c%c%c%c bo_num:%d plane_num:%d",
2091                         buffer, display_buffer->width, display_buffer->height,
2092                         FOURCC_STR(display_buffer->format), display_buffer->count, count);
2093
2094         for (i = 0; i < count; i++) {
2095                 int bo_idx = 0;
2096                 tbm_bo bo = NULL;
2097
2098                 bo_idx = tbm_surface_internal_get_plane_bo_idx(buffer, i);
2099                 bo = tbm_surface_internal_get_bo(buffer, bo_idx);
2100                 display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
2101
2102                 tbm_surface_internal_get_plane_data(buffer, i, &display_buffer->size,
2103                                                                                         &display_buffer->offsets[i],
2104                                                                                         &display_buffer->pitches[i]);
2105                 TDM_BACKEND_DBG("\tplane%d(size:%d offset:%d pitch:%d) bo%d(handle:%d)",
2106                                 i, display_buffer->size, display_buffer->offsets[i],
2107                                 display_buffer->pitches[i], bo_idx, display_buffer->handles[i]);
2108         }
2109
2110         ret = drmModeAddFB2(display_data->drm_fd, display_buffer->width, display_buffer->height,
2111                                 display_buffer->format, display_buffer->handles, display_buffer->pitches,
2112                                 display_buffer->offsets, &display_buffer->fb_id, 0);
2113         if (ret < 0) {
2114                 TDM_BACKEND_ERR("add fb failed: %m");
2115                 free(display_buffer);
2116                 if (err)
2117                         *err = HAL_TDM_ERROR_OPERATION_FAILED;
2118                 tbm_surface_internal_remove_destroy_handler(buffer, _tdm_nexell_display_cb_destroy_buffer, display_data);
2119                 return NULL;
2120         }
2121
2122         TDM_BACKEND_DBG("display_data->drm_fd : %d, display_buffer->fb_id:%u", display_data->drm_fd,
2123                         display_buffer->fb_id);
2124
2125         if (IS_RGB(display_buffer->format))
2126                 display_buffer->width = display_buffer->pitches[0] >> 2;
2127         else
2128                 display_buffer->width = display_buffer->pitches[0];
2129
2130         LIST_ADDTAIL(&display_buffer->link, &display_data->buffer_list);
2131
2132         if (err)
2133                 *err = HAL_TDM_ERROR_NONE;
2134
2135         return display_buffer;
2136 }
2137
2138 void
2139 tdm_nexell_display_destroy_buffer_list(tdm_nexell_display *display_data)
2140 {
2141         tdm_nexell_display_buffer *b = NULL, *bb = NULL;
2142
2143         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &display_data->buffer_list, link) {
2144                 tbm_surface_internal_remove_destroy_handler(b->buffer, _tdm_nexell_display_cb_destroy_buffer, display_data);
2145                 _tdm_nexell_display_cb_destroy_buffer(b->buffer, display_data);
2146         }
2147 }
2148
2149 hal_tdm_error
2150 nexell_layer_set_buffer(tdm_nexell_layer *layer_data, tbm_surface_h buffer)
2151 {
2152         tdm_nexell_display *display_data;
2153         tdm_nexell_display_buffer *display_buffer;
2154         hal_tdm_error err = HAL_TDM_ERROR_NONE;
2155
2156         TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
2157         TDM_BACKEND_RETURN_VAL_IF_FAIL(buffer, HAL_TDM_ERROR_INVALID_PARAMETER);
2158
2159         display_data = layer_data->display_data;
2160         display_buffer = _tdm_nexell_display_find_buffer(display_data, buffer);
2161         if (!display_buffer) {
2162                 display_buffer = _tdm_nexell_display_create_buffer(display_data, buffer, &err);
2163                 TDM_BACKEND_RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
2164         }
2165
2166         if (layer_data->display_buffer != display_buffer) {
2167                 if (layer_data->display_buffer)
2168                         tbm_surface_internal_unref(layer_data->display_buffer->buffer);
2169
2170                 layer_data->display_buffer = display_buffer;
2171                 tbm_surface_internal_ref(layer_data->display_buffer->buffer);
2172                 layer_data->display_buffer_changed = 1;
2173         }
2174
2175         return HAL_TDM_ERROR_NONE;
2176 }
2177
2178 hal_tdm_error
2179 nexell_layer_unset_buffer(tdm_nexell_layer *layer_data)
2180 {
2181         TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
2182
2183         if (!(layer_data->capabilities & TDM_NEXELL_LAYER_CAPABILITY_PRIMARY) && layer_data->display_buffer) {
2184                 tbm_surface_internal_unref(layer_data->display_buffer->buffer);
2185                 layer_data->display_buffer = NULL;
2186         }
2187
2188         layer_data->display_buffer_changed = 1;
2189
2190         return HAL_TDM_ERROR_NONE;
2191 }
2192
2193 tdm_nexell_layer *
2194 nexell_output_data_get_layer_data(tdm_nexell_output *output_data, int layer_zpos)
2195 {
2196         tdm_nexell_layer *l = NULL;
2197
2198         TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, NULL);
2199
2200         LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link) {
2201                 if (l->zpos == layer_zpos)
2202                         return l;
2203         }
2204
2205         return NULL;
2206 }