make hal-backend-tdm-exynos-deconfb package 22/253322/7
authorSooChan Lim <sc1.lim@samsung.com>
Mon, 8 Feb 2021 23:45:51 +0000 (08:45 +0900)
committerJunkyeong Kim <jk0430.kim@samsung.com>
Wed, 10 Mar 2021 06:17:17 +0000 (15:17 +0900)
This is the first step for implementing the new hal backend.
libhal-backend-tdm-exynos-deconfb package has a new hal backend module.
The new hal architecture will be available for Tizen 6.5.

Change-Id: I3173255d379ed4342339f6ae83101a4a1dfc0dfb
Signed-off-by: Junkyeong Kim <jk0430.kim@samsung.com>
20 files changed:
configure.ac
packaging/libhal-backend-tdm-exynos-deconfb.manifest [new file with mode: 0644]
packaging/libtdm-exynos-deconfb.spec
src/Makefile.am
src/libhal-backend-tdm-exynos-deconfb/Makefile.am [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/exynos_pp.h [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_backend_exynos.c [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_backend_exynos.h [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_backend_exynos_types.h [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_backend_log.c [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_backend_log.h [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_capture.c [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_display.c [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_format.c [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_format.h [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_hwc.c [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_hwc_window.c [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_pp.c [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_sc_v4l2.c [new file with mode: 0644]
src/libhal-backend-tdm-exynos-deconfb/tdm_list.h [new file with mode: 0644]

index cb1dd5953e0aacb4c0a137dc3557c1d3d3ff1886..5db5e0c15bbee778179a32f77e149ff19b75d076 100644 (file)
@@ -23,17 +23,34 @@ LT_INIT([disable-static])
 # Enable quiet compiles on automake 1.11.
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 
-PKG_CHECK_MODULES(TDM_EXYNOS_DECONFB, libtdm libtbm [libdrm >= 2.4.47] libdrm_exynos)
 PKG_CHECK_MODULES(UDEV, libudev, [udev=yes], [udev=no])
+
+# for libtdm-exynos-deconfb
+PKG_CHECK_MODULES(TDM_EXYNOS_DECONFB, libtdm libtbm [libdrm >= 2.4.47] libdrm libdrm_exynos)
+
+# for libhal-backend-tdm-exynos-deconfb
+PKG_CHECK_MODULES(LIBHAL_BACKEND_TDM_EXYNOS_DECONFB, hal-api-common hal-api-tdm hal-api-tbm libdrm libdrm_exynos dlog pixman-1)
 if test x"$udev" = xyes; then
+       # for libtdm-exynos-deconfb
        AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection])
        TDM_EXYNOS_DECONFB_CFLAGS="$TDM_EXYNOS_DECONFB_CFLAGS $UDEV_CFLAGS"
        TDM_EXYNOS_DECONFB_LIBS="$TDM_EXYNOS_DECONFB_LIBS $UDEV_LIBS"
+
+       # for libhal-backend-tdm-exynos-deconfb
+       LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_CFLAGS="$LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_CFLAGS $UDEV_CFLAGS"
+       LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_LIBS="$LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_LIBS $UDEV_LIBS"
+       AC_SUBST(LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_CFLAGS)
+       AC_SUBST(LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_LIBS)
 fi
 
+# for libtdm-exynos-deconfb
 AC_SUBST(TDM_EXYNOS_DECONFB_CFLAGS)
 AC_SUBST(TDM_EXYNOS_DECONFB_LIBS)
 
+# for libhal-backend-tdm-exynos-deconfb
+AC_SUBST(LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_CFLAGS)
+AC_SUBST(LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_LIBS)
+
 AC_ARG_ENABLE([tiled-format],
               [AC_HELP_STRING([--enable-tiled-format], [Enable tiled format])],
               [], [enable_tiled_format=no])
@@ -48,12 +65,28 @@ AC_ARG_WITH(tdm-module-path, AS_HELP_STRING([--with-tdm-module-path=PATH], [tdm
                                [ TDM_MODULE_PATH="${DEFAULT_TDM_MODULE_PATH}" ])
 AC_SUBST(TDM_MODULE_PATH)
 
+# set the library dir for the tdm hal backend
+DEFAULT_HAL_LIBDIR="/hal/lib"
+AC_ARG_WITH(hal-libdir, AS_HELP_STRING([--with-hal-libdir=PATH], [hal backend library path]),
+                [ HAL_LIBDIR="$withval" ],
+                [ HAL_LIBDIR="${DEFAULT_HAL_LIBDIR}" ])
+AC_DEFINE_UNQUOTED(HAL_LIBDIR, "${HAL_LIBDIR}", [Directory for hal backend library path])
+AC_SUBST(HAL_LIBDIR)
+
 # For enumerating devices in test case
 AC_OUTPUT([
        Makefile
+       src/libhal-backend-tdm-exynos-deconfb/Makefile
        src/libtdm-exynos-deconfb/Makefile
        src/Makefile])
 
+echo ""
+echo "$PACKAGE_STRING will be compiled with:"
+echo ""
+echo "TDM_EXYNOS_DECONFB_CFLAGS : $LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_CFLAGS"
+echo "TDM_EXYNOS_DECONFB_LIBS   : $LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_LIBS"
+echo "TDM_MODULE_DIR : $HAL_LIBDIR"
+echo ""
 echo ""
 echo "$PACKAGE_STRING will be compiled with:"
 echo ""
diff --git a/packaging/libhal-backend-tdm-exynos-deconfb.manifest b/packaging/libhal-backend-tdm-exynos-deconfb.manifest
new file mode 100644 (file)
index 0000000..75b0fa5
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+    <request>
+        <domain name="_"/>
+    </request>
+</manifest>
index 41058246780aec188c52855371b8cc6eeebd2f6f..3e427078f3adb05597ffc0f365443fd19dbf62d2 100644 (file)
@@ -6,10 +6,18 @@ Group:          Development/Libraries
 License:        MIT
 Source0:        %{name}-%{version}.tar.gz
 Source1001:        %{name}.manifest
+Source1002:        libhal-backend-tdm-exynos-deconfb.manifest
+
 BuildRequires: pkgconfig(libdrm)
 BuildRequires: pkgconfig(libdrm_exynos)
 BuildRequires: pkgconfig(libudev)
+BuildRequires: pkgconfig(dlog)
 BuildRequires: pkgconfig(libtdm)
+BuildRequires: pkgconfig(libtbm)
+BuildRequires: pkgconfig(hal-api-common)
+BuildRequires: pkgconfig(hal-api-tdm)
+BuildRequires: pkgconfig(hal-api-tbm)
+BuildRequires: pkgconfig(pixman-1)
 ExclusiveArch: %{arm} aarch64
 
 %description
@@ -29,14 +37,40 @@ Group:          Development/Libraries
 %description tw3
 Back-End library of Tizen Display Manager Exynos : libtdm-mgr Exynos library for TW3
 
+%package -n hal-backend-tdm-exynos-deconfb
+Summary:       hal-backend-tdm module for exynos-deconfb
+Group:         System/Libraries
+Requires:      hal-api-tdm
+Requires:      hal-api-common
+
+%description -n hal-backend-tdm-exynos-deconfb
+
+%package -n hal-backend-tdm-exynos-deconfb-tw2
+Summary:       hal-backend-tdm module for exynos-deconfb-tw2
+Group:         System/Libraries
+Requires:      hal-api-tdm
+Requires:      hal-api-common
+
+%description -n hal-backend-tdm-exynos-deconfb-tw2
+
+%package -n hal-backend-tdm-exynos-deconfb-tw3
+Summary:       hal-backend-tdm module for exynos-deconfb-tw3
+Group:         System/Libraries
+Requires:      hal-api-tdm
+Requires:      hal-api-common
+
+%description -n hal-backend-tdm-exynos-deconfb-tw3
+
 %global TZ_SYS_RO_SHARE  %{?TZ_SYS_RO_SHARE:%TZ_SYS_RO_SHARE}%{!?TZ_SYS_RO_SHARE:/usr/share}
 
 %prep
 %setup -q
 cp %{SOURCE1001} .
+cp %{SOURCE1002} .
 
 %build
 %reconfigure --prefix=%{_prefix} --libdir=%{_libdir}  --disable-static \
+             --with-hal-libdir=%{_hal_libdir} \
              CFLAGS="${CFLAGS} -Wall -Werror" \
              LDFLAGS="${LDFLAGS} -Wl,--hash-style=both -Wl,--as-needed"
 make %{?_smp_mflags}
@@ -69,6 +103,30 @@ ln -s libtdm-exynos-deconfb-tw3.so %{_libdir}/tdm/libtdm-default.so
 
 %postun tw3 -p /sbin/ldconfig
 
+%post -n hal-backend-tdm-exynos-deconfb
+if [ -f %{_hal_libdir}/libhal-backend-tdm.so ]; then
+    rm -rf %{_hal_libdir}/libhal-backend-tdm.so
+fi
+ln -s libhal-backend-tdm-exynos-deconfb.so %{_hal_libdir}/libhal-backend-tdm.so
+
+%postun -n hal-backend-tdm-exynos-deconfb -p /sbin/ldconfig
+
+%post -n hal-backend-tdm-exynos-deconfb-tw2
+if [ -f %{_hal_libdir}/libhal-backend-tdm.so ]; then
+    rm -rf %{_hal_libdir}/libhal-backend-tdm.so
+fi
+ln -s libhal-backend-tdm-exynos-deconfb-tw2.so %{_hal_libdir}/libhal-backend-tdm.so
+
+%postun -n hal-backend-tdm-exynos-deconfb-tw2 -p /sbin/ldconfig
+
+%post -n hal-backend-tdm-exynos-deconfb-tw3
+if [ -f %{_hal_libdir}/libhal-backend-tdm.so ]; then
+    rm -rf %{_hal_libdir}/libhal-backend-tdm.so
+fi
+ln -s libhal-backend-tdm-exynos-deconfb-tw3.so %{_hal_libdir}/libhal-backend-tdm.so
+
+%postun -n hal-backend-tdm-exynos-deconfb-tw3 -p /sbin/ldconfig
+
 %files
 %defattr(-,root,root,-)
 %manifest %{name}.manifest
@@ -86,3 +144,18 @@ ln -s libtdm-exynos-deconfb-tw3.so %{_libdir}/tdm/libtdm-default.so
 %manifest %{name}.manifest
 %license COPYING
 %{_libdir}/tdm/libtdm-exynos-deconfb-tw3.so
+
+%files -n hal-backend-tdm-exynos-deconfb
+%manifest libhal-backend-tdm-exynos-deconfb.manifest
+%license COPYING
+%{_hal_libdir}/libhal-backend-tdm-exynos-deconfb.so
+
+%files -n hal-backend-tdm-exynos-deconfb-tw2
+%manifest libhal-backend-tdm-exynos-deconfb.manifest
+%license COPYING
+%{_hal_libdir}/libhal-backend-tdm-exynos-deconfb-tw2.so
+
+%files -n hal-backend-tdm-exynos-deconfb-tw3
+%manifest libhal-backend-tdm-exynos-deconfb.manifest
+%license COPYING
+%{_hal_libdir}/libhal-backend-tdm-exynos-deconfb-tw3.so
index 8d409c9978b55522dc1623161c1119f45892329c..f91d661b7a02bf20a9a87a3797bf8f9d85048f88 100644 (file)
@@ -1 +1 @@
-SUBDIRS = libtdm-exynos-deconfb 
+SUBDIRS = libtdm-exynos-deconfb libhal-backend-tdm-exynos-deconfb
diff --git a/src/libhal-backend-tdm-exynos-deconfb/Makefile.am b/src/libhal-backend-tdm-exynos-deconfb/Makefile.am
new file mode 100644 (file)
index 0000000..9ac0384
--- /dev/null
@@ -0,0 +1,57 @@
+libhal_backend_tdm_exynos_deconfb_la_LTLIBRARIES = libhal-backend-tdm-exynos-deconfb.la
+libhal_backend_tdm_exynos_deconfb_ladir = @HAL_LIBDIR@
+libhal_backend_tdm_exynos_deconfb_la_LDFLAGS = -module -avoid-version
+libhal_backend_tdm_exynos_deconfb_la_LIBADD = $(LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_LIBS) -ldl -ldrm
+libhal_backend_tdm_exynos_deconfb_la_CFLAGS = \
+       $(LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_CFLAGS) \
+       -I$(top_srcdir)/src/libhal-backend-tdm-exynos-deconfb \
+       -I$(top_srcdir)/include/tw3
+libhal_backend_tdm_exynos_deconfb_la_SOURCES = \
+       tdm_exynos_format.c \
+       tdm_backend_log.c \
+       tdm_backend_exynos.c \
+       tdm_exynos_display.c \
+       tdm_exynos_hwc_window.c \
+       tdm_exynos_hwc.c \
+       tdm_exynos_pp.c \
+       tdm_exynos_sc_v4l2.c \
+       tdm_exynos_capture.c
+
+libhal_backend_tdm_exynos_deconfb_tw2_la_LTLIBRARIES = libhal-backend-tdm-exynos-deconfb-tw2.la
+libhal_backend_tdm_exynos_deconfb_tw2_ladir = @HAL_LIBDIR@
+libhal_backend_tdm_exynos_deconfb_tw2_la_LDFLAGS = -module -avoid-version
+libhal_backend_tdm_exynos_deconfb_tw2_la_LIBADD = $(LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_LIBS) -ldl -ldrm
+libhal_backend_tdm_exynos_deconfb_tw2_la_CFLAGS = \
+       $(LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_CFLAGS) \
+       -I$(top_srcdir)/src/libhal-backend-tdm-exynos-deconfb \
+       -I$(top_srcdir)/include/tw2
+libhal_backend_tdm_exynos_deconfb_tw2_la_SOURCES = \
+       tdm_exynos_format.c \
+       tdm_backend_log.c \
+       tdm_backend_exynos.c \
+       tdm_exynos_display.c \
+       tdm_exynos_hwc_window.c \
+       tdm_exynos_hwc.c \
+       tdm_exynos_pp.c \
+       tdm_exynos_sc_v4l2.c \
+       tdm_exynos_capture.c
+
+libhal_backend_tdm_exynos_deconfb_tw3_la_LTLIBRARIES = libhal-backend-tdm-exynos-deconfb-tw3.la
+libhal_backend_tdm_exynos_deconfb_tw3_ladir = @HAL_LIBDIR@
+libhal_backend_tdm_exynos_deconfb_tw3_la_LDFLAGS = -module -avoid-version
+libhal_backend_tdm_exynos_deconfb_tw3_la_LIBADD = $(LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_LIBS) -ldl -ldrm
+libhal_backend_tdm_exynos_deconfb_tw3_la_CFLAGS = \
+       $(LIBHAL_BACKEND_TDM_EXYNOS_DECONFB_CFLAGS) \
+       -I$(top_srcdir)/src/libhal-backend-tdm-exynos-deconfb \
+       -I$(top_srcdir)/include/tw3
+libhal_backend_tdm_exynos_deconfb_tw3_la_SOURCES = \
+       tdm_exynos_format.c \
+       tdm_backend_log.c \
+       tdm_backend_exynos.c \
+       tdm_exynos_display.c \
+       tdm_exynos_hwc_window.c \
+       tdm_exynos_hwc.c \
+       tdm_exynos_pp.c \
+       tdm_exynos_sc_v4l2.c \
+       tdm_exynos_capture.c
+
diff --git a/src/libhal-backend-tdm-exynos-deconfb/exynos_pp.h b/src/libhal-backend-tdm-exynos-deconfb/exynos_pp.h
new file mode 100644 (file)
index 0000000..ac23a1e
--- /dev/null
@@ -0,0 +1,336 @@
+/* exynos_pp.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Authors:
+ *     JinYoung Jeon <jy0.jeon@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _UAPI_EXYNOS_DRM_H_
+#define _UAPI_EXYNOS_DRM_H_
+
+#include <drm.h>
+
+#define EXYNOS_DRM_GEM_MAX_INDEX 3
+
+#define PP_MAX_UP_RATIO 8
+#define PP_MAX_DOWN_RATIO 16
+#define PP_MIN_DOWN_SIZE(size) (((size) + PP_MAX_DOWN_RATIO - 1) / PP_MAX_DOWN_RATIO)
+#define PP_MAX_UP_SIZE(size)   ((size) * PP_MAX_UP_RATIO)
+
+#define PP_RATIO(src, dst) ((65536 * src) / dst)
+#define PP_UP_MAX_RATIO PP_RATIO(1, PP_MAX_UP_RATIO)
+#define PP_DOWN_MIN_RATIO PP_RATIO(PP_MAX_DOWN_RATIO, 1)
+#define PP_CHECK_SUPPORT_ASPECT_RATIO(src_w, src_h, dst_w, dst_h) \
+       (((src_w > dst_w && src_h < dst_h) || (src_w < dst_w && src_h > dst_h)) ? 0 : 1)
+
+enum tgm_planer {
+       TGM_PLANAR_Y,
+       TGM_PLANAR_CB,
+       TGM_PLANAR_CR,
+       TGM_PLANAR_MAX,
+};
+
+enum tdm_crtc_id {
+       TDM_CRTC_PRIMARY,
+       TDM_CRTC_VIRTUAL,
+       TDM_CRTC_MAX,
+};
+
+enum tdm_dpms_type {
+       DPMS_SYNC_WORK = 0x0,
+       DPMS_EVENT_DRIVEN = 0x1,
+};
+
+struct tdm_control_dpms {
+       enum tdm_crtc_id        crtc_id;
+       __u32   dpms;
+       __u32   user_data;
+       enum tdm_dpms_type      type;
+};
+
+struct tdm_control_dpms_event {
+       struct drm_event        base;
+       enum tdm_crtc_id        crtc_id;
+       __u32   dpms;
+       __u32   user_data;
+};
+
+struct tbm_gem_create {
+       uint64_t size;
+       unsigned int flags;
+       unsigned int handle;
+};
+
+struct tbm_gem_mmap {
+       unsigned int handle;
+       unsigned int pad;
+       uint64_t size;
+       uint64_t mapped;
+};
+
+struct tbm_gem_info {
+       unsigned int handle;
+       unsigned int flags;
+       uint64_t size;
+};
+
+struct tbm_gem_cpu_access {
+       unsigned int handle;
+       unsigned int reserved;
+};
+
+enum tdm_ops_id {
+       TDM_OPS_SRC,
+       TDM_OPS_DST,
+       TDM_OPS_MAX,
+};
+
+struct tdm_sz {
+       __u32   hsize;
+       __u32   vsize;
+};
+
+struct hal_tdm_pos {
+       __u32   x;
+       __u32   y;
+       __u32   w;
+       __u32   h;
+};
+
+enum tdm_flip {
+       TDM_FLIP_NONE = (0 << 0),
+       TDM_FLIP_VERTICAL = (1 << 0),
+       TDM_FLIP_HORIZONTAL = (1 << 1),
+       TDM_FLIP_BOTH = TDM_FLIP_VERTICAL |
+                       TDM_FLIP_HORIZONTAL,
+};
+
+enum tdm_degree {
+       TDM_DEGREE_0,
+       TDM_DEGREE_90,
+       TDM_DEGREE_180,
+       TDM_DEGREE_270,
+};
+
+enum tdm_planer {
+       TDM_PLANAR_Y,
+       TDM_PLANAR_CB,
+       TDM_PLANAR_CR,
+       TDM_PLANAR_MAX,
+};
+
+/**
+ * A structure for pp supported property list.
+ *
+ * @version: version of this structure.
+ * @pp_id: id of pp driver.
+ * @count: count of pp driver.
+ * @writeback: flag of writeback supporting.
+ * @flip: flag of flip supporting.
+ * @degree: flag of degree information.
+ * @csc: flag of csc supporting.
+ * @crop: flag of crop supporting.
+ * @scale: flag of scale supporting.
+ * @refresh_min: min hz of refresh.
+ * @refresh_max: max hz of refresh.
+ * @crop_min: crop min resolution.
+ * @crop_max: crop max resolution.
+ * @scale_min: scale min resolution.
+ * @scale_max: scale max resolution.
+ */
+struct tdm_pp_prop_list {
+       __u32   version;
+       __u32   pp_id;
+       __u32   count;
+       __u32   writeback;
+       __u32   flip;
+       __u32   degree;
+       __u32   csc;
+       __u32   crop;
+       __u32   scale;
+       __u32   refresh_min;
+       __u32   refresh_max;
+       __u32   reserved;
+       struct tdm_sz   crop_min;
+       struct tdm_sz   crop_max;
+       struct tdm_sz   scale_min;
+       struct tdm_sz   scale_max;
+};
+
+/**
+ * A structure for pp config.
+ *
+ * @ops_id: property of operation directions.
+ * @flip: property of mirror, flip.
+ * @degree: property of rotation degree.
+ * @fmt: property of image format.
+ * @sz: property of image size.
+ * @pos: property of image position(src-cropped,dst-scaler).
+ */
+struct tdm_pp_config {
+       enum tdm_ops_id ops_id;
+       enum tdm_flip   flip;
+       enum tdm_degree degree;
+       __u32   fmt;
+       struct tdm_sz   sz;
+       struct hal_tdm_pos      pos;
+};
+
+enum tdm_pp_cmd {
+       PP_CMD_NONE,
+       PP_CMD_M2M,
+       PP_CMD_WB,
+       PP_CMD_OUTPUT,
+       PP_CMD_MAX,
+};
+
+/* define of ipp operation type */
+enum tdm_pp_type {
+       PP_SYNC_WORK = 0x0,
+       PP_EVENT_DRIVEN = 0x1,
+       PP_TYPE_MAX = 0x2,
+};
+
+/**
+ * A structure for pp property.
+ *
+ * @config: source, destination config.
+ * @cmd: definition of command.
+ * @pp_id: id of pp driver.
+ * @prop_id: id of property.
+ * @refresh_rate: refresh rate.
+ * @type: definition of operation type.
+ */
+struct tdm_pp_property {
+       struct tdm_pp_config config[TDM_OPS_MAX];
+       enum tdm_pp_cmd cmd;
+       __u32   pp_id;
+       __u32   prop_id;
+       __u32   refresh_rate;
+       enum tdm_pp_type        type;
+};
+
+enum tdm_pp_buf_type {
+       PP_BUF_ENQUEUE,
+       PP_BUF_DEQUEUE,
+};
+
+/**
+ * A structure for pp buffer operations.
+ *
+ * @ops_id: operation directions.
+ * @buf_type: definition of buffer.
+ * @prop_id: id of property.
+ * @buf_id: id of buffer.
+ * @handle: Y, Cb, Cr each planar handle.
+ * @user_data: user data.
+ */
+struct tdm_pp_queue_buf {
+       enum tdm_ops_id ops_id;
+       enum tdm_pp_buf_type    buf_type;
+       __u32   prop_id;
+       __u32   buf_id;
+       __u32   handle[TDM_PLANAR_MAX];
+       __u32   reserved;
+       __u64   user_data;
+};
+
+enum tdm_pp_ctrl {
+       PP_CTRL_PLAY,
+       PP_CTRL_STOP,
+       PP_CTRL_PAUSE,
+       PP_CTRL_RESUME,
+       PP_CTRL_MAX,
+};
+
+/**
+ * A structure for pp start/stop operations.
+ *
+ * @prop_id: id of property.
+ * @ctrl: definition of control.
+ */
+struct tdm_pp_cmd_ctrl {
+       __u32   prop_id;
+       enum tdm_pp_ctrl        ctrl;
+};
+
+struct tdm_pp_event {
+       struct drm_event        base;
+       __u64                   user_data;
+       __u32                   tv_sec;
+       __u32                   tv_usec;
+       __u32                   prop_id;
+       __u32                   reserved;
+       __u32                   buf_id[TDM_OPS_MAX];
+};
+
+#define DRM_TBM_GEM_CREATE             0x00
+#define DRM_TBM_GEM_MMAP               0x02
+#define DRM_TBM_GEM_GET                0x04
+#define DRM_TBM_GEM_CPU_PREP           0x05
+#define DRM_TBM_GEM_CPU_FINI           0x06
+#define DRM_TDM_DPMS_CONTROL           0x50
+
+/* PP - Post Processing */
+#define DRM_TDM_PP_GET_PROPERTY        0x30
+#define DRM_TDM_PP_SET_PROPERTY        0x31
+#define DRM_TDM_PP_QUEUE_BUF   0x32
+#define DRM_TDM_PP_CMD_CTRL    0x33
+#define DRM_TDM_PP_GET_PERMISSION      0x34
+
+#define DRM_IOCTL_TBM_GEM_CREATE               DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_TBM_GEM_CREATE, struct tbm_gem_create)
+
+#define DRM_IOCTL_TBM_GEM_MMAP         DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_TBM_GEM_MMAP, struct tbm_gem_mmap)
+
+#define DRM_IOCTL_TBM_GEM_GET  DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_TBM_GEM_GET,        struct tbm_gem_info)
+
+#define DRM_IOCTL_TBM_GEM_CPU_PREP             DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_TBM_GEM_CPU_PREP, struct tbm_gem_cpu_access)
+
+#define DRM_IOCTL_TBM_GEM_CPU_FINI             DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_TBM_GEM_CPU_FINI, struct tbm_gem_cpu_access)
+
+#define DRM_IOCTL_TDM_DPMS_CONTROL     DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_TDM_DPMS_CONTROL, struct tdm_control_dpms)
+
+#define DRM_IOCTL_TDM_PP_GET_PROPERTY  DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_TDM_PP_GET_PROPERTY, struct tdm_pp_prop_list)
+
+#define DRM_IOCTL_TDM_PP_SET_PROPERTY  DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_TDM_PP_SET_PROPERTY, struct tdm_pp_property)
+
+#define DRM_IOCTL_TDM_PP_QUEUE_BUF     DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_TDM_PP_QUEUE_BUF, struct tdm_pp_queue_buf)
+
+#define DRM_IOCTL_TDM_PP_CMD_CTRL              DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_TDM_PP_CMD_CTRL, struct tdm_pp_cmd_ctrl)
+
+#define DRM_IOCTL_TDM_PP_GET_PERMISSION                DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_TDM_PP_GET_PERMISSION, bool)
+
+#define TDM_PP_EVENT           0x80000001
+#define TDM_DPMS_EVENT         0x80000002
+
+#endif /* _UAPI_EXYNOS_DRM_H_ */
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_backend_exynos.c b/src/libhal-backend-tdm-exynos-deconfb/tdm_backend_exynos.c
new file mode 100644 (file)
index 0000000..d8060a6
--- /dev/null
@@ -0,0 +1,452 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_exynos.h"
+
+#if HAVE_UDEV
+#include <libudev.h>
+#endif
+
+#define SET_DRM_IRQ
+
+#define DRM_DRV_NAME "tgm"
+
+static int
+_tdm_exynos_open_drm(void)
+{
+       int fd = -1;
+
+       fd = drmOpen(DRM_DRV_NAME, NULL);
+       if (fd < 0)
+               TDM_BACKEND_ERR("Cannot open '%s' drm", DRM_DRV_NAME);
+
+#ifdef HAVE_UDEV
+       if (fd < 0) {
+               struct udev *udev;
+               struct udev_enumerate *e;
+               struct udev_list_entry *entry;
+               struct udev_device *device, *drm_device, *device_parent;
+               const char *filename;
+
+               TDM_BACKEND_WRN("Cannot open drm device.. search by udev");
+               udev = udev_new();
+               if (!udev) {
+                       TDM_BACKEND_ERR("fail to initialize udev context\n");
+                       goto close_l;
+               }
+
+               /* Will try to find sys path /exynos-drm/drm/card0 */
+               e = udev_enumerate_new(udev);
+               udev_enumerate_add_match_subsystem(e, "drm");
+               udev_enumerate_add_match_sysname(e, "card[0-9]*");
+               udev_enumerate_scan_devices(e);
+
+               drm_device = NULL;
+               udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
+                       device = udev_device_new_from_syspath(udev_enumerate_get_udev(e),
+                                                                                                 udev_list_entry_get_name(entry));
+                       device_parent = udev_device_get_parent(device);
+                       /* Not need unref device_parent. device_parent and device have same refcnt */
+                       if (device_parent) {
+                               if (strcmp(udev_device_get_sysname(device_parent), "exynos-drm") == 0) {
+                                       drm_device = device;
+                                       TDM_BACKEND_DBG("Found drm device: '%s' (%s)\n",
+                                                       udev_device_get_syspath(drm_device),
+                                                       udev_device_get_sysname(device_parent));
+                                       break;
+                               }
+                       }
+                       udev_device_unref(device);
+               }
+
+               if (drm_device == NULL) {
+                       TDM_BACKEND_ERR("fail to find drm device\n");
+                       udev_enumerate_unref(e);
+                       udev_unref(udev);
+                       goto close_l;
+               }
+
+               filename = udev_device_get_devnode(drm_device);
+
+               fd = open(filename, O_RDWR | O_CLOEXEC);
+               if (fd < 0)
+                       TDM_BACKEND_ERR("Cannot open drm device(%s)\n", filename);
+
+               udev_device_unref(drm_device);
+               udev_enumerate_unref(e);
+               udev_unref(udev);
+       }
+close_l:
+#endif
+
+#ifdef SET_DRM_IRQ
+       drmCtlInstHandler(fd, 78);
+#endif
+
+       return fd;
+}
+
+static void
+_tdm_exynos_display_deinitialize(tdm_exynos_display *display_data)
+{
+       tdm_exynos_display_destroy_output_list(display_data);
+       tdm_exynos_display_destroy_buffer_list(display_data);
+
+       tdm_exynos_display_deinit_event_handling(display_data);
+}
+
+static hal_tdm_error
+_tdm_exynos_display_initialize(tdm_exynos_display *display_data)
+{
+       hal_tdm_error ret;
+
+#if 0
+       if (drmSetClientCap(display_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0)
+               TDM_BACKEND_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed_l");
+#endif
+
+       ret = tdm_exynos_display_create_output_list(display_data);
+       if (ret != HAL_TDM_ERROR_NONE)
+               goto failed;
+
+       ret = tdm_exynos_display_init_event_handling(display_data);
+       if (ret != HAL_TDM_ERROR_NONE)
+               goto failed;
+
+       return ret;
+
+failed:
+       _tdm_exynos_display_deinitialize(display_data);
+
+       return ret;
+}
+
+static hal_tdm_error
+_tdm_exynos_master_drm_fd_handler(hal_tdm_fd master_drm_fd, void *user_data)
+{
+       tdm_exynos_display *display_data = (tdm_exynos_display *) user_data;
+       hal_tdm_error ret;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       display_data->drm_fd = master_drm_fd;
+       TDM_BACKEND_INFO("Get the master drm_fd(%d)!\n", display_data->drm_fd);
+
+       // initialize display with a master drm_fd
+       ret = _tdm_exynos_display_initialize(display_data);
+       if (ret != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("fail to _tdm_exynos_display_initialize!\n");
+               _tdm_exynos_display_deinitialize(display_data);
+
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+int
+hal_backend_tdm_exynos_exit(void *data)
+{
+       hal_tdm_backend_data *backend_data = (hal_tdm_backend_data *)data;
+       tdm_exynos_display *display_data;
+
+       TDM_BACKEND_INFO("deinit");
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(backend_data != NULL, -1);
+
+       display_data = (tdm_exynos_display *)backend_data->display;
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data != NULL, -1);
+
+       if (backend_data->hwc_window_funcs) {
+               free(backend_data->hwc_window_funcs);
+               backend_data->hwc_window_funcs = NULL;
+       }
+       if (backend_data->hwc_funcs) {
+               free(backend_data->hwc_funcs);
+               backend_data->hwc_funcs = NULL;
+       }
+       if (backend_data->output_funcs) {
+               free(backend_data->output_funcs);
+               backend_data->output_funcs = NULL;
+       }
+       if (backend_data->display_funcs) {
+               free(backend_data->display_funcs);
+               backend_data->display_funcs = NULL;
+       }
+
+       _tdm_exynos_display_deinitialize(display_data);
+
+       if (display_data->pp) {
+               exynos_pp_v4l2_destroy(display_data->pp);
+               display_data->pp = NULL;
+               for (int i = 0; i < backend_data->num_event_sources; i++) {
+                       hal_tdm_event_source *event_source = backend_data->event_sources[i];
+                       free(event_source);
+               }
+       }
+
+       if (display_data->drm_fd >= 0)
+               close(display_data->drm_fd);
+
+       free(display_data);
+       display_data = NULL;
+
+       free(backend_data);
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+int
+hal_backend_tdm_exynos_init(void **data)
+{
+       hal_tdm_backend_data *backend_data = NULL;
+       hal_tdm_display_funcs *display_funcs = NULL;
+       hal_tdm_output_funcs *output_funcs = NULL;
+       hal_tdm_hwc_funcs *hwc_funcs = NULL;
+       hal_tdm_hwc_window_funcs *hwc_window_funcs = NULL;
+       hal_tdm_pp_funcs *pp_funcs = NULL;
+       hal_tdm_capture_funcs *capture_funcs = NULL;
+       tdm_exynos_display *display_data = NULL;
+       hal_tdm_error ret;
+       int drm_fd;
+
+       if (!*data) {
+               TDM_BACKEND_ERR("*data is null.\n");
+               return -1;
+       }
+
+       /* allocate a hal_tdm_backend_data */
+       backend_data = calloc(1, sizeof(struct _hal_tdm_backend_data));
+       if (!backend_data) {
+               TDM_BACKEND_ERR("fail to alloc backend_data!\n");
+               *data = NULL;
+               return -1;
+       }
+       *data = backend_data;
+
+       /* allocate a hal_tdm_display */
+       display_data = calloc(1, sizeof(struct _tdm_exynos_display));
+       if (!display_data) {
+               TDM_BACKEND_ERR("fail to alloc display_data!\n");
+               goto failed;
+       }
+       backend_data->display = (hal_tdm_display *)display_data;
+
+       LIST_INITHEAD(&display_data->output_list);
+       LIST_INITHEAD(&display_data->buffer_list);
+
+       // check if drm_fd is master fd.
+       drm_fd = _tdm_exynos_open_drm();
+       if (drm_fd < 0) {
+               ret = HAL_TDM_ERROR_OPERATION_FAILED;
+               goto failed;
+       }
+
+       // set true when backend has a drm_device.
+       backend_data->has_drm_device = 1;
+
+       if (drmIsMaster(drm_fd)) {
+               // drm_fd is a master drm_fd.
+               backend_data->drm_info.drm_fd = drm_fd;
+               backend_data->drm_info.is_master = 1;
+
+               display_data->drm_fd = drm_fd;
+               TDM_BACKEND_INFO("Get the master drm_fd(%d)!\n", display_data->drm_fd);
+
+               // initialize display with a master drm_fd
+               ret = _tdm_exynos_display_initialize(display_data);
+               if (ret != HAL_TDM_ERROR_NONE) {
+                       TDM_BACKEND_ERR("fail to _tdm_exynos_display_initialize!\n");
+                       goto failed;
+               }
+       } else {
+               // drm_fd is not a master drm_fd.
+               // request a master drm_fd
+               close(drm_fd);
+               backend_data->drm_info.drm_fd = -1;
+               backend_data->drm_info.is_master = 0;
+               backend_data->drm_info.master_drm_fd_func = _tdm_exynos_master_drm_fd_handler;
+               backend_data->drm_info.user_data = display_data;
+
+               TDM_BACKEND_INFO("A backend requests an master drm_fd.\n");
+       }
+
+       tdm_exynos_display_get_drm_pp_permission((hal_tdm_display *)display_data);
+
+       if (!display_data->drm_pp) {
+               int fd1 = -1;
+               int fd2 = -1;
+               hal_tdm_event_source *event_source;
+
+               display_data->pp = tdm_exynos_pp_v4l2_create(display_data, &ret, &fd1, &fd2);
+               if (display_data->pp == NULL || ret != HAL_TDM_ERROR_NONE)
+                       goto failed;
+
+               event_source = calloc(1, sizeof(struct _hal_tdm_event_source));
+               if (!event_source) {
+                       TDM_BACKEND_ERR("fail to alloc event_source!\n");
+                       goto failed;
+               }
+               event_source->event_fd = fd1;
+               event_source->func = tdm_exynos_pp_v4l2_task_done_handler;
+               event_source->user_data = display_data->pp;
+               backend_data->event_sources[0] = event_source;
+               backend_data->num_event_sources++;
+
+               event_source = calloc(1, sizeof(struct _hal_tdm_event_source));
+               if (!event_source) {
+                       TDM_BACKEND_ERR("fail to alloc event_source!\n");
+                       event_source = backend_data->event_sources[0];
+                       free(event_source);
+                       backend_data->num_event_sources = 0;
+                       goto failed;
+               }
+               event_source->event_fd = fd2;
+               event_source->func = tdm_exynos_pp_v4l2_task_done_handler;
+               event_source->user_data = display_data->pp;
+               backend_data->event_sources[1] = event_source;
+               backend_data->num_event_sources++;
+       }
+
+       /* alloc and register display_funcs */
+       display_funcs = calloc(1, sizeof(struct _hal_tdm_display_funcs));
+       if (!display_funcs) {
+               TDM_BACKEND_ERR("fail to alloc display_funcs!\n");
+               goto failed;
+       }
+       backend_data->display_funcs = display_funcs;
+
+       display_funcs->display_get_capability = exynos_display_get_capabilitiy;
+       display_funcs->display_get_pp_capability = exynos_display_get_pp_capability;
+       display_funcs->display_get_capture_capability = exynos_display_get_capture_capability;
+       display_funcs->display_get_outputs = exynos_display_get_outputs;
+       display_funcs->display_get_fd = exynos_display_get_fd;
+       display_funcs->display_handle_events = exynos_display_handle_events;
+       if (display_data->drm_pp)
+               display_funcs->display_create_pp = exynos_display_create_pp;
+       else
+               display_funcs->display_create_pp = exynos_display_create_pp_v4l2;
+
+       /* alloc and register output_funcs */
+       output_funcs = calloc(1, sizeof(struct _hal_tdm_output_funcs));
+       if (!output_funcs) {
+               TDM_BACKEND_ERR("fail to alloc output_funcs!\n");
+               goto failed;
+       }
+       backend_data->output_funcs = output_funcs;
+
+       output_funcs->output_get_capability = exynos_output_get_capability;
+       output_funcs->output_set_property = exynos_output_set_property;
+       output_funcs->output_get_property = exynos_output_get_property;
+       //output_funcs->output_get_cur_msc = exynos_output_get_cur_msc;
+       output_funcs->output_wait_vblank = exynos_output_wait_vblank;
+       output_funcs->output_set_vblank_handler = exynos_output_set_vblank_handler;
+       output_funcs->output_commit = exynos_output_commit;
+       output_funcs->output_set_commit_handler = exynos_output_set_commit_handler;
+       output_funcs->output_set_dpms = exynos_output_set_dpms;
+       //output_funcs->output_set_dpms_handler = exynos_output_set_dpms_handler;
+       output_funcs->output_get_dpms = exynos_output_get_dpms;
+       output_funcs->output_set_mode = exynos_output_set_mode;
+       output_funcs->output_get_mode = exynos_output_get_mode;
+       output_funcs->output_create_capture = exynos_output_create_capture;
+       output_funcs->output_set_status_handler = exynos_output_set_status_handler;
+       output_funcs->output_get_hwc = exynos_output_get_hwc;
+
+       /* alloc and register hwc_funcs */
+       hwc_funcs = calloc(1, sizeof(struct _hal_tdm_hwc_funcs));
+       if (!hwc_funcs) {
+               TDM_BACKEND_ERR("fail to alloc hwc_funcs!\n");
+               goto failed;
+       }
+       backend_data->hwc_funcs = hwc_funcs;
+
+       hwc_funcs->hwc_create_window = exynos_hwc_create_window;
+       hwc_funcs->hwc_get_video_supported_formats = exynos_hwc_get_video_supported_formats;
+       hwc_funcs->hwc_get_video_available_properties = NULL;
+       hwc_funcs->hwc_get_capabilities = exynos_hwc_get_capabilities;
+       hwc_funcs->hwc_get_available_properties = exynos_hwc_get_available_properties;
+       hwc_funcs->hwc_get_client_target_buffer_queue = exynos_hwc_get_client_target_buffer_queue;
+       hwc_funcs->hwc_set_client_target_buffer = exynos_hwc_set_client_target_buffer;
+       hwc_funcs->hwc_validate = exynos_hwc_validate;
+       hwc_funcs->hwc_get_changed_composition_types = exynos_hwc_get_changed_composition_types;
+       hwc_funcs->hwc_accept_validation  = exynos_hwc_accept_validation;
+       hwc_funcs->hwc_commit = exynos_hwc_commit;
+       hwc_funcs->hwc_set_commit_handler = exynos_hwc_set_commit_handler;
+
+       /* alloc and register hwc_window_funcs */
+       hwc_window_funcs = calloc(1, sizeof(struct _hal_tdm_hwc_window_funcs));
+       if (!hwc_funcs) {
+               TDM_BACKEND_ERR("fail to alloc hwc_window_funcs!\n");
+               goto failed;
+       }
+       backend_data->hwc_window_funcs = hwc_window_funcs;
+
+       hwc_window_funcs->hwc_window_destroy = exynos_hwc_window_destroy;
+       hwc_window_funcs->hwc_window_acquire_buffer_queue = NULL; // no need
+       hwc_window_funcs->hwc_window_release_buffer_queue = NULL; // no need
+       hwc_window_funcs->hwc_window_set_composition_type = exynos_hwc_window_set_composition_type;
+       hwc_window_funcs->hwc_window_set_buffer_damage = exynos_hwc_window_set_buffer_damage;
+       hwc_window_funcs->hwc_window_set_info = exynos_hwc_window_set_info;
+       hwc_window_funcs->hwc_window_set_buffer = exynos_hwc_window_set_buffer;
+       hwc_window_funcs->hwc_window_set_property = exynos_hwc_window_set_property;
+       hwc_window_funcs->hwc_window_get_property = exynos_hwc_window_get_property;
+       hwc_window_funcs->hwc_window_get_constraints = exynos_hwc_window_get_constraints;
+       hwc_window_funcs->hwc_window_set_name = exynos_hwc_window_set_name;
+       hwc_window_funcs->hwc_window_set_cursor_image = NULL; // no need
+
+       /* alloc and register pp_funcs */
+       pp_funcs = calloc(1, sizeof(struct _hal_tdm_pp_funcs));
+       if (!pp_funcs) {
+               TDM_BACKEND_ERR("fail to alloc pp_funcs!\n");
+               goto failed;
+       }
+       backend_data->pp_funcs = pp_funcs;
+
+       if (display_data->drm_pp) {
+               pp_funcs->pp_destroy = exynos_pp_destroy;
+               pp_funcs->pp_set_info = exynos_pp_set_info;
+               pp_funcs->pp_attach = exynos_pp_attach;
+               pp_funcs->pp_commit = exynos_pp_commit;
+               pp_funcs->pp_set_done_handler = exynos_pp_set_done_handler;
+       } else {
+               pp_funcs->pp_destroy = exynos_display_destroy_pp_v4l2;//exynos_pp_v4l2_destroy;
+               pp_funcs->pp_set_info = exynos_pp_v4l2_set_info;
+               pp_funcs->pp_attach = exynos_pp_v4l2_attach;
+               pp_funcs->pp_commit = exynos_pp_v4l2_commit;
+               pp_funcs->pp_set_done_handler = exynos_pp_v4l2_set_done_handler;
+       }
+
+       /* alloc and register capture_funcs */
+       capture_funcs = calloc(1, sizeof(struct _hal_tdm_capture_funcs));
+       if (!capture_funcs) {
+               TDM_BACKEND_ERR("fail to alloc pp_funcs!\n");
+               goto failed;
+       }
+       backend_data->capture_funcs = capture_funcs;
+
+       capture_funcs->capture_destroy = exynos_capture_destroy;
+       capture_funcs->capture_set_info = exynos_capture_set_info;
+       capture_funcs->capture_attach = exynos_capture_attach;
+       capture_funcs->capture_commit = exynos_capture_commit;
+       capture_funcs->capture_set_done_handler = exynos_capture_set_done_handler;
+
+       TDM_BACKEND_INFO("init success!");
+
+       return HAL_TDM_ERROR_NONE;
+
+failed:
+       TDM_BACKEND_ERR("init failed!");
+
+       hal_backend_tdm_exynos_exit((void *)backend_data);
+
+       return -1;
+}
+
+hal_backend hal_backend_tdm_data = {
+       "exynos",
+       "Samsung",
+       HAL_ABI_VERSION_TIZEN_6_5,
+       hal_backend_tdm_exynos_init,
+       hal_backend_tdm_exynos_exit
+};
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_backend_exynos.h b/src/libhal-backend-tdm-exynos-deconfb/tdm_backend_exynos.h
new file mode 100644 (file)
index 0000000..cf14b0e
--- /dev/null
@@ -0,0 +1,120 @@
+#ifndef _TDM_EXYNOS_H_
+#define _TDM_EXYNOS_H_
+
+#include "tdm_backend_exynos_types.h"
+
+/* display funcs */
+hal_tdm_error    exynos_display_get_capabilitiy(hal_tdm_display *display, hal_tdm_caps_display *caps);
+hal_tdm_output** exynos_display_get_outputs(hal_tdm_display *display, int *count, hal_tdm_error *error);
+hal_tdm_error    exynos_display_get_fd(hal_tdm_display *display, int *fd);
+hal_tdm_error    exynos_display_handle_events(hal_tdm_display *display);
+hal_tdm_error    exynos_display_get_pp_capability(hal_tdm_display *display, hal_tdm_caps_pp *caps);
+hal_tdm_error    exynos_display_get_capture_capability(hal_tdm_display *display, hal_tdm_caps_capture *caps);
+hal_tdm_pp      *exynos_display_create_pp(hal_tdm_display *display, hal_tdm_error *error);
+hal_tdm_pp      *exynos_display_create_pp_v4l2(hal_tdm_display *display, hal_tdm_error *error);
+
+/* output funcs */
+hal_tdm_error    exynos_output_get_capability(hal_tdm_output *output, hal_tdm_caps_output *caps);
+hal_tdm_error    exynos_output_set_property(hal_tdm_output *output, unsigned int id, hal_tdm_value value);
+hal_tdm_error    exynos_output_get_property(hal_tdm_output *output, unsigned int id, hal_tdm_value *value);
+hal_tdm_error    exynos_output_get_cur_msc(hal_tdm_output *output, uint *msc);
+hal_tdm_error    exynos_output_wait_vblank(hal_tdm_output *output, int interval, int sync, void *user_data);
+hal_tdm_error    exynos_output_set_vblank_handler(hal_tdm_output *output, hal_tdm_output_vblank_handler func);
+hal_tdm_error    exynos_output_commit(hal_tdm_output *output, int sync, void *user_data);
+hal_tdm_error    exynos_output_set_commit_handler(hal_tdm_output *output, hal_tdm_output_commit_handler func);
+hal_tdm_error    exynos_output_set_dpms(hal_tdm_output *output, hal_tdm_output_dpms dpms_value);
+hal_tdm_error    exynos_output_set_dpms_handler(hal_tdm_output *output, hal_tdm_output_dpms_handler func);
+hal_tdm_error    exynos_output_get_dpms(hal_tdm_output *output, hal_tdm_output_dpms *dpms_value);
+hal_tdm_error    exynos_output_set_mode(hal_tdm_output *output, const hal_tdm_output_mode *mode);
+hal_tdm_error    exynos_output_get_mode(hal_tdm_output *output, const hal_tdm_output_mode **mode);
+hal_tdm_capture *exynos_output_create_capture(hal_tdm_output *output, hal_tdm_error *error);
+hal_tdm_error    exynos_output_set_status_handler(hal_tdm_output *output, hal_tdm_output_status_handler func, void *user_data);
+hal_tdm_hwc     *exynos_output_get_hwc(hal_tdm_output *output, hal_tdm_error *error);
+
+/* hwc funcs */
+hal_tdm_hwc_window  *exynos_hwc_create_window(hal_tdm_hwc *hwc, hal_tdm_error *error);
+hal_tdm_error        exynos_hwc_get_video_supported_formats(hal_tdm_output *output, const tbm_format **formats, int *count);
+hal_tdm_error        exynos_hwc_get_capabilities(hal_tdm_hwc *hwc, hal_tdm_hwc_capability *capabilities);
+hal_tdm_error        exynos_hwc_get_available_properties(hal_tdm_hwc *hwc, const hal_tdm_prop **props, int *count);
+tbm_surface_queue_h  exynos_hwc_get_client_target_buffer_queue(hal_tdm_hwc *hwc, hal_tdm_error *error);
+hal_tdm_error        exynos_hwc_set_client_target_buffer(hal_tdm_hwc *hwc, tbm_surface_h buffer, hal_tdm_region damage);
+hal_tdm_error        exynos_hwc_validate(hal_tdm_hwc *hwc, hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types);
+hal_tdm_error        exynos_hwc_get_changed_composition_types(hal_tdm_hwc *hwc, uint32_t *num_elements, hal_tdm_hwc_window **hwc_wnds, hal_tdm_hwc_window_composition *composition_types);
+hal_tdm_error        exynos_hwc_accept_validation(hal_tdm_hwc *hwc);
+hal_tdm_error        exynos_hwc_commit(hal_tdm_hwc *hwc, int sync, void *user_data);
+hal_tdm_error        exynos_hwc_set_commit_handler(hal_tdm_hwc *hwc, hal_tdm_hwc_commit_handler func);
+
+/* hwc_window funcs */
+void           exynos_hwc_window_destroy(hal_tdm_hwc_window *hwc_window);
+hal_tdm_error  exynos_hwc_window_set_composition_type(hal_tdm_hwc_window *hwc_window, hal_tdm_hwc_window_composition composition_type);
+hal_tdm_error  exynos_hwc_window_set_buffer_damage(hal_tdm_hwc_window *hwc_window, hal_tdm_region damage);
+hal_tdm_error  exynos_hwc_window_set_info(hal_tdm_hwc_window *hwc_window, hal_tdm_hwc_window_info *info);
+hal_tdm_error  exynos_hwc_window_set_buffer(hal_tdm_hwc_window *hwc_window, tbm_surface_h surface);
+hal_tdm_error  exynos_hwc_window_set_property(hal_tdm_hwc_window *hwc_window, unsigned int id, hal_tdm_value value);
+hal_tdm_error  exynos_hwc_window_get_property(hal_tdm_hwc_window *hwc_window, unsigned int id, hal_tdm_value *value);
+hal_tdm_error  exynos_hwc_window_get_constraints(hal_tdm_hwc_window *hwc_window, int *constraints);
+hal_tdm_error  exynos_hwc_window_set_name(hal_tdm_hwc_window *hwc_window, const char *name);
+
+/* pp funcs */
+void           exynos_pp_destroy(hal_tdm_pp *pp);
+hal_tdm_error  exynos_pp_set_info(hal_tdm_pp *pp, hal_tdm_info_pp *info);
+hal_tdm_error  exynos_pp_attach(hal_tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst);
+hal_tdm_error  exynos_pp_commit(hal_tdm_pp *pp);
+hal_tdm_error  exynos_pp_set_done_handler(hal_tdm_pp *pp, hal_tdm_pp_done_handler func, void *user_data);
+
+void           exynos_display_destroy_pp_v4l2(hal_tdm_pp *pp);
+void           exynos_pp_v4l2_destroy(hal_tdm_pp *pp);
+hal_tdm_error  exynos_pp_v4l2_set_info(hal_tdm_pp *pp, hal_tdm_info_pp *info);
+hal_tdm_error  exynos_pp_v4l2_attach(hal_tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst);
+hal_tdm_error  exynos_pp_v4l2_commit(hal_tdm_pp *pp);
+hal_tdm_error  exynos_pp_v4l2_set_done_handler(hal_tdm_pp *pp, hal_tdm_pp_done_handler func, void *user_data);
+
+/* capture funcs */
+void           exynos_capture_destroy(hal_tdm_capture *capture);
+hal_tdm_error  exynos_capture_set_info(hal_tdm_capture *capture, hal_tdm_info_capture *info);
+hal_tdm_error  exynos_capture_attach(hal_tdm_capture *capture, tbm_surface_h buffer);
+hal_tdm_error  exynos_capture_commit(hal_tdm_capture *capture);
+hal_tdm_error  exynos_capture_set_done_handler(hal_tdm_pp *pp, hal_tdm_capture_done_handler func, void *user_data);
+
+
+/* exynos display */
+hal_tdm_error  tdm_exynos_display_create_output_list(tdm_exynos_display *display_data);
+void           tdm_exynos_display_destroy_output_list(tdm_exynos_display *display_data);
+hal_tdm_error  tdm_exynos_display_create_layer_list(tdm_exynos_display *display_data);
+hal_tdm_error  tdm_exynos_display_init_event_handling(tdm_exynos_display *display_data);
+void           tdm_exynos_display_deinit_event_handling(tdm_exynos_display *display_data);
+void           tdm_exynos_display_destroy_buffer_list(tdm_exynos_display *display_data);
+
+/* exynos output */
+tdm_exynos_layer * tdm_exynos_output_data_get_layer_data(tdm_exynos_output *output_data, int zpos);
+
+/* exynos layer_data */
+hal_tdm_error    tdm_exynos_layer_get_capability(tdm_exynos_layer *layer_data, tdm_exynos_caps_layer *caps);
+hal_tdm_error    tdm_exynos_layer_set_property(tdm_exynos_layer *layer_data, unsigned int id, hal_tdm_value value);
+hal_tdm_error    tdm_exynos_layer_get_property(tdm_exynos_layer *layer_data, unsigned int id, hal_tdm_value *value);
+hal_tdm_error    tdm_exynos_layer_set_info(tdm_exynos_layer *layer_data, tdm_exynos_layer_info *info);
+hal_tdm_error    tdm_exynos_layer_get_info(tdm_exynos_layer *layer_data, tdm_exynos_layer_info *info);
+hal_tdm_error    tdm_exynos_layer_set_buffer(tdm_exynos_layer *layer_data, tbm_surface_h buffer);
+hal_tdm_error    tdm_exynos_layer_unset_buffer(tdm_exynos_layer *layer_data);
+hal_tdm_error    tdm_exynos_display_get_drm_pp_permission(hal_tdm_display *display);
+
+/* exynos hwc */
+hal_tdm_error exynos_hwc_initailize_target_window(tdm_exynos_hwc *hwc_data, int width, int height);
+
+/* exynos pp */
+hal_tdm_error   tdm_exynos_get_pp_permission(tdm_exynos_display *display_data);
+hal_tdm_error   tdm_exynos_pp_get_capability(tdm_exynos_display *display_data, hal_tdm_caps_pp *caps);
+hal_tdm_pp     *tdm_exynos_pp_create(tdm_exynos_display *display_data, hal_tdm_error *error);
+void            tdm_exynos_pp_handler(struct tdm_pp_event *hw_ipp_p);
+hal_tdm_error  tdm_exynos_pp_task_done_handler(int fd, hal_tdm_event_loop_mask mask, void *user_data);
+hal_tdm_pp     *tdm_exynos_pp_v4l2_create(tdm_exynos_display *display_data, hal_tdm_error *error, int *fd1, int *fd2);
+void            tdm_exynos_pp_v4l2_reset(hal_tdm_pp *pp);
+hal_tdm_error   tdm_exynos_pp_v4l2_task_done_handler(int fd, hal_tdm_event_loop_mask mask, void *user_data);
+
+/* exynos capture */
+hal_tdm_error  tdm_exynos_capture_get_capability(tdm_exynos_display *display_data, hal_tdm_caps_capture *caps);
+hal_tdm_pp    *tdm_exynos_capture_create_output(tdm_exynos_display *display_data, hal_tdm_output *output, hal_tdm_error *error);
+void           tdm_exynos_capture_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_find_prop_id(unsigned int prop_id);
+
+#endif /* _TDM_EXYNOS_H_ */
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_backend_exynos_types.h b/src/libhal-backend-tdm-exynos-deconfb/tdm_backend_exynos_types.h
new file mode 100644 (file)
index 0000000..9d8f083
--- /dev/null
@@ -0,0 +1,286 @@
+#ifndef _TDM_EXYNOS_TYPES_H_
+#define _TDM_EXYNOS_TYPES_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <linux/fb.h>
+
+#include <drm.h>
+#include <drm_fourcc.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <xf86drmMode.h>
+
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+#include <tbm_surface_queue.h>
+
+#include <hal-common.h>
+#include <hal-tdm-types.h>
+#include <hal-tdm-interface.h>
+#include <pixman.h>
+
+#include "tdm_list.h"
+#include "tdm_exynos_format.h"
+#include "tdm_backend_log.h"
+#include "exynos_pp.h"
+#include "decon-fb.h"
+
+/* exynos module internal macros, structures, functions */
+
+typedef enum {
+       TDM_PROP_SET_AOD,
+       TDM_PROP_MAX,
+} tdm_property_list;
+
+typedef enum {
+       TDM_AOD_SET_CONFIG,
+       TDM_AOD_UPDATE_DATA,
+       TDM_AOD_CHANGE_STATE,
+} tdm_aod_request_type;
+
+typedef enum {
+       TDM_AOD_OFF,
+       TDM_AOD_ALPM,
+       TDM_AOD_HLPM,
+       TDM_AOD_SCLK_ANALOG,
+       TDM_AOD_SCLK_DIGITAL,
+} tdm_aod_mode;
+
+typedef enum {
+       TDM_AOD_DISABLE,
+       TDM_AOD_ENABLE,
+} tdm_aod_state;
+
+typedef struct _tdm_sc_analog_prop {
+       unsigned int center_x, center_y;
+       unsigned int hh, mm, ss, ms;
+       unsigned int update_rate;
+       tbm_bo h_bo, m_bo, s_bo;
+} tdm_sc_analog_prop;
+
+typedef struct _tdm_sc_digital_prop {
+       unsigned int circle_radius;
+       unsigned int circle1_x, circle1_y;
+       unsigned int circle2_x, circle2_y;
+       unsigned int circle_r, circle_g, circle_b;
+       unsigned int update_rate;
+} tdm_sc_digital_prop;
+
+typedef struct _tdm_aod_property {
+       tdm_aod_request_type req;
+       tdm_aod_mode mode;
+       union {
+               tdm_sc_analog_prop analog_info;
+               tdm_sc_digital_prop digital_info;
+               tdm_aod_state state;
+       };
+} tdm_aod_property;
+
+typedef struct _tdm_exynos_display tdm_exynos_display;
+typedef struct _tdm_exynos_output tdm_exynos_output;
+typedef struct _tdm_exynos_layer tdm_exynos_layer;
+typedef struct _tdm_exynos_hwc tdm_exynos_hwc;
+typedef struct _tdm_exynos_hwc_window tdm_exynos_hwc_window_data;
+typedef struct _tdm_exynos_vblank_data tdm_exynos_vblank_data;
+typedef struct _tdm_exynos_dpms_data tdm_exynos_dpms_data;
+
+typedef enum {
+       TDM_EXYNOS_LAYER_CAPABILITY_CURSOR         = (1 << 0), /**< cursor */
+       TDM_EXYNOS_LAYER_CAPABILITY_PRIMARY        = (1 << 1), /**< primary */
+       TDM_EXYNOS_LAYER_CAPABILITY_OVERLAY        = (1 << 2), /**< overlay */
+       TDM_EXYNOS_LAYER_CAPABILITY_GRAPHIC        = (1 << 4), /**< graphic */
+       TDM_EXYNOS_LAYER_CAPABILITY_VIDEO          = (1 << 5), /**< video */
+       TDM_EXYNOS_LAYER_CAPABILITY_SCALE          = (1 << 8), /**< if a layer_data has scale capability  */
+       TDM_EXYNOS_LAYER_CAPABILITY_TRANSFORM      = (1 << 9), /**< if a layer_data has transform capability  */
+       TDM_EXYNOS_LAYER_CAPABILITY_SCANOUT        = (1 << 10), /**< if a layer_data allows a scanout buffer only */
+       TDM_EXYNOS_LAYER_CAPABILITY_RESEVED_MEMORY = (1 << 11), /**< if a layer_data allows a reserved buffer only */
+       TDM_EXYNOS_LAYER_CAPABILITY_NO_CROP        = (1 << 12), /**< if a layer_data has no cropping capability */
+} tdm_exynos_layer_capability;
+
+struct _tdm_exynos_display
+{
+    drmEventContext evctx;
+
+    int drm_fd;
+    int output_count;
+
+    int hwc_mode;
+
+    struct list_head output_list;
+    struct list_head buffer_list;
+    bool drm_pp;
+    hal_tdm_pp *pp;
+    int pp_count;
+    int fd1;
+    int fd2;
+};
+
+struct _tdm_exynos_dpms_data {
+       tdm_exynos_output *output_data;
+       void *user_data;
+};
+
+typedef enum {
+        VBLANK_TYPE_WAIT,
+        VBLANK_TYPE_COMMIT,
+} vblank_type_t;
+
+struct _tdm_exynos_vblank_data {
+       vblank_type_t type;
+       tdm_exynos_output *output_data;
+       void *user_data;
+};
+
+typedef struct _tdm_exynos_display_buffer {
+       struct list_head link;
+
+       tbm_surface_h buffer;
+       int width;
+       unsigned int height;
+       unsigned int format;
+       unsigned int handles[4];
+       unsigned int fds[4];
+       unsigned int pitches[4];
+       unsigned int offsets[4];
+       unsigned int size;
+       unsigned int count;
+} tdm_exynos_display_buffer;
+
+struct _tdm_exynos_output {
+       struct list_head link;
+
+       /* data which are fixed at initializing */
+       tdm_exynos_display *display_data;
+       uint32_t pipe;
+       int count_modes;
+       hal_tdm_output_mode *output_modes;
+       hal_tdm_output_type connector_type;
+       unsigned int connector_type_id;
+       struct list_head layer_list;
+       tdm_exynos_layer *primary_layer;
+
+       hal_tdm_output_vblank_handler vblank_func;
+       hal_tdm_output_commit_handler commit_func;
+       hal_tdm_output_dpms_handler dpms_func;
+       hal_tdm_output_status_handler status_func;
+       hal_tdm_output_conn_status status;
+       void *status_user_data;
+       int mode_changed;
+       const hal_tdm_output_mode *current_mode;
+
+       int waiting_vblank_event;
+
+       char *fb_fd_name;
+       int fb_fd;
+
+       struct fb_var_screeninfo mi;
+
+       unsigned int prop_count;
+       hal_tdm_prop *props;
+       tdm_aod_property *aod_prop;
+
+       hal_tdm_output_dpms dpms_value;
+
+       /* hwc data */
+       tdm_exynos_hwc *hwc_data;
+};
+
+typedef struct _tdm_exynos_layer_info {
+       hal_tdm_info_config src_config;
+       hal_tdm_pos dst_pos;
+       hal_tdm_transform transform;
+} tdm_exynos_layer_info;
+
+typedef struct _tdm_exynos_caps_layer {
+       tdm_exynos_layer_capability capabilities;  /**< The capabilities of layer_data */
+
+       /**
+        * The z-order
+        * GRAPHIC layers are non-changeable. The zpos of GRAPHIC layers starts
+        * from 0. If there are 4 GRAPHIC layers, The zpos SHOULD be 0, 1, 2, 3.\n
+        * But the zpos of VIDEO layer_data is changeable by layer_set_video_pos() function
+        * of #tdm_func_layer. And The zpos of VIDEO layers is less than GRAPHIC
+        * layers or more than GRAPHIC layers.
+        * ie, ..., -2, -1, 4, 5, ... (if 0 <= GRAPHIC layer_data's zpos < 4).
+        * The zpos of VIDEO layers is @b relative. It doesn't need to start
+        * from -1 or 4. Let's suppose that there are two VIDEO layers.
+        * One has -2 zpos. Another has -4 zpos. Then -2 Video layer_data is higher
+        * than -4 VIDEO layer_data.
+       */
+       int zpos;
+
+       unsigned int format_count;      /**< The count of available formats */
+       tbm_format *formats;            /**< The @b newly-allocated array of formats. will be freed in frontend. */
+
+       unsigned int prop_count;        /**< The count of available properties */
+       hal_tdm_prop *props;                /**< The @b newly-allocated array of properties. will be freed in frontend. */
+} tdm_exynos_caps_layer;
+
+struct _tdm_exynos_layer {
+       struct list_head link;
+
+       /* data which are fixed at initializing */
+       tdm_exynos_display *display_data;
+       tdm_exynos_output *output_data;
+       tdm_exynos_layer_capability capabilities;
+       int zpos;
+
+       //list of exynos formats
+       int format_count;
+       tbm_format *formats;
+
+       /* not fixed data below */
+       tdm_exynos_layer_info info;
+       int info_changed;
+
+       tdm_exynos_display_buffer *display_buffer;
+       int display_buffer_changed;
+
+       /* current hw overlay setting */
+       struct decon_win_config win_cfg;
+       int enabled_flag;
+
+       hal_tdm_prop *props;
+       int prop_count;
+};
+
+struct _tdm_exynos_hwc {
+       tdm_exynos_hwc_window_data *target_hwc_window;
+
+       int need_validate;
+       int need_target_window;
+       int need_set_crtc;
+
+       int target_window_zpos;
+
+       tdm_exynos_output *output_data;
+       struct list_head hwc_window_list;
+
+       hal_tdm_hwc_commit_handler commit_func;
+};
+
+struct _tdm_exynos_hwc_window {
+       struct list_head link;
+
+       tdm_exynos_hwc *hwc_data;
+
+       hal_tdm_hwc_window_info info;
+       tbm_surface_h surface;
+       hal_tdm_hwc_window_composition client_type;
+       hal_tdm_hwc_window_composition validated_type;
+       int lzpos;
+
+       char name[HAL_TDM_NAME_LEN];
+};
+
+#endif /* _TDM_EXYNOS_TYPES_H_ */
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_backend_log.c b/src/libhal-backend-tdm-exynos-deconfb/tdm_backend_log.c
new file mode 100644 (file)
index 0000000..44d8508
--- /dev/null
@@ -0,0 +1,43 @@
+#include "tdm_backend_log.h"
+
+#undef LOG_TAG
+#define LOG_TAG "TDM_BACKEND"
+
+unsigned int tbm_log_debug_level = TDM_BACKEND_LOG_LEVEL_INFO;
+
+static void
+_tdm_backend_log_dlog_print(int level, const char *fmt, va_list arg)
+{
+       log_priority dlog_prio;
+
+       switch (level) {
+       case TDM_BACKEND_LOG_LEVEL_ERR:
+               dlog_prio = DLOG_ERROR;
+               break;
+       case TDM_BACKEND_LOG_LEVEL_WRN:
+               dlog_prio = DLOG_WARN;
+               break;
+       case TDM_BACKEND_LOG_LEVEL_INFO:
+               dlog_prio = DLOG_INFO;
+               break;
+       case TDM_BACKEND_LOG_LEVEL_DBG:
+               dlog_prio = DLOG_DEBUG;
+               break;
+       default:
+               return;
+       }
+       __dlog_vprint(LOG_ID_SYSTEM, dlog_prio, LOG_TAG, fmt, arg);
+}
+
+void
+tdm_backend_log_print(int level, const char *fmt, ...)
+{
+       va_list arg;
+
+       if (level > tbm_log_debug_level)
+               return;
+
+       va_start(arg, fmt);
+       _tdm_backend_log_dlog_print(level, fmt, arg);
+       va_end(arg);
+}
\ No newline at end of file
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_backend_log.h b/src/libhal-backend-tdm-exynos-deconfb/tdm_backend_log.h
new file mode 100644 (file)
index 0000000..3df1163
--- /dev/null
@@ -0,0 +1,106 @@
+/**************************************************************************
+
+libtbm_exynos
+
+Copyright 2021 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: SooChan Lim <sc1.lim@samsung.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sub license, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#ifndef __TDM_BACKEND_LOG_H__
+#define __TDM_BACKEND_LOG_H__
+
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <time.h>
+#include <dlog.h>
+
+enum {
+       TDM_BACKEND_LOG_LEVEL_NONE,
+       TDM_BACKEND_LOG_LEVEL_ERR,
+       TDM_BACKEND_LOG_LEVEL_WRN,
+       TDM_BACKEND_LOG_LEVEL_INFO,
+       TDM_BACKEND_LOG_LEVEL_DBG,
+};
+
+
+/* log level */
+void tdm_backend_log_print(int level, const char *fmt, ...);
+
+#define TDM_BACKEND_DBG(fmt, args...) \
+       do { \
+               struct timespec ts; \
+               clock_gettime(CLOCK_MONOTONIC, &ts); \
+               tdm_backend_log_print(TDM_BACKEND_LOG_LEVEL_DBG, "[%5d.%06d][%d][%s %d]"fmt, \
+                                         (int)ts.tv_sec, (int)ts.tv_nsec / 1000, \
+                                         (int)syscall(SYS_gettid), __FUNCTION__, __LINE__, ##args);  \
+       } while (0)
+
+#define TDM_BACKEND_INFO(fmt, args...) \
+       do { \
+               struct timespec ts; \
+               clock_gettime(CLOCK_MONOTONIC, &ts); \
+               tdm_backend_log_print(TDM_BACKEND_LOG_LEVEL_INFO, "[%5d.%06d][%d][%s %d]"fmt, \
+                                         (int)ts.tv_sec, (int)ts.tv_nsec / 1000, \
+                                         (int)syscall(SYS_gettid), __FUNCTION__, __LINE__, ##args);  \
+       } while (0)
+
+#define TDM_BACKEND_WRN(fmt, args...) \
+       do { \
+               struct timespec ts; \
+               clock_gettime(CLOCK_MONOTONIC, &ts); \
+               tdm_backend_log_print(TDM_BACKEND_LOG_LEVEL_WRN, "[%5d.%06d][%d][%s %d]"fmt, \
+                                         (int)ts.tv_sec, (int)ts.tv_nsec / 1000, \
+                                         (int)syscall(SYS_gettid), __FUNCTION__, __LINE__, ##args);  \
+       } while (0)
+
+#define TDM_BACKEND_ERR(fmt, args...) \
+       do { \
+               struct timespec ts; \
+               clock_gettime(CLOCK_MONOTONIC, &ts); \
+               tdm_backend_log_print(TDM_BACKEND_LOG_LEVEL_ERR, "[%5d.%06d][%d][%s %d]"fmt, \
+                                         (int)ts.tv_sec, (int)ts.tv_nsec / 1000, \
+                                         (int)syscall(SYS_gettid), __FUNCTION__, __LINE__, ##args);  \
+       } while (0)
+
+#define TDM_BACKEND_RETURN_IF_FAIL(cond) {\
+       if (!(cond)) {\
+               TDM_BACKEND_ERR("'%s' failed.\n", #cond);\
+               return;\
+       } \
+}
+#define TDM_BACKEND_RETURN_VAL_IF_FAIL(cond, val) {\
+       if (!(cond)) {\
+               TDM_BACKEND_ERR("'%s' failed.\n", #cond);\
+               return val;\
+       } \
+}
+#define TDM_BACKEND_GOTO_VAL_IF_FAIL(cond, val) {\
+       if (!(cond)) {\
+               TDM_BACKEND_ERR("'%s' failed.\n", #cond);\
+               goto val;\
+       } \
+}
+
+#endif /* __TDM_BACKEND_LOG_H__ */
\ No newline at end of file
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_capture.c b/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_capture.c
new file mode 100644 (file)
index 0000000..0633064
--- /dev/null
@@ -0,0 +1,880 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_exynos.h"
+
+typedef struct _tdm_exynos_capture_buffer {
+       int index;
+       tbm_surface_h ui_buffer;
+       tbm_surface_h buffer;
+       struct list_head link;
+} tdm_exynos_capture_buffer;
+
+typedef struct _tdm_exynos_pp_data {
+       tdm_exynos_display *display_data;
+
+       tdm_exynos_output *output_data;
+
+       hal_tdm_info_capture info;
+       int info_changed;
+
+       struct list_head pending_buffer_list;
+       struct list_head buffer_list;
+
+       struct {
+#if 0
+               tdm_event_loop_source *timer_source;
+#endif
+               unsigned int prop_id;
+
+               int startd;
+               int first_event;
+       } stream;
+
+       hal_tdm_capture_done_handler done_func;
+       void *done_user_data;
+
+       struct list_head link;
+} tdm_exynos_capture_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_find_prop_id(unsigned int prop_id)
+{
+       tdm_exynos_capture_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_data *capture_data)
+{
+       tdm_exynos_capture_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;
+}
+
+#if 0
+static hal_tdm_error
+_tdm_exynos_capture_stream_pp_set(tdm_exynos_capture_data *capture_data, tbm_surface_h ui_buffer)
+{
+       tdm_exynos_display *display_data = capture_data->display_data;
+       hal_tdm_info_capture *info = &capture_data->info;
+       struct tdm_pp_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 = TDM_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 = TDM_OPS_DST;
+       property.config[1].degree = info->transform % 4;
+       property.config[1].flip = (info->transform > 3) ? TDM_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(hal_tdm_size));
+       memcpy(&property.config[1].pos, &info->dst_config.pos, sizeof(hal_tdm_pos));
+       property.cmd = PP_CMD_M2M;
+       property.prop_id = capture_data->stream.prop_id;
+
+       TDM_BACKEND_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_BACKEND_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(display_data->drm_fd, DRM_IOCTL_TDM_PP_SET_PROPERTY, &property);
+       if (ret) {
+               TDM_BACKEND_ERR("failed: %m");
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       TDM_BACKEND_DBG("success. prop_id(%d) ", property.prop_id);
+       capture_data->stream.prop_id = property.prop_id;
+       return HAL_TDM_ERROR_NONE;
+}
+#endif
+
+static hal_tdm_error
+_tdm_exynos_capture_stream_pp_queue(tdm_exynos_capture_data *capture_data,
+                                                                       tdm_exynos_capture_buffer *b,
+                                                                       enum tdm_pp_buf_type type)
+{
+       tdm_exynos_display *display_data = capture_data->display_data;
+       struct tdm_pp_queue_buf buf;
+       int i, bo_num, ret = 0;
+
+       CLEAR(buf);
+       buf.prop_id = capture_data->stream.prop_id;
+       buf.ops_id = TDM_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 < TDM_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_BACKEND_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(display_data->drm_fd, DRM_IOCTL_TDM_PP_QUEUE_BUF, &buf);
+       if (ret) {
+               TDM_BACKEND_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 HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       CLEAR(buf);
+       buf.prop_id = capture_data->stream.prop_id;
+       buf.ops_id = TDM_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 < TDM_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_BACKEND_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(display_data->drm_fd, DRM_IOCTL_TDM_PP_QUEUE_BUF, &buf);
+       if (ret) {
+               TDM_BACKEND_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 HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       TDM_BACKEND_DBG("success. prop_id(%d)", buf.prop_id);
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_tdm_exynos_capture_stream_pp_cmd(tdm_exynos_capture_data *capture_data, enum tdm_pp_ctrl cmd)
+{
+       tdm_exynos_display *display_data = capture_data->display_data;
+       struct tdm_pp_cmd_ctrl ctrl;
+       int ret = 0;
+
+       ctrl.prop_id = capture_data->stream.prop_id;
+       ctrl.ctrl = cmd;
+
+       TDM_BACKEND_DBG("prop_id(%d) ctrl(%d). ", ctrl.prop_id, ctrl.ctrl);
+
+       ret = ioctl(display_data->drm_fd, DRM_IOCTL_TDM_PP_CMD_CTRL, &ctrl);
+       if (ret) {
+               TDM_BACKEND_ERR("failed. prop_id(%d) ctrl(%d). %m", ctrl.prop_id, ctrl.ctrl);
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       TDM_BACKEND_DBG("success. prop_id(%d) ", ctrl.prop_id);
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+void
+tdm_exynos_capture_stream_pp_handler(unsigned int prop_id, unsigned int *buf_idx,
+                                                                        unsigned int tv_sec, unsigned int tv_usec, void *data)
+{
+       tdm_exynos_capture_data *found = NULL, *d = NULL, *capture_data = data;
+       tdm_exynos_capture_buffer *b = NULL, *bb = NULL, *dequeued_buffer = NULL;
+
+       if (!capture_data || !buf_idx) {
+               TDM_BACKEND_ERR("invalid params");
+               return;
+       }
+
+       LIST_FOR_EACH_ENTRY(d, &capture_list, link) {
+               if (d == capture_data) {
+                       found = d;
+                       break;
+               }
+       }
+       if (!found)
+               return;
+
+       TDM_BACKEND_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_BACKEND_DBG("dequeued: %d", dequeued_buffer->index);
+                       break;
+               }
+       }
+
+       if (!dequeued_buffer) {
+               TDM_BACKEND_ERR("not found buffer index: %d", buf_idx[0]);
+               return;
+       }
+
+       if (!capture_data->stream.first_event) {
+               TDM_BACKEND_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);
+
+       tbm_surface_internal_unref(dequeued_buffer->ui_buffer);
+
+       free(dequeued_buffer);
+}
+
+#if 0
+static hal_tdm_error
+_tdm_exynos_capture_stream_timer_handler(void *user_data)
+{
+       tdm_exynos_capture_data *capture_data = user_data;
+       unsigned int ms = 1000 / capture_data->info.frequency;
+       tdm_exynos_capture_buffer *b = NULL, *bb = NULL;
+       tbm_surface_h ui_buffer = NULL;
+       hal_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 HAL_TDM_ERROR_NONE;
+
+       if (capture_data->info_changed) {
+               if (capture_data->stream.startd)
+                       _tdm_exynos_capture_stream_pp_cmd(capture_data, PP_CTRL_PAUSE);
+
+               ret = _tdm_exynos_capture_stream_pp_set(capture_data, ui_buffer);
+               if (ret < 0)
+                       return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &capture_data->pending_buffer_list, link) {
+               LIST_DEL(&b->link);
+               b->ui_buffer = tbm_surface_internal_ref(ui_buffer);
+               _tdm_exynos_capture_stream_pp_queue(capture_data, b, PP_BUF_ENQUEUE);
+               TDM_BACKEND_DBG("queued: %d", b->index);
+               LIST_ADDTAIL(&b->link, &capture_data->buffer_list);
+               break;
+       }
+
+       if (capture_data->info_changed) {
+               capture_data->info_changed = 0;
+
+               if (!capture_data->stream.startd) {
+                       capture_data->stream.startd = 1;
+                       _tdm_exynos_capture_stream_pp_cmd(capture_data, PP_CTRL_PLAY);
+               } else
+                       _tdm_exynos_capture_stream_pp_cmd(capture_data, PP_CTRL_RESUME);
+       }
+
+
+       return HAL_TDM_ERROR_NONE;
+}
+#endif
+
+#if 0
+static hal_tdm_error
+_tdm_exynos_capture_commit_stream(tdm_exynos_capture_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->display_data->dpy,
+                                                                                        _tdm_exynos_capture_stream_timer_handler,
+                                                                                        capture_data, NULL);
+                       TDM_BACKEND_RETURN_VAL_IF_FAIL(capture_data->stream.timer_source != NULL, HAL_TDM_ERROR_OUT_OF_MEMORY);
+       }
+
+       tdm_event_loop_source_timer_update(capture_data->stream.timer_source, ms);
+
+       return HAL_TDM_ERROR_NONE;
+}
+#endif
+
+static void
+_tdm_exynos_capture_oneshot_center_rect(int src_w, int src_h, int dst_w, int dst_h, hal_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_oneshot_rect_scale(int src_w, int src_h, int dst_w, int dst_h, hal_tdm_pos *scale)
+{
+       float ratio;
+       hal_tdm_pos center = {0,};
+
+       _tdm_exynos_capture_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_oneshot_get_showing_rect(hal_tdm_pos *out_rect, hal_tdm_pos *dst_rect, hal_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_oneshot_get_src_crop_info(tdm_exynos_capture_data *capture_data,
+                                                                                         tdm_exynos_layer *layer_data, hal_tdm_pos *src_crop, hal_tdm_pos *showing_rect)
+{
+       tdm_exynos_output *output_data = capture_data->output_data;
+       float ratio_x, ratio_y;
+       hal_tdm_pos out_rect;
+       hal_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_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_oneshot_get_dst_crop_info(tdm_exynos_capture_data *capture_data, tdm_exynos_layer *layer_data,
+                                                                                         hal_tdm_pos *dst_pos, hal_tdm_pos *showing_pos, hal_tdm_pos *dst_crop,
+                                                                                         hal_tdm_transform transform)
+{
+       tdm_exynos_output *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 == HAL_TDM_TRANSFORM_NORMAL || transform == HAL_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 == HAL_TDM_TRANSFORM_90 || transform == HAL_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 == HAL_TDM_TRANSFORM_180 || transform == HAL_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 == HAL_TDM_TRANSFORM_270 || transform == HAL_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_BACKEND_ERR("oneshot: get_crop unknown case error");
+       }
+}
+
+static pixman_format_code_t
+_tdm_exynos_pixman_format_get(tbm_format format)
+{
+       switch (format) {
+       case TBM_FORMAT_ARGB8888:
+               return PIXMAN_a8r8g8b8;
+       case TBM_FORMAT_XRGB8888:
+               return PIXMAN_x8r8g8b8;
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static hal_tdm_error
+_tdm_exynos_capture_convert_buffer(tbm_surface_h srcbuf, tbm_surface_h dstbuf,
+                                                 hal_tdm_pos *srcpos, hal_tdm_pos *dstpos,
+                                                 hal_tdm_transform transform, int over)
+{
+       tbm_surface_info_s src_info, dst_info;
+       pixman_image_t *src_img = NULL, *dst_img = NULL;
+       pixman_format_code_t src_format, dst_format;
+       double scale_x, scale_y;
+       int rotate_step, bos;
+       pixman_transform_t t;
+       struct pixman_f_transform ft;
+       pixman_op_t op;
+       int src_stride, dst_stride;
+       int buf_width, err;
+       hal_tdm_error ret = HAL_TDM_ERROR_OPERATION_FAILED;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(srcbuf != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(dstbuf != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       bos = tbm_surface_internal_get_num_bos(srcbuf);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(bos == 1, HAL_TDM_ERROR_OPERATION_FAILED);
+
+       bos = tbm_surface_internal_get_num_bos(dstbuf);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(bos == 1, HAL_TDM_ERROR_OPERATION_FAILED);
+
+       err = tbm_surface_map(srcbuf, TBM_OPTION_READ, &src_info);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(err == TBM_SURFACE_ERROR_NONE, HAL_TDM_ERROR_OPERATION_FAILED);
+
+       err = tbm_surface_map(dstbuf, TBM_OPTION_WRITE, &dst_info);
+       TDM_BACKEND_GOTO_VAL_IF_FAIL(err == TBM_SURFACE_ERROR_NONE, unmap_srcbuf);
+
+       /* not handle buffers which have 2 more gem handles */
+       TDM_BACKEND_GOTO_VAL_IF_FAIL(src_info.planes[0].ptr != NULL, unmap_dstbuf);
+       TDM_BACKEND_GOTO_VAL_IF_FAIL(dst_info.planes[0].ptr != NULL, unmap_dstbuf);
+
+       src_format = _tdm_exynos_pixman_format_get(src_info.format);
+       TDM_BACKEND_GOTO_VAL_IF_FAIL(src_format > 0, unmap_dstbuf);
+       dst_format = _tdm_exynos_pixman_format_get(dst_info.format);
+       TDM_BACKEND_GOTO_VAL_IF_FAIL(dst_format > 0, unmap_dstbuf);
+
+       buf_width = src_info.planes[0].stride >> 2;
+       src_stride = src_info.planes[0].stride;
+       src_img = pixman_image_create_bits(src_format, buf_width, src_info.height,
+                                                                          (uint32_t*)src_info.planes[0].ptr, src_stride);
+       TDM_BACKEND_GOTO_VAL_IF_FAIL(src_img, unref_img);
+
+       buf_width = dst_info.planes[0].stride >> 2;
+       dst_stride = dst_info.planes[0].stride;
+       dst_img = pixman_image_create_bits(dst_format, buf_width, dst_info.height,
+                                                                          (uint32_t*)dst_info.planes[0].ptr, dst_stride);
+       TDM_BACKEND_GOTO_VAL_IF_FAIL(dst_img, unref_img);
+
+       pixman_f_transform_init_identity(&ft);
+
+       if (transform & HAL_TDM_TRANSFORM_FLIPPED) {
+               pixman_f_transform_scale(&ft, NULL, -1, 1);
+               pixman_f_transform_translate(&ft, NULL, dstpos->w, 0);
+       }
+
+       rotate_step = transform & 0x3;
+       if (rotate_step > 0) {
+               int c, s, tx = 0, ty = 0;
+               switch (rotate_step) {
+               case 1:
+                       c = 0, s = -1, tx = -dstpos->w;
+                       break;
+               case 2:
+                       c = -1, s = 0, tx = -dstpos->w, ty = -dstpos->h;
+                       break;
+               case 3:
+                       c = 0, s = 1, ty = -dstpos->h;
+                       break;
+               }
+               pixman_f_transform_translate(&ft, NULL, tx, ty);
+               pixman_f_transform_rotate(&ft, NULL, c, s);
+       }
+
+       if (rotate_step % 2 == 0) {
+               scale_x = (double)srcpos->w / dstpos->w;
+               scale_y = (double)srcpos->h / dstpos->h;
+       } else {
+               scale_x = (double)srcpos->w / dstpos->h;
+               scale_y = (double)srcpos->h / dstpos->w;
+       }
+
+       pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
+       pixman_f_transform_translate(&ft, NULL, srcpos->x, srcpos->y);
+       pixman_transform_from_pixman_f_transform(&t, &ft);
+       pixman_image_set_transform(src_img, &t);
+
+       op = (!over) ? PIXMAN_OP_SRC : PIXMAN_OP_OVER;
+
+       pixman_image_composite(op, src_img, NULL, dst_img, 0, 0, 0, 0,
+                                                  dstpos->x, dstpos->y, dstpos->w, dstpos->h);
+
+       ret = HAL_TDM_ERROR_NONE;
+
+unref_img:
+       if (src_img)
+               pixman_image_unref(src_img);
+       if (dst_img)
+               pixman_image_unref(dst_img);
+unmap_dstbuf:
+       tbm_surface_unmap(dstbuf);
+unmap_srcbuf:
+       tbm_surface_unmap(srcbuf);
+
+       return ret;
+}
+
+static void
+_tdm_exynos_capture_oneshot_composite_layers_sw(tdm_exynos_capture_data *capture_data, tbm_surface_h buffer)
+{
+       tdm_exynos_output *output_data = capture_data->output_data;
+       tdm_exynos_layer *layer_data = NULL;
+       tbm_surface_info_s buf_info;
+       int err;
+
+       err = tbm_surface_get_info(buffer, &buf_info);
+       TDM_BACKEND_RETURN_IF_FAIL(err == TBM_SURFACE_ERROR_NONE);
+
+       LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
+               tbm_surface_h buf;
+               hal_tdm_pos dst_pos;
+               hal_tdm_pos showing_pos;
+               hal_tdm_pos src_crop;
+               hal_tdm_pos dst_crop;
+               hal_tdm_transform transform = HAL_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_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_oneshot_get_src_crop_info(capture_data, layer_data, &src_crop, &showing_pos);
+               _tdm_exynos_capture_oneshot_get_dst_crop_info(capture_data, layer_data, &dst_pos, &showing_pos, &dst_crop, transform);
+
+               TDM_BACKEND_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_exynos_capture_convert_buffer(buf, buffer,
+                                                                 &src_crop, &dst_crop, transform, 1);
+       }
+}
+
+static hal_tdm_error
+_tdm_exynos_capture_commit_oneshot(tdm_exynos_capture_data *capture_data)
+{
+       tdm_exynos_capture_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_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 HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+tdm_exynos_capture_get_capability(tdm_exynos_display *display_data, hal_tdm_caps_capture *caps)
+{
+       int i;
+
+       if (!caps) {
+               TDM_BACKEND_ERR("invalid params");
+               return HAL_TDM_ERROR_INVALID_PARAMETER;
+       }
+
+       caps->capabilities = HAL_TDM_CAPTURE_CAPABILITY_OUTPUT|
+                                                HAL_TDM_CAPTURE_CAPABILITY_ONESHOT;
+
+       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_BACKEND_ERR("alloc failed");
+                       return HAL_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 HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_capture*
+tdm_exynos_capture_create_output(tdm_exynos_display *display_data, hal_tdm_output *output, hal_tdm_error *error)
+{
+       tdm_exynos_capture_data *capture_data = calloc(1, sizeof(tdm_exynos_capture_data));
+       if (!capture_data) {
+               TDM_BACKEND_ERR("alloc failed");
+               if (error)
+                       *error = HAL_TDM_ERROR_OUT_OF_MEMORY;
+               return NULL;
+       }
+
+       capture_data->display_data = display_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_BACKEND_DBG("capture(%p) create", capture_data);
+
+       return capture_data;
+}
+
+void
+exynos_capture_destroy(hal_tdm_capture *capture)
+{
+       tdm_exynos_capture_data *capture_data = capture;
+       tdm_exynos_capture_buffer *b = NULL, *bb = NULL;
+
+       if (!capture_data)
+               return;
+
+       TDM_BACKEND_DBG("capture(%p) destroy", capture_data);
+
+#if 0
+       if (capture_data->stream.timer_source)
+               tdm_event_loop_source_remove(capture_data->stream.timer_source);
+#endif
+
+       if (capture_data->stream.prop_id)
+               _tdm_exynos_capture_stream_pp_cmd(capture_data, PP_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);
+               tbm_surface_internal_unref(b->ui_buffer);
+               _tdm_exynos_capture_stream_pp_queue(capture_data, b, PP_BUF_DEQUEUE);
+               free(b);
+       }
+
+       LIST_DEL(&capture_data->link);
+
+       free(capture_data);
+}
+
+hal_tdm_error
+exynos_capture_set_info(hal_tdm_capture *capture, hal_tdm_info_capture *info)
+{
+       tdm_exynos_capture_data *capture_data = capture;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(capture_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(info, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       capture_data->info = *info;
+       capture_data->info_changed = 1;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_capture_attach(hal_tdm_capture *capture, tbm_surface_h buffer)
+{
+       tdm_exynos_capture_data *capture_data = capture;
+       tdm_exynos_capture_buffer *b;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(capture_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(buffer, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       b = calloc(1, sizeof(tdm_exynos_capture_buffer));
+       if (!b) {
+               TDM_BACKEND_ERR("alloc failed");
+               return HAL_TDM_ERROR_NONE;
+       }
+
+       LIST_ADDTAIL(&b->link, &capture_data->pending_buffer_list);
+
+       b->index = _get_index(capture_data);
+       b->buffer = buffer;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_capture_commit(hal_tdm_capture *capture)
+{
+       tdm_exynos_capture_data *capture_data = capture;
+       hal_tdm_error ret;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(capture_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       if (capture_data->info.type == HAL_TDM_CAPTURE_TYPE_ONESHOT)
+               ret = _tdm_exynos_capture_commit_oneshot(capture_data);
+       else
+#if 0
+               ret = _tdm_exynos_capture_commit_stream(capture_data);
+#else
+               ret = HAL_TDM_ERROR_NOT_IMPLEMENTED;
+#endif
+
+       return ret;
+}
+
+hal_tdm_error
+exynos_capture_set_done_handler(hal_tdm_capture *capture, hal_tdm_capture_done_handler func, void *user_data)
+{
+       tdm_exynos_capture_data *capture_data = capture;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(capture_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       capture_data->done_func = func;
+       capture_data->done_user_data = user_data;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_display.c b/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_display.c
new file mode 100644 (file)
index 0000000..d70e0ac
--- /dev/null
@@ -0,0 +1,1866 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_exynos.h"
+
+#define MIN_WIDTH   32
+#define LAYER_COUNT_PER_OUTPUT   3
+#ifdef HAVE_FB_VBLANK
+/** @TODO fb event struct */
+#else
+typedef struct drm_event hw_event_t;
+#endif
+
+#define FB_DEV_LCD  "/dev/fb0"
+
+typedef struct _Drm_Event_Context {
+       void (*vblank_handler)(int fd, unsigned int sequence, unsigned int tv_sec,
+                                                  unsigned int tv_usec, void *user_data);
+       void (*pp_handler)(int fd, unsigned int  prop_id, unsigned int *buf_idx,
+                                          unsigned int  tv_sec, unsigned int  tv_usec, void *user_data);
+} Drm_Event_Context;
+
+tbm_format win0_formats[] = {
+       TBM_FORMAT_XRGB8888,
+       TBM_FORMAT_ARGB8888,
+};
+
+tbm_format win1_formats[] = {
+       TBM_FORMAT_XRGB8888,
+       TBM_FORMAT_ARGB8888,
+};
+
+tbm_format win2_formats[] = {
+       TBM_FORMAT_XRGB8888,
+       TBM_FORMAT_ARGB8888,
+};
+
+static hal_tdm_prop tdm_exynos_props[] = {
+       { TDM_PROP_SET_AOD, "set_aod"},
+};
+
+#if 0
+static hal_tdm_error
+check_hw_restriction(unsigned int output_w, unsigned int buf_w,
+                                        unsigned int src_x, unsigned int src_w, unsigned int dst_x, unsigned int dst_w,
+                                        unsigned int *new_src_x, unsigned int *new_src_w,
+                                        unsigned int *new_dst_x, unsigned int *new_dst_w)
+{
+       int start, end, diff;
+       int virtual_screen;
+
+       *new_src_x = src_x;
+       *new_src_w = src_w;
+       *new_dst_x = dst_x;
+       *new_dst_w = dst_w;
+
+       if (buf_w < MIN_WIDTH || buf_w % 2) {
+               TDM_BACKEND_ERR("buf_w(%d) not 2's multiple or less than %d", buf_w, MIN_WIDTH);
+               return HAL_TDM_ERROR_BAD_REQUEST;
+       }
+
+       if (src_x > dst_x || ((dst_x - src_x) + buf_w) > output_w)
+               virtual_screen = 1;
+       else
+               virtual_screen = 0;
+
+       start = (dst_x < 0) ? 0 : dst_x;
+       end = ((dst_x + dst_w) > output_w) ? output_w : (dst_x + dst_w);
+
+       /* check window minimun width */
+       if ((end - start) < MIN_WIDTH) {
+               TDM_BACKEND_ERR("visible_w(%d) less than %d", end - start, MIN_WIDTH);
+               return HAL_TDM_ERROR_BAD_REQUEST;
+       }
+
+       if (!virtual_screen) {
+               /* Pagewidth of window (= 8 byte align / bytes-per-pixel ) */
+               if ((end - start) % 2)
+                       end--;
+       } else {
+               /* You should align the sum of PAGEWIDTH_F and OFFSIZE_F double-word (8 byte) boundary. */
+               if (end % 2)
+                       end--;
+       }
+
+       *new_dst_x = start;
+       *new_dst_w = end - start;
+       *new_src_w = *new_dst_w;
+       diff = start - dst_x;
+       *new_src_x += diff;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(*new_src_w > 0, HAL_TDM_ERROR_BAD_REQUEST);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(*new_dst_w > 0, HAL_TDM_ERROR_BAD_REQUEST);
+
+       if (src_x != *new_src_x || src_w != *new_src_w || dst_x != *new_dst_x ||
+           dst_w != *new_dst_w)
+               TDM_BACKEND_DBG("=> buf_w(%d) src(%d,%d) dst(%d,%d), virt(%d) start(%d) end(%d)",
+                               buf_w, *new_src_x, *new_src_w, *new_dst_x, *new_dst_w, virtual_screen, start,
+                               end);
+
+       return HAL_TDM_ERROR_NONE;
+}
+#endif
+
+static tdm_exynos_display_buffer *
+_tdm_exynos_display_find_buffer(tdm_exynos_display *display_data, tbm_surface_h buffer)
+{
+       tdm_exynos_display_buffer *display_buffer = NULL;
+
+       LIST_FOR_EACH_ENTRY(display_buffer, &display_data->buffer_list, link) {
+               if (display_buffer->buffer == buffer)
+                       return display_buffer;
+       }
+
+       return NULL;
+}
+
+
+static inline uint32_t
+_get_refresh(struct fb_var_screeninfo *timing)
+{
+       uint32_t pixclock, hfreq, htotal, vtotal;
+
+       pixclock = PICOS2KHZ(timing->pixclock) * 1000;
+
+       htotal = timing->xres + timing->right_margin + timing->hsync_len + timing->left_margin;
+       vtotal = timing->yres + timing->lower_margin + timing->vsync_len + timing->upper_margin;
+
+       if (timing->vmode & FB_VMODE_INTERLACED)
+               vtotal /= 2;
+       if (timing->vmode & FB_VMODE_DOUBLE)
+               vtotal *= 2;
+
+       hfreq = pixclock / htotal;
+       return hfreq / vtotal;
+}
+
+/*
+ * Convert fb_var_screeninfo to hal_tdm_output_mode
+ */
+static inline void
+_tdm_exynos_display_to_tdm_mode(struct fb_var_screeninfo *timing,
+                                                                                hal_tdm_output_mode  *mode)
+{
+       if (!timing->pixclock)
+               return;
+
+       mode->clock = timing->pixclock / 1000;
+       mode->vrefresh = _get_refresh(timing);
+       mode->hdisplay = timing->xres;
+       mode->hsync_start = mode->hdisplay + timing->right_margin;
+       mode->hsync_end = mode->hsync_start + timing->hsync_len;
+       mode->htotal = mode->hsync_end + timing->left_margin;
+
+       mode->vdisplay = timing->yres;
+       mode->vsync_start = mode->vdisplay + timing->lower_margin;
+       mode->vsync_end = mode->vsync_start + timing->vsync_len;
+       mode->vtotal = mode->vsync_end + timing->upper_margin;
+
+       mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+
+       if (timing->vmode & FB_VMODE_INTERLACED)
+               mode->flags |= DRM_MODE_FLAG_INTERLACE;
+
+       if (timing->vmode & FB_VMODE_DOUBLE)
+               mode->flags |= DRM_MODE_FLAG_DBLSCAN;
+
+       int interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+       snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d%s", mode->hdisplay,
+                        mode->vdisplay, interlaced ? "i" : "");
+}
+
+static int
+_localdrmWaitVBlank(int fd, drmVBlank *vbl)
+{
+       struct timespec timeout, cur;
+       int ret;
+
+       ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
+       if (ret < 0) {
+               TDM_BACKEND_ERR("clock_gettime failed: %s", strerror(errno));
+               goto out;
+       }
+       timeout.tv_sec++;
+
+       do {
+               ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
+               vbl->request.type &= ~DRM_VBLANK_RELATIVE;
+               if (ret && errno == EINTR) {
+                       clock_gettime(CLOCK_MONOTONIC, &cur);
+                       /* Timeout after 1s */
+                       if (cur.tv_sec > timeout.tv_sec + 1 ||
+                           (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
+                            timeout.tv_nsec)) {
+                               errno = EBUSY;
+                               ret = -1;
+                               break;
+                       }
+               }
+       } while (ret && errno == EINTR);
+
+out:
+       return ret;
+}
+
+static hal_tdm_error
+_tdm_exynos_display_wait_sync(int fd, int pipe)
+{
+       drmVBlank vbl;
+       int ret = HAL_TDM_ERROR_NONE;
+
+       vbl.request.type = DRM_VBLANK_NEXTONMISS;
+       if (pipe > 0)
+               vbl.request.type |= DRM_VBLANK_SECONDARY;
+
+       vbl.request.sequence = 0;
+       vbl.request.signal = 0;
+
+       if (_localdrmWaitVBlank(fd, &vbl)) {
+               TDM_BACKEND_ERR("get vblank counter failed: %m");
+               ret = HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       return ret;
+}
+
+static hal_tdm_error
+_tdm_exynos_display_get_cur_msc(int fd, int pipe, uint *msc)
+{
+       drmVBlank vbl;
+
+       vbl.request.type = DRM_VBLANK_RELATIVE;
+       if (pipe > 0)
+               vbl.request.type |= DRM_VBLANK_SECONDARY;
+
+       vbl.request.sequence = 0;
+       if (_localdrmWaitVBlank(fd, &vbl)) {
+               TDM_BACKEND_ERR("get vblank counter failed: %m");
+               *msc = 0;
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       *msc = vbl.reply.sequence;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_tdm_exynos_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data)
+{
+       drmVBlank vbl;
+
+       vbl.request.type =  DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
+       if (pipe > 0)
+               vbl.request.type |= DRM_VBLANK_SECONDARY;
+
+       vbl.request.sequence = *target_msc;
+       vbl.request.signal = (unsigned long)(uintptr_t)data;
+
+       if (_localdrmWaitVBlank(fd, &vbl)) {
+               *target_msc = 0;
+               TDM_BACKEND_ERR("wait vblank failed: %m");
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       *target_msc = vbl.reply.sequence;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_tdm_exynos_display_layer_disable(tdm_exynos_layer *layer_data)
+{
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_OPERATION_FAILED);
+
+       if (layer_data->enabled_flag) {
+               memset(&layer_data->win_cfg, 0, sizeof(struct decon_win_config));
+               layer_data->enabled_flag = 0;
+       }
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+_tdm_exynos_output_update_status(tdm_exynos_output *output_data,
+                                                                hal_tdm_output_conn_status status)
+{
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       if (output_data->status == status)
+               return HAL_TDM_ERROR_NONE;
+
+       output_data->status = status;
+
+       if (output_data->status_func)
+               output_data->status_func(output_data, status,
+                                                                output_data->status_user_data);
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_tdm_exynos_display_do_commit(tdm_exynos_output *output_data)
+{
+       hal_tdm_error res = HAL_TDM_ERROR_NONE;
+       tdm_exynos_display *display_data = NULL;
+       tdm_exynos_layer *layer_data = NULL;
+       struct decon_win_config_data win_data;
+       int layer_index = 0;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_OPERATION_FAILED);
+       display_data = output_data->display_data;
+
+       memset(&win_data, 0x00, sizeof(struct decon_win_config_data));
+
+       LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
+               if (!layer_data->display_buffer_changed && !layer_data->info_changed)
+                       continue;
+               if (layer_data->display_buffer) {
+                       layer_index = layer_data->zpos;
+
+                       win_data.config[layer_index].src.f_w = layer_data->display_buffer->width;
+                       win_data.config[layer_index].src.f_h = layer_data->display_buffer->height;
+                       win_data.config[layer_index].src.x = layer_data->info.src_config.pos.x;
+                       win_data.config[layer_index].src.y = layer_data->info.src_config.pos.y;
+                       win_data.config[layer_index].src.w = layer_data->info.src_config.pos.w;
+                       win_data.config[layer_index].src.h = layer_data->info.src_config.pos.h;
+
+                       win_data.config[layer_index].dst.f_w = layer_data->display_buffer->width;
+                       win_data.config[layer_index].dst.f_h = layer_data->display_buffer->height;
+                       win_data.config[layer_index].dst.x = layer_data->info.dst_pos.x;
+                       win_data.config[layer_index].dst.y = layer_data->info.dst_pos.y;
+                       win_data.config[layer_index].dst.w = layer_data->info.dst_pos.w;
+                       win_data.config[layer_index].dst.h = layer_data->info.dst_pos.h;
+                       win_data.config[layer_index].blending = layer_index ?
+                               DECON_BLENDING_PREMULT : DECON_BLENDING_NONE;
+                       win_data.config[layer_index].fence_fd = -1;
+                       win_data.config[layer_index].plane_alpha = 255;
+                       win_data.config[layer_index].idma_type = layer_index;
+
+                       if (display_data->drm_pp)
+                               win_data.config[layer_index].format = tdm_exynos_format_to_decon_format(layer_data->display_buffer->format);
+                       else
+                               win_data.config[layer_index].format = DECON_PIXEL_FORMAT_BGRA_8888;
+
+                       win_data.config[layer_index].state = DECON_WIN_STATE_BUFFER;
+                       win_data.config[layer_index].fd_idma[0] = layer_data->display_buffer->fds[0];
+
+                       if (memcmp(&layer_data->win_cfg, &win_data.config[layer_index], sizeof(struct decon_win_config)) != 0) {
+                               TDM_BACKEND_DBG("S3CFB_WIN_CONFIG(%d) rect:%dx%d+%d+%d size:%dx%d\n",
+                                               layer_index,
+                                               win_data.config[layer_index].dst.w, win_data.config[layer_index].dst.h,
+                                               win_data.config[layer_index].dst.x, win_data.config[layer_index].dst.y,
+                                               win_data.config[layer_index].dst.f_w, win_data.config[layer_index].dst.f_h);
+                               memcpy(&layer_data->win_cfg, &win_data.config[layer_index], sizeof(struct decon_win_config));
+                       }
+
+                       layer_data->enabled_flag = 1;
+               } else {
+                       _tdm_exynos_display_layer_disable(layer_data);
+               }
+       }
+
+       if (output_data->mode_changed) {
+               _tdm_exynos_output_update_status(output_data, HAL_TDM_OUTPUT_CONN_STATUS_MODE_SETTED);
+               output_data->mode_changed = 0;
+       }
+
+       TDM_BACKEND_DBG("S3CFB_WIN_CONFIG fd:%d\n", win_data.config[layer_index].fd_idma[0]);
+
+       if (ioctl(output_data->fb_fd, S3CFB_WIN_CONFIG, &win_data)) {
+               TDM_BACKEND_ERR("S3CFB_WIN_CONFIG error: %s \n", strerror(errno));
+               res = HAL_TDM_ERROR_OPERATION_FAILED;
+       } else {
+               //save enable layers
+//            enable_layers |= ov_disp.layer_index;
+       }
+
+       return res;
+}
+
+#if 0
+static void
+_tdm_exynos_display_cb_pp(int fd, unsigned int prop_id, unsigned int *buf_idx,
+                                                 unsigned int tv_sec, unsigned int tv_usec,
+                                                 void *user_data)
+{
+       tdm_exynos_pp_handler(prop_id, buf_idx, tv_sec, tv_usec, user_data);
+}
+#endif
+#if 0
+static int
+_tdm_exynos_display_events_handle(int fd, Drm_Event_Context *evctx)
+{
+#define MAX_BUF_SIZE    1024
+
+       char buffer[MAX_BUF_SIZE];
+       unsigned int len, i;
+       struct drm_event *e;
+
+       /* The DRM read semantics guarantees that we always get only
+        * complete events. */
+       len = read(fd, buffer, sizeof buffer);
+       if (len == 0) {
+               TDM_BACKEND_WRN("warning: the size of the drm_event is 0.");
+               return 0;
+       }
+       if (len < sizeof * e) {
+               TDM_BACKEND_WRN("warning: the size of the drm_event is less than drm_event structure.");
+               return -1;
+       }
+#if 0
+       if (len > MAX_BUF_SIZE - sizeof(struct drm_exynos_ipp_event)) {
+               TDM_BACKEND_WRN("warning: the size of the drm_event can be over the maximum size.");
+               return -1;
+       }
+#endif
+       i = 0;
+       while (i < len) {
+               e = (struct drm_event *) &buffer[i];
+               switch (e->type) {
+               case DRM_EVENT_VBLANK: {
+                       struct drm_event_vblank *vblank;
+
+                       if (evctx->vblank_handler == NULL)
+                               break;
+
+                       vblank = (struct drm_event_vblank *)e;
+                       TDM_BACKEND_DBG("******* VBLANK *******");
+                       evctx->vblank_handler(fd, vblank->sequence,
+                                                                 vblank->tv_sec, vblank->tv_usec,
+                                                                 (void *)((unsigned long)vblank->user_data));
+                       TDM_BACKEND_DBG("******* VBLANK *******...");
+               }
+               break;
+#if 0
+               case DRM_EXYNOS_IPP_EVENT: {
+                       struct drm_exynos_ipp_event *ipp;
+
+                       if (evctx->pp_handler == NULL)
+                               break;
+
+                       ipp = (struct drm_exynos_ipp_event *)e;
+                       TDM_BACKEND_DBG("******* PP *******");
+                       evctx->pp_handler(fd, ipp->prop_id, ipp->buf_id,
+                                                         ipp->tv_sec, ipp->tv_usec,
+                                                         (void *)((unsigned long)ipp->user_data));
+                       TDM_BACKEND_DBG("******* PP *******...");
+               }
+#endif
+               break;
+               case DRM_EVENT_FLIP_COMPLETE:
+                       /* do nothing for flip complete */
+                       break;
+               default:
+                       break;
+               }
+               i += e->length;
+       }
+
+       return 0;
+}
+#endif
+
+static hal_tdm_error
+_tdm_exynos_display_create_layer_list_LCD(tdm_exynos_output *output_data)
+{
+       int idx;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       tdm_exynos_display *display_data = output_data->display_data;
+       tdm_exynos_layer *win[LAYER_COUNT_PER_OUTPUT];
+
+       for (idx = 0; idx < LAYER_COUNT_PER_OUTPUT; idx++) {
+               win[idx] = calloc(1, sizeof(tdm_exynos_layer));
+               if (!win[idx]) {
+                       TDM_BACKEND_ERR("alloc failed win[%d]", idx);
+                       goto err;
+               }
+
+               win[idx]->display_data = display_data;
+               win[idx]->output_data = output_data;
+               win[idx]->zpos = idx;
+
+               if (idx == 0) {
+                       win[idx]->capabilities = TDM_EXYNOS_LAYER_CAPABILITY_OVERLAY |
+                                                                        TDM_EXYNOS_LAYER_CAPABILITY_GRAPHIC;
+                       win[idx]->format_count = sizeof(win0_formats) / sizeof(int);
+                       win[idx]->formats = win0_formats;
+               } else if (idx == 1) {
+                       win[idx]->capabilities = TDM_EXYNOS_LAYER_CAPABILITY_PRIMARY |
+                                                                        TDM_EXYNOS_LAYER_CAPABILITY_GRAPHIC;
+                       win[idx]->format_count = sizeof(win1_formats) / sizeof(int);
+                       win[idx]->formats = win1_formats;
+                       output_data->primary_layer = win[idx];
+               } else { /* idx == 2 */
+                       win[idx]->capabilities = TDM_EXYNOS_LAYER_CAPABILITY_OVERLAY |
+                                                                        TDM_EXYNOS_LAYER_CAPABILITY_GRAPHIC;
+                       win[idx]->format_count = sizeof(win2_formats) / sizeof(int);
+                       win[idx]->formats = win2_formats;
+               }
+
+               TDM_BACKEND_DBG("win[%d](%p) capabilities(%x)", idx, win[idx], win[idx]->capabilities);
+
+               LIST_ADDTAIL(&win[idx]->link, &output_data->layer_list);
+       }
+
+       return HAL_TDM_ERROR_NONE;
+err:
+       if (!LIST_IS_EMPTY(&output_data->layer_list)) {
+               tdm_exynos_layer *l = NULL, *ll = NULL;
+
+               LIST_FOR_EACH_ENTRY_SAFE(l, ll, &output_data->layer_list, link) {
+                       LIST_DEL(&l->link);
+                       free(l);
+               }
+       }
+
+       return HAL_TDM_ERROR_OUT_OF_MEMORY;
+}
+
+hal_tdm_error
+_tdm_exynos_display_output_update(tdm_exynos_output *output)
+{
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output->fb_fd_name, HAL_TDM_ERROR_INVALID_PARAMETER);
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+       if (!output->fb_fd)
+               output->fb_fd = open(output->fb_fd_name, O_RDWR, 0);
+
+       if (output->fb_fd <= 0) {
+               TDM_BACKEND_ERR("failed to get fb_fd");
+               goto failed;
+       }
+
+       if (ioctl(output->fb_fd, FBIOGET_VSCREENINFO, &output->mi) == -1) {
+               ret = HAL_TDM_ERROR_OPERATION_FAILED;
+               TDM_BACKEND_ERR("failed to FBIOGET_VSCREENINFO");
+               goto failed;
+       }
+
+       output->status = HAL_TDM_OUTPUT_CONN_STATUS_CONNECTED;
+
+       if (output->mi.activate & FB_ACTIVATE_VBL)
+               output->dpms_value = HAL_TDM_OUTPUT_DPMS_ON;
+       else
+               output->dpms_value = HAL_TDM_OUTPUT_DPMS_OFF;
+
+       return ret;
+
+
+failed:
+
+       if (output->fb_fd > 0) {
+               close(output->fb_fd);
+               output->fb_fd = 0;
+       }
+       output->dpms_value = HAL_TDM_OUTPUT_DPMS_OFF;
+       output->status = HAL_TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
+       return ret;
+}
+
+static void
+_tdm_exynos_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
+{
+       tdm_exynos_display *display_data;
+       tdm_exynos_display_buffer *display_buffer;
+       tdm_exynos_layer *layer_data = NULL;
+       tdm_exynos_output *output_data = NULL;
+       if (!user_data) {
+               TDM_BACKEND_ERR("no user_data");
+               return;
+       }
+       if (!buffer) {
+               TDM_BACKEND_ERR("no buffer");
+               return;
+       }
+
+       display_data = (tdm_exynos_display *)user_data;
+
+       display_buffer = _tdm_exynos_display_find_buffer(display_data, buffer);
+       if (!display_buffer) {
+               TDM_BACKEND_ERR("no display_buffer");
+               return;
+       }
+
+       LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link) {
+               LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
+                       if (display_buffer == layer_data->display_buffer) {
+                               _tdm_exynos_display_layer_disable(layer_data);
+                               layer_data->display_buffer = NULL;
+                       }
+               }
+       }
+
+       TDM_BACKEND_DBG("destroy buffer fd:%d", display_buffer->fds[0]);
+
+       LIST_DEL(&display_buffer->link);
+       free(display_buffer);
+}
+
+static tdm_exynos_display_buffer *
+_tdm_exynos_display_create_buffer(tdm_exynos_display *display_data, tbm_surface_h buffer, hal_tdm_error *err)
+{
+       tdm_exynos_display_buffer *display_buffer = NULL;
+       int ret, count, i;
+
+       display_buffer = calloc(1, sizeof(tdm_exynos_display_buffer));
+       if (!display_buffer) {
+               TDM_BACKEND_ERR("alloc failed");
+               if (err)
+                       *err = HAL_TDM_ERROR_OUT_OF_MEMORY;
+               return NULL;
+       }
+
+       display_buffer->buffer = buffer;
+
+       ret = tbm_surface_internal_add_destroy_handler(buffer, _tdm_exynos_display_cb_destroy_buffer, display_data);
+       if (ret == 0) {
+               TDM_BACKEND_ERR("add destroy handler fail");
+               free(display_buffer);
+               if (err)
+                       *err = HAL_TDM_ERROR_OPERATION_FAILED;
+               return NULL;
+       }
+
+       display_buffer->width = tbm_surface_get_width(buffer);
+       display_buffer->height = tbm_surface_get_height(buffer);
+       display_buffer->format = tbm_surface_get_format(buffer);
+       display_buffer->count = tbm_surface_internal_get_num_bos(buffer);
+       count = tbm_surface_internal_get_num_planes(display_buffer->format);
+       TDM_BACKEND_DBG("create buffer:%p %dx%d %c%c%c%c bo_num:%d plane_num:%d",
+                       buffer, display_buffer->width, display_buffer->height,
+                       FOURCC_STR(display_buffer->format), display_buffer->count, count);
+
+       for (i = 0; i < count; i++) {
+               int bo_idx = 0;
+               tbm_bo bo = NULL;
+
+               bo_idx = tbm_surface_internal_get_plane_bo_idx(buffer, i);
+               bo = tbm_surface_internal_get_bo(buffer, bo_idx);
+               display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+               display_buffer->fds[i] = tbm_bo_get_handle(bo, TBM_DEVICE_3D).u32;
+
+               tbm_surface_internal_get_plane_data(buffer, i, &display_buffer->size,
+                                                                                       &display_buffer->offsets[i],
+                                                                                       &display_buffer->pitches[i]);
+               TDM_BACKEND_DBG("  create buffer:%p plane%d(size:%d offset:%d pitch:%d) bo%d(fd:%d handle:%d)",
+                               buffer, i, display_buffer->size, display_buffer->offsets[i],
+                               display_buffer->pitches[i], bo_idx, display_buffer->fds[i],
+                               display_buffer->handles[i]);
+       }
+
+       if (IS_RGB(display_buffer->format))
+               display_buffer->width = display_buffer->pitches[0] >> 2;
+       else
+               display_buffer->width = display_buffer->pitches[0];
+
+       LIST_ADDTAIL(&display_buffer->link, &display_data->buffer_list);
+
+       if (err)
+               *err = HAL_TDM_ERROR_NONE;
+
+       return display_buffer;
+}
+
+tdm_exynos_output *
+_tdm_exynos_display_create_output_LCD(tdm_exynos_display *display_data)
+{
+       tdm_exynos_output *output_data = NULL;
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+       output_data = calloc(1, sizeof(tdm_exynos_output));
+       if (!output_data) {
+               TDM_BACKEND_ERR("alloc failed");
+               return NULL;
+       }
+
+       output_data->display_data = display_data;
+       output_data->pipe = 0;
+       output_data->connector_type = HAL_TDM_OUTPUT_TYPE_DSI;
+       output_data->count_modes = 0;
+       output_data->fb_fd_name = FB_DEV_LCD;
+       LIST_INITHEAD(&output_data->layer_list);
+
+       ret = _tdm_exynos_display_output_update(output_data);
+       if (ret != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("_tdm_exynos_display_output_update failed (%d)", ret);
+               goto err_output_update;
+       }
+
+       if (output_data->status == HAL_TDM_OUTPUT_CONN_STATUS_CONNECTED) {
+               //LCD has only one mode
+               output_data->count_modes = 1;
+               output_data->output_modes = calloc(output_data->count_modes, sizeof(hal_tdm_output_mode));
+               if (!output_data->output_modes) {
+                       TDM_BACKEND_ERR("alloc failed");
+                       goto err_output_modes;
+               }
+
+               _tdm_exynos_display_to_tdm_mode(&output_data->mi, &output_data->output_modes[0]);
+
+               output_data->prop_count = sizeof(tdm_exynos_props) / sizeof(hal_tdm_prop);
+               output_data->props = tdm_exynos_props;
+
+               output_data->aod_prop = calloc(1, sizeof(tdm_aod_property));
+               if (!output_data->aod_prop) {
+                       TDM_BACKEND_ERR("alloc failed for aod_prop");
+                       goto err_aod_prop;
+               }
+       }
+
+       TDM_BACKEND_DBG("output(%p, status:%d type:%d-%d) pipe(%d) dpms(%d)", output_data,
+                       output_data->status,
+                       output_data->connector_type, output_data->connector_type_id, output_data->pipe,
+                       output_data->dpms_value);
+
+       ret = _tdm_exynos_display_create_layer_list_LCD(output_data);
+       if (ret != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("_tdm_exynos_display_create_layer_list_LCD failed (%d)", ret);
+               goto err_create_layer_list;
+       }
+
+       return output_data;
+
+err_create_layer_list:
+       if (output_data->aod_prop)
+               free(output_data->aod_prop);
+err_aod_prop:
+       free(output_data->output_modes);
+err_output_modes:
+       if (output_data->fb_fd > 0)
+               close(output_data->fb_fd);
+err_output_update:
+       free(output_data);
+       return NULL;
+}
+
+
+void
+tdm_exynos_display_destroy_output_list(tdm_exynos_display *display_data)
+{
+       tdm_exynos_output *o = NULL, *oo = NULL;
+
+       if (LIST_IS_EMPTY(&display_data->output_list))
+               return;
+
+       LIST_FOR_EACH_ENTRY_SAFE(o, oo, &display_data->output_list, link) {
+               LIST_DEL(&o->link);
+               if (!LIST_IS_EMPTY(&o->layer_list)) {
+                       tdm_exynos_layer *l = NULL, *ll = NULL;
+                       LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
+                               LIST_DEL(&l->link);
+                               if (l->display_buffer)
+                                       tbm_surface_internal_unref(l->display_buffer->buffer);
+                               free(l);
+                       }
+               }
+
+               free(o->aod_prop);
+               free(o->output_modes);
+               free(o);
+       }
+}
+
+hal_tdm_error
+tdm_exynos_display_create_output_list(tdm_exynos_display *display_data)
+{
+       tdm_exynos_output *output_data = NULL;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&display_data->output_list),
+                                          HAL_TDM_ERROR_OPERATION_FAILED);
+
+       //have only LCD output
+       output_data = _tdm_exynos_display_create_output_LCD(display_data);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_OPERATION_FAILED);
+       LIST_ADDTAIL(&output_data->link, &display_data->output_list);
+       display_data->output_count = 1;
+
+       TDM_BACKEND_DBG("output count: %d", display_data->output_count);
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+void
+tdm_exynos_display_destroy_buffer_list(tdm_exynos_display *display_data)
+{
+       tdm_exynos_display_buffer *b = NULL, *bb = NULL;
+
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &display_data->buffer_list, link) {
+               tbm_surface_internal_remove_destroy_handler(b->buffer, _tdm_exynos_display_cb_destroy_buffer, display_data);
+               _tdm_exynos_display_cb_destroy_buffer(b->buffer, display_data);
+       }
+}
+
+hal_tdm_error
+exynos_display_get_capabilitiy(hal_tdm_display *display, hal_tdm_caps_display *caps)
+{
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(caps, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       caps->max_layer_count = -1; /* not defined */
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_display_get_pp_capability(hal_tdm_display *display, hal_tdm_caps_pp *caps)
+{
+       return tdm_exynos_pp_get_capability(display, caps);
+}
+
+hal_tdm_error
+exynos_display_get_capture_capability(hal_tdm_display *display, hal_tdm_caps_capture *caps)
+{
+       return tdm_exynos_capture_get_capability(display, caps);
+}
+
+hal_tdm_output **
+exynos_display_get_outputs(hal_tdm_display *display, int *count, hal_tdm_error *error)
+{
+       tdm_exynos_display *display_data = (tdm_exynos_display *)display;
+       tdm_exynos_output *output_data = NULL;
+       hal_tdm_output **outputs;
+       hal_tdm_error ret;
+       int i;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data, NULL);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(count, NULL);
+
+       *count = 0;
+       LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link)
+       (*count)++;
+
+       if (*count == 0) {
+               ret = HAL_TDM_ERROR_NONE;
+               goto failed_get;
+       }
+
+       /* will be freed in frontend */
+       outputs = calloc(*count, sizeof(tdm_exynos_output *));
+       if (!outputs) {
+               TDM_BACKEND_ERR("failed: alloc memory");
+               *count = 0;
+               ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+               goto failed_get;
+       }
+
+       i = 0;
+       LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link)
+       outputs[i++] = output_data;
+
+       if (error)
+               *error = HAL_TDM_ERROR_NONE;
+
+       return outputs;
+failed_get:
+       if (error)
+               *error = ret;
+       return NULL;
+}
+
+hal_tdm_error
+exynos_display_get_fd(hal_tdm_display *display, int *fd)
+{
+       tdm_exynos_display *display_data = (tdm_exynos_display *)display;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(fd, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       *fd = display_data->drm_fd;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_display_handle_events(hal_tdm_display *display)
+{
+       tdm_exynos_display *display_data = (tdm_exynos_display *)display;
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       if (drmHandleEvent(display_data->drm_fd, &display_data->evctx) < 0)
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+tdm_exynos_display_get_drm_pp_permission(hal_tdm_display *display)
+{
+       tdm_exynos_display *display_data = (tdm_exynos_display *)display;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       return tdm_exynos_get_pp_permission(display_data);
+}
+
+hal_tdm_pp *
+exynos_display_create_pp(hal_tdm_display *display, hal_tdm_error *error)
+{
+       tdm_exynos_display *display_data = (tdm_exynos_display *)display;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data, NULL);
+
+       return tdm_exynos_pp_create(display_data, error);
+}
+
+hal_tdm_pp *
+exynos_display_create_pp_v4l2(hal_tdm_display *display, hal_tdm_error *error)
+{
+       tdm_exynos_display *display_data = (tdm_exynos_display *)display;
+
+       if (error)
+               *error = HAL_TDM_ERROR_NOT_IMPLEMENTED;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data, NULL);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data->pp, NULL);
+       if (display_data->pp_count) {
+               if (error)
+                       *error = HAL_TDM_ERROR_BUSY;
+               return NULL;
+       }
+       display_data->pp_count = 1;
+
+       if (error)
+               *error = HAL_TDM_ERROR_NONE;
+
+       return display_data->pp;
+}
+
+hal_tdm_error
+exynos_output_get_capability(hal_tdm_output *output, hal_tdm_caps_output *caps)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+       int i;
+       hal_tdm_error ret;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(caps, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       memset(caps, 0, sizeof(hal_tdm_caps_output));
+
+       snprintf(caps->maker, HAL_TDM_NAME_LEN, "unknown");
+       snprintf(caps->model, HAL_TDM_NAME_LEN, "unknown");
+       snprintf(caps->name, HAL_TDM_NAME_LEN, "unknown");
+
+       caps->status = output_data->status;
+       caps->type = output_data->connector_type;
+       caps->type_id = output_data->connector_type_id;
+
+       caps->mode_count = output_data->count_modes;
+       caps->modes = calloc(1, sizeof(hal_tdm_output_mode) * caps->mode_count);
+       if (!caps->modes) {
+               ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+               TDM_BACKEND_ERR("alloc failed modes\n");
+               goto failed_get;
+       }
+       for (i = 0; i < caps->mode_count; i++)
+               caps->modes[i] = output_data->output_modes[i];
+
+       caps->mmWidth = output_data->mi.width;
+       caps->mmHeight = output_data->mi.height;
+       caps->subpixel = 0;
+
+       caps->min_w = 32;
+       caps->min_h = 0;
+       caps->max_w = output_data->mi.xres_virtual;
+       caps->max_h = output_data->mi.yres_virtual;
+       caps->preferred_align = -1;
+       caps->prop_count = output_data->prop_count;
+       caps->props = calloc(output_data->prop_count, sizeof(hal_tdm_prop));
+       if (!caps->props) {
+               ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+               TDM_BACKEND_ERR("alloc failed props\n");
+               goto failed_get;
+       }
+       memmove(caps->props, output_data->props, output_data->prop_count * sizeof(hal_tdm_prop));
+
+       caps->capabilities |= HAL_TDM_OUTPUT_CAPABILITY_HWC;
+
+       return HAL_TDM_ERROR_NONE;
+failed_get:
+       if (caps->modes)
+               free(caps->modes);
+       if (caps->props)
+               free(caps->props);
+       memset(caps, 0, sizeof(hal_tdm_caps_output));
+       return ret;
+}
+
+hal_tdm_error
+__exynos_output_aod_set_config(hal_tdm_output *output, tdm_aod_property *aod_prop)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+       struct decon_metadata metadata;
+
+       TDM_BACKEND_INFO("aod_set_config:mode[%d]", aod_prop->mode);
+
+       metadata.ops = METADATA_OP_AOD_SET_INFO;
+       metadata.aod_cfg.req = aod_prop->req;
+
+       switch (aod_prop->mode) {
+       case TDM_AOD_OFF:
+               metadata.aod_cfg.mode = AOD_DISABLE;
+               break;
+       case TDM_AOD_ALPM:
+               metadata.aod_cfg.mode = AOD_ALPM;
+               break;
+       case TDM_AOD_HLPM:
+               metadata.aod_cfg.mode = AOD_HLPM;
+               break;
+       case TDM_AOD_SCLK_ANALOG: {
+               tdm_sc_analog_prop analog_info = aod_prop->analog_info;
+
+               metadata.aod_cfg.mode = AOD_SCLK_ANALOG;
+
+               metadata.aod_cfg.analog_cfg.pos[0] = analog_info.center_x;
+               metadata.aod_cfg.analog_cfg.pos[1] = analog_info.center_y;
+               metadata.aod_cfg.analog_cfg.timestamp[0] = analog_info.hh;
+               metadata.aod_cfg.analog_cfg.timestamp[1] = analog_info.mm;
+               metadata.aod_cfg.analog_cfg.timestamp[2] = analog_info.ss;
+               metadata.aod_cfg.analog_cfg.timestamp[3] = analog_info.ms;
+               metadata.aod_cfg.analog_cfg.rate = analog_info.update_rate;
+
+               metadata.aod_cfg.analog_cfg.addr[0] = (unsigned int)(uintptr_t)
+                       tbm_bo_get_handle(analog_info.h_bo, TBM_DEVICE_CPU).ptr;
+               metadata.aod_cfg.analog_cfg.addr[1] = (unsigned int)(uintptr_t)
+                       tbm_bo_get_handle(analog_info.m_bo, TBM_DEVICE_CPU).ptr;
+               metadata.aod_cfg.analog_cfg.addr[2] = (unsigned int)(uintptr_t)
+                       tbm_bo_get_handle(analog_info.s_bo, TBM_DEVICE_CPU).ptr;
+               break;
+       }
+       case TDM_AOD_SCLK_DIGITAL: {
+               tdm_sc_digital_prop digital_info = aod_prop->digital_info;
+
+               metadata.aod_cfg.mode = AOD_SCLK_DIGITAL;
+
+               metadata.aod_cfg.digital_cfg.circle_r = digital_info.circle_radius;
+               metadata.aod_cfg.digital_cfg.circle1[0] = digital_info.circle1_x;
+               metadata.aod_cfg.digital_cfg.circle1[1] = digital_info.circle1_y;
+               metadata.aod_cfg.digital_cfg.circle2[0] = digital_info.circle2_x;
+               metadata.aod_cfg.digital_cfg.circle2[1] = digital_info.circle2_y;
+               metadata.aod_cfg.digital_cfg.color[0] = digital_info.circle_r;
+               metadata.aod_cfg.digital_cfg.color[1] = digital_info.circle_g;
+               metadata.aod_cfg.digital_cfg.color[2] = digital_info.circle_b;
+               metadata.aod_cfg.digital_cfg.rate = digital_info.update_rate;
+               break;
+       }
+       default:
+               TDM_BACKEND_ERR("invalid type[%d]", aod_prop->mode);
+               ret = HAL_TDM_ERROR_INVALID_PARAMETER;
+               goto out;
+       }
+
+       if (ioctl(output_data->fb_fd, S3CFB_METADATA_SET, &metadata)) {
+               TDM_BACKEND_ERR("S3CFB_METADATA_SET error: %s", strerror(errno));
+               ret = HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       if (ret == HAL_TDM_ERROR_NONE)
+               memcpy(output_data->aod_prop, aod_prop, sizeof(tdm_aod_property));
+
+out:
+       return ret;
+}
+
+hal_tdm_error
+__exynos_output_aod_update_data(hal_tdm_output *output, tdm_aod_property *aod_prop)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+       struct decon_metadata metadata;
+
+       if (!output_data->aod_prop) {
+               TDM_BACKEND_ERR("failed to get tdm_aod_property");
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       TDM_BACKEND_INFO("aod_update_data:mode[%d]", aod_prop->mode);
+
+       if (output_data->aod_prop->mode != aod_prop->mode) {
+               TDM_BACKEND_ERR("invalid mode[%d -> %d]", output_data->aod_prop->mode, aod_prop->mode);
+               return HAL_TDM_ERROR_BAD_REQUEST;
+       }
+
+       metadata.ops = METADATA_OP_AOD_SET_INFO;
+       metadata.aod_cfg.req = aod_prop->req;
+
+       switch (aod_prop->mode) {
+       case TDM_AOD_OFF:
+               metadata.aod_cfg.mode = AOD_DISABLE;
+               break;
+       case TDM_AOD_ALPM:
+               metadata.aod_cfg.mode = AOD_ALPM;
+               break;
+       case TDM_AOD_HLPM:
+               metadata.aod_cfg.mode = AOD_HLPM;
+               break;
+       case TDM_AOD_SCLK_ANALOG: {
+               tdm_sc_analog_prop analog_info = aod_prop->analog_info;
+
+               metadata.aod_cfg.mode = AOD_SCLK_ANALOG;
+
+               metadata.aod_cfg.analog_cfg.pos[0] = analog_info.center_x;
+               metadata.aod_cfg.analog_cfg.pos[1] = analog_info.center_y;
+               metadata.aod_cfg.analog_cfg.timestamp[0] = analog_info.hh;
+               metadata.aod_cfg.analog_cfg.timestamp[1] = analog_info.mm;
+               metadata.aod_cfg.analog_cfg.timestamp[2] = analog_info.ss;
+               metadata.aod_cfg.analog_cfg.timestamp[3] = analog_info.ms;
+               metadata.aod_cfg.analog_cfg.rate = analog_info.update_rate;
+               break;
+       }
+       case TDM_AOD_SCLK_DIGITAL: {
+               tdm_sc_digital_prop digital_info = aod_prop->digital_info;
+
+               metadata.aod_cfg.mode = AOD_SCLK_DIGITAL;
+
+               metadata.aod_cfg.digital_cfg.circle_r = digital_info.circle_radius;
+               metadata.aod_cfg.digital_cfg.circle1[0] = digital_info.circle1_x;
+               metadata.aod_cfg.digital_cfg.circle1[1] = digital_info.circle1_y;
+               metadata.aod_cfg.digital_cfg.circle2[0] = digital_info.circle2_x;
+               metadata.aod_cfg.digital_cfg.circle2[1] = digital_info.circle2_y;
+               metadata.aod_cfg.digital_cfg.color[0] = digital_info.circle_r;
+               metadata.aod_cfg.digital_cfg.color[1] = digital_info.circle_g;
+               metadata.aod_cfg.digital_cfg.color[2] = digital_info.circle_b;
+               metadata.aod_cfg.digital_cfg.rate = digital_info.update_rate;
+               break;
+       }
+       default:
+               TDM_BACKEND_ERR("invalid type[%d]", aod_prop->mode);
+               ret = HAL_TDM_ERROR_INVALID_PARAMETER;
+               goto out;
+       }
+
+       if (ioctl(output_data->fb_fd, S3CFB_METADATA_SET, &metadata)) {
+               TDM_BACKEND_ERR("S3CFB_METADATA_SET error: %s", strerror(errno));
+               ret = HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       if (ret == HAL_TDM_ERROR_NONE)
+               memcpy(output_data->aod_prop, aod_prop, sizeof(tdm_aod_property));
+
+out:
+       return ret;
+}
+
+hal_tdm_error
+__exynos_output_aod_change_state(hal_tdm_output *output, tdm_aod_property *aod_prop)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+       struct decon_metadata metadata;
+
+       if (!output_data->aod_prop) {
+               TDM_BACKEND_ERR("failed to get tdm_aod_property");
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       TDM_BACKEND_INFO("aod_change_state:mode[%d]", aod_prop->mode);
+
+       if (output_data->aod_prop->mode != aod_prop->mode) {
+               TDM_BACKEND_ERR("invalid mode[%d -> %d]", output_data->aod_prop->mode, aod_prop->mode);
+               return HAL_TDM_ERROR_BAD_REQUEST;
+       }
+
+       TDM_BACKEND_INFO("aod_change_state:state[%d -> %d]", output_data->aod_prop->state, aod_prop->state);
+
+       metadata.ops = METADATA_OP_AOD_SET_STATE;
+
+       switch (aod_prop->state) {
+       case TDM_AOD_DISABLE:
+               metadata.state = AOD_EXIT;
+               break;
+       case TDM_AOD_ENABLE:
+               metadata.state = AOD_ENTER;
+               break;
+       default:
+               TDM_BACKEND_ERR("invalid state[%d]", aod_prop->state);
+               ret = HAL_TDM_ERROR_INVALID_PARAMETER;
+               goto out;
+       }
+
+       if (ioctl(output_data->fb_fd, S3CFB_METADATA_SET, &metadata)) {
+               TDM_BACKEND_ERR("S3CFB_METADATA_SET error: %s", strerror(errno));
+               ret = HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       if (ret == HAL_TDM_ERROR_NONE)
+               output_data->aod_prop->state = aod_prop->state;
+
+out:
+       return ret;
+}
+
+hal_tdm_error
+exynos_output_set_property(hal_tdm_output *output, unsigned int id, hal_tdm_value value)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+       tdm_aod_property *aod_prop = NULL;
+
+       TDM_BACKEND_INFO("id[%d]", id);
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(value.ptr, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       switch (id) {
+       case TDM_PROP_SET_AOD: {
+               aod_prop = (tdm_aod_property *)value.ptr;
+
+               switch (aod_prop->req) {
+               case TDM_AOD_SET_CONFIG:
+                       ret = __exynos_output_aod_set_config(output_data, aod_prop);
+                       break;
+               case TDM_AOD_UPDATE_DATA:
+                       ret = __exynos_output_aod_update_data(output_data, aod_prop);
+                       break;
+               case TDM_AOD_CHANGE_STATE:
+                       ret = __exynos_output_aod_change_state(output_data, aod_prop);
+                       break;
+               default:
+                       ret = HAL_TDM_ERROR_INVALID_PARAMETER;
+                       break;
+               }
+               break;
+       }
+       default:
+               ret = HAL_TDM_ERROR_NOT_IMPLEMENTED;
+               break;
+       }
+
+       return ret;
+}
+
+hal_tdm_error
+exynos_output_get_property(hal_tdm_output *output, unsigned int id, hal_tdm_value *value)
+{
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+       TDM_BACKEND_INFO("id[%d]", id);
+
+       switch (id) {
+       default:
+               ret = HAL_TDM_ERROR_NONE;
+               break;
+       }
+
+       (*value).u32 = 0;
+
+       return ret;
+}
+
+hal_tdm_error
+exynos_output_get_cur_msc(hal_tdm_output *output, uint *msc)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+       tdm_exynos_display *display_data;
+       hal_tdm_error ret;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       display_data = output_data->display_data;
+
+       ret = _tdm_exynos_display_get_cur_msc(display_data->drm_fd, output_data->pipe, msc);
+
+       return ret;
+}
+
+hal_tdm_error
+exynos_output_wait_vblank(hal_tdm_output *output, int interval, int sync, void *user_data)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+       tdm_exynos_display *display_data;
+       tdm_exynos_vblank_data *vblank_data;
+       uint target_msc;
+       hal_tdm_error ret;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       vblank_data = calloc(1, sizeof(tdm_exynos_vblank_data));
+       if (!vblank_data) {
+               TDM_BACKEND_ERR("alloc failed");
+               return HAL_TDM_ERROR_OUT_OF_MEMORY;
+       }
+
+       display_data = output_data->display_data;
+
+       ret = _tdm_exynos_display_get_cur_msc(display_data->drm_fd, output_data->pipe,
+                                                                                 &target_msc);
+       if (ret != HAL_TDM_ERROR_NONE)
+               goto failed_vblank;
+
+       target_msc = target_msc + interval;
+
+       vblank_data->type = VBLANK_TYPE_WAIT;
+       vblank_data->output_data = output_data;
+       vblank_data->user_data = user_data;
+
+       ret = _tdm_exynos_display_wait_vblank(display_data->drm_fd, output_data->pipe,
+                                                                                 &target_msc, vblank_data);
+       if (ret != HAL_TDM_ERROR_NONE)
+               goto failed_vblank;
+
+       return HAL_TDM_ERROR_NONE;
+failed_vblank:
+       free(vblank_data);
+       return ret;
+}
+
+hal_tdm_error
+exynos_output_set_vblank_handler(hal_tdm_output *output,
+                                                                               hal_tdm_output_vblank_handler func)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
+       output_data->vblank_func = func;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+tdm_exynos_layer *
+tdm_exynos_output_data_get_layer_data(tdm_exynos_output *output_data, int zpos)
+{
+       tdm_exynos_layer *l = NULL;
+       LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link)
+               if (l->zpos == zpos)
+                       return l;
+
+       return NULL;
+}
+
+hal_tdm_error
+exynos_output_commit(hal_tdm_output *output, int sync, void *user_data)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+       tdm_exynos_display *display_data;
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       display_data = output_data->display_data;
+
+       if (output_data->aod_prop &&  output_data->aod_prop->state == TDM_AOD_ENABLE) {
+               struct decon_metadata metadata;
+
+               metadata.ops = METADATA_OP_AOD_SET_STATE;
+               metadata.state = AOD_UPDATE_REQ;
+
+               TDM_BACKEND_INFO("set aod state[%d]\n", metadata.state);
+               if (ioctl(output_data->fb_fd, S3CFB_METADATA_SET, &metadata)) {
+                       TDM_BACKEND_ERR("S3CFB_METADATA_SET error: %s \n", strerror(errno));
+                       ret = HAL_TDM_ERROR_OPERATION_FAILED;
+                       goto out;
+               }
+       }
+
+       if (sync) {
+               _tdm_exynos_display_do_commit(output_data);
+               ret = _tdm_exynos_display_wait_sync(display_data->drm_fd, output_data->pipe);
+       } else {
+               tdm_exynos_vblank_data *vblank_data;
+               uint target_msc;
+
+               vblank_data = calloc(1, sizeof(tdm_exynos_vblank_data));
+               if (!vblank_data) {
+                       TDM_BACKEND_ERR("alloc failed");
+                       ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+                       goto out;
+               }
+
+               ret = _tdm_exynos_display_get_cur_msc(display_data->drm_fd, output_data->pipe,
+                                                                                         &target_msc);
+               if (ret != HAL_TDM_ERROR_NONE) {
+                       free(vblank_data);
+                       goto out;
+               }
+
+               _tdm_exynos_display_do_commit(output_data);
+
+               target_msc++;
+
+               vblank_data->type = VBLANK_TYPE_COMMIT;
+               vblank_data->output_data = output_data;
+               vblank_data->user_data = user_data;
+
+               ret = _tdm_exynos_display_wait_vblank(display_data->drm_fd, output_data->pipe,
+                                                                                         &target_msc, vblank_data);
+               if (ret != HAL_TDM_ERROR_NONE) {
+                       free(vblank_data);
+                       goto out;
+               }
+       }
+out:
+       if (output_data->aod_prop &&  output_data->aod_prop->state == TDM_AOD_ENABLE) {
+               struct decon_metadata metadata;
+
+               metadata.ops = METADATA_OP_AOD_SET_STATE;
+               metadata.state = AOD_UPDATE_DONE;
+
+               TDM_BACKEND_INFO("set aod state[%d]\n", metadata.state);
+               if (ioctl(output_data->fb_fd, S3CFB_METADATA_SET, &metadata)) {
+                       TDM_BACKEND_ERR("S3CFB_METADATA_SET error: %s \n", strerror(errno));
+                       ret = HAL_TDM_ERROR_OPERATION_FAILED;
+               }
+       }
+
+       return ret;
+}
+
+hal_tdm_error
+exynos_output_set_commit_handler(hal_tdm_output *output,
+                                                                                hal_tdm_output_commit_handler func)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       output_data->commit_func = func;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_output_set_dpms(hal_tdm_output *output, hal_tdm_output_dpms dpms_value)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+       tdm_exynos_display *display_data = output_data->display_data;
+       tdm_exynos_layer *layer_data = NULL;
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+       struct tdm_control_dpms  dpms_ctrl;
+
+       TDM_BACKEND_INFO("dpms[%d -> %d]", output_data->dpms_value, dpms_value);
+
+       if (output_data->dpms_value == dpms_value) {
+               ret = HAL_TDM_ERROR_OPERATION_FAILED;
+               goto out;
+       }
+
+       switch (dpms_value) {
+       case HAL_TDM_OUTPUT_DPMS_ON:
+               dpms_ctrl.dpms = DRM_MODE_DPMS_ON;
+               break;
+       case HAL_TDM_OUTPUT_DPMS_OFF:
+               dpms_ctrl.dpms = DRM_MODE_DPMS_OFF;
+               break;
+       case HAL_TDM_OUTPUT_DPMS_STANDBY:
+       case HAL_TDM_OUTPUT_DPMS_SUSPEND:
+               TDM_BACKEND_WRN("not supported dpms[%d]\n", dpms_value);
+               output_data->dpms_value = dpms_value;
+               goto out;
+       default:
+               TDM_BACKEND_ERR("invalid dpms[%d]\n", dpms_value);
+               ret = HAL_TDM_ERROR_OPERATION_FAILED;
+               goto out;
+       }
+
+       dpms_ctrl.user_data = 0;
+       dpms_ctrl.type = DPMS_SYNC_WORK;
+       dpms_ctrl.crtc_id = TDM_CRTC_PRIMARY;
+
+       if (ioctl(display_data->drm_fd, DRM_IOCTL_TDM_DPMS_CONTROL, &dpms_ctrl) < 0) {
+               TDM_BACKEND_ERR("failed to TDM_DPMS_CONTROL:%s\n", strerror(errno));
+               ret = HAL_TDM_ERROR_OPERATION_FAILED;
+               goto out;
+       }
+
+       /* ToDo: event handling */
+       LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
+               memset(&layer_data->win_cfg, 0, sizeof(struct decon_win_config));
+       }
+
+       output_data->dpms_value = dpms_value;
+
+out:
+       TDM_BACKEND_INFO("dpms[%d -> %d]done\n", output_data->dpms_value, dpms_value);
+       return ret;
+}
+
+hal_tdm_error
+exynos_output_set_dpms_handler(hal_tdm_output *output,
+                                                                          hal_tdm_output_dpms_handler func)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       output_data->dpms_func = func;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_output_get_dpms(hal_tdm_output *output, hal_tdm_output_dpms *dpms_value)
+{
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(dpms_value, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       *dpms_value = output_data->dpms_value;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_output_set_mode(hal_tdm_output *output, const hal_tdm_output_mode *mode)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(mode, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       /* create or replace the target_window when the output mode is set */
+       ret = exynos_hwc_initailize_target_window(output_data->hwc_data, mode->hdisplay, mode->vdisplay);
+       if (ret != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("create target hwc window failed (%d)", ret);
+               return ret;
+       }
+
+       output_data->current_mode = mode;
+       output_data->mode_changed = 1;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_output_get_mode(hal_tdm_output *output, const hal_tdm_output_mode **mode)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(mode, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       *mode = output_data->current_mode;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_capture*
+exynos_output_create_capture(hal_tdm_output *output, hal_tdm_error *error)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+       tdm_exynos_display *display_data;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, NULL);
+
+       display_data = output_data->display_data;
+
+       return tdm_exynos_capture_create_output(display_data, output, error);
+}
+
+hal_tdm_error
+exynos_output_set_status_handler(hal_tdm_output *output,
+                                                                          hal_tdm_output_status_handler func,
+                                                                          void *user_data)
+{
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       output_data->status_func = func;
+       output_data->status_user_data = user_data;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_hwc *
+exynos_output_get_hwc(hal_tdm_output *output, hal_tdm_error *error)
+{
+       tdm_exynos_hwc *hwc_data = NULL;
+       tdm_exynos_output *output_data = (tdm_exynos_output *)output;
+
+       if (!output_data) {
+               TDM_BACKEND_ERR("invalid params");
+               if (error)
+                       *error = HAL_TDM_ERROR_INVALID_PARAMETER;
+               return NULL;
+       }
+
+       if (output_data->hwc_data) {
+               TDM_BACKEND_INFO("hwc_data already exists");
+               if (error)
+                       *error = HAL_TDM_ERROR_NONE;
+               return output_data->hwc_data;
+       }
+
+       hwc_data = calloc(1, sizeof(tdm_exynos_hwc));
+       if (!hwc_data) {
+               TDM_BACKEND_ERR("alloc failed");
+               if (error)
+                       *error = HAL_TDM_ERROR_OUT_OF_MEMORY;
+               return NULL;
+       }
+       hwc_data->output_data = output_data;
+
+       LIST_INITHEAD(&hwc_data->hwc_window_list);
+
+       output_data->hwc_data = hwc_data;
+
+       if (error)
+               *error = HAL_TDM_ERROR_NONE;
+
+       return hwc_data;
+}
+
+hal_tdm_error
+tdm_exynos_layer_get_capability(tdm_exynos_layer *layer_data, tdm_exynos_caps_layer *caps)
+{
+       int i;
+       hal_tdm_error ret;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(caps, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       memset(caps, 0, sizeof(tdm_exynos_caps_layer));
+
+       caps->capabilities = layer_data->capabilities;
+       caps->zpos = layer_data->zpos;
+
+       caps->format_count = layer_data->format_count;
+       caps->formats = calloc(1, sizeof(tbm_format) * caps->format_count);
+       if (!caps->formats) {
+               ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+               TDM_BACKEND_ERR("alloc failed\n");
+               goto failed_get;
+       }
+
+       for (i = 0; i < caps->format_count; i++)
+               caps->formats[i] = layer_data->formats[i];
+
+       caps->prop_count = 0;
+       caps->props = NULL;
+
+       return HAL_TDM_ERROR_NONE;
+failed_get:
+       if (caps->formats)
+               free(caps->formats);
+       if (caps->props)
+               free(caps->props);
+       memset(caps, 0, sizeof(tdm_exynos_caps_layer));
+       return ret;
+}
+
+hal_tdm_error
+tdm_exynos_layer_set_property(tdm_exynos_layer *layer_data, unsigned int id, hal_tdm_value value)
+{
+       return HAL_TDM_ERROR_NOT_IMPLEMENTED;
+}
+
+hal_tdm_error
+tdm_exynos_layer_get_property(tdm_exynos_layer *layer_data, unsigned int id, hal_tdm_value *value)
+{
+       return HAL_TDM_ERROR_NOT_IMPLEMENTED;
+}
+
+hal_tdm_error
+tdm_exynos_layer_set_info(tdm_exynos_layer *layer_data, tdm_exynos_layer_info *info)
+{
+       hal_tdm_output_mode *output_modes;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(info, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       output_modes = layer_data->output_data->output_modes;
+
+       if ((int)info->dst_pos.w <= 0 || info->dst_pos.x + info->dst_pos.w > output_modes->hdisplay ||
+               info->dst_pos.x + info->dst_pos.w <= 0) {
+               TDM_BACKEND_ERR("invalid dst hpos");
+               return HAL_TDM_ERROR_INVALID_PARAMETER;
+       }
+
+       if ((int)info->dst_pos.h <= 0 || info->dst_pos.y + info->dst_pos.h > output_modes->vdisplay ||
+               info->dst_pos.y + info->dst_pos.h <= 0) {
+               TDM_BACKEND_ERR("invalid dst vpos");
+               return HAL_TDM_ERROR_INVALID_PARAMETER;
+       }
+
+       layer_data->info = *info;
+       layer_data->info_changed = 1;
+
+       TDM_BACKEND_DBG("layer_data[%p]zpos[%d]src:sz[%d %d]pos[%d %d %d %d]dst:pos[%d %d %d %d]",
+               layer_data, layer_data->zpos,
+               layer_data->info.src_config.size.h, layer_data->info.src_config.size.v,
+               layer_data->info.src_config.pos.x, layer_data->info.src_config.pos.y,
+               layer_data->info.src_config.pos.w, layer_data->info.src_config.pos.h,
+               layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
+               layer_data->info.dst_pos.w, layer_data->info.dst_pos.h);
+
+       if ((int)layer_data->info.dst_pos.x < 0) {
+               layer_data->info.dst_pos.w += layer_data->info.dst_pos.x;
+               if (layer_data->info.dst_pos.w != layer_data->info.src_config.pos.w)
+                       layer_data->info.dst_pos.w = layer_data->info.src_config.pos.w;
+               layer_data->info.dst_pos.x = 0;
+       }
+
+       if ((int)layer_data->info.dst_pos.y < 0) {
+               layer_data->info.dst_pos.h += layer_data->info.dst_pos.y;
+               if (layer_data->info.dst_pos.h != layer_data->info.src_config.pos.h)
+                       layer_data->info.dst_pos.h = layer_data->info.src_config.pos.h;
+               layer_data->info.dst_pos.y = 0;
+       }
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+tdm_exynos_layer_get_info(tdm_exynos_layer *layer_data, tdm_exynos_layer_info *info)
+{
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(info, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       *info = layer_data->info;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+tdm_exynos_layer_set_buffer(tdm_exynos_layer *layer_data, tbm_surface_h surface)
+{
+       tdm_exynos_display *display_data;
+       tdm_exynos_display_buffer *display_buffer;
+       hal_tdm_error err = HAL_TDM_ERROR_NONE;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(surface, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       TDM_BACKEND_DBG("layer_data[%p]zpos[%d] buffer:%p", layer_data, layer_data->zpos, surface);
+
+       display_data = layer_data->display_data;
+       display_buffer = _tdm_exynos_display_find_buffer(display_data, surface);
+       if (!display_buffer) {
+               display_buffer = _tdm_exynos_display_create_buffer(display_data, surface, &err);
+               TDM_BACKEND_RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
+       }
+
+       if (layer_data->display_buffer != display_buffer) {
+               if (layer_data->display_buffer)
+                       tbm_surface_internal_unref(layer_data->display_buffer->buffer);
+
+               layer_data->display_buffer = display_buffer;
+               tbm_surface_internal_ref(layer_data->display_buffer->buffer);
+               layer_data->display_buffer_changed = 1;
+       }
+
+       return HAL_TDM_ERROR_NONE;
+
+}
+
+hal_tdm_error
+tdm_exynos_layer_unset_buffer(tdm_exynos_layer *layer_data)
+{
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       TDM_BACKEND_DBG("layer_data[%p]zpos[%d]", layer_data, layer_data->zpos);
+
+       _tdm_exynos_display_layer_disable(layer_data);
+
+       if (layer_data->display_buffer)
+               tbm_surface_internal_unref(layer_data->display_buffer->buffer);
+
+       layer_data->display_buffer = NULL;
+       layer_data->display_buffer_changed = 1;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+static int
+_exynos_drm_user_handler(struct drm_event *event)
+{
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(event, -1);
+
+       TDM_BACKEND_INFO("got event %x\n", event->type);
+
+       switch (event->type) {
+       case TDM_PP_EVENT:
+               tdm_exynos_pp_handler((struct tdm_pp_event *)event);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static void
+_exynos_drm_vblank_event(int fd, unsigned int sequence, unsigned int tv_sec,
+                                                               unsigned int tv_usec, void *user_data)
+{
+       tdm_exynos_vblank_data *vblank_data = (tdm_exynos_vblank_data *)user_data;
+       tdm_exynos_output *output_data;
+       tdm_exynos_hwc *hwc_data;
+
+       if (!vblank_data) {
+               TDM_BACKEND_ERR("no vblank data");
+               return;
+       }
+
+       output_data = vblank_data->output_data;
+       if (!output_data) {
+               TDM_BACKEND_ERR("no output data");
+               return;
+       }
+
+       switch (vblank_data->type) {
+       case VBLANK_TYPE_WAIT:
+               if (output_data->vblank_func)
+                       output_data->vblank_func(output_data, sequence,
+                                                                        tv_sec, tv_usec,
+                                                                        vblank_data->user_data);
+               break;
+       case VBLANK_TYPE_COMMIT:
+               hwc_data = output_data->hwc_data;
+               if (!hwc_data) {
+                       TDM_BACKEND_ERR("no hwc_data");
+                       break;
+               }
+
+               if (hwc_data->commit_func)
+                       hwc_data->commit_func(hwc_data, sequence,
+                                                                        tv_sec, tv_usec,
+                                                                        vblank_data->user_data);
+               break;
+       default:
+               return;
+       }
+
+       free(vblank_data);
+}
+
+static void
+_exynos_drm_flip_complete_event(int fd, unsigned int sequence,
+                                                                          unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+{
+       TDM_BACKEND_DBG("FLIP EVENT");
+}
+
+hal_tdm_error
+tdm_exynos_display_init_event_handling(tdm_exynos_display *display_data)
+{
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       display_data->evctx.version = 2;
+       display_data->evctx.page_flip_handler = _exynos_drm_flip_complete_event;
+       display_data->evctx.vblank_handler = _exynos_drm_vblank_event;
+
+       drmAddUserHandler(display_data->drm_fd, _exynos_drm_user_handler);
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+void
+tdm_exynos_display_deinit_event_handling(tdm_exynos_display *display_data)
+{
+       TDM_BACKEND_RETURN_IF_FAIL(display_data);
+
+       drmRemoveUserHandler(display_data->drm_fd, _exynos_drm_user_handler);
+}
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_format.c b/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_format.c
new file mode 100644 (file)
index 0000000..a0cfe93
--- /dev/null
@@ -0,0 +1,182 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <drm_fourcc.h>
+#include <tbm_surface.h>
+
+#include "tdm_backend_exynos.h"
+
+#include <linux/videodev2.h>
+
+#ifndef TBM_FORMAT_NV12MT
+#define TBM_FORMAT_NV12MT   FOURCC('T', 'M', '1', '2')
+#endif
+
+#ifndef DRM_FORMAT_12MT
+#define DRM_FORMAT_12MT     FOURCC('T', 'M', '1', '2')
+#endif
+
+typedef struct {
+       tbm_format  tbm_format;
+       uint32_t    target_format;
+} tbm_exynos_format_data;
+
+static const tbm_exynos_format_data decon_formats[] = {
+       {TBM_FORMAT_RGBA5551, DECON_PIXEL_FORMAT_RGBA_5551},
+       {TBM_FORMAT_RGB565, DECON_PIXEL_FORMAT_RGB_565},
+       {TBM_FORMAT_XRGB8888, DECON_PIXEL_FORMAT_XRGB_8888},
+       {TBM_FORMAT_XBGR8888, DECON_PIXEL_FORMAT_XBGR_8888},
+       {TBM_FORMAT_RGBX8888, DECON_PIXEL_FORMAT_RGBX_8888},
+       {TBM_FORMAT_BGRX8888, DECON_PIXEL_FORMAT_BGRX_8888},
+       {TBM_FORMAT_ARGB8888, DECON_PIXEL_FORMAT_ARGB_8888},
+       {TBM_FORMAT_ABGR8888, DECON_PIXEL_FORMAT_ABGR_8888},
+       {TBM_FORMAT_RGBA8888, DECON_PIXEL_FORMAT_RGBA_8888},
+       {TBM_FORMAT_BGRA8888, DECON_PIXEL_FORMAT_BGRA_8888},
+       {TBM_FORMAT_NV12, DECON_PIXEL_FORMAT_NV12},
+       {TBM_FORMAT_NV21, DECON_PIXEL_FORMAT_NV21},
+       {TBM_FORMAT_NV16, DECON_PIXEL_FORMAT_NV16},
+       {TBM_FORMAT_NV61, DECON_PIXEL_FORMAT_NV61},
+       {TBM_FORMAT_YUV420, DECON_PIXEL_FORMAT_YUV420},
+       {TBM_FORMAT_YVU420, DECON_PIXEL_FORMAT_YVU420},
+       {TBM_FORMAT_YVU422, DECON_PIXEL_FORMAT_YVU422_3P},
+};
+
+static const tbm_exynos_format_data drm_formats[] = {
+       {TBM_FORMAT_C8, DRM_FORMAT_C8},
+       {TBM_FORMAT_RGB332, DRM_FORMAT_RGB332},
+       {TBM_FORMAT_BGR233, DRM_FORMAT_BGR233},
+       {TBM_FORMAT_XRGB4444, DRM_FORMAT_XRGB4444},
+       {TBM_FORMAT_XBGR4444, DRM_FORMAT_XBGR4444},
+       {TBM_FORMAT_RGBX4444, DRM_FORMAT_RGBX4444},
+       {TBM_FORMAT_BGRX4444, DRM_FORMAT_BGRX4444},
+       {TBM_FORMAT_ARGB4444, DRM_FORMAT_ARGB4444},
+       {TBM_FORMAT_ABGR4444, DRM_FORMAT_ABGR4444},
+       {TBM_FORMAT_RGBA4444, DRM_FORMAT_RGBA4444},
+       {TBM_FORMAT_BGRA4444, DRM_FORMAT_BGRA4444},
+       {TBM_FORMAT_XRGB1555, DRM_FORMAT_XRGB1555},
+       {TBM_FORMAT_XBGR1555, DRM_FORMAT_XBGR1555},
+       {TBM_FORMAT_RGBX5551, DRM_FORMAT_RGBX5551},
+       {TBM_FORMAT_BGRX5551, DRM_FORMAT_BGRX5551},
+       {TBM_FORMAT_ARGB1555, DRM_FORMAT_ARGB1555},
+       {TBM_FORMAT_ABGR1555, DRM_FORMAT_ABGR1555},
+       {TBM_FORMAT_RGBA5551, DRM_FORMAT_RGBA5551},
+       {TBM_FORMAT_BGRA5551, DRM_FORMAT_BGRA5551},
+       {TBM_FORMAT_RGB565, DRM_FORMAT_RGB565},
+       {TBM_FORMAT_BGR565, DRM_FORMAT_BGR565},
+       {TBM_FORMAT_RGB888, DRM_FORMAT_RGB888},
+       {TBM_FORMAT_BGR888, DRM_FORMAT_BGR888},
+       {TBM_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888},
+       {TBM_FORMAT_XBGR8888, DRM_FORMAT_XBGR8888},
+       {TBM_FORMAT_RGBX8888, DRM_FORMAT_RGBX8888},
+       {TBM_FORMAT_BGRX8888, DRM_FORMAT_BGRX8888},
+       {TBM_FORMAT_ARGB8888, DRM_FORMAT_ARGB8888},
+       {TBM_FORMAT_ABGR8888, DRM_FORMAT_ABGR8888},
+       {TBM_FORMAT_RGBA8888, DRM_FORMAT_RGBA8888},
+       {TBM_FORMAT_BGRA8888, DRM_FORMAT_BGRA8888},
+       {TBM_FORMAT_XRGB2101010, DRM_FORMAT_XRGB2101010},
+       {TBM_FORMAT_XBGR2101010, DRM_FORMAT_XBGR2101010},
+       {TBM_FORMAT_RGBX1010102, DRM_FORMAT_RGBX1010102},
+       {TBM_FORMAT_BGRX1010102, DRM_FORMAT_BGRX1010102},
+       {TBM_FORMAT_ARGB2101010, DRM_FORMAT_ARGB2101010},
+       {TBM_FORMAT_ABGR2101010, DRM_FORMAT_ABGR2101010},
+       {TBM_FORMAT_RGBA1010102, DRM_FORMAT_RGBA1010102},
+       {TBM_FORMAT_BGRA1010102, DRM_FORMAT_BGRA1010102},
+       {TBM_FORMAT_YUYV, DRM_FORMAT_YUYV},
+       {TBM_FORMAT_YVYU, DRM_FORMAT_YVYU},
+       {TBM_FORMAT_UYVY, DRM_FORMAT_UYVY},
+       {TBM_FORMAT_VYUY, DRM_FORMAT_VYUY},
+       {TBM_FORMAT_AYUV, DRM_FORMAT_AYUV},
+       {TBM_FORMAT_NV12, DRM_FORMAT_NV12},
+       {TBM_FORMAT_NV21, DRM_FORMAT_NV21},
+       {TBM_FORMAT_NV16, DRM_FORMAT_NV16},
+       {TBM_FORMAT_NV61, DRM_FORMAT_NV61},
+       {TBM_FORMAT_YUV410, DRM_FORMAT_YUV410},
+       {TBM_FORMAT_YVU410, DRM_FORMAT_YVU410},
+       {TBM_FORMAT_YUV411, DRM_FORMAT_YUV411},
+       {TBM_FORMAT_YVU411, DRM_FORMAT_YVU411},
+       {TBM_FORMAT_YUV420, DRM_FORMAT_YUV420},
+       {TBM_FORMAT_YVU420, DRM_FORMAT_YVU420},
+       {TBM_FORMAT_YUV422, DRM_FORMAT_YUV422},
+       {TBM_FORMAT_YVU422, DRM_FORMAT_YVU422},
+       {TBM_FORMAT_YUV444, DRM_FORMAT_YUV444},
+       {TBM_FORMAT_YVU444, DRM_FORMAT_YVU444},
+       {TBM_FORMAT_NV12MT, DRM_FORMAT_12MT},
+};
+
+static const tbm_exynos_format_data v4l2_formats[] = {
+       {TBM_FORMAT_RGB565, V4L2_PIX_FMT_RGB565},
+       {TBM_FORMAT_XRGB8888, V4L2_PIX_FMT_BGR32},
+       {TBM_FORMAT_ARGB8888, V4L2_PIX_FMT_BGR32},
+       {TBM_FORMAT_RGBA8888, V4L2_PIX_FMT_RGB32},
+       {TBM_FORMAT_RGBX8888, V4L2_PIX_FMT_RGB32},
+       {TBM_FORMAT_YUV420, V4L2_PIX_FMT_YUV420},
+       {TBM_FORMAT_YUV422, V4L2_PIX_FMT_YUV422P},
+       {TBM_FORMAT_NV12, V4L2_PIX_FMT_NV12M},
+       {TBM_FORMAT_NV21, V4L2_PIX_FMT_NV21},
+       {TBM_FORMAT_NV12MT, V4L2_PIX_FMT_NV12MT_16X16},
+};
+
+
+#define NUM_DECON_FORMATS (sizeof(decon_formats) / sizeof(decon_formats[0]))
+#define NUM_DRM_FORMATS (sizeof(drm_formats) / sizeof(drm_formats[0]))
+#define NUM_V4L2_FORMATS (sizeof(v4l2_formats) / sizeof(v4l2_formats[0]))
+
+tbm_format
+tdm_exynos_format_to_tbm_format(uint32_t format)
+{
+       int i;
+
+       for (i = 0; i < NUM_DRM_FORMATS; i++)
+               if (drm_formats[i].target_format == format)
+                       return drm_formats[i].tbm_format;
+
+       TDM_BACKEND_ERR("drm format '%c%c%c%c' not found", FOURCC_STR(format));
+
+       return 0;
+}
+
+uint32_t
+tdm_exynos_format_to_decon_format(tbm_format format)
+{
+       int i;
+
+       for (i = 0; i < NUM_DECON_FORMATS; i++)
+               if (decon_formats[i].tbm_format == format) {
+                       return decon_formats[i].target_format;
+               }
+
+       TDM_BACKEND_ERR("tbm format '%c%c%c%c' not found", FOURCC_STR(format));
+
+       return 0;
+}
+
+uint32_t
+tdm_exynos_format_to_drm_format(tbm_format format)
+{
+       int i;
+
+       for (i = 0; i < NUM_DRM_FORMATS; i++)
+               if (drm_formats[i].tbm_format == format)
+                       return drm_formats[i].target_format;
+
+       TDM_BACKEND_ERR("tbm format '%c%c%c%c' not found", FOURCC_STR(format));
+
+       return 0;
+}
+
+uint32_t
+tdm_exynos_format_to_v4l2_format(tbm_format format)
+{
+       int i;
+
+       for (i = 0; i < NUM_V4L2_FORMATS; i++)
+               if (v4l2_formats[i].tbm_format == format)
+                       return v4l2_formats[i].target_format;
+
+       TDM_BACKEND_ERR("tbm format '%c%c%c%c' not found", FOURCC_STR(format));
+
+       return 0;
+}
+
+
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_format.h b/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_format.h
new file mode 100644 (file)
index 0000000..32832ea
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _TDM_EXYNOS_FORMAT_H_
+#define _TDM_EXYNOS_FORMAT_H_
+
+#include <tbm_surface.h>
+
+#define C(b,m)              (((b) >> (m)) & 0xFF)
+#define B(c,s)              ((((unsigned int)(c)) & 0xff) << (s))
+#define FOURCC(a,b,c,d)     (B(d,24) | B(c,16) | B(b,8) | B(a,0))
+#define FOURCC_STR(id)      C(id,0), C(id,8), C(id,16), C(id,24)
+
+#define IS_RGB(format)      (format == TBM_FORMAT_XRGB8888 || format == TBM_FORMAT_ARGB8888 || \
+                             format == TBM_FORMAT_XBGR8888 || format == TBM_FORMAT_ABGR8888)
+
+#define CLEAR(x) memset(&(x), 0, sizeof(x))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define SWAP(a, b)  ({int t; t = a; a = b; b = t;})
+#define ROUNDUP(x)  (ceil (floor ((float)(height) / 4)))
+
+#define ALIGN_TO_16B(x)    ((((x) + (1 <<  4) - 1) >>  4) <<  4)
+#define ALIGN_TO_32B(x)    ((((x) + (1 <<  5) - 1) >>  5) <<  5)
+#define ALIGN_TO_128B(x)   ((((x) + (1 <<  7) - 1) >>  7) <<  7)
+#define ALIGN_TO_2KB(x)    ((((x) + (1 << 11) - 1) >> 11) << 11)
+#define ALIGN_TO_8KB(x)    ((((x) + (1 << 13) - 1) >> 13) << 13)
+#define ALIGN_TO_64KB(x)   ((((x) + (1 << 16) - 1) >> 16) << 16)
+
+tbm_format   tdm_exynos_format_to_tbm_format(uint32_t format);
+uint32_t     tdm_exynos_format_to_decon_format(tbm_format format);
+uint32_t     tdm_exynos_format_to_drm_format(tbm_format format);
+uint32_t     tdm_exynos_format_to_v4l2_format(tbm_format format);
+
+#endif /* _TDM_EXYNOS_FORMAT_H_ */
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_hwc.c b/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_hwc.c
new file mode 100644 (file)
index 0000000..dd5de2e
--- /dev/null
@@ -0,0 +1,607 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <tdm_helper.h>
+#include "tdm_backend_exynos.h"
+
+#define MIN_WIDTH      32
+
+#define NUM_LAYERS     3
+#define NUM_BUFFERS    3
+
+#define NUM_UI_LAYERS  3
+
+#define ZPOS_MAX       3
+#define ZPOS_2         2
+#define ZPOS_1         1
+#define ZPOS_0         0
+#define ZPOS_VIDEO1    0
+#define ZPOS_NONE      -999
+
+tbm_format hwc_window_video_formats[] = {
+       TBM_FORMAT_ARGB8888,
+       TBM_FORMAT_XRGB8888,
+};
+
+const char *
+_comp_to_str(hal_tdm_hwc_window_composition composition_type)
+{
+       if (composition_type == HAL_TDM_HWC_WIN_COMPOSITION_CLIENT)
+               return "CLIENT";
+       else if (composition_type == HAL_TDM_HWC_WIN_COMPOSITION_DEVICE)
+               return "DEVICE";
+       else if (composition_type == HAL_TDM_HWC_WIN_COMPOSITION_CURSOR)
+               return "CURSOR";
+       else if (composition_type == HAL_TDM_HWC_WIN_COMPOSITION_VIDEO)
+               return "VIDEO";
+       else if (composition_type == HAL_TDM_HWC_WIN_COMPOSITION_NONE)
+               return "SKIP";
+
+       return "unknown";
+}
+
+static void
+_print_validate_result(tdm_exynos_hwc *hwc_data, hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds)
+{
+       tdm_exynos_hwc_window_data *hwc_window_data = NULL;
+       int i;
+
+       for (i = 0; i < num_wnds; i++) {
+               hwc_window_data = composited_wnds[i];
+               switch (hwc_window_data->validated_type) {
+               case HAL_TDM_HWC_WIN_COMPOSITION_CLIENT:
+                       TDM_BACKEND_DBG(" window(%p) %s -> %s : lzpos(%d) -- {%s} on TARGET WINDOW", hwc_window_data,
+                                       _comp_to_str(hwc_window_data->client_type),
+                                       _comp_to_str(hwc_window_data->validated_type),
+                                       hwc_data->target_hwc_window->lzpos,
+                                       hwc_window_data->name ? hwc_window_data->name : "NONE");
+                       break;
+               case HAL_TDM_HWC_WIN_COMPOSITION_DEVICE:
+               case HAL_TDM_HWC_WIN_COMPOSITION_VIDEO:
+               case HAL_TDM_HWC_WIN_COMPOSITION_CURSOR:
+               case HAL_TDM_HWC_WIN_COMPOSITION_NONE:
+                       TDM_BACKEND_DBG(" window(%p) %s -> %s : lzpos(%d) -- {%s}", hwc_window_data,
+                                       _comp_to_str(hwc_window_data->client_type),
+                                       _comp_to_str(hwc_window_data->validated_type),
+                                       hwc_window_data->lzpos,
+                                       hwc_window_data->name ? hwc_window_data->name : "NONE");
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static int
+_exynos_hwc_window_can_set_on_hw_layer(tdm_exynos_hwc_window_data *hwc_window_data)
+{
+       if (!hwc_window_data->surface)
+               return 0;
+
+       if (hwc_window_data->info.transform != HAL_TDM_TRANSFORM_NORMAL)
+               return 0;
+
+       if (hwc_window_data->info.src_config.pos.w != hwc_window_data->info.dst_pos.w)
+               return 0;
+
+       if (hwc_window_data->info.src_config.pos.h != hwc_window_data->info.dst_pos.h)
+               return 0;
+
+       if (!IS_RGB(hwc_window_data->info.src_config.format))
+               return 0;
+
+       if (hwc_window_data->info.dst_pos.x > hwc_window_data->hwc_data->output_data->current_mode->hdisplay ||
+               hwc_window_data->info.dst_pos.y > hwc_window_data->hwc_data->output_data->current_mode->vdisplay)
+               return 0;
+
+       /* do not allow hw layer_data when the size of window is over the one of output mode resolution */
+       if (hwc_window_data->info.dst_pos.w > hwc_window_data->hwc_data->output_data->current_mode->hdisplay ||
+               hwc_window_data->info.dst_pos.h > hwc_window_data->hwc_data->output_data->current_mode->vdisplay)
+               return 0;
+
+       if (hwc_window_data->info.src_config.pos.w < MIN_WIDTH || hwc_window_data->info.src_config.pos.w % 2)
+               return 0;
+
+       return 1;
+}
+
+static tbm_surface_queue_h
+_exynos_hwc_window_get_tbm_buffer_queue(hal_tdm_hwc_window *hwc_window, hal_tdm_error *error)
+{
+       tdm_exynos_hwc_window_data *hwc_window_data = NULL;
+       tbm_surface_queue_h tqueue = NULL;
+       int width, height;
+       tbm_format format;
+
+       if (error)
+               *error = HAL_TDM_ERROR_INVALID_PARAMETER;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window != NULL, NULL);
+
+       hwc_window_data = hwc_window;
+
+       width = hwc_window_data->info.src_config.size.h;
+       height = hwc_window_data->info.src_config.size.v;
+       format = hwc_window_data->info.src_config.format;
+
+       tqueue = tbm_surface_queue_create(NUM_BUFFERS, width, height, format, TBM_BO_SCANOUT);
+       if (error)
+               *error = HAL_TDM_ERROR_OPERATION_FAILED;
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(tqueue != NULL, NULL);
+
+       if (error)
+               *error = HAL_TDM_ERROR_NONE;
+
+       return tqueue;
+}
+
+static hal_tdm_error
+_exynos_hwc_layer_attach_window(tdm_exynos_layer *layer_data, tdm_exynos_hwc_window_data *hwc_window_data)
+{
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_OPERATION_FAILED);
+
+       if (hwc_window_data == NULL || hwc_window_data->surface == NULL) {
+               if (layer_data->display_buffer)
+                       ret = tdm_exynos_layer_unset_buffer(layer_data);
+               TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret);
+       } else {
+               ret = tdm_exynos_layer_set_info((tdm_layer *)layer_data, (tdm_exynos_layer_info *)&(hwc_window_data->info));
+               TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret);
+               TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data->surface != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+               ret = tdm_exynos_layer_set_buffer(layer_data, hwc_window_data->surface);
+               TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret);
+       }
+
+       return ret;
+}
+
+static hal_tdm_error
+_exynos_hwc_prepare_commit(tdm_exynos_hwc *hwc_data)
+{
+       tdm_exynos_hwc_window_data *hwc_window_data = NULL;
+       tdm_exynos_layer *layer_data = NULL;
+       int use_layers_zpos[NUM_LAYERS] = {0,};
+       int lzpos = 0;
+
+       /* set target hwc window to the layer_data */
+       if (hwc_data->need_target_window) {
+               layer_data = tdm_exynos_output_data_get_layer_data(hwc_data->output_data, hwc_data->target_hwc_window->lzpos);
+               _exynos_hwc_layer_attach_window(layer_data, hwc_data->target_hwc_window);
+               use_layers_zpos[hwc_data->target_hwc_window->lzpos] = 1;
+       }
+
+       /* set the hwc_windows to the layers */
+       LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) {
+               if (hwc_window_data->validated_type == HAL_TDM_HWC_WIN_COMPOSITION_NONE ||
+                       hwc_window_data->validated_type == HAL_TDM_HWC_WIN_COMPOSITION_CLIENT)
+                       continue;
+
+               if (hwc_window_data == hwc_data->target_hwc_window)
+                       continue;
+
+               layer_data = tdm_exynos_output_data_get_layer_data(hwc_data->output_data, hwc_window_data->lzpos);
+               _exynos_hwc_layer_attach_window(layer_data, hwc_window_data);
+               use_layers_zpos[hwc_window_data->lzpos] = 1;
+       }
+
+       /* unset the unused layers */
+       for (lzpos = 0; lzpos < NUM_LAYERS; lzpos++) {
+               if (use_layers_zpos[lzpos])
+                       continue;
+
+               layer_data = tdm_exynos_output_data_get_layer_data(hwc_data->output_data, lzpos);
+               if (!layer_data)
+                       continue;
+
+               _exynos_hwc_layer_attach_window(layer_data, NULL);
+       }
+
+       /* for debug */
+       for (lzpos = NUM_LAYERS -1 ; lzpos >= 0; lzpos--) {
+               if (use_layers_zpos[lzpos])
+                       TDM_BACKEND_DBG(" lzpos(%d) : %s", lzpos, use_layers_zpos[lzpos] ? "SET" : "UNSET");
+       }
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+/* assign the validated_type to the composited_wnds
+ * assign the layer_zpos to the composited_wnds
+ */
+static void
+_exynos_hwc_apply_policy(tdm_exynos_hwc *hwc_data , hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds)
+{
+       tdm_exynos_hwc_window_data *hwc_window_data = NULL;
+       tdm_exynos_hwc_window_data **composited_list = NULL;
+       int client_count = 0;
+       int device_count = 0;
+       int video_count = 0;
+       int ui_lzpos_top = ZPOS_2;
+       int ui_lzpos_bottom = ZPOS_0;
+       int num_ui_layers = NUM_UI_LAYERS;
+       int set_clients_below = 0;
+       int i = 0;
+
+       composited_list = (tdm_exynos_hwc_window_data **)composited_wnds;
+
+       /* initialize the need_target_window */
+       hwc_data->need_target_window = 0;
+
+       /* initialize the validated_types */
+       LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) {
+               if (hwc_window_data->validated_type != HAL_TDM_HWC_WIN_COMPOSITION_NONE)
+                       hwc_window_data->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_NONE;
+       }
+
+       /* use the target_window to commit when there is no window. */
+       if (num_wnds == 0) {
+               hwc_data->need_target_window = 1;
+               hwc_data->target_hwc_window->lzpos = ui_lzpos_bottom;
+               return;
+       }
+
+       /* 1. first check validate_type without target_window */
+       for (i = 0; i < num_wnds; i++) {
+               switch (composited_list[i]->client_type) {
+               case HAL_TDM_HWC_WIN_COMPOSITION_VIDEO:
+                       composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_VIDEO;
+                       video_count++;
+                       continue;
+               case HAL_TDM_HWC_WIN_COMPOSITION_DEVICE:
+                       if (video_count > 0) break;
+                       if (set_clients_below) break;
+                       if (num_ui_layers <= 0) break;
+                       if (!_exynos_hwc_window_can_set_on_hw_layer(composited_list[i])) break;
+
+                       composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_DEVICE;
+                       device_count++;
+                       num_ui_layers--;
+                       continue;
+               default:
+                       break;
+               }
+
+               composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_CLIENT;
+               client_count++;
+               set_clients_below = 1;
+       }
+
+       /* 2. check need target window and set ui_lzpos top and bottom */
+       num_ui_layers = NUM_UI_LAYERS;
+
+       if (video_count > 0) {
+               ui_lzpos_bottom++;
+               num_ui_layers--;
+       }
+
+       if (client_count > 0) {
+               ui_lzpos_bottom++;
+               num_ui_layers--;
+               hwc_data->need_target_window = 1;
+               hwc_data->target_hwc_window->lzpos = ui_lzpos_bottom - 1;
+       }
+
+       if (num_ui_layers > device_count)
+               ui_lzpos_top = ui_lzpos_bottom + device_count - 1;
+
+       /* 3. set lzpos and modify validate_type with target_window */
+       for (i = 0; i < num_wnds; i++) {
+               switch (composited_list[i]->validated_type) {
+               case HAL_TDM_HWC_WIN_COMPOSITION_VIDEO:
+                       composited_list[i]->lzpos = ZPOS_VIDEO1;
+                       continue;
+               case HAL_TDM_HWC_WIN_COMPOSITION_DEVICE:
+                       if (num_ui_layers <= 0) break;
+                       composited_list[i]->lzpos = ui_lzpos_top;
+                       ui_lzpos_top--;
+                       num_ui_layers--;
+                       continue;
+               default:
+                       break;
+               }
+
+               composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_CLIENT;
+               composited_list[i]->lzpos = ZPOS_NONE;
+       }
+}
+
+static int
+_exynos_hwc_get_changed_number(tdm_exynos_hwc *hwc_data)
+{
+       int num = 0;
+       tdm_exynos_hwc_window_data *hwc_window_data = NULL;
+
+       LIST_FOR_EACH_ENTRY(hwc_window_data, &hwc_data->hwc_window_list, link) {
+               if (hwc_window_data->client_type == HAL_TDM_HWC_WIN_COMPOSITION_NONE)
+                       continue;
+
+               if (hwc_window_data->client_type != hwc_window_data->validated_type)
+                       num++;
+       }
+
+       return num;
+}
+
+hal_tdm_hwc_window *
+_exynos_hwc_create_window(hal_tdm_hwc *hwc, hal_tdm_hwc_window_info *info, hal_tdm_error *error)
+{
+       tdm_exynos_hwc *hwc_data = hwc;
+       tdm_exynos_hwc_window_data *hwc_window_data = NULL;
+
+       if (error)
+               *error = HAL_TDM_ERROR_NONE;
+
+       if (!hwc_data) {
+               TDM_BACKEND_ERR("invalid params");
+               if (error)
+                       *error = HAL_TDM_ERROR_INVALID_PARAMETER;
+               return NULL;
+       }
+
+       hwc_window_data = calloc(1, sizeof(tdm_exynos_hwc_window_data));
+       if (!hwc_window_data) {
+               TDM_BACKEND_ERR("alloc failed");
+               if (error)
+                       *error = HAL_TDM_ERROR_OUT_OF_MEMORY;
+               return NULL;
+       }
+
+       hwc_window_data->hwc_data = hwc_data;
+
+       if (info)
+               memcpy(&hwc_window_data->info, info, sizeof(hal_tdm_hwc_window_info));
+
+       LIST_INITHEAD(&hwc_window_data->link);
+
+       return hwc_window_data;
+}
+
+hal_tdm_hwc_window *
+exynos_hwc_create_window(hal_tdm_hwc *hwc, hal_tdm_error *error)
+{
+       tdm_exynos_hwc *hwc_data = hwc;
+       tdm_exynos_hwc_window_data *hwc_window_data = NULL;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, NULL);
+
+       hwc_window_data = _exynos_hwc_create_window(hwc_data, NULL, error);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data, NULL);
+
+       LIST_ADDTAIL(&hwc_window_data->link, &hwc_data->hwc_window_list);
+
+       TDM_BACKEND_DBG("hwc_window(%p) create", hwc_window_data);
+       if (error)
+               *error = HAL_TDM_ERROR_NONE;
+
+       return hwc_window_data;
+}
+
+hal_tdm_error
+exynos_hwc_get_video_supported_formats(hal_tdm_hwc *hwc, const tbm_format **formats, int *count)
+{
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(formats != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(count != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       // TODO: fix these formats.
+       *formats = hwc_window_video_formats;
+       *count = sizeof(hwc_window_video_formats) / sizeof(tbm_format);
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_get_capabilities(hal_tdm_hwc *hwc, hal_tdm_hwc_capability *capabilities)
+{
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(capabilities != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       *capabilities = 0;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_get_available_properties(hal_tdm_hwc *hwc, const hal_tdm_prop **props, int *count)
+{
+       tdm_exynos_hwc *hwc_data = hwc;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(props != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(count != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       *props = NULL;
+       *count = 0;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+tbm_surface_queue_h
+exynos_hwc_get_client_target_buffer_queue(hal_tdm_hwc *hwc, hal_tdm_error *error)
+{
+       tdm_exynos_hwc *hwc_data = hwc;
+       tbm_surface_queue_h tqueue = NULL;
+
+       if (error)
+               *error = HAL_TDM_ERROR_INVALID_PARAMETER;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, NULL);
+
+       if (hwc_data->target_hwc_window == NULL) {
+               if (error)
+                       *error = HAL_TDM_ERROR_OPERATION_FAILED;
+               return NULL;
+       }
+
+       tqueue = _exynos_hwc_window_get_tbm_buffer_queue(hwc_data->target_hwc_window, error);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(tqueue, NULL);
+
+       if (error)
+               *error = HAL_TDM_ERROR_NONE;
+
+       return tqueue;
+}
+
+hal_tdm_error
+exynos_hwc_set_client_target_buffer(hal_tdm_hwc *hwc, tbm_surface_h buffer, hal_tdm_region damage)
+{
+       tdm_exynos_hwc *hwc_data = hwc;
+       hal_tdm_error err;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data->target_hwc_window  != NULL, HAL_TDM_ERROR_OPERATION_FAILED);
+
+       err = exynos_hwc_window_set_buffer(hwc_data->target_hwc_window, buffer);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(err == HAL_TDM_ERROR_NONE, err);
+
+       err = exynos_hwc_window_set_buffer_damage(hwc_data->target_hwc_window, damage);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(err == HAL_TDM_ERROR_NONE, err);
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_validate(hal_tdm_hwc *hwc, hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types)
+{
+       tdm_exynos_hwc *hwc_data = hwc;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(num_types != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       TDM_BACKEND_DBG(" ==============Validate=================================");
+
+       _exynos_hwc_apply_policy(hwc_data, composited_wnds, num_wnds);
+
+       *num_types = _exynos_hwc_get_changed_number(hwc_data);
+
+       _print_validate_result(hwc_data, composited_wnds, num_wnds);
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_get_changed_composition_types(hal_tdm_hwc *hwc, uint32_t *num_elements,
+                               hal_tdm_hwc_window **hwc_wnds, hal_tdm_hwc_window_composition *composition_types)
+{
+       tdm_exynos_hwc *hwc_data = hwc;
+       tdm_exynos_hwc_window_data *hwc_window_data = NULL;
+       int num = 0;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(num_elements != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       if ((hwc_wnds == NULL) || (composition_types == NULL)) {
+               *num_elements = _exynos_hwc_get_changed_number(hwc_data);
+               return HAL_TDM_ERROR_NONE;
+       }
+
+       LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) {
+               if (hwc_window_data->client_type == HAL_TDM_HWC_WIN_COMPOSITION_NONE)
+                       continue;
+
+               if (num >= *num_elements)
+                       break;
+
+               if (hwc_window_data->client_type != hwc_window_data->validated_type) {
+                       composition_types[num] = hwc_window_data->validated_type;
+                       hwc_wnds[num] = hwc_window_data;
+                       num++;
+               }
+       }
+
+       /* set real num of changed composition types */
+       *num_elements = num;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_accept_validation(hal_tdm_hwc *hwc)
+{
+       tdm_exynos_hwc *hwc_data = hwc;
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data->output_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       TDM_BACKEND_DBG(" ==============Accept Changes Done=================================");
+
+       ret = _exynos_hwc_prepare_commit(hwc_data);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret);
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_commit(hal_tdm_hwc *hwc, int sync, void *user_data)
+{
+       tdm_exynos_hwc *hwc_data = hwc;
+       tdm_exynos_output *output_data = NULL;
+       hal_tdm_error ret;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       output_data = hwc_data->output_data;
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       TDM_BACKEND_DBG(" ==============COMMIT=================================");
+
+       ret = exynos_output_commit(output_data, sync, user_data);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret);
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_set_commit_handler(hal_tdm_hwc *hwc, hal_tdm_hwc_commit_handler func)
+{
+       tdm_exynos_hwc *hwc_data = hwc;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       hwc_data->commit_func = func;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_initailize_target_window(tdm_exynos_hwc *hwc_data, int width, int height)
+{
+       hal_tdm_hwc_window_info info = {0};
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+       tdm_exynos_hwc_window_data *target_hwc_window;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       info.dst_pos.x = 0;
+       info.dst_pos.y = 0;
+       info.dst_pos.h = height;
+       info.dst_pos.w = width;
+
+       info.src_config.pos.x = 0;
+       info.src_config.pos.y = 0;
+       info.src_config.pos.h = height;
+       info.src_config.pos.w = width;
+
+       info.src_config.size.h = width;
+       info.src_config.size.v = height;
+       info.src_config.format = TBM_FORMAT_ARGB8888;
+
+       target_hwc_window = _exynos_hwc_create_window(hwc_data, &info, &ret);
+       if (ret != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("create target hwc window failed (%d)", ret);
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       if (hwc_data->target_hwc_window)
+               exynos_hwc_window_destroy(hwc_data->target_hwc_window);
+
+       hwc_data->target_hwc_window = target_hwc_window;
+       hwc_data->need_set_crtc = 1;
+
+       return HAL_TDM_ERROR_NONE;
+}
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_hwc_window.c b/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_hwc_window.c
new file mode 100644 (file)
index 0000000..86eb977
--- /dev/null
@@ -0,0 +1,136 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_exynos.h"
+
+void
+exynos_hwc_window_destroy(hal_tdm_hwc_window *hwc_window)
+{
+       tdm_exynos_hwc_window_data *hwc_window_data = hwc_window;
+
+       TDM_BACKEND_RETURN_IF_FAIL(hwc_window_data != NULL);
+
+       LIST_DEL(&hwc_window_data->link);
+
+       free(hwc_window_data);
+}
+
+hal_tdm_error
+exynos_hwc_window_set_composition_type(hal_tdm_hwc_window *hwc_window,
+                                                                       hal_tdm_hwc_window_composition comp_type)
+{
+       tdm_exynos_hwc_window_data *hwc_window_data = hwc_window;
+       tdm_exynos_hwc *hwc_data = hwc_window_data->hwc_data;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       /* change the client_type when it is different from one which has before */
+       if (hwc_window_data->client_type == comp_type)
+               return HAL_TDM_ERROR_NONE;
+
+       hwc_window_data->client_type = comp_type;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_window_set_buffer_damage(hal_tdm_hwc_window *hwc_window, hal_tdm_region damage)
+{
+       tdm_exynos_hwc_window_data *hwc_window_data = hwc_window;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       //TODO::
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_window_set_info(hal_tdm_hwc_window *hwc_window, hal_tdm_hwc_window_info *info)
+{
+       tdm_exynos_hwc_window_data *hwc_window_data = hwc_window;
+       tdm_exynos_hwc *hwc_data;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       hwc_data = hwc_window_data->hwc_data;
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(info != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       if (!memcmp(&hwc_window_data->info, info, sizeof(hal_tdm_hwc_window_info)))
+               return HAL_TDM_ERROR_NONE;
+
+       hwc_window_data->info = *info;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_window_set_buffer(hal_tdm_hwc_window *hwc_window, tbm_surface_h surface)
+{
+       tdm_exynos_hwc_window_data *hwc_window_data = hwc_window;
+       hal_tdm_error err = HAL_TDM_ERROR_OPERATION_FAILED;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data != NULL, err);
+
+       if (hwc_window_data->surface == surface)
+               return HAL_TDM_ERROR_NONE;
+
+       hwc_window_data->surface = surface;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_window_set_property(hal_tdm_hwc_window *hwc_window, unsigned int id, hal_tdm_value value)
+{
+       tdm_exynos_hwc_window_data *hwc_window_data = hwc_window;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       //TODO:
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_window_get_property(hal_tdm_hwc_window *hwc_window, unsigned int id, hal_tdm_value *value)
+{
+       tdm_exynos_hwc_window_data *hwc_window_data = hwc_window;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       //TODO:
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_window_get_constraints(hal_tdm_hwc_window *hwc_window, int *constraints)
+{
+       tdm_exynos_hwc_window_data *hwc_window_data = hwc_window;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(constraints != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       // no constraints
+       *constraints = 0;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_hwc_window_set_name(hal_tdm_hwc_window *hwc_window, const char *name)
+{
+       tdm_exynos_hwc_window_data *hwc_window_data = hwc_window;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       if (!name)
+               return HAL_TDM_ERROR_NONE;
+
+       snprintf(hwc_window_data->name, HAL_TDM_NAME_LEN, "%s", name);
+
+       return HAL_TDM_ERROR_NONE;
+}
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_pp.c b/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_pp.c
new file mode 100644 (file)
index 0000000..0ee3455
--- /dev/null
@@ -0,0 +1,1025 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#define PP_MAX_STEP 2
+#include "tdm_backend_exynos.h"
+
+#define EXYNOS_C(b, m)              (((b) >> (m)) & 0xFF)
+#define EXYNOS_FOURCC_STR(id)      EXYNOS_C(id, 0), EXYNOS_C(id, 8), EXYNOS_C(id, 16), EXYNOS_C(id, 24)
+typedef struct _tdm_exynos_pp_buffer {
+       int index;
+       tbm_surface_h src;
+       tbm_surface_h dst;
+       struct list_head link;
+} tdm_exynos_pp_buffer;
+
+typedef enum _tdm_exynos_pp_ctrl {
+       PP_STOP = 0,
+       PP_RUN = 1,
+       PP_PAUSE = 2
+} tdm_exynos_pp_ctrl;
+
+typedef enum _tdm_exynos_task_status {
+       TASK_WAITING,
+       TASK_CONVERTING,
+       TASK_DONE
+} tdm_exynos_task_status;
+
+typedef struct _tdm_exynos_prop_id {
+       enum tdm_pp_ctrl status;
+       unsigned int prop_id;
+       struct list_head link;
+} tdm_exynos_prop_id;
+
+typedef struct _tdm_exynos_pp_task {
+       int stamp;
+       unsigned int prop_id[PP_MAX_STEP];
+       tdm_exynos_pp_buffer buffers[PP_MAX_STEP];
+       unsigned int max_step;
+       unsigned int current_step;
+       int status;
+       hal_tdm_pp_done_handler done_func;
+       void *done_user_data;
+       struct list_head link;
+} tdm_exynos_pp_task;
+
+typedef struct _tdm_exynos_pp_roadmap {
+       unsigned int prop_id[PP_MAX_STEP];
+       hal_tdm_info_pp step_info[PP_MAX_STEP];
+       unsigned int max_step;
+} tdm_exynos_pp_roadmap;
+typedef struct _tdm_exynos_pp_data {
+       tdm_exynos_display *display_data;
+       int stamp;
+       struct list_head pending_buffer_list;
+       struct list_head pending_tasks_list;
+       struct list_head prop_id_list;
+       tdm_exynos_pp_roadmap roadmap;
+       tdm_exynos_pp_roadmap new_roadmap;
+       tdm_exynos_pp_task *current_task_p;
+       hal_tdm_pp_done_handler done_func;
+       void *done_user_data;
+       int roadmap_changed;
+       int new_buffers;
+       int first_event;
+       int pp_need_destroy;
+       struct list_head link;
+       int sync;
+} tdm_exynos_pp_data;
+
+#if 1
+static tbm_format pp_formats[] = {
+       TBM_FORMAT_XRGB8888,
+       TBM_FORMAT_ARGB8888,
+       TBM_FORMAT_RGB888,
+       TBM_FORMAT_RGB565,
+       TBM_FORMAT_NV12,
+       TBM_FORMAT_YUV420,
+       TBM_FORMAT_YUV422,
+};
+#else
+static tbm_format *pp_formats = NULL;
+#endif
+
+#if 1
+#define NUM_PP_FORMAT   (sizeof(pp_formats) / sizeof(pp_formats[0]))
+#else
+#define NUM_PP_FORMAT 0
+#endif
+
+static int pp_list_init = 0;
+static int pp_stamp = 1001;
+static int task_stamp = 10001;
+static struct list_head pp_list;
+
+void _tdm_exynos_pp_post_work(tdm_exynos_pp_data *pp_data, u32 prop_id);
+
+static tdm_exynos_prop_id *
+_find_prop_id(tdm_exynos_pp_data *pp_data, unsigned int prop_id)
+{
+       tdm_exynos_prop_id *prop = NULL;
+       LIST_FOR_EACH_ENTRY(prop, &pp_data->prop_id_list, link) {
+               if (prop->prop_id == prop_id)
+                       return prop;
+       }
+       return NULL;
+}
+
+int _tdm_exynos_pp_check_struct(tdm_exynos_pp_data *pp_data)
+{
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(pp_list_init == 1, 0);
+       if (pp_data == NULL) {
+               TDM_BACKEND_ERR("pp nil(0). Received NULL pointer");
+               return 0;
+       }
+       tdm_exynos_pp_data * pp_next = NULL;
+       LIST_FOR_EACH_ENTRY(pp_next, &pp_list, link) {
+               if (pp_next->stamp == pp_data->stamp)
+                       return 1;
+       }
+       TDM_BACKEND_ERR("pp %p(%d). Wrong ", pp_data, pp_data->stamp);
+       return 0;
+}
+
+void _tdm_exynos_pp_roadmap_print(tdm_exynos_pp_roadmap *roadmap)
+{
+       TDM_BACKEND_RETURN_IF_FAIL(roadmap);
+       int i;
+       TDM_BACKEND_DBG("Count of steps %d", roadmap->max_step);
+       for (i = 0; i < roadmap->max_step; i++) {
+               TDM_BACKEND_DBG("Step %d, Prop_id %d", i+1, roadmap->prop_id[i]);
+               TDM_BACKEND_DBG("format (%u)%c%c%c%c -> (%u)%c%c%c%c", roadmap->step_info[i].src_config.format,
+                               EXYNOS_FOURCC_STR(roadmap->step_info[i].src_config.format), roadmap->step_info[i].dst_config.format,
+                               EXYNOS_FOURCC_STR(roadmap->step_info[i].dst_config.format));
+               TDM_BACKEND_DBG("rotate+flip is %u+%s", roadmap->step_info[i].transform % 4,
+                               roadmap->step_info[i].transform > 3 ? "Horizontal" : "None");
+               TDM_BACKEND_DBG("size src->dst (w)x(h) (%u)x(%u) -> (%u)x(%u)", roadmap->step_info[i].src_config.size.h,
+                               roadmap->step_info[i].src_config.size.v, roadmap->step_info[i].dst_config.size.h,
+                               roadmap->step_info[i].dst_config.size.v);
+               TDM_BACKEND_DBG("crop src->dst (x)(y)+(w)+(h) (%u)x(%u)+(%u)+(%u) -> (%u)x(%u)+(%u)+(%u)", roadmap->step_info[i].src_config.pos.x,
+                               roadmap->step_info[i].src_config.pos.y, roadmap->step_info[i].src_config.pos.w,
+                               roadmap->step_info[i].src_config.pos.h, roadmap->step_info[i].dst_config.pos.x,
+                               roadmap->step_info[i].dst_config.pos.y, roadmap->step_info[i].dst_config.pos.w,
+                               roadmap->step_info[i].dst_config.pos.h);
+       }
+       TDM_BACKEND_DBG("-------------------------------------------------------------------");
+}
+
+int _tdm_exynos_pp_roadmap_copy(tdm_exynos_pp_roadmap *to_roadmap, tdm_exynos_pp_roadmap *from_roadmap)
+{
+       int i = 0;
+       for (i = 0; i < PP_MAX_STEP; i++)
+               memcpy(&to_roadmap->step_info[i], &from_roadmap->step_info[i], sizeof(hal_tdm_info_pp));
+       to_roadmap->max_step = from_roadmap->max_step;
+       return 1;
+}
+
+#if 1
+static void
+_tdm_exynos_pp_property_format_check(struct tdm_pp_property *prop)
+{
+       int src_alpha = 0, dst_alpha = 0;
+       __u32 src_fmt, dst_fmt, change_fmt = 0;
+       __u8 alpha;
+
+       src_fmt = prop->config[0].fmt;
+       dst_fmt = prop->config[1].fmt;
+
+       /* no corresponding format to AYUV */
+       if (src_fmt == TBM_FORMAT_AYUV || dst_fmt == TBM_FORMAT_AYUV)
+               return;
+
+       alpha = src_fmt & 0xff;
+       if (alpha == 'A')
+               src_alpha = 1;
+       alpha = (src_fmt >> 8) & 0xff;
+       if (alpha == 'A')
+               src_alpha = 2;
+
+       alpha = dst_fmt & 0xff;
+       if (alpha == 'A')
+               dst_alpha = 1;
+       alpha = (dst_fmt >> 8) & 0xff;
+       if (alpha == 'A')
+               dst_alpha = 2;
+
+       /* not chane format if both have alpha or not*/
+       if ((src_alpha == 0 && dst_alpha == 0) ||
+               (src_alpha != 0 && dst_alpha != 0))
+               return;
+
+       alpha = 'X';
+       if (src_alpha == 1) {
+               change_fmt = src_fmt;
+               change_fmt = (change_fmt & 0xffffff00) | alpha;
+               prop->config[0].fmt = change_fmt;
+       } else if (src_alpha == 2) {
+               change_fmt = src_fmt;
+               change_fmt = (change_fmt & 0xffff00ff) | alpha << 8;
+               prop->config[0].fmt = change_fmt;
+       } else if (dst_alpha == 1) {
+               change_fmt = dst_fmt;
+               change_fmt = (change_fmt & 0xffffff00) | alpha;
+               prop->config[1].fmt = change_fmt;
+       } else if (dst_alpha == 2) {
+               change_fmt = dst_fmt;
+               change_fmt = (change_fmt & 0xffff00ff) | alpha << 8;
+               prop->config[1].fmt = change_fmt;
+       }
+
+       if (src_alpha != 0)
+               TDM_BACKEND_DBG("src format change fmt(%c%c%c%c) -> fmt(%c%c%c%c)",
+                               FOURCC_STR(src_fmt), FOURCC_STR(change_fmt));
+       else
+               TDM_BACKEND_DBG("dst format change fmt(%c%c%c%c) -> fmt(%c%c%c%c)",
+                               FOURCC_STR(dst_fmt), FOURCC_STR(change_fmt));
+}
+
+static unsigned int
+_tdm_exynos_pp_set(tdm_exynos_pp_data *pp_data, hal_tdm_info_pp *info,
+                                unsigned int prop_id)
+{
+       tdm_exynos_display *display_data = pp_data->display_data;
+       struct tdm_pp_property property;
+       int ret = 0;
+
+       CLEAR(property);
+       property.config[0].ops_id = TDM_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(hal_tdm_size));
+       memcpy(&property.config[0].pos, &info->src_config.pos, sizeof(hal_tdm_pos));
+       property.config[1].ops_id = TDM_OPS_DST;
+       property.config[1].degree = info->transform % 4;
+       property.config[1].flip = (info->transform > 3) ? TDM_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(hal_tdm_size));
+       memcpy(&property.config[1].pos, &info->dst_config.pos, sizeof(hal_tdm_pos));
+       property.cmd = PP_CMD_M2M;
+       property.prop_id = prop_id;
+       property.type = info->sync ? PP_SYNC_WORK : PP_EVENT_DRIVEN;
+
+       _tdm_exynos_pp_property_format_check(&property);
+
+       TDM_BACKEND_INFO("pp %p(%d). src : flip(%x) deg(%d) fmt(%c%c%c%c) sz(%dx%d) pos(%d,%d %dx%d)  ",
+                       pp_data, pp_data->stamp,
+                       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_BACKEND_INFO("pp %p(%d). dst : flip(%x) deg(%d) fmt(%c%c%c%c) sz(%dx%d) pos(%d,%d %dx%d)  ",
+                       pp_data, pp_data->stamp,
+                       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(display_data->drm_fd, DRM_IOCTL_TDM_PP_SET_PROPERTY, &property);
+       TDM_BACKEND_INFO("DRM_IOCTL_TDM_PP_SET_PROPERTY[0x%x]ret[%d]",
+               DRM_IOCTL_TDM_PP_SET_PROPERTY, ret);
+
+       if (ret) {
+               TDM_BACKEND_ERR("pp %p(%d). failed: %m", pp_data, pp_data->stamp);
+               return 0;
+       }
+
+       TDM_BACKEND_INFO("pp %p(%d). success. prop_id(%u) ", pp_data, pp_data->stamp, property.prop_id);
+       return property.prop_id;
+}
+#endif
+#if 1
+static hal_tdm_error
+_tdm_exynos_pp_queue(tdm_exynos_pp_data *pp_data, unsigned int prop_id,
+                                  tbm_surface_h src, tbm_surface_h dst, enum tdm_pp_buf_type type)
+{
+       tdm_exynos_display *display_data = pp_data->display_data;
+       struct tdm_pp_queue_buf buf;
+       int i, bo_num, ret = 0;
+       uint32_t size = 0, stride = 0, offset = 0;
+
+       CLEAR(buf);
+       buf.prop_id = prop_id;
+       buf.ops_id = TDM_OPS_SRC;
+       buf.buf_type = type;
+       buf.buf_id = 0;
+       buf.user_data = (__u64)(uintptr_t)pp_data;
+       bo_num = tbm_surface_internal_get_num_bos(src);
+       for (i = 0; i < TDM_PLANAR_MAX && i < bo_num; i++) {
+               tbm_bo bo = tbm_surface_internal_get_bo(src, i);
+               buf.handle[i] = (__u32)tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+               tbm_surface_internal_get_plane_data(src, i, &size, &offset, &stride);
+               TDM_BACKEND_DBG("pp %p(%d). prop_id(%d) src plane(%d) size(%u) offset(%u) stride(%u) ",
+                               pp_data, pp_data->stamp, buf.prop_id, i, size, offset, stride);
+       }
+
+       TDM_BACKEND_DBG("pp %p(%d). prop_id(%d) ops_id(%d) ctrl(%d) id(%d) handles(%x %x %x). ",
+                       pp_data, pp_data->stamp,
+                       buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id,
+                       buf.handle[0], buf.handle[1], buf.handle[2]);
+
+       ret = ioctl(display_data->drm_fd, DRM_IOCTL_TDM_PP_QUEUE_BUF, &buf);
+       if (ret) {
+               TDM_BACKEND_ERR("pp %p(%d). src failed. prop_id(%d) op(%d) buf(%d) id(%d). %m",
+                               pp_data, pp_data->stamp,
+                               buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id);
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       CLEAR(buf);
+       buf.prop_id = prop_id;
+       buf.ops_id = TDM_OPS_DST;
+       buf.buf_type = type;
+       buf.buf_id = 0;
+       buf.user_data = (__u64)(uintptr_t)pp_data;
+       bo_num = tbm_surface_internal_get_num_bos(dst);
+       for (i = 0; i < TDM_PLANAR_MAX && i < bo_num; i++) {
+               tbm_bo bo = tbm_surface_internal_get_bo(dst, i);
+               buf.handle[i] = (__u32)tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+               tbm_surface_internal_get_plane_data(dst, i, &size, &offset, &stride);
+               TDM_BACKEND_DBG("pp %p(%d). prop_id(%d) dst plane(%d) size(%u) offset(%u) stride(%u) ",
+                               pp_data, pp_data->stamp, buf.prop_id, i, size, offset, stride);
+       }
+
+       TDM_BACKEND_INFO("pp %p(%d). prop_id(%d) ops_id(%d) ctrl(%d) id(%d) handles(%x %x %x). ",
+                       pp_data, pp_data->stamp,
+                       buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id,
+                       buf.handle[0], buf.handle[1], buf.handle[2]);
+
+       ret = ioctl(display_data->drm_fd, DRM_IOCTL_TDM_PP_QUEUE_BUF, &buf);
+       TDM_BACKEND_INFO("DRM_IOCTL_TDM_PP_QUEUE_BUF[0x%x]ret[%d]",
+               DRM_IOCTL_TDM_PP_QUEUE_BUF, ret);
+
+       if (ret) {
+               TDM_BACKEND_ERR("pp %p(%d). dst failed. prop_id(%d) op(%d) buf(%d) id(%d). %m",
+                               pp_data, pp_data->stamp,
+                               buf.prop_id, buf.ops_id, buf.buf_type, buf.buf_id);
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       TDM_BACKEND_INFO("pp %p(%d). Success. prop_id(%d)", pp_data, pp_data->stamp, buf.prop_id);
+       return HAL_TDM_ERROR_NONE;
+}
+#endif
+#if 1
+static hal_tdm_error
+_tdm_exynos_pp_cmd(tdm_exynos_pp_data *pp_data, unsigned int prop_id,
+                                tdm_exynos_pp_ctrl cmd)
+{
+       tdm_exynos_display *display_data = pp_data->display_data;
+       struct tdm_pp_cmd_ctrl ctrl;
+       int ret = 0;
+       tdm_exynos_prop_id * found_prop = _find_prop_id(pp_data, prop_id);
+       if (found_prop == NULL) {
+               if ((found_prop = calloc(1, sizeof(tdm_exynos_prop_id))) == NULL) {
+                       TDM_BACKEND_ERR("pp %p(%d). Out of memory", pp_data, pp_data->stamp);
+                       return HAL_TDM_ERROR_OUT_OF_MEMORY;
+               }
+               found_prop->prop_id = prop_id;
+               found_prop->status = PP_CTRL_STOP;
+               LIST_ADDTAIL(&found_prop->link, &pp_data->prop_id_list);
+       }
+       ctrl.prop_id = prop_id;
+       switch (cmd) {
+       case PP_RUN:
+               if (found_prop->status == PP_CTRL_STOP)
+                       ctrl.ctrl = PP_CTRL_PLAY;
+               else if (found_prop->status == PP_CTRL_PAUSE)
+                       ctrl.ctrl = PP_CTRL_RESUME;
+               else if (found_prop->status == PP_CTRL_PLAY ||
+                                found_prop->status == PP_CTRL_RESUME)
+                       return HAL_TDM_ERROR_NONE;
+               break;
+       case PP_PAUSE:
+               if (found_prop->status == PP_CTRL_PLAY ||
+                       found_prop->status == PP_CTRL_RESUME)
+                       ctrl.ctrl = PP_CTRL_PAUSE;
+               else if (found_prop->status == PP_CTRL_PAUSE ||
+                                found_prop->status == PP_CTRL_STOP)
+                       return HAL_TDM_ERROR_NONE;
+               break;
+       case PP_STOP:
+               if (found_prop->status == PP_CTRL_STOP) {
+                       LIST_DEL(&found_prop->link);
+                       free(found_prop);
+                       return HAL_TDM_ERROR_NONE;
+               }
+               LIST_DEL(&found_prop->link);
+               free(found_prop);
+               ctrl.ctrl = PP_CTRL_STOP;
+               found_prop = NULL;
+               break;
+       default:
+               break;
+       }
+
+       TDM_BACKEND_DBG("pp %p(%d). prop_id(%d) ctrl(%d). ", pp_data, pp_data->stamp, ctrl.prop_id, ctrl.ctrl);
+
+       ret = ioctl(display_data->drm_fd, DRM_IOCTL_TDM_PP_CMD_CTRL, &ctrl);
+       if (ret) {
+               TDM_BACKEND_ERR("pp %p(%d). Failed. prop_id(%d) ctrl(%d). %m", pp_data, pp_data->stamp, ctrl.prop_id, ctrl.ctrl);
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+       if (found_prop)
+               found_prop->status = ctrl.ctrl;
+       TDM_BACKEND_DBG("pp %p(%d). Success. prop_id(%d) ", pp_data, pp_data->stamp, ctrl.prop_id);
+       return HAL_TDM_ERROR_NONE;
+}
+#endif
+static void
+_tdm_exynos_pp_destroy_task(tdm_exynos_pp_data *pp_data, tdm_exynos_pp_task * task)
+{
+       int i;
+
+       for (i = 0; i < task->max_step; i++) {
+               if (task->buffers[i].src)
+                       tbm_surface_internal_unref(task->buffers[i].src);
+               if (task->buffers[i].dst)
+                       tbm_surface_internal_unref(task->buffers[i].dst);
+       }
+
+       if (task->done_func) {
+               TDM_BACKEND_DBG("pp %p(%d). Return src %p dst %p", pp_data, pp_data->stamp,
+                               task->buffers[0].src, task->buffers[task->max_step-1].dst);
+               task->done_func(pp_data, task->buffers[0].src,
+                                               task->buffers[task->max_step-1].dst,
+                                               task->done_user_data);
+       }
+       TDM_BACKEND_DBG("pp %p(%d). Task %p(%d) released", pp_data, pp_data->stamp, task, task->stamp);
+       free(task);
+}
+
+static int
+_tdm_exynos_pp_make_new_tasks(tdm_exynos_pp_data *pp_data)
+{
+       tdm_exynos_pp_buffer *main_buffer = NULL, *b = NULL, *bb = NULL;
+       tdm_exynos_pp_task *new_task = NULL;
+       int i;
+       if (LIST_IS_EMPTY(&pp_data->pending_buffer_list)) {
+               TDM_BACKEND_WRN("pp %p(%d) buffer list is empty. Nothing to do", pp_data, pp_data->stamp);
+               return 0;
+       }
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
+               main_buffer = b;
+               if ((new_task = calloc(1, sizeof(tdm_exynos_pp_task))) == NULL) {
+                       TDM_BACKEND_ERR("Out of memory");
+                       return -1;
+               }
+               LIST_DEL(&b->link);
+               memcpy(new_task->prop_id, pp_data->roadmap.prop_id, sizeof(unsigned int)*PP_MAX_STEP);
+               new_task->stamp = task_stamp++;
+               new_task->max_step = pp_data->roadmap.max_step;
+               new_task->current_step = 0;
+               new_task->done_func = pp_data->done_func;
+               new_task->done_user_data = pp_data->done_user_data;
+               tbm_surface_internal_ref(main_buffer->src);
+               new_task->buffers[0].src = main_buffer->src;
+               tbm_surface_internal_ref(main_buffer->dst);
+               new_task->buffers[new_task->max_step-1].dst = main_buffer->dst;
+
+#if 0
+               if (new_task->max_step > 1) {
+                       tbm_surface_info_s src_buf_info;
+                       tbm_surface_info_s dst_buf_info;
+                       tbm_surface_get_info(main_buffer->src, &src_buf_info);
+                       tbm_surface_get_info(main_buffer->dst, &dst_buf_info);
+                       unsigned int max_width = (src_buf_info.width > dst_buf_info.width) ? src_buf_info.width : dst_buf_info.width;
+                       unsigned int max_height = (src_buf_info.height > dst_buf_info.height) ? src_buf_info.height : dst_buf_info.height;
+                       tbm_format temp_buf_fmt = dst_buf_info.format;
+                       for (i = 1; i < new_task->max_step; i++) {
+                               new_task->buffers[i-1].dst = tbm_surface_create(max_width, max_height, temp_buf_fmt);
+                               tbm_surface_internal_ref(new_task->buffers[i-1].dst);
+                               new_task->buffers[i].src = new_task->buffers[i-1].dst;
+                       }
+               }
+#endif
+               for (i = 1; i < new_task->max_step; i++) {
+                       new_task->buffers[i-1].dst = tbm_surface_create(pp_data->roadmap.step_info[i-1].dst_config.size.h,
+                                                                                                                       pp_data->roadmap.step_info[i-1].dst_config.size.v,
+                                                                                                                       pp_data->roadmap.step_info[i-1].dst_config.format);
+                       tbm_surface_internal_ref(new_task->buffers[i-1].dst);
+                       new_task->buffers[i].src = new_task->buffers[i-1].dst;
+                       }
+               LIST_ADDTAIL(&new_task->link, &pp_data->pending_tasks_list);
+               TDM_BACKEND_DBG("pp %p(%d). Add new src %p dst %p buffer", pp_data, pp_data->stamp, main_buffer->src, main_buffer->dst);
+               TDM_BACKEND_DBG("To New task %p(%d)", new_task, new_task->stamp);
+               free(main_buffer);
+               main_buffer = NULL;
+       }
+       return 1;
+}
+
+static hal_tdm_error
+_tdm_exynos_pp_worker(tdm_exynos_pp_data *pp_data)
+{
+       tdm_exynos_pp_task *next_task = NULL, *done_task = pp_data->current_task_p;
+       if (done_task) {
+               if (done_task->status == TASK_DONE) {
+                       ++(done_task->current_step);
+                       if (done_task->current_step < done_task->max_step) {
+                               TDM_BACKEND_DBG("pp %p(%d). Task %p(%d) setup next step %d of %d",
+                                               pp_data, pp_data->stamp, done_task, done_task->stamp,
+                                               done_task->current_step+1, done_task->max_step);
+                               if (_tdm_exynos_pp_queue(pp_data, done_task->prop_id[done_task->current_step],
+                                               done_task->buffers[done_task->current_step].src,
+                                               done_task->buffers[done_task->current_step].dst,
+                                               PP_BUF_ENQUEUE) != HAL_TDM_ERROR_NONE) {
+                                       return HAL_TDM_ERROR_OPERATION_FAILED;
+                               }
+                               done_task->status = TASK_CONVERTING;
+                               if (_tdm_exynos_pp_cmd(pp_data,
+                                                                        done_task->prop_id[done_task->current_step],
+                                                                        PP_RUN) != HAL_TDM_ERROR_NONE) {
+                                       return HAL_TDM_ERROR_OPERATION_FAILED;
+                               }
+                               return HAL_TDM_ERROR_NONE;
+                       }
+                       pp_data->current_task_p = NULL;
+/*
+                       if (done_task->done_func) {
+                                       TDM_BACKEND_DBG("pp %p(%d). Return src %p dst %p", pp_data, pp_data->stamp,
+                                                       done_task->buffers[0].src, done_task->buffers[done_task->max_step-1].dst);
+                                       done_task->done_func(pp_data, done_task->buffers[0].src,
+                                                                                done_task->buffers[done_task->max_step-1].dst,
+                                                                                done_task->done_user_data);
+                               }
+                       else {
+                               TDM_BACKEND_WRN("pp %p(%d). No done func", pp_data, pp_data->stamp);
+                       }
+*/
+                       _tdm_exynos_pp_destroy_task(pp_data, done_task);
+               } else {
+                       TDM_BACKEND_INFO("pp %p(%d). Still converting, add task to queue", pp_data, pp_data->stamp);
+                       return HAL_TDM_ERROR_NONE;
+               }
+       }
+
+       if (pp_data->roadmap_changed == 1) {
+               tdm_exynos_pp_task *temp_task = NULL, *temp_task_next = NULL;
+               int i = 0;
+               LIST_FOR_EACH_ENTRY_SAFE(temp_task, temp_task_next, &pp_data->pending_tasks_list, link) {
+                       LIST_DEL(&temp_task->link);
+                       _tdm_exynos_pp_destroy_task(pp_data, temp_task);
+               }
+               _tdm_exynos_pp_roadmap_copy(&pp_data->roadmap, &pp_data->new_roadmap);
+               for (i = 0; i < pp_data->roadmap.max_step; i++) {
+                       pp_data->roadmap.prop_id[i] = _tdm_exynos_pp_set(pp_data, &pp_data->roadmap.step_info[i], pp_data->roadmap.prop_id[i]);
+                       if (pp_data->roadmap.prop_id[i] <= 0) {
+                               TDM_BACKEND_ERR("pp %p(%d). Can't setup converter", pp_data, pp_data->stamp);
+                               return HAL_TDM_ERROR_BAD_REQUEST;
+                       }
+               }
+               pp_data->roadmap_changed = 0;
+               _tdm_exynos_pp_roadmap_print(&pp_data->roadmap);
+               if (pp_data->new_buffers == 1) {
+                       if (_tdm_exynos_pp_make_new_tasks(pp_data) < 0) {
+                               TDM_BACKEND_ERR("pp %p(%d). Can't create new task", pp_data, pp_data->stamp);
+                               return HAL_TDM_ERROR_BAD_REQUEST;
+                       }
+                       pp_data->new_buffers = 0;
+               }
+       }
+
+       if (!LIST_IS_EMPTY(&pp_data->pending_tasks_list)) {
+               next_task = (tdm_exynos_pp_task *)container_of(pp_data->pending_tasks_list.next, next_task, link);
+               LIST_DEL(&next_task->link);
+       }
+       if (next_task) {
+               TDM_BACKEND_DBG("pp %p(%d). Task %p(%d) setup next step %d of %d",
+                               pp_data, pp_data->stamp, next_task, next_task->stamp,
+                               next_task->current_step+1, next_task->max_step);
+               if (_tdm_exynos_pp_queue(pp_data, next_task->prop_id[next_task->current_step],
+                                                          next_task->buffers[next_task->current_step].src,
+                                                          next_task->buffers[next_task->current_step].dst,
+                                                          PP_BUF_ENQUEUE) != HAL_TDM_ERROR_NONE) {
+                       return HAL_TDM_ERROR_OPERATION_FAILED;
+               }
+               if (_tdm_exynos_pp_cmd(pp_data,
+                                                        next_task->prop_id[next_task->current_step],
+                                                        PP_RUN) != HAL_TDM_ERROR_NONE) {
+                       return HAL_TDM_ERROR_OPERATION_FAILED;
+               }
+               next_task->status = TASK_CONVERTING;
+               pp_data->current_task_p = next_task;
+               if (pp_data->sync)
+                       _tdm_exynos_pp_post_work(pp_data, next_task->prop_id[next_task->current_step]);
+               return HAL_TDM_ERROR_NONE;
+       } else {
+               TDM_BACKEND_DBG("pp %p(%d). Nothing to do", pp_data, pp_data->stamp);
+       }
+       return HAL_TDM_ERROR_NONE;
+}
+
+void
+_tdm_exynos_pp_post_work(tdm_exynos_pp_data *pp_data, u32 prop_id)
+{
+       tdm_exynos_pp_task *done_task = NULL;
+
+       if (!pp_data) {
+               TDM_BACKEND_ERR("invalid params");
+               return;
+       }
+
+       TDM_BACKEND_RETURN_IF_FAIL(pp_data);
+       TDM_BACKEND_RETURN_IF_FAIL(_tdm_exynos_pp_check_struct(pp_data));
+       TDM_BACKEND_DBG("pp %p(%d) prop_id(%u)", pp_data, pp_data->stamp, prop_id);
+
+       if (!pp_data->first_event) {
+               TDM_BACKEND_DBG("pp %p(%d) got a first event. ", pp_data, pp_data->stamp);
+               pp_data->first_event = 1;
+       }
+
+       if (pp_data->pp_need_destroy) {
+               TDM_BACKEND_DBG("pp %p(%d) Deferred event of delete", pp_data, pp_data->stamp);
+               LIST_DEL(&pp_data->link);
+               free(pp_data);
+               return;
+       }
+
+       if ((done_task = pp_data->current_task_p) == NULL) {
+               TDM_BACKEND_ERR("pp %p(%d) received wrong event", pp_data, pp_data->stamp);
+               return;
+       }
+       if (done_task->prop_id[done_task->current_step] != prop_id) {
+               TDM_BACKEND_ERR("pp %p(%d) received wrong event. prop_id expected %u prop_id received %u", pp_data, pp_data->stamp,
+                               done_task->prop_id[done_task->current_step], prop_id);
+               return;
+       }
+       done_task->status = TASK_DONE;
+       TDM_BACKEND_DBG("pp %p(%d). Task %p(%d) done step %d of %d", pp_data, pp_data->stamp, done_task, done_task->stamp,
+                       done_task->current_step+1, done_task->max_step);
+
+       if (_tdm_exynos_pp_cmd(pp_data,
+                                                done_task->prop_id[done_task->current_step],
+                                                PP_PAUSE) != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("pp %p(%d). Can't PAUSE conveter. Prop_id %d", pp_data,
+                               pp_data->stamp, done_task->prop_id[done_task->current_step]);
+               return;
+       }
+
+       if (_tdm_exynos_pp_worker(pp_data) != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("pp %p(%d) worker return ERROR", pp_data,
+                               pp_data->stamp);
+       }
+}
+
+void
+tdm_exynos_pp_handler(struct tdm_pp_event *hw_ipp_p)
+{
+       TDM_BACKEND_RETURN_IF_FAIL(hw_ipp_p);
+       tdm_exynos_pp_data *pp_data = (tdm_exynos_pp_data *)(unsigned long) hw_ipp_p->user_data;
+
+       if (!pp_data) {
+               TDM_BACKEND_ERR("invalid params");
+               return;
+       }
+
+       TDM_BACKEND_DBG("pp %p(%d) index(%d, %d) prop_id(%u)", pp_data, pp_data->stamp, hw_ipp_p->buf_id[0],
+                       hw_ipp_p->buf_id[1], hw_ipp_p->prop_id);
+
+       _tdm_exynos_pp_post_work(pp_data, hw_ipp_p->prop_id);
+}
+
+hal_tdm_error
+tdm_exynos_pp_get_capability(tdm_exynos_display *display_data, hal_tdm_caps_pp *caps)
+{
+       int i;
+
+       if (!caps) {
+               TDM_BACKEND_ERR("invalid params");
+               return HAL_TDM_ERROR_INVALID_PARAMETER;
+       }
+
+       caps->capabilities = HAL_TDM_PP_CAPABILITY_ASYNC;
+
+       caps->format_count = NUM_PP_FORMAT;
+       caps->formats = NULL;
+       if (NUM_PP_FORMAT) {
+               /* will be freed in frontend */
+               caps->formats = calloc(1, sizeof pp_formats);
+               if (!caps->formats) {
+                       TDM_BACKEND_ERR("alloc failed");
+                       return HAL_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 = 2;
+       caps->preferred_align_vertical = 2;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+tdm_exynos_get_pp_permission(tdm_exynos_display *display_data)
+{
+#if 0
+       int ret;
+       bool enable;
+
+       ret = ioctl(display_data->drm_fd, DRM_IOCTL_TDM_PP_GET_PERMISSION, &enable);
+       if (ret) {
+               TDM_BACKEND_ERR("failed to get permission");
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       if (!enable) {
+               TDM_BACKEND_ERR("permission disabled");
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       display_data->drm_pp = enable;
+
+       return HAL_TDM_ERROR_NONE;
+#else
+       display_data->drm_pp = 1;
+       return HAL_TDM_ERROR_NONE;
+#endif
+}
+
+hal_tdm_pp *
+tdm_exynos_pp_create(tdm_exynos_display *display_data, hal_tdm_error *error)
+{
+       tdm_exynos_pp_data *pp_data = calloc(1, sizeof(tdm_exynos_pp_data));
+       if (!pp_data) {
+               TDM_BACKEND_ERR("alloc failed");
+               if (error)
+                       *error = HAL_TDM_ERROR_OUT_OF_MEMORY;
+               return NULL;
+       }
+
+       pp_data->display_data = display_data;
+       pp_data->stamp = pp_stamp++;
+       pp_data->pp_need_destroy = 0;
+       if (!pp_list_init) {
+               pp_list_init = 1;
+               LIST_INITHEAD(&pp_list);
+       }
+       /* Find old pp_data and remove*/
+       tdm_exynos_pp_data *pp_data_cur = NULL, *pp_data_next = NULL;
+       LIST_FOR_EACH_ENTRY_SAFE(pp_data_cur, pp_data_next, &pp_list, link) {
+               if (pp_data_cur->pp_need_destroy) {
+                       LIST_DEL(&pp_data_cur->link);
+                       free(pp_data_cur);
+               }
+       }
+
+       LIST_INITHEAD(&pp_data->pending_buffer_list);
+       LIST_INITHEAD(&pp_data->pending_tasks_list);
+       LIST_INITHEAD(&pp_data->prop_id_list);
+       LIST_ADDTAIL(&pp_data->link, &pp_list);
+       TDM_BACKEND_DBG("pp %p(%d). Create", pp_data, pp_data->stamp);
+       return pp_data;
+}
+
+void
+exynos_pp_destroy(hal_tdm_pp *pp)
+{
+       tdm_exynos_pp_data *pp_data = (tdm_exynos_pp_data *) pp;
+       tdm_exynos_pp_buffer *b = NULL, *bb = NULL;
+       tdm_exynos_pp_task *task = NULL, *next_task = NULL;
+       tdm_exynos_prop_id *prop_id = NULL, *next_prop_id = NULL;
+       TDM_BACKEND_RETURN_IF_FAIL(_tdm_exynos_pp_check_struct(pp_data));
+       TDM_BACKEND_DBG("pp %p(%d). Destroy", pp_data, pp_data->stamp);
+
+       LIST_FOR_EACH_ENTRY_SAFE(prop_id, next_prop_id, &pp_data->prop_id_list, link)
+               _tdm_exynos_pp_cmd(pp_data, prop_id->prop_id, PP_STOP);
+
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
+               LIST_DEL(&b->link);
+               free(b);
+       }
+
+       LIST_FOR_EACH_ENTRY_SAFE(task, next_task, &pp_data->pending_tasks_list, link) {
+               LIST_DEL(&task->link);
+               _tdm_exynos_pp_destroy_task(pp_data, task);
+       }
+
+       if (pp_data->current_task_p && pp_data->current_task_p->status == TASK_CONVERTING) {
+               TDM_BACKEND_DBG("pp %p(%d) Still converting. Should Remove after callback", pp_data, pp_data->stamp);
+               pp_data->pp_need_destroy = 1;
+               _tdm_exynos_pp_destroy_task(pp_data, pp_data->current_task_p);
+               pp_data->current_task_p = NULL;
+       }
+
+       if (pp_data->pp_need_destroy)
+               return;
+
+       LIST_DEL(&pp_data->link);
+       free(pp_data);
+
+}
+
+static hal_tdm_error
+_exynos_pp_get_scale_leap(unsigned int src, unsigned int dst,
+                                               unsigned int *leap_array, unsigned int *size)
+{
+       unsigned int i = 0;
+       unsigned int ratio, next_value = src;
+       TDM_BACKEND_DBG("pp. scale src %u", src);
+       for (i = 0; i < PP_MAX_STEP; i++) {
+               ratio = PP_RATIO(next_value, dst);
+               if ((ratio >= PP_UP_MAX_RATIO) && (ratio <= PP_DOWN_MIN_RATIO))
+                       break;
+               if (ratio < PP_UP_MAX_RATIO)
+                       next_value = PP_RATIO(next_value, PP_UP_MAX_RATIO);
+               else if (ratio > PP_DOWN_MIN_RATIO)
+                       next_value =  PP_RATIO(next_value, PP_DOWN_MIN_RATIO);
+               if (leap_array)
+                       leap_array[i] = next_value;
+               TDM_BACKEND_DBG("[%u] => %u", i, next_value);
+       }
+       if (i == PP_MAX_STEP) {
+               TDM_BACKEND_ERR("Can't scale. Reaching maximum iteration count %d", PP_MAX_STEP);
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+       TDM_BACKEND_DBG("[%u] dst => %u", i, dst);
+       if (leap_array)
+               leap_array[i] = dst;
+       if (size)
+               *size = i + 1;
+       return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_exynos_pp_make_roadmap(tdm_exynos_pp_data *pp_data, hal_tdm_info_pp *info)
+{
+       unsigned int height_leap[PP_MAX_STEP], width_leap[PP_MAX_STEP],
+                        height_leap_size = 0, width_leap_size = 0, max_size = 0,
+                        src_height = (info->transform % 2) ? info->src_config.pos.w : info->src_config.pos.h,
+                        src_width = (info->transform % 2) ? info->src_config.pos.h : info->src_config.pos.w;
+       TDM_BACKEND_DBG("Height %u", info->src_config.pos.h);
+       if (_exynos_pp_get_scale_leap(src_height,
+                                                               info->dst_config.pos.h,
+                                                               height_leap,
+                                                               &height_leap_size) != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("height %u -> %u ratio out of range", info->src_config.pos.h,
+                               info->dst_config.pos.h);
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+       TDM_BACKEND_DBG("Width %u", info->src_config.pos.w);
+       if (_exynos_pp_get_scale_leap(src_width,
+                                                               info->dst_config.pos.w,
+                                                               width_leap,
+                                                               &width_leap_size) != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("width %u -> %u ratio out of range", info->src_config.pos.w,
+                               info->dst_config.pos.w);
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+       max_size = (width_leap_size > height_leap_size ? width_leap_size :
+                               height_leap_size);
+
+       if (height_leap_size - 1 >= PP_MAX_STEP ||
+           width_leap_size -1 >= PP_MAX_STEP) {
+               TDM_BACKEND_ERR("height_leap_size %u or width_leap_size %u out of range", height_leap_size,
+                               width_leap_size);
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+
+       if ((src_height < height_leap[height_leap_size -1] &&
+               src_width > width_leap[width_leap_size -1]) ||
+               (src_height > height_leap[height_leap_size -1] &&
+                src_width < width_leap[width_leap_size - 1])) {
+               if (max_size > 1 || max_size == PP_MAX_STEP) {
+                       TDM_BACKEND_ERR("pp %p(%d). Unsupported scale", pp_data, pp_data->stamp);
+                       return HAL_TDM_ERROR_OPERATION_FAILED;
+               }
+               height_leap[1] = height_leap[0];
+               height_leap[0] = src_height;
+               height_leap_size = 2;
+/*
+               width_leap[1] = width_leap[0];
+               width_leap[0] = src_width;
+               width_leap_size = 2;
+*/
+       }
+       memcpy(&pp_data->new_roadmap.step_info[0], info, sizeof(hal_tdm_info_pp));
+       pp_data->new_roadmap.step_info[0].dst_config.pos.h = height_leap[0];
+       pp_data->new_roadmap.step_info[0].dst_config.pos.w = width_leap[0];
+       max_size = (width_leap_size > height_leap_size ? width_leap_size :
+                               height_leap_size);
+       if (max_size - 1 >= PP_MAX_STEP) {
+               TDM_BACKEND_ERR("max_size %u out of range", max_size);
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+#if 0  // static analysis error  -- unreachable problem
+       int i;
+       for (i = 1; i < max_size; i++) {
+               pp_data->new_roadmap.step_info[i - 1].dst_config.pos.w =
+                                                               width_leap[(((i - 1) < width_leap_size) ? (i - 1) : (width_leap_size - 1))];
+               pp_data->new_roadmap.step_info[i - 1].dst_config.pos.h =
+                                                               height_leap[(((i - 1) < height_leap_size) ? (i - 1) : (height_leap_size - 1))];
+               pp_data->new_roadmap.step_info[i - 1].dst_config.size.h = pp_data->new_roadmap.step_info[i - 1].dst_config.pos.w;
+               pp_data->new_roadmap.step_info[i - 1].dst_config.size.v = pp_data->new_roadmap.step_info[i - 1].dst_config.pos.h;
+               pp_data->new_roadmap.step_info[i].transform = HAL_TDM_TRANSFORM_NORMAL
+               pp_data->new_roadmap.step_info[i].src_config.format = pp_data->new_roadmap.step_info[i - 1].dst_config.format;
+               pp_data->new_roadmap.step_info[i].dst_config.format = pp_data->new_roadmap.step_info[i - 1].dst_config.format;
+               pp_data->new_roadmap.step_info[i].src_config = pp_data->new_roadmap.step_info[i - 1].dst_config;
+               pp_data->new_roadmap.step_info[i].dst_config = pp_data->new_roadmap.step_info[i - 1].dst_config;
+               pp_data->new_roadmap.step_info[i].src_config.pos.x = 0;
+               pp_data->new_roadmap.step_info[i].src_config.pos.y = 0;
+               pp_data->new_roadmap.step_info[i].dst_config.pos.x = 0;
+               pp_data->new_roadmap.step_info[i].dst_config.pos.y = 0;
+               pp_data->new_roadmap.step_info[i].sync = pp_data->new_roadmap.step_info[i - 1].sync;
+               pp_data->new_roadmap.step_info[i].flags = pp_data->new_roadmap.step_info[i - 1].flags;
+       }
+#endif
+       memcpy(&pp_data->new_roadmap.step_info[max_size - 1].dst_config, &info->dst_config, sizeof(hal_tdm_info_config));
+       pp_data->new_roadmap.step_info[max_size-1].dst_config.pos.h = height_leap[height_leap_size - 1];
+       pp_data->new_roadmap.step_info[max_size-1].dst_config.pos.w = width_leap[width_leap_size - 1];
+       pp_data->new_roadmap.max_step = max_size;
+       //_exynos_pp_make_roadmap_transform (pp_data, info);
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_pp_set_info(hal_tdm_pp *pp, hal_tdm_info_pp *info)
+{
+       tdm_exynos_pp_data *pp_data = (tdm_exynos_pp_data *) pp;
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(info, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(_tdm_exynos_pp_check_struct(pp_data), HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_DBG("pp %p(%d). Set new info.", pp_data, pp_data->stamp);
+       if (pp_data->pp_need_destroy) {
+               TDM_BACKEND_WRN("pp %p(%d) Will remove. Ignoring request.", pp_data, pp_data->stamp);
+               return HAL_TDM_ERROR_BAD_REQUEST;
+       }
+       if (_exynos_pp_make_roadmap(pp_data, info) != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("pp %p(%d). Wrong convertation settings", pp_data, pp_data->stamp);
+               return HAL_TDM_ERROR_INVALID_PARAMETER;
+       }
+       pp_data->roadmap_changed = 1;
+       pp_data->sync = info->sync;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_pp_attach(hal_tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
+{
+       tdm_exynos_pp_data *pp_data = (tdm_exynos_pp_data *) pp;
+       tdm_exynos_pp_buffer *buffer;
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(src, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(dst, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(_tdm_exynos_pp_check_struct(pp_data), HAL_TDM_ERROR_INVALID_PARAMETER);
+       if (pp_data->pp_need_destroy) {
+               TDM_BACKEND_WRN("pp %p(%d) Will remove. Ignoring request.", pp_data, pp_data->stamp);
+               return HAL_TDM_ERROR_BAD_REQUEST;
+       }
+       buffer = calloc(1, sizeof(tdm_exynos_pp_buffer));
+       if (!buffer) {
+               TDM_BACKEND_ERR("pp %p(%d). Alloc failed", pp_data, pp_data->stamp);
+               return HAL_TDM_ERROR_NONE;
+       }
+       buffer->index = 0;
+       buffer->src = src;
+       buffer->dst = dst;
+       pp_data->new_buffers = 1;
+       TDM_BACKEND_DBG("pp %p(%d). Attach src %p dst %p buffers", pp_data, pp_data->stamp, buffer->src, buffer->dst);
+       LIST_ADDTAIL(&buffer->link, &pp_data->pending_buffer_list);
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+
+
+hal_tdm_error
+exynos_pp_commit(hal_tdm_pp *pp)
+{
+       tdm_exynos_pp_data *pp_data = (tdm_exynos_pp_data *) pp;
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(_tdm_exynos_pp_check_struct(pp_data), HAL_TDM_ERROR_INVALID_PARAMETER);
+       if (pp_data->pp_need_destroy) {
+               TDM_BACKEND_WRN("pp %p(%d) Will remove. Ignoring request.", pp_data, pp_data->stamp);
+               return HAL_TDM_ERROR_BAD_REQUEST;
+       }
+       if (pp_data->roadmap_changed) {
+               unsigned int i, need_postpond = 0;
+               for (i = 0; i < pp_data->roadmap.max_step; i++) {
+                       if (pp_data->roadmap.prop_id[i] > 0) {
+                               tdm_exynos_prop_id * found_prop = _find_prop_id(pp_data, pp_data->roadmap.prop_id[i]);
+                               if (found_prop != NULL &&
+                                               (found_prop->status == PP_CTRL_PLAY || found_prop->status == PP_CTRL_RESUME)) {
+//                                     _tdm_exynos_pp_cmd(pp_data, pp_data->roadmap.prop_id[i], PP_PAUSE);
+                                       need_postpond = 1;
+                               }
+                       }
+               }
+               if (!need_postpond) {
+                       _tdm_exynos_pp_roadmap_copy(&pp_data->roadmap, &pp_data->new_roadmap);
+                       for (i = 0; i < pp_data->roadmap.max_step; i++) {
+                               pp_data->roadmap.prop_id[i] = _tdm_exynos_pp_set(pp_data, &pp_data->roadmap.step_info[i], pp_data->roadmap.prop_id[i]);
+                               if (pp_data->roadmap.prop_id[i] <= 0) {
+                                       TDM_BACKEND_ERR("pp %p(%d). Can't setup converter", pp_data, pp_data->stamp);
+                                       return HAL_TDM_ERROR_BAD_REQUEST;
+                               }
+                       }
+                       pp_data->roadmap_changed = 0;
+                       _tdm_exynos_pp_roadmap_print(&pp_data->roadmap);
+               }
+       }
+       if (pp_data->new_buffers == 1 && pp_data->roadmap_changed == 0) {
+               if (_tdm_exynos_pp_make_new_tasks(pp_data) < 0) {
+                       TDM_BACKEND_ERR("pp %p(%d). Can't create new task", pp_data, pp_data->stamp);
+                       return HAL_TDM_ERROR_BAD_REQUEST;
+               }
+               pp_data->new_buffers = 0;
+               return _tdm_exynos_pp_worker(pp_data);
+       }
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_pp_set_done_handler(hal_tdm_pp *pp, hal_tdm_pp_done_handler func, void *user_data)
+{
+       tdm_exynos_pp_data *pp_data = (tdm_exynos_pp_data *) pp;
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(_tdm_exynos_pp_check_struct(pp_data), HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_DBG("pp %p(%d). Set done handler func %p", pp_data, pp_data->stamp, func);
+       pp_data->done_func = func;
+       pp_data->done_user_data = user_data;
+       return HAL_TDM_ERROR_NONE;
+}
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_sc_v4l2.c b/src/libhal-backend-tdm-exynos-deconfb/tdm_exynos_sc_v4l2.c
new file mode 100644 (file)
index 0000000..82bf33f
--- /dev/null
@@ -0,0 +1,1317 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#define PP_MAX_STEP 2
+#include "tdm_backend_exynos.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <linux/videodev2.h>
+
+
+#define EXYNOS_C(b, m)           (((b) >> (m)) & 0xFF)
+#define EXYNOS_FOURCC_STR(id)    EXYNOS_C(id, 0), EXYNOS_C(id, 8), EXYNOS_C(id, 16), EXYNOS_C(id, 24)
+#define MAX_ATTACH_BUFFER 4
+
+typedef struct _tdm_exynos_pp_v4l2_buffer {
+       int index;
+       tbm_surface_h src;
+       tbm_surface_h dst;
+       struct list_head link;
+} tdm_exynos_pp_v4l2_buffer;
+
+typedef enum _tdm_exynos_pp_v4l2_ctrl {
+       PP_STOP = 0,
+       PP_RUN = 1,
+       PP_PAUSE = 2
+} tdm_exynos_pp_v4l2_ctrl;
+
+typedef enum _tdm_exynos_task_status {
+       TASK_WAITING,
+       TASK_CONVERTING,
+       TASK_DONE
+} tdm_exynos_task_status;
+
+typedef struct _tdm_exynos_prop_id {
+       enum tdm_pp_ctrl status;
+       unsigned int prop_id;
+       struct list_head link;
+} tdm_exynos_prop_id;
+
+typedef struct _tdm_exynos_pp_v4l2_task {
+       int stamp;
+       unsigned int prop_id[PP_MAX_STEP];
+       tdm_exynos_pp_v4l2_buffer buffers[PP_MAX_STEP];
+       tdm_exynos_pp_v4l2_buffer *attach_buffer;
+       unsigned int max_step;
+       unsigned int current_step;
+       int status;
+       hal_tdm_pp_done_handler done_func;
+       void *done_user_data;
+       struct list_head link;
+} tdm_exynos_pp_v4l2_task;
+
+typedef struct _tdm_exynos_pp_v4l2_roadmap {
+       unsigned int prop_id[PP_MAX_STEP];
+       hal_tdm_info_pp step_info[PP_MAX_STEP];
+       unsigned int max_step;
+} tdm_exynos_pp_v4l2_roadmap;
+
+typedef struct _tdm_exynos_pp_v4l2_data {
+       tdm_exynos_display *display_data;
+       int stamp;
+       int v4l2_fd[PP_MAX_STEP];
+       struct list_head pending_buffer_list;
+       struct list_head pending_tasks_list;
+       struct list_head prop_id_list;
+       tdm_exynos_pp_v4l2_roadmap roadmap;
+       tdm_exynos_pp_v4l2_roadmap new_roadmap;
+       tdm_exynos_pp_v4l2_task *current_task_p;
+       hal_tdm_pp_done_handler done_func;
+       void *done_user_data;
+       int roadmap_changed;
+       int new_buffers;
+       int first_event;
+       struct list_head link;
+       int sync;
+       int ref_count;
+       unsigned int buffer_index_arr[MAX_ATTACH_BUFFER];
+//     tdm_event_loop_source *event_source[PP_MAX_STEP];
+} tdm_exynos_pp_v4l2_data;
+
+static tbm_format pp_v4l2_formats[] = {
+       TBM_FORMAT_XRGB8888,
+       TBM_FORMAT_ARGB8888,
+       TBM_FORMAT_RGB565,
+       TBM_FORMAT_NV12,
+       TBM_FORMAT_YUV420,
+       TBM_FORMAT_YUV422,
+};
+static int _tdm_exynos_pp_v4l2_make_new_tasks(tdm_exynos_pp_v4l2_data *pp_v4l2_data);
+
+#define NUM_PP_FORMAT   (sizeof(pp_v4l2_formats) / sizeof(pp_v4l2_formats[0]))
+
+static int pp_v4l2_list_init = 0;
+static int pp_v4l2_stamp = 1001;
+static int task_stamp = 10001;
+static struct list_head pp_v4l2_list;
+
+int _find_buffer_index(tdm_exynos_pp_v4l2_data *pp_v4l2_data)
+{
+       int i;
+       for (i = 0; i < MAX_ATTACH_BUFFER; i++) {
+               /* find buffer index which can use.*/
+               if (!pp_v4l2_data->buffer_index_arr[i])
+                       return i;
+       }
+       TDM_BACKEND_ERR("can't find buffer index for Qbuf");
+       return -1;
+}
+
+void _reset_buffer_index(tdm_exynos_pp_v4l2_data *pp_v4l2_data, unsigned int idx, tbm_surface_h src, tbm_surface_h dst)
+{
+       if (idx < MAX_ATTACH_BUFFER) {
+               pp_v4l2_data->buffer_index_arr[idx] = 0;
+               TDM_BACKEND_DBG("DQbuf inx(%d) , value(%d), src(%p), dst(%p)", idx, pp_v4l2_data->buffer_index_arr[idx], src, dst);
+       } else
+               TDM_BACKEND_ERR("invalid index");
+}
+void _set_buffer_index(tdm_exynos_pp_v4l2_data *pp_v4l2_data, unsigned int idx, tbm_surface_h src, tbm_surface_h dst)
+{
+       if (idx < MAX_ATTACH_BUFFER) {
+               pp_v4l2_data->buffer_index_arr[idx] = 1;
+               TDM_BACKEND_DBG("Qbuf inx(%d) , value(%d), src(%p), dst(%p)", idx, pp_v4l2_data->buffer_index_arr[idx], src, dst);
+       } else
+               TDM_BACKEND_ERR("invalid index");
+}
+static tdm_exynos_prop_id *
+_find_prop_id(tdm_exynos_pp_v4l2_data *pp_v4l2_data, unsigned int prop_id)
+{
+       tdm_exynos_prop_id *prop = NULL;
+       LIST_FOR_EACH_ENTRY(prop, &pp_v4l2_data->prop_id_list, link) {
+               if (prop->prop_id == prop_id)
+                       return prop;
+       }
+       return NULL;
+}
+
+int _tdm_exynos_pp_v4l2_check_struct(tdm_exynos_pp_v4l2_data *pp_v4l2_data)
+{
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(pp_v4l2_list_init == 1, 0);
+       if (pp_v4l2_data == NULL) {
+               TDM_BACKEND_ERR("pp nil(0). Received NULL pointer");
+               return 0;
+       }
+       tdm_exynos_pp_v4l2_data * pp_v4l2_next = NULL;
+       LIST_FOR_EACH_ENTRY(pp_v4l2_next, &pp_v4l2_list, link) {
+               if (pp_v4l2_next->stamp == pp_v4l2_data->stamp)
+                       return 1;
+       }
+       TDM_BACKEND_ERR("pp %p(%d). Wrong ", pp_v4l2_data, pp_v4l2_data->stamp);
+       return 0;
+}
+
+void _tdm_exynos_pp_v4l2_roadmap_print(tdm_exynos_pp_v4l2_roadmap *roadmap)
+{
+       TDM_BACKEND_RETURN_IF_FAIL(roadmap);
+       int i;
+       TDM_BACKEND_DBG("Count of steps %d", roadmap->max_step);
+       for (i = 0; i < roadmap->max_step; i++) {
+               TDM_BACKEND_DBG("Step %d, Prop_id %d", i+1, roadmap->prop_id[i]);
+               TDM_BACKEND_DBG("format %c%c%c%c(%u) -> %c%c%c%c(%u)", roadmap->step_info[i].src_config.format,
+                               EXYNOS_FOURCC_STR(roadmap->step_info[i].src_config.format), roadmap->step_info[i].dst_config.format,
+                               EXYNOS_FOURCC_STR(roadmap->step_info[i].dst_config.format));
+               TDM_BACKEND_DBG("rotate+flip %u+%s", roadmap->step_info[i].transform % 4,
+                               roadmap->step_info[i].transform > 3 ? "Horizontal" : "None");
+               TDM_BACKEND_DBG("size src->dst wxh (%u)x(%u) -> (%u)x(%u)", roadmap->step_info[i].src_config.size.h,
+                               roadmap->step_info[i].src_config.size.v, roadmap->step_info[i].dst_config.size.h,
+                               roadmap->step_info[i].dst_config.size.v);
+               TDM_BACKEND_DBG("crop src->dst xy+w+h (%u)x(%u)+(%u)+(%u) -> (%u)x(%u)+(%u)+(%u)", roadmap->step_info[i].src_config.pos.x,
+                               roadmap->step_info[i].src_config.pos.y, roadmap->step_info[i].src_config.pos.w,
+                               roadmap->step_info[i].src_config.pos.h, roadmap->step_info[i].dst_config.pos.x,
+                               roadmap->step_info[i].dst_config.pos.y, roadmap->step_info[i].dst_config.pos.w,
+                               roadmap->step_info[i].dst_config.pos.h);
+       }
+       TDM_BACKEND_DBG("-------------------------------------------------------------------");
+}
+
+int _tdm_exynos_pp_v4l2_roadmap_copy(tdm_exynos_pp_v4l2_roadmap *to_roadmap, tdm_exynos_pp_v4l2_roadmap *from_roadmap)
+{
+       int i = 0;
+       for (i = 0; i < PP_MAX_STEP; i++)
+               memcpy(&to_roadmap->step_info[i], &from_roadmap->step_info[i], sizeof(hal_tdm_info_pp));
+
+       to_roadmap->max_step = from_roadmap->max_step;
+       return 1;
+}
+
+static unsigned int
+_tdm_exynos_pp_v4l2_set(tdm_exynos_pp_v4l2_data *pp_v4l2_data, hal_tdm_info_pp *info,
+                                unsigned int prop_id)
+{
+       struct v4l2_requestbuffers reqBuf;
+       struct v4l2_format format;
+       struct v4l2_control ctrl;
+       struct v4l2_crop crop;
+       unsigned int idx = prop_id - 1;
+
+       memset(&reqBuf, 0, sizeof(reqBuf));
+       memset(&format, 0, sizeof(format));
+       memset(&ctrl, 0, sizeof(ctrl));
+       memset(&crop, 0, sizeof(crop));
+
+       /* reqbufs(0) */
+       reqBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       reqBuf.memory = V4L2_MEMORY_DMABUF;
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_REQBUFS, &reqBuf)) {
+               TDM_BACKEND_ERR("ioctl error %d", errno);
+               return 0;
+       }
+       reqBuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_REQBUFS, &reqBuf)) {
+               TDM_BACKEND_ERR("ioctl error %d", errno);
+               return 0;
+       }
+
+       format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       format.fmt.pix_mp.width = info->src_config.size.h;
+       format.fmt.pix_mp.height = info->src_config.size.v;
+       format.fmt.pix_mp.colorspace = V4L2_COLORSPACE_SRGB;
+       format.fmt.pix_mp.pixelformat = tdm_exynos_format_to_v4l2_format(info->src_config.format);
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_TRY_FMT, &format)) {
+               TDM_BACKEND_ERR("ioctl error %d", errno);
+               return 0;
+       }
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_S_FMT, &format)) {
+               TDM_BACKEND_ERR("ioctl error %d", errno);
+               return 0;
+       }
+
+       /*dst*/
+       format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       format.fmt.pix_mp.width = info->dst_config.size.h;
+       format.fmt.pix_mp.height = info->dst_config.size.v;
+       format.fmt.pix_mp.colorspace = V4L2_COLORSPACE_SRGB;
+       format.fmt.pix_mp.pixelformat = tdm_exynos_format_to_v4l2_format(info->dst_config.format);
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_TRY_FMT, &format)) {
+               TDM_BACKEND_ERR("ioctl error %d", errno);
+               return 0;
+       }
+
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_S_FMT, &format)) {
+               TDM_BACKEND_ERR("ioctl error %d", errno);
+               return 0;
+       }
+
+       crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       crop.c.left = info->src_config.pos.x;
+       crop.c.top =  info->src_config.pos.y;
+       crop.c.width =  info->src_config.pos.w;
+       crop.c.height =  info->src_config.pos.h;
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_S_CROP, &crop)) {
+               TDM_BACKEND_ERR("ioctl error %d", errno);
+               return 0;
+       }
+
+       crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       crop.c.left = info->dst_config.pos.x;
+       crop.c.top =  info->dst_config.pos.y;
+       crop.c.width =  info->dst_config.pos.w;
+       crop.c.height =  info->dst_config.pos.h;
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_S_CROP, &crop)) {
+               TDM_BACKEND_ERR("ioctl error %d", errno);
+               return 0;
+       }
+
+       ctrl.id = V4L2_CID_ROTATE;
+       ctrl.value = (info->transform % 4) * 90;
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_S_CTRL, &ctrl)) {
+               TDM_BACKEND_ERR("ioctl error %d", errno);
+               return 0;
+       }
+
+       ctrl.id = V4L2_CID_HFLIP;
+       ctrl.value = (info->transform > 3) ? 1 : 0;
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_S_CTRL, &ctrl)) {
+               TDM_BACKEND_ERR("ioctl error %d", errno);
+               return 0;
+       }
+
+       /* reqbufs(4) */
+       reqBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       reqBuf.memory = V4L2_MEMORY_DMABUF;
+       reqBuf.count = MAX_ATTACH_BUFFER;
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_REQBUFS, &reqBuf)) {
+               TDM_BACKEND_ERR("ioctl error %d", errno);
+               return 0;
+       }
+       reqBuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_REQBUFS, &reqBuf)) {
+               reqBuf.count = 0;
+               reqBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+               ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_REQBUFS, &reqBuf);
+               return 0;
+       }
+
+       return prop_id;
+}
+
+static hal_tdm_error
+_tdm_exynos_pp_v4l2_queue(tdm_exynos_pp_v4l2_data *pp_v4l2_data, unsigned int prop_id,
+                                  tbm_surface_h src, tbm_surface_h dst, enum tdm_pp_buf_type type)
+{
+       int i, bo_num;
+       unsigned int idx = prop_id - 1;
+       struct v4l2_buffer qbuf;
+       struct v4l2_plane plane[TDM_PLANAR_MAX];
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+       struct v4l2_requestbuffers reqBuf;
+       int out_id = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       int cap_id = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+
+       memset(&reqBuf, 0, sizeof(reqBuf));
+       memset(&qbuf, 0, sizeof(qbuf));
+       memset(&plane, 0, sizeof(plane));
+
+       if (type == PP_BUF_ENQUEUE) {
+               /* find valid buffer index */
+               int buf_index = _find_buffer_index(pp_v4l2_data);
+
+               /* invalid buffer index */
+               if (buf_index < 0)
+                       return HAL_TDM_ERROR_BAD_REQUEST;
+
+               qbuf.index = buf_index;
+               qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+               qbuf.memory = V4L2_MEMORY_DMABUF;
+               qbuf.m.planes = plane;
+               bo_num = tbm_surface_internal_get_num_bos(src);
+               for (i = 0; i < TDM_PLANAR_MAX && i < bo_num; i++) {
+                       tbm_bo bo = tbm_surface_internal_get_bo(src, i);
+                       qbuf.m.planes[i].length = tbm_bo_size(bo);
+                       qbuf.m.planes[i].bytesused = tbm_bo_size(bo);
+                       qbuf.m.planes[i].m.fd = tbm_bo_get_handle(bo, TBM_DEVICE_MM).u32;
+
+               }
+               qbuf.length = bo_num;
+               if (ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_QBUF, &qbuf) < 0) {
+                       /* handle an error */
+                       TDM_BACKEND_ERR("error ioctl %d", errno);
+               }
+
+               qbuf.index = buf_index;
+               qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+               qbuf.memory = V4L2_MEMORY_DMABUF;
+               qbuf.m.planes = plane;
+               bo_num = tbm_surface_internal_get_num_bos(dst);
+               for (i = 0; i < TDM_PLANAR_MAX && i < bo_num; i++) {
+                       tbm_bo bo = tbm_surface_internal_get_bo(dst, i);
+                       qbuf.m.planes[i].length = tbm_bo_size(bo);
+                       qbuf.m.planes[i].bytesused = 0;
+                       qbuf.m.planes[i].m.fd = tbm_bo_get_handle(bo, TBM_DEVICE_MM).u32;
+               }
+               qbuf.length = bo_num;
+               if (ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_QBUF, &qbuf) < 0) {
+                       tdm_exynos_prop_id * found_prop = _find_prop_id(pp_v4l2_data, prop_id);
+                       TDM_BACKEND_ERR("error ioctl %d", errno);
+                       if (found_prop == NULL) {
+                               TDM_BACKEND_ERR("error caanot find prop %d", prop_id);
+                               return HAL_TDM_ERROR_OPERATION_FAILED;
+                       }
+                       switch (found_prop->status) {
+                       case PP_CTRL_PAUSE:
+                               /* reqbufs(0) */
+                               reqBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+                               reqBuf.memory = V4L2_MEMORY_DMABUF;
+                               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_REQBUFS, &reqBuf)) {
+                                       TDM_BACKEND_ERR("ioctl error %d", errno);
+                                       return 0;
+                               }
+                               reqBuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+                               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_REQBUFS, &reqBuf)) {
+                                       TDM_BACKEND_ERR("ioctl error %d", errno);
+                                       return 0;
+                               }
+                               /* reqbufs(4) */
+                               reqBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+                               reqBuf.memory = V4L2_MEMORY_DMABUF;
+                               reqBuf.count = MAX_ATTACH_BUFFER;
+                               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_REQBUFS, &reqBuf)) {
+                                       TDM_BACKEND_ERR("ioctl error %d", errno);
+                                       return 0;
+                               }
+                               reqBuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+                               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_REQBUFS, &reqBuf)) {
+                                       reqBuf.count = 0;
+                                       reqBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+                                       ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_REQBUFS, &reqBuf);
+                                       return 0;
+                               }
+                               break;
+                       case PP_CTRL_PLAY:
+                       case PP_CTRL_RESUME:
+                               /* streamoff */
+                               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_STREAMOFF, &out_id)) {
+                                       TDM_BACKEND_ERR("ioctl error : %d", errno);
+                                       return HAL_TDM_ERROR_BAD_REQUEST;
+                               }
+                               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_STREAMOFF, &cap_id)) {
+                                       TDM_BACKEND_ERR("ioctl error : %d", errno);
+                                       return HAL_TDM_ERROR_BAD_REQUEST;
+                               }
+                               /* streamon */
+                               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_STREAMON, &out_id)) {
+                                       TDM_BACKEND_ERR("ioctl error : %d", errno);
+                                       return HAL_TDM_ERROR_BAD_REQUEST;
+                               }
+                               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_STREAMON, &cap_id)) {
+                                       TDM_BACKEND_ERR("ioctl error : %d", errno);
+                                       /* out stream off -> return */
+                                       return HAL_TDM_ERROR_BAD_REQUEST;
+                               }
+                               break;
+                       default:
+                               /* error */
+                               break;
+                       }
+                       /* return rerro*/
+               }
+
+               /* set buffer index after qbuf */
+               _set_buffer_index(pp_v4l2_data, buf_index, src, dst);
+#if 0
+               /* event loop remove after qbuf*/
+               if (!pp_v4l2_data->sync && (!pp_v4l2_data->event_source[0] && !pp_v4l2_data->event_source[1])) {
+                       pp_v4l2_data->event_source[0] = tdm_event_loop_add_fd_handler(pp_v4l2_data->display_data->dpy, pp_v4l2_data->v4l2_fd[0], HAL_TDM_EVENT_LOOP_READABLE, tdm_exynos_pp_v4l2_task_done_handler, pp_v4l2_data, &ret);
+                       pp_v4l2_data->event_source[1] = tdm_event_loop_add_fd_handler(pp_v4l2_data->display_data->dpy, pp_v4l2_data->v4l2_fd[1], HAL_TDM_EVENT_LOOP_READABLE, tdm_exynos_pp_v4l2_task_done_handler, pp_v4l2_data, &ret);
+               }
+#endif
+       } else {
+               qbuf.index = 0;
+               qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+               qbuf.memory = V4L2_MEMORY_DMABUF;
+               qbuf.m.planes = plane;
+               qbuf.length = tbm_surface_internal_get_num_bos(src);
+               if (ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_DQBUF, &qbuf) < 0) {
+                       if (errno == EINTR) {
+                               while (ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_DQBUF, &qbuf) < 0) {
+                                       if (errno != EINTR) {
+                                               TDM_BACKEND_ERR("ioctl error : %d", errno);
+                                               ret = HAL_TDM_ERROR_BAD_REQUEST;
+                                               break;
+                                       }
+                               }
+                               goto out1;
+                       }
+                       TDM_BACKEND_ERR("ioctl error : %d", errno);
+                       ret = HAL_TDM_ERROR_BAD_REQUEST;
+               }
+out1:
+               if (!!(qbuf.flags & V4L2_BUF_FLAG_ERROR)) {
+                       TDM_BACKEND_ERR("ioctl error in stream:");
+                       ret = HAL_TDM_ERROR_BAD_REQUEST;
+               }
+
+               qbuf.index = 0;
+               qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+               qbuf.memory = V4L2_MEMORY_DMABUF;
+               qbuf.m.planes = plane;
+               qbuf.length = tbm_surface_internal_get_num_bos(dst);
+               if (ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_DQBUF, &qbuf) < 0) {
+                       if (errno == EINTR) {
+                               while (ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_DQBUF, &qbuf) < 0) {
+                                       if (errno != EINTR) {
+                                               TDM_BACKEND_ERR("ioctl error : %d", errno);
+                                               ret = HAL_TDM_ERROR_BAD_REQUEST;
+                                               break;
+                                       }
+                               }
+                               goto out2;
+                       }
+                       TDM_BACKEND_ERR("ioctl error : %d", errno);
+                       return HAL_TDM_ERROR_BAD_REQUEST;
+               }
+out2:
+               if (!!(qbuf.flags & V4L2_BUF_FLAG_ERROR))
+                       return HAL_TDM_ERROR_BAD_REQUEST;
+
+               /* reset Dqbuf index */
+               _reset_buffer_index(pp_v4l2_data, qbuf.index, src, dst);
+       }
+
+       return ret;
+}
+
+static hal_tdm_error
+_tdm_exynos_pp_v4l2_cmd(tdm_exynos_pp_v4l2_data *pp_v4l2_data, unsigned int prop_id,
+                                tdm_exynos_pp_v4l2_ctrl cmd)
+{
+       struct tdm_pp_cmd_ctrl ctrl;
+       int cap_id = 0, out_id = 0;
+       unsigned int idx = prop_id - 1;
+       struct v4l2_requestbuffers reqBuf;
+       tdm_exynos_prop_id * found_prop = _find_prop_id(pp_v4l2_data, prop_id);
+
+       memset(&reqBuf, 0, sizeof(reqBuf));
+
+       if (found_prop == NULL) {
+               if ((found_prop = calloc(1, sizeof(tdm_exynos_prop_id))) == NULL) {
+                       TDM_BACKEND_ERR("pp %p(%d). Out of memory", pp_v4l2_data, pp_v4l2_data->stamp);
+                       return HAL_TDM_ERROR_OUT_OF_MEMORY;
+               }
+               found_prop->prop_id = prop_id;
+               found_prop->status = PP_CTRL_STOP;
+               LIST_ADDTAIL(&found_prop->link, &pp_v4l2_data->prop_id_list);
+       }
+       ctrl.prop_id = prop_id;
+       switch (cmd) {
+       case PP_RUN:
+               if (found_prop->status == PP_CTRL_STOP)
+                       ctrl.ctrl = PP_CTRL_PLAY;
+               else if (found_prop->status == PP_CTRL_PAUSE)
+                       ctrl.ctrl = PP_CTRL_RESUME;
+               else if (found_prop->status == PP_CTRL_PLAY ||
+                                found_prop->status == PP_CTRL_RESUME)
+                       return HAL_TDM_ERROR_NONE;
+               break;
+       case PP_PAUSE:
+               if (found_prop->status == PP_CTRL_PLAY ||
+                       found_prop->status == PP_CTRL_RESUME)
+                       ctrl.ctrl = PP_CTRL_PAUSE;
+               else if (found_prop->status == PP_CTRL_PAUSE ||
+                                found_prop->status == PP_CTRL_STOP)
+                       return HAL_TDM_ERROR_NONE;
+               break;
+       case PP_STOP:
+               if (found_prop->status == PP_CTRL_STOP) {
+                       LIST_DEL(&found_prop->link);
+                       free(found_prop);
+                       return HAL_TDM_ERROR_NONE;
+               }
+               LIST_DEL(&found_prop->link);
+               free(found_prop);
+               ctrl.ctrl = PP_CTRL_STOP;
+               found_prop = NULL;
+               break;
+       default:
+               break;
+       }
+
+       TDM_BACKEND_DBG("pp %p(%d). prop_id(%d) ctrl(%d). ", pp_v4l2_data, pp_v4l2_data->stamp, ctrl.prop_id, ctrl.ctrl);
+
+       out_id = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       cap_id = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       switch (ctrl.ctrl) {
+       case PP_CTRL_PLAY:
+       case PP_CTRL_RESUME:
+               /* streamon */
+               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_STREAMON, &out_id)) {
+                       TDM_BACKEND_ERR("ioctl error : %d", errno);
+                       return HAL_TDM_ERROR_BAD_REQUEST;
+               }
+               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_STREAMON, &cap_id)) {
+                       TDM_BACKEND_ERR("ioctl error : %d", errno);
+                       /* out stream off -> return */
+                       return HAL_TDM_ERROR_BAD_REQUEST;
+               }
+               break;
+       case PP_CTRL_PAUSE:
+               /* streamoff */
+               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_STREAMOFF, &out_id)) {
+                       TDM_BACKEND_ERR("ioctl error : %d", errno);
+                       return HAL_TDM_ERROR_BAD_REQUEST;
+               }
+               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_STREAMOFF, &cap_id)) {
+                       TDM_BACKEND_ERR("ioctl error : %d", errno);
+                       return HAL_TDM_ERROR_BAD_REQUEST;
+               }
+               break;
+       case PP_CTRL_STOP:
+               if (ctrl.ctrl != PP_CTRL_PAUSE) {
+                       /* streamoff */
+                       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_STREAMOFF, &out_id)) {
+                               TDM_BACKEND_ERR("ioctl error : %d", errno);
+                               return HAL_TDM_ERROR_BAD_REQUEST;
+                       }
+                       if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_STREAMOFF, &cap_id)) {
+                               TDM_BACKEND_ERR("ioctl error : %d", errno);
+                               return HAL_TDM_ERROR_BAD_REQUEST;
+                       }
+               }
+               /* reqbufs(0) */
+               reqBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+               reqBuf.memory = V4L2_MEMORY_DMABUF;
+               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_REQBUFS, &reqBuf)) {
+                       TDM_BACKEND_ERR("ioctl error : %d", errno);
+                       return HAL_TDM_ERROR_BAD_REQUEST;
+               }
+               reqBuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+               if (0 > ioctl(pp_v4l2_data->v4l2_fd[idx], VIDIOC_REQBUFS, &reqBuf)) {
+                       TDM_BACKEND_ERR("ioctl error : %d", errno);
+                       return HAL_TDM_ERROR_BAD_REQUEST;
+               }
+               break;
+       default:
+               /* error */
+               break;
+       }
+
+       if (found_prop)
+               found_prop->status = ctrl.ctrl;
+
+       TDM_BACKEND_DBG("pp %p(%d). Success. prop_id(%d) ", pp_v4l2_data, pp_v4l2_data->stamp, ctrl.prop_id);
+       return HAL_TDM_ERROR_NONE;
+}
+
+static void
+_tdm_exynos_pp_v4l2_destroy_task(tdm_exynos_pp_v4l2_data *pp_v4l2_data, tdm_exynos_pp_v4l2_task * task)
+{
+       int i;
+       for (i = 0; i < task->max_step; i++) {
+               if (task->buffers[i].src)
+                       tbm_surface_internal_unref(task->buffers[i].src);
+               if (task->buffers[i].dst)
+                       tbm_surface_internal_unref(task->buffers[i].dst);
+       }
+       TDM_BACKEND_DBG("pp %p(%d). Task %p(%d) released", pp_v4l2_data, pp_v4l2_data->stamp, task, task->stamp);
+       if (task->attach_buffer)
+               free(task->attach_buffer);
+
+       free(task);
+}
+
+static hal_tdm_error
+_tdm_exynos_pp_v4l2_worker(tdm_exynos_pp_v4l2_data *pp_v4l2_data)
+{
+       tdm_exynos_pp_v4l2_task *next_task = NULL, *done_task = pp_v4l2_data->current_task_p;
+       if (done_task && done_task->status == TASK_DONE) {
+               unsigned int next_step = done_task->current_step + 1;
+               /* double operation*/
+               if (next_step < done_task->max_step) {
+                       TDM_BACKEND_DBG("pp %p(%d). Task %p(%d) setup next step %d of %d",
+                                       pp_v4l2_data, pp_v4l2_data->stamp, done_task, done_task->stamp,
+                                       next_step, done_task->max_step);
+                       if (_tdm_exynos_pp_v4l2_queue(pp_v4l2_data, done_task->prop_id[next_step],
+                                               done_task->buffers[next_step].src,
+                                               done_task->buffers[next_step].dst,
+                                               PP_BUF_ENQUEUE) != HAL_TDM_ERROR_NONE) {
+                               return HAL_TDM_ERROR_OPERATION_FAILED;
+                       }
+                       done_task->status = TASK_CONVERTING;
+                       return HAL_TDM_ERROR_NONE;
+               }
+               pp_v4l2_data->current_task_p = NULL;
+               if (done_task->done_func && !pp_v4l2_data->roadmap.step_info[done_task->current_step].sync) {
+                       TDM_BACKEND_DBG("done_task call, Return src %p dst %p",
+                                       done_task->buffers[0].src, done_task->buffers[done_task->max_step-1].dst);
+                       done_task->done_func(pp_v4l2_data, done_task->buffers[0].src,
+                                       done_task->buffers[done_task->max_step-1].dst,
+                                       done_task->done_user_data);
+               } else {
+                       TDM_BACKEND_WRN("pp %p(%d). No done func", pp_v4l2_data, pp_v4l2_data->stamp);
+               }
+               _tdm_exynos_pp_v4l2_destroy_task(pp_v4l2_data, done_task);
+
+               return HAL_TDM_ERROR_NONE;
+       }
+       if (!LIST_IS_EMPTY(&pp_v4l2_data->pending_tasks_list)) {
+               next_task = (tdm_exynos_pp_v4l2_task *)container_of(pp_v4l2_data->pending_tasks_list.prev, next_task, link);
+               if (pp_v4l2_data->sync)
+                       LIST_DEL(&next_task->link);
+       }
+       if (next_task && pp_v4l2_data->new_buffers) {
+               TDM_BACKEND_DBG("pp %p(%d). Task %p(%d) setup next step %d of %d",
+                               pp_v4l2_data, pp_v4l2_data->stamp, next_task, next_task->stamp,
+                               next_task->current_step+1, next_task->max_step);
+               if (_tdm_exynos_pp_v4l2_queue(pp_v4l2_data, next_task->prop_id[next_task->current_step],
+                                                          next_task->buffers[next_task->current_step].src,
+                                                          next_task->buffers[next_task->current_step].dst,
+                                                          PP_BUF_ENQUEUE) != HAL_TDM_ERROR_NONE) {
+                       return HAL_TDM_ERROR_OPERATION_FAILED;
+               }
+               next_task->status = TASK_CONVERTING;
+               pp_v4l2_data->current_task_p = next_task;
+       } else {
+               TDM_BACKEND_DBG("pp %p(%d). Nothing to do", pp_v4l2_data, pp_v4l2_data->stamp);
+       }
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error tdm_exynos_pp_v4l2_task_done_handler(int fd, hal_tdm_event_loop_mask mask, void *user_data)
+{
+       tdm_exynos_pp_v4l2_data *pp_v4l2_data = (tdm_exynos_pp_v4l2_data *)(unsigned long) user_data;
+       tdm_exynos_pp_v4l2_task *done_task = NULL, *next_task = NULL;
+
+       if (!pp_v4l2_data) {
+               TDM_BACKEND_ERR("invalid params %p ", pp_v4l2_data);
+               return HAL_TDM_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!LIST_IS_EMPTY(&pp_v4l2_data->pending_tasks_list)) {
+               next_task = (tdm_exynos_pp_v4l2_task *)container_of(pp_v4l2_data->pending_tasks_list.next, next_task, link);
+               pp_v4l2_data->current_task_p = next_task;
+               LIST_DEL(&next_task->link);
+       }
+       /* remove event loop */
+       pp_v4l2_data->ref_count--;
+#if 0
+       if (pp_v4l2_data->ref_count == 0) {
+               if (!pp_v4l2_data->sync && (pp_v4l2_data->event_source[0] && pp_v4l2_data->event_source[1])) {
+                       tdm_event_loop_source_remove(pp_v4l2_data->event_source[0]);
+                       tdm_event_loop_source_remove(pp_v4l2_data->event_source[1]);
+                       pp_v4l2_data->event_source[0] = NULL;
+                       pp_v4l2_data->event_source[1] = NULL;
+               }
+       }
+#endif
+       if (fd != pp_v4l2_data->v4l2_fd[0] && fd != pp_v4l2_data->v4l2_fd[1]) {
+               TDM_BACKEND_ERR("fd : %d , fd[0] %d , fd[1] %d", fd, pp_v4l2_data->v4l2_fd[0], pp_v4l2_data->v4l2_fd[1]);
+               return HAL_TDM_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!pp_v4l2_data->first_event) {
+               TDM_BACKEND_DBG("pp %p(%d) got a first event. ", pp_v4l2_data, pp_v4l2_data->stamp);
+               pp_v4l2_data->first_event = 1;
+       }
+       if ((done_task = pp_v4l2_data->current_task_p) == NULL) {
+               TDM_BACKEND_ERR("pp %p(%d) received wrong event", pp_v4l2_data, pp_v4l2_data->stamp);
+               return HAL_TDM_ERROR_INVALID_PARAMETER;
+       }
+       done_task->status = TASK_DONE;
+       TDM_BACKEND_DBG("pp %p(%d). Task %p(%d) done step %d of %d", pp_v4l2_data, pp_v4l2_data->stamp, done_task, done_task->stamp,
+                       done_task->current_step+1, done_task->max_step);
+
+       /* dequeue  */
+       if (done_task->buffers[pp_v4l2_data->current_task_p->current_step].src &&
+                       done_task->buffers[pp_v4l2_data->current_task_p->current_step].dst) {
+               _tdm_exynos_pp_v4l2_queue(pp_v4l2_data, done_task->prop_id[done_task->current_step],
+                               done_task->buffers[pp_v4l2_data->current_task_p->current_step].src,
+                               done_task->buffers[pp_v4l2_data->current_task_p->current_step].dst, PP_BUF_DEQUEUE);
+       }
+
+       if (_tdm_exynos_pp_v4l2_worker(pp_v4l2_data) != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("pp %p(%d) worker return ERROR", pp_v4l2_data,
+                               pp_v4l2_data->stamp);
+       }
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+tdm_exynos_pp_v4l2_get_capability(tdm_exynos_display *display_data, hal_tdm_caps_pp *caps)
+{
+       int i;
+
+       if (!caps) {
+               TDM_BACKEND_ERR("invalid params");
+               return HAL_TDM_ERROR_INVALID_PARAMETER;
+       }
+
+       caps->capabilities = HAL_TDM_PP_CAPABILITY_ASYNC;
+
+       caps->format_count = NUM_PP_FORMAT;
+       caps->formats = NULL;
+       if (NUM_PP_FORMAT) {
+               /* will be freed in frontend */
+               caps->formats = calloc(1, sizeof pp_v4l2_formats);
+               if (!caps->formats) {
+                       TDM_BACKEND_ERR("alloc failed");
+                       return HAL_TDM_ERROR_OUT_OF_MEMORY;
+               }
+               for (i = 0; i < caps->format_count; i++)
+                       caps->formats[i] = pp_v4l2_formats[i];
+       }
+
+       caps->min_w = 16;
+       caps->min_h = 8;
+       caps->max_w = -1;   /* not defined */
+       caps->max_h = -1;
+       caps->preferred_align = 2;
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+
+hal_tdm_pp *
+tdm_exynos_pp_v4l2_create(tdm_exynos_display *display_data, hal_tdm_error *error, int *fd1, int *fd2)
+{
+       tdm_exynos_pp_v4l2_data *pp_v4l2_data = calloc(1, sizeof(tdm_exynos_pp_v4l2_data));
+
+       if (!pp_v4l2_data) {
+               TDM_BACKEND_ERR("alloc failed");
+               if (error)
+                       *error = HAL_TDM_ERROR_OUT_OF_MEMORY;
+               return NULL;
+       }
+
+       if ((pp_v4l2_data->v4l2_fd[0] = open("/dev/video50", O_RDWR)) < 0) {
+               TDM_BACKEND_ERR("open error : %d", errno);
+               if (error)
+                       *error = HAL_TDM_ERROR_OPERATION_FAILED;
+               free(pp_v4l2_data);
+               return NULL;
+       }
+       if ((pp_v4l2_data->v4l2_fd[1] = open("/dev/video50", O_RDWR)) < 0) {
+               TDM_BACKEND_ERR("open error : %d", errno);
+               close(pp_v4l2_data->v4l2_fd[0]);
+               if (error)
+                       *error = HAL_TDM_ERROR_OPERATION_FAILED;
+               free(pp_v4l2_data);
+               return NULL;
+       }
+
+       pp_v4l2_data->display_data = display_data;
+       pp_v4l2_data->stamp = pp_v4l2_stamp++;
+       pp_v4l2_data->ref_count = 0;
+       if (!pp_v4l2_list_init) {
+               pp_v4l2_list_init = 1;
+               LIST_INITHEAD(&pp_v4l2_list);
+       }
+       LIST_INITHEAD(&pp_v4l2_data->pending_buffer_list);
+       LIST_INITHEAD(&pp_v4l2_data->pending_tasks_list);
+       LIST_INITHEAD(&pp_v4l2_data->prop_id_list);
+       LIST_ADDTAIL(&pp_v4l2_data->link, &pp_v4l2_list);
+       if (fd1) *fd1 = pp_v4l2_data->v4l2_fd[0];
+       if (fd2) *fd2 = pp_v4l2_data->v4l2_fd[1];
+       TDM_BACKEND_DBG("pp %p(%d). Create", pp_v4l2_data, pp_v4l2_data->stamp);
+       return pp_v4l2_data;
+}
+
+void
+tdm_exynos_pp_v4l2_reset(hal_tdm_pp *pp)
+{
+       tdm_exynos_pp_v4l2_data *pp_v4l2_data = (tdm_exynos_pp_v4l2_data *) pp;
+       tdm_exynos_pp_v4l2_buffer *b = NULL, *bb = NULL;
+       tdm_exynos_pp_v4l2_task *task = NULL, *next_task = NULL;
+       tdm_exynos_prop_id *prop_id = NULL, *next_prop_id = NULL;
+       TDM_BACKEND_RETURN_IF_FAIL(_tdm_exynos_pp_v4l2_check_struct(pp_v4l2_data));
+       TDM_BACKEND_DBG("pp %p(%d). Reset", pp_v4l2_data, pp_v4l2_data->stamp);
+
+       if (pp_v4l2_data->current_task_p && pp_v4l2_data->current_task_p->status == TASK_CONVERTING) {
+               _tdm_exynos_pp_v4l2_queue(pp_v4l2_data, pp_v4l2_data->current_task_p->prop_id[pp_v4l2_data->current_task_p->current_step],
+                                                  pp_v4l2_data->current_task_p->buffers[pp_v4l2_data->current_task_p->current_step].src,
+                                                  pp_v4l2_data->current_task_p->buffers[pp_v4l2_data->current_task_p->current_step].dst, PP_BUF_DEQUEUE);
+               _tdm_exynos_pp_v4l2_destroy_task(pp_v4l2_data, pp_v4l2_data->current_task_p);
+       }
+       LIST_FOR_EACH_ENTRY_SAFE(task, next_task, &pp_v4l2_data->pending_tasks_list, link) {
+               LIST_DEL(&task->link);
+               _tdm_exynos_pp_v4l2_destroy_task(pp_v4l2_data, task);
+       }
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_v4l2_data->pending_buffer_list, link) {
+               LIST_DEL(&b->link);
+               free(b);
+       }
+       LIST_FOR_EACH_ENTRY_SAFE(prop_id, next_prop_id, &pp_v4l2_data->prop_id_list, link) {
+               _tdm_exynos_pp_v4l2_cmd(pp_v4l2_data, prop_id->prop_id, PP_STOP);
+       }
+
+       pp_v4l2_data->stamp = pp_v4l2_stamp++;
+       pp_v4l2_data->ref_count = 0;
+
+       LIST_INITHEAD(&pp_v4l2_data->pending_buffer_list);
+       LIST_INITHEAD(&pp_v4l2_data->pending_tasks_list);
+       LIST_INITHEAD(&pp_v4l2_data->prop_id_list);
+}
+
+void
+exynos_display_destroy_pp_v4l2(hal_tdm_pp *pp)
+{
+       tdm_exynos_display *display_data = NULL;
+       tdm_exynos_pp_v4l2_data *pp_v4l2_data = (tdm_exynos_pp_v4l2_data *) pp;
+       TDM_BACKEND_RETURN_IF_FAIL(pp_v4l2_data);
+
+       display_data = pp_v4l2_data->display_data;
+       TDM_BACKEND_RETURN_IF_FAIL(display_data);
+       TDM_BACKEND_RETURN_IF_FAIL(display_data->pp_count);
+
+       display_data->pp_count = 0;
+       tdm_exynos_pp_v4l2_reset(pp_v4l2_data);
+}
+
+void
+exynos_pp_v4l2_destroy(hal_tdm_pp *pp)
+{
+       tdm_exynos_pp_v4l2_data *pp_v4l2_data = (tdm_exynos_pp_v4l2_data *) pp;
+       tdm_exynos_pp_v4l2_buffer *b = NULL, *bb = NULL;
+       tdm_exynos_pp_v4l2_task *task = NULL, *next_task = NULL;
+       tdm_exynos_prop_id *prop_id = NULL, *next_prop_id = NULL;
+       TDM_BACKEND_RETURN_IF_FAIL(_tdm_exynos_pp_v4l2_check_struct(pp_v4l2_data));
+       TDM_BACKEND_DBG("pp %p(%d). Destroy", pp_v4l2_data, pp_v4l2_data->stamp);
+#if 0
+       if (!pp_v4l2_data->sync && (pp_v4l2_data->event_source[0] && pp_v4l2_data->event_source[1])) {
+               tdm_event_loop_source_remove(pp_v4l2_data->event_source[0]);
+               tdm_event_loop_source_remove(pp_v4l2_data->event_source[1]);
+               pp_v4l2_data->event_source[0] = NULL;
+               pp_v4l2_data->event_source[1] = NULL;
+       }
+#endif
+       if (pp_v4l2_data->current_task_p && pp_v4l2_data->current_task_p->status == TASK_CONVERTING) {
+               _tdm_exynos_pp_v4l2_queue(pp_v4l2_data, pp_v4l2_data->current_task_p->prop_id[pp_v4l2_data->current_task_p->current_step],
+                                                  pp_v4l2_data->current_task_p->buffers[pp_v4l2_data->current_task_p->current_step].src,
+                                                  pp_v4l2_data->current_task_p->buffers[pp_v4l2_data->current_task_p->current_step].dst, PP_BUF_DEQUEUE);
+               _tdm_exynos_pp_v4l2_destroy_task(pp_v4l2_data, pp_v4l2_data->current_task_p);
+       }
+       LIST_FOR_EACH_ENTRY_SAFE(task, next_task, &pp_v4l2_data->pending_tasks_list, link) {
+               LIST_DEL(&task->link);
+               _tdm_exynos_pp_v4l2_destroy_task(pp_v4l2_data, task);
+       }
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_v4l2_data->pending_buffer_list, link) {
+               LIST_DEL(&b->link);
+               free(b);
+       }
+       LIST_FOR_EACH_ENTRY_SAFE(prop_id, next_prop_id, &pp_v4l2_data->prop_id_list, link) {
+               _tdm_exynos_pp_v4l2_cmd(pp_v4l2_data, prop_id->prop_id, PP_STOP);
+       }
+
+       if (pp_v4l2_data->v4l2_fd[1])
+           close(pp_v4l2_data->v4l2_fd[1]);
+
+       if (pp_v4l2_data->v4l2_fd[0])
+           close(pp_v4l2_data->v4l2_fd[0]);
+
+       pp_v4l2_data->display_data = NULL;
+
+       LIST_DEL(&pp_v4l2_data->link);
+       free(pp_v4l2_data);
+}
+
+static hal_tdm_error
+_exynos_pp_v4l2_get_scale_leap(unsigned int src, unsigned int dst,
+                                               unsigned int *leap_array, unsigned int *size)
+{
+       unsigned int i = 0;
+       unsigned int ratio, next_value = src;
+       TDM_BACKEND_DBG("pp. scale src %u", src);
+       for (i = 0; i < PP_MAX_STEP; i++) {
+               ratio = PP_RATIO(next_value, dst);
+
+               if (ratio < PP_UP_MAX_RATIO)
+                       next_value = PP_MAX_UP_SIZE(next_value);
+               else if (ratio > PP_DOWN_MIN_RATIO)
+                       next_value =  PP_MIN_DOWN_SIZE(next_value);
+
+               if (leap_array)
+                       leap_array[i] = next_value;
+               TDM_BACKEND_DBG("[%u] => %u", i, next_value);
+
+               if ((ratio >= PP_UP_MAX_RATIO) && (ratio <= PP_DOWN_MIN_RATIO))
+                       break;
+       }
+       if (i >= PP_MAX_STEP - 1) {
+               TDM_BACKEND_ERR("Can't scale. Reaching maximum iteration count %d", PP_MAX_STEP);
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+       TDM_BACKEND_DBG("[%u] dst => %u", i, dst);
+       if (leap_array)
+               leap_array[i] = dst;
+       if (size)
+               *size = i + 1;
+       return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_exynos_pp_v4l2_make_roadmap(tdm_exynos_pp_v4l2_data *pp_v4l2_data, hal_tdm_info_pp *info)
+{
+
+       unsigned int height_leap[PP_MAX_STEP], width_leap[PP_MAX_STEP],
+                        height_leap_size = 0, width_leap_size = 0, max_size = 0, i,
+                        src_height = (info->transform % 2) ? info->src_config.pos.w : info->src_config.pos.h,
+                        src_width = (info->transform % 2) ? info->src_config.pos.h : info->src_config.pos.w;
+       TDM_BACKEND_DBG("Height %u", info->src_config.pos.h);
+       if (_exynos_pp_v4l2_get_scale_leap(src_height,
+                                                               info->dst_config.pos.h,
+                                                               height_leap,
+                                                               &height_leap_size) != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("height %u -> %u ratio out of range", info->src_config.pos.h,
+                               info->dst_config.pos.h);
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+       TDM_BACKEND_DBG("Width %u", info->src_config.pos.w);
+       if (_exynos_pp_v4l2_get_scale_leap(src_width,
+                                                               info->dst_config.pos.w,
+                                                               width_leap,
+                                                               &width_leap_size) != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("width %u -> %u ratio out of range", info->src_config.pos.w,
+                               info->dst_config.pos.w);
+               return HAL_TDM_ERROR_OPERATION_FAILED;
+       }
+       max_size = (width_leap_size > height_leap_size ? width_leap_size :
+                               height_leap_size);
+
+       memcpy(&pp_v4l2_data->new_roadmap.step_info[0], info, sizeof(hal_tdm_info_pp));
+       pp_v4l2_data->new_roadmap.step_info[0].dst_config.pos.h = height_leap[0];
+       pp_v4l2_data->new_roadmap.step_info[0].dst_config.pos.w = width_leap[0];
+       max_size = (width_leap_size > height_leap_size ? width_leap_size :
+                               height_leap_size);
+       for (i = 1; i < max_size; i++) {
+               pp_v4l2_data->new_roadmap.step_info[i - 1].dst_config.pos.w =
+                                                               width_leap[(((i - 1) < width_leap_size) ? (i - 1) : (width_leap_size - 1))];
+               pp_v4l2_data->new_roadmap.step_info[i - 1].dst_config.pos.h =
+                                                               height_leap[(((i - 1) < height_leap_size) ? (i - 1) : (height_leap_size - 1))];
+               pp_v4l2_data->new_roadmap.step_info[i - 1].dst_config.size.h = pp_v4l2_data->new_roadmap.step_info[i - 1].dst_config.pos.w;
+               pp_v4l2_data->new_roadmap.step_info[i - 1].dst_config.size.v = pp_v4l2_data->new_roadmap.step_info[i - 1].dst_config.pos.h;
+               pp_v4l2_data->new_roadmap.step_info[i].transform = HAL_TDM_TRANSFORM_NORMAL;
+               pp_v4l2_data->new_roadmap.step_info[i].src_config = pp_v4l2_data->new_roadmap.step_info[i - 1].dst_config;
+               pp_v4l2_data->new_roadmap.step_info[i].dst_config = pp_v4l2_data->new_roadmap.step_info[i - 1].dst_config;
+               pp_v4l2_data->new_roadmap.step_info[i].src_config.pos.x = 0;
+               pp_v4l2_data->new_roadmap.step_info[i].src_config.pos.y = 0;
+               pp_v4l2_data->new_roadmap.step_info[i].dst_config.pos.x = 0;
+               pp_v4l2_data->new_roadmap.step_info[i].dst_config.pos.y = 0;
+               pp_v4l2_data->new_roadmap.step_info[i].sync = pp_v4l2_data->new_roadmap.step_info[i - 1].sync;
+               pp_v4l2_data->new_roadmap.step_info[i].flags = pp_v4l2_data->new_roadmap.step_info[i - 1].flags;
+       }
+       memcpy(&pp_v4l2_data->new_roadmap.step_info[max_size - 1].dst_config, &info->dst_config, sizeof(hal_tdm_info_config));
+       pp_v4l2_data->new_roadmap.max_step = max_size;
+       return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+exynos_pp_v4l2_set_info(hal_tdm_pp *pp, hal_tdm_info_pp *info)
+{
+       tdm_exynos_pp_v4l2_data *pp_v4l2_data = (tdm_exynos_pp_v4l2_data *) pp;
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+       int cap_id = 0, out_id = 0;
+       unsigned int i;
+       tdm_exynos_pp_v4l2_task *task = NULL, *next_task = NULL, *done_task = NULL;
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(info, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(_tdm_exynos_pp_v4l2_check_struct(pp_v4l2_data), HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_DBG("pp %p(%d). Set new info.", pp_v4l2_data, pp_v4l2_data->stamp);
+
+       if (_exynos_pp_v4l2_make_roadmap(pp_v4l2_data, info) != HAL_TDM_ERROR_NONE) {
+               TDM_BACKEND_ERR("pp %p(%d). Wrong convertation settings", pp_v4l2_data, pp_v4l2_data->stamp);
+               return HAL_TDM_ERROR_INVALID_PARAMETER;
+       }
+       pp_v4l2_data->roadmap_changed = 1;
+       pp_v4l2_data->sync = info->sync;
+
+       /* error case (set_info->attach->set_info) - remove previous attach buffer  */
+       if (pp_v4l2_data->new_buffers == 1) {
+               LIST_FOR_EACH_ENTRY_SAFE(task, next_task, &pp_v4l2_data->pending_tasks_list, link) {
+                       LIST_DEL(&task->link);
+                       if (task->done_func) {
+                               task->done_func(pp_v4l2_data, task->buffers[0].src,
+                                               task->buffers[task->max_step-1].dst,
+                                               task->done_user_data);
+                       }
+                       _tdm_exynos_pp_v4l2_destroy_task(pp_v4l2_data, task);
+               }
+               TDM_BACKEND_WRN("error case : set_info->attach->set_info");
+               pp_v4l2_data->new_buffers = 0;
+       }
+
+       /* reset ref_count */
+       pp_v4l2_data->ref_count = 0;
+
+       /* copy roadmap*/
+       if (pp_v4l2_data->roadmap_changed) {
+               _tdm_exynos_pp_v4l2_roadmap_copy(&pp_v4l2_data->roadmap, &pp_v4l2_data->new_roadmap);
+               pp_v4l2_data->roadmap_changed = 0;
+               _tdm_exynos_pp_v4l2_roadmap_print(&pp_v4l2_data->roadmap);
+       }
+#if 0
+       /* event loop remove */
+       if (!pp_v4l2_data->sync && (pp_v4l2_data->event_source[0] && pp_v4l2_data->event_source[1])) {
+               tdm_event_loop_source_remove(pp_v4l2_data->event_source[0]);
+               tdm_event_loop_source_remove(pp_v4l2_data->event_source[1]);
+               pp_v4l2_data->event_source[0] = NULL;
+               pp_v4l2_data->event_source[1] = NULL;
+       }
+#endif
+       /* now converting buffer handling */
+       if (pp_v4l2_data->current_task_p && pp_v4l2_data->current_task_p->status == TASK_CONVERTING) {
+               tdm_exynos_pp_v4l2_task *done_task = pp_v4l2_data->current_task_p;
+               _tdm_exynos_pp_v4l2_queue(pp_v4l2_data, done_task->prop_id[done_task->current_step],
+                               done_task->buffers[done_task->current_step].src,
+                               done_task->buffers[done_task->current_step].dst, PP_BUF_DEQUEUE);
+               pp_v4l2_data->current_task_p = NULL;
+
+               if (!LIST_IS_EMPTY(&pp_v4l2_data->pending_tasks_list)) {
+                       next_task = (tdm_exynos_pp_v4l2_task *)container_of(pp_v4l2_data->pending_tasks_list.next, next_task, link);
+                       LIST_DEL(&next_task->link);
+               }
+               if (done_task->done_func) {
+                       done_task->done_func(pp_v4l2_data, done_task->buffers[0].src,
+                                       done_task->buffers[done_task->max_step-1].dst,
+                                       done_task->done_user_data);
+               }
+
+               _tdm_exynos_pp_v4l2_destroy_task(pp_v4l2_data, done_task);
+       }
+
+       /* pending task list handling */
+       while (!LIST_IS_EMPTY(&pp_v4l2_data->pending_tasks_list)) {
+               /*find pending list*/
+               next_task = (tdm_exynos_pp_v4l2_task *)container_of(pp_v4l2_data->pending_tasks_list.next, next_task, link);
+               LIST_DEL(&next_task->link);
+
+               /* qbuf */
+               TDM_BACKEND_DBG("pp %p(%d). Task %p(%d) setup next step %d of %d",
+                               pp_v4l2_data, pp_v4l2_data->stamp, next_task, next_task->stamp,
+                               next_task->current_step+1, next_task->max_step);
+               if (_tdm_exynos_pp_v4l2_queue(pp_v4l2_data, next_task->prop_id[next_task->current_step],
+                                       next_task->buffers[next_task->current_step].src,
+                                       next_task->buffers[next_task->current_step].dst,
+                                       PP_BUF_ENQUEUE) != HAL_TDM_ERROR_NONE) {
+                       return HAL_TDM_ERROR_OPERATION_FAILED;
+               }
+               next_task->status = TASK_CONVERTING;
+               pp_v4l2_data->current_task_p = next_task;
+
+               /* dqbuf */
+               done_task = pp_v4l2_data->current_task_p;
+               int prop_id = done_task->prop_id[done_task->current_step];
+               int idx = prop_id - 1;
+               _tdm_exynos_pp_v4l2_queue(pp_v4l2_data, prop_id, done_task->buffers[idx].src, done_task->buffers[idx].dst, PP_BUF_DEQUEUE);
+               pp_v4l2_data->current_task_p->status = TASK_DONE;
+
+               /* double operation */
+
+               /* buffer release */
+               pp_v4l2_data->current_task_p = NULL;
+               if (done_task->done_func) {
+                       done_task->done_func(pp_v4l2_data, done_task->buffers[0].src,
+                                       done_task->buffers[done_task->max_step-1].dst,
+                                       done_task->done_user_data);
+               }
+
+               _tdm_exynos_pp_v4l2_destroy_task(pp_v4l2_data, done_task);
+       }
+
+       /* Stream OFF */
+       out_id = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       cap_id = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[0], VIDIOC_STREAMOFF, &out_id)) {
+               TDM_BACKEND_ERR("ioctl error : %d", errno);
+               return HAL_TDM_ERROR_BAD_REQUEST;
+       }
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[0], VIDIOC_STREAMOFF, &cap_id)) {
+               TDM_BACKEND_ERR("ioctl error : %d", errno);
+               return HAL_TDM_ERROR_BAD_REQUEST;
+       }
+
+       /* pp_v4l2_set call */
+       for (i = 0; i < pp_v4l2_data->roadmap.max_step; i++) {
+               pp_v4l2_data->roadmap.prop_id[i] = _tdm_exynos_pp_v4l2_set(pp_v4l2_data, &pp_v4l2_data->roadmap.step_info[i], i + 1);
+               if (pp_v4l2_data->roadmap.prop_id[i] <= 0) {
+                       TDM_BACKEND_ERR("pp %p(%d). Can't setup converter", pp_v4l2_data, pp_v4l2_data->stamp);
+                       return HAL_TDM_ERROR_BAD_REQUEST;
+               }
+       }
+
+       /* stream ON */
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[0], VIDIOC_STREAMON, &out_id)) {
+               TDM_BACKEND_ERR("ioctl error : %d", errno);
+               return HAL_TDM_ERROR_BAD_REQUEST;
+       }
+       if (0 > ioctl(pp_v4l2_data->v4l2_fd[0], VIDIOC_STREAMON, &cap_id)) {
+               TDM_BACKEND_ERR("ioctl error : %d", errno);
+               /* out stream off -> return */
+               return HAL_TDM_ERROR_BAD_REQUEST;
+       }
+
+       return ret;
+}
+
+hal_tdm_error
+exynos_pp_v4l2_attach(hal_tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
+{
+       tdm_exynos_pp_v4l2_data *pp_v4l2_data = (tdm_exynos_pp_v4l2_data *) pp;
+       tdm_exynos_pp_v4l2_buffer *buffer;
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(src, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(dst, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(_tdm_exynos_pp_v4l2_check_struct(pp_v4l2_data), HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       /* error case (attach -> attach) */
+       if (pp_v4l2_data->new_buffers == 1) {
+               TDM_BACKEND_ERR("error case : attach -> attach");
+               return HAL_TDM_ERROR_NOT_IMPLEMENTED;
+       }
+
+       /* check max attach buffer count */
+       pp_v4l2_data->ref_count++;
+       if (pp_v4l2_data->ref_count > MAX_ATTACH_BUFFER) {
+               pp_v4l2_data->ref_count = 4;
+               TDM_BACKEND_ERR("exceed maximum attach number 4");
+               return HAL_TDM_ERROR_NOT_IMPLEMENTED;
+       }
+
+       buffer = calloc(1, sizeof(tdm_exynos_pp_v4l2_buffer));
+       if (!buffer) {
+               TDM_BACKEND_ERR("pp %p(%d). Alloc failed", pp_v4l2_data, pp_v4l2_data->stamp);
+               return HAL_TDM_ERROR_NONE;
+       }
+       buffer->index = 0;
+       buffer->src = src;
+       buffer->dst = dst;
+       pp_v4l2_data->new_buffers = 1;
+
+       TDM_BACKEND_DBG("pp %p(%d). Attach src %p dst %p buffers", pp_v4l2_data, pp_v4l2_data->stamp, buffer->src, buffer->dst);
+       LIST_ADDTAIL(&buffer->link, &pp_v4l2_data->pending_buffer_list);
+
+       /* add pending_tasks_list */
+       if (_tdm_exynos_pp_v4l2_make_new_tasks(pp_v4l2_data) < 0) {
+               TDM_BACKEND_ERR("pp %p(%d). Can't create new task", pp_v4l2_data, pp_v4l2_data->stamp);
+               return HAL_TDM_ERROR_BAD_REQUEST;
+       }
+
+       return HAL_TDM_ERROR_NONE;
+}
+
+static int
+_tdm_exynos_pp_v4l2_make_new_tasks(tdm_exynos_pp_v4l2_data *pp_v4l2_data)
+{
+       tdm_exynos_pp_v4l2_buffer *main_buffer = NULL, *b = NULL, *bb = NULL;
+       tdm_exynos_pp_v4l2_task *new_task = NULL;
+       int i;
+
+
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_v4l2_data->pending_buffer_list, link) {
+               main_buffer = b;
+               if ((new_task = calloc(1, sizeof(tdm_exynos_pp_v4l2_task))) == NULL) {
+                       TDM_BACKEND_ERR("Out of memory");
+                       return -1;
+               }
+               memcpy(new_task->prop_id, pp_v4l2_data->roadmap.prop_id, sizeof(unsigned int)*PP_MAX_STEP);
+               new_task->stamp = task_stamp++;
+               new_task->max_step = pp_v4l2_data->roadmap.max_step;
+               new_task->current_step = 0;
+               new_task->done_func = pp_v4l2_data->done_func;
+               new_task->done_user_data = pp_v4l2_data->done_user_data;
+               tbm_surface_internal_ref(main_buffer->src);
+               new_task->buffers[0].src = main_buffer->src;
+               tbm_surface_internal_ref(main_buffer->dst);
+               new_task->buffers[new_task->max_step-1].dst = main_buffer->dst;
+               new_task->attach_buffer = b;
+               LIST_DEL(&b->link);
+
+               for (i = 1; i < new_task->max_step; i++) {
+                       new_task->buffers[i-1].dst = tbm_surface_create(pp_v4l2_data->roadmap.step_info[i-1].dst_config.size.h,
+                                                                                                                       pp_v4l2_data->roadmap.step_info[i-1].dst_config.size.v,
+                                                                                                                       pp_v4l2_data->roadmap.step_info[i-1].dst_config.format);
+                       tbm_surface_internal_ref(new_task->buffers[i-1].dst);
+                       new_task->buffers[i].src = new_task->buffers[i-1].dst;
+                       }
+               LIST_ADDTAIL(&new_task->link, &pp_v4l2_data->pending_tasks_list);
+               TDM_BACKEND_DBG("pp %p(%d). Add new src %p dst %p buffer", pp_v4l2_data, pp_v4l2_data->stamp, main_buffer->src, main_buffer->dst);
+               TDM_BACKEND_DBG("To New task %p(%d)", new_task, new_task->stamp);
+       }
+       if (main_buffer == NULL) {
+               TDM_BACKEND_WRN("pp %p(%d) buffer list is empty. Nothing to do", pp_v4l2_data, pp_v4l2_data->stamp);
+               return 0;
+       }
+       return 1;
+}
+
+hal_tdm_error
+exynos_pp_v4l2_commit(hal_tdm_pp *pp)
+{
+       unsigned int prop_id, idx;
+       tdm_exynos_pp_v4l2_data *pp_v4l2_data = (tdm_exynos_pp_v4l2_data *) pp;
+       hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+       tdm_exynos_pp_v4l2_task *done_task = NULL;
+
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(_tdm_exynos_pp_v4l2_check_struct(pp_v4l2_data), HAL_TDM_ERROR_INVALID_PARAMETER);
+
+       if (pp_v4l2_data->new_buffers == 1) {
+               /* call pp_v4l2_worker for Qbuf */
+               ret = _tdm_exynos_pp_v4l2_worker(pp_v4l2_data);
+               pp_v4l2_data->new_buffers = 0;
+
+               /* sync mode */
+               if (pp_v4l2_data->roadmap.step_info[pp_v4l2_data->current_task_p->current_step].sync) {
+                       pp_v4l2_data->current_task_p->status = TASK_CONVERTING;
+                       done_task = pp_v4l2_data->current_task_p;
+                       prop_id = pp_v4l2_data->current_task_p->prop_id[pp_v4l2_data->current_task_p->current_step];
+                       idx = prop_id - 1;
+                       _tdm_exynos_pp_v4l2_queue(pp_v4l2_data, prop_id, done_task->buffers[idx].src, done_task->buffers[idx].dst, PP_BUF_DEQUEUE);
+                       pp_v4l2_data->current_task_p->status = TASK_DONE;
+
+                       unsigned int next_step = done_task->current_step + 1;
+                       /* double operation */
+                       if (next_step < done_task->max_step) {
+                               TDM_BACKEND_DBG("pp %p(%d). Task %p(%d) setup next step %d of %d",
+                                               pp_v4l2_data, pp_v4l2_data->stamp, done_task, done_task->stamp,
+                                               next_step, done_task->max_step);
+                               if (_tdm_exynos_pp_v4l2_queue(pp_v4l2_data, done_task->prop_id[next_step],
+                                                       done_task->buffers[next_step].src,
+                                                       done_task->buffers[next_step].dst,
+                                                       PP_BUF_ENQUEUE) != HAL_TDM_ERROR_NONE) {
+                                       return HAL_TDM_ERROR_OPERATION_FAILED;
+                               }
+                               done_task->status = TASK_CONVERTING;
+                               prop_id = pp_v4l2_data->current_task_p->prop_id[next_step];
+                               idx = prop_id - 1;
+                               _tdm_exynos_pp_v4l2_queue(pp_v4l2_data, prop_id, done_task->buffers[idx].src, done_task->buffers[idx].dst, PP_BUF_DEQUEUE);
+                               pp_v4l2_data->current_task_p->status = TASK_DONE;
+                               ++(done_task->current_step);
+                       }
+                       pp_v4l2_data->current_task_p = NULL;
+
+                       if (done_task->done_func) {
+                               done_task->done_func(pp_v4l2_data, done_task->buffers[0].src,
+                                               done_task->buffers[done_task->max_step-1].dst,
+                                               done_task->done_user_data);
+                       }
+
+                       _tdm_exynos_pp_v4l2_destroy_task(pp_v4l2_data, done_task);
+               }
+       } else {
+               /* error case (attach->commit->commit(error)) */
+               TDM_BACKEND_ERR("error case : attach->commit->commit");
+               return HAL_TDM_ERROR_NOT_IMPLEMENTED;
+       }
+
+       return ret;
+}
+
+hal_tdm_error
+exynos_pp_v4l2_set_done_handler(hal_tdm_pp *pp, hal_tdm_pp_done_handler func, void *user_data)
+{
+       tdm_exynos_pp_v4l2_data *pp_v4l2_data = (tdm_exynos_pp_v4l2_data *) pp;
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_RETURN_VAL_IF_FAIL(_tdm_exynos_pp_v4l2_check_struct(pp_v4l2_data), HAL_TDM_ERROR_INVALID_PARAMETER);
+       TDM_BACKEND_DBG("pp %p(%d). Set done handler func %p", pp_v4l2_data, pp_v4l2_data->stamp, func);
+       pp_v4l2_data->done_func = func;
+       pp_v4l2_data->done_user_data = user_data;
+       return HAL_TDM_ERROR_NONE;
+}
diff --git a/src/libhal-backend-tdm-exynos-deconfb/tdm_list.h b/src/libhal-backend-tdm-exynos-deconfb/tdm_list.h
new file mode 100644 (file)
index 0000000..3873817
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+
+/**
+ * \file
+ * List macros heavily inspired by the Linux kernel
+ * list handling. No list looping yet.
+ *
+ * Is not threadsafe, so common operations need to
+ * be protected using an external mutex.
+ */
+#ifndef _U_DOUBLE_LIST_H_
+#define _U_DOUBLE_LIST_H_
+
+#include <stddef.h>
+
+struct list_head {
+       struct list_head *prev;
+       struct list_head *next;
+};
+
+static inline void list_inithead(struct list_head *item)
+{
+       item->prev = item;
+       item->next = item;
+}
+
+static inline void list_add(struct list_head *item, struct list_head *list)
+{
+       item->prev = list;
+       item->next = list->next;
+       list->next->prev = item;
+       list->next = item;
+}
+
+static inline void list_addtail(struct list_head *item, struct list_head *list)
+{
+       item->next = list;
+       item->prev = list->prev;
+       list->prev->next = item;
+       list->prev = item;
+}
+
+static inline void list_replace(struct list_head *from, struct list_head *to)
+{
+       to->prev = from->prev;
+       to->next = from->next;
+       from->next->prev = to;
+       from->prev->next = to;
+}
+
+static inline void list_del(struct list_head *item)
+{
+       item->prev->next = item->next;
+       item->next->prev = item->prev;
+}
+
+static inline void list_delinit(struct list_head *item)
+{
+       item->prev->next = item->next;
+       item->next->prev = item->prev;
+       item->next = item;
+       item->prev = item;
+}
+
+static inline int list_length(struct list_head *item)
+{
+       struct list_head *next;
+       int length = 0;
+
+       next = item->next;
+       while (next != item) {
+               length++;
+               next = next->next;
+       }
+
+       return length;
+}
+
+#define LIST_INITHEAD(__item) list_inithead(__item)
+#define LIST_ADD(__item, __list) list_add(__item, __list)
+#define LIST_ADDTAIL(__item, __list) list_addtail(__item, __list)
+#define LIST_REPLACE(__from, __to) list_replace(__from, __to)
+#define LIST_DEL(__item) list_del(__item)
+#define LIST_DELINIT(__item) list_delinit(__item)
+#define LIST_LENGTH(__item) list_length(__item)
+
+#define LIST_ENTRY(__type, __item, __field)   \
+       ((__type *)(((char *)(__item)) - offsetof(__type, __field)))
+
+#define LIST_FIRST_ENTRY(__ptr, __type, __field)   \
+       LIST_ENTRY(__type, (__ptr)->next, __field)
+
+#define LIST_LAST_ENTRY(__ptr, __type, __field)   \
+       LIST_ENTRY(__type, (__ptr)->prev, __field)
+
+#define LIST_IS_EMPTY(__list)                   \
+       ((__list)->next == (__list))
+
+#ifndef container_of
+#define container_of(ptr, sample, member)                              \
+       (void *)((char *)(ptr)                                          \
+            - ((char *)&(sample)->member - (char *)(sample)))
+#endif
+
+#define LIST_FOR_EACH_ENTRY(pos, head, member)                         \
+       for (pos = container_of((head)->next, pos, member);                     \
+       &pos->member != (head);                                         \
+       pos = container_of(pos->member.next, pos, member))
+
+#define LIST_FOR_EACH_ENTRY_REV(pos, head, member)                             \
+       for (pos = container_of((head)->prev, pos, member);                     \
+       &pos->member != (head);                                         \
+       pos = container_of(pos->member.prev, pos, member))
+
+#define LIST_FOR_EACH_ENTRY_SAFE(pos, storage, head, member)   \
+       for (pos = container_of((head)->next, pos, member),                     \
+       storage = container_of(pos->member.next, pos, member);  \
+       &pos->member != (head);                                         \
+       pos = storage, storage = container_of(storage->member.next, storage, member))
+
+#define LIST_FOR_EACH_ENTRY_SAFE_REV(pos, storage, head, member)       \
+       for (pos = container_of((head)->prev, pos, member),                     \
+       storage = container_of(pos->member.prev, pos, member);          \
+       &pos->member != (head);                                         \
+       pos = storage, storage = container_of(storage->member.prev, storage, member))
+
+#define LIST_FOR_EACH_ENTRY_FROM(pos, start, head, member)             \
+       for (pos = container_of((start), pos, member);                  \
+       &pos->member != (head);                                         \
+       pos = container_of(pos->member.next, pos, member))
+
+#define LIST_FOR_EACH_ENTRY_FROM_REV(pos, start, head, member)         \
+       for (pos = container_of((start), pos, member);                  \
+       &pos->member != (head);                                         \
+       pos = container_of(pos->member.prev, pos, member))
+
+#define LIST_FIND_ITEM(item, head, type, member, found) \
+       do {    \
+               type *pos = NULL;       \
+               found = NULL;   \
+               LIST_FOR_EACH_ENTRY(pos, head, member)  \
+                       if (pos == item) { found = item; break; }       \
+       } while (0)
+
+#endif /*_U_DOUBLE_LIST_H_*/