This is the first step for implementing the new hal backend.
libhal-backend-tdm-sprd package has a new hal backend module.
The new hal architecture will be available for Tizen 6.5.
Change-Id: I3ff5e89d6a3141a2d522d653a4eb14d580ba70fb
Signed-off-by: Junkyeong Kim <jk0430.kim@samsung.com>
# Enable quiet compiles on automake 1.11.
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
-PKG_CHECK_MODULES(TDM_SPRD, libtdm libtbm libdrm)
PKG_CHECK_MODULES(UDEV, libudev, [udev=yes], [udev=no])
+
+# for libtdm-sprd
+PKG_CHECK_MODULES(TDM_SPRD, libtdm libtbm [libdrm >= 2.4.47] libdrm libdrm_exynos)
+
+# for libhal-backend-tdm-sprd
+PKG_CHECK_MODULES(LIBHAL_BACKEND_TDM_SPRD, hal-api-common hal-api-tdm hal-api-tbm libdrm dlog pixman-1)
+
if test x"$udev" = xyes; then
AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection])
+
+ # for libtdm-sprd
TDM_SPRD_CFLAGS="$TDM_SPRD_CFLAGS $UDEV_CFLAGS"
TDM_SPRD_LIBS="$TDM_SPRD_LIBS $UDEV_LIBS"
+
+ # for libhal-backend-tdm-sprd
+ LIBHAL_BACKEND_TDM_SPRD_CFLAGS="$LIBHAL_BACKEND_TDM_SPRD_CFLAGS $UDEV_CFLAGS"
+ LIBHAL_BACKEND_TDM_SPRD_LIBS="$LIBHAL_BACKEND_TDM_SPRD_LIBS $UDEV_LIBS"
+ AC_SUBST(LIBHAL_BACKEND_TDM_SPRD_CFLAGS)
+ AC_SUBST(LIBHAL_BACKEND_TDM_SPRD_LIBS)
fi
+# for libtdm-sprd
AC_SUBST(TDM_SPRD_CFLAGS)
AC_SUBST(TDM_SPRD_LIBS)
+# for libhal-backend-tdm-sprd
+AC_SUBST(LIBHAL_BACKEND_TDM_SPRD_CFLAGS)
+AC_SUBST(LIBHAL_BACKEND_TDM_SPRD_LIBS)
+
+AC_DEFINE_UNQUOTED(LIBDRM_MAJOR_VERSION, [`pkg-config --modversion libdrm | cut -d '.' -f 1`], dnl
+ [libdrm major version])
+AC_DEFINE_UNQUOTED(LIBDRM_MINOR_VERSION, [`pkg-config --modversion libdrm | cut -d '.' -f 2`], dnl
+ [libdrm major version])
+AC_DEFINE_UNQUOTED(LIBDRM_MICRO_VERSION, [`pkg-config --modversion libdrm | cut -d '.' -f 3`], dnl
+ [libdrm major version])
+
# set the dir for the tbm module
DEFAULT_TDM_MODULE_PATH="${libdir}/tdm"
AC_ARG_WITH(tdm-module-path, AS_HELP_STRING([--with-tdm-module-path=PATH], [tdm module dir]),
[ 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-sprd/Makefile
src/libtdm-sprd/Makefile
src/Makefile])
echo ""
echo "$PACKAGE_STRING will be compiled with:"
echo ""
+echo "TDM_SPRD_CFLAGS : $LIBHAL_BACKEND_TDM_SPRD_CFLAGS"
+echo "TDM_SPRD_LIBS : $LIBHAL_BACKEND_TDM_SPRD_LIBS"
+echo "TDM_MODULE_DIR : $HAL_LIBDIR"
+echo ""
+echo ""
+echo "$PACKAGE_STRING will be compiled with:"
+echo ""
echo "TDM_SPRD_CFLAGS : $TDM_SPRD_CFLAGS"
echo "TDM_SPRD_LIBS : $TDM_SPRD_LIBS"
echo "TDM_MODULE_DIR : $TDM_MODULE_PATH"
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
ExcludeArch: %{ix86} x86_64 aarch64
Source0: %{name}-%{version}.tar.gz
Source1001: %{name}.manifest
+Source1002: libhal-backend-tdm-sprd.manifest
+
BuildRequires: pkgconfig(libdrm)
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)
BuildRequires: kernel-headers-3.10-sc7730
BuildConflicts: linux-glibc-devel
%description
Back-End library of Tizen Display Manager Spreadtrum : libtdm-mgr SPRD library
+%package -n hal-backend-tdm-sprd
+Summary: hal-backend-tdm module for sprd
+Group: System/Libraries
+Requires: hal-api-tdm
+Requires: hal-api-common
+
+%description -n hal-backend-tdm-sprd
+descriptionion: hal tdm backend module for sprd
+
%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}
fi
ln -s libtdm-sprd.so %{_libdir}/tdm/libtdm-default.so
+if [ -f %{_hal_libdir}/libhal-backend-tdm.so ]; then
+ rm -rf %{_hal_libdir}/libhal-backend-tdm.so
+fi
+ln -s libhal-backend-tdm-sprd.so %{_hal_libdir}/libhal-backend-tdm.so
+
%postun -p /sbin/ldconfig
%files
%manifest %{name}.manifest
%license COPYING
%{_libdir}/tdm/libtdm-sprd.so
+
+%files -n hal-backend-tdm-sprd
+%manifest libhal-backend-tdm-sprd.manifest
+%license COPYING
+%{_hal_libdir}/libhal-backend-*.so*
-SUBDIRS = libtdm-sprd
+SUBDIRS = libtdm-sprd libhal-backend-tdm-sprd
--- /dev/null
+AM_CFLAGS = \
+ $(LIBHAL_BACKEND_TDM_SPRD_CFLAGS) \
+ -I$(top_srcdir)/src/libhal-backend-tdm-sprd
+
+libhal_backend_tdm_sprd_la_LTLIBRARIES = libhal-backend-tdm-sprd.la
+libhal_backend_tdm_sprd_ladir = @HAL_LIBDIR@
+libhal_backend_tdm_sprd_la_LDFLAGS = -module -avoid-version
+libhal_backend_tdm_sprd_la_LIBADD = $(LIBHAL_BACKEND_TDM_SPRD_LIBS) -ldl
+
+libhal_backend_tdm_sprd_la_SOURCES = \
+ tdm_backend_log.c \
+ tdm_backend_sprd.c \
+ tdm_sprd_capture.c \
+ tdm_sprd_display.c \
+ tdm_sprd_format.c \
+ tdm_sprd_hwc_window.c \
+ tdm_sprd_hwc.c \
+ tdm_sprd_pp.c
--- /dev/null
+/* sprd_drm.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Authors:
+ * Inki Dae <inki.dae@samsung.com>
+ * Joonyoung Shim <jy0922.shim@samsung.com>
+ * Seung-Woo Kim <sw0312.kim@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_SPRD_DRM_H_
+#define _UAPI_SPRD_DRM_H_
+
+#include <drm.h>
+
+#define SPRD_DRM_GEM_MAX_INDEX 3
+#define PP_RATIO(src, dst) ((65536*src)/dst)
+#define PP_UP_MAX_RATIO PP_RATIO(1, 4)
+#define PP_DOWN_MIN_RATIO PP_RATIO(4, 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)
+struct sprd_drm_gem_index {
+ unsigned int bufcount;
+ uint64_t idx_size[SPRD_DRM_GEM_MAX_INDEX];
+ unsigned int flags;
+ unsigned int handle;
+};
+
+/**
+ * User-desired buffer creation information structure.
+ *
+ * @size: user-desired memory allocation size.
+ * - this size value would be page-aligned internally.
+ * @flags: user request for setting memory type or cache attributes.
+ * @handle: returned a handle to created gem object.
+ * - this handle will be set by gem module of kernel side.
+ */
+struct drm_sprd_gem_create {
+ uint64_t size;
+ unsigned int flags;
+ unsigned int handle;
+};
+
+/**
+ * A structure for getting buffer offset.
+ *
+ * @handle: a pointer to gem object created.
+ * @pad: just padding to be 64-bit aligned.
+ * @offset: relatived offset value of the memory region allocated.
+ * - this value should be set by user.
+ */
+struct drm_sprd_gem_map_off {
+ unsigned int handle;
+ unsigned int pad;
+ uint64_t offset;
+};
+
+/**
+ * A structure for mapping buffer.
+ *
+ * @handle: a handle to gem object created.
+ * @pad: just padding to be 64-bit aligned.
+ * @size: memory size to be mapped.
+ * @mapped: having user virtual address mmaped.
+ * - this variable would be filled by sprd gem module
+ * of kernel side with user virtual address which is allocated
+ * by do_mmap().
+ */
+struct drm_sprd_gem_mmap {
+ unsigned int handle;
+ unsigned int pad;
+ uint64_t size;
+ uint64_t mapped;
+};
+
+/**
+ * A structure to gem information.
+ *
+ * @handle: a handle to gem object created.
+ * @flags: flag value including memory type and cache attribute and
+ * this value would be set by driver.
+ * @size: size to memory region allocated by gem and this size would
+ * be set by driver.
+ */
+struct drm_sprd_gem_info {
+ unsigned int handle;
+ unsigned int flags;
+ uint64_t size;
+};
+
+struct drm_sprd_gem_lock_handle {
+ uint32_t handle;
+ uint32_t pid;
+};
+
+struct drm_sprd_gem_unlock_handle {
+ uint32_t handle;
+};
+
+/* indicate cache units. */
+enum e_drm_sprd_gem_cache_sel {
+ SPRD_DRM_L1_CACHE = 1,
+ SPRD_DRM_L2_CACHE = 2,
+ SPRD_DRM_ALL_CACHE = 3
+};
+
+/* indicate cache operation types. */
+enum e_drm_sprd_gem_cache_op {
+ SPRD_DRM_CACHE_INV = 4,
+ SPRD_DRM_CACHE_CLN = 8,
+ SPRD_DRM_CACHE_FSH = 0xC
+};
+
+/**
+ * A structure for cache operation.
+ *
+ * @usr_addr: user space address.
+ * P.S. it SHOULD BE user space.
+ * @size: buffer size for cache operation.
+ * @flags: select cache unit and cache operation.
+ * @gem_handle: a handle to a gem object.
+ * this gem handle is needed for cache range operation to L2 cache.
+ */
+struct drm_sprd_gem_cache_op {
+ uint64_t usr_addr;
+ unsigned int size;
+ unsigned int flags;
+ unsigned int gem_handle;
+};
+
+/* memory type definitions. */
+enum e_drm_sprd_gem_mem_type {
+ /* Physically Continuous memory and used as default. */
+ SPRD_BO_CONTIG = 0 << 0,
+ /* Physically Non-Continuous memory. */
+ SPRD_BO_NONCONTIG = 1 << 0,
+ /* non-cachable mapping and used as default. */
+ SPRD_BO_NONCACHABLE = 0 << 1,
+ /* cachable mapping. */
+ SPRD_BO_CACHABLE = 1 << 1,
+ /* write-combine mapping. */
+ SPRD_BO_WC = 1 << 2,
+ SPRD_BO_MASK = SPRD_BO_NONCONTIG | SPRD_BO_CACHABLE |
+ SPRD_BO_WC,
+
+ /* System type */
+ SPRD_BO_DEV_SYSTEM = 1 << 16,
+ /* Multimedia type */
+ SPRD_BO_DEV_MM = 1 << 17,
+ /* Overlay type */
+ SPRD_BO_DEV_OVERLAY = 1 << 18,
+ /* GSP type */
+ SPRD_BO_DEV_GSP = 1 << 19,
+ SPRD_BO_DEV_MASK = SPRD_BO_DEV_SYSTEM | SPRD_BO_DEV_MM |
+ SPRD_BO_DEV_OVERLAY | SPRD_BO_DEV_GSP,
+};
+
+enum drm_sprd_ops_id {
+ SPRD_DRM_OPS_SRC,
+ SPRD_DRM_OPS_DST,
+ SPRD_DRM_OPS_MAX,
+};
+
+struct drm_sprd_sz {
+ __u32 hsize;
+ __u32 vsize;
+};
+
+struct drm_sprd_pos {
+ __u32 x;
+ __u32 y;
+ __u32 w;
+ __u32 h;
+};
+enum drm_sprd_flip {
+ SPRD_DRM_FLIP_NONE = (0 << 0),
+ SPRD_DRM_FLIP_VERTICAL = (1 << 0),
+ SPRD_DRM_FLIP_HORIZONTAL = (1 << 1),
+ SPRD_DRM_FLIP_BOTH = SPRD_DRM_FLIP_VERTICAL |
+ SPRD_DRM_FLIP_HORIZONTAL,
+};
+
+enum drm_sprd_degree {
+ SPRD_DRM_DEGREE_0,
+ SPRD_DRM_DEGREE_90,
+ SPRD_DRM_DEGREE_180,
+ SPRD_DRM_DEGREE_270,
+};
+
+enum drm_sprd_planer {
+ SPRD_DRM_PLANAR_Y,
+ SPRD_DRM_PLANAR_CB,
+ SPRD_DRM_PLANAR_CR,
+ SPRD_DRM_PLANAR_MAX,
+};
+
+/**
+ * A structure for ipp supported property list.
+ *
+ * @version: version of this structure.
+ * @ipp_id: id of ipp driver.
+ * @count: count of ipp 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 drm_sprd_ipp_prop_list {
+ __u32 version;
+ __u32 ipp_id;
+ __u32 count;
+ __u32 writeback;
+ __u32 flip;
+ __u32 degree;
+ __u32 csc;
+ __u32 crop;
+ __u32 scale;
+ __u32 refresh_min;
+ __u32 refresh_max;
+ __u32 reserved;
+ struct drm_sprd_sz crop_min;
+ struct drm_sprd_sz crop_max;
+ struct drm_sprd_sz scale_min;
+ struct drm_sprd_sz scale_max;
+};
+
+/**
+ * A structure for ipp 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 drm_sprd_ipp_config {
+ enum drm_sprd_ops_id ops_id;
+ enum drm_sprd_flip flip;
+ enum drm_sprd_degree degree;
+ __u32 fmt;
+ struct drm_sprd_sz sz;
+ struct drm_sprd_pos pos;
+};
+
+enum drm_sprd_ipp_cmd {
+ IPP_CMD_NONE,
+ IPP_CMD_M2M,
+ IPP_CMD_WB,
+ IPP_CMD_OUTPUT,
+ IPP_CMD_MAX,
+};
+
+/* define of ipp operation type */
+enum drm_sprd_ipp_type {
+ IPP_SYNC_WORK = 0x0,
+ IPP_EVENT_DRIVEN = 0x1,
+ IPP_TYPE_MAX = 0x2,
+};
+
+/**
+ * A structure for ipp property.
+ *
+ * @config: source, destination config.
+ * @cmd: definition of command.
+ * @ipp_id: id of ipp driver.
+ * @prop_id: id of property.
+ * @refresh_rate: refresh rate.
+ * @type: definition of operation type.
+ */
+struct drm_sprd_ipp_property {
+ struct drm_sprd_ipp_config config[SPRD_DRM_OPS_MAX];
+ enum drm_sprd_ipp_cmd cmd;
+ __u32 ipp_id;
+ __u32 prop_id;
+ __u32 refresh_rate;
+ enum drm_sprd_ipp_type type;
+};
+
+enum drm_sprd_ipp_buf_type {
+ IPP_BUF_ENQUEUE,
+ IPP_BUF_DEQUEUE,
+};
+
+/**
+ * A structure for ipp 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 drm_sprd_ipp_queue_buf {
+ enum drm_sprd_ops_id ops_id;
+ enum drm_sprd_ipp_buf_type buf_type;
+ __u32 prop_id;
+ __u32 buf_id;
+ __u32 handle[SPRD_DRM_PLANAR_MAX];
+ __u32 reserved;
+ __u64 user_data;
+};
+
+enum drm_sprd_ipp_ctrl {
+ IPP_CTRL_PLAY,
+ IPP_CTRL_STOP,
+ IPP_CTRL_PAUSE,
+ IPP_CTRL_RESUME,
+ IPP_CTRL_MAX,
+};
+
+/**
+ * A structure for ipp start/stop operations.
+ *
+ * @prop_id: id of property.
+ * @ctrl: definition of control.
+ */
+struct drm_sprd_ipp_cmd_ctrl {
+ __u32 prop_id;
+ enum drm_sprd_ipp_ctrl ctrl;
+};
+
+#define DRM_SPRD_GEM_CREATE 0x00
+#define DRM_SPRD_GEM_MAP_OFFSET 0x01
+#define DRM_SPRD_GEM_MMAP 0x02
+/* Reserved 0x03 ~ 0x05 for sprd specific gem ioctl */
+#define DRM_SPRD_GEM_USERPTR 0x03
+#define DRM_SPRD_GEM_GET 0x04
+#define DRM_SPRD_GEM_MMAP_IOMMU 0x08
+#define DRM_SPRD_GEM_UNMAP_IOMMU 0x09
+#define DRM_SPRD_GEM_LOCK_HANDLE 0x0B
+#define DRM_SPRD_GEM_UNLOCK_HANDLE 0x0C
+#define DRM_SPRD_GEM_CACHE_OP 0x12
+#define DRM_SPRD_GEM_INDEX_CREATE 0x13
+
+/* IPP - Image Post Processing */
+#define DRM_SPRD_IPP_GET_PROPERTY 0x30
+#define DRM_SPRD_IPP_SET_PROPERTY 0x31
+#define DRM_SPRD_IPP_QUEUE_BUF 0x32
+#define DRM_SPRD_IPP_CMD_CTRL 0x33
+
+#define DRM_IOCTL_SPRD_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_GEM_CREATE, struct drm_sprd_gem_create)
+#define DRM_IOCTL_SPRD_GEM_MAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_GEM_MAP_OFFSET, struct drm_sprd_gem_map_off)
+#define DRM_IOCTL_SPRD_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_GEM_MMAP, struct drm_sprd_gem_mmap)
+#define DRM_IOCTL_SPRD_GEM_MMAP_IOMMU DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_GEM_MMAP_IOMMU, struct drm_sprd_gem_mmap)
+#define DRM_IOCTL_SPRD_GEM_UNMAP_IOMMU DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_GEM_UNMAP_IOMMU, struct drm_sprd_gem_mmap)
+#define DRM_IOCTL_SPRD_GEM_GET DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_GEM_GET, struct drm_sprd_gem_info)
+#define DRM_IOCTL_SPRD_GEM_LOCK_HANDLE DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_GEM_LOCK_HANDLE, struct drm_sprd_gem_lock_handle)
+#define DRM_IOCTL_SPRD_GEM_UNLOCK_HANDLE DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_GEM_UNLOCK_HANDLE, struct drm_sprd_gem_unlock_handle)
+#define DRM_IOCTL_SPRD_GEM_CACHE_OP DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_GEM_CACHE_OP, struct drm_sprd_gem_cache_op)
+#define DRM_IOCTL_SPRD_GEM_INDEX_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_GEM_INDEX_CREATE, struct sprd_drm_gem_index)
+
+#define DRM_IOCTL_SPRD_IPP_GET_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_IPP_GET_PROPERTY, struct drm_sprd_ipp_prop_list)
+#define DRM_IOCTL_SPRD_IPP_SET_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_IPP_SET_PROPERTY, struct drm_sprd_ipp_property)
+#define DRM_IOCTL_SPRD_IPP_QUEUE_BUF DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_IPP_QUEUE_BUF, struct drm_sprd_ipp_queue_buf)
+#define DRM_IOCTL_SPRD_IPP_CMD_CTRL DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_SPRD_IPP_CMD_CTRL, struct drm_sprd_ipp_cmd_ctrl)
+
+/* SPRD specific events */
+#define DRM_SPRD_IPP_EVENT 0x80000001
+
+struct drm_sprd_ipp_event {
+ struct drm_event base;
+ __u64 user_data;
+ __u32 tv_sec;
+ __u32 tv_usec;
+ __u32 prop_id;
+ __u32 reserved;
+ __u32 buf_id[SPRD_DRM_OPS_MAX];
+};
+
+enum drm_crtc_id {
+ DRM_CRTC_PRIMARY,
+ DRM_CRTC_FAKE,
+ DRM_CRTC_ID_MAX,
+};
+
+/* definition of DRM_DPMS_IOCTL */
+#define DRM_DPMS_CONTROL 0x50
+
+#define DRM_IOCTL_DPMS_CONTROL DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_DPMS_CONTROL, struct drm_control_dpms)
+
+#define DRM_DPMS_EVENT 0x80000002
+
+enum drm_dpms_type {
+ DPMS_SYNC_WORK = 0x0,
+ DPMS_EVENT_DRIVEN = 0x1,
+};
+
+struct drm_control_dpms {
+ enum drm_crtc_id crtc_id;
+ __u32 dpms;
+ __u32 user_data;
+ enum drm_dpms_type type;
+};
+
+struct drm_control_dpms_event {
+ struct drm_event base;
+ enum drm_crtc_id crtc_id;
+ __u32 dpms;
+ __u32 user_data;
+};
+
+#endif /* _UAPI_SPRD_DRM_H_ */
--- /dev/null
+/*
+ *
+ * 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_*/
--- /dev/null
+#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
--- /dev/null
+/**************************************************************************
+
+libtbm_sprd
+
+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
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_sprd.h"
+
+#if HAVE_UDEV
+#include <libudev.h>
+#endif
+
+#define SPRD_DRM_NAME "sprd"
+
+#define SET_DRM_IRQ
+
+#ifdef HAVE_UDEV
+static struct udev_device *
+_tdm_find_primary_gpu(void)
+{
+ struct udev *udev;
+ struct udev_enumerate *e;
+ struct udev_list_entry *entry;
+ const char *path, *id;
+ struct udev_device *device, *drm_device, *pci;
+
+ udev = udev_new();
+ if (!udev) {
+ TDM_BACKEND_ERR("fail to initialize udev context\n");
+ return NULL;
+ }
+
+ 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)) {
+ path = udev_list_entry_get_name(entry);
+ device = udev_device_new_from_syspath(udev, path);
+ if (!device)
+ continue;
+
+ pci = udev_device_get_parent_with_subsystem_devtype(device, "pci", NULL);
+ if (pci) {
+ id = udev_device_get_sysattr_value(pci, "boot_vga");
+ if (id && !strcmp(id, "1")) {
+ if (drm_device)
+ udev_device_unref(drm_device);
+ drm_device = device;
+ break;
+ }
+ }
+
+ if (!drm_device)
+ drm_device = device;
+ else
+ udev_device_unref(device);
+ }
+
+ udev_enumerate_unref(e);
+
+ return drm_device;
+}
+#endif
+
+static int
+_tdm_sprd_open_drm(void)
+{
+ int fd = -1;
+
+ fd = drmOpen(SPRD_DRM_NAME, NULL);
+ if (fd < 0)
+ TDM_BACKEND_ERR("Cannot open '%s' drm", SPRD_DRM_NAME);
+
+#ifdef HAVE_UDEV
+ if (fd < 0) {
+ struct udev_device *drm_device = NULL;
+ const char *filename;
+ TDM_BACKEND_WRN("Cannot open drm device.. search by udev");
+
+ drm_device = _tdm_find_primary_gpu();
+ if (drm_device == NULL) {
+ TDM_BACKEND_ERR("fail to find drm device\n");
+ 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);
+
+ TDM_BACKEND_DBG("open drm device (name:%s, fd:%d)", filename, fd);
+
+ udev_device_unref(drm_device);
+ }
+close_l:
+#endif
+
+#ifdef SET_DRM_IRQ
+ drmCtlInstHandler(fd, 78);
+#endif
+
+ return fd;
+}
+
+static void
+_tdm_sprd_display_deinitialize(tdm_sprd_display *display_data)
+{
+ tdm_sprd_display_destroy_output_list(display_data);
+ tdm_sprd_display_destroy_buffer_list(display_data);
+
+ tdm_sprd_display_deinit_event_handling(display_data);
+}
+
+static hal_tdm_error
+_tdm_sprd_display_initialize(tdm_sprd_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");
+#endif
+
+ ret = tdm_sprd_display_create_output_list(display_data);
+ if (ret != HAL_TDM_ERROR_NONE)
+ goto failed;
+
+ ret = tdm_sprd_display_init_event_handling(display_data);
+ if (ret != HAL_TDM_ERROR_NONE)
+ goto failed;
+
+ return ret;
+
+failed:
+ _tdm_sprd_display_deinitialize(display_data);
+
+ return ret;
+}
+
+static hal_tdm_error
+_tdm_sprd_master_drm_fd_handler(hal_tdm_fd master_drm_fd, void *user_data)
+{
+ tdm_sprd_display *display_data = (tdm_sprd_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_sprd_display_initialize(display_data);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("fail to _tdm_sprd_display_initialize!\n");
+ _tdm_sprd_display_deinitialize(display_data);
+
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+int
+hal_backend_tdm_sprd_exit(void *data)
+{
+ hal_tdm_backend_data *backend_data = (hal_tdm_backend_data *)data;
+ tdm_sprd_display *display_data;
+
+ TDM_BACKEND_INFO("deinit");
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(backend_data != NULL, -1);
+
+ display_data = (tdm_sprd_display *)backend_data->display;
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data != NULL, -1);
+
+ if (backend_data->capture_funcs) {
+ free(backend_data->capture_funcs);
+ backend_data->capture_funcs = NULL;
+ }
+ if (backend_data->pp_funcs) {
+ free(backend_data->pp_funcs);
+ backend_data->pp_funcs = NULL;
+ }
+ 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_sprd_display_deinitialize(display_data);
+
+ if (display_data->drm_fd >= 0)
+ close(display_data->drm_fd);
+
+ free(display_data);
+ free(backend_data);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+static int
+hal_backend_tdm_sprd_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_sprd_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_sprd_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_sprd_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_sprd_display_initialize(display_data);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("fail to _tdm_sprd_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_sprd_master_drm_fd_handler;
+ backend_data->drm_info.user_data = display_data;
+
+ TDM_BACKEND_INFO("A backend requests an master drm_fd.\n");
+ }
+
+ /* 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 = sprd_display_get_capability;
+ display_funcs->display_get_pp_capability = sprd_display_get_pp_capability;
+ display_funcs->display_get_outputs = sprd_display_get_outputs;
+ display_funcs->display_get_fd = sprd_display_get_fd;
+ display_funcs->display_handle_events = sprd_display_handle_events;
+ display_funcs->display_create_pp = sprd_display_create_pp;
+ display_funcs->display_get_capture_capability = sprd_display_get_capture_capability;
+
+ /* 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 = sprd_output_get_capability;
+ output_funcs->output_set_property = sprd_output_set_property;
+ output_funcs->output_get_property = sprd_output_get_property;
+ output_funcs->output_wait_vblank = sprd_output_wait_vblank;
+ output_funcs->output_set_vblank_handler = sprd_output_set_vblank_handler;
+ output_funcs->output_commit = sprd_output_commit;
+ output_funcs->output_set_commit_handler = sprd_output_set_commit_handler;
+ output_funcs->output_set_dpms = sprd_output_set_dpms;
+ output_funcs->output_get_dpms = sprd_output_get_dpms;
+ output_funcs->output_set_mode = sprd_output_set_mode;
+ output_funcs->output_get_mode = sprd_output_get_mode;
+ output_funcs->output_create_capture = sprd_output_create_capture;
+ output_funcs->output_get_hwc = sprd_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 = sprd_hwc_create_window;
+ hwc_funcs->hwc_get_video_supported_formats = sprd_hwc_get_video_supported_formats;
+ hwc_funcs->hwc_get_capabilities = sprd_hwc_get_capabilities;
+ hwc_funcs->hwc_get_available_properties = sprd_hwc_get_available_properties;
+ hwc_funcs->hwc_get_client_target_buffer_queue = sprd_hwc_get_client_target_buffer_queue;
+ hwc_funcs->hwc_set_client_target_buffer = sprd_hwc_set_client_target_buffer;
+ hwc_funcs->hwc_validate = sprd_hwc_validate;
+ hwc_funcs->hwc_get_changed_composition_types = sprd_hwc_get_changed_composition_types;
+ hwc_funcs->hwc_accept_validation = sprd_hwc_accept_validation;
+ hwc_funcs->hwc_commit = sprd_hwc_commit;
+ hwc_funcs->hwc_set_commit_handler = sprd_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 = sprd_hwc_window_destroy;
+ hwc_window_funcs->hwc_window_acquire_buffer_queue = sprd_hwc_window_acquire_buffer_queue;
+ hwc_window_funcs->hwc_window_release_buffer_queue = sprd_hwc_window_release_buffer_queue;
+ hwc_window_funcs->hwc_window_set_composition_type = sprd_hwc_window_set_composition_type;
+ hwc_window_funcs->hwc_window_set_buffer_damage = sprd_hwc_window_set_buffer_damage;
+ hwc_window_funcs->hwc_window_set_info = sprd_hwc_window_set_info;
+ hwc_window_funcs->hwc_window_set_buffer = sprd_hwc_window_set_buffer;
+ hwc_window_funcs->hwc_window_set_property = sprd_hwc_window_set_property;
+ hwc_window_funcs->hwc_window_get_property = sprd_hwc_window_get_property;
+ hwc_window_funcs->hwc_window_get_constraints = sprd_hwc_window_get_constraints;
+ hwc_window_funcs->hwc_window_set_name = sprd_hwc_window_set_name;
+
+ /* 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;
+
+ pp_funcs->pp_destroy = sprd_pp_destroy;
+ pp_funcs->pp_set_info = sprd_pp_set_info;
+ pp_funcs->pp_attach = sprd_pp_attach;
+ pp_funcs->pp_commit = sprd_pp_commit;
+ pp_funcs->pp_set_done_handler = sprd_pp_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_attach = sprd_capture_attach;
+ capture_funcs->capture_commit = sprd_capture_commit;
+ capture_funcs->capture_destroy = sprd_capture_destroy;
+ capture_funcs->capture_set_done_handler = sprd_capture_set_done_handler;
+ capture_funcs->capture_set_info = sprd_capture_set_info;
+
+ TDM_BACKEND_INFO("init success!");
+
+ return HAL_TDM_ERROR_NONE;
+
+failed:
+ TDM_BACKEND_ERR("init failed!");
+
+ hal_backend_tdm_sprd_exit((void *)backend_data);
+
+ return -1;
+}
+
+hal_backend hal_backend_tdm_data = {
+ "sprd",
+ "Samsung",
+ HAL_ABI_VERSION_TIZEN_6_5,
+ hal_backend_tdm_sprd_init,
+ hal_backend_tdm_sprd_exit
+};
+
--- /dev/null
+#ifndef _TDM_SPRD_H_
+#define _TDM_SPRD_H_
+
+#include "tdm_backend_sprd_types.h"
+
+/* display funcs */
+hal_tdm_error sprd_display_get_capability(hal_tdm_display *display, hal_tdm_caps_display *caps);
+hal_tdm_output **sprd_display_get_outputs(hal_tdm_display *display, int *count, hal_tdm_error *error);
+hal_tdm_error sprd_display_get_fd(hal_tdm_display *display, int *fd);
+hal_tdm_error sprd_display_handle_events(hal_tdm_display *display);
+hal_tdm_error sprd_display_get_pp_capability(hal_tdm_display *display, hal_tdm_caps_pp *caps);
+hal_tdm_error sprd_display_get_capture_capability (hal_tdm_display *display, hal_tdm_caps_capture *caps);
+
+/* output funcs */
+hal_tdm_error sprd_output_get_capability(hal_tdm_output *output, hal_tdm_caps_output *caps);
+hal_tdm_error sprd_output_set_property(hal_tdm_output *output, unsigned int id, hal_tdm_value value);
+hal_tdm_error sprd_output_get_property(hal_tdm_output *output, unsigned int id, hal_tdm_value *value);
+hal_tdm_error sprd_output_wait_vblank(hal_tdm_output *output, int interval, int sync, void *user_data);
+hal_tdm_error sprd_output_set_vblank_handler(hal_tdm_output *output, hal_tdm_output_vblank_handler func);
+hal_tdm_error sprd_output_commit(hal_tdm_output *output, int sync, void *user_data);
+hal_tdm_error sprd_output_set_commit_handler(hal_tdm_output *output, hal_tdm_output_commit_handler func);
+hal_tdm_error sprd_output_set_dpms(hal_tdm_output *output, hal_tdm_output_dpms dpms_value);
+hal_tdm_error sprd_output_get_dpms(hal_tdm_output *output, hal_tdm_output_dpms *dpms_value);
+hal_tdm_error sprd_output_set_mode(hal_tdm_output *output, const hal_tdm_output_mode *mode);
+hal_tdm_error sprd_output_get_mode(hal_tdm_output *output, const hal_tdm_output_mode **mode);
+hal_tdm_hwc *sprd_output_get_hwc(hal_tdm_output *output, hal_tdm_error *error);
+hal_tdm_pp *sprd_display_create_pp(hal_tdm_display *display, hal_tdm_error *error);
+hal_tdm_capture *sprd_output_create_capture (hal_tdm_output *output, hal_tdm_error *error);
+
+/* hwc funcs */
+hal_tdm_hwc_window *sprd_hwc_create_window(hal_tdm_hwc *hwc, hal_tdm_error *error);
+hal_tdm_error sprd_hwc_get_video_supported_formats(hal_tdm_hwc *hwc, const tbm_format **formats, int *count);
+hal_tdm_error sprd_hwc_get_capabilities(hal_tdm_hwc *hwc, hal_tdm_hwc_capability *capabilities);
+hal_tdm_error sprd_hwc_get_available_properties(hal_tdm_hwc *hwc, const hal_tdm_prop **props, int *count);
+tbm_surface_queue_h sprd_hwc_get_client_target_buffer_queue(hal_tdm_hwc *hwc, hal_tdm_error *error);
+hal_tdm_error sprd_hwc_set_client_target_buffer(hal_tdm_hwc *hwc, tbm_surface_h buffer, hal_tdm_region damage);
+hal_tdm_error sprd_hwc_validate(hal_tdm_hwc *hwc, hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types);
+hal_tdm_error sprd_hwc_get_changed_composition_types(hal_tdm_hwc *hwc, uint32_t *num_elements, hal_tdm_hwc_window **hwc_window, hal_tdm_hwc_window_composition *composition_types);
+hal_tdm_error sprd_hwc_accept_validation(hal_tdm_hwc *hwc);
+hal_tdm_error sprd_hwc_commit(hal_tdm_hwc *hwc, int sync, void *user_data);
+hal_tdm_error sprd_hwc_set_commit_handler(hal_tdm_hwc *hwc, hal_tdm_hwc_commit_handler func);
+
+/* hwc_window funcs */
+void sprd_hwc_window_destroy(hal_tdm_hwc_window *hwc_window);
+hal_tdm_error sprd_hwc_window_set_composition_type(hal_tdm_hwc_window *hwc_window, hal_tdm_hwc_window_composition composition_type);
+hal_tdm_error sprd_hwc_window_set_buffer_damage(hal_tdm_hwc_window *hwc_window, hal_tdm_region damage);
+hal_tdm_error sprd_hwc_window_set_info(hal_tdm_hwc_window *hwc_window, hal_tdm_hwc_window_info *info);
+hal_tdm_error sprd_hwc_window_set_buffer(hal_tdm_hwc_window *hwc_window, tbm_surface_h surface);
+hal_tdm_error sprd_hwc_window_set_property(hal_tdm_hwc_window *hwc_window, unsigned int id, hal_tdm_value value);
+hal_tdm_error sprd_hwc_window_get_property(hal_tdm_hwc_window *hwc_window, unsigned int id, hal_tdm_value *value);
+tbm_surface_queue_h sprd_hwc_window_acquire_buffer_queue(hal_tdm_hwc_window *hwc_window, hal_tdm_error *error);
+void sprd_hwc_window_release_buffer_queue(hal_tdm_hwc_window *hwc_window, tbm_surface_queue_h queue);
+hal_tdm_error sprd_hwc_window_get_constraints(hal_tdm_hwc_window *hwc_window, int *constraints);
+hal_tdm_error sprd_hwc_window_set_name(hal_tdm_hwc_window *hwc_window, const char *name);
+
+/* pp funcs */
+void sprd_pp_destroy(hal_tdm_pp *pp);
+hal_tdm_error sprd_pp_set_info(hal_tdm_pp *pp, hal_tdm_info_pp *info);
+hal_tdm_error sprd_pp_attach(hal_tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst);
+hal_tdm_error sprd_pp_commit(hal_tdm_pp *pp);
+hal_tdm_error sprd_pp_set_done_handler(hal_tdm_pp *pp, hal_tdm_pp_done_handler func, void *user_data);
+
+/* capture funcs */
+void sprd_capture_destroy(hal_tdm_capture *capture);
+hal_tdm_error sprd_capture_attach(hal_tdm_capture *capture, tbm_surface_h buffer);
+hal_tdm_error sprd_capture_set_info(hal_tdm_capture *capture, hal_tdm_info_capture *info);
+hal_tdm_error sprd_capture_commit(hal_tdm_capture *capture);
+hal_tdm_error sprd_capture_set_done_handler(hal_tdm_capture *capture, hal_tdm_capture_done_handler func, void *user_data);
+
+/* sprd display */
+hal_tdm_error tdm_sprd_display_create_output_list(tdm_sprd_display *display_data);
+void tdm_sprd_display_destroy_output_list(tdm_sprd_display *display_data);
+void tdm_sprd_display_destroy_buffer_list(tdm_sprd_display *display_data);
+hal_tdm_error tdm_sprd_display_create_layer_list(tdm_sprd_display *display_data);
+hal_tdm_error tdm_sprd_display_init_event_handling(tdm_sprd_display *display_data);
+void tdm_sprd_display_deinit_event_handling(tdm_sprd_display *display_data);
+
+/* sprd output */
+tdm_sprd_display *tdm_sprd_output_get_display(hal_tdm_output *output);
+hal_tdm_error tdm_sprd_output_do_commit(tdm_sprd_output *output_data);
+hal_tdm_error tdm_sprd_output_get_cur_msc(int fd, int pipe, uint *msc);
+hal_tdm_error tdm_sprd_output_wait_vblank(int fd, int pipe, uint *target_msc, int sync, void *data);
+tdm_sprd_layer *tdm_sprd_output_get_tdm_sprd_layer(tdm_sprd_output *output_data, int layer_zpos);
+hal_tdm_error tdm_sprd_output_attach_capture(hal_tdm_output *output, hal_tdm_capture *capture);
+void tdm_sprd_output_dettach_capture(hal_tdm_output *output, hal_tdm_capture *capture);
+
+/* sprd hwc */
+hal_tdm_error tdm_sprd_hwc_initailize_target_window(hal_tdm_hwc *hwc_data, int width, int height);
+
+/* sprd layer */
+hal_tdm_error tdm_sprd_layer_get_capability(tdm_sprd_layer *layer_data, tdm_sprd_caps_layer *caps);
+hal_tdm_error tdm_sprd_layer_set_property(tdm_sprd_layer *layer_data, unsigned int id, hal_tdm_value value);
+hal_tdm_error tdm_sprd_layer_get_property(tdm_sprd_layer *layer_data, unsigned int id, hal_tdm_value *value);
+hal_tdm_error tdm_sprd_layer_set_info(tdm_sprd_layer *layer_data, tdm_sprd_layer_info *info);
+hal_tdm_error tdm_sprd_layer_get_info(tdm_sprd_layer *layer_data, tdm_sprd_layer_info *info);
+hal_tdm_error tdm_sprd_layer_set_buffer(tdm_sprd_layer *layer_data, tbm_surface_h buffer);
+hal_tdm_error tdm_sprd_layer_unset_buffer(tdm_sprd_layer *layer_data);
+hal_tdm_error tdm_sprd_layer_get_buffer_flags(tdm_sprd_layer *layer_data, unsigned int *flags);
+hal_tdm_error tdm_sprd_layer_get_buffer(tdm_sprd_layer *layer_data, tbm_surface_h *surface);
+hal_tdm_error tdm_sprd_layer_get_zpos(tdm_sprd_layer *layer_data, int *zpos);
+
+/* sprd pp */
+hal_tdm_error tdm_sprd_pp_get_capability(tdm_sprd_display *display_data, hal_tdm_caps_pp *caps);
+hal_tdm_pp *tdm_sprd_pp_create(tdm_sprd_display *display_data, hal_tdm_error *error);
+void tdm_sprd_pp_handler(struct drm_sprd_ipp_event *hw_ipp_p);
+
+/* sprd buffer */
+tdm_sprd_display_buffer *tdm_sprd_display_buffer_create(tdm_sprd_display *display_data, tbm_surface_h surface, hal_tdm_error *err);
+tdm_sprd_display_buffer *tdm_sprd_display_buffer_find(tdm_sprd_display *display_data, tbm_surface_h buffer);
+
+/* sprd format */
+uint32_t tdm_format_get_drm_format(tbm_format format);
+tbm_format tdm_format_get_tbm_format(uint32_t format);
+
+#endif /* _TDM_SPRD_H_ */
--- /dev/null
+#ifndef _TDM_SPRD_TYPES_H_
+#define _TDM_SPRD_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 <drm.h>
+#include <drm_fourcc.h>
+
+#include <xf86drm.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 <linux/fb.h>
+#include <video/sprdfb.h>
+
+#include "tdm_list.h"
+#include "tdm_backend_log.h"
+#include "sprd_pp_7727.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)
+
+#define LAYER_COUNT_PER_OUTPUT 2
+
+typedef struct _tdm_sprd_display tdm_sprd_display;
+typedef struct _tdm_sprd_output tdm_sprd_output;
+typedef struct _tdm_sprd_layer tdm_sprd_layer;
+typedef struct _tdm_sprd_hwc tdm_sprd_hwc;
+typedef struct _tdm_sprd_hwc_window tdm_sprd_hwc_window;
+typedef struct _tdm_sprd_vblank tdm_sprd_vblank;
+
+typedef enum {
+ TDM_SPRD_LAYER_CAPABILITY_CURSOR = (1 << 0), /**< cursor */
+ TDM_SPRD_LAYER_CAPABILITY_PRIMARY = (1 << 1), /**< primary */
+ TDM_SPRD_LAYER_CAPABILITY_OVERLAY = (1 << 2), /**< overlay */
+ TDM_SPRD_LAYER_CAPABILITY_GRAPHIC = (1 << 4), /**< graphic */
+ TDM_SPRD_LAYER_CAPABILITY_VIDEO = (1 << 5), /**< video */
+ TDM_SPRD_LAYER_CAPABILITY_SCALE = (1 << 8), /**< if a layer_data has scale capability */
+ TDM_SPRD_LAYER_CAPABILITY_TRANSFORM = (1 << 9), /**< if a layer_data has transform capability */
+ TDM_SPRD_LAYER_CAPABILITY_SCANOUT = (1 << 10), /**< if a layer_data allows a scanout buffer only */
+ TDM_SPRD_LAYER_CAPABILITY_RESEVED_MEMORY = (1 << 11), /**< if a layer_data allows a reserved buffer only */
+ TDM_SPRD_LAYER_CAPABILITY_NO_CROP = (1 << 12), /**< if a layer_data has no cropping capability */
+} tdm_sprd_layer_capability;
+
+struct _tdm_sprd_display {
+ drmEventContext evctx;
+
+ int drm_fd;
+ int output_count;
+
+ struct list_head output_list;
+ struct list_head buffer_list;
+
+};
+
+typedef enum {
+ VBLANK_TYPE_WAIT,
+ VBLANK_TYPE_COMMIT,
+} vblank_type_t;
+
+struct _tdm_sprd_vblank {
+ vblank_type_t type;
+ tdm_sprd_output *output_data;
+ void *user_data;
+};
+
+typedef struct _tdm_sprd_display_buffer {
+ struct list_head link;
+
+ unsigned int fb_id;
+ tbm_surface_h buffer;
+ int width;
+ unsigned int height;
+ unsigned int format;
+ unsigned int name[4];
+ unsigned int pitches[4];
+ unsigned int offsets[4];
+ unsigned int size;
+ unsigned int count;
+} tdm_sprd_display_buffer;
+
+typedef struct _tdm_sprd_capture {
+ hal_tdm_capture * tdm_capture_p;
+ struct list_head link;
+} tdm_sprd_capture;
+
+struct _tdm_sprd_output {
+ struct list_head link;
+
+ /* data which are fixed at initializing */
+ tdm_sprd_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;
+
+ hal_tdm_output_vblank_handler vblank_func;
+ hal_tdm_output_commit_handler commit_func;
+ hal_tdm_output_conn_status status;
+
+ 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;
+
+ hal_tdm_output_dpms dpms_value;
+
+ struct list_head capture_list;
+
+ /* hwc data */
+ tdm_sprd_hwc *hwc_data;
+};
+
+typedef struct _tdm_sprd_layer_info {
+ hal_tdm_info_config src_config;
+ hal_tdm_pos dst_pos;
+ hal_tdm_transform transform;
+} tdm_sprd_layer_info;
+
+typedef struct _tdm_sprd_caps_layer {
+ tdm_sprd_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_sprd_caps_layer;
+
+struct _tdm_sprd_layer {
+ struct list_head link;
+
+ /* data which are fixed at initializing */
+ tdm_sprd_display *display_data;
+ tdm_sprd_output *output_data;
+ tdm_sprd_layer_capability capabilities;
+ int zpos;
+
+ //list of sprd formats
+ int format_count;
+ tbm_format *formats;
+
+ /* not fixed data below */
+ tdm_sprd_layer_info info;
+ int info_changed;
+
+ tdm_sprd_display_buffer *display_buffer;
+ int display_buffer_changed;
+ /* current hw overlay setting */
+ overlay_info ovi;
+ int enabled_flag;
+
+ int need_unset;
+};
+
+struct _tdm_sprd_hwc {
+ tdm_sprd_hwc_window *target_hwc_window;
+ int target_window_zpos;
+
+ int need_target_window;
+
+ tdm_sprd_output *output_data;
+ struct list_head hwc_window_list;
+
+ hal_tdm_hwc_commit_handler commit_func;
+};
+
+struct _tdm_sprd_hwc_window {
+ struct list_head link;
+
+ tdm_sprd_hwc *hwc_data;
+
+ hal_tdm_hwc_window_info info; /* latest window information */
+ tbm_surface_h surface; /* latest buffer to be set */
+ hal_tdm_hwc_window_composition client_type; /* composition type set by client(compositor) */
+
+ hal_tdm_hwc_window_composition validated_type; /* composition type after validation */
+ int lzpos; /* layer's zpos to be assigned after validation */
+
+ int constraints;
+ tbm_surface_queue_h tqueue;
+
+ char name[HAL_TDM_NAME_LEN];
+};
+
+#endif /* _TDM_SPRD_TYPES_H_ */
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_sprd.h"
+
+#define NUM_LAYERS 2
+
+typedef struct _tdm_sprd_capture_buffer {
+ tbm_surface_h buffer;
+ struct list_head link;
+} tdm_sprd_capture_buffer;
+
+typedef struct _tdm_sprd_capture_pp_data {
+ hal_tdm_pp * pp_link;
+ tbm_surface_h src_buffer;
+ tbm_surface_h dst_buffer;
+ struct list_head link;
+} tdm_sprd_capture_pp_data;
+
+typedef struct _tdm_sprd_capture_composite_data {
+ tbm_surface_h temp_layer_buffer[LAYER_COUNT_PER_OUTPUT];
+ hal_tdm_pos dst_pos[LAYER_COUNT_PER_OUTPUT];
+ int zpos[LAYER_COUNT_PER_OUTPUT];
+ tbm_surface_h client_buffer;
+ tbm_surface_h temp_composite_buffer;
+ tdm_sprd_capture_pp_data * composite_buf_pp_task;
+ int current_done_buf_num;
+ int need_done_buf_num;
+ struct list_head link;
+} tdm_sprd_capture_composite;
+
+typedef struct _tdm_sprd_capture_data {
+ int stamp;
+ int removing;
+ tdm_sprd_display *display_data;
+
+ hal_tdm_output *output_data;
+
+ hal_tdm_info_capture info;
+ int info_changed;
+ struct list_head pending_buffer_list;
+ struct list_head pp_convert_list;
+ struct list_head composite_list;
+#if 0
+ struct {
+ tdm_event_loop_source *timer_source;
+ } stream;
+#endif
+ hal_tdm_capture_done_handler done_func;
+ void *done_user_data;
+ struct list_head link;
+} tdm_sprd_capture_data;
+
+static tbm_format capture_client_formats[] = {
+ TBM_FORMAT_XRGB8888,
+ TBM_FORMAT_ARGB8888,
+ TBM_FORMAT_NV12,
+ TBM_FORMAT_YUV420
+};
+
+#define NUM_CAPTURE_FORMAT (sizeof(capture_client_formats) / sizeof(capture_client_formats[0]))
+
+static int capture_list_init;
+static struct list_head capture_list;
+static int capture_stamp = 1001;
+
+int _tdm_sprd_capture_check_struct(tdm_sprd_capture_data *capture_data)
+{
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(capture_list_init == 1, 0);
+ if (capture_data == NULL) {
+ TDM_BACKEND_WRN("capture nil(0). Received NULL pointer");
+ return 0;
+ }
+ tdm_sprd_capture_data * capture_next = NULL;
+ LIST_FOR_EACH_ENTRY(capture_next, &capture_list, link) {
+ if (capture_next->stamp == capture_data->stamp)
+ return 1;
+ }
+ TDM_BACKEND_INFO("capture %p(%d). Maybe, receive handler after remove",
+ capture_data, capture_data->stamp);
+ return 0;
+}
+
+static void
+_tdm_sprd_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_sprd_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_sprd_capture_oneshot_center_rect(src_w, src_h, dst_w, dst_h, ¢er);
+
+ ratio = (float)center.w / src_w;
+ scale->x = scale->x * ratio + center.x;
+ scale->y = scale->y * ratio + center.y;
+ scale->w = scale->w * ratio;
+ scale->h = scale->h * ratio;
+}
+
+static void
+_tdm_sprd_capture_destroy_converter(tdm_sprd_capture_pp_data ** pp_task_p)
+{
+ TDM_BACKEND_RETURN_IF_FAIL(pp_task_p);
+ TDM_BACKEND_RETURN_IF_FAIL(*pp_task_p);
+ LIST_DEL(&(*pp_task_p)->link);
+ if ((*pp_task_p)->pp_link)
+ sprd_pp_destroy((*pp_task_p)->pp_link);
+ if ((*pp_task_p)->src_buffer) {
+ tbm_surface_internal_unref((*pp_task_p)->src_buffer);
+ (*pp_task_p)->src_buffer = NULL;
+ }
+ if ((*pp_task_p)->dst_buffer) {
+ tbm_surface_internal_unref((*pp_task_p)->dst_buffer);
+ (*pp_task_p)->dst_buffer = NULL;
+ }
+ free(*pp_task_p);
+ *pp_task_p = NULL;
+}
+
+static pixman_format_code_t
+_tdm_sprd_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_sprd_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_sprd_pixman_format_get(src_info.format);
+ TDM_BACKEND_GOTO_VAL_IF_FAIL(src_format > 0, unmap_dstbuf);
+ dst_format = _tdm_sprd_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 hal_tdm_error
+_tdm_sprd_capture_composite_sw(tdm_sprd_capture_data *capture_data,
+ tdm_sprd_capture_composite * composite_data,
+ tbm_surface_h composite_buf)
+{
+ int i, k;
+ hal_tdm_error tdm_err = HAL_TDM_ERROR_NONE;
+ tbm_surface_h temp_buffer = NULL;
+ int temp_zpos = 0;
+ hal_tdm_pos temp_dpos = {0, 0, 0, 0};
+/* Good old bubble sort */
+ for (k = 0; k < LAYER_COUNT_PER_OUTPUT-1; ++k) {
+ for (i = 0; i < LAYER_COUNT_PER_OUTPUT - 1 - k; ++i) {
+ if (composite_data->zpos[i] > composite_data->zpos[i+1]) {
+ temp_buffer = composite_data->temp_layer_buffer[i];
+ temp_zpos = composite_data->zpos[i];
+ temp_dpos = composite_data->dst_pos[i];
+ composite_data->temp_layer_buffer[i] = composite_data->temp_layer_buffer[i+1];
+ composite_data->zpos[i] = composite_data->zpos[i+1];
+ composite_data->dst_pos[i] = composite_data->dst_pos[i+1];
+ composite_data->dst_pos[i+1] = temp_dpos;
+ composite_data->temp_layer_buffer[i+1] = temp_buffer;
+ composite_data->zpos[i+1] = temp_zpos;
+ }
+ }
+ }
+ for (i = 0; i < LAYER_COUNT_PER_OUTPUT; i++) {
+ if (composite_data->temp_layer_buffer[i]) {
+ hal_tdm_pos src_pos = {.x = 0,
+ .y = 0,
+ .w = tbm_surface_get_width(composite_data->temp_layer_buffer[i]),
+ .h = tbm_surface_get_height(composite_data->temp_layer_buffer[i])};
+ tdm_err = _tdm_sprd_capture_convert_buffer(composite_data->temp_layer_buffer[i],
+ composite_buf, &src_pos,
+ &composite_data->dst_pos[i], 0, 1);
+ if (tdm_err != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_WRN("Capture %p error %d Can't composite buffers src %p dst %p. Skip",
+ capture_data, tdm_err, composite_data->temp_layer_buffer[i], composite_buf);
+ }
+ tbm_surface_internal_unref(composite_data->temp_layer_buffer[i]);
+ composite_data->temp_layer_buffer[i] = NULL;
+ }
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+static void
+_tdm_sprd_capture_pp_done_handler (hal_tdm_pp *pp, tbm_surface_h src,
+ tbm_surface_h dst, void *user_data)
+{
+ if (!_tdm_sprd_capture_check_struct(user_data)) {
+ return;
+ }
+ tdm_sprd_capture_data *capture_data = user_data;
+ if (capture_data->removing) {
+ TDM_BACKEND_INFO("Capture removing. Skip handler");
+ return;
+ }
+ tdm_sprd_capture_composite *composite_data = NULL, *composite_next = NULL;
+ tdm_sprd_capture_pp_data *pp_task = NULL, *pp_tasks_next = NULL;
+ int i;
+ LIST_FOR_EACH_ENTRY_SAFE(pp_task, pp_tasks_next, &capture_data->pp_convert_list, link) {
+ if (pp_task->pp_link == pp) {
+ tbm_surface_internal_unref(pp_task->src_buffer);
+ pp_task->src_buffer = NULL;
+ tbm_surface_internal_unref(pp_task->dst_buffer);
+ pp_task->dst_buffer = NULL;
+ break;
+ }
+ }
+ LIST_FOR_EACH_ENTRY_SAFE(composite_data, composite_next, &capture_data->composite_list, link) {
+ if (composite_data->client_buffer && composite_data->client_buffer == dst) {
+ LIST_DEL(&composite_data->link);
+ tbm_surface_internal_unref(composite_data->client_buffer);
+ tbm_surface_internal_unref(composite_data->temp_composite_buffer);
+ composite_data->temp_composite_buffer = NULL;
+ if (capture_data->done_func) {
+ capture_data->done_func(capture_data,
+ composite_data->client_buffer,
+ capture_data->done_user_data);
+ }
+ free(composite_data);
+ break;
+ }
+ for (i = 0; i < LAYER_COUNT_PER_OUTPUT; i++) {
+ if (composite_data->temp_layer_buffer[i] && composite_data->temp_layer_buffer[i] == dst) {
+ composite_data->current_done_buf_num++;
+ }
+ }
+ if (composite_data->current_done_buf_num == composite_data->need_done_buf_num) {
+ if (!composite_data->temp_composite_buffer) {
+ _tdm_sprd_capture_composite_sw(capture_data, composite_data,
+ composite_data->client_buffer);
+ tbm_surface_internal_unref(composite_data->client_buffer);
+ if (capture_data->done_func) {
+ capture_data->done_func(capture_data,
+ composite_data->client_buffer,
+ capture_data->done_user_data);
+ }
+ LIST_DEL(&composite_data->link);
+ free(composite_data);
+ } else {
+ _tdm_sprd_capture_composite_sw(capture_data, composite_data,
+ composite_data->temp_composite_buffer);
+ sprd_pp_commit(composite_data->composite_buf_pp_task->pp_link);
+ composite_data->current_done_buf_num = 0;
+ }
+ break;
+ }
+ }
+ TDM_BACKEND_DBG("capture pp handler done");
+}
+
+static hal_tdm_error
+_tdm_sprd_capture_make_converter(tdm_sprd_capture_data *capture_data,
+ tbm_surface_h src, tbm_surface_h dst,
+ hal_tdm_pos *src_pos, hal_tdm_pos *dst_pos,
+ hal_tdm_transform transform,
+ tdm_sprd_capture_pp_data ** pp_task_p)
+{
+ hal_tdm_error tdm_err = HAL_TDM_ERROR_NONE;
+ hal_tdm_pp *pp = NULL;
+ hal_tdm_info_pp info_pp;
+ tdm_sprd_capture_pp_data *new_pp_task = NULL, *pp_task = NULL, *pp_tasks_next = NULL;
+ tbm_format src_format, dst_format;
+ unsigned int src_bpp, src_stride, dst_bpp, dst_stride;
+
+ if (pp_task_p == NULL) {
+ return HAL_TDM_ERROR_INVALID_PARAMETER;
+ }
+ LIST_FOR_EACH_ENTRY_SAFE(pp_task, pp_tasks_next, &capture_data->pp_convert_list, link) {
+ if (pp_task->src_buffer == NULL &&
+ pp_task->dst_buffer == NULL) {
+ new_pp_task = pp_task;
+ new_pp_task->dst_buffer = dst;
+ new_pp_task->src_buffer = src;
+ tbm_surface_internal_ref(dst);
+ tbm_surface_internal_ref(src);
+ break;
+ }
+ }
+ if (new_pp_task == NULL) {
+ new_pp_task = calloc(1, sizeof(tdm_sprd_capture_pp_data));
+ if (new_pp_task == NULL) {
+ TDM_BACKEND_WRN("Out of memory");
+ return HAL_TDM_ERROR_OUT_OF_MEMORY;
+ }
+ new_pp_task->dst_buffer = dst;
+ new_pp_task->src_buffer = src;
+ tbm_surface_internal_ref(dst);
+ tbm_surface_internal_ref(src);
+ LIST_ADD(&new_pp_task->link, &capture_data->pp_convert_list);
+ pp = tdm_sprd_pp_create(capture_data->display_data, &tdm_err);
+ if (tdm_err != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_WRN("can't create pp");
+ goto fail;
+ }
+ if ((tdm_err = sprd_pp_set_done_handler(pp, _tdm_sprd_capture_pp_done_handler,
+ capture_data)) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_WRN("can't create done handler");
+ goto fail;
+ }
+ new_pp_task->pp_link = pp;
+ }
+ CLEAR(info_pp);
+ src_format = tbm_surface_get_format(src);
+ src_bpp = tbm_surface_internal_get_bpp(src_format);
+ src_stride = 0;
+ if (!tbm_surface_internal_get_plane_data(src, 0, NULL, NULL, &src_stride)) {
+ TDM_BACKEND_WRN("can't get stride");
+ tdm_err = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto fail;
+ }
+ if (IS_RGB(src_format)) {
+ src_bpp >>= 3;
+ if (src_bpp != 0)
+ src_stride /= src_bpp;
+ }
+ info_pp.src_config.format = tbm_surface_get_format(src);
+ info_pp.src_config.pos.x = (src_pos) ? src_pos->x : 0;
+ info_pp.src_config.pos.y = (src_pos) ? src_pos->y : 0;
+ info_pp.src_config.pos.w = (src_pos) ? src_pos->w : tbm_surface_get_width(src);
+ info_pp.src_config.pos.h = (src_pos) ? src_pos->h : tbm_surface_get_height(src);
+ info_pp.src_config.size.h = src_stride;
+ info_pp.src_config.size.v = tbm_surface_get_height(src);
+
+ dst_format = tbm_surface_get_format(dst);
+ dst_bpp = tbm_surface_internal_get_bpp(dst_format);
+ dst_stride = 0;
+ if (!tbm_surface_internal_get_plane_data(dst, 0, NULL, NULL, &dst_stride)) {
+ TDM_BACKEND_WRN("can't get stride");
+ tdm_err = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto fail;
+ }
+ if (IS_RGB(dst_format)) {
+ dst_bpp >>= 3;
+ if (dst_bpp != 0)
+ dst_stride /= dst_bpp;
+ }
+
+ info_pp.dst_config.format = dst_format;
+ info_pp.dst_config.pos.x = (dst_pos) ? dst_pos->x : 0;
+ info_pp.dst_config.pos.y = (dst_pos) ? dst_pos->y : 0;
+ info_pp.dst_config.pos.w = (dst_pos) ? dst_pos->w : tbm_surface_get_width(dst);
+ info_pp.dst_config.pos.h = (dst_pos) ? dst_pos->h : tbm_surface_get_height(dst);
+ info_pp.dst_config.size.h = dst_stride;
+ info_pp.dst_config.size.v = tbm_surface_get_height(dst);
+ info_pp.transform = transform;
+ if ((tdm_err = sprd_pp_set_info(new_pp_task->pp_link, &info_pp)) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_WRN("can't set pp info");
+ tdm_err = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto fail;
+ }
+ if ((tdm_err = sprd_pp_attach(new_pp_task->pp_link, src, dst)) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_WRN("can't set buffers to pp");
+ tdm_err = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto fail;
+ }
+ *pp_task_p = new_pp_task;
+ return HAL_TDM_ERROR_NONE;
+
+fail:
+ if (pp)
+ sprd_pp_destroy(pp);
+ if (new_pp_task) {
+ LIST_DEL(&new_pp_task->link);
+ if (new_pp_task->dst_buffer)
+ tbm_surface_internal_unref(dst);
+ if (new_pp_task->src_buffer)
+ tbm_surface_internal_unref(src);
+ free(new_pp_task);
+ }
+ return tdm_err;
+}
+
+void _tdm_sprd_capture_oneshot_transform_rect(int dpy_w, int dpy_h, hal_tdm_transform transform, hal_tdm_pos *pos)
+{
+ int temp = 0;
+
+ if (transform == HAL_TDM_TRANSFORM_90) {
+ temp = pos->x;
+ pos->x = dpy_h - pos->y - pos->h;
+ pos->y = temp;
+ temp = pos->w;
+ pos->w = pos->h;
+ pos->h = temp;
+ } else if (transform == HAL_TDM_TRANSFORM_180) {
+ pos->x = dpy_w - pos->x - pos->w;
+ pos->y = dpy_h - pos->y - pos->h;
+ } else if (transform == HAL_TDM_TRANSFORM_270) {
+ temp = pos->y;
+ pos->y = dpy_w - pos->x - pos->w;
+ pos->x = temp;
+ temp = pos->w;
+ pos->w = pos->h;
+ pos->h = temp;
+ } else if (transform == HAL_TDM_TRANSFORM_FLIPPED) {
+ pos->x = dpy_w - pos->x - pos->w;
+ } else if (transform == HAL_TDM_TRANSFORM_FLIPPED_90) {
+ temp = pos->x;
+ pos->x = pos->y;
+ pos->y = temp;
+ temp = pos->w;
+ pos->w = pos->h;
+ pos->h = temp;
+ } else if (transform == HAL_TDM_TRANSFORM_FLIPPED_180) {
+ pos->y = dpy_h - pos->y - pos->h;
+ } else if (transform == HAL_TDM_TRANSFORM_FLIPPED_270) {
+ temp = pos->y;
+ pos->y = dpy_w - pos->x - pos->w;
+ pos->x = dpy_h - temp - pos->h;
+ temp = pos->w;
+ pos->w = pos->h;
+ pos->h = temp;
+ }
+}
+
+static hal_tdm_error
+_tdm_sprd_capture_oneshot_composite_layers_sw(tdm_sprd_capture_data *capture_data,
+ tbm_surface_h buffer)
+{
+ tbm_surface_info_s buf_info;
+ const hal_tdm_output_mode *current_mode = NULL;
+ tbm_surface_h surface = NULL;
+ tdm_sprd_capture_composite *composite_data = NULL;
+ tdm_sprd_capture_pp_data ** pp_tasks = NULL;
+ int int_err, i;
+ hal_tdm_error tdm_err = HAL_TDM_ERROR_NONE;
+
+ if ((sprd_output_get_mode(capture_data->output_data, ¤t_mode)) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("can't get output mode");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+ if (current_mode == NULL) {
+ TDM_BACKEND_WRN("Output mode not init. Can't capture");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ int_err = tbm_surface_get_info(buffer, &buf_info);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(int_err == TBM_SURFACE_ERROR_NONE, HAL_TDM_ERROR_BAD_REQUEST);
+
+ composite_data = calloc(1, sizeof(tdm_sprd_capture_composite));
+ if (composite_data == NULL) {
+ TDM_BACKEND_WRN("Out of memory");
+ tdm_err = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ goto fail;
+ }
+
+ composite_data->client_buffer = buffer;
+ tbm_surface_internal_ref(buffer);
+ LIST_ADD(&composite_data->link, &capture_data->composite_list);
+ pp_tasks = calloc(NUM_LAYERS, sizeof(tdm_sprd_capture_pp_data *));
+ if (pp_tasks == NULL) {
+ TDM_BACKEND_WRN("Out of memory");
+ tdm_err = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ goto fail;
+ }
+ for (i = 0; i < NUM_LAYERS; ++i) {
+ tdm_sprd_output *output_data = NULL;
+ tdm_sprd_layer *layer_data = NULL;
+ tdm_sprd_layer_info layer_info;
+
+ output_data = (tdm_sprd_output *)capture_data->output_data;
+ layer_data = tdm_sprd_output_get_tdm_sprd_layer(output_data, i);
+ if (!layer_data) continue;
+
+ CLEAR(layer_info);
+ if (tdm_sprd_layer_get_info(layer_data, &layer_info) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_WRN("can't get layer %p info. Skip", layer_data);
+ continue;
+ }
+ if (layer_info.src_config.pos.h == 0 || layer_info.src_config.pos.w == 0) {
+ TDM_BACKEND_INFO("layer %p info is NULL. Skip", layer_data);
+ continue;
+ }
+ if (tdm_sprd_layer_get_buffer(layer_data, &surface) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_WRN("can't get layer %p surface. Skip", layer_data);
+ continue;
+ }
+ if (surface == NULL) {
+ TDM_BACKEND_INFO("layer %p buffer is NULL. Skip", layer_data);
+ continue;
+ }
+ tbm_surface_internal_ref(surface);
+ TDM_BACKEND_DBG("Get layer %p surface %p", layer_data, surface);
+ if (1) {
+
+ int output_width = current_mode->hdisplay;
+ int width = layer_info.src_config.pos.w;
+ int pos_x = layer_info.dst_pos.x;
+ hal_tdm_pos scale_pos = {.x = pos_x, .y = layer_info.dst_pos.y,
+ .w = ((width + pos_x) <= output_width ? width : output_width - pos_x),
+ .h = layer_info.src_config.pos.h};
+ hal_tdm_pos src_pos = layer_info.src_config.pos;
+ hal_tdm_pos dst_pos = capture_data->info.dst_config.pos;
+
+ TDM_BACKEND_DBG("src_pos (x)(y)+(w)+(h) (%d)(%d)+(%d)+(%d)", src_pos.x, src_pos.y,
+ src_pos.w, src_pos.h);
+ TDM_BACKEND_DBG("dst_pos (x)(y)+(w)+(h) (%d)(%d)+(%d)+(%d)", dst_pos.x, dst_pos.y,
+ dst_pos.w, dst_pos.h);
+ TDM_BACKEND_DBG("scale_pos (x)(y)+(w)+(h) (%d)(%d)+(%d)+(%d)", scale_pos.x, scale_pos.y,
+ scale_pos.w, scale_pos.h);
+ if (dst_pos.w == 0 || dst_pos.h == 0) {
+ dst_pos.x = 0;
+ dst_pos.y = 0;
+ dst_pos.h = tbm_surface_get_height(buffer);
+ dst_pos.w = tbm_surface_get_width(buffer);
+
+ if (dst_pos.w == 0 || dst_pos.h == 0) {
+ TDM_BACKEND_WRN("dst_pos size is zero");
+ tbm_surface_internal_unref(surface);
+ continue;
+ }
+
+ _tdm_sprd_capture_oneshot_center_rect(current_mode->hdisplay,
+ current_mode->vdisplay,
+ dst_pos.w, dst_pos.h, &dst_pos);
+
+ TDM_BACKEND_DBG("--> new_dst_pos (x)(y)+(w)+(h) (%d)(%d)+(%d)+(%d)", dst_pos.x, dst_pos.y,
+ dst_pos.w, dst_pos.h);
+ }
+
+ _tdm_sprd_capture_oneshot_transform_rect(current_mode->hdisplay,
+ current_mode->vdisplay,
+ capture_data->info.transform,
+ &scale_pos);
+
+ if (capture_data->info.transform & 1) {
+ _tdm_sprd_capture_oneshot_rect_scale(current_mode->vdisplay,
+ current_mode->hdisplay,
+ dst_pos.w, dst_pos.h, &scale_pos);
+ } else {
+ _tdm_sprd_capture_oneshot_rect_scale(current_mode->hdisplay,
+ current_mode->vdisplay,
+ dst_pos.w, dst_pos.h, &scale_pos);
+ }
+
+ TDM_BACKEND_DBG("scale_pos (x)(y)+(w)+(h) (%d)(%d)+(%d)+(%d)", scale_pos.x, scale_pos.y,
+ scale_pos.w, scale_pos.h);
+/*
+ if (capture_data->info.transform & 1) {
+
+ }
+*/
+ tbm_surface_h temp_buffer = tbm_surface_create(dst_pos.w,
+ dst_pos.h,
+ TBM_FORMAT_ARGB8888);
+ if (temp_buffer == NULL) {
+ TDM_BACKEND_WRN("Out of memory");
+ tbm_surface_internal_unref(surface);
+ continue;
+ }
+
+ dst_pos.x += scale_pos.x;
+ dst_pos.y += scale_pos.y;
+ dst_pos.h = scale_pos.h;
+ dst_pos.w = scale_pos.w;
+
+ TDM_BACKEND_DBG("adapted dst_pos (x)(y)+(w)+(h) (%d)(%d)+(%d)+(%d)", dst_pos.x, dst_pos.y,
+ dst_pos.w, dst_pos.h);
+
+ tdm_err = _tdm_sprd_capture_make_converter(capture_data, surface, temp_buffer,
+ &src_pos, NULL, capture_data->info.transform,
+ &pp_tasks[i]);
+ if (tdm_err != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_WRN("can't create converter");
+ tbm_surface_internal_unref(surface);
+ tbm_surface_internal_unref(temp_buffer);
+ continue;
+ }
+
+ int zpos;
+ if (tdm_sprd_layer_get_zpos(layer_data, &zpos) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_WRN("can't get layer %p zpos", layer_data);
+ _tdm_sprd_capture_destroy_converter(&pp_tasks[i]);
+ tbm_surface_internal_unref(surface);
+ tbm_surface_internal_unref(temp_buffer);
+ continue;
+ }
+ composite_data->temp_layer_buffer[i] = temp_buffer;
+ composite_data->dst_pos[i] = dst_pos;
+ composite_data->zpos[i] = zpos;
+ composite_data->need_done_buf_num++;
+ }
+ tbm_surface_internal_unref(surface);
+ }
+
+ if (!composite_data->need_done_buf_num) {
+ TDM_BACKEND_INFO("Layers buffer are empty. Nothing to do");
+ tdm_err = HAL_TDM_ERROR_NONE;
+ goto fail;
+ }
+
+ if (!IS_RGB(tbm_surface_get_format(composite_data->client_buffer))) {
+ tdm_sprd_capture_pp_data * pp_task = NULL;
+ composite_data->temp_composite_buffer = tbm_surface_create(tbm_surface_get_width(buffer),
+ tbm_surface_get_height(buffer),
+ TBM_FORMAT_ARGB8888);
+ if (composite_data->temp_composite_buffer == NULL) {
+ TDM_BACKEND_WRN("Out of memory");
+ tdm_err = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ goto fail;
+ }
+ tdm_err = _tdm_sprd_capture_make_converter(capture_data, composite_data->temp_composite_buffer,
+ composite_data->client_buffer,
+ NULL, NULL, 0, &pp_task);
+ if (tdm_err != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_WRN("can't create converter");
+ goto fail;
+ }
+ composite_data->composite_buf_pp_task = pp_task;
+ }
+ for (i = 0; i < NUM_LAYERS; i++) {
+ if (pp_tasks[i]) {
+ tdm_err = sprd_pp_commit(pp_tasks[i]->pp_link);
+ if (tdm_err != HAL_TDM_ERROR_NONE) {
+ composite_data->need_done_buf_num--;
+ _tdm_sprd_capture_destroy_converter(&pp_tasks[i]);
+ tbm_surface_internal_unref(composite_data->temp_layer_buffer[i]);
+ composite_data->temp_layer_buffer[i] = NULL;
+ }
+ }
+ }
+ if (!composite_data->need_done_buf_num) {
+ TDM_BACKEND_WRN("Can't capture layers");
+ goto fail;
+ }
+ if (pp_tasks) {
+ free(pp_tasks);
+ }
+
+ return HAL_TDM_ERROR_NONE;
+
+fail:
+ if (pp_tasks) {
+ for (i = 0; i < NUM_LAYERS; ++i) {
+ if (pp_tasks[i])
+ _tdm_sprd_capture_destroy_converter(&pp_tasks[i]);
+ }
+ free(pp_tasks);
+ }
+ if (composite_data) {
+ LIST_DEL(&composite_data->link);
+ if (composite_data->composite_buf_pp_task) {
+ _tdm_sprd_capture_destroy_converter(&composite_data->composite_buf_pp_task);
+ }
+ if (composite_data->temp_composite_buffer != NULL) {
+ tbm_surface_internal_unref(composite_data->temp_composite_buffer);
+ }
+ for (i = 0; i < LAYER_COUNT_PER_OUTPUT; i++) {
+ if (composite_data->temp_layer_buffer[i] != NULL) {
+ tbm_surface_internal_unref(composite_data->temp_layer_buffer[i]);
+ }
+ }
+ if (composite_data->client_buffer != NULL) {
+ tbm_surface_internal_unref(composite_data->client_buffer);
+ if (capture_data->done_func) {
+ capture_data->done_func(capture_data,
+ composite_data->client_buffer,
+ capture_data->done_user_data);
+ }
+ composite_data->client_buffer = NULL;
+ }
+ free(composite_data);
+ }
+
+ return tdm_err;
+}
+
+void
+sprd_capture_destroy(hal_tdm_capture *capture)
+{
+ tdm_sprd_capture_data *capture_data = capture;
+ if (!_tdm_sprd_capture_check_struct(capture_data)) {
+ return;
+ }
+ tdm_sprd_capture_buffer *b = NULL, *bb = NULL;
+ tdm_sprd_capture_pp_data *pp_task = NULL, *pp_tasks_next = NULL;
+ tdm_sprd_capture_composite *composite = NULL, *composite_next = NULL;
+ int i;
+ capture_data->removing = 1;
+ TDM_BACKEND_DBG("capture(%p) destroy", capture_data);
+
+ LIST_FOR_EACH_ENTRY_SAFE(pp_task, pp_tasks_next, &capture_data->pp_convert_list, link) {
+ _tdm_sprd_capture_destroy_converter(&pp_task);
+ }
+
+ LIST_FOR_EACH_ENTRY_SAFE(composite, composite_next, &capture_data->composite_list, link) {
+ LIST_DEL(&composite->link);
+ for (i = 0; i < LAYER_COUNT_PER_OUTPUT; i++) {
+ if (composite->temp_layer_buffer[i]) {
+ tbm_surface_internal_unref(composite->temp_layer_buffer[i]);
+ composite->temp_layer_buffer[i] = NULL;
+ }
+ }
+ if (composite->client_buffer) {
+ tbm_surface_internal_unref(composite->client_buffer);
+ if (capture_data->done_func) {
+ capture_data->done_func(capture_data,
+ composite->client_buffer,
+ capture_data->done_user_data);
+ }
+ composite->client_buffer = NULL;
+ }
+ if (composite->temp_composite_buffer) {
+ tbm_surface_internal_unref(composite->temp_composite_buffer);
+ composite->temp_composite_buffer = NULL;
+ }
+ free(composite);
+ }
+ LIST_FOR_EACH_ENTRY_SAFE(b, bb, &capture_data->pending_buffer_list, link) {
+ LIST_DEL(&b->link);
+ if (capture_data->done_func) {
+ capture_data->done_func(capture_data,
+ b->buffer,
+ capture_data->done_user_data);
+ }
+ free(b);
+ }
+#if 0
+ if (capture_data->stream.timer_source) {
+ TDM_BACKEND_DBG("capture %p removing postponed", capture_data);
+ return;
+ }
+#endif
+ LIST_DEL(&capture_data->link);
+ capture_data->stamp = 0;
+ tdm_sprd_output_dettach_capture(capture_data->output_data, capture_data);
+ free(capture_data);
+}
+#if 0
+static hal_tdm_error
+_tdm_sprd_capture_stream_timer_handler(void *user_data)
+{
+ tdm_sprd_capture_data *capture_data = user_data;
+ if (!_tdm_sprd_capture_check_struct(user_data)) {
+ return HAL_TDM_ERROR_NONE;
+ }
+
+ if (capture_data->removing) {
+ TDM_BACKEND_DBG("Capture %p Postponded removing", capture_data);
+ tdm_event_loop_source_remove(capture_data->stream.timer_source);
+ LIST_DEL(&capture_data->link);
+ capture_data->stamp = 0;
+ tdm_sprd_output_dettach_capture(capture_data->output_data, capture_data);
+ free(capture_data);
+ return HAL_TDM_ERROR_NONE;
+ }
+ unsigned int ms = 1000 / capture_data->info.frequency;
+ tdm_sprd_capture_buffer *b = NULL, *bb = NULL;
+ tbm_surface_h current_buffer = NULL;
+ hal_tdm_error tdm_err = HAL_TDM_ERROR_NONE;
+ if (!capture_data->stream.timer_source) {
+ TDM_BACKEND_ERR("Timer removed");
+ return HAL_TDM_ERROR_NONE;
+ }
+ tdm_event_loop_source_timer_update(capture_data->stream.timer_source, ms);
+ if (!LIST_IS_EMPTY(&capture_data->composite_list)) {
+ TDM_BACKEND_DBG("Converter is busy");
+ return HAL_TDM_ERROR_NONE;
+ }
+ LIST_FOR_EACH_ENTRY_SAFE(b, bb, &capture_data->pending_buffer_list, link) {
+ LIST_DEL(&b->link);
+ current_buffer = tbm_surface_internal_ref(b->buffer);
+ free(b);
+ tdm_err = _tdm_sprd_capture_oneshot_composite_layers_sw(capture_data, current_buffer);
+ tbm_surface_internal_unref(current_buffer);
+ break;
+ }
+ return tdm_err;
+}
+#endif
+
+static hal_tdm_error
+_tdm_sprd_capture_commit_stream(tdm_sprd_capture_data *capture_data)
+{
+#if 0
+ 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_sprd_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);
+#endif
+ return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_tdm_sprd_capture_commit_oneshot(tdm_sprd_capture_data *capture_data)
+{
+ tdm_sprd_capture_buffer *b = NULL, *bb = NULL;
+ tbm_surface_h current_buffer = NULL;
+ hal_tdm_error tdm_err = HAL_TDM_ERROR_NONE;
+ LIST_FOR_EACH_ENTRY_SAFE(b, bb, &capture_data->pending_buffer_list, link) {
+ LIST_DEL(&b->link);
+ current_buffer = b->buffer;
+ tbm_surface_internal_ref(b->buffer);
+ free(b);
+ tdm_err = _tdm_sprd_capture_oneshot_composite_layers_sw(capture_data, current_buffer);
+ tbm_surface_internal_unref(current_buffer);
+ if (tdm_err != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("capture %p composite func return err %d", tdm_err);
+ break;
+ }
+ }
+ return tdm_err;
+}
+
+hal_tdm_error
+sprd_display_get_capture_capability(hal_tdm_display *display, hal_tdm_caps_capture *caps)
+{
+ int i;
+
+ if (!caps || !display) {
+ TDM_BACKEND_ERR("invalid params");
+ return HAL_TDM_ERROR_INVALID_PARAMETER;
+ }
+
+ caps->capabilities = HAL_TDM_CAPTURE_CAPABILITY_OUTPUT|
+ HAL_TDM_CAPTURE_CAPABILITY_ONESHOT;
+// HAL_TDM_CAPTURE_CAPABILITY_STREAM;
+
+ caps->format_count = NUM_CAPTURE_FORMAT;
+ caps->formats = NULL;
+ if (NUM_CAPTURE_FORMAT) {
+ /* will be freed in frontend */
+ caps->formats = calloc(1, sizeof capture_client_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_client_formats[i];
+ }
+
+ caps->min_w = 16;
+ caps->min_h = 8;
+ caps->preferred_align = 2;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_capture*
+sprd_output_create_capture(hal_tdm_output *output, hal_tdm_error *error)
+{
+ if (!output) {
+ TDM_BACKEND_ERR("invalid params");
+ if (error) {
+ *error = HAL_TDM_ERROR_INVALID_PARAMETER;
+ }
+ return NULL;
+ }
+ tdm_sprd_capture_data *capture_data = calloc(1, sizeof(tdm_sprd_capture_data));
+ if (!capture_data) {
+ TDM_BACKEND_ERR("alloc failed");
+ if (error)
+ *error = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ return NULL;
+ }
+
+ if ((capture_data->display_data = tdm_sprd_output_get_display(output)) == NULL) {
+ TDM_BACKEND_ERR("invalid params");
+ if (error)
+ *error = HAL_TDM_ERROR_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ if ((tdm_sprd_output_attach_capture(output, capture_data)) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("can't attach capture to output");
+ if (error)
+ *error = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto fail;
+ }
+ capture_data->output_data = output;
+ capture_data->stamp = capture_stamp++;
+ LIST_INITHEAD(&capture_data->pending_buffer_list);
+ LIST_INITHEAD(&capture_data->pp_convert_list);
+ LIST_INITHEAD(&capture_data->composite_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);
+ if (error) {
+ *error = HAL_TDM_ERROR_NONE;
+ }
+ return capture_data;
+fail:
+ if (capture_data)
+ free(capture_data);
+ return NULL;
+}
+
+hal_tdm_error
+sprd_capture_set_info(hal_tdm_capture *capture, hal_tdm_info_capture *info)
+{
+ tdm_sprd_capture_data *capture_data = capture;
+ if (!_tdm_sprd_capture_check_struct(capture_data)) {
+ return HAL_TDM_ERROR_INVALID_PARAMETER;
+ }
+ if (capture_data->removing) {
+ TDM_BACKEND_INFO("Capture removing. Skip call func");
+ return HAL_TDM_ERROR_BUSY;
+ }
+ 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
+sprd_capture_attach(hal_tdm_capture *capture, tbm_surface_h buffer)
+{
+ tdm_sprd_capture_data *capture_data = capture;
+ tdm_sprd_capture_buffer *b;
+ if (!_tdm_sprd_capture_check_struct(capture_data)) {
+ return HAL_TDM_ERROR_INVALID_PARAMETER;
+ }
+ if (capture_data->removing) {
+ TDM_BACKEND_INFO("Capture removing. Skip call func");
+ return HAL_TDM_ERROR_BUSY;
+ }
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(buffer, HAL_TDM_ERROR_INVALID_PARAMETER);
+ b = calloc(1, sizeof(tdm_sprd_capture_buffer));
+ if (!b) {
+ TDM_BACKEND_ERR("alloc failed");
+ return HAL_TDM_ERROR_NONE;
+ }
+ TDM_BACKEND_DBG("capture %p attach buffer %p", capture, buffer);
+ LIST_ADDTAIL(&b->link, &capture_data->pending_buffer_list);
+
+ b->buffer = buffer;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+sprd_capture_commit(hal_tdm_capture *capture)
+{
+ tdm_sprd_capture_data *capture_data = capture;
+ hal_tdm_error ret;
+ if (!_tdm_sprd_capture_check_struct(capture_data)) {
+ return HAL_TDM_ERROR_INVALID_PARAMETER;
+ }
+ if (capture_data->removing) {
+ TDM_BACKEND_INFO("Capture removing. Skip call func");
+ return HAL_TDM_ERROR_BUSY;
+ }
+ TDM_BACKEND_DBG("capture %p commit", capture);
+ if (capture_data->info.type == HAL_TDM_CAPTURE_TYPE_ONESHOT)
+ ret = _tdm_sprd_capture_commit_oneshot(capture_data);
+ else
+ ret = _tdm_sprd_capture_commit_stream(capture_data);
+
+ return ret;
+}
+
+hal_tdm_error
+sprd_capture_set_done_handler(hal_tdm_capture *capture, hal_tdm_capture_done_handler func, void *user_data)
+{
+ tdm_sprd_capture_data *capture_data = capture;
+
+ if (!_tdm_sprd_capture_check_struct(capture_data)) {
+ return HAL_TDM_ERROR_INVALID_PARAMETER;
+ }
+ if (capture_data->removing) {
+ TDM_BACKEND_INFO("Capture removing. Skip call func");
+ return HAL_TDM_ERROR_BUSY;
+ }
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ capture_data->done_func = func;
+ capture_data->done_user_data = user_data;
+ TDM_BACKEND_DBG("capture %p set done handler func %p", capture, func);
+ return HAL_TDM_ERROR_NONE;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_sprd.h"
+
+#ifdef HAVE_FB_VBLANK
+/** @TODO fb event struct */
+#else
+typedef struct drm_event hw_event_t;
+#endif
+
+#define FB_DEV_LCD "/dev/fb0"
+
+#define HW_LAYER_NUM 2
+
+#define LIST_INSERT_AFTER(__after, __item) \
+ (__item)->prev = (__after); \
+ (__item)->next = (__after)->next; \
+ (__after)->next->prev = (__item); \
+ (__after)->next = (__item);
+
+#define STRERROR_SIZE 128
+
+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 img_layer_formats[] = {
+ TBM_FORMAT_NV12,
+ TBM_FORMAT_YUV420
+};
+
+tbm_format osd_layer_formats[] = {
+ TBM_FORMAT_RGB565,
+ TBM_FORMAT_XRGB8888,
+ TBM_FORMAT_ARGB8888
+};
+
+tdm_sprd_display_buffer *
+tdm_sprd_display_buffer_find(tdm_sprd_display *display_data, tbm_surface_h buffer)
+{
+ tdm_sprd_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_sprd_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 = {0, }, cur = {0, };
+ int ret;
+ char buf[STRERROR_SIZE];
+
+ ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("clock_gettime failed: %s", strerror_r(errno, buf, STRERROR_SIZE));
+ 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;
+}
+
+hal_tdm_error
+tdm_sprd_output_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;
+}
+
+hal_tdm_error
+tdm_sprd_output_wait_vblank(int fd, int pipe, uint *target_msc, int sync, void *data)
+{
+ drmVBlank vbl;
+
+ if (sync) {
+ vbl.request.type = DRM_VBLANK_RELATIVE;
+ vbl.request.sequence = 1;
+ vbl.request.signal = (unsigned long) (uintptr_t) data;
+ } else {
+ vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
+ vbl.request.sequence = *target_msc;
+ vbl.request.signal = (unsigned long) (uintptr_t) data;
+ }
+
+ if (pipe > 0)
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+
+ 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_sprd_display_output_disable(tdm_sprd_output *output_data)
+{
+ tdm_sprd_layer *layer_data = NULL;
+ char buf[STRERROR_SIZE];
+
+ LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
+ memset(&layer_data->ovi, 0, sizeof(overlay_info));
+
+ TDM_BACKEND_DBG("FB_BLANK_POWERDOWN\n");
+ if (ioctl(output_data->fb_fd, FBIOBLANK, FB_BLANK_POWERDOWN) < 0) {
+ TDM_BACKEND_ERR("FB_BLANK_POWERDOWN is failed: %s\n", strerror_r(errno, buf, STRERROR_SIZE));
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+ return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_tdm_sprd_display_output_enable(tdm_sprd_output *output_data)
+{
+ TDM_BACKEND_DBG("FB_BLANK_UNBLANK\n");
+ tdm_sprd_layer *layer_data = NULL;
+ char buf[STRERROR_SIZE];
+
+ LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
+ memset(&layer_data->ovi, 0, sizeof(overlay_info));
+ }
+ if (ioctl(output_data->fb_fd, FBIOBLANK, FB_BLANK_UNBLANK) < 0) {
+ TDM_BACKEND_ERR("FB_BLANK_UNBLANK is failed: %s\n", strerror_r(errno, buf, STRERROR_SIZE));
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+ return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_tdm_sprd_display_layer_disable(tdm_sprd_layer *layer_data)
+{
+ int layer_index = 0;
+ char buf[STRERROR_SIZE];
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_OPERATION_FAILED);
+ if (layer_data->capabilities & TDM_SPRD_LAYER_CAPABILITY_PRIMARY) {
+ layer_index = SPRD_LAYER_OSD;
+ } else if (layer_data->capabilities & TDM_SPRD_LAYER_CAPABILITY_OVERLAY) {
+ layer_index = SPRD_LAYER_IMG;
+ } else {
+ TDM_BACKEND_ERR("layer capability (0x%x) not supported\n", layer_data->capabilities);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+ if (layer_data->enabled_flag) {
+ TDM_BACKEND_DBG("SPRD_FB_UNSET_OVERLAY(%d)\n", layer_index);
+ if (ioctl(layer_data->output_data->fb_fd, SPRD_FB_UNSET_OVERLAY, &layer_index) == -1)
+ TDM_BACKEND_ERR("SPRD_FB_UNSET_OVERLAY(%d) error:%s\n", layer_index, strerror_r(errno, buf, STRERROR_SIZE));
+
+ memset(&layer_data->ovi, 0, sizeof(overlay_info));
+ layer_data->enabled_flag = 0;
+ }
+ return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_tdm_sprd_tbmformat_to_sprdformat(int tbm_format, overlay_info *ovi)
+{
+ ovi->rb_switch = 0;
+ ovi->data_type = 0;
+ ovi->endian.y = 0;
+ ovi->endian.u = 0;
+ ovi->endian.v = 0;
+
+ switch (tbm_format) {
+ case TBM_FORMAT_RGB565:
+ ovi->data_type = SPRD_DATA_FORMAT_RGB565;
+ ovi->endian.y = SPRD_DATA_ENDIAN_B0B1B2B3;
+ ovi->endian.u = SPRD_DATA_ENDIAN_B0B1B2B3;
+ break;
+ case TBM_FORMAT_ARGB8888:
+ case TBM_FORMAT_XRGB8888:
+ ovi->data_type = SPRD_DATA_FORMAT_RGB888;
+ ovi->endian.y = SPRD_DATA_ENDIAN_B0B1B2B3;
+ ovi->endian.u = SPRD_DATA_ENDIAN_B0B1B2B3;
+ break;
+ case TBM_FORMAT_NV12:
+ ovi->data_type = SPRD_DATA_FORMAT_YUV420;
+ ovi->endian.y = SPRD_DATA_ENDIAN_B3B2B1B0;
+ ovi->endian.u = SPRD_DATA_ENDIAN_B3B2B1B0;
+ break;
+ case TBM_FORMAT_YUV420:
+ ovi->data_type = SPRD_DATA_FORMAT_YUV420_3P;
+ ovi->endian.y = SPRD_DATA_ENDIAN_B3B2B1B0;
+ ovi->endian.u = SPRD_DATA_ENDIAN_B3B2B1B0;
+ ovi->endian.v = SPRD_DATA_ENDIAN_B3B2B1B0;
+ break;
+ default:
+ return HAL_TDM_ERROR_INVALID_PARAMETER;
+ }
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+tdm_sprd_output_do_commit(tdm_sprd_output *output_data)
+{
+ hal_tdm_error res = HAL_TDM_ERROR_NONE;
+ tdm_sprd_layer *layer_data = NULL;
+ overlay_info ovi = {0};
+ overlay_display ov_disp = {0};
+ int layer_index = 0;
+ char buf[STRERROR_SIZE];
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_OPERATION_FAILED);
+#if 0
+ if (output_data->dpms_value != HAL_TDM_OUTPUT_DPMS_ON) {
+ output_data->dpms_value = HAL_TDM_OUTPUT_DPMS_ON;
+ _tdm_sprd_display_output_enable(output_data);
+ }
+#endif
+ 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) {
+ if (layer_data->capabilities & TDM_SPRD_LAYER_CAPABILITY_PRIMARY) {
+ layer_index = SPRD_LAYER_OSD;
+ } else if (layer_data->capabilities & TDM_SPRD_LAYER_CAPABILITY_OVERLAY) {
+ layer_index = SPRD_LAYER_IMG;
+ } else {
+ TDM_BACKEND_ERR("layer capability (0x%x) not supported\n", layer_data->capabilities);
+ continue;
+ }
+ tbm_format frmt = layer_data->display_buffer->format;
+ if (_tdm_sprd_tbmformat_to_sprdformat(frmt, &ovi) != HAL_TDM_ERROR_NONE) {
+ ovi.data_type = SPRD_DATA_FORMAT_RGB888;
+ ovi.endian.y = SPRD_DATA_ENDIAN_B0B1B2B3;
+ ovi.endian.u = SPRD_DATA_ENDIAN_B0B1B2B3;
+ ovi.endian.v = SPRD_DATA_ENDIAN_B0B1B2B3;
+ TDM_BACKEND_ERR("Unsupported format: %x %c%c%c%c\n", frmt, FOURCC_STR(frmt));
+ continue;
+ }
+
+ ovi.layer_index = layer_index;
+ ovi.size.hsize = layer_data->display_buffer->width;
+ ovi.size.vsize = layer_data->display_buffer->height;
+
+ ovi.rect.x = layer_data->info.dst_pos.x;
+ ovi.rect.y = layer_data->info.dst_pos.y;
+
+ //restrict width
+ int output_width = output_data->mi.xres;
+ int width = layer_data->info.src_config.pos.w;
+ int x = layer_data->info.dst_pos.x;
+
+ ovi.rect.w = (width + x) <= output_width ? width : output_width - x;
+ ovi.rect.h = layer_data->info.src_config.pos.h;
+
+ if (ovi.layer_index == SPRD_LAYER_OSD)
+ ov_disp.osd_handle = layer_data->display_buffer->name[0];
+ else if (ovi.layer_index == SPRD_LAYER_IMG)
+ ov_disp.img_handle = layer_data->display_buffer->name[0];
+
+ if (memcmp(&layer_data->ovi, &ovi, sizeof(overlay_info)) != 0) {
+ TDM_BACKEND_DBG("SPRD_FB_SET_OVERLAY(%d) rect:%dx%d+%d+%d size:%dx%d\n", ovi.layer_index, ovi.rect.w,
+ ovi.rect.h, ovi.rect.x, ovi.rect.y, ovi.size.hsize, ovi.size.vsize);
+ if (ioctl(layer_data->output_data->fb_fd, SPRD_FB_SET_OVERLAY, &ovi) == -1) {
+ TDM_BACKEND_ERR("SPRD_FB_SET_OVERLAY(%d) error:%s\n", layer_index, strerror_r(errno, buf, STRERROR_SIZE));
+ continue;
+ }
+ memcpy(&layer_data->ovi, &ovi, sizeof(overlay_info));
+ }
+ layer_data->enabled_flag = 1;
+ ov_disp.layer_index |= layer_index;
+ } else {
+ layer_data->need_unset = 1;
+ }
+
+ layer_data->display_buffer_changed = layer_data->info_changed = 0;
+ }
+
+ if (ov_disp.layer_index) {
+ ov_disp.display_mode = SPRD_DISPLAY_OVERLAY_SYNC;
+
+ TDM_BACKEND_DBG("SPRD_FB_DISPLAY_OVERLAY(%d) osd_handle:%d img_handle:%d\n", ov_disp.layer_index, ov_disp.osd_handle,
+ ov_disp.img_handle);
+ if (ioctl(output_data->fb_fd, SPRD_FB_DISPLAY_OVERLAY, &ov_disp) == -1) {
+ TDM_BACKEND_ERR("SPRD_FB_DISPLAY_OVERLAY(%d) error:%s\n", ov_disp.layer_index, strerror_r(errno, buf, STRERROR_SIZE));
+ res = HAL_TDM_ERROR_OPERATION_FAILED;
+ } else {
+ //save enable layers
+// enable_layers |= ov_disp.layer_index;
+ }
+ }
+
+ return res;
+}
+
+#if 0
+static void
+_tdm_sprd_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_sprd_pp_handler(prop_id, buf_idx, tv_sec, tv_usec, user_data);
+}
+#endif
+
+#if 0
+static int
+_tdm_sprd_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_sprd_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_sprd_ipp_event *ipp;
+
+ if (evctx->pp_handler == NULL)
+ break;
+
+ ipp = (struct drm_sprd_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_sprd_display_create_layer_list_LCD(tdm_sprd_output *output_data)
+{
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ tdm_sprd_display *display_data = output_data->display_data;
+ tdm_sprd_layer *layer_data_osd, *layer_data_img;
+
+ layer_data_osd = calloc(1, sizeof(tdm_sprd_layer));
+ if (!layer_data_osd) {
+ TDM_BACKEND_ERR("alloc failed osd");
+ return HAL_TDM_ERROR_OUT_OF_MEMORY;
+ }
+ layer_data_img = calloc(1, sizeof(tdm_sprd_layer));
+ if (!layer_data_img) {
+ TDM_BACKEND_ERR("alloc failed img");
+ free(layer_data_osd);
+ return HAL_TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* create OSD layer */
+ layer_data_osd->display_data = display_data;
+ layer_data_osd->output_data = output_data;
+
+ layer_data_osd->capabilities = TDM_SPRD_LAYER_CAPABILITY_PRIMARY |
+ TDM_SPRD_LAYER_CAPABILITY_GRAPHIC |
+ TDM_SPRD_LAYER_CAPABILITY_SCANOUT |
+ TDM_SPRD_LAYER_CAPABILITY_RESEVED_MEMORY |
+ TDM_SPRD_LAYER_CAPABILITY_NO_CROP;
+ layer_data_osd->zpos = 1;
+
+ layer_data_osd->format_count = sizeof(osd_layer_formats) / sizeof(int);
+ layer_data_osd->formats = osd_layer_formats;
+
+ TDM_BACKEND_DBG("layer_data_osd(%p) capabilities(0x%x)", layer_data_osd, layer_data_osd->capabilities);
+
+ LIST_ADDTAIL(&layer_data_osd->link, &output_data->layer_list);
+
+ /* create IMG layer */
+ layer_data_img->display_data = display_data;
+ layer_data_img->output_data = output_data;
+ layer_data_img->capabilities = TDM_SPRD_LAYER_CAPABILITY_OVERLAY |
+ TDM_SPRD_LAYER_CAPABILITY_GRAPHIC |
+ TDM_SPRD_LAYER_CAPABILITY_SCANOUT |
+ TDM_SPRD_LAYER_CAPABILITY_RESEVED_MEMORY |
+ TDM_SPRD_LAYER_CAPABILITY_NO_CROP;
+ layer_data_img->zpos = 0;
+
+ layer_data_img->format_count = sizeof(img_layer_formats) / sizeof(int);
+ layer_data_img->formats = img_layer_formats;
+
+ TDM_BACKEND_DBG("layer_data_img(%p) capabilities(0x%x)", layer_data_img, layer_data_img->capabilities);
+
+ LIST_ADDTAIL(&layer_data_img->link, &output_data->layer_list);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+_tdm_sprd_display_output_update(tdm_sprd_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);
+
+ if (!output->fb_fd)
+ output->fb_fd = open(output->fb_fd_name, O_RDWR, 0);
+
+ if (output->fb_fd < 0)
+ goto failed;
+
+ if (ioctl(output->fb_fd, FBIOGET_VSCREENINFO, &output->mi) == -1)
+ 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 HAL_TDM_ERROR_NONE;
+
+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 HAL_TDM_ERROR_OPERATION_FAILED;
+}
+
+static void
+_tdm_sprd_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
+{
+ tdm_sprd_display *display_data;
+ tdm_sprd_display_buffer *display_buffer;
+ tdm_sprd_layer *layer_data = NULL;
+ tdm_sprd_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_sprd_display *) user_data;
+
+ display_buffer = tdm_sprd_display_buffer_find(display_data, buffer);
+ if (!display_buffer) {
+ TDM_BACKEND_ERR("no display_buffer");
+ return;
+ }
+ TDM_BACKEND_DBG("destroy buffer handle:%d", display_buffer->name[0]);
+
+ 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_sprd_display_layer_disable(layer_data);
+ layer_data->display_buffer = NULL;
+ }
+ }
+ }
+ LIST_DEL(&display_buffer->link);
+
+ free(display_buffer);
+}
+
+tdm_sprd_output *
+_tdm_sprd_display_create_output_LCD(tdm_sprd_display *display_data)
+{
+ tdm_sprd_output *output_data = NULL;
+ hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+ output_data = calloc(1, sizeof(tdm_sprd_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_LVDS;
+ output_data->count_modes = 0;
+ output_data->fb_fd_name = FB_DEV_LCD;
+ LIST_INITHEAD(&output_data->layer_list);
+
+ ret = _tdm_sprd_display_output_update(output_data);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("_tdm_sprd_display_output_update failed (%d)", ret);
+ free(output_data);
+ return NULL;
+ }
+
+ 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");
+ if (output_data->fb_fd > 0)
+ close(output_data->fb_fd);
+ free(output_data);
+ return NULL;
+ }
+ _tdm_sprd_display_to_tdm_mode(&output_data->mi, &output_data->output_modes[0]);
+
+ output_data->status = HAL_TDM_OUTPUT_CONN_STATUS_MODE_SETTED;
+ }
+
+ 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_sprd_display_create_layer_list_LCD(output_data);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("_tdm_sprd_display_create_layer_list_LCD failed (%d)", ret);
+ if (output_data->fb_fd > 0)
+ close(output_data->fb_fd);
+ free(output_data->output_modes);
+ free(output_data);
+ return NULL;
+ }
+
+ LIST_INITHEAD(&output_data->capture_list);
+
+ return output_data;
+}
+
+static void
+_tdm_display_buffer_get_full_size(tbm_surface_h buffer, int *buffer_w, int *buffer_h)
+{
+ tbm_surface_info_s info;
+ int ret;
+
+ TDM_BACKEND_RETURN_IF_FAIL(buffer != NULL);
+
+ ret = tbm_surface_get_info(buffer, &info);
+ TDM_BACKEND_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
+
+ if (buffer_w) {
+ if (IS_RGB(info.format))
+ *buffer_w = info.planes[0].stride >> 2;
+ else
+ *buffer_w = info.planes[0].stride;
+ }
+
+ if (buffer_h)
+ *buffer_h = info.planes[0].size / info.planes[0].stride;
+}
+
+tdm_sprd_display_buffer *
+tdm_sprd_display_buffer_create(tdm_sprd_display *display_data, tbm_surface_h surface, hal_tdm_error *err)
+{
+ int ret, i, count;
+ int bw = 0, bh = 0;
+ tdm_sprd_display_buffer * display_buffer = NULL;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data, NULL);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(surface, NULL);
+
+ display_buffer = calloc(1, sizeof(tdm_sprd_display_buffer));
+ if (!display_buffer) {
+ if (err)
+ *err = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ return NULL;
+ }
+
+ display_buffer->buffer = surface;
+
+ ret = tbm_surface_internal_add_destroy_handler(surface, _tdm_sprd_display_cb_destroy_buffer, display_data);
+ if (ret == 0) {
+ if (err)
+ *err = HAL_TDM_ERROR_OPERATION_FAILED;
+ TDM_BACKEND_ERR("add destroy handler fail");
+ free(display_buffer);
+ return NULL;
+ }
+
+ _tdm_display_buffer_get_full_size(surface, &bw, &bh);
+
+ display_buffer->width = bw;
+ display_buffer->height = bh;
+ display_buffer->format = tbm_surface_get_format(surface);
+ display_buffer->count = tbm_surface_internal_get_num_bos(surface);
+ count = tbm_surface_internal_get_num_planes(display_buffer->format);
+ TDM_BACKEND_DBG("create buffer: %dx%d %c%c%c%c bo_num:%d plane_num:%d",
+ 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(surface, i);
+ bo = tbm_surface_internal_get_bo(surface, bo_idx);
+ display_buffer->name[i] = tbm_bo_export(bo);
+
+ tbm_surface_internal_get_plane_data(surface, 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(name:%d)",
+ surface, i, display_buffer->size, display_buffer->offsets[i],
+ display_buffer->pitches[i], bo_idx, display_buffer->name[i]);
+ }
+
+ if (IS_RGB(display_buffer->format))
+ display_buffer->width = display_buffer->pitches[0] >> 2;
+ else
+ display_buffer->width = display_buffer->pitches[0];
+
+ if (err)
+ *err = HAL_TDM_ERROR_NONE;
+
+ LIST_ADDTAIL(&display_buffer->link, &display_data->buffer_list);
+
+ return display_buffer;
+}
+
+static int
+_sprd_drm_user_handler(struct drm_event *event)
+{
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(event, -1);
+
+ TDM_BACKEND_DBG("got event %d\n", event->type);
+
+ if (event->type != DRM_SPRD_IPP_EVENT)
+ return -1;
+ tdm_sprd_pp_handler((struct drm_sprd_ipp_event *) event);
+
+ return 0;
+}
+
+static void
+_sprd_drm_vblank_event(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+{
+ tdm_sprd_vblank *vblank_data = (tdm_sprd_vblank *) user_data;
+ tdm_sprd_output *output_data = NULL;
+ tdm_sprd_layer *layer_data = NULL;
+ tdm_sprd_hwc *hwc_data = NULL;
+
+ 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;
+ }
+
+ hwc_data = output_data->hwc_data;
+
+ 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:
+ LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
+ if (layer_data->need_unset) {
+ _tdm_sprd_display_layer_disable(layer_data);
+ layer_data->need_unset = 0;
+ }
+ }
+
+ if (hwc_data && hwc_data->commit_func)
+ hwc_data->commit_func(output_data, sequence, tv_sec, tv_usec, vblank_data->user_data);
+
+ break;
+ default:
+ break;
+ }
+ free(vblank_data);
+}
+
+static void
+_sprd_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");
+}
+
+void
+tdm_sprd_display_destroy_output_list(tdm_sprd_display *display_data)
+{
+ tdm_sprd_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 (o->fb_fd > 0)
+ close(o->fb_fd);
+ if (!LIST_IS_EMPTY(&o->capture_list)) {
+ tdm_sprd_capture *l = NULL, *ll = NULL;
+ LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->capture_list, link) {
+ sprd_capture_destroy(l->tdm_capture_p);
+ }
+ }
+ if (!LIST_IS_EMPTY(&o->layer_list)) {
+ tdm_sprd_layer *l = NULL, *ll = NULL;
+ LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
+ LIST_DEL(&l->link);
+ free(l);
+ }
+ }
+ free(o->output_modes);
+ free(o);
+ }
+}
+
+hal_tdm_error
+tdm_sprd_display_create_output_list(tdm_sprd_display *display_data)
+{
+ tdm_sprd_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_sprd_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_sprd_display_destroy_buffer_list(tdm_sprd_display *display_data)
+{
+ tdm_sprd_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_sprd_display_cb_destroy_buffer, display_data);
+ _tdm_sprd_display_cb_destroy_buffer(b->buffer, display_data);
+ }
+}
+
+hal_tdm_error
+sprd_display_get_capability(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
+sprd_display_get_pp_capability(hal_tdm_display *display, hal_tdm_caps_pp *caps)
+{
+ return tdm_sprd_pp_get_capability(display, caps);
+}
+
+hal_tdm_output **
+sprd_display_get_outputs(hal_tdm_display *display, int *count, hal_tdm_error *error)
+{
+ tdm_sprd_display *display_data = display;
+ tdm_sprd_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_sprd_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
+sprd_display_get_fd(hal_tdm_display *display, int *fd)
+{
+ tdm_sprd_display *display_data = 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
+sprd_display_handle_events(hal_tdm_display *display)
+{
+ tdm_sprd_display *display_data = 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_pp *
+sprd_display_create_pp(hal_tdm_display *display, hal_tdm_error *error)
+{
+ tdm_sprd_display *display_data = display;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data, NULL);
+
+ return tdm_sprd_pp_create(display_data, error);
+}
+
+hal_tdm_error
+sprd_output_get_capability(hal_tdm_output *output, hal_tdm_caps_output *caps)
+{
+ tdm_sprd_output *output_data = (tdm_sprd_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);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data->display_data, 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\n");
+ memset(caps, 0, sizeof(hal_tdm_caps_output));
+ return ret;
+ }
+ 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 = 0;
+ 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 = 0;
+ caps->props = NULL;
+
+ caps->capabilities |= HAL_TDM_OUTPUT_CAPABILITY_HWC;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+sprd_output_set_property(hal_tdm_output *output, unsigned int id, hal_tdm_value value)
+{
+ return HAL_TDM_ERROR_NOT_IMPLEMENTED;
+}
+
+hal_tdm_error
+sprd_output_get_property(hal_tdm_output *output, unsigned int id, hal_tdm_value *value)
+{
+ return HAL_TDM_ERROR_NOT_IMPLEMENTED;
+}
+
+hal_tdm_error
+sprd_output_wait_vblank(hal_tdm_output *output, int interval, int sync, void *user_data)
+{
+ tdm_sprd_output *output_data = (tdm_sprd_output *)output;
+ tdm_sprd_display *display_data;
+ tdm_sprd_vblank *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_sprd_vblank));
+ if (!vblank_data) {
+ TDM_BACKEND_ERR("alloc failed");
+ return HAL_TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ display_data = output_data->display_data;
+
+ ret = tdm_sprd_output_get_cur_msc(display_data->drm_fd, output_data->pipe, &target_msc);
+ if (ret != HAL_TDM_ERROR_NONE)
+ goto failed_vblank;
+
+ target_msc += interval;
+
+ vblank_data->type = VBLANK_TYPE_WAIT;
+ vblank_data->output_data = output_data;
+ vblank_data->user_data = user_data;
+
+ ret = tdm_sprd_output_wait_vblank(display_data->drm_fd, output_data->pipe, &target_msc, sync, 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
+sprd_output_set_vblank_handler(hal_tdm_output *output, hal_tdm_output_vblank_handler func)
+{
+ tdm_sprd_output *output_data = (tdm_sprd_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;
+}
+
+hal_tdm_error
+sprd_output_commit(hal_tdm_output *output, int sync, void *user_data)
+{
+ tdm_sprd_output *output_data = (tdm_sprd_output *)output;
+ tdm_sprd_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;
+
+ tdm_sprd_output_do_commit(output_data);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret);
+
+ tdm_sprd_vblank *vblank_data = calloc(1, sizeof(tdm_sprd_vblank));
+ uint target_msc;
+
+ if (!vblank_data) {
+ TDM_BACKEND_ERR("alloc failed");
+ return HAL_TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ ret = tdm_sprd_output_get_cur_msc(display_data->drm_fd, output_data->pipe, &target_msc);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(vblank_data);
+ return ret;
+ }
+
+ target_msc++;
+
+ vblank_data->type = VBLANK_TYPE_COMMIT;
+ vblank_data->output_data = output_data;
+ vblank_data->user_data = user_data;
+
+ ret = tdm_sprd_output_wait_vblank(display_data->drm_fd, output_data->pipe, &target_msc, sync, vblank_data);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(vblank_data);
+ return ret;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+sprd_output_set_commit_handler(hal_tdm_output *output, hal_tdm_output_commit_handler func)
+{
+ tdm_sprd_output *output_data = (tdm_sprd_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
+sprd_output_set_dpms(hal_tdm_output *output, hal_tdm_output_dpms dpms_value)
+{
+ tdm_sprd_output *output_data = (tdm_sprd_output *)output;
+ hal_tdm_error ret;
+
+ if (output_data->dpms_value == dpms_value)
+ return HAL_TDM_ERROR_NONE;
+
+ output_data->dpms_value = dpms_value;
+
+ if (dpms_value != HAL_TDM_OUTPUT_DPMS_ON)
+ ret = _tdm_sprd_display_output_disable(output_data);
+ else
+ ret = _tdm_sprd_display_output_enable(output_data);
+
+ return ret;
+}
+
+hal_tdm_error
+sprd_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_sprd_output *output_data = (tdm_sprd_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
+sprd_output_set_mode(hal_tdm_output *output, const hal_tdm_output_mode *mode)
+{
+ tdm_sprd_output *output_data = (tdm_sprd_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);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data->display_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ /* create or replace the target_window when the output mode is set */
+ ret = tdm_sprd_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
+sprd_output_get_mode(hal_tdm_output *output, const hal_tdm_output_mode **mode)
+{
+ tdm_sprd_output *output_data = (tdm_sprd_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_error
+tdm_sprd_layer_get_capability(tdm_sprd_layer *layer_data, tdm_sprd_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_sprd_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");
+ memset(caps, 0, sizeof(tdm_sprd_caps_layer));
+ return ret;
+ }
+
+ 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;
+}
+
+hal_tdm_error
+tdm_sprd_layer_set_property(tdm_sprd_layer *layer_data, unsigned int id, hal_tdm_value value)
+{
+ return HAL_TDM_ERROR_NOT_IMPLEMENTED;
+}
+
+hal_tdm_error
+tdm_sprd_layer_get_property(tdm_sprd_layer *layer_data, unsigned int id, hal_tdm_value *value)
+{
+ return HAL_TDM_ERROR_NOT_IMPLEMENTED;
+}
+
+hal_tdm_error
+tdm_sprd_layer_set_info(tdm_sprd_layer *layer_data, tdm_sprd_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);
+
+ layer_data->info = *info;
+ layer_data->info_changed = 1;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+tdm_sprd_layer_get_info(tdm_sprd_layer *layer_data, tdm_sprd_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_sprd_layer_set_buffer(tdm_sprd_layer *layer_data, tbm_surface_h surface)
+{
+ tdm_sprd_display *display_data;
+ tdm_sprd_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);
+
+ display_data = layer_data->display_data;
+ display_buffer = tdm_sprd_display_buffer_find(display_data, surface);
+ if (!display_buffer) {
+ display_buffer = tdm_sprd_display_buffer_create(display_data, surface, &err);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
+ }
+
+ layer_data->display_buffer = display_buffer;
+ layer_data->display_buffer_changed = 1;
+
+ return HAL_TDM_ERROR_NONE;
+
+}
+
+hal_tdm_error
+tdm_sprd_layer_unset_buffer(tdm_sprd_layer *layer_data)
+{
+ TDM_BACKEND_DBG("Unset buffer");
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data->output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ if (layer_data->display_buffer)
+ layer_data->display_buffer_changed = 1;
+ layer_data->display_buffer = NULL;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+tdm_sprd_layer_get_buffer_flags(tdm_sprd_layer *layer_data, unsigned int *flags)
+{
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ switch (layer_data->zpos) {
+ case 0:
+ case 1:
+ *flags = TBM_BO_SCANOUT;
+ break;
+ default:
+ return HAL_TDM_ERROR_INVALID_PARAMETER;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+tdm_sprd_display_init_event_handling(tdm_sprd_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 = _sprd_drm_flip_complete_event;
+ display_data->evctx.vblank_handler = _sprd_drm_vblank_event;
+
+ drmAddUserHandler(display_data->drm_fd, _sprd_drm_user_handler);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+void
+tdm_sprd_display_deinit_event_handling(tdm_sprd_display *display_data)
+{
+ TDM_BACKEND_RETURN_IF_FAIL(display_data);
+
+ drmRemoveUserHandler(display_data->drm_fd, _sprd_drm_user_handler);
+}
+
+tdm_sprd_display*
+tdm_sprd_output_get_display(hal_tdm_output *output)
+{
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output, NULL);
+ tdm_sprd_output *output_data = (tdm_sprd_output *)output;
+ return output_data->display_data;
+}
+
+hal_tdm_error
+tdm_sprd_output_attach_capture(hal_tdm_output *output, hal_tdm_capture *capture)
+{
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(capture, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ tdm_sprd_capture *capture_data = calloc(1, sizeof(tdm_sprd_capture));
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(capture_data, HAL_TDM_ERROR_OUT_OF_MEMORY);
+ tdm_sprd_output *output_data = (tdm_sprd_output *)output;
+ capture_data->tdm_capture_p = capture;
+ LIST_ADD(&capture_data->link, &output_data->capture_list);
+ TDM_BACKEND_DBG("capture attached");
+ return HAL_TDM_ERROR_NONE;
+}
+
+void
+tdm_sprd_output_dettach_capture(hal_tdm_output *output, hal_tdm_capture *capture)
+{
+ TDM_BACKEND_RETURN_IF_FAIL(output);
+ TDM_BACKEND_RETURN_IF_FAIL(capture);
+
+ tdm_sprd_output *output_data = (tdm_sprd_output *)output;
+ if (!LIST_IS_EMPTY(&output_data->capture_list)) {
+ tdm_sprd_capture *l = NULL, *ll = NULL;
+ LIST_FOR_EACH_ENTRY_SAFE(l, ll, &output_data->capture_list, link) {
+ if (l->tdm_capture_p == capture) {
+ LIST_DEL(&l->link);
+ free(l);
+ }
+ }
+ }
+}
+
+hal_tdm_error
+tdm_sprd_layer_get_buffer(tdm_sprd_layer *layer_data, tbm_surface_h *surface)
+{
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+ if (!layer_data->display_buffer) {
+ if (surface) {
+ *surface = NULL;
+ }
+ return HAL_TDM_ERROR_NONE;
+ }
+ if (surface) {
+ *surface = layer_data->display_buffer->buffer;
+ }
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+tdm_sprd_layer_get_zpos(tdm_sprd_layer *layer_data, int *zpos)
+{
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+ if (zpos) {
+ *zpos = layer_data->zpos;
+ }
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_hwc *
+sprd_output_get_hwc(hal_tdm_output *output, hal_tdm_error *error)
+{
+ tdm_sprd_hwc *hwc_data = NULL;
+ tdm_sprd_output *output_data = (tdm_sprd_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_sprd_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;
+}
+
+tdm_sprd_layer *
+tdm_sprd_output_get_tdm_sprd_layer(tdm_sprd_output *output_data, int layer_zpos)
+{
+ tdm_sprd_layer *l = NULL;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, NULL);
+
+ LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link) {
+ if (l->zpos == layer_zpos)
+ return l;
+ }
+
+ return NULL;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_sprd.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 drm_format;
+} tbm_format_data;
+
+static const tbm_format_data 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},
+};
+
+#define NUM_FORMATS (sizeof(formats) / sizeof(formats[0]))
+
+uint32_t
+tdm_format_get_drm_format(tbm_format format)
+{
+ int i;
+
+ for (i = 0; i < NUM_FORMATS; i++)
+ if (formats[i].tbm_format == format)
+ return formats[i].drm_format;
+
+ TDM_BACKEND_ERR("tbm format '%c%c%c%c' not found", FOURCC_STR(format));
+
+ return 0;
+}
+
+tbm_format
+tdm_format_get_tbm_format(uint32_t format)
+{
+ int i;
+
+ for (i = 0; i < NUM_FORMATS; i++)
+ if (formats[i].drm_format == format)
+ return formats[i].tbm_format;
+
+ TDM_BACKEND_ERR("drm format '%c%c%c%c' not found", FOURCC_STR(format));
+
+ return 0;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_sprd.h"
+
+#define MIN_WIDTH 32
+
+#define NUM_LAYERS 2
+#define NUM_BUFFERS 3
+
+#define ZPOS_OSD 1
+#define ZPOS_IMG 0
+#define NUM_UI_LAYERS 1
+
+tbm_format hwc_window_video_formats[] = {
+ TBM_FORMAT_NV12,
+ TBM_FORMAT_YUV420
+};
+
+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_sprd_hwc *hwc_data, hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds)
+{
+ tdm_sprd_hwc_window *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
+_sprd_hwc_window_has_reserved_buffer(tdm_sprd_hwc_window *hwc_window_data) {
+ tbm_bo bo = NULL;
+ int flags = 0;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data != NULL, 0);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data->surface != NULL, 0);
+
+ bo = tbm_surface_internal_get_bo(hwc_window_data->surface, 0);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(bo != NULL, 0);
+
+ flags = tbm_bo_get_flags(bo);
+
+ return flags & TBM_BO_SCANOUT;
+}
+
+static int
+_sprd_hwc_window_can_set_on_hw_layer(tdm_sprd_hwc_window *hwc_window_data)
+{
+ 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;
+
+ 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
+_sprd_hwc_window_get_tbm_surface_queue(hal_tdm_hwc_window *hwc_window, hal_tdm_error *error)
+{
+ tdm_sprd_hwc_window *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);
+
+ hwc_window_data->tqueue = tqueue;
+
+ if (error)
+ *error = HAL_TDM_ERROR_NONE;
+
+ return tqueue;
+}
+
+static hal_tdm_error
+_sprd_hwc_layer_attach_window(tdm_sprd_layer *layer_data, tdm_sprd_hwc_window *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_sprd_layer_unset_buffer(layer_data);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret);
+ } else {
+ ret = tdm_sprd_layer_set_info((tdm_sprd_layer *)layer_data, (tdm_sprd_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_sprd_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
+_sprd_hwc_prepare_commit(tdm_sprd_hwc *hwc_data)
+{
+ tdm_sprd_hwc_window *hwc_window_data = NULL;
+ tdm_sprd_layer *layer_data = NULL;
+ int use_layers_zpos[NUM_LAYERS] = {0,};
+ int lzpos = 0;
+
+ /* set target hwc window to the layer */
+ if (hwc_data->need_target_window) {
+ layer_data = tdm_sprd_output_get_tdm_sprd_layer(hwc_data->output_data, ZPOS_OSD);
+ _sprd_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_sprd_output_get_tdm_sprd_layer(hwc_data->output_data, hwc_window_data->lzpos);
+ _sprd_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_sprd_output_get_tdm_sprd_layer(hwc_data->output_data, use_layers_zpos[lzpos]);
+ _sprd_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
+_sprd_hwc_apply_policy(tdm_sprd_hwc *hwc_data , hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds)
+{
+ tdm_sprd_hwc_window *hwc_window_data = NULL;
+ tdm_sprd_hwc_window **composited_list = NULL;
+ int client_count = 0;
+ int device_count = 0;
+ int video_count = 0;
+ int cursor_count = 0;
+ int next_idx = 0;
+ int ui_lzpos = ZPOS_OSD; // this is 1
+ int video_lzpos = ZPOS_IMG; // this is 0
+ int i = 0;
+
+ composited_list = (tdm_sprd_hwc_window **)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) {
+ hwc_window_data->constraints = HAL_TDM_HWC_WIN_CONSTRAINT_NONE;
+ if (hwc_window_data->validated_type == HAL_TDM_HWC_WIN_COMPOSITION_NONE)
+ continue;
+ 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;
+ return;
+ }
+
+ /* count the composited(visible) windows */
+ for (i = 0; i < num_wnds; i++) {
+ if (composited_list[i]->client_type == HAL_TDM_HWC_WIN_COMPOSITION_CURSOR)
+ cursor_count++;
+ if (composited_list[i]->client_type == HAL_TDM_HWC_WIN_COMPOSITION_CLIENT)
+ client_count++;
+ if (client_count == 0 && composited_list[i]->client_type == HAL_TDM_HWC_WIN_COMPOSITION_DEVICE)
+ device_count++;
+ if (composited_list[i]->client_type == HAL_TDM_HWC_WIN_COMPOSITION_VIDEO)
+ video_count++;
+ }
+
+ if (cursor_count > 0)
+ goto set_clients_below;
+
+ if (client_count > 0)
+ goto set_clients_below;
+
+ /* calculate the available device_count */
+ if (device_count > NUM_UI_LAYERS)
+ goto set_clients_below;
+
+ /* NUM_UI_LAYSERS is 1, so device_count always 1 at this point */
+ while (device_count > 0) {
+ /* for video */
+ if (composited_list[next_idx]->client_type == HAL_TDM_HWC_WIN_COMPOSITION_VIDEO) {
+ composited_list[next_idx]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_VIDEO;
+ composited_list[next_idx]->lzpos = video_lzpos;
+ next_idx++;
+ continue;
+ }
+
+ /* set clients below when sprd can not set the window to the hw layer */
+ if (!_sprd_hwc_window_can_set_on_hw_layer(composited_list[next_idx]))
+ break;
+
+ /* set the buffer_queue constraint */
+ composited_list[next_idx]->constraints = HAL_TDM_HWC_WIN_CONSTRAINT_BUFFER_QUEUE;
+
+ /* set clients below when the hwc_window does not have the reserved buffer */
+ if (!_sprd_hwc_window_has_reserved_buffer(composited_list[next_idx])) {
+ composited_list[next_idx]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_CLIENT;
+ composited_list[next_idx]->lzpos = -1;
+ hwc_data->need_target_window = 1;
+ next_idx++;
+ break;
+ }
+
+ /* set the OSD */
+ composited_list[next_idx]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_DEVICE;
+ composited_list[next_idx]->lzpos = ui_lzpos--;
+ next_idx++;
+
+ device_count--;
+ }
+
+set_clients_below:
+ while (next_idx < num_wnds) {
+ hwc_data->need_target_window = 1;
+
+ /* for video */
+ if (composited_list[next_idx]->client_type == HAL_TDM_HWC_WIN_COMPOSITION_VIDEO) {
+ composited_list[next_idx]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_VIDEO;
+ composited_list[next_idx]->lzpos = video_lzpos;
+ next_idx++;
+ continue;
+ }
+ composited_list[next_idx]->constraints = HAL_TDM_HWC_WIN_CONSTRAINT_NONE;
+ composited_list[next_idx]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_CLIENT;
+ composited_list[next_idx]->lzpos = -1;
+ next_idx++;
+ }
+}
+
+int
+_sprd_hwc_get_changed_number(tdm_sprd_hwc *hwc_data)
+{
+ int num = 0;
+ tdm_sprd_hwc_window *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;
+}
+
+static hal_tdm_hwc_window *
+_sprd_hwc_create_window(tdm_sprd_hwc *hwc_data, hal_tdm_hwc_window_info *info, hal_tdm_error *error)
+{
+ tdm_sprd_hwc_window *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_sprd_hwc_window));
+ 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 *
+sprd_hwc_create_window(hal_tdm_hwc *hwc, hal_tdm_error *error)
+{
+ tdm_sprd_hwc *hwc_data = hwc;
+ tdm_sprd_hwc_window *hwc_window_data = NULL;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, NULL);
+
+ hwc_window_data = _sprd_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
+sprd_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
+sprd_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 = HAL_TDM_HWC_CAPABILITY_VIDEO_SCANOUT;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+sprd_hwc_get_available_properties(hal_tdm_hwc *hwc, const hal_tdm_prop **props, int *count)
+{
+ tdm_sprd_hwc *hwc_data = hwc;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ *props = NULL;
+ *count = 0;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+tbm_surface_queue_h
+sprd_hwc_get_client_target_buffer_queue(hal_tdm_hwc *hwc, hal_tdm_error *error)
+{
+ tdm_sprd_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 = _sprd_hwc_window_get_tbm_surface_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
+sprd_hwc_set_client_target_buffer(hal_tdm_hwc *hwc, tbm_surface_h buffer, hal_tdm_region damage)
+{
+ tdm_sprd_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 = sprd_hwc_window_set_buffer(hwc_data->target_hwc_window, buffer);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(err == HAL_TDM_ERROR_NONE, err);
+
+ err = sprd_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
+sprd_hwc_validate(hal_tdm_hwc *hwc, hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types)
+{
+ tdm_sprd_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=================================");
+
+ _sprd_hwc_apply_policy(hwc_data, composited_wnds, num_wnds);
+
+ *num_types = _sprd_hwc_get_changed_number(hwc_data);
+
+ _print_validate_result(hwc_data, composited_wnds, num_wnds);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+sprd_hwc_get_changed_composition_types(hal_tdm_hwc *hwc, uint32_t *num_elements,
+ hal_tdm_hwc_window **hwc_window, hal_tdm_hwc_window_composition *composition_types)
+{
+ tdm_sprd_hwc *hwc_data = hwc;
+ tdm_sprd_hwc_window *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_window == NULL) || (composition_types == NULL)) {
+ *num_elements = _sprd_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_window[num] = hwc_window_data;
+ num++;
+ }
+ }
+
+ /* set real num of changed composition types */
+ *num_elements = num;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+sprd_hwc_accept_validation(hal_tdm_hwc *hwc)
+{
+ tdm_sprd_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 = _sprd_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
+sprd_hwc_commit(hal_tdm_hwc *hwc, int sync, void *user_data)
+{
+ tdm_sprd_output *output_data = NULL;
+ tdm_sprd_hwc *hwc_data = NULL;
+ tdm_sprd_display *display_data = NULL;
+ hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ hwc_data = (tdm_sprd_hwc *)hwc;
+
+ output_data = hwc_data->output_data;
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ display_data = output_data->display_data;
+
+ tdm_sprd_output_do_commit(output_data);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret);
+
+ tdm_sprd_vblank *vblank_data = calloc(1, sizeof(tdm_sprd_vblank));
+ uint target_msc;
+
+ if (!vblank_data) {
+ TDM_BACKEND_ERR("alloc failed");
+ return HAL_TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ ret = tdm_sprd_output_get_cur_msc(display_data->drm_fd, output_data->pipe, &target_msc);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(vblank_data);
+ return ret;
+ }
+
+ target_msc++;
+
+ vblank_data->type = VBLANK_TYPE_COMMIT;
+ vblank_data->output_data = output_data;
+ vblank_data->user_data = user_data;
+
+ ret = tdm_sprd_output_wait_vblank(display_data->drm_fd, output_data->pipe, &target_msc, sync, vblank_data);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(vblank_data);
+ return ret;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+sprd_hwc_set_commit_handler(hal_tdm_hwc *hwc, hal_tdm_hwc_commit_handler func)
+{
+ tdm_sprd_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
+tdm_sprd_hwc_initailize_target_window(hal_tdm_hwc *hwc, int width, int height)
+{
+ hal_tdm_hwc_window_info info = {0};
+ hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+ tdm_sprd_hwc_window *target_hwc_window;
+ tdm_sprd_hwc *hwc_data = hwc;
+
+ 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 = _sprd_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)
+ sprd_hwc_window_destroy(hwc_data->target_hwc_window);
+
+ hwc_data->target_hwc_window = target_hwc_window;
+ hwc_data->target_hwc_window->lzpos = ZPOS_OSD;
+
+ return HAL_TDM_ERROR_NONE;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_sprd.h"
+
+tbm_surface_queue_h
+sprd_hwc_window_acquire_buffer_queue(hal_tdm_hwc_window *hwc_window, hal_tdm_error *error)
+{
+ tdm_sprd_hwc *hwc_data = NULL;
+ tdm_sprd_hwc_window *hwc_window_data = NULL;
+ tdm_sprd_hwc_window *target_hwc_window_data = NULL;
+
+ if (error)
+ *error = HAL_TDM_ERROR_INVALID_PARAMETER;
+
+ hwc_window_data = (tdm_sprd_hwc_window *)hwc_window;
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data != NULL, NULL);
+
+ hwc_data = hwc_window_data->hwc_data;
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, NULL);
+
+ target_hwc_window_data = hwc_data->target_hwc_window;
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(target_hwc_window_data != NULL, NULL);
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(target_hwc_window_data->tqueue != NULL, NULL);
+
+ if (error)
+ *error = HAL_TDM_ERROR_NONE;
+
+ return target_hwc_window_data->tqueue;
+}
+
+void
+sprd_hwc_window_release_buffer_queue(hal_tdm_hwc_window *hwc_window, tbm_surface_queue_h queue)
+{
+ return;
+}
+
+void
+sprd_hwc_window_destroy(hal_tdm_hwc_window *hwc_window)
+{
+ tdm_sprd_hwc_window *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
+sprd_hwc_window_set_composition_type(hal_tdm_hwc_window *hwc_window,
+ hal_tdm_hwc_window_composition comp_type)
+{
+ tdm_sprd_hwc_window *hwc_window_data = hwc_window;
+ tdm_sprd_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
+sprd_hwc_window_set_buffer_damage(hal_tdm_hwc_window *hwc_window, hal_tdm_region damage)
+{
+ tdm_sprd_hwc_window *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
+sprd_hwc_window_set_info(hal_tdm_hwc_window *hwc_window, hal_tdm_hwc_window_info *info)
+{
+ tdm_sprd_hwc_window *hwc_window_data = hwc_window;
+ tdm_sprd_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
+sprd_hwc_window_set_buffer(hal_tdm_hwc_window *hwc_window, tbm_surface_h surface)
+{
+ tdm_sprd_hwc_window *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
+sprd_hwc_window_get_property(hal_tdm_hwc_window *hwc_window, unsigned int id, hal_tdm_value *value)
+{
+ tdm_sprd_hwc_window *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
+sprd_hwc_window_set_property(hal_tdm_hwc_window *hwc_window, unsigned int id, hal_tdm_value value)
+{
+ tdm_sprd_hwc_window *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
+sprd_hwc_window_get_constraints(hal_tdm_hwc_window *hwc_window, int *constraints)
+{
+ tdm_sprd_hwc_window *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);
+
+ *constraints = hwc_window_data->constraints;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+sprd_hwc_window_set_name(hal_tdm_hwc_window *hwc_window, const char *name)
+{
+ tdm_sprd_hwc_window *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;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_sprd.h"
+
+#define PP_MAX_STEP 4
+#define PP_UP_RATIO 4
+#define PP_DOWN_RATIO 4
+
+#define SPRD_C(b, m) (((b) >> (m)) & 0xFF)
+#define SPRD_FOURCC_STR(id) SPRD_C(id, 0), SPRD_C(id, 8), SPRD_C(id, 16), SPRD_C(id, 24)
+
+typedef struct _tdm_sprd_pp_buffer {
+ int index;
+ tbm_surface_h src;
+ tbm_surface_h dst;
+ struct list_head link;
+} tdm_sprd_pp_buffer;
+
+typedef enum _tdm_sprd_pp_ctrl {
+ IPP_STOP = 0,
+ IPP_RUN = 1,
+ IPP_PAUSE = 2
+} tdm_sprd_pp_ctrl;
+
+typedef enum _tdm_sprd_task_status {
+ TASK_WAITING,
+ TASK_CONVERTING,
+ TASK_IGNORE,
+ TASK_DONE
+} tdm_sprd_task_status;
+
+
+typedef struct _tdm_sprd_pp_roadmap {
+ hal_tdm_info_pp step_info;
+ unsigned int stamp;
+ unsigned int prop_id;
+} tdm_sprd_pp_roadmap;
+
+typedef struct _tdm_sprd_prop_id {
+ enum drm_sprd_ipp_ctrl status;
+ unsigned int prop_id;
+ tdm_sprd_pp_roadmap current_roadmap;
+ struct list_head link;
+} tdm_sprd_prop_id;
+
+typedef struct _tdm_sprd_pp_task {
+ int stamp;
+ tdm_sprd_pp_roadmap roadmap;
+ tdm_sprd_pp_buffer process_buffer;
+ tdm_sprd_task_status status;
+ hal_tdm_pp_done_handler done_func;
+ tdm_sprd_pp_buffer return_buffer;
+ void *done_user_data;
+ struct list_head link;
+} tdm_sprd_pp_task;
+
+typedef struct _tdm_sprd_pp_data {
+ tdm_sprd_display *display_data;
+ int stamp;
+ struct list_head pending_buffer_list;
+ struct list_head pending_tasks_list;
+ struct list_head prop_id_list;
+ tdm_sprd_pp_roadmap current_roadmap[PP_MAX_STEP];
+ unsigned int roadmap_step;
+ tdm_sprd_pp_roadmap new_roadmap;
+ 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;
+} tdm_sprd_pp_data;
+
+static tbm_format pp_formats[] = {
+ TBM_FORMAT_XRGB8888,
+ TBM_FORMAT_ARGB8888,
+ TBM_FORMAT_NV12,
+ TBM_FORMAT_YUV420,
+};
+
+#define NUM_PP_FORMAT (sizeof(pp_formats) / sizeof(pp_formats[0]))
+
+static int pp_list_init = 0;
+static int pp_stamp = 1001;
+static int task_stamp = 10001;
+static unsigned int roadmap_stamp = 10;
+static struct list_head pp_list;
+
+static tdm_sprd_prop_id *
+_find_prop_id(tdm_sprd_pp_data *pp_data, unsigned int prop_id)
+{
+ tdm_sprd_prop_id *prop = NULL;
+ if (prop_id == 0)
+ return NULL;
+ LIST_FOR_EACH_ENTRY(prop, &pp_data->prop_id_list, link) {
+ if (prop->prop_id == prop_id)
+ return prop;
+ }
+ return NULL;
+}
+static void
+_set_task_status(tdm_sprd_pp_task *task, tdm_sprd_task_status new_status)
+{
+ TDM_BACKEND_DBG("Set Task %p(%d) status old->new %u->%u", task, task->stamp, task->status, new_status);
+ task->status = new_status;
+}
+
+int _tdm_sprd_pp_check_struct(tdm_sprd_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_sprd_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_INFO("pp %p(%d). Maybe, receive handler after remove", pp_data, pp_data->stamp);
+ return 0;
+}
+
+void _tdm_sprd_pp_roadmap_print(tdm_sprd_pp_roadmap *roadmap)
+{
+ TDM_BACKEND_RETURN_IF_FAIL(roadmap);
+ TDM_BACKEND_DBG("----------------------ROADMAP--------------------------------------");
+ TDM_BACKEND_DBG("stamp %u", roadmap->stamp);
+ TDM_BACKEND_DBG("format (%u)%c%c%c%c -> (%u)%c%c%c%c", roadmap->step_info.src_config.format,
+ SPRD_FOURCC_STR(roadmap->step_info.src_config.format), roadmap->step_info.dst_config.format,
+ SPRD_FOURCC_STR(roadmap->step_info.dst_config.format));
+ TDM_BACKEND_DBG("rotate+flip is %u+%s", roadmap->step_info.transform % 4,
+ roadmap->step_info.transform > 3 ? "Horizontal" : "None");
+ TDM_BACKEND_DBG("size src->dst (w)x(h) (%u)x(%u) -> (%u)x(%u)", roadmap->step_info.src_config.size.h,
+ roadmap->step_info.src_config.size.v, roadmap->step_info.dst_config.size.h,
+ roadmap->step_info.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.src_config.pos.x,
+ roadmap->step_info.src_config.pos.y, roadmap->step_info.src_config.pos.w,
+ roadmap->step_info.src_config.pos.h, roadmap->step_info.dst_config.pos.x,
+ roadmap->step_info.dst_config.pos.y, roadmap->step_info.dst_config.pos.w,
+ roadmap->step_info.dst_config.pos.h);
+ TDM_BACKEND_DBG("-------------------------------------------------------------------");
+}
+
+#if 1
+static void
+_tdm_sprd_pp_property_format_check(struct drm_sprd_ipp_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));
+}
+#endif
+
+static int
+_tdm_sprd_pp_check_roadmap_equal(tdm_sprd_pp_roadmap *roadmap1, tdm_sprd_pp_roadmap *roadmap2)
+{
+ if (!roadmap1 | !roadmap2) {
+ TDM_BACKEND_DBG("One of comparing roadmap is NULL %p, %p", roadmap1, roadmap2);
+ return 0;
+ }
+ if (!roadmap1->stamp || !roadmap2->stamp) {
+ TDM_BACKEND_DBG("One of comparing roadmap stamp is 0 %p(%u), %p(%u)", roadmap1, roadmap1->stamp,
+ roadmap2, roadmap2->stamp);
+ return 0;
+ }
+ if (memcmp(&roadmap1->step_info, &roadmap2->step_info, sizeof(hal_tdm_info_pp))) {
+ TDM_BACKEND_DBG("roadmaps %p(%u), %p(%u) is different", roadmap1, roadmap1->stamp, roadmap2, roadmap2->stamp);
+ return 0;
+ }
+ TDM_BACKEND_DBG("roadmaps %p(%u), %p(%u) is equal", roadmap1, roadmap1->stamp, roadmap2, roadmap2->stamp);
+ return 1;
+}
+
+static hal_tdm_error
+_tdm_sprd_pp_cmd(tdm_sprd_pp_data *pp_data, unsigned int prop_id,
+ tdm_sprd_pp_ctrl cmd)
+{
+ tdm_sprd_display *display_data = pp_data->display_data;
+ tdm_sprd_prop_id *found_prop = _find_prop_id(pp_data, prop_id);
+ if (found_prop == NULL) {
+ TDM_BACKEND_ERR("pp %p(%d). Failed. prop_id(%d)", pp_data, pp_data->stamp, prop_id);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+ struct drm_sprd_ipp_cmd_ctrl ctrl;
+ int ret = 0;
+
+ ctrl.prop_id = prop_id;
+ switch (cmd) {
+ case IPP_RUN:
+ if (found_prop->status == IPP_CTRL_STOP)
+ ctrl.ctrl = IPP_CTRL_PLAY;
+ else if (found_prop->status == IPP_CTRL_PAUSE)
+ ctrl.ctrl = IPP_CTRL_RESUME;
+ else if (found_prop->status == IPP_CTRL_PLAY ||
+ found_prop->status == IPP_CTRL_RESUME)
+ return HAL_TDM_ERROR_NONE;
+ break;
+ case IPP_PAUSE:
+ if (found_prop->status == IPP_CTRL_PLAY ||
+ found_prop->status == IPP_CTRL_RESUME)
+ ctrl.ctrl = IPP_CTRL_PAUSE;
+ else if (found_prop->status == IPP_CTRL_PAUSE ||
+ found_prop->status == IPP_CTRL_STOP)
+ return HAL_TDM_ERROR_NONE;
+ break;
+ case IPP_STOP:
+ if (found_prop->status == IPP_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 = IPP_CTRL_STOP;
+ found_prop = NULL;
+ break;
+ default:
+ TDM_BACKEND_ERR("Never Get Here!");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ 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_SPRD_IPP_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;
+}
+
+static unsigned int
+_tdm_sprd_pp_set(tdm_sprd_pp_data *pp_data, tdm_sprd_pp_roadmap *new_roadmap,
+ unsigned int prop_id)
+{
+ tdm_sprd_display *display_data = pp_data->display_data;
+ hal_tdm_info_pp *info = &new_roadmap->step_info;
+ struct drm_sprd_ipp_property property;
+ int ret = 0;
+
+ tdm_sprd_prop_id * found_prop = _find_prop_id(pp_data, prop_id);
+ if (found_prop != NULL) {
+ if (_tdm_sprd_pp_check_roadmap_equal(new_roadmap, &found_prop->current_roadmap)) {
+ TDM_BACKEND_DBG("pp %p(%d) set same property. Ignoring.", pp_data, pp_data->stamp);
+ found_prop->current_roadmap.stamp = new_roadmap->stamp;
+ return prop_id;
+ } else if (_tdm_sprd_pp_cmd(pp_data, prop_id, IPP_PAUSE) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_WRN("pp %p(%d) Can't set pause mode. Ignore prop_id %u", pp_data, pp_data->stamp,
+ prop_id);
+ prop_id = 0;
+ }
+ }
+ CLEAR(property);
+ property.config[0].ops_id = SPRD_DRM_OPS_SRC;
+ property.config[0].fmt = tdm_format_get_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 = SPRD_DRM_OPS_DST;
+ property.config[1].degree = info->transform % 4;
+ property.config[1].flip = (info->transform > 3) ? SPRD_DRM_FLIP_HORIZONTAL : 0;
+ property.config[1].fmt = tdm_format_get_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 = IPP_CMD_M2M;
+ property.prop_id = prop_id;
+ property.type = IPP_EVENT_DRIVEN;
+
+ _tdm_sprd_pp_property_format_check(&property);
+
+ TDM_BACKEND_DBG("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_DBG("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_SPRD_IPP_SET_PROPERTY, &property);
+ if (ret) {
+ TDM_BACKEND_ERR("pp %p(%d). failed: %m", pp_data, pp_data->stamp);
+ return 0;
+ }
+ found_prop = _find_prop_id(pp_data, property.prop_id);
+ if (found_prop == NULL) {
+ if ((found_prop = calloc(1, sizeof(tdm_sprd_prop_id))) == NULL) {
+ TDM_BACKEND_ERR("pp %p(%d). Out of memory", pp_data, pp_data->stamp);
+ return 0;
+ }
+ found_prop->prop_id = property.prop_id;
+ found_prop->status = IPP_CTRL_STOP;
+ LIST_ADDTAIL(&found_prop->link, &pp_data->prop_id_list);
+ }
+ memcpy(&found_prop->current_roadmap, new_roadmap, sizeof(tdm_sprd_pp_roadmap));
+ TDM_BACKEND_DBG("pp %p(%d). success. prop_id(%u) roadmap stamp(%u)", pp_data, pp_data->stamp,
+ property.prop_id,
+ found_prop->current_roadmap.stamp);
+ return property.prop_id;
+}
+
+static hal_tdm_error
+_tdm_sprd_pp_queue(tdm_sprd_pp_data *pp_data, unsigned int prop_id,
+ tbm_surface_h src, tbm_surface_h dst, enum drm_sprd_ipp_buf_type type)
+{
+ tdm_sprd_display *display_data = pp_data->display_data;
+ tdm_sprd_prop_id *found_prop = _find_prop_id(pp_data, prop_id);
+ if (found_prop == NULL) {
+ TDM_BACKEND_ERR("pp %p(%d). Failed. prop_id(%d)", pp_data, pp_data->stamp, prop_id);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+ struct drm_sprd_ipp_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 = SPRD_DRM_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 < SPRD_DRM_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_SPRD_IPP_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 = SPRD_DRM_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 < SPRD_DRM_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_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_SPRD_IPP_QUEUE_BUF, &buf);
+ 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_DBG("pp %p(%d). Success. prop_id(%d)", pp_data, pp_data->stamp, buf.prop_id);
+ return HAL_TDM_ERROR_NONE;
+}
+
+static void
+_tdm_sprd_pp_destroy_task(tdm_sprd_pp_data *pp_data, tdm_sprd_pp_task * task)
+{
+
+ if (task->process_buffer.src) {
+ tbm_surface_internal_unref(task->process_buffer.src);
+ task->process_buffer.src = NULL;
+ }
+ if (task->process_buffer.dst) {
+ tbm_surface_internal_unref(task->process_buffer.dst);
+ task->process_buffer.dst = NULL;
+ }
+ if (task->done_func) {
+ TDM_BACKEND_DBG("pp %p(%d). Return src %p dst %p", pp_data, pp_data->stamp,
+ task->return_buffer.src, task->return_buffer.dst);
+ task->done_func(pp_data, task->return_buffer.src,
+ task->return_buffer.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 void
+_tdm_sprd_pp_clear_queue(tdm_sprd_pp_data *pp_data)
+{
+ tdm_sprd_pp_task *task = NULL, *next_task = NULL;
+ LIST_FOR_EACH_ENTRY_SAFE(task, next_task, &pp_data->pending_tasks_list, link) {
+ LIST_DEL(&task->link);
+ _tdm_sprd_pp_destroy_task(pp_data, task);
+ }
+}
+
+static void
+_tdm_sprd_pp_drop_queue(tdm_sprd_pp_data *pp_data)
+{
+ tdm_sprd_pp_task *task = NULL, *next_task = NULL;
+ LIST_FOR_EACH_ENTRY_SAFE(task, next_task, &pp_data->pending_tasks_list, link) {
+ if (task->status != TASK_CONVERTING)
+ _set_task_status(task, TASK_IGNORE);
+ }
+}
+
+static hal_tdm_error
+_tdm_sprd_pp_make_tasks(tdm_sprd_pp_data *pp_data)
+{
+ tdm_sprd_pp_buffer *main_buffer = NULL, *b = NULL, *bb = NULL;
+ tdm_sprd_pp_task *new_task[PP_MAX_STEP] = {NULL};
+ hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+ unsigned 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 HAL_TDM_ERROR_NONE;
+ }
+ LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
+ LIST_DEL(&b->link);
+ main_buffer = b;
+ CLEAR(new_task);
+ if (pp_data->roadmap_step > PP_MAX_STEP) {
+ TDM_BACKEND_ERR("pp %p(%d). Never get here!", pp_data, pp_data->stamp);
+ goto fail_l;
+ }
+ for (i = 0; i < pp_data->roadmap_step; i++) {
+ if (pp_data->current_roadmap[i].stamp == 0) {
+ TDM_BACKEND_WRN("pp %p(%d) roadmap not set", pp_data, pp_data->stamp);
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto fail_l;
+ }
+ if ((new_task[i] = calloc(1, sizeof(tdm_sprd_pp_task))) == NULL) {
+ TDM_BACKEND_ERR("pp %p(%d). Out of memory", pp_data, pp_data->stamp);
+ ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ goto fail_l;
+ }
+ memcpy(&new_task[i]->roadmap, &pp_data->current_roadmap[i], sizeof(tdm_sprd_pp_roadmap));
+ new_task[i]->stamp = task_stamp++;
+ if (i == 0) {
+ new_task[i]->process_buffer.src = main_buffer->src;
+ tbm_surface_internal_ref(main_buffer->src);
+ } else {
+ new_task[i]->process_buffer.src = new_task[i-1]->process_buffer.dst;
+ tbm_surface_internal_ref(new_task[i-1]->process_buffer.dst);
+ }
+ if (i == (pp_data->roadmap_step - 1)) {
+ new_task[i]->process_buffer.dst = main_buffer->dst;
+ tbm_surface_internal_ref(main_buffer->dst);
+ } else {
+ tbm_surface_h temp_buffer = tbm_surface_create(new_task[i]->roadmap.step_info.dst_config.size.h,
+ new_task[i]->roadmap.step_info.dst_config.size.v,
+ new_task[i]->roadmap.step_info.dst_config.format);
+ if (temp_buffer == NULL) {
+ TDM_BACKEND_ERR("pp %p(%d). Out of memory", pp_data, pp_data->stamp);
+ ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ goto fail_l;
+ }
+ new_task[i]->process_buffer.dst = temp_buffer;
+ }
+ new_task[i]->status = TASK_WAITING;
+ new_task[i]->done_func = NULL;
+ TDM_BACKEND_DBG("pp %p(%d). New task %p(%d)", pp_data, pp_data->stamp, new_task[i], new_task[i]->stamp);
+ }
+ TDM_BACKEND_DBG("pp %p(%d). Add new src %p dst %p buffer", pp_data, pp_data->stamp,
+ main_buffer->src, main_buffer->dst);
+ new_task[pp_data->roadmap_step-1]->done_func = pp_data->done_func;
+ new_task[pp_data->roadmap_step-1]->done_user_data = pp_data->done_user_data;
+ new_task[pp_data->roadmap_step-1]->return_buffer.src = main_buffer->src;
+ new_task[pp_data->roadmap_step-1]->return_buffer.dst = main_buffer->dst;
+ free(main_buffer);
+ main_buffer = NULL;
+ for (i = 0; i < pp_data->roadmap_step; i++) {
+ LIST_ADDTAIL(&new_task[i]->link, &pp_data->pending_tasks_list);
+ }
+ }
+ return HAL_TDM_ERROR_NONE;
+fail_l:
+ for (i = 0; i < PP_MAX_STEP; i++) {
+ if (new_task[i] != NULL) {
+ if (new_task[i]->process_buffer.src) {
+ tbm_surface_internal_unref(new_task[i]->process_buffer.src);
+ }
+ if (new_task[i]->process_buffer.dst) {
+ tbm_surface_internal_unref(new_task[i]->process_buffer.dst);
+ }
+ free(new_task[i]);
+ }
+ }
+ return ret;
+}
+
+static hal_tdm_error
+_tdm_sprd_pp_worker(tdm_sprd_pp_data *pp_data)
+{
+ tdm_sprd_pp_task *next_task = NULL;
+ hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+ if (LIST_IS_EMPTY(&pp_data->pending_tasks_list)) {
+ TDM_BACKEND_DBG("pp %p(%d). Nothing to do", pp_data, pp_data->stamp);
+ return ret;
+ }
+ next_task = (tdm_sprd_pp_task *)container_of(pp_data->pending_tasks_list.next, next_task, link);
+ switch (next_task->status) {
+ case TASK_CONVERTING:
+ TDM_BACKEND_DBG("pp %p(%d). Still converting", pp_data, pp_data->stamp);
+ break;
+ case TASK_DONE:
+ case TASK_IGNORE:
+ LIST_DEL(&next_task->link);
+ _tdm_sprd_pp_destroy_task(pp_data, next_task);
+ return _tdm_sprd_pp_worker(pp_data);
+ case TASK_WAITING:
+ _set_task_status(next_task, TASK_CONVERTING);
+ if (_tdm_sprd_pp_queue(pp_data, next_task->roadmap.prop_id,
+ next_task->process_buffer.src,
+ next_task->process_buffer.dst,
+ IPP_BUF_ENQUEUE) != HAL_TDM_ERROR_NONE) {
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto fail_l;
+ }
+ if (_tdm_sprd_pp_cmd(pp_data,
+ next_task->roadmap.prop_id,
+ IPP_RUN) != HAL_TDM_ERROR_NONE) {
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto fail_l;
+ }
+ break;
+ default:
+ TDM_BACKEND_ERR("pp %p(%d). Never Get Here!", pp_data, pp_data->stamp);
+ ret = HAL_TDM_ERROR_NOT_IMPLEMENTED;
+ goto fail_l;
+ }
+ return ret;
+fail_l:
+ _tdm_sprd_pp_clear_queue(pp_data);
+ return ret;
+}
+
+void
+tdm_sprd_pp_handler(struct drm_sprd_ipp_event *hw_ipp_p)
+{
+ TDM_BACKEND_RETURN_IF_FAIL(hw_ipp_p);
+ tdm_sprd_pp_data *pp_data = (tdm_sprd_pp_data *)(unsigned long) hw_ipp_p->user_data;
+ tdm_sprd_pp_task *done_task = NULL;
+ if (!pp_data) {
+ TDM_BACKEND_ERR("invalid params");
+ return;
+ }
+
+ if (!_tdm_sprd_pp_check_struct(pp_data)) {
+ return;
+ }
+ if (pp_data->pp_need_destroy) {
+ TDM_BACKEND_DBG("pp %p Deferred event of delete", pp_data);
+ 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);
+ 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 (LIST_IS_EMPTY(&pp_data->pending_tasks_list)) {
+ TDM_BACKEND_ERR("pp %p(%d) received wrong event. Tasks_list is empty", pp_data, pp_data->stamp);
+ return;
+ }
+ done_task = (tdm_sprd_pp_task *)container_of(pp_data->pending_tasks_list.next, done_task, link);
+
+ if (done_task->status != TASK_CONVERTING) {
+ TDM_BACKEND_ERR("pp %p(%d) received wrong event. Task %p(%d) status is not converting (%u)",
+ pp_data, pp_data->stamp, done_task, done_task->stamp, done_task->status);
+ return;
+ }
+
+ if (done_task->roadmap.prop_id != hw_ipp_p->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->roadmap.prop_id, hw_ipp_p->prop_id);
+ return;
+ }
+ _set_task_status(done_task, TASK_DONE);
+ TDM_BACKEND_DBG("pp %p(%d). Task %p(%d) done", pp_data, pp_data->stamp, done_task, done_task->stamp);
+/*
+ if (pp_data->pp_need_destroy) {
+ TDM_BACKEND_DBG("pp %p(%d) Deferred event of delete", pp_data, pp_data->stamp);
+ _tdm_sprd_pp_destroy_task(pp_data, pp_data->current_task_p);
+ pp_data->current_task_p = NULL;
+ LIST_DEL(&pp_data->link);
+ free(pp_data);
+ return;
+ }
+*/
+ if (_tdm_sprd_pp_worker(pp_data) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("pp %p(%d) worker return ERROR", pp_data,
+ pp_data->stamp);
+ }
+}
+
+hal_tdm_error
+tdm_sprd_pp_get_capability(tdm_sprd_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 = 4;
+ caps->min_h = 4;
+ caps->max_w = -1; /* not defined */
+ caps->max_h = -1;
+ caps->preferred_align = 2;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_pp *
+tdm_sprd_pp_create(tdm_sprd_display *display_data, hal_tdm_error *error)
+{
+ tdm_sprd_pp_data *pp_data = calloc(1, sizeof(tdm_sprd_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_sprd_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);
+ if (error) {
+ *error = HAL_TDM_ERROR_NONE;
+ }
+ return pp_data;
+}
+
+void
+sprd_pp_destroy(hal_tdm_pp *pp)
+{
+ tdm_sprd_pp_data *pp_data = (tdm_sprd_pp_data *) pp;
+ tdm_sprd_pp_buffer *b = NULL, *bb = NULL;
+ tdm_sprd_pp_task *task = NULL, *next_task = NULL;
+ tdm_sprd_prop_id *prop_id = NULL, *next_prop_id = NULL;
+ TDM_BACKEND_RETURN_IF_FAIL(_tdm_sprd_pp_check_struct(pp_data));
+ TDM_BACKEND_DBG("pp %p(%d). Destroy", pp_data, pp_data->stamp);
+ pp_data->pp_need_destroy = 1;
+ LIST_FOR_EACH_ENTRY_SAFE(prop_id, next_prop_id, &pp_data->prop_id_list, link) {
+ _tdm_sprd_pp_cmd(pp_data, prop_id->prop_id, IPP_STOP);
+ }
+
+ LIST_FOR_EACH_ENTRY_SAFE(task, next_task, &pp_data->pending_tasks_list, link) {
+ LIST_DEL(&task->link);
+ _tdm_sprd_pp_destroy_task(pp_data, task);
+ }
+
+ LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
+ LIST_DEL(&b->link);
+ if (pp_data->done_func)
+ pp_data->done_func(pp_data, b->src, b->dst,
+ pp_data->done_user_data);
+ free(b);
+ }
+ TDM_BACKEND_DBG("pp %p(%d). Destroyed", pp_data, pp_data->stamp);
+ pp_data->stamp = 0;
+ LIST_DEL(&pp_data->link);
+ free(pp_data);
+}
+
+static hal_tdm_error
+_sprd_pp_check_ratio_limit(hal_tdm_info_pp *info)
+{
+ unsigned int
+ dst_height = (info->transform % 2) ? info->dst_config.pos.w : info->dst_config.pos.h,
+ dst_width = (info->transform % 2) ? info->dst_config.pos.h : info->dst_config.pos.w;
+
+ if (info->src_config.pos.w == 0 || info->src_config.pos.h == 0 || dst_height == 0 || dst_width == 0) {
+ TDM_BACKEND_ERR("Frame width or height is 0");
+ goto fail_l;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+fail_l:
+ TDM_BACKEND_ERR("src wxh(%ux%u) => dst wxh(%ux%u)", info->src_config.pos.w, info->src_config.pos.h,
+ info->dst_config.pos.w, info->dst_config.pos.h);
+ return HAL_TDM_ERROR_INVALID_PARAMETER;
+}
+
+static hal_tdm_error
+_sprd_pp_make_roadmap(tdm_sprd_pp_data *pp_data, hal_tdm_info_pp *info)
+{
+ if (_sprd_pp_check_ratio_limit(info) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("IPP Convertion out of range");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+ memcpy(&pp_data->new_roadmap.step_info, info, sizeof(hal_tdm_info_pp));
+ pp_data->new_roadmap.stamp = roadmap_stamp++;
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+sprd_pp_set_info(hal_tdm_pp *pp, hal_tdm_info_pp *info)
+{
+ tdm_sprd_pp_data *pp_data = (tdm_sprd_pp_data *) pp;
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(info, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(_tdm_sprd_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 (info->sync) {
+ TDM_BACKEND_ERR("pp %p(%d). not support sync mode currently", pp_data, pp_data->stamp);
+ return HAL_TDM_ERROR_INVALID_PARAMETER;
+ }
+ if (_sprd_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;
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+sprd_pp_attach(hal_tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
+{
+ tdm_sprd_pp_data *pp_data = (tdm_sprd_pp_data *) pp;
+ tdm_sprd_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_sprd_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_sprd_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;
+}
+
+static unsigned int*
+_tdm_sprd_pp_granulate(tdm_sprd_pp_data * pp_data, unsigned int src, unsigned int dst, unsigned int *array_size)
+{
+ if (!array_size || !src || !dst) {
+ TDM_BACKEND_ERR("pp %p(%d) Wrong arguments src(%u) dst(%u) size_p(%p)", pp_data, pp_data->stamp,
+ src, dst, array_size);
+ return NULL;
+ }
+ unsigned int i = 0, step = 0;
+ unsigned int temp_array[PP_MAX_STEP+1];
+
+ if (src < dst) {
+ step = src;
+ temp_array[i++] = step;
+ while (((step*PP_UP_RATIO) < dst)) {
+ step *= PP_UP_RATIO;
+ temp_array[i++] = step;
+ if (i >= (PP_MAX_STEP+1)) {
+ TDM_BACKEND_ERR("pp %p(%d) Can't scale. Reaching maximum iteration count %d", pp_data, pp_data->stamp,
+ PP_MAX_STEP);
+ return NULL;
+ }
+ }
+ temp_array[i++] = dst;
+ } else {
+ step = dst;
+ temp_array[i++] = step;
+ while (src > (step*PP_DOWN_RATIO)) {
+ step *= PP_DOWN_RATIO;
+ temp_array[i++] = step;
+ if (i >= (PP_MAX_STEP+1)) {
+ TDM_BACKEND_ERR("pp %p(%d) Can't scale. Reaching maximum iteration count %d", pp_data, pp_data->stamp,
+ PP_MAX_STEP);
+ return NULL;
+ }
+ }
+ temp_array[i++] = src;
+ }
+ *array_size = i;
+ unsigned int * ret_array = calloc((*array_size), sizeof(unsigned int));
+ if (ret_array == NULL) {
+ TDM_BACKEND_ERR("pp %p(%d) Out of memory", pp_data, pp_data->stamp);
+ return NULL;
+ }
+ for (i = 0; i < (*array_size); i++) {
+ if (src < dst) {
+ ret_array[i] = temp_array[i];
+ } else {
+ ret_array[i] = temp_array[(*array_size) - i - 1];
+ }
+ }
+ return ret_array;
+}
+
+static hal_tdm_error
+_tdm_sprd_pp_prepare_roadmap(tdm_sprd_pp_data * pp_data)
+{
+ if (pp_data->new_roadmap.stamp == 0) {
+ TDM_BACKEND_WRN("pp %p(%d) new roadmap is wrong", pp_data, pp_data->stamp);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+ TDM_BACKEND_DBG("pp %p(%d). Desired roadmap", pp_data, pp_data->stamp);
+ _tdm_sprd_pp_roadmap_print(&pp_data->new_roadmap);
+ hal_tdm_error ret_err = HAL_TDM_ERROR_NONE;
+ CLEAR(pp_data->current_roadmap);
+ unsigned int *foots_w = NULL, *foots_h = NULL, foots_w_size = 0, foots_h_size = 0, i = 0, k = 0, m = 0;
+ unsigned int
+ dst_height =
+ (pp_data->new_roadmap.step_info.transform % 2) ? pp_data->new_roadmap.step_info.dst_config.pos.w :
+ pp_data->new_roadmap.step_info.dst_config.pos.h,
+ dst_width =
+ (pp_data->new_roadmap.step_info.transform % 2) ? pp_data->new_roadmap.step_info.dst_config.pos.h :
+ pp_data->new_roadmap.step_info.dst_config.pos.w;
+ int cross_scale_flag = 0;
+ if ((pp_data->new_roadmap.step_info.src_config.pos.w > dst_width &&
+ pp_data->new_roadmap.step_info.src_config.pos.h < dst_height) ||
+ (pp_data->new_roadmap.step_info.src_config.pos.w < dst_width &&
+ pp_data->new_roadmap.step_info.src_config.pos.h > dst_height)) {
+ cross_scale_flag = 1;
+ }
+
+ foots_w = _tdm_sprd_pp_granulate(pp_data, pp_data->new_roadmap.step_info.src_config.pos.w,
+ dst_width, &foots_w_size);
+ if (!foots_w) {
+ TDM_BACKEND_ERR("pp %p(%d) Can't scale", pp_data, pp_data->stamp);
+ ret_err = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto done_l;
+ }
+ foots_h = _tdm_sprd_pp_granulate(pp_data, pp_data->new_roadmap.step_info.src_config.pos.h,
+ dst_height, &foots_h_size);
+ if (!foots_h) {
+ TDM_BACKEND_ERR("pp %p(%d) Can't scale", pp_data, pp_data->stamp);
+ ret_err = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto done_l;
+ }
+
+ if (cross_scale_flag == 0 && foots_w_size == 2 && foots_h_size == 2) {
+ memcpy(&pp_data->current_roadmap[0], &pp_data->new_roadmap, sizeof(tdm_sprd_pp_roadmap));
+ pp_data->roadmap_step = 1;
+ goto done_l;
+ }
+ memcpy(&pp_data->current_roadmap[0].step_info.src_config,
+ &pp_data->new_roadmap.step_info.src_config, sizeof(hal_tdm_info_config));
+ pp_data->current_roadmap[0].stamp = pp_data->new_roadmap.stamp;
+ if (cross_scale_flag == 0) {
+ if ((MAX(foots_h_size, foots_w_size) - 1) > PP_MAX_STEP) {
+ TDM_BACKEND_ERR("pp %p(%d) Can't scale. Reaching maximum iteration count %d", pp_data,
+ pp_data->stamp,
+ PP_MAX_STEP);
+ ret_err = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto done_l;
+ }
+ pp_data->roadmap_step = MAX(foots_h_size, foots_w_size) - 1;
+ for (i = 1; i < pp_data->roadmap_step; i++) {
+ pp_data->current_roadmap[i].stamp = roadmap_stamp++;
+ pp_data->current_roadmap[i-1].step_info.dst_config.format =
+ pp_data->current_roadmap[i-1].step_info.src_config.format;
+ pp_data->current_roadmap[i].step_info.src_config.format =
+ pp_data->current_roadmap[i-1].step_info.dst_config.format;
+ /*POS Height*/
+ if (i > (foots_h_size - 1)) {
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.h =
+ pp_data->current_roadmap[i-1].step_info.src_config.pos.h;
+ } else {
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.h = foots_h[i];
+ }
+ pp_data->current_roadmap[i].step_info.src_config.pos.h =
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.h;
+ /* Size Height*/
+ pp_data->current_roadmap[i-1].step_info.dst_config.size.v =
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.h;
+ pp_data->current_roadmap[i].step_info.src_config.size.v =
+ pp_data->current_roadmap[i-1].step_info.dst_config.size.v;
+ /* POS Width */
+ if (i > (foots_w_size - 1)) {
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.w =
+ pp_data->current_roadmap[i-1].step_info.src_config.pos.w;
+ } else {
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.w = foots_w[i];
+ }
+ pp_data->current_roadmap[i].step_info.src_config.pos.w =
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.w;
+ /* Size Width */
+ pp_data->current_roadmap[i-1].step_info.dst_config.size.h =
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.w;
+ pp_data->current_roadmap[i].step_info.src_config.size.h =
+ pp_data->current_roadmap[i-1].step_info.dst_config.size.h;
+ }
+ memcpy(&pp_data->current_roadmap[pp_data->roadmap_step - 1].step_info.dst_config,
+ &pp_data->new_roadmap.step_info.dst_config, sizeof(hal_tdm_info_config));
+ pp_data->current_roadmap[pp_data->roadmap_step - 1].step_info.transform =
+ pp_data->new_roadmap.step_info.transform;
+ }
+
+ if (cross_scale_flag == 1) {
+ if ((foots_w_size + foots_h_size - 2) > PP_MAX_STEP) {
+ TDM_BACKEND_ERR("pp %p(%d) Can't scale. Reaching maximum iteration count %d", pp_data, pp_data->stamp,
+ PP_MAX_STEP);
+ ret_err = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto done_l;
+ }
+ pp_data->roadmap_step = foots_w_size + foots_h_size - 2;
+ k = 1;
+ m = 1;
+ for (i = 1; i < pp_data->roadmap_step; i++) {
+ pp_data->current_roadmap[i].stamp = roadmap_stamp++;
+ pp_data->current_roadmap[i-1].step_info.dst_config.format =
+ pp_data->current_roadmap[i-1].step_info.src_config.format;
+ pp_data->current_roadmap[i].step_info.src_config.format =
+ pp_data->current_roadmap[i-1].step_info.dst_config.format;
+ if (k < foots_w_size) {
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.w = foots_w[k++];
+ pp_data->current_roadmap[i].step_info.src_config.pos.w =
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.w;
+ pp_data->current_roadmap[i-1].step_info.dst_config.size.h =
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.w;
+ pp_data->current_roadmap[i].step_info.src_config.size.h =
+ pp_data->current_roadmap[i-1].step_info.dst_config.size.h;
+
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.h =
+ pp_data->current_roadmap[i-1].step_info.src_config.pos.h;
+ pp_data->current_roadmap[i].step_info.src_config.pos.h =
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.h;
+ pp_data->current_roadmap[i-1].step_info.dst_config.size.v =
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.h;
+ pp_data->current_roadmap[i].step_info.src_config.size.v =
+ pp_data->current_roadmap[i-1].step_info.dst_config.size.v;
+ } else if (m < foots_h_size) {
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.h = foots_h[m++];
+ pp_data->current_roadmap[i].step_info.src_config.pos.h =
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.h;
+ pp_data->current_roadmap[i-1].step_info.dst_config.size.v =
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.h;
+ pp_data->current_roadmap[i].step_info.src_config.size.v =
+ pp_data->current_roadmap[i-1].step_info.dst_config.size.v;
+
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.w =
+ pp_data->current_roadmap[i-1].step_info.src_config.pos.w;
+ pp_data->current_roadmap[i].step_info.src_config.pos.w =
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.w;
+ pp_data->current_roadmap[i-1].step_info.dst_config.size.h =
+ pp_data->current_roadmap[i-1].step_info.dst_config.pos.w;
+ pp_data->current_roadmap[i].step_info.src_config.size.h =
+ pp_data->current_roadmap[i-1].step_info.dst_config.size.h;
+ } else {
+ TDM_BACKEND_ERR("pp %p(%d). Never Get Here!", pp_data, pp_data->stamp);
+ ret_err = HAL_TDM_ERROR_NOT_IMPLEMENTED;
+ goto done_l;
+ }
+ }
+ memcpy(&pp_data->current_roadmap[pp_data->roadmap_step - 1].step_info.dst_config,
+ &pp_data->new_roadmap.step_info.dst_config, sizeof(hal_tdm_info_config));
+ pp_data->current_roadmap[pp_data->roadmap_step - 1].step_info.transform =
+ pp_data->new_roadmap.step_info.transform;
+ }
+
+done_l:
+ if (foots_w)
+ free(foots_w);
+ if (foots_h)
+ free(foots_h);
+ return ret_err;
+}
+
+static hal_tdm_error
+_tdm_sprd_pp_commit_roadmap(tdm_sprd_pp_data * pp_data)
+{
+ tdm_sprd_pp_task * current_task = NULL;
+ tdm_sprd_prop_id *prop = NULL, *ignore_prop = NULL;
+ unsigned int prop_id = 0;
+ int current_step = 0;
+ if (!LIST_IS_EMPTY(&pp_data->pending_tasks_list)) {
+ current_task = (tdm_sprd_pp_task *)container_of(pp_data->pending_tasks_list.next, current_task, link);
+ }
+ if (current_task && current_task->status == TASK_CONVERTING) {
+ LIST_FOR_EACH_ENTRY(prop, &pp_data->prop_id_list, link) {
+ if (current_task->roadmap.stamp == prop->current_roadmap.stamp) {
+ ignore_prop = prop;
+ break;
+ }
+ }
+ }
+ prop = NULL;
+ LIST_FOR_EACH_ENTRY(prop, &pp_data->prop_id_list, link) {
+ if (current_step >= pp_data->roadmap_step)
+ break;
+ if (prop == ignore_prop)
+ continue;
+ if (current_step >= PP_MAX_STEP) {
+ TDM_BACKEND_ERR("pp %p(%d). Never get here!", pp_data, pp_data->stamp);
+ goto fail_l;
+ }
+ prop_id = _tdm_sprd_pp_set(pp_data, &pp_data->current_roadmap[current_step], prop->prop_id);
+ if (prop_id == 0) {
+ goto fail_l;
+ }
+ pp_data->current_roadmap[current_step].prop_id = prop_id;
+ current_step++;
+ }
+ while (current_step < pp_data->roadmap_step) {
+ if (current_step >= PP_MAX_STEP) {
+ TDM_BACKEND_ERR("pp %p(%d). Never get here!", pp_data, pp_data->stamp);
+ goto fail_l;
+ }
+ prop_id = _tdm_sprd_pp_set(pp_data, &pp_data->current_roadmap[current_step], 0);
+ if (prop_id == 0) {
+ goto fail_l;
+ }
+ pp_data->current_roadmap[current_step].prop_id = prop_id;
+ current_step++;
+ }
+ return HAL_TDM_ERROR_NONE;
+fail_l:
+ TDM_BACKEND_ERR("pp %p(%d). Can't setup converter", pp_data, pp_data->stamp);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+}
+
+hal_tdm_error
+sprd_pp_commit(hal_tdm_pp *pp)
+{
+ unsigned int i;
+ tdm_sprd_pp_data *pp_data = (tdm_sprd_pp_data *) pp;
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(_tdm_sprd_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) {
+ _tdm_sprd_pp_drop_queue(pp_data);
+ if (_tdm_sprd_pp_prepare_roadmap(pp_data) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("pp %p(%d). Can't create roadmap", pp_data, pp_data->stamp);
+ goto fail_l;
+ }
+ if (pp_data->roadmap_step > PP_MAX_STEP) {
+ TDM_BACKEND_ERR("pp %p(%d). Never Get Here!", pp_data, pp_data->stamp);
+ goto fail_l;
+ }
+ TDM_BACKEND_DBG("pp %p(%d). Resulted roadmap", pp_data, pp_data->stamp);
+ for (i = 0; i < pp_data->roadmap_step; i++) {
+ _tdm_sprd_pp_roadmap_print(&pp_data->current_roadmap[i]);
+ }
+ if (_tdm_sprd_pp_commit_roadmap(pp_data) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("pp %p(%d). Can't setup roadmap", pp_data, pp_data->stamp);
+ goto fail_l;
+ }
+ pp_data->roadmap_changed = 0;
+ }
+
+ if (pp_data->new_buffers == 1) {
+ if (_tdm_sprd_pp_make_tasks(pp_data) != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("pp %p(%d). Can't create new task", pp_data, pp_data->stamp);
+ goto fail_l;
+ }
+ pp_data->new_buffers = 0;
+ }
+
+ return _tdm_sprd_pp_worker(pp_data);
+fail_l:
+ _tdm_sprd_pp_clear_queue(pp_data);
+ if (pp_data->roadmap_changed) {
+ pp_data->new_roadmap.stamp = 0;
+ for (i = 0; i < PP_MAX_STEP; i++) {
+ pp_data->current_roadmap[i].stamp = 0;
+ }
+ pp_data->roadmap_changed = 0;
+ }
+ if (pp_data->new_buffers) {
+ tdm_sprd_pp_buffer *b = NULL, *bb = NULL;
+ LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
+ LIST_DEL(&b->link);
+ free(b);
+ }
+ pp_data->new_buffers = 0;
+ }
+ return HAL_TDM_ERROR_BAD_REQUEST;
+}
+
+hal_tdm_error
+sprd_pp_set_done_handler(hal_tdm_pp *pp, hal_tdm_pp_done_handler func, void *user_data)
+{
+ tdm_sprd_pp_data *pp_data = (tdm_sprd_pp_data *) pp;
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(_tdm_sprd_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;
+}