5 #include "tdm_exynos.h"
7 typedef struct _tdm_exynos_pp_buffer {
12 struct list_head link;
13 } tdm_exynos_pp_buffer;
15 typedef struct _tdm_exynos_pp_data {
16 tdm_exynos_data *exynos_data;
23 struct list_head pending_buffer_list;
24 struct list_head buffer_list;
26 tdm_pp_done_handler done_func;
32 struct list_head link;
36 static tbm_format pp_formats[] = {
45 #ifdef HAVE_TILED_FORMAT
50 #define NUM_PP_FORMAT (sizeof(pp_formats) / sizeof(pp_formats[0]))
52 static int pp_list_init;
53 static struct list_head pp_list;
56 _get_index(tdm_exynos_pp_data *pp_data)
58 tdm_exynos_pp_buffer *buffer = NULL;
63 LIST_FOR_EACH_ENTRY(buffer, &pp_data->pending_buffer_list, link) {
64 if (ret == buffer->index) {
70 LIST_FOR_EACH_ENTRY(buffer, &pp_data->buffer_list, link) {
71 if (ret == buffer->index) {
85 _tdm_exynos_pp_set(tdm_exynos_pp_data *pp_data)
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;
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;
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);
119 ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY, &property);
121 TDM_ERR("failed: %m");
122 return TDM_ERROR_OPERATION_FAILED;
125 TDM_DBG("success. prop_id(%d) ", property.prop_id);
126 pp_data->prop_id = property.prop_id;
127 return TDM_ERROR_NONE;
131 _tdm_exynos_pp_queue(tdm_exynos_pp_data *pp_data, tdm_exynos_pp_buffer *buffer,
132 enum drm_exynos_ipp_buf_type type)
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;
139 buf.prop_id = pp_data->prop_id;
140 buf.ops_id = EXYNOS_DRM_OPS_SRC;
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;
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]);
154 ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, &buf);
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;
162 buf.prop_id = pp_data->prop_id;
163 buf.ops_id = EXYNOS_DRM_OPS_DST;
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;
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]);
177 ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, &buf);
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;
184 TDM_DBG("success. prop_id(%d)", buf.prop_id);
186 return TDM_ERROR_NONE;
190 _tdm_exynos_pp_cmd(tdm_exynos_pp_data *pp_data, enum drm_exynos_ipp_ctrl cmd)
192 tdm_exynos_data *exynos_data = pp_data->exynos_data;
193 struct drm_exynos_ipp_cmd_ctrl ctrl;
196 ctrl.prop_id = pp_data->prop_id;
199 TDM_DBG("prop_id(%d) ctrl(%d). ", ctrl.prop_id, ctrl.ctrl);
201 ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_CMD_CTRL, &ctrl);
203 TDM_ERR("failed. prop_id(%d) ctrl(%d). %m", ctrl.prop_id, ctrl.ctrl);
204 return TDM_ERROR_OPERATION_FAILED;
207 TDM_DBG("success. prop_id(%d) ", ctrl.prop_id);
209 return TDM_ERROR_NONE;
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)
216 tdm_exynos_pp_handler(prop_id, buf_idx, tv_sec, tv_usec, user_data);
220 tdm_exynos_pp_handler(unsigned int prop_id, unsigned int *buf_idx,
221 unsigned int tv_sec, unsigned int tv_usec, void *data)
223 tdm_exynos_pp_data *found = NULL, *pp_data = data;
224 tdm_exynos_pp_buffer *b = NULL, *bb = NULL, *dequeued_buffer = NULL;
226 if (!pp_data || !buf_idx) {
227 TDM_ERR("invalid params");
231 LIST_FOR_EACH_ENTRY(found, &pp_list, link) {
232 if (found == pp_data)
238 TDM_DBG("pp_data(%p) index(%d, %d)", pp_data, buf_idx[0], buf_idx[1]);
240 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->buffer_list, link) {
241 if (buf_idx[0] == b->index) {
243 LIST_DEL(&dequeued_buffer->link);
244 TDM_DBG("dequeued: %d", dequeued_buffer->index);
249 if (!dequeued_buffer) {
250 TDM_ERR("not found buffer index: %d", buf_idx[0]);
254 if (!pp_data->first_event) {
255 TDM_DBG("pp(%p) got a first event. ", pp_data);
256 pp_data->first_event = 1;
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);
268 tdm_exynos_pp_get_capability(tdm_exynos_data *exynos_data, tdm_caps_pp *caps)
273 TDM_ERR("invalid params");
274 return TDM_ERROR_INVALID_PARAMETER;
277 caps->capabilities = TDM_PP_CAPABILITY_ASYNC;
279 caps->format_count = NUM_PP_FORMAT;
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;
287 for (i = 0; i < caps->format_count; i++)
288 caps->formats[i] = pp_formats[i];
292 caps->max_w = -1; /* not defined */
294 caps->preferred_align = 16;
296 caps->max_attach_count = -1;
298 return TDM_ERROR_NONE;
302 tdm_exynos_pp_create(tdm_exynos_data *exynos_data, tdm_error *error)
304 tdm_exynos_pp_data *pp_data = calloc(1, sizeof(tdm_exynos_pp_data));
306 TDM_ERR("alloc failed");
308 *error = TDM_ERROR_OUT_OF_MEMORY;
312 pp_data->exynos_data = exynos_data;
314 LIST_INITHEAD(&pp_data->pending_buffer_list);
315 LIST_INITHEAD(&pp_data->buffer_list);
319 LIST_INITHEAD(&pp_list);
321 LIST_ADDTAIL(&pp_data->link, &pp_list);
327 exynos_pp_destroy(tdm_pp *pp)
329 tdm_exynos_pp_data *pp_data = pp;
330 tdm_exynos_pp_buffer *b = NULL, *bb = NULL;
335 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
340 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->buffer_list, link) {
342 _tdm_exynos_pp_queue(pp_data, b, IPP_BUF_DEQUEUE);
346 if (pp_data->prop_id)
347 _tdm_exynos_pp_cmd(pp_data, IPP_CTRL_STOP);
349 LIST_DEL(&pp_data->link);
355 exynos_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
357 tdm_exynos_pp_data *pp_data = pp;
359 RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
360 RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
363 TDM_ERR("not support sync mode currently");
364 return TDM_ERROR_INVALID_PARAMETER;
367 pp_data->info = *info;
368 pp_data->info_changed = 1;
370 return TDM_ERROR_NONE;
374 exynos_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
376 tdm_exynos_pp_data *pp_data = pp;
377 tdm_exynos_pp_buffer *buffer;
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);
383 buffer = calloc(1, sizeof(tdm_exynos_pp_buffer));
385 TDM_ERR("alloc failed");
386 return TDM_ERROR_NONE;
389 LIST_ADDTAIL(&buffer->link, &pp_data->pending_buffer_list);
390 buffer->index = _get_index(pp_data);
394 return TDM_ERROR_NONE;
398 exynos_pp_commit(tdm_pp *pp)
400 tdm_exynos_pp_data *pp_data = pp;
401 tdm_exynos_pp_buffer *b = NULL, *bb = NULL;
404 RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
406 if (pp_data->info_changed) {
408 _tdm_exynos_pp_cmd(pp_data, IPP_CTRL_PAUSE);
410 ret = _tdm_exynos_pp_set(pp_data);
412 return TDM_ERROR_OPERATION_FAILED;
415 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, 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);
422 if (pp_data->info_changed) {
423 pp_data->info_changed = 0;
425 if (!pp_data->startd) {
427 _tdm_exynos_pp_cmd(pp_data, IPP_CTRL_PLAY);
429 _tdm_exynos_pp_cmd(pp_data, IPP_CTRL_RESUME);
432 return TDM_ERROR_NONE;
436 exynos_pp_set_done_handler(tdm_pp *pp, tdm_pp_done_handler func,
439 tdm_exynos_pp_data *pp_data = pp;
441 RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
442 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
444 pp_data->done_func = func;
445 pp_data->done_user_data = user_data;
447 return TDM_ERROR_NONE;