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