remove legacy libtdm backend
[platform/adaptation/samsung_exynos/libtdm-exynos.git] / src / tdm_exynos_pp.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include "tdm_exynos.h"
6
7 typedef struct _tdm_exynos_pp_buffer {
8         int index;
9         tbm_surface_h src;
10         tbm_surface_h dst;
11
12         struct list_head link;
13 } tdm_exynos_pp_buffer;
14
15 typedef struct _tdm_exynos_pp_data {
16         tdm_exynos_data *exynos_data;
17
18         unsigned int prop_id;
19
20         tdm_info_pp info;
21         int info_changed;
22
23         struct list_head pending_buffer_list;
24         struct list_head buffer_list;
25
26         tdm_pp_done_handler done_func;
27         void *done_user_data;
28
29         int startd;
30         int first_event;
31
32         struct list_head link;
33 } tdm_exynos_pp_data;
34
35
36 static tbm_format pp_formats[] = {
37         TBM_FORMAT_ARGB8888,
38         TBM_FORMAT_XRGB8888,
39         TBM_FORMAT_YUYV,
40         TBM_FORMAT_UYVY,
41         TBM_FORMAT_NV12,
42         TBM_FORMAT_NV21,
43         TBM_FORMAT_YUV420,
44         TBM_FORMAT_YVU420,
45 #ifdef HAVE_TILED_FORMAT
46         TBM_FORMAT_NV12MT,
47 #endif
48 };
49
50 #define NUM_PP_FORMAT   (sizeof(pp_formats) / sizeof(pp_formats[0]))
51
52 static int pp_list_init;
53 static struct list_head pp_list;
54
55 static int
56 _get_index(tdm_exynos_pp_data *pp_data)
57 {
58         tdm_exynos_pp_buffer *buffer = NULL;
59         int ret = 0;
60
61         while (1) {
62                 int found = 0;
63                 LIST_FOR_EACH_ENTRY(buffer, &pp_data->pending_buffer_list, link) {
64                         if (ret == buffer->index) {
65                                 found = 1;
66                                 break;
67                         }
68                 }
69                 if (!found)
70                         LIST_FOR_EACH_ENTRY(buffer, &pp_data->buffer_list, link) {
71                         if (ret == buffer->index) {
72                                 found = 1;
73                                 break;
74                         }
75                 }
76                 if (!found)
77                         break;
78                 ret++;
79         }
80
81         return ret;
82 }
83
84 static tdm_error
85 _tdm_exynos_pp_set(tdm_exynos_pp_data *pp_data)
86 {
87         tdm_exynos_data *exynos_data = pp_data->exynos_data;
88         tdm_info_pp *info = &pp_data->info;
89         struct drm_exynos_ipp_property property;
90         int ret = 0;
91
92         CLEAR(property);
93         property.config[0].ops_id = EXYNOS_DRM_OPS_SRC;
94         property.config[0].fmt = tdm_exynos_format_to_drm_format(info->src_config.format);
95         memcpy(&property.config[0].sz, &info->src_config.size, sizeof(tdm_size));
96         memcpy(&property.config[0].pos, &info->src_config.pos, sizeof(tdm_pos));
97         property.config[1].ops_id = EXYNOS_DRM_OPS_DST;
98         property.config[1].degree = info->transform % 4;
99         property.config[1].flip = (info->transform > 3) ? EXYNOS_DRM_FLIP_HORIZONTAL : 0;
100         property.config[1].fmt = tdm_exynos_format_to_drm_format(info->dst_config.format);
101         memcpy(&property.config[1].sz, &info->dst_config.size, sizeof(tdm_size));
102         memcpy(&property.config[1].pos, &info->dst_config.pos, sizeof(tdm_pos));
103         property.cmd = IPP_CMD_M2M;
104         property.prop_id = pp_data->prop_id;
105
106         TDM_DBG("src : flip(%x) deg(%d) fmt(%c%c%c%c) sz(%dx%d) pos(%d,%d %dx%d)  ",
107                         property.config[0].flip, property.config[0].degree,
108                         FOURCC_STR(property.config[0].fmt),
109                         property.config[0].sz.hsize, property.config[0].sz.vsize,
110                         property.config[0].pos.x, property.config[0].pos.y, property.config[0].pos.w,
111                         property.config[0].pos.h);
112         TDM_DBG("dst : flip(%x) deg(%d) fmt(%c%c%c%c) sz(%dx%d) pos(%d,%d %dx%d)  ",
113                         property.config[1].flip, property.config[1].degree,
114                         FOURCC_STR(property.config[1].fmt),
115                         property.config[1].sz.hsize, property.config[1].sz.vsize,
116                         property.config[1].pos.x, property.config[1].pos.y, property.config[1].pos.w,
117                         property.config[1].pos.h);
118
119         ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY, &property);
120         if (ret) {
121                 TDM_ERR("failed: %m");
122                 return TDM_ERROR_OPERATION_FAILED;
123         }
124
125         TDM_DBG("success. prop_id(%d) ", property.prop_id);
126         pp_data->prop_id = property.prop_id;
127         return TDM_ERROR_NONE;
128 }
129
130 static tdm_error
131 _tdm_exynos_pp_queue(tdm_exynos_pp_data *pp_data, tdm_exynos_pp_buffer *buffer,
132                                                         enum drm_exynos_ipp_buf_type type)
133 {
134         tdm_exynos_data *exynos_data = pp_data->exynos_data;
135         struct drm_exynos_ipp_queue_buf buf;
136         int i, bo_num, ret = 0;
137
138         CLEAR(buf);
139         buf.prop_id = pp_data->prop_id;
140         buf.ops_id = EXYNOS_DRM_OPS_SRC;
141         buf.buf_type = type;
142         buf.buf_id = buffer->index;
143         buf.user_data = (__u64)(uintptr_t)pp_data;
144         bo_num = tbm_surface_internal_get_num_bos(buffer->src);
145         for (i = 0; i < EXYNOS_DRM_PLANAR_MAX && i < bo_num; i++) {
146                 tbm_bo bo = tbm_surface_internal_get_bo(buffer->src, i);
147                 buf.handle[i] = (__u32)tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
148         }
149
150         TDM_DBG("prop_id(%d) ops_id(%d) ctrl(%d) id(%d) handles(%x %x %x). ",
151                         buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id,
152                         buf.handle[0], buf.handle[1], buf.handle[2]);
153
154         ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, &buf);
155         if (ret) {
156                 TDM_ERR("src failed. prop_id(%d) op(%d) buf(%d) id(%d). %m",
157                                 buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id);
158                 return TDM_ERROR_OPERATION_FAILED;
159         }
160
161         CLEAR(buf);
162         buf.prop_id = pp_data->prop_id;
163         buf.ops_id = EXYNOS_DRM_OPS_DST;
164         buf.buf_type = type;
165         buf.buf_id = buffer->index;
166         buf.user_data = (__u64)(uintptr_t)pp_data;
167         bo_num = tbm_surface_internal_get_num_bos(buffer->dst);
168         for (i = 0; i < EXYNOS_DRM_PLANAR_MAX && i < bo_num; i++) {
169                 tbm_bo bo = tbm_surface_internal_get_bo(buffer->dst, i);
170                 buf.handle[i] = (__u32)tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
171         }
172
173         TDM_DBG("prop_id(%d) ops_id(%d) ctrl(%d) id(%d) handles(%x %x %x). ",
174                         buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id,
175                         buf.handle[0], buf.handle[1], buf.handle[2]);
176
177         ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, &buf);
178         if (ret) {
179                 TDM_ERR("dst failed. prop_id(%d) op(%d) buf(%d) id(%d). %m",
180                                 buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id);
181                 return TDM_ERROR_OPERATION_FAILED;
182         }
183
184         TDM_DBG("success. prop_id(%d)", buf.prop_id);
185
186         return TDM_ERROR_NONE;
187 }
188
189 static tdm_error
190 _tdm_exynos_pp_cmd(tdm_exynos_pp_data *pp_data, enum drm_exynos_ipp_ctrl cmd)
191 {
192         tdm_exynos_data *exynos_data = pp_data->exynos_data;
193         struct drm_exynos_ipp_cmd_ctrl ctrl;
194         int ret = 0;
195
196         ctrl.prop_id = pp_data->prop_id;
197         ctrl.ctrl = cmd;
198
199         TDM_DBG("prop_id(%d) ctrl(%d). ", ctrl.prop_id, ctrl.ctrl);
200
201         ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_CMD_CTRL, &ctrl);
202         if (ret) {
203                 TDM_ERR("failed. prop_id(%d) ctrl(%d). %m", ctrl.prop_id, ctrl.ctrl);
204                 return TDM_ERROR_OPERATION_FAILED;
205         }
206
207         TDM_DBG("success. prop_id(%d) ", ctrl.prop_id);
208
209         return TDM_ERROR_NONE;
210 }
211
212 void
213 tdm_exynos_pp_cb(int fd, unsigned int prop_id, unsigned int *buf_idx,
214                                           unsigned int tv_sec, unsigned int tv_usec, void *user_data)
215 {
216         tdm_exynos_pp_handler(prop_id, buf_idx, tv_sec, tv_usec, user_data);
217 }
218
219 void
220 tdm_exynos_pp_handler(unsigned int prop_id, unsigned int *buf_idx,
221                                                         unsigned int tv_sec, unsigned int tv_usec, void *data)
222 {
223         tdm_exynos_pp_data *found = NULL, *pp_data = data;
224         tdm_exynos_pp_buffer *b = NULL, *bb = NULL, *dequeued_buffer = NULL;
225
226         if (!pp_data || !buf_idx) {
227                 TDM_ERR("invalid params");
228                 return;
229         }
230
231         LIST_FOR_EACH_ENTRY(found, &pp_list, link) {
232                 if (found == pp_data)
233                         break;
234         }
235         if (!found)
236                 return;
237
238         TDM_DBG("pp_data(%p) index(%d, %d)", pp_data, buf_idx[0], buf_idx[1]);
239
240         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->buffer_list, link) {
241                 if (buf_idx[0] == b->index) {
242                         dequeued_buffer = b;
243                         LIST_DEL(&dequeued_buffer->link);
244                         TDM_DBG("dequeued: %d", dequeued_buffer->index);
245                         break;
246                 }
247         }
248
249         if (!dequeued_buffer) {
250                 TDM_ERR("not found buffer index: %d", buf_idx[0]);
251                 return;
252         }
253
254         if (!pp_data->first_event) {
255                 TDM_DBG("pp(%p) got a first event. ", pp_data);
256                 pp_data->first_event = 1;
257         }
258
259         if (pp_data->done_func)
260                 pp_data->done_func(pp_data,
261                                                    dequeued_buffer->src,
262                                                    dequeued_buffer->dst,
263                                                    pp_data->done_user_data);
264         free(dequeued_buffer);
265 }
266
267 tdm_error
268 tdm_exynos_pp_get_capability(tdm_exynos_data *exynos_data, tdm_caps_pp *caps)
269 {
270         int i;
271
272         if (!caps) {
273                 TDM_ERR("invalid params");
274                 return TDM_ERROR_INVALID_PARAMETER;
275         }
276
277         caps->capabilities = TDM_PP_CAPABILITY_ASYNC;
278
279         caps->format_count = NUM_PP_FORMAT;
280
281         /* will be freed in frontend */
282         caps->formats = calloc(1, sizeof pp_formats);
283         if (!caps->formats) {
284                 TDM_ERR("alloc failed");
285                 return TDM_ERROR_OUT_OF_MEMORY;
286         }
287         for (i = 0; i < caps->format_count; i++)
288                 caps->formats[i] = pp_formats[i];
289
290         caps->min_w = 16;
291         caps->min_h = 8;
292         caps->max_w = -1;   /* not defined */
293         caps->max_h = -1;
294         caps->preferred_align = 16;
295
296         caps->max_attach_count = -1;
297
298         return TDM_ERROR_NONE;
299 }
300
301 tdm_pp *
302 tdm_exynos_pp_create(tdm_exynos_data *exynos_data, tdm_error *error)
303 {
304         tdm_exynos_pp_data *pp_data = calloc(1, sizeof(tdm_exynos_pp_data));
305         if (!pp_data) {
306                 TDM_ERR("alloc failed");
307                 if (error)
308                         *error = TDM_ERROR_OUT_OF_MEMORY;
309                 return NULL;
310         }
311
312         pp_data->exynos_data = exynos_data;
313
314         LIST_INITHEAD(&pp_data->pending_buffer_list);
315         LIST_INITHEAD(&pp_data->buffer_list);
316
317         if (!pp_list_init) {
318                 pp_list_init = 1;
319                 LIST_INITHEAD(&pp_list);
320         }
321         LIST_ADDTAIL(&pp_data->link, &pp_list);
322
323         return pp_data;
324 }
325
326 void
327 exynos_pp_destroy(tdm_pp *pp)
328 {
329         tdm_exynos_pp_data *pp_data = pp;
330         tdm_exynos_pp_buffer *b = NULL, *bb = NULL;
331
332         if (!pp_data)
333                 return;
334
335         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
336                 LIST_DEL(&b->link);
337                 free(b);
338         }
339
340         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->buffer_list, link) {
341                 LIST_DEL(&b->link);
342                 _tdm_exynos_pp_queue(pp_data, b, IPP_BUF_DEQUEUE);
343                 free(b);
344         }
345
346         if (pp_data->prop_id)
347                 _tdm_exynos_pp_cmd(pp_data, IPP_CTRL_STOP);
348
349         LIST_DEL(&pp_data->link);
350
351         free(pp_data);
352 }
353
354 tdm_error
355 exynos_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
356 {
357         tdm_exynos_pp_data *pp_data = pp;
358
359         RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
360         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
361
362         if (info->sync) {
363                 TDM_ERR("not support sync mode currently");
364                 return TDM_ERROR_INVALID_PARAMETER;
365         }
366
367         pp_data->info = *info;
368         pp_data->info_changed = 1;
369
370         return TDM_ERROR_NONE;
371 }
372
373 tdm_error
374 exynos_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
375 {
376         tdm_exynos_pp_data *pp_data = pp;
377         tdm_exynos_pp_buffer *buffer;
378
379         RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
380         RETURN_VAL_IF_FAIL(src, TDM_ERROR_INVALID_PARAMETER);
381         RETURN_VAL_IF_FAIL(dst, TDM_ERROR_INVALID_PARAMETER);
382
383         buffer = calloc(1, sizeof(tdm_exynos_pp_buffer));
384         if (!buffer) {
385                 TDM_ERR("alloc failed");
386                 return TDM_ERROR_NONE;
387         }
388
389         LIST_ADDTAIL(&buffer->link, &pp_data->pending_buffer_list);
390         buffer->index = _get_index(pp_data);
391         buffer->src = src;
392         buffer->dst = dst;
393
394         return TDM_ERROR_NONE;
395 }
396
397 tdm_error
398 exynos_pp_commit(tdm_pp *pp)
399 {
400         tdm_exynos_pp_data *pp_data = pp;
401         tdm_exynos_pp_buffer *b = NULL, *bb = NULL;
402         tdm_error ret;
403
404         RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
405
406         if (pp_data->info_changed) {
407                 if (pp_data->startd)
408                         _tdm_exynos_pp_cmd(pp_data, IPP_CTRL_PAUSE);
409
410                 ret = _tdm_exynos_pp_set(pp_data);
411                 if (ret < 0)
412                         return TDM_ERROR_OPERATION_FAILED;
413         }
414
415         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
416                 LIST_DEL(&b->link);
417                 _tdm_exynos_pp_queue(pp_data, b, IPP_BUF_ENQUEUE);
418                 TDM_DBG("queued: %d", b->index);
419                 LIST_ADDTAIL(&b->link, &pp_data->buffer_list);
420         }
421
422         if (pp_data->info_changed) {
423                 pp_data->info_changed = 0;
424
425                 if (!pp_data->startd) {
426                         pp_data->startd = 1;
427                         _tdm_exynos_pp_cmd(pp_data, IPP_CTRL_PLAY);
428                 } else
429                         _tdm_exynos_pp_cmd(pp_data, IPP_CTRL_RESUME);
430         }
431
432         return TDM_ERROR_NONE;
433 }
434
435 tdm_error
436 exynos_pp_set_done_handler(tdm_pp *pp, tdm_pp_done_handler func,
437                                                                   void *user_data)
438 {
439         tdm_exynos_pp_data *pp_data = pp;
440
441         RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
442         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
443
444         pp_data->done_func = func;
445         pp_data->done_user_data = user_data;
446
447         return TDM_ERROR_NONE;
448 }