libtdm-exynos: seperate ippv1 and ippv2 54/174254/6
authorBoram Park <boram1288.park@samsung.com>
Thu, 29 Mar 2018 08:59:49 +0000 (17:59 +0900)
committerBoram Park <boram1288.park@samsung.com>
Fri, 30 Mar 2018 04:23:31 +0000 (13:23 +0900)
Change-Id: I89dd7c900d76f036009acb7fb1f72a8f01d3747c

src/Makefile.am
src/tdm_exynos.c
src/tdm_exynos.h
src/tdm_exynos_capture_legacy.c [new file with mode: 0644]
src/tdm_exynos_capture_legacy.h [new file with mode: 0644]
src/tdm_exynos_display.c
src/tdm_exynos_output.c
src/tdm_exynos_pp_legacy.c [new file with mode: 0644]
src/tdm_exynos_pp_legacy.h [new file with mode: 0644]
src/tdm_exynos_types.h

index 69ea107b0f91949e7f70c05b2e934c716f402919..2f9a333ec08c4bf953ca656d0a385b121c2ba437 100644 (file)
@@ -15,4 +15,6 @@ libtdm_exynos_la_SOURCES = \
        tdm_exynos_window.c \
        tdm_exynos_pp.c \
        tdm_exynos_capture.c \
+       tdm_exynos_pp_legacy.c \
+       tdm_exynos_capture_legacy.c \
        tdm_exynos.c
index 85c0be207467fb1eef76d9ecf8ea75be4a58ce77..4dbd4e499c4c37ffb6e2c1fa18e02be34cb3e069 100644 (file)
@@ -186,6 +186,28 @@ close_l:
        return fd;
 }
 
+static int
+_tdm_exynos_drm_user_handler_legacy(struct drm_event *event)
+{
+       struct drm_exynos_ipp_event *ipp;
+
+       if (event->type != DRM_EXYNOS_IPP_EVENT)
+               return -1;
+
+       TDM_DBG("got ipp event");
+
+       ipp = (struct drm_exynos_ipp_event *)event;
+
+       if (tdm_exynos_capture_legacy_find_prop_id(ipp->prop_id))
+               tdm_exynos_capture_legacy_stream_pp_handler(ipp->prop_id, ipp->buf_id, ipp->tv_sec, ipp->tv_usec,
+                                                                                        (void *)(unsigned long)ipp->user_data);
+       else
+               tdm_exynos_pp_legacy_handler(ipp->prop_id, ipp->buf_id, ipp->tv_sec, ipp->tv_usec,
+                                                         (void *)(unsigned long)ipp->user_data);
+
+       return 0;
+}
+
 static int
 _tdm_exynos_drm_user_handler(struct drm_event *event)
 {
@@ -213,7 +235,10 @@ tdm_exynos_deinit(tdm_backend_data *bdata)
        _tdm_exynos_udev_deinit(exynos_data);
 #endif
 
-       drmRemoveUserHandler(exynos_data->drm_fd, _tdm_exynos_drm_user_handler);
+       if (exynos_data->use_ippv2)
+               drmRemoveUserHandler(exynos_data->drm_fd, _tdm_exynos_drm_user_handler);
+       else
+               drmRemoveUserHandler(exynos_data->drm_fd, _tdm_exynos_drm_user_handler_legacy);
 
        tdm_exynos_display_destroy_output_list(exynos_data);
 
@@ -239,6 +264,7 @@ tdm_exynos_init(tdm_display *dpy, tdm_error *error)
        tdm_func_capture exynos_func_capture;
        tdm_error ret;
        const char *value;
+       drmVersionPtr drm_version;
 
        value = (const char*)getenv("SCREEN_PREROTATION_HINT");
        if (value) {
@@ -269,6 +295,44 @@ tdm_exynos_init(tdm_display *dpy, tdm_error *error)
                return NULL;
        }
 
+       exynos_data->dpy = dpy;
+
+       /* The drm master fd can be opened by a tbm backend module in
+        * tbm_bufmgr_init() time. In this case, we just get it from tbm.
+        */
+       exynos_data->drm_fd = tbm_drm_helper_get_master_fd();
+       if (exynos_data->drm_fd < 0) {
+               exynos_data->drm_fd = _tdm_exynos_open_drm();
+
+               if (exynos_data->drm_fd < 0) {
+                       ret = TDM_ERROR_OPERATION_FAILED;
+                       goto failed;
+               }
+
+               tbm_drm_helper_set_tbm_master_fd(exynos_data->drm_fd);
+       }
+
+       TDM_INFO("master fd(%d)", exynos_data->drm_fd);
+
+#ifdef HAVE_UDEV
+       _tdm_exynos_udev_init(exynos_data);
+#endif
+
+       drm_version = drmGetVersion(exynos_data->drm_fd);
+       if (!drm_version) {
+               TDM_ERR("no drm version: %m");
+               ret = TDM_ERROR_OPERATION_FAILED;
+               goto failed;
+       } else {
+               TDM_INFO("drm version: %d.%d.%d",
+                                drm_version->version_major,
+                                drm_version->version_minor,
+                                drm_version->version_patchlevel);
+               if (drm_version->version_major > 1 ||
+                       (drm_version->version_major == 1 && drm_version->version_minor >= 1))
+                       exynos_data->use_ippv2 = 1;
+       }
+
        value = getenv("TDM_HWC");
        if (value)
                exynos_data->hwc_mode = strtol(value, NULL, 10);
@@ -344,18 +408,34 @@ tdm_exynos_init(tdm_display *dpy, tdm_error *error)
        exynos_func_layer.layer_unset_buffer = exynos_layer_unset_buffer;
 
        memset(&exynos_func_pp, 0, sizeof(exynos_func_pp));
-       exynos_func_pp.pp_destroy = exynos_pp_destroy;
-       exynos_func_pp.pp_set_info = exynos_pp_set_info;
-       exynos_func_pp.pp_attach = exynos_pp_attach;
-       exynos_func_pp.pp_commit = exynos_pp_commit;
-       exynos_func_pp.pp_set_done_handler = exynos_pp_set_done_handler;
+       if (exynos_data->use_ippv2) {
+               exynos_func_pp.pp_destroy = exynos_pp_destroy;
+               exynos_func_pp.pp_set_info = exynos_pp_set_info;
+               exynos_func_pp.pp_attach = exynos_pp_attach;
+               exynos_func_pp.pp_commit = exynos_pp_commit;
+               exynos_func_pp.pp_set_done_handler = exynos_pp_set_done_handler;
+       } else {
+               exynos_func_pp.pp_destroy = exynos_pp_legacy_destroy;
+               exynos_func_pp.pp_set_info = exynos_pp_legacy_set_info;
+               exynos_func_pp.pp_attach = exynos_pp_legacy_attach;
+               exynos_func_pp.pp_commit = exynos_pp_legacy_commit;
+               exynos_func_pp.pp_set_done_handler = exynos_pp_legacy_set_done_handler;
+       }
 
        memset(&exynos_func_capture, 0, sizeof(exynos_func_capture));
-       exynos_func_capture.capture_destroy = exynos_capture_destroy;
-       exynos_func_capture.capture_set_info = exynos_capture_set_info;
-       exynos_func_capture.capture_attach = exynos_capture_attach;
-       exynos_func_capture.capture_commit = exynos_capture_commit;
-       exynos_func_capture.capture_set_done_handler = exynos_capture_set_done_handler;
+       if (exynos_data->use_ippv2) {
+               exynos_func_capture.capture_destroy = exynos_capture_destroy;
+               exynos_func_capture.capture_set_info = exynos_capture_set_info;
+               exynos_func_capture.capture_attach = exynos_capture_attach;
+               exynos_func_capture.capture_commit = exynos_capture_commit;
+               exynos_func_capture.capture_set_done_handler = exynos_capture_set_done_handler;
+       } else {
+               exynos_func_capture.capture_destroy = exynos_capture_legacy_destroy;
+               exynos_func_capture.capture_set_info = exynos_capture_legacy_set_info;
+               exynos_func_capture.capture_attach = exynos_capture_legacy_attach;
+               exynos_func_capture.capture_commit = exynos_capture_legacy_commit;
+               exynos_func_capture.capture_set_done_handler = exynos_capture_legacy_set_done_handler;
+       }
 
        ret = tdm_backend_register_func_display(dpy, &exynos_func_display);
        if (ret != TDM_ERROR_NONE)
@@ -383,30 +463,10 @@ tdm_exynos_init(tdm_display *dpy, tdm_error *error)
        if (ret != TDM_ERROR_NONE)
                goto failed;
 
-       exynos_data->dpy = dpy;
-
-       /* The drm master fd can be opened by a tbm backend module in
-        * tbm_bufmgr_init() time. In this case, we just get it from tbm.
-        */
-       exynos_data->drm_fd = tbm_drm_helper_get_master_fd();
-       if (exynos_data->drm_fd < 0) {
-               exynos_data->drm_fd = _tdm_exynos_open_drm();
-
-               if (exynos_data->drm_fd < 0) {
-                       ret = TDM_ERROR_OPERATION_FAILED;
-                       goto failed;
-               }
-
-               tbm_drm_helper_set_tbm_master_fd(exynos_data->drm_fd);
-       }
-
-       TDM_INFO("master fd(%d)", exynos_data->drm_fd);
-
-#ifdef HAVE_UDEV
-       _tdm_exynos_udev_init(exynos_data);
-#endif
-
-       drmAddUserHandler(exynos_data->drm_fd, _tdm_exynos_drm_user_handler);
+       if (exynos_data->use_ippv2)
+               drmAddUserHandler(exynos_data->drm_fd, _tdm_exynos_drm_user_handler);
+       else
+               drmAddUserHandler(exynos_data->drm_fd, _tdm_exynos_drm_user_handler_legacy);
 
        if (drmSetClientCap(exynos_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0)
                TDM_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
@@ -442,7 +502,9 @@ tdm_exynos_init(tdm_display *dpy, tdm_error *error)
        } else
                TDM_DBG("plane doesn't have zpos info");
 
-       ret = tdm_exynos_pp_init(exynos_data);
+       if (exynos_data->use_ippv2)
+               ret = tdm_exynos_pp_init(exynos_data);
+
        if (ret != TDM_ERROR_NONE)
                goto failed;
 
index 75ca1b27f17b92ed5173b144441ed11b5c5cd881..2547665a2fdcbd3465ab96133ba4200ceadb68e2 100644 (file)
@@ -30,6 +30,8 @@
 #include "tdm_exynos_output.h"
 #include "tdm_exynos_layer.h"
 #include "tdm_exynos_window.h"
+#include "tdm_exynos_pp_legacy.h"
+#include "tdm_exynos_capture_legacy.h"
 #include "tdm_exynos_pp.h"
 #include "tdm_exynos_capture.h"
 
@@ -96,6 +98,17 @@ tdm_error    exynos_hwc_window_video_get_capability(tdm_hwc_window *hwc_window,
 tdm_error    exynos_hwc_window_video_get_available_properties(tdm_hwc_window *hwc_window, const tdm_prop **props, int *count);
 tdm_error    exynos_hwc_window_video_get_property(tdm_hwc_window *hwc_window, unsigned int id, tdm_value *value);
 tdm_error    exynos_hwc_window_video_set_property(tdm_hwc_window *hwc_window, unsigned int id, tdm_value value);
+void         exynos_pp_legacy_destroy(tdm_pp *pp);
+tdm_error    exynos_pp_legacy_set_info(tdm_pp *pp, tdm_info_pp *info);
+tdm_error    exynos_pp_legacy_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst);
+tdm_error    exynos_pp_legacy_commit(tdm_pp *pp);
+tdm_error    exynos_pp_legacy_set_done_handler(tdm_pp *pp, tdm_pp_done_handler func, void *user_data);
+void         exynos_capture_legacy_destroy(tdm_capture *capture);
+tdm_error    exynos_capture_legacy_set_info(tdm_capture *capture, tdm_info_capture *info);
+tdm_error    exynos_capture_legacy_attach(tdm_capture *capture, tbm_surface_h buffer);
+tdm_error    exynos_capture_legacy_commit(tdm_capture *capture);
+tdm_error    exynos_capture_legacy_set_done_handler(tdm_pp *pp, tdm_capture_done_handler func, void *user_data);
+
 void         exynos_pp_destroy(tdm_pp *pp);
 tdm_error    exynos_pp_set_info(tdm_pp *pp, tdm_info_pp *info);
 tdm_error    exynos_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst);
diff --git a/src/tdm_exynos_capture_legacy.c b/src/tdm_exynos_capture_legacy.c
new file mode 100644 (file)
index 0000000..0fc4651
--- /dev/null
@@ -0,0 +1,742 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_exynos.h"
+
+typedef struct _tdm_exynos_capture_legacy_buffer {
+       int index;
+       tbm_surface_h ui_buffer;
+       tbm_surface_h buffer;
+       struct list_head link;
+} tdm_exynos_capture_legacy_buffer;
+
+typedef struct _tdm_exynos_pp_legacy_data {
+       tdm_exynos_data *exynos_data;
+
+       tdm_exynos_output_data *output_data;
+
+       tdm_info_capture info;
+       int info_changed;
+
+       struct list_head pending_buffer_list;
+       struct list_head buffer_list;
+
+       struct {
+               tdm_event_loop_source *timer_source;
+
+               unsigned int prop_id;
+
+               int startd;
+               int first_event;
+       } stream;
+
+       tdm_capture_done_handler done_func;
+       void *done_user_data;
+
+       struct list_head link;
+} tdm_exynos_capture_legacy_data;
+
+static tbm_format capture_formats[] = {
+       TBM_FORMAT_ARGB8888,
+       TBM_FORMAT_XRGB8888,
+};
+
+#define NUM_CAPTURE_FORMAT   (sizeof(capture_formats) / sizeof(capture_formats[0]))
+
+static int capture_list_init;
+static struct list_head capture_list;
+
+int
+tdm_exynos_capture_legacy_find_prop_id(unsigned int prop_id)
+{
+       tdm_exynos_capture_legacy_data *capture_data = NULL;
+
+       if (!capture_list_init) {
+               capture_list_init = 1;
+               LIST_INITHEAD(&capture_list);
+       }
+
+       if (LIST_IS_EMPTY(&capture_list))
+               return 0;
+
+       LIST_FOR_EACH_ENTRY(capture_data, &capture_list, link) {
+               if (capture_data->stream.prop_id == prop_id)
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int
+_get_index(tdm_exynos_capture_legacy_data *capture_data)
+{
+       tdm_exynos_capture_legacy_buffer *b = NULL;
+       int ret = 0;
+
+       while (1) {
+               int found = 0;
+               LIST_FOR_EACH_ENTRY(b, &capture_data->pending_buffer_list, link) {
+                       if (ret == b->index) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found)
+                       LIST_FOR_EACH_ENTRY(b, &capture_data->buffer_list, link) {
+                       if (ret == b->index) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found)
+                       break;
+               ret++;
+       }
+
+       return ret;
+}
+
+static tdm_error
+_tdm_exynos_capture_legacy_stream_pp_set(tdm_exynos_capture_legacy_data *capture_data, tbm_surface_h ui_buffer)
+{
+       tdm_exynos_data *exynos_data = capture_data->exynos_data;
+       tdm_info_capture *info = &capture_data->info;
+       struct drm_exynos_ipp_property property;
+       unsigned int width, height, stride = 0;
+       int ret = 0;
+
+       tbm_surface_internal_get_plane_data(ui_buffer, 0, NULL, NULL, &stride);
+       width = tbm_surface_get_width(ui_buffer);
+       height = tbm_surface_get_height(ui_buffer);
+
+       CLEAR(property);
+
+       property.config[0].ops_id = EXYNOS_DRM_OPS_SRC;
+       property.config[0].fmt = tdm_exynos_format_to_drm_format(tbm_surface_get_format(ui_buffer));
+       property.config[0].sz.hsize = stride >> 2;
+       property.config[0].sz.vsize = height;
+       property.config[0].pos.w = width;
+       property.config[0].pos.h = height;
+
+       property.config[1].ops_id = EXYNOS_DRM_OPS_DST;
+       property.config[1].degree = info->transform % 4;
+       property.config[1].flip = (info->transform > 3) ? EXYNOS_DRM_FLIP_HORIZONTAL : 0;
+       property.config[1].fmt = tdm_exynos_format_to_drm_format(info->dst_config.format);
+       memcpy(&property.config[1].sz, &info->dst_config.size, sizeof(tdm_size));
+       memcpy(&property.config[1].pos, &info->dst_config.pos, sizeof(tdm_pos));
+       property.cmd = IPP_CMD_M2M;
+       property.prop_id = capture_data->stream.prop_id;
+
+       TDM_DBG("src : flip(%x) deg(%d) fmt(%c%c%c%c) sz(%dx%d) pos(%d,%d %dx%d)  ",
+                       property.config[0].flip, property.config[0].degree,
+                       FOURCC_STR(property.config[0].fmt),
+                       property.config[0].sz.hsize, property.config[0].sz.vsize,
+                       property.config[0].pos.x, property.config[0].pos.y, property.config[0].pos.w,
+                       property.config[0].pos.h);
+       TDM_DBG("dst : flip(%x) deg(%d) fmt(%c%c%c%c) sz(%dx%d) pos(%d,%d %dx%d)  ",
+                       property.config[1].flip, property.config[1].degree,
+                       FOURCC_STR(property.config[1].fmt),
+                       property.config[1].sz.hsize, property.config[1].sz.vsize,
+                       property.config[1].pos.x, property.config[1].pos.y, property.config[1].pos.w,
+                       property.config[1].pos.h);
+
+       ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY, &property);
+       if (ret) {
+               TDM_ERR("failed: %m");
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       TDM_DBG("success. prop_id(%d) ", property.prop_id);
+       capture_data->stream.prop_id = property.prop_id;
+       return TDM_ERROR_NONE;
+}
+
+static tdm_error
+_tdm_exynos_capture_legacy_stream_pp_queue(tdm_exynos_capture_legacy_data *capture_data,
+                                                                       tdm_exynos_capture_legacy_buffer *b,
+                                                                       enum drm_exynos_ipp_buf_type type)
+{
+       tdm_exynos_data *exynos_data = capture_data->exynos_data;
+       struct drm_exynos_ipp_queue_buf buf;
+       int i, bo_num, ret = 0;
+
+       CLEAR(buf);
+       buf.prop_id = capture_data->stream.prop_id;
+       buf.ops_id = EXYNOS_DRM_OPS_SRC;
+       buf.buf_type = type;
+       buf.buf_id = b->index;
+       buf.user_data = (__u64)(uintptr_t)capture_data;
+       bo_num = tbm_surface_internal_get_num_bos(b->ui_buffer);
+       for (i = 0; i < EXYNOS_DRM_PLANAR_MAX && i < bo_num; i++) {
+               tbm_bo bo = tbm_surface_internal_get_bo(b->ui_buffer, i);
+               buf.handle[i] = (__u32)tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+       }
+
+       TDM_DBG("prop_id(%d) ops_id(%d) ctrl(%d) id(%d) handles(%x %x %x). ",
+                       buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id,
+                       buf.handle[0], buf.handle[1], buf.handle[2]);
+
+       ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, &buf);
+       if (ret) {
+               TDM_ERR("src failed. prop_id(%d) op(%d) buf(%d) id(%d). %m",
+                               buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id);
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       CLEAR(buf);
+       buf.prop_id = capture_data->stream.prop_id;
+       buf.ops_id = EXYNOS_DRM_OPS_DST;
+       buf.buf_type = type;
+       buf.buf_id = b->index;
+       buf.user_data = (__u64)(uintptr_t)capture_data;
+       bo_num = tbm_surface_internal_get_num_bos(b->buffer);
+       for (i = 0; i < EXYNOS_DRM_PLANAR_MAX && i < bo_num; i++) {
+               tbm_bo bo = tbm_surface_internal_get_bo(b->buffer, i);
+               buf.handle[i] = (__u32)tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+       }
+
+       TDM_DBG("prop_id(%d) ops_id(%d) ctrl(%d) id(%d) handles(%x %x %x). ",
+                       buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id,
+                       buf.handle[0], buf.handle[1], buf.handle[2]);
+
+       ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, &buf);
+       if (ret) {
+               TDM_ERR("dst failed. prop_id(%d) op(%d) buf(%d) id(%d). %m",
+                               buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id);
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       TDM_DBG("success. prop_id(%d)", buf.prop_id);
+
+       return TDM_ERROR_NONE;
+}
+
+static tdm_error
+_tdm_exynos_capture_legacy_stream_pp_cmd(tdm_exynos_capture_legacy_data *capture_data, enum drm_exynos_ipp_ctrl cmd)
+{
+       tdm_exynos_data *exynos_data = capture_data->exynos_data;
+       struct drm_exynos_ipp_cmd_ctrl ctrl;
+       int ret = 0;
+
+       ctrl.prop_id = capture_data->stream.prop_id;
+       ctrl.ctrl = cmd;
+
+       TDM_DBG("prop_id(%d) ctrl(%d). ", ctrl.prop_id, ctrl.ctrl);
+
+       ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_CMD_CTRL, &ctrl);
+       if (ret) {
+               TDM_ERR("failed. prop_id(%d) ctrl(%d). %m", ctrl.prop_id, ctrl.ctrl);
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       TDM_DBG("success. prop_id(%d) ", ctrl.prop_id);
+
+       return TDM_ERROR_NONE;
+}
+
+void
+tdm_exynos_capture_legacy_stream_pp_handler(unsigned int prop_id, unsigned int *buf_idx,
+                                                                        unsigned int tv_sec, unsigned int tv_usec, void *data)
+{
+       tdm_exynos_capture_legacy_data *found = NULL, *d = NULL, *capture_data = data;
+       tdm_exynos_capture_legacy_buffer *b = NULL, *bb = NULL, *dequeued_buffer = NULL;
+
+       if (!capture_data || !buf_idx) {
+               TDM_ERR("invalid params");
+               return;
+       }
+
+       LIST_FOR_EACH_ENTRY(d, &capture_list, link) {
+               if (d == capture_data) {
+                       found = d;
+                       break;
+               }
+       }
+       if (!found)
+               return;
+
+       TDM_DBG("capture_data(%p) index(%d, %d)", capture_data, buf_idx[0], buf_idx[1]);
+
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &capture_data->buffer_list, link) {
+               if (buf_idx[0] == b->index) {
+                       dequeued_buffer = b;
+                       LIST_DEL(&dequeued_buffer->link);
+                       TDM_DBG("dequeued: %d", dequeued_buffer->index);
+                       break;
+               }
+       }
+
+       if (!dequeued_buffer) {
+               TDM_ERR("not found buffer index: %d", buf_idx[0]);
+               return;
+       }
+
+       if (!capture_data->stream.first_event) {
+               TDM_DBG("capture(%p) got a first event. ", capture_data);
+               capture_data->stream.first_event = 1;
+       }
+
+       if (capture_data->done_func)
+               capture_data->done_func(capture_data,
+                                                               dequeued_buffer->buffer,
+                                                               capture_data->done_user_data);
+
+       tdm_buffer_unref_backend(dequeued_buffer->ui_buffer);
+
+       free(dequeued_buffer);
+}
+
+static tdm_error
+_tdm_exynos_capture_legacy_stream_timer_handler(void *user_data)
+{
+       tdm_exynos_capture_legacy_data *capture_data = user_data;
+       unsigned int ms = 1000 / capture_data->info.frequency;
+       tdm_exynos_capture_legacy_buffer *b = NULL;
+       tbm_surface_h ui_buffer = NULL;
+       tdm_error ret;
+
+       tdm_event_loop_source_timer_update(capture_data->stream.timer_source, ms);
+
+       if (capture_data->output_data->primary_layer->display_buffer)
+               ui_buffer = capture_data->output_data->primary_layer->display_buffer->buffer;
+
+       if (!ui_buffer)
+               return TDM_ERROR_NONE;
+
+       if (capture_data->info_changed) {
+               if (capture_data->stream.startd)
+                       _tdm_exynos_capture_legacy_stream_pp_cmd(capture_data, IPP_CTRL_PAUSE);
+
+               ret = _tdm_exynos_capture_legacy_stream_pp_set(capture_data, ui_buffer);
+               if (ret < 0)
+                       return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       b = LIST_FIRST_ENTRY(&capture_data->pending_buffer_list, tdm_exynos_capture_legacy_buffer, link);
+       RETURN_VAL_IF_FAIL(b != NULL, TDM_ERROR_OPERATION_FAILED);
+
+       LIST_DEL(&b->link);
+       b->ui_buffer = tdm_buffer_ref_backend(ui_buffer);
+       _tdm_exynos_capture_legacy_stream_pp_queue(capture_data, b, IPP_BUF_ENQUEUE);
+       TDM_DBG("queued: %d", b->index);
+       LIST_ADDTAIL(&b->link, &capture_data->buffer_list);
+
+       if (capture_data->info_changed) {
+               capture_data->info_changed = 0;
+
+               if (!capture_data->stream.startd) {
+                       capture_data->stream.startd = 1;
+                       _tdm_exynos_capture_legacy_stream_pp_cmd(capture_data, IPP_CTRL_PLAY);
+               } else
+                       _tdm_exynos_capture_legacy_stream_pp_cmd(capture_data, IPP_CTRL_RESUME);
+       }
+
+
+       return TDM_ERROR_NONE;
+}
+
+
+static tdm_error
+_tdm_exynos_capture_legacy_commit_stream(tdm_exynos_capture_legacy_data *capture_data)
+{
+       unsigned int ms = 1000 / capture_data->info.frequency;
+
+       if (!capture_data->stream.timer_source) {
+               capture_data->stream.timer_source =
+                       tdm_event_loop_add_timer_handler(capture_data->exynos_data->dpy,
+                                                                                        _tdm_exynos_capture_legacy_stream_timer_handler,
+                                                                                        capture_data, NULL);
+                       RETURN_VAL_IF_FAIL(capture_data->stream.timer_source != NULL, TDM_ERROR_OUT_OF_MEMORY);
+       }
+
+       tdm_event_loop_source_timer_update(capture_data->stream.timer_source, ms);
+
+       return TDM_ERROR_NONE;
+}
+
+static void
+_tdm_exynos_capture_legacy_oneshot_center_rect(int src_w, int src_h, int dst_w, int dst_h, tdm_pos *fit)
+{
+       float rw = (float)src_w / dst_w;
+       float rh = (float)src_h / dst_h;
+
+       fit->x = fit->y = 0;
+
+       if (rw > rh) {
+               fit->w = dst_w;
+               fit->h = src_h / rw;
+               fit->y = (dst_h - fit->h) / 2;
+       } else if (rw < rh) {
+               fit->w = src_w / rh;
+               fit->h = dst_h;
+               fit->x = (dst_w - fit->w) / 2;
+       } else {
+               fit->w = dst_w;
+               fit->h = dst_h;
+       }
+
+       fit->x = fit->x & ~0x1;
+}
+
+static void
+_tdm_exynos_capture_legacy_oneshot_rect_scale(int src_w, int src_h, int dst_w, int dst_h, tdm_pos *scale)
+{
+       float ratio;
+       tdm_pos center = {0,};
+
+       _tdm_exynos_capture_legacy_oneshot_center_rect(src_w, src_h, dst_w, dst_h, &center);
+
+       ratio = (float)center.w / src_w;
+       scale->x = scale->x * ratio + center.x;
+       scale->y = scale->y * ratio + center.y;
+       scale->w = scale->w * ratio;
+       scale->h = scale->h * ratio;
+}
+
+static void
+_tdm_exynos_capture_legacy_oneshot_get_showing_rect(tdm_pos *out_rect, tdm_pos *dst_rect, tdm_pos *showing_rect)
+{
+       showing_rect->x = dst_rect->x;
+       showing_rect->y = dst_rect->y;
+
+       if (dst_rect->x >= out_rect->w)
+               showing_rect->w = 0;
+       else if (dst_rect->x + dst_rect->w > out_rect->w)
+               showing_rect->w = out_rect->w - dst_rect->x;
+       else
+               showing_rect->w = dst_rect->w;
+
+       if (dst_rect->y >= out_rect->h)
+               showing_rect->h = 0;
+       else if (dst_rect->y + dst_rect->h > out_rect->h)
+               showing_rect->h = out_rect->h - dst_rect->y;
+       else
+               showing_rect->h = dst_rect->h;
+}
+
+static void
+_tdm_exynos_capture_legacy_oneshot_get_src_crop_info(tdm_exynos_capture_legacy_data *capture_data,
+                                                                                         tdm_exynos_layer_data *layer_data, tdm_pos *src_crop, tdm_pos *showing_rect)
+{
+       tdm_exynos_output_data *output_data = capture_data->output_data;
+       float ratio_x, ratio_y;
+       tdm_pos out_rect;
+       tdm_pos dst_rect;
+
+       out_rect.x = 0;
+       out_rect.y = 0;
+       out_rect.w = output_data->current_mode->hdisplay;
+       out_rect.h = output_data->current_mode->vdisplay;
+
+       dst_rect.x = layer_data->info.dst_pos.x;
+       dst_rect.y = layer_data->info.dst_pos.y;
+       dst_rect.w = layer_data->info.dst_pos.w;
+       dst_rect.h = layer_data->info.dst_pos.h;
+
+       _tdm_exynos_capture_legacy_oneshot_get_showing_rect(&out_rect, &dst_rect, showing_rect);
+
+       src_crop->x = layer_data->info.src_config.pos.x;
+       src_crop->y = layer_data->info.src_config.pos.y;
+
+       if (layer_data->info.transform % 2 == 0) {
+               ratio_x = (float)layer_data->info.src_config.pos.w / dst_rect.w;
+               ratio_y = (float)layer_data->info.src_config.pos.h / dst_rect.h;
+
+               src_crop->w = showing_rect->w * ratio_x;
+               src_crop->h = showing_rect->h * ratio_y;
+       } else {
+               ratio_x = (float)layer_data->info.src_config.pos.w / dst_rect.h;
+               ratio_y = (float)layer_data->info.src_config.pos.h / dst_rect.w;
+
+               src_crop->w = showing_rect->h * ratio_x;
+               src_crop->h = showing_rect->w * ratio_y;
+       }
+}
+
+static void
+_tdm_exynos_capture_legacy_oneshot_get_dst_crop_info(tdm_exynos_capture_legacy_data *capture_data, tdm_exynos_layer_data *layer_data,
+                                                                                         tdm_pos *dst_pos, tdm_pos *showing_pos, tdm_pos *dst_crop,
+                                                                                         tdm_transform transform)
+{
+       tdm_exynos_output_data *output_data = capture_data->output_data;
+
+       if (layer_data->info.src_config.pos.w == output_data->current_mode->hdisplay &&
+               layer_data->info.src_config.pos.h == output_data->current_mode->vdisplay &&
+               dst_pos->x == 0 && dst_pos->y == 0 &&
+               dst_pos->w == capture_data->info.dst_config.size.h &&
+               dst_pos->h == capture_data->info.dst_config.size.v) {
+               dst_crop->x = dst_pos->x;
+               dst_crop->y = dst_pos->y;
+               dst_crop->w = dst_pos->w;
+               dst_crop->h = dst_pos->h;
+       } else if ((output_data->current_mode->hdisplay == dst_pos->w) &&
+                          (output_data->current_mode->vdisplay == dst_pos->h) &&
+                          (showing_pos->w == dst_pos->w) && (showing_pos->h == dst_pos->h)) {
+               dst_crop->x = layer_data->info.dst_pos.x + dst_pos->x;
+               dst_crop->y = layer_data->info.dst_pos.y + dst_pos->y;
+               dst_crop->w = layer_data->info.dst_pos.w;
+               dst_crop->h = layer_data->info.dst_pos.h;
+       } else if (transform == TDM_TRANSFORM_NORMAL || transform == TDM_TRANSFORM_FLIPPED) {
+               dst_crop->x = showing_pos->x * dst_pos->w / output_data->current_mode->hdisplay + dst_pos->x;
+               dst_crop->y = showing_pos->y * dst_pos->h / output_data->current_mode->vdisplay + dst_pos->y;
+               dst_crop->w = showing_pos->w * dst_pos->w / output_data->current_mode->hdisplay;
+               dst_crop->h = showing_pos->h * dst_pos->h / output_data->current_mode->vdisplay;
+       } else if (transform == TDM_TRANSFORM_90 || transform == TDM_TRANSFORM_FLIPPED_90) {
+               dst_crop->x = (output_data->current_mode->vdisplay - showing_pos->y - showing_pos->h) *
+                                         dst_pos->w / output_data->current_mode->vdisplay + dst_pos->x;
+               dst_crop->y = showing_pos->x * dst_pos->h / output_data->current_mode->hdisplay + dst_pos->y;
+               dst_crop->w = showing_pos->h * dst_pos->w / output_data->current_mode->vdisplay;
+               dst_crop->h = showing_pos->w * dst_pos->h / output_data->current_mode->hdisplay;
+       } else if (transform == TDM_TRANSFORM_180 || transform == TDM_TRANSFORM_FLIPPED_180) {
+               dst_crop->x = (output_data->current_mode->hdisplay - showing_pos->x - showing_pos->w) *
+                                         dst_pos->w / output_data->current_mode->hdisplay + dst_pos->x;
+               dst_crop->y = (output_data->current_mode->vdisplay - showing_pos->y - showing_pos->h) *
+                                         dst_pos->h / output_data->current_mode->vdisplay + dst_pos->y;
+               dst_crop->w = showing_pos->w * dst_pos->w / output_data->current_mode->hdisplay;
+               dst_crop->h = showing_pos->h * dst_pos->h / output_data->current_mode->vdisplay;
+       } else if (transform == TDM_TRANSFORM_270 || transform == TDM_TRANSFORM_FLIPPED_270) {
+               dst_crop->x = showing_pos->y * dst_pos->w / output_data->current_mode->vdisplay + dst_pos->x;
+               dst_crop->y = (output_data->current_mode->hdisplay - showing_pos->x - showing_pos->w) *
+                                         dst_pos->h / output_data->current_mode->hdisplay + dst_pos->y;
+               dst_crop->w = showing_pos->h * dst_pos->w / output_data->current_mode->vdisplay;
+               dst_crop->h = showing_pos->w * dst_pos->h / output_data->current_mode->hdisplay;
+       } else {
+               dst_crop->x = dst_pos->x;
+               dst_crop->y = dst_pos->y;
+               dst_crop->w = dst_pos->w;
+               dst_crop->h = dst_pos->h;
+               TDM_ERR("oneshot: get_crop unknown case error");
+       }
+}
+
+static void
+_tdm_exynos_capture_legacy_oneshot_composite_layers_sw(tdm_exynos_capture_legacy_data *capture_data, tbm_surface_h buffer)
+{
+       tdm_exynos_output_data *output_data = capture_data->output_data;
+       tdm_exynos_layer_data *layer_data = NULL;
+       tbm_surface_info_s buf_info;
+       int err;
+
+       err = tbm_surface_get_info(buffer, &buf_info);
+       RETURN_IF_FAIL(err == TBM_SURFACE_ERROR_NONE);
+
+       LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
+               tbm_surface_h buf;
+               tdm_pos dst_pos;
+               tdm_pos showing_pos;
+               tdm_pos src_crop;
+               tdm_pos dst_crop;
+               tdm_transform transform = TDM_TRANSFORM_NORMAL;
+
+               if (!layer_data->display_buffer)
+                       continue;
+
+               buf = layer_data->display_buffer->buffer;
+
+               if (capture_data->info.dst_config.pos.w == 0 ||
+                       capture_data->info.dst_config.pos.h == 0) {
+                       dst_pos = layer_data->info.dst_pos;
+                       _tdm_exynos_capture_legacy_oneshot_rect_scale(output_data->current_mode->hdisplay,
+                                                                                                  output_data->current_mode->vdisplay,
+                                                                                                  buf_info.width, buf_info.height, &dst_pos);
+               } else {
+                       dst_pos = capture_data->info.dst_config.pos;
+                       transform = capture_data->info.transform;
+               }
+
+               _tdm_exynos_capture_legacy_oneshot_get_src_crop_info(capture_data, layer_data, &src_crop, &showing_pos);
+               _tdm_exynos_capture_legacy_oneshot_get_dst_crop_info(capture_data, layer_data, &dst_pos, &showing_pos, &dst_crop, transform);
+
+               TDM_DBG("oneshot convert buff: src_crop(%dx%d, %dx%d), dst_crop(%dx%d, %dx%d)\n",
+                               src_crop.x, src_crop.y, src_crop.w, src_crop.h,
+                               dst_crop.x, dst_crop.y, dst_crop.w, dst_crop.h);
+
+               tdm_helper_convert_buffer(buf, buffer,
+                                                                 &src_crop, &dst_crop, transform, 1);
+       }
+}
+
+static tdm_error
+_tdm_exynos_capture_legacy_commit_oneshot(tdm_exynos_capture_legacy_data *capture_data)
+{
+       tdm_exynos_capture_legacy_buffer *b = NULL, *bb = NULL;
+
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &capture_data->pending_buffer_list, link) {
+               LIST_DEL(&b->link);
+
+               /* TODO: need to improve the performance with hardware */
+               _tdm_exynos_capture_legacy_oneshot_composite_layers_sw(capture_data, b->buffer);
+
+               if (capture_data->done_func)
+                       capture_data->done_func(capture_data,
+                                                                       b->buffer,
+                                                                       capture_data->done_user_data);
+               free(b);
+       }
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+tdm_exynos_capture_legacy_get_capability(tdm_exynos_data *exynos_data, tdm_caps_capture *caps)
+{
+       int i;
+
+       if (!caps) {
+               TDM_ERR("invalid params");
+               return TDM_ERROR_INVALID_PARAMETER;
+       }
+
+       caps->capabilities = TDM_CAPTURE_CAPABILITY_OUTPUT|
+                                                TDM_CAPTURE_CAPABILITY_ONESHOT|
+                                                TDM_CAPTURE_CAPABILITY_STREAM;
+
+       caps->format_count = NUM_CAPTURE_FORMAT;
+       caps->formats = NULL;
+       if (NUM_CAPTURE_FORMAT) {
+               /* will be freed in frontend */
+               caps->formats = calloc(1, sizeof capture_formats);
+               if (!caps->formats) {
+                       TDM_ERR("alloc failed");
+                       return TDM_ERROR_OUT_OF_MEMORY;
+               }
+               for (i = 0; i < caps->format_count; i++)
+                       caps->formats[i] = capture_formats[i];
+       }
+
+       caps->min_w = 16;
+       caps->min_h = 8;
+       caps->preferred_align = 2;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_capture*
+tdm_exynos_capture_legacy_create_output(tdm_exynos_data *exynos_data, tdm_output *output, tdm_error *error)
+{
+       tdm_exynos_capture_legacy_data *capture_data = calloc(1, sizeof(tdm_exynos_capture_legacy_data));
+       if (!capture_data) {
+               TDM_ERR("alloc failed");
+               if (error)
+                       *error = TDM_ERROR_OUT_OF_MEMORY;
+               return NULL;
+       }
+
+       capture_data->exynos_data = exynos_data;
+       capture_data->output_data = output;
+
+       LIST_INITHEAD(&capture_data->pending_buffer_list);
+       LIST_INITHEAD(&capture_data->buffer_list);
+
+       if (!capture_list_init) {
+               capture_list_init = 1;
+               LIST_INITHEAD(&capture_list);
+       }
+       LIST_ADDTAIL(&capture_data->link, &capture_list);
+
+       TDM_DBG("capture(%p) create", capture_data);
+
+       return capture_data;
+}
+
+void
+exynos_capture_legacy_destroy(tdm_capture *capture)
+{
+       tdm_exynos_capture_legacy_data *capture_data = capture;
+       tdm_exynos_capture_legacy_buffer *b = NULL, *bb = NULL;
+
+       if (!capture_data)
+               return;
+
+       TDM_DBG("capture(%p) destroy", capture_data);
+
+       if (capture_data->stream.timer_source)
+               tdm_event_loop_source_remove(capture_data->stream.timer_source);
+
+       if (capture_data->stream.prop_id)
+               _tdm_exynos_capture_legacy_stream_pp_cmd(capture_data, IPP_CTRL_STOP);
+
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &capture_data->pending_buffer_list, link) {
+               LIST_DEL(&b->link);
+               free(b);
+       }
+
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &capture_data->buffer_list, link) {
+               LIST_DEL(&b->link);
+               tdm_buffer_unref_backend(b->ui_buffer);
+               _tdm_exynos_capture_legacy_stream_pp_queue(capture_data, b, IPP_BUF_DEQUEUE);
+               free(b);
+       }
+
+       LIST_DEL(&capture_data->link);
+
+       free(capture_data);
+}
+
+tdm_error
+exynos_capture_legacy_set_info(tdm_capture *capture, tdm_info_capture *info)
+{
+       tdm_exynos_capture_legacy_data *capture_data = capture;
+
+       RETURN_VAL_IF_FAIL(capture_data, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
+
+       capture_data->info = *info;
+       capture_data->info_changed = 1;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+exynos_capture_legacy_attach(tdm_capture *capture, tbm_surface_h buffer)
+{
+       tdm_exynos_capture_legacy_data *capture_data = capture;
+       tdm_exynos_capture_legacy_buffer *b;
+
+       RETURN_VAL_IF_FAIL(capture_data, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
+
+       b = calloc(1, sizeof(tdm_exynos_capture_legacy_buffer));
+       if (!b) {
+               TDM_ERR("alloc failed");
+               return TDM_ERROR_NONE;
+       }
+
+       LIST_ADDTAIL(&b->link, &capture_data->pending_buffer_list);
+
+       b->index = _get_index(capture_data);
+       b->buffer = buffer;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+exynos_capture_legacy_commit(tdm_capture *capture)
+{
+       tdm_exynos_capture_legacy_data *capture_data = capture;
+       tdm_error ret;
+
+       RETURN_VAL_IF_FAIL(capture_data, TDM_ERROR_INVALID_PARAMETER);
+
+       if (capture_data->info.type == TDM_CAPTURE_TYPE_ONESHOT)
+               ret = _tdm_exynos_capture_legacy_commit_oneshot(capture_data);
+       else
+               ret = _tdm_exynos_capture_legacy_commit_stream(capture_data);
+
+       return ret;
+}
+
+tdm_error
+exynos_capture_legacy_set_done_handler(tdm_capture *capture, tdm_capture_done_handler func, void *user_data)
+{
+       tdm_exynos_capture_legacy_data *capture_data = capture;
+
+       RETURN_VAL_IF_FAIL(capture_data, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
+
+       capture_data->done_func = func;
+       capture_data->done_user_data = user_data;
+
+       return TDM_ERROR_NONE;
+}
diff --git a/src/tdm_exynos_capture_legacy.h b/src/tdm_exynos_capture_legacy.h
new file mode 100644 (file)
index 0000000..dfcc01c
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _TDM_EXYNOS_CAPTURE_LEGACY_H_
+#define _TDM_EXYNOS_CAPTURE_LEGACY_H_
+
+#include "tdm_exynos.h"
+
+tdm_error    tdm_exynos_capture_legacy_get_capability(tdm_exynos_data *exynos_data, tdm_caps_capture *caps);
+tdm_pp*      tdm_exynos_capture_legacy_create_output(tdm_exynos_data *exynos_data, tdm_output *output, tdm_error *error);
+void         tdm_exynos_capture_legacy_stream_pp_handler(unsigned int prop_id, unsigned int *buf_idx,
+                                                                                                 unsigned int tv_sec, unsigned int tv_usec, void *data);
+int          tdm_exynos_capture_legacy_find_prop_id(unsigned int prop_id);
+
+#endif /* _TDM_EXYNOS_CAPTURE_LEGACY_H_ */
index d2a28061af1d786796be8f187a2fb3c4a44546b1..90b7232bebe339607d524c81ddc49cd41e5e9e17 100644 (file)
@@ -632,13 +632,21 @@ exynos_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps)
 tdm_error
 exynos_display_get_pp_capability(tdm_backend_data *bdata, tdm_caps_pp *caps)
 {
-       return tdm_exynos_pp_get_capability(bdata, caps);
+       tdm_exynos_data *exynos_data = bdata;
+       if (exynos_data->use_ippv2)
+               return tdm_exynos_pp_get_capability(bdata, caps);
+       else
+               return tdm_exynos_pp_legacy_get_capability(bdata, caps);
 }
 
 tdm_error
 exynos_display_get_capture_capability(tdm_backend_data *bdata, tdm_caps_capture *caps)
 {
-       return tdm_exynos_capture_get_capability(bdata, caps);
+       tdm_exynos_data *exynos_data = bdata;
+       if (exynos_data->use_ippv2)
+               return tdm_exynos_capture_get_capability(bdata, caps);
+       else
+               return tdm_exynos_capture_legacy_get_capability(bdata, caps);
 }
 
 tdm_output **
@@ -725,5 +733,8 @@ exynos_display_create_pp(tdm_backend_data *bdata, tdm_error *error)
 
        RETURN_VAL_IF_FAIL(exynos_data, NULL);
 
-       return tdm_exynos_pp_create(exynos_data, error);
+       if (exynos_data->use_ippv2)
+               return tdm_exynos_pp_create(exynos_data, error);
+       else
+               return tdm_exynos_pp_legacy_create(exynos_data, error);
 }
index 47b36095d66de63aaaae36c5ef3e62b7980f635b..e56166d76a88e8170a112db02b43a1fc13659ee0 100644 (file)
@@ -1192,7 +1192,10 @@ exynos_output_create_capture(tdm_output *output, tdm_error *error)
 
        exynos_data = output_data->exynos_data;
 
-       return tdm_exynos_capture_create_output(exynos_data, output, error);
+       if (exynos_data->use_ippv2)
+               return tdm_exynos_capture_create_output(exynos_data, output, error);
+       else
+               return tdm_exynos_capture_legacy_create_output(exynos_data, output, error);
 }
 
 tdm_error
diff --git a/src/tdm_exynos_pp_legacy.c b/src/tdm_exynos_pp_legacy.c
new file mode 100644 (file)
index 0000000..13a7237
--- /dev/null
@@ -0,0 +1,451 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_exynos.h"
+
+typedef struct _tdm_exynos_pp_legacy_buffer {
+       int index;
+       tbm_surface_h src;
+       tbm_surface_h dst;
+
+       struct list_head link;
+} tdm_exynos_pp_legacy_buffer;
+
+typedef struct _tdm_exynos_pp_legacy_data {
+       tdm_exynos_data *exynos_data;
+
+       unsigned int prop_id;
+
+       tdm_info_pp info;
+       int info_changed;
+
+       struct list_head pending_buffer_list;
+       struct list_head buffer_list;
+
+       tdm_pp_done_handler done_func;
+       void *done_user_data;
+
+       int startd;
+       int first_event;
+
+       struct list_head link;
+} tdm_exynos_pp_legacy_data;
+
+
+static tbm_format pp_formats[] = {
+       TBM_FORMAT_ARGB8888,
+       TBM_FORMAT_XRGB8888,
+       TBM_FORMAT_NV12,
+       TBM_FORMAT_NV21,
+       TBM_FORMAT_YUV420,
+       TBM_FORMAT_YVU420,
+#ifdef HAVE_TILED_FORMAT
+       TBM_FORMAT_NV12MT,
+#endif
+};
+
+#define NUM_PP_FORMAT   (sizeof(pp_formats) / sizeof(pp_formats[0]))
+
+static int pp_list_init;
+static struct list_head pp_list;
+
+static int
+_get_index(tdm_exynos_pp_legacy_data *pp_data)
+{
+       tdm_exynos_pp_legacy_buffer *buffer = NULL;
+       int ret = 0;
+
+       while (1) {
+               int found = 0;
+               LIST_FOR_EACH_ENTRY(buffer, &pp_data->pending_buffer_list, link) {
+                       if (ret == buffer->index) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found)
+                       LIST_FOR_EACH_ENTRY(buffer, &pp_data->buffer_list, link) {
+                       if (ret == buffer->index) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found)
+                       break;
+               ret++;
+       }
+
+       return ret;
+}
+
+static tdm_error
+_tdm_exynos_pp_legacy_set(tdm_exynos_pp_legacy_data *pp_data)
+{
+       tdm_exynos_data *exynos_data = pp_data->exynos_data;
+       tdm_info_pp *info = &pp_data->info;
+       struct drm_exynos_ipp_property property;
+       int ret = 0;
+
+       CLEAR(property);
+       property.config[0].ops_id = EXYNOS_DRM_OPS_SRC;
+       property.config[0].fmt = tdm_exynos_format_to_drm_format(info->src_config.format);
+       memcpy(&property.config[0].sz, &info->src_config.size, sizeof(tdm_size));
+       memcpy(&property.config[0].pos, &info->src_config.pos, sizeof(tdm_pos));
+       property.config[1].ops_id = EXYNOS_DRM_OPS_DST;
+       property.config[1].degree = info->transform % 4;
+       property.config[1].flip = (info->transform > 3) ? EXYNOS_DRM_FLIP_HORIZONTAL : 0;
+       property.config[1].fmt = tdm_exynos_format_to_drm_format(info->dst_config.format);
+       memcpy(&property.config[1].sz, &info->dst_config.size, sizeof(tdm_size));
+       memcpy(&property.config[1].pos, &info->dst_config.pos, sizeof(tdm_pos));
+       property.cmd = IPP_CMD_M2M;
+       property.prop_id = pp_data->prop_id;
+
+       TDM_DBG("src : flip(%x) deg(%d) fmt(%c%c%c%c) sz(%dx%d) pos(%d,%d %dx%d)  ",
+                       property.config[0].flip, property.config[0].degree,
+                       FOURCC_STR(property.config[0].fmt),
+                       property.config[0].sz.hsize, property.config[0].sz.vsize,
+                       property.config[0].pos.x, property.config[0].pos.y, property.config[0].pos.w,
+                       property.config[0].pos.h);
+       TDM_DBG("dst : flip(%x) deg(%d) fmt(%c%c%c%c) sz(%dx%d) pos(%d,%d %dx%d)  ",
+                       property.config[1].flip, property.config[1].degree,
+                       FOURCC_STR(property.config[1].fmt),
+                       property.config[1].sz.hsize, property.config[1].sz.vsize,
+                       property.config[1].pos.x, property.config[1].pos.y, property.config[1].pos.w,
+                       property.config[1].pos.h);
+
+       ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY, &property);
+       if (ret) {
+               TDM_ERR("failed: %m");
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       TDM_DBG("success. prop_id(%d) ", property.prop_id);
+       pp_data->prop_id = property.prop_id;
+       return TDM_ERROR_NONE;
+}
+
+static tdm_error
+_tdm_exynos_pp_legacy_queue(tdm_exynos_pp_legacy_data *pp_data, tdm_exynos_pp_legacy_buffer *buffer,
+                                                       enum drm_exynos_ipp_buf_type type)
+{
+       tdm_exynos_data *exynos_data = pp_data->exynos_data;
+       struct drm_exynos_ipp_queue_buf buf;
+       int i, bo_num, ret = 0;
+
+       CLEAR(buf);
+       buf.prop_id = pp_data->prop_id;
+       buf.ops_id = EXYNOS_DRM_OPS_SRC;
+       buf.buf_type = type;
+       buf.buf_id = buffer->index;
+       buf.user_data = (__u64)(uintptr_t)pp_data;
+       bo_num = tbm_surface_internal_get_num_bos(buffer->src);
+       for (i = 0; i < EXYNOS_DRM_PLANAR_MAX && i < bo_num; i++) {
+               tbm_bo bo = tbm_surface_internal_get_bo(buffer->src, i);
+               buf.handle[i] = (__u32)tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+       }
+
+       TDM_DBG("prop_id(%d) ops_id(%d) ctrl(%d) id(%d) handles(%x %x %x). ",
+                       buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id,
+                       buf.handle[0], buf.handle[1], buf.handle[2]);
+
+       ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, &buf);
+       if (ret) {
+               TDM_ERR("src failed. prop_id(%d) op(%d) buf(%d) id(%d). %m",
+                               buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id);
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       CLEAR(buf);
+       buf.prop_id = pp_data->prop_id;
+       buf.ops_id = EXYNOS_DRM_OPS_DST;
+       buf.buf_type = type;
+       buf.buf_id = buffer->index;
+       buf.user_data = (__u64)(uintptr_t)pp_data;
+       bo_num = tbm_surface_internal_get_num_bos(buffer->dst);
+       for (i = 0; i < EXYNOS_DRM_PLANAR_MAX && i < bo_num; i++) {
+               tbm_bo bo = tbm_surface_internal_get_bo(buffer->dst, i);
+               buf.handle[i] = (__u32)tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+       }
+
+       TDM_DBG("prop_id(%d) ops_id(%d) ctrl(%d) id(%d) handles(%x %x %x). ",
+                       buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id,
+                       buf.handle[0], buf.handle[1], buf.handle[2]);
+
+       ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, &buf);
+       if (ret) {
+               TDM_ERR("dst failed. prop_id(%d) op(%d) buf(%d) id(%d). %m",
+                               buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id);
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       TDM_DBG("success. prop_id(%d)", buf.prop_id);
+
+       return TDM_ERROR_NONE;
+}
+
+static tdm_error
+_tdm_exynos_pp_legacy_cmd(tdm_exynos_pp_legacy_data *pp_data, enum drm_exynos_ipp_ctrl cmd)
+{
+       tdm_exynos_data *exynos_data = pp_data->exynos_data;
+       struct drm_exynos_ipp_cmd_ctrl ctrl;
+       int ret = 0;
+
+       ctrl.prop_id = pp_data->prop_id;
+       ctrl.ctrl = cmd;
+
+       TDM_DBG("prop_id(%d) ctrl(%d). ", ctrl.prop_id, ctrl.ctrl);
+
+       ret = ioctl(exynos_data->drm_fd, DRM_IOCTL_EXYNOS_IPP_CMD_CTRL, &ctrl);
+       if (ret) {
+               TDM_ERR("failed. prop_id(%d) ctrl(%d). %m", ctrl.prop_id, ctrl.ctrl);
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       TDM_DBG("success. prop_id(%d) ", ctrl.prop_id);
+
+       return TDM_ERROR_NONE;
+}
+
+void
+tdm_exynos_pp_legacy_cb(int fd, unsigned int prop_id, unsigned int *buf_idx,
+                                         unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+{
+       tdm_exynos_pp_legacy_handler(prop_id, buf_idx, tv_sec, tv_usec, user_data);
+}
+
+void
+tdm_exynos_pp_legacy_handler(unsigned int prop_id, unsigned int *buf_idx,
+                                                       unsigned int tv_sec, unsigned int tv_usec, void *data)
+{
+       tdm_exynos_pp_legacy_data *found = NULL, *d = NULL, *pp_data = data;
+       tdm_exynos_pp_legacy_buffer *b = NULL, *bb = NULL, *dequeued_buffer = NULL;
+
+       if (!pp_data || !buf_idx) {
+               TDM_ERR("invalid params");
+               return;
+       }
+
+       if (!pp_list_init)
+               return;
+
+       LIST_FOR_EACH_ENTRY(d, &pp_list, link) {
+               if (d == pp_data) {
+                       found = d;
+                       break;
+               }
+       }
+       if (!found)
+               return;
+
+       TDM_DBG("pp_data(%p) index(%d, %d)", pp_data, buf_idx[0], buf_idx[1]);
+
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->buffer_list, link) {
+               if (buf_idx[0] == b->index) {
+                       dequeued_buffer = b;
+                       LIST_DEL(&dequeued_buffer->link);
+                       TDM_DBG("dequeued: %d", dequeued_buffer->index);
+                       break;
+               }
+       }
+
+       if (!dequeued_buffer) {
+               TDM_ERR("not found buffer index: %d", buf_idx[0]);
+               return;
+       }
+
+       if (!pp_data->first_event) {
+               TDM_DBG("pp(%p) got a first event. ", pp_data);
+               pp_data->first_event = 1;
+       }
+
+       if (pp_data->done_func)
+               pp_data->done_func(pp_data,
+                                                  dequeued_buffer->src,
+                                                  dequeued_buffer->dst,
+                                                  pp_data->done_user_data);
+       free(dequeued_buffer);
+}
+
+tdm_error
+tdm_exynos_pp_legacy_get_capability(tdm_exynos_data *exynos_data, tdm_caps_pp *caps)
+{
+       int i;
+
+       if (!caps) {
+               TDM_ERR("invalid params");
+               return TDM_ERROR_INVALID_PARAMETER;
+       }
+
+       caps->capabilities = TDM_PP_CAPABILITY_ASYNC;
+
+       caps->format_count = NUM_PP_FORMAT;
+
+       /* will be freed in frontend */
+       caps->formats = calloc(1, sizeof pp_formats);
+       if (!caps->formats) {
+               TDM_ERR("alloc failed");
+               return TDM_ERROR_OUT_OF_MEMORY;
+       }
+       for (i = 0; i < caps->format_count; i++)
+               caps->formats[i] = pp_formats[i];
+
+       caps->min_w = 16;
+       caps->min_h = 8;
+       caps->max_w = -1;   /* not defined */
+       caps->max_h = -1;
+       caps->preferred_align = 16;
+
+       caps->max_attach_count = -1;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_pp *
+tdm_exynos_pp_legacy_create(tdm_exynos_data *exynos_data, tdm_error *error)
+{
+       tdm_exynos_pp_legacy_data *pp_data = calloc(1, sizeof(tdm_exynos_pp_legacy_data));
+       if (!pp_data) {
+               TDM_ERR("alloc failed");
+               if (error)
+                       *error = TDM_ERROR_OUT_OF_MEMORY;
+               return NULL;
+       }
+
+       pp_data->exynos_data = exynos_data;
+
+       LIST_INITHEAD(&pp_data->pending_buffer_list);
+       LIST_INITHEAD(&pp_data->buffer_list);
+
+       if (!pp_list_init) {
+               pp_list_init = 1;
+               LIST_INITHEAD(&pp_list);
+       }
+       LIST_ADDTAIL(&pp_data->link, &pp_list);
+
+       return pp_data;
+}
+
+void
+exynos_pp_legacy_destroy(tdm_pp *pp)
+{
+       tdm_exynos_pp_legacy_data *pp_data = pp;
+       tdm_exynos_pp_legacy_buffer *b = NULL, *bb = NULL;
+
+       if (!pp_data)
+               return;
+
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
+               LIST_DEL(&b->link);
+               free(b);
+       }
+
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->buffer_list, link) {
+               LIST_DEL(&b->link);
+               _tdm_exynos_pp_legacy_queue(pp_data, b, IPP_BUF_DEQUEUE);
+               free(b);
+       }
+
+       if (pp_data->prop_id)
+               _tdm_exynos_pp_legacy_cmd(pp_data, IPP_CTRL_STOP);
+
+       LIST_DEL(&pp_data->link);
+
+       free(pp_data);
+}
+
+tdm_error
+exynos_pp_legacy_set_info(tdm_pp *pp, tdm_info_pp *info)
+{
+       tdm_exynos_pp_legacy_data *pp_data = pp;
+
+       RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
+
+       if (info->sync) {
+               TDM_ERR("not support sync mode currently");
+               return TDM_ERROR_INVALID_PARAMETER;
+       }
+
+       pp_data->info = *info;
+       pp_data->info_changed = 1;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+exynos_pp_legacy_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
+{
+       tdm_exynos_pp_legacy_data *pp_data = pp;
+       tdm_exynos_pp_legacy_buffer *buffer;
+
+       RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(src, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(dst, TDM_ERROR_INVALID_PARAMETER);
+
+       buffer = calloc(1, sizeof(tdm_exynos_pp_legacy_buffer));
+       if (!buffer) {
+               TDM_ERR("alloc failed");
+               return TDM_ERROR_NONE;
+       }
+
+       LIST_ADDTAIL(&buffer->link, &pp_data->pending_buffer_list);
+       buffer->index = _get_index(pp_data);
+       buffer->src = src;
+       buffer->dst = dst;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+exynos_pp_legacy_commit(tdm_pp *pp)
+{
+       tdm_exynos_pp_legacy_data *pp_data = pp;
+       tdm_exynos_pp_legacy_buffer *b = NULL, *bb = NULL;
+       tdm_error ret;
+
+       RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
+
+       if (pp_data->info_changed) {
+               if (pp_data->startd)
+                       _tdm_exynos_pp_legacy_cmd(pp_data, IPP_CTRL_PAUSE);
+
+               ret = _tdm_exynos_pp_legacy_set(pp_data);
+               if (ret < 0)
+                       return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
+               LIST_DEL(&b->link);
+               _tdm_exynos_pp_legacy_queue(pp_data, b, IPP_BUF_ENQUEUE);
+               TDM_DBG("queued: %d", b->index);
+               LIST_ADDTAIL(&b->link, &pp_data->buffer_list);
+       }
+
+       if (pp_data->info_changed) {
+               pp_data->info_changed = 0;
+
+               if (!pp_data->startd) {
+                       pp_data->startd = 1;
+                       _tdm_exynos_pp_legacy_cmd(pp_data, IPP_CTRL_PLAY);
+               } else
+                       _tdm_exynos_pp_legacy_cmd(pp_data, IPP_CTRL_RESUME);
+       }
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+exynos_pp_legacy_set_done_handler(tdm_pp *pp, tdm_pp_done_handler func,
+                                                                 void *user_data)
+{
+       tdm_exynos_pp_legacy_data *pp_data = pp;
+
+       RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
+
+       pp_data->done_func = func;
+       pp_data->done_user_data = user_data;
+
+       return TDM_ERROR_NONE;
+}
diff --git a/src/tdm_exynos_pp_legacy.h b/src/tdm_exynos_pp_legacy.h
new file mode 100644 (file)
index 0000000..21354bf
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _TDM_EXYNOS_PP_LEGACY_H_
+#define _TDM_EXYNOS_PP_LEGACY_H_
+
+#include "tdm_exynos.h"
+
+tdm_error    tdm_exynos_pp_legacy_get_capability(tdm_exynos_data *exynos_data, tdm_caps_pp *caps);
+tdm_pp*      tdm_exynos_pp_legacy_create(tdm_exynos_data *exynos_data, tdm_error *error);
+void         tdm_exynos_pp_legacy_handler(unsigned int prop_id, unsigned int *buf_idx,
+                                                                                unsigned int tv_sec, unsigned int tv_usec, void *data);
+void         tdm_exynos_pp_legacy_cb(int fd, unsigned int prop_id, unsigned int *buf_idx,
+                                                                       unsigned int tv_sec, unsigned int tv_usec,
+                                                                       void *user_data);
+#endif /* _TDM_EXYNOS_PP_LEGACY_H_ */
index 000a2ac1291584884f5b8b24b987899fbfc8e6c6..6c525934fc4d5159a0fdc2dc808829c5abc22dac 100644 (file)
@@ -109,6 +109,7 @@ struct _tdm_exynos_data {
        struct list_head output_list;
        struct list_head buffer_list;
 
+       int use_ippv2;
        int ipp_module_id;
 };