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)
{
_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);
tdm_func_capture exynos_func_capture;
tdm_error ret;
const char *value;
+ drmVersionPtr drm_version;
value = (const char*)getenv("SCREEN_PREROTATION_HINT");
if (value) {
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);
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)
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");
} 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;
--- /dev/null
+#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, ¢er);
+
+ 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;
+}
--- /dev/null
+#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;
+}