--- /dev/null
+Copyright (C) 2021 Samsung Electronics co., Ltd. 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 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.
--- /dev/null
+SUBDIRS = src
--- /dev/null
+#! /bin/sh
+
+test -n "$srcdir" || srcdir=`dirname "$0"`
+test -n "$srcdir" || srcdir=.
+autoreconf --force --install --verbose "$srcdir"
+test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
--- /dev/null
+AC_PREREQ([2.60])
+AC_INIT([libtdm-meson],
+ [0.1.0],
+ [https://www.tizen.org],
+ [libtdm-meson])
+
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_SRCDIR([Makefile.am])
+AM_INIT_AUTOMAKE([1.10 foreign dist-bzip2])
+AM_MAINTAINER_MODE([enable])
+
+# Check for programs
+AC_PROG_CC
+
+AC_USE_SYSTEM_EXTENSIONS
+AC_SYS_LARGEFILE
+AC_FUNC_ALLOCA
+
+# Initialize libtool
+LT_PREREQ([2.2])
+LT_INIT([disable-static])
+
+# Enable quiet compiles on automake 1.11.
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+# for libhal-backend-tdm-meson
+PKG_CHECK_MODULES(LIBHAL_BACKEND_TDM_MESON, hal-api-common hal-api-tdm libtbm libdrm dlog pixman-1)
+
+PKG_CHECK_MODULES(UDEV, libudev, [udev=yes], [udev=no])
+if test x"$udev" = xyes; then
+ AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection])
+
+ # for libhal-backend-tdm-meson
+ LIBHAL_BACKEND_TDM_MESON_CFLAGS="$LIBHAL_BACKEND_TDM_MESON_CFLAGS $UDEV_CFLAGS"
+ LIBHAL_BACKEND_TDM_MESON_LIBS="$LIBHAL_BACKEND_TDM_MESON_LIBS $UDEV_LIBS"
+fi
+
+# for libhal-backend-tdm-meson
+AC_SUBST(LIBHAL_BACKEND_TDM_MESON_CFLAGS)
+AC_SUBST(LIBHAL_BACKEND_TDM_MESON_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 tdm 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="$withval" ],
+ [ 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/Makefile])
+
+echo ""
+echo "$PACKAGE_STRING will be compiled with:"
+echo ""
+echo "TDM_MESON_CFLAGS : $LIBHAL_BACKEND_TDM_MESON_CFLAGS"
+echo "TDM_MESON_LIBS : $LIBHAL_BACKEND_TDM_MESON_LIBS"
+echo "TDM_MODULE_DIR : $HAL_LIBDIR"
+echo ""
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
--- /dev/null
+Name: libtdm-meson
+Version: 1.0.0
+Release: 0
+Summary: Tizen Display Manager Meson Back-End Library
+Group: Development/Libraries
+License: MIT
+Source0: %{name}-%{version}.tar.gz
+Source1001: libhal-backend-tdm-meson.manifest
+
+BuildRequires: pkgconfig(libdrm)
+BuildRequires: pkgconfig(libudev)
+BuildRequires: pkgconfig(libtdm)
+BuildRequires: pkgconfig(pixman-1)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(hal-api-common)
+BuildRequires: pkgconfig(hal-api-tdm)
+ExclusiveArch: %{arm} aarch64
+
+%description
+Back-End library of Tizen Display Manager MESON : libtdm-mgr MESON library
+
+%package -n hal-backend-tdm-meson
+Summary: hal-backend-tdm module for meson
+Group: System/Libraries
+Requires: hal-api-tdm
+Requires: hal-api-common
+
+%description -n hal-backend-tdm-meson
+descriptionion: hal tdm backend module for meson
+
+%global TZ_SYS_RO_SHARE %{?TZ_SYS_RO_SHARE:%TZ_SYS_RO_SHARE}%{!?TZ_SYS_RO_SHARE:/usr/share}
+
+%prep
+%setup -q
+cp %{SOURCE1001} .
+
+%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}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+%post
+if [ -f %{_hal_libdir}/libhal-backend-tdm.so ]; then
+ rm -rf %{_hal_libdir}/libhal-backend-tdm.so
+fi
+ln -s libhal-backend-tdm-meson.so %{_hal_libdir}/libhal-backend-tdm.so
+
+%postun -n hal-backend-tdm-meson -p /sbin/ldconfig
+
+%files
+%manifest libhal-backend-tdm-meson.manifest
+%license COPYING
+%{_hal_libdir}/libhal-backend-*.so*
--- /dev/null
+AM_CFLAGS = \
+ $(LIBHAL_BACKEND_TDM_MESON_CFLAGS) \
+ -I$(top_srcdir)/src/
+
+libhal_backend_tdm_meson_la_LTLIBRARIES = libhal-backend-tdm-meson.la
+libhal_backend_tdm_meson_ladir = @HAL_LIBDIR@
+libhal_backend_tdm_meson_la_LDFLAGS = -module -avoid-version
+libhal_backend_tdm_meson_la_LIBADD = $(LIBHAL_BACKEND_TDM_MESON_LIBS) -ldl
+
+libhal_backend_tdm_meson_la_SOURCES = \
+ tdm_backend_log.c \
+ tdm_backend_meson.c \
+ tdm_meson_display.c \
+ tdm_meson_format.c \
+ tdm_meson_hwc_window.c \
+ tdm_meson_hwc.c
--- /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
+/**************************************************************************
+
+libtdm_vc4
+
+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.
+
+**************************************************************************/
+
+#include "tdm_backend_log.h"
+
+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
+/**************************************************************************
+
+libtdm_vc4
+
+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>
+
+#undef LOG_TAG
+#define LOG_TAG "TDM_BACKEND"
+
+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
+/**************************************************************************
+
+libtdm_meson
+
+Copyright 2021 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: SooChan Lim <sc1.lim@samsung.com>,
+ Junkyeong Kim <jk0430.kim@samsung.com>,
+ Changyeon Lee <cyeon.lee@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.
+
+**************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_UDEV
+#include <libudev.h>
+#endif
+
+#include "tdm_backend_meson.h"
+
+#if HAVE_UDEV
+#include <libudev.h>
+#endif
+
+#define TDM_DRM_NAME "meson"
+
+#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;
+}
+
+static hal_tdm_error
+_tdm_meson_udev_fd_handler(int fd, hal_tdm_event_loop_mask mask, void *user_data)
+{
+ tdm_meson_display *display_data = (tdm_meson_display*)user_data;
+ struct udev_device *dev;
+ const char *hotplug;
+ struct stat s;
+ dev_t udev_devnum;
+ int ret;
+
+ dev = udev_monitor_receive_device(display_data->uevent_monitor);
+ if (!dev) {
+ TDM_BACKEND_ERR("couldn't receive device");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ udev_devnum = udev_device_get_devnum(dev);
+
+ ret = fstat(display_data->drm_fd, &s);
+ if (ret == -1) {
+ TDM_BACKEND_ERR("fstat failed");
+ udev_device_unref(dev);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ hotplug = udev_device_get_property_value(dev, "HOTPLUG");
+
+ if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
+ hotplug && atoi(hotplug) == 1) {
+ TDM_BACKEND_INFO("HotPlug");
+ tdm_meson_display_update_output_status(display_data);
+ }
+
+ udev_device_unref(dev);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+static struct udev_monitor *
+_tdm_meson_create_udev_monitor()
+{
+ struct udev *u = NULL;
+ struct udev_monitor *mon = NULL;
+
+ u = udev_new();
+ if (!u) {
+ TDM_BACKEND_ERR("couldn't create udev");
+ goto failed;
+ }
+
+ mon = udev_monitor_new_from_netlink(u, "udev");
+ if (!mon) {
+ TDM_BACKEND_ERR("couldn't create udev monitor");
+ goto failed;
+ }
+
+ if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") > 0 ||
+ udev_monitor_enable_receiving(mon) < 0) {
+ TDM_BACKEND_ERR("add match subsystem failed");
+ goto failed;
+ }
+
+ TDM_BACKEND_INFO("hotplug monitor created");
+
+ return mon;
+
+failed:
+ if (mon)
+ udev_monitor_unref(mon);
+ if (u)
+ udev_unref(u);
+
+ return NULL;
+}
+
+static void
+_tdm_meson_destroy_udev_monitor(struct udev_monitor *mon)
+{
+ struct udev *u;
+
+ if (!mon)
+ return;
+
+ u = udev_monitor_get_udev(mon);
+ udev_monitor_unref(mon);
+ udev_unref(u);
+
+ TDM_BACKEND_INFO("hotplug monitor destroyed");
+}
+#endif
+
+static int
+_tdm_meson_open_drm(void)
+{
+ int fd = -1;
+
+ fd = drmOpen(TDM_DRM_NAME, NULL);
+ if (fd < 0)
+ TDM_BACKEND_WRN("Cannot open '%s' drm", TDM_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
+
+ return fd;
+}
+
+static void
+_tdm_meson_display_deinitialize(tdm_meson_display *display_data)
+{
+ tdm_meson_display_destroy_output_list(display_data);
+ tdm_meson_display_destroy_buffer_list(display_data);
+
+ if (display_data->plane_res)
+ drmModeFreePlaneResources(display_data->plane_res);
+ if (display_data->mode_res)
+ drmModeFreeResources(display_data->mode_res);
+}
+
+static hal_tdm_error
+_tdm_meson_display_initialize(tdm_meson_display *display_data)
+{
+ hal_tdm_error ret;
+
+#if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
+ if (drmSetClientCap(display_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) {
+ TDM_BACKEND_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
+ } else {
+ TDM_BACKEND_INFO("has universal planes");
+ display_data->has_universal_plane = 1;
+ }
+ if (drmSetClientCap(display_data->drm_fd, DRM_CLIENT_CAP_ATOMIC, 1) < 0) {
+ TDM_BACKEND_WRN("Set DRM_CLIENT_CAP_ATOMIC failed");
+ } else {
+ TDM_BACKEND_INFO("has atomic");
+ display_data->has_atomic = 1;
+ }
+#endif
+
+ display_data->mode_res = drmModeGetResources(display_data->drm_fd);
+ if (!display_data->mode_res) {
+ TDM_BACKEND_ERR("no drm resource: %m");
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto failed;
+ }
+
+ display_data->plane_res = drmModeGetPlaneResources(display_data->drm_fd);
+ if (!display_data->plane_res) {
+ TDM_BACKEND_ERR("no drm plane resource: %m");
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto failed;
+ }
+
+ if (display_data->plane_res->count_planes <= 0) {
+ TDM_BACKEND_ERR("no drm plane resource");
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto failed;
+ }
+
+ ret = tdm_meson_display_create_output_list(display_data);
+ if (ret != HAL_TDM_ERROR_NONE)
+ goto failed;
+
+ ret = tdm_meson_display_create_layer_list(display_data);
+ if (ret != HAL_TDM_ERROR_NONE)
+ goto failed;
+
+
+ return ret;
+
+failed:
+ _tdm_meson_display_deinitialize(display_data);
+
+ return ret;
+}
+
+static hal_tdm_error
+_tdm_meson_master_drm_fd_handler(hal_tdm_fd master_drm_fd, void *user_data)
+{
+ tdm_meson_display *display_data = (tdm_meson_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_meson_display_initialize(display_data);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("fail to _tdm_meson_display_initialize!\n");
+
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+int
+hal_backend_tdm_meson_exit(void *data)
+{
+ hal_tdm_backend_data *backend_data = (hal_tdm_backend_data *)data;
+ tdm_meson_display *display_data;
+
+ TDM_BACKEND_INFO("deinit");
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(backend_data != NULL, -1);
+
+ display_data = (tdm_meson_display *)backend_data->display;
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data != NULL, -1);
+
+ if (backend_data->hwc_window_funcs) {
+ free(backend_data->hwc_window_funcs);
+ backend_data->hwc_window_funcs = NULL;
+ }
+ if (backend_data->hwc_funcs) {
+ free(backend_data->hwc_funcs);
+ backend_data->hwc_funcs = NULL;
+ }
+ if (backend_data->output_funcs) {
+ free(backend_data->output_funcs);
+ backend_data->output_funcs = NULL;
+ }
+ if (backend_data->display_funcs) {
+ free(backend_data->display_funcs);
+ backend_data->display_funcs = NULL;
+ }
+
+ _tdm_meson_display_deinitialize(display_data);
+
+#ifdef HAVE_UDEV
+ if (display_data->uevent_monitor)
+ _tdm_meson_destroy_udev_monitor(display_data->uevent_monitor);
+#endif
+
+ if (display_data->drm_fd >= 0)
+ close(display_data->drm_fd);
+
+ free(display_data);
+ display_data = NULL;
+
+ free(backend_data);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+static int
+hal_backend_tdm_meson_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;
+ tdm_meson_display *display_data = NULL;
+ hal_tdm_error ret;
+ int drm_fd;
+#ifdef HAVE_UDEV
+ static struct udev_monitor *mon;
+ hal_tdm_event_source *udev_event_source;
+#endif
+
+ /* 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_meson_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_meson_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_meson_display_initialize(display_data);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("fail to _tdm_meson_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_meson_master_drm_fd_handler;
+ backend_data->drm_info.user_data = display_data;
+
+ TDM_BACKEND_INFO("A backend requests an master drm_fd.\n");
+ }
+
+#ifdef HAVE_UDEV
+ mon = _tdm_meson_create_udev_monitor();
+ if (!mon) {
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto failed;
+ }
+ display_data->uevent_monitor = mon;
+
+ /* alloc and register udev_event_source */
+ udev_event_source = calloc(1, sizeof(struct _hal_tdm_event_source));
+ if (!udev_event_source) {
+ TDM_BACKEND_ERR("fail to alloc udev_event_source!\n");
+ goto failed;
+ }
+ udev_event_source->event_fd = udev_monitor_get_fd(mon);
+ udev_event_source->func = _tdm_meson_udev_fd_handler;
+ udev_event_source->user_data = display_data;
+
+ backend_data->event_sources[0] = udev_event_source;
+ backend_data->num_event_sources++;
+#endif
+
+ /* 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 = meson_display_get_capability;
+ display_funcs->display_get_outputs = meson_display_get_outputs;
+ display_funcs->display_get_fd = meson_display_get_fd;
+ display_funcs->display_handle_events = meson_display_handle_events;
+
+ /* 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 = meson_output_get_capability;
+ output_funcs->output_set_property = meson_output_set_property;
+ output_funcs->output_get_property = meson_output_get_property;
+ output_funcs->output_wait_vblank = meson_output_wait_vblank;
+ output_funcs->output_set_vblank_handler = meson_output_set_vblank_handler;
+ output_funcs->output_set_dpms = meson_output_set_dpms;
+ output_funcs->output_get_dpms = meson_output_get_dpms;
+ output_funcs->output_set_mode = meson_output_set_mode;
+ output_funcs->output_get_mode = meson_output_get_mode;
+#ifdef HAVE_UDEV
+ output_funcs->output_set_status_handler = meson_output_set_status_handler;
+#endif
+ output_funcs->output_get_hwc = meson_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 = meson_hwc_create_window;
+ hwc_funcs->hwc_get_video_supported_formats = meson_hwc_get_video_supported_formats;
+ hwc_funcs->hwc_get_video_available_properties = NULL;
+ hwc_funcs->hwc_get_capabilities = meson_hwc_get_capabilities;
+ hwc_funcs->hwc_get_available_properties = meson_hwc_get_available_properties;
+ hwc_funcs->hwc_get_client_target_buffer_queue = meson_hwc_get_client_target_buffer_queue;
+ hwc_funcs->hwc_set_client_target_buffer = meson_hwc_set_client_target_buffer;
+ hwc_funcs->hwc_set_client_target_acquire_fence = meson_hwc_set_client_target_acquire_fence;
+ hwc_funcs->hwc_validate = meson_hwc_validate;
+ hwc_funcs->hwc_get_changed_composition_types = meson_hwc_get_changed_composition_types;
+ hwc_funcs->hwc_accept_validation = meson_hwc_accept_validation;
+ hwc_funcs->hwc_commit = meson_hwc_commit;
+ hwc_funcs->hwc_set_commit_handler = meson_hwc_set_commit_handler;
+ hwc_funcs->hwc_get_commit_fence = meson_hwc_get_commit_fence;
+ hwc_funcs->hwc_get_release_fences = meson_hwc_get_release_fences;
+
+ /* alloc and register hwc_window_funcs */
+ hwc_window_funcs = calloc(1, sizeof(struct _hal_tdm_hwc_window_funcs));
+ if (!hwc_window_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 = meson_hwc_window_destroy;
+ hwc_window_funcs->hwc_window_acquire_buffer_queue = NULL; // no need
+ hwc_window_funcs->hwc_window_release_buffer_queue = NULL; // no need
+ hwc_window_funcs->hwc_window_set_composition_type = meson_hwc_window_set_composition_type;
+ hwc_window_funcs->hwc_window_set_buffer_damage = meson_hwc_window_set_buffer_damage;
+ hwc_window_funcs->hwc_window_set_info = meson_hwc_window_set_info;
+ hwc_window_funcs->hwc_window_set_buffer = meson_hwc_window_set_buffer;
+ hwc_window_funcs->hwc_window_set_property = meson_hwc_window_set_property;
+ hwc_window_funcs->hwc_window_get_property = meson_hwc_window_get_property;
+ hwc_window_funcs->hwc_window_get_constraints = meson_hwc_window_get_constraints;
+ hwc_window_funcs->hwc_window_set_name = meson_hwc_window_set_name;
+ hwc_window_funcs->hwc_window_set_cursor_image = meson_hwc_window_set_cursor_image;
+ hwc_window_funcs->hwc_window_set_acquire_fence = meson_hwc_window_set_acquire_fence;
+
+ TDM_BACKEND_INFO("init success!");
+
+ return HAL_TDM_ERROR_NONE;
+
+failed:
+ TDM_BACKEND_ERR("init failed!");
+
+ hal_backend_tdm_meson_exit((void *)backend_data);
+
+ return -1;
+}
+
+hal_backend hal_backend_tdm_data = {
+ "meson",
+ "Samsung",
+ HAL_ABI_VERSION_TIZEN_6_5,
+ hal_backend_tdm_meson_init,
+ hal_backend_tdm_meson_exit
+};
--- /dev/null
+/**************************************************************************
+
+libtdm_meson
+
+Copyright 2021 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: SooChan Lim <sc1.lim@samsung.com>,
+ Junkyeong Kim <jk0430.kim@samsung.com>,
+ Changyeon Lee <cyeon.lee@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_MESON_H_
+#define _TDM_MESON_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#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>
+#if HAVE_UDEV
+#include <libudev.h>
+#endif
+
+#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 "tdm_backend_meson_types.h"
+
+/* drm backend functions (display) */
+hal_tdm_error meson_display_get_capability(hal_tdm_display *display, hal_tdm_caps_display *caps);
+hal_tdm_output** meson_display_get_outputs(hal_tdm_display *display, int *count, hal_tdm_error *error);
+hal_tdm_error meson_display_get_fd(hal_tdm_display *display, int *fd);
+hal_tdm_error meson_display_handle_events(hal_tdm_display *display);
+hal_tdm_error meson_output_get_capability(hal_tdm_output *output, hal_tdm_caps_output *caps);
+hal_tdm_error meson_output_set_property(hal_tdm_output *output, unsigned int id, hal_tdm_value value);
+hal_tdm_error meson_output_get_property(hal_tdm_output *output, unsigned int id, hal_tdm_value *value);
+hal_tdm_error meson_output_wait_vblank(hal_tdm_output *output, int interval, int sync, void *user_data);
+hal_tdm_error meson_output_set_vblank_handler(hal_tdm_output *output, hal_tdm_output_vblank_handler func);
+hal_tdm_error meson_output_commit(hal_tdm_output *output, int sync, void *user_data);
+hal_tdm_error meson_output_set_commit_handler(hal_tdm_output *output, hal_tdm_output_commit_handler func);
+hal_tdm_error meson_output_set_dpms(hal_tdm_output *output, hal_tdm_output_dpms dpms_value);
+hal_tdm_error meson_output_get_dpms(hal_tdm_output *output, hal_tdm_output_dpms *dpms_value);
+hal_tdm_error meson_output_set_mode(hal_tdm_output *output, const hal_tdm_output_mode *mode);
+hal_tdm_error meson_output_get_mode(hal_tdm_output *output, const hal_tdm_output_mode **mode);
+hal_tdm_error meson_output_set_status_handler(hal_tdm_output *output, hal_tdm_output_status_handler func, void *user_data);
+hal_tdm_hwc *meson_output_get_hwc(hal_tdm_output *output, hal_tdm_error *error);
+
+hal_tdm_error meson_layer_get_capability(tdm_meson_layer *layer, tdm_meson_caps_layer *caps);
+hal_tdm_error meson_layer_set_property(tdm_meson_layer *layer, unsigned int id, hal_tdm_value value);
+hal_tdm_error meson_layer_get_property(tdm_meson_layer *layer, unsigned int id, hal_tdm_value *value);
+hal_tdm_error meson_layer_set_info(tdm_meson_layer *layer, tdm_meson_layer_info *info);
+hal_tdm_error meson_layer_get_info(tdm_meson_layer *layer, tdm_meson_layer_info *info);
+hal_tdm_error meson_layer_set_buffer(tdm_meson_layer *layer, tbm_surface_h buffer);
+hal_tdm_error meson_layer_unset_buffer(tdm_meson_layer *layer);
+hal_tdm_error meson_layer_get_buffer_flags(tdm_meson_layer *layer, unsigned int *flags);
+hal_tdm_error meson_layer_set_acquire_fence(tdm_meson_layer *layer, int acquire_fence);
+
+uint32_t tdm_meson_format_to_drm_format(tbm_format format);
+tbm_format tdm_meson_format_to_tbm_format(uint32_t format);
+
+void tdm_meson_display_update_output_status(tdm_meson_display *display_data);
+hal_tdm_error tdm_meson_display_create_output_list(tdm_meson_display *display_data);
+void tdm_meson_display_destroy_output_list(tdm_meson_display *display_data);
+hal_tdm_error tdm_meson_display_create_layer_list(tdm_meson_display *display_data);
+void tdm_meson_display_destroy_buffer_list(tdm_meson_display *display_data);
+
+
+tdm_meson_layer *meson_output_data_get_layer_data(tdm_meson_output *output_data, int layer_zops);
+
+hal_tdm_error meson_hwc_initialize_target_window(tdm_meson_hwc *hwc_data);
+hal_tdm_error meson_hwc_target_window_set_info(tdm_meson_hwc *hwc_data, int width, int height);
+
+hal_tdm_hwc_window *meson_hwc_create_window(hal_tdm_hwc *hwc, hal_tdm_error *error);
+hal_tdm_error meson_hwc_get_video_supported_formats(hal_tdm_hwc *hwc, const tbm_format **formats, int *count);
+hal_tdm_error meson_hwc_get_capabilities(hal_tdm_hwc *hwc, hal_tdm_hwc_capability *capabilities);
+hal_tdm_error meson_hwc_get_available_properties(hal_tdm_hwc *hwc, const hal_tdm_prop **props, int *count);
+tbm_surface_queue_h meson_hwc_get_client_target_buffer_queue(hal_tdm_hwc *hwc, hal_tdm_error *error);
+hal_tdm_error meson_hwc_set_client_target_buffer(hal_tdm_hwc *hwc, tbm_surface_h buffer, hal_tdm_region damage);
+hal_tdm_error meson_hwc_set_client_target_acquire_fence(hal_tdm_hwc *hwc, int acquire_fence);
+hal_tdm_error meson_hwc_validate(hal_tdm_hwc *hwc, hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types);
+hal_tdm_error meson_hwc_get_changed_composition_types(hal_tdm_hwc *hwc, uint32_t *num_elements, hal_tdm_hwc_window **hwc_wnds, hal_tdm_hwc_window_composition *composition_types);
+hal_tdm_error meson_hwc_accept_validation(hal_tdm_hwc *hwc);
+hal_tdm_error meson_hwc_commit(hal_tdm_hwc *hwc, int sync, void *user_data);
+hal_tdm_error meson_hwc_set_commit_handler(hal_tdm_hwc *hwc, hal_tdm_hwc_commit_handler func);
+hal_tdm_error meson_hwc_get_commit_fence(hal_tdm_hwc *hwc, int *fence);
+hal_tdm_error meson_hwc_get_release_fences(hal_tdm_hwc *hwc, uint32_t *num_elements, hal_tdm_hwc_window **hwc_window, int *fences);
+
+void meson_hwc_window_destroy(hal_tdm_hwc_window *hwc_window);
+hal_tdm_error meson_hwc_window_set_composition_type(hal_tdm_hwc_window *hwc_window, hal_tdm_hwc_window_composition composition_type);
+hal_tdm_error meson_hwc_window_set_buffer_damage(hal_tdm_hwc_window *hwc_window, hal_tdm_region damage);
+hal_tdm_error meson_hwc_window_set_info(hal_tdm_hwc_window *hwc_window, hal_tdm_hwc_window_info *info);
+hal_tdm_error meson_hwc_window_set_buffer(hal_tdm_hwc_window *hwc_window, tbm_surface_h surface);
+hal_tdm_error meson_hwc_window_set_property(hal_tdm_hwc_window *hwc_window, unsigned int id, hal_tdm_value value);
+hal_tdm_error meson_hwc_window_get_property(hal_tdm_hwc_window *hwc_window, unsigned int id, hal_tdm_value *value);
+hal_tdm_error meson_hwc_window_get_constraints(hal_tdm_hwc_window *hwc_window, int *constraints);
+hal_tdm_error meson_hwc_window_set_name(hal_tdm_hwc_window *hwc_window, const char *name);
+hal_tdm_error meson_hwc_window_set_cursor_image(hal_tdm_hwc_window *hwc_window, int width, int height, int stride, void *ptr);
+hal_tdm_error meson_hwc_window_set_acquire_fence(hal_tdm_hwc_window *hwc_window, int acquire_fence);
+
+#endif /* _TDM_MESON_H_ */
--- /dev/null
+/**************************************************************************
+
+libtdm_meson
+
+Copyright 2021 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: SooChan Lim <sc1.lim@samsung.com>,
+ Junkyeong Kim <jk0430.kim@samsung.com>,
+ Changyeon Lee <cyeon.lee@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_meson_TYPES_H_
+#define _TDM_meson_TYPES_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <linux/fb.h>
+#include <drm.h>
+#include <drm_fourcc.h>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <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 "tdm_backend_log.h"
+#include "tdm_backend_list.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 ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#define RETURN_VAL_IF_FAIL(cond, val) {\
+ if (!(cond)) {\
+ TDM_ERR("'%s' failed", #cond);\
+ return val;\
+ } \
+}
+
+#define RETURN_IF_FAIL(cond) {\
+ if (!(cond)) {\
+ TDM_ERR("'%s' failed", #cond);\
+ return;\
+ } \
+}
+
+#define GOTO_IF_FAIL(cond, val) {\
+ if (!(cond)) {\
+ TDM_ERR("'%s' failed", #cond);\
+ goto val;\
+ } \
+}
+
+typedef struct _tdm_meson_display tdm_meson_display;
+typedef struct _tdm_meson_output tdm_meson_output;
+typedef struct _tdm_meson_layer tdm_meson_layer;
+typedef struct _tdm_meson_hwc tdm_meson_hwc;
+typedef struct _tdm_meson_hwc_window tdm_meson_hwc_window;
+typedef struct _tdm_meson_event tdm_meson_event;
+typedef struct _tdm_meson_display_buffer tdm_meson_display_buffer;
+
+typedef enum {
+ TDM_DRM_EVENT_TYPE_WAIT,
+ TDM_DRM_EVENT_TYPE_COMMIT,
+ TDM_DRM_EVENT_TYPE_PAGEFLIP,
+} tdm_meson_event_type;
+
+typedef enum {
+ TDM_MESON_LAYER_CAPABILITY_CURSOR = (1 << 0), /**< cursor */
+ TDM_MESON_LAYER_CAPABILITY_PRIMARY = (1 << 1), /**< primary */
+ TDM_MESON_LAYER_CAPABILITY_OVERLAY = (1 << 2), /**< overlay */
+ TDM_MESON_LAYER_CAPABILITY_GRAPHIC = (1 << 4), /**< graphic */
+ TDM_MESON_LAYER_CAPABILITY_VIDEO = (1 << 5), /**< video */
+ TDM_MESON_LAYER_CAPABILITY_SCALE = (1 << 8), /**< if a layer_data has scale capability */
+ TDM_MESON_LAYER_CAPABILITY_TRANSFORM = (1 << 9), /**< if a layer_data has transform capability */
+ TDM_MESON_LAYER_CAPABILITY_SCANOUT = (1 << 10), /**< if a layer_data allows a scanout buffer only */
+ TDM_MESON_LAYER_CAPABILITY_RESEVED_MEMORY = (1 << 11), /**< if a layer_data allows a reserved buffer only */
+ TDM_MESON_LAYER_CAPABILITY_NO_CROP = (1 << 12), /**< if a layer_data has no cropping capability */
+} tdm_meson_layer_capability;
+
+struct _tdm_meson_display {
+ int drm_fd;
+
+#if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
+ int has_universal_plane;
+ int has_atomic;
+#endif
+
+#if HAVE_UDEV
+ struct udev_monitor *uevent_monitor;
+#endif
+
+ drmModeResPtr mode_res;
+ drmModePlaneResPtr plane_res;
+
+ struct list_head output_list;
+ struct list_head buffer_list;
+};
+
+struct _tdm_meson_display_buffer {
+ struct list_head link;
+
+ unsigned int fb_id;
+ tbm_surface_h buffer;
+ int width;
+ unsigned int height;
+ unsigned int format;
+ unsigned int handles[4];
+ unsigned int fds[4];
+ unsigned int pitches[4];
+ unsigned int offsets[4];
+ unsigned int size;
+ unsigned int count;
+};
+
+struct _tdm_meson_event {
+ tdm_meson_event_type type;
+ tdm_meson_output *output_data;
+ void *user_data;
+};
+
+struct display_properties_ids {
+ uint32_t connector_crtc_id;
+ uint32_t crtc_mode_id;
+ uint32_t crtc_active;
+ uint32_t plane_fb_id;
+ uint32_t plane_crtc_id;
+ uint32_t plane_src_x;
+ uint32_t plane_src_y;
+ uint32_t plane_src_w;
+ uint32_t plane_src_h;
+ uint32_t plane_crtc_x;
+ uint32_t plane_crtc_y;
+ uint32_t plane_crtc_w;
+ uint32_t plane_crtc_h;
+ uint32_t plane_zpos;
+};
+
+struct _tdm_meson_output {
+ struct list_head link;
+
+ /* data which are fixed at initializing */
+ tdm_meson_display *display_data;
+ uint32_t connector_id;
+ uint32_t encoder_id;
+ uint32_t crtc_id;
+ uint32_t pipe;
+ uint32_t dpms_prop_id;
+ int count_modes;
+ int count_drm_modes;
+ drmModeModeInfoPtr meson_modes;
+ hal_tdm_output_mode *output_modes;
+ hal_tdm_output_type connector_type;
+ unsigned int connector_type_id;
+ struct list_head layer_list;
+ int layer_count;
+ tdm_meson_layer *primary_layer;
+ int primary_zpos;
+
+ /* not fixed data below */
+ hal_tdm_output_vblank_handler vblank_func;
+ hal_tdm_output_commit_handler commit_func;
+
+ hal_tdm_output_conn_status status;
+ hal_tdm_output_status_handler status_func;
+ void *status_user_data;
+
+ int mode_changed;
+ const hal_tdm_output_mode *current_mode;
+ unsigned int current_mode_blob_id;
+
+ int crtc_enabled;
+
+ uint32_t output_plane;
+ struct display_properties_ids props;
+
+ /* hwc */
+ tdm_meson_hwc *hwc_data;
+
+ /* atomic prop ids*/
+ struct {
+ uint32_t crtc_id;
+ uint32_t crtc_mode_id;
+ uint32_t crtc_active;
+ uint32_t out_fence_ptr;
+ } atomic_props_ids;
+
+ int commit_fence;
+};
+
+typedef struct _tdm_layer_info {
+ hal_tdm_info_config src_config;
+ hal_tdm_pos dst_pos;
+ hal_tdm_transform transfrom;
+} tdm_meson_layer_info;
+
+typedef struct _tdm_caps_layer {
+ tdm_meson_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_meson_caps_layer;
+
+struct _tdm_meson_layer {
+ struct list_head link;
+
+ /* data which are fixed at initializing */
+ tdm_meson_display *display_data;
+ tdm_meson_output *output_data;
+ uint32_t plane_id;
+ tdm_meson_layer_capability capabilities;
+ int zpos;
+
+ /* not fixed data below */
+ tdm_meson_layer_info info;
+ int info_changed;
+
+ tdm_meson_display_buffer *display_buffer;
+ int display_buffer_changed;
+
+ /* atomic prop ids*/
+ struct {
+ uint32_t fb_id;
+ uint32_t crtc_id;
+ uint32_t src_x;
+ uint32_t src_y;
+ uint32_t src_w;
+ uint32_t src_h;
+ uint32_t crtc_x;
+ uint32_t crtc_y;
+ uint32_t crtc_w;
+ uint32_t crtc_h;
+ uint32_t zpos;
+ uint32_t in_fence_fd;
+ } atomic_props_ids;
+
+ int acquire_fence;
+};
+
+struct _tdm_meson_hwc {
+ tdm_meson_hwc_window *target_hwc_window;
+
+ int need_validate;
+ int need_target_window;
+ int need_set_crtc;
+
+ int target_window_zpos;
+
+ tdm_meson_output *output_data;
+ struct list_head hwc_window_list;
+
+ tbm_surface_queue_h cursor_tqueue;
+ tbm_surface_h cursor_tsurface;
+
+ hal_tdm_hwc_commit_handler commit_func;
+};
+
+struct _tdm_meson_hwc_window {
+ struct list_head link;
+
+ tdm_meson_hwc *hwc_data;
+
+ hal_tdm_hwc_window_info info;
+ tbm_surface_h surface;
+ hal_tdm_hwc_window_composition client_type;
+ hal_tdm_hwc_window_composition validated_type;
+ int lzpos;
+
+ char name[HAL_TDM_NAME_LEN];
+ struct {
+ int width;
+ int height;
+ int stride;
+ void *ptr;
+ } cursor_img;
+ int cursor_img_surface;
+ int cursor_img_refresh;
+
+ int acquire_fence;
+};
+
+#endif /* _TDM_MESON_TYPES_H_ */
--- /dev/null
+/**************************************************************************
+
+libtdm_meson
+
+Copyright 2021 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: SooChan Lim <sc1.lim@samsung.com>,
+ Junkyeong Kim <jk0430.kim@samsung.com>,
+ Changyeon Lee <cyeon.lee@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.
+
+**************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_meson.h"
+
+static drmModeModeInfoPtr
+_tdm_meson_display_get_mode(tdm_meson_output *output_data)
+{
+ int i;
+
+ if (!output_data->current_mode) {
+ TDM_BACKEND_ERR("no output_data->current_mode");
+ return NULL;
+ }
+
+ const hal_tdm_output_mode *mode;
+
+ mode = output_data->current_mode;
+ TDM_BACKEND_INFO("Current mode: %s, %d, %d, %d, %d, %d",
+ mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags, mode->type);
+
+
+ TDM_BACKEND_INFO(" Count modes: %d %d", output_data->count_drm_modes, output_data->count_modes);
+
+ for (i = 0; i < output_data->count_drm_modes; i++) {
+ drmModeModeInfoPtr meson_mode = &output_data->meson_modes[i];
+
+ TDM_BACKEND_INFO(" DRM mode: %s, %d, %d, %d, %d, %d",
+ meson_mode->name, meson_mode->hdisplay, meson_mode->vdisplay, meson_mode->vrefresh, meson_mode->flags, meson_mode->type);
+
+ if ((meson_mode->hdisplay == output_data->current_mode->hdisplay) &&
+ (meson_mode->hsync_start == output_data->current_mode->hsync_start) &&
+ (meson_mode->hsync_end == output_data->current_mode->hsync_end) &&
+ (meson_mode->htotal == output_data->current_mode->htotal) &&
+ (meson_mode->hskew == output_data->current_mode->hskew) &&
+ (meson_mode->vdisplay == output_data->current_mode->vdisplay) &&
+ (meson_mode->vsync_start == output_data->current_mode->vsync_start) &&
+ (meson_mode->vsync_end == output_data->current_mode->vsync_end) &&
+ (meson_mode->vtotal == output_data->current_mode->vtotal) &&
+ (meson_mode->vscan == output_data->current_mode->vscan) &&
+ (meson_mode->clock == output_data->current_mode->clock) &&
+ (meson_mode->vrefresh == output_data->current_mode->vrefresh) &&
+ (meson_mode->flags == output_data->current_mode->flags) &&
+ (meson_mode->type == output_data->current_mode->type) &&
+ !(strncmp(meson_mode->name, output_data->current_mode->name, HAL_TDM_NAME_LEN)))
+ return meson_mode;
+ }
+
+ return NULL;
+}
+
+static hal_tdm_error
+_tdm_meson_output_update_status(tdm_meson_output *output_data,
+ hal_tdm_output_conn_status status)
+{
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ if (output_data->status == status)
+ return HAL_TDM_ERROR_NONE;
+
+ output_data->status = status;
+
+ if (output_data->status_func)
+ output_data->status_func(output_data, status,
+ output_data->status_user_data);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+static void
+_tdm_meson_display_to_tdm_mode(drmModeModeInfoPtr meson_mode,
+ hal_tdm_output_mode *tdm_mode)
+{
+ tdm_mode->clock = meson_mode->clock;
+ tdm_mode->hdisplay = meson_mode->hdisplay;
+ tdm_mode->hsync_start = meson_mode->hsync_start;
+ tdm_mode->hsync_end = meson_mode->hsync_end;
+ tdm_mode->htotal = meson_mode->htotal;
+ tdm_mode->hskew = meson_mode->hskew;
+ tdm_mode->vdisplay = meson_mode->vdisplay;
+ tdm_mode->vsync_start = meson_mode->vsync_start;
+ tdm_mode->vsync_end = meson_mode->vsync_end;
+ tdm_mode->vtotal = meson_mode->vtotal;
+ tdm_mode->vscan = meson_mode->vscan;
+ tdm_mode->vrefresh = meson_mode->vrefresh;
+ tdm_mode->flags = meson_mode->flags;
+ tdm_mode->type = meson_mode->type;
+ snprintf(tdm_mode->name, HAL_TDM_NAME_LEN, "%s", meson_mode->name);
+}
+
+static hal_tdm_error
+_tdm_meson_display_get_cur_msc(int fd, int pipe, uint *msc)
+{
+ drmVBlank vbl;
+
+ vbl.request.type = DRM_VBLANK_RELATIVE;
+ if (pipe == 1)
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ else if (pipe > 1)
+ vbl.request.type |= pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
+
+ vbl.request.sequence = 0;
+ if (drmWaitVBlank(fd, &vbl)) {
+ TDM_BACKEND_ERR("get vblank counter failed: %m");
+ *msc = 0;
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ *msc = vbl.reply.sequence;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_tdm_meson_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data)
+{
+ drmVBlank vbl;
+
+ vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
+ if (pipe == 1)
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ else if (pipe > 1)
+ vbl.request.type |= pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
+
+ vbl.request.sequence = *target_msc;
+ vbl.request.signal = (unsigned long)(uintptr_t)data;
+
+ if (drmWaitVBlank(fd, &vbl)) {
+ TDM_BACKEND_ERR("wait vblank failed: %m");
+ *target_msc = 0;
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ *target_msc = vbl.reply.sequence;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+
+static hal_tdm_error
+_tdm_meson_output_commit_primary_layer(tdm_meson_layer *layer_data,
+ void *user_data, int *do_waitvblank)
+{
+ tdm_meson_display *display_data = layer_data->display_data;
+ tdm_meson_output *output_data = layer_data->output_data;
+
+ if ((!output_data->crtc_enabled || output_data->mode_changed) &&
+ (layer_data->display_buffer_changed)) {
+ tdm_meson_layer_info layer_info = layer_data->info;
+ drmModeModeInfoPtr mode;
+
+ if (!layer_data->display_buffer) {
+ TDM_BACKEND_ERR("primary layer should have a buffer for modestting");
+ return HAL_TDM_ERROR_BAD_REQUEST;
+ }
+
+ output_data->mode_changed = 0;
+ layer_data->display_buffer_changed = 0;
+ layer_data->info_changed = 0;
+
+ mode = _tdm_meson_display_get_mode(output_data);
+ if (!mode) {
+ TDM_BACKEND_ERR("couldn't find proper mode");
+ return HAL_TDM_ERROR_BAD_REQUEST;
+ }
+
+ TDM_BACKEND_DBG("SetCrtc: drm_fd(%d) crtc_id(%u) fb_id(%u) mode(%ux%u, %uhz) pos(%u %u)",
+ display_data->drm_fd, output_data->crtc_id, layer_data->display_buffer->fb_id,
+ mode->hdisplay, mode->vdisplay, mode->vrefresh,
+ layer_info.src_config.pos.x, layer_info.src_config.pos.y);
+
+ if (drmModeSetCrtc(display_data->drm_fd, output_data->crtc_id,
+ layer_data->display_buffer->fb_id,
+ layer_info.src_config.pos.x, layer_info.src_config.pos.y,
+ &output_data->connector_id, 1, mode)) {
+ TDM_BACKEND_ERR("set crtc failed: %m");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ _tdm_meson_output_update_status(output_data, HAL_TDM_OUTPUT_CONN_STATUS_MODE_SETTED);
+
+ *do_waitvblank = 1;
+
+ return HAL_TDM_ERROR_NONE;
+ } else if (layer_data->display_buffer_changed) {
+ layer_data->display_buffer_changed = 0;
+
+ if (layer_data->display_buffer) {
+ tdm_meson_event *event_data = calloc(1, sizeof(tdm_meson_event));
+
+ if (!event_data) {
+ TDM_BACKEND_ERR("alloc failed");
+ return HAL_TDM_ERROR_OUT_OF_MEMORY;
+ }
+ event_data->type = TDM_DRM_EVENT_TYPE_PAGEFLIP;
+ event_data->output_data = output_data;
+ event_data->user_data = user_data;
+
+ TDM_BACKEND_DBG("PageFlip: drm_fd(%d) crtc_id(%u) fb_id(%u)",
+ display_data->drm_fd, output_data->crtc_id,
+ layer_data->display_buffer->fb_id);
+
+ if (drmModePageFlip(display_data->drm_fd, output_data->crtc_id,
+ layer_data->display_buffer->fb_id, DRM_MODE_PAGE_FLIP_EVENT, event_data)) {
+ TDM_BACKEND_ERR("pageflip failed: %m");
+ free(event_data);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+ *do_waitvblank = 0;
+ } else {
+ /* to call a user commit handler whenever committed */
+ *do_waitvblank = 1;
+ }
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_tdm_meson_display_commit_layer(tdm_meson_layer *layer_data)
+{
+ tdm_meson_display *display_data = layer_data->display_data;
+ tdm_meson_output *output_data = layer_data->output_data;
+ uint32_t fx, fy, fw, fh;
+
+ layer_data->display_buffer_changed = 0;
+ layer_data->info_changed = 0;
+
+ if (!layer_data->display_buffer) {
+ if (drmModeSetPlane(display_data->drm_fd, layer_data->plane_id,
+ output_data->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
+ TDM_BACKEND_ERR("unset plane(%d) filed: %m", layer_data->plane_id);
+
+ return HAL_TDM_ERROR_NONE;
+ }
+
+ /* Source values are 16.16 fixed point */
+ fx = ((unsigned int)layer_data->info.src_config.pos.x) << 16;
+ fy = ((unsigned int)layer_data->info.src_config.pos.y) << 16;
+ fw = ((unsigned int)layer_data->info.src_config.pos.w) << 16;
+ fh = ((unsigned int)layer_data->info.src_config.pos.h) << 16;
+
+ if (drmModeSetPlane(display_data->drm_fd, layer_data->plane_id,
+ output_data->crtc_id, layer_data->display_buffer->fb_id, 0,
+ layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
+ layer_data->info.dst_pos.w, layer_data->info.dst_pos.h,
+ fx, fy, fw, fh) < 0) {
+ TDM_BACKEND_ERR("set plane(%d) failed: %m", layer_data->plane_id);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ TDM_BACKEND_DBG("plane(%d) crtc(%d) pos(%d) on: fb(%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n",
+ layer_data->plane_id, output_data->crtc_id, layer_data->zpos,
+ layer_data->display_buffer->fb_id,
+ layer_data->info.src_config.pos.x, layer_data->info.src_config.pos.y,
+ layer_data->info.src_config.pos.w, layer_data->info.src_config.pos.h,
+ layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
+ layer_data->info.dst_pos.w, layer_data->info.dst_pos.h);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+static void
+_tdm_meson_display_cb_event(int fd, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec,
+ void *user_data)
+{
+ tdm_meson_event *event_data = user_data;
+ tdm_meson_output *output_data;
+ tdm_meson_hwc *hwc_data;
+
+
+ if (!event_data) {
+ TDM_BACKEND_ERR("no event data");
+ return;
+ }
+
+ output_data = event_data->output_data;
+
+
+ TDM_BACKEND_DBG("==== Atomic Commit Handler pipe, %u, crtc_id, %u connector_id, %u",
+ output_data->pipe, output_data->crtc_id, output_data->connector_id);
+
+ switch (event_data->type) {
+ case TDM_DRM_EVENT_TYPE_PAGEFLIP:
+ if (output_data->commit_func)
+ output_data->commit_func(output_data, sequence, tv_sec, tv_usec,
+ event_data->user_data);
+ break;
+ case TDM_DRM_EVENT_TYPE_WAIT:
+ if (output_data->vblank_func)
+ output_data->vblank_func(output_data, sequence, tv_sec, tv_usec,
+ event_data->user_data);
+ break;
+ case TDM_DRM_EVENT_TYPE_COMMIT:
+ hwc_data = output_data->hwc_data;
+ if (!hwc_data) {
+ TDM_BACKEND_ERR("no hwc_data");
+ break;
+ }
+
+ if (hwc_data->commit_func)
+ hwc_data->commit_func(hwc_data, sequence,
+ tv_sec, tv_usec,
+ event_data->user_data);
+ break;
+ default:
+ break;
+ }
+
+ free(event_data);
+}
+
+static hal_tdm_error
+_meson_output_get_atomic_prop_id(int drm_fd, uint32_t object_id, uint32_t object_type, const char *name, uint32_t *id)
+{
+ drmModeObjectPropertiesPtr properties = NULL;
+ drmModePropertyPtr property = NULL;
+ int i;
+
+ properties = drmModeObjectGetProperties(drm_fd, object_id, object_type);
+ if (properties == NULL) {
+ TDM_BACKEND_ERR("drmModeObjectGetProperties failed");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ for (i = 0; i < properties->count_props; i++) {
+ property = drmModeGetProperty(drm_fd, properties->props[i]);
+ if (property == NULL) {
+ continue;
+ }
+
+ if (strcmp(property->name, name) == 0) {
+ *id = property->prop_id;
+ drmModeFreeProperty(property);
+ break;
+ }
+ drmModeFreeProperty(property);
+ }
+
+ drmModeFreeObjectProperties(properties);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_tdm_meson_display_create_layer_list(tdm_meson_display *display_data)
+{
+ tdm_meson_output *output_data = NULL;
+ int i;
+
+ if (LIST_IS_EMPTY(&display_data->output_list)) {
+ TDM_BACKEND_ERR("no output");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ output_data = LIST_FIRST_ENTRY(&display_data->output_list, tdm_meson_output, link);
+ if (!output_data) {
+ TDM_BACKEND_ERR("fail to get output");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ if (display_data->plane_res->count_planes == 0) {
+ TDM_BACKEND_ERR("no layer error");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ for (i = 0; i < display_data->plane_res->count_planes; i++) {
+ tdm_meson_layer *layer_data;
+ drmModePlanePtr plane;
+
+ plane = drmModeGetPlane(display_data->drm_fd, display_data->plane_res->planes[i]);
+ if (!plane) {
+ TDM_BACKEND_ERR("no plane");
+ continue;
+ }
+
+ if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
+ drmModeFreePlane(plane);
+ continue;
+ }
+
+ layer_data = calloc(1, sizeof(tdm_meson_layer));
+ if (!layer_data) {
+ TDM_BACKEND_ERR("alloc failed");
+ drmModeFreePlane(plane);
+ continue;
+ }
+
+ layer_data->display_data = display_data;
+ layer_data->output_data = output_data;
+ layer_data->plane_id = display_data->plane_res->planes[i];
+ layer_data->acquire_fence = -1;
+
+ layer_data->capabilities = TDM_MESON_LAYER_CAPABILITY_PRIMARY |
+ TDM_MESON_LAYER_CAPABILITY_GRAPHIC;
+ output_data->primary_layer = layer_data;
+
+ TDM_BACKEND_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) capabilities(%x)",
+ layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
+ layer_data->capabilities);
+
+ LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
+
+ drmModeFreePlane(plane);
+
+ /* can't take care of other planes for various hardware devices */
+ break;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+#if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
+
+static hal_tdm_error
+_tdm_meson_display_get_property(tdm_meson_display *display_data,
+ unsigned int obj_id, unsigned int obj_type,
+ const char *name, unsigned int *value,
+ int *is_immutable)
+{
+ drmModeObjectPropertiesPtr props = NULL;
+ int i;
+
+ props = drmModeObjectGetProperties(display_data->drm_fd, obj_id, obj_type);
+ if (!props)
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+
+ for (i = 0; i < props->count_props; i++) {
+ drmModePropertyPtr prop = drmModeGetProperty(display_data->drm_fd,
+ props->props[i]);
+
+ if (!prop)
+ continue;
+
+ if (!strcmp(prop->name, name)) {
+ if (is_immutable)
+ *is_immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
+ if (value)
+ *value = (unsigned int)props->prop_values[i];
+ drmModeFreeProperty(prop);
+ drmModeFreeObjectProperties(props);
+ return HAL_TDM_ERROR_NONE;
+ }
+
+ drmModeFreeProperty(prop);
+ }
+ drmModeFreeObjectProperties(props);
+ TDM_BACKEND_DBG("coundn't find '%s' property", name);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+}
+
+static hal_tdm_error
+_tdm_meson_display_create_layer_list_type(tdm_meson_display *display_data)
+{
+ drmModePlanePtr plane;
+ hal_tdm_error ret;
+ int i;
+
+ for (i = 0; i < display_data->plane_res->count_planes; i++) {
+ tdm_meson_output *output_data = NULL;
+ tdm_meson_layer *layer_data;
+ unsigned int type = 0;
+ int output_find = 0;
+
+ plane = drmModeGetPlane(display_data->drm_fd, display_data->plane_res->planes[i]);
+ if (!plane) {
+ TDM_BACKEND_ERR("no plane");
+ continue;
+ }
+
+ ret = _tdm_meson_display_get_property(display_data,
+ display_data->plane_res->planes[i],
+ DRM_MODE_OBJECT_PLANE, "type", &type, NULL);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("plane(%d) doesn't have 'type' info",
+ display_data->plane_res->planes[i]);
+ drmModeFreePlane(plane);
+ continue;
+ }
+
+ layer_data = calloc(1, sizeof(tdm_meson_layer));
+ if (!layer_data) {
+ TDM_BACKEND_ERR("alloc failed");
+ drmModeFreePlane(plane);
+ continue;
+ }
+
+ LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link) {
+ if (plane->possible_crtcs & (1 << output_data->pipe)) {
+ output_find = 1;
+ break;
+ }
+ }
+
+ if (!output_find) {
+ TDM_BACKEND_ERR("plane(%d) couldn't found proper output", plane->plane_id);
+ drmModeFreePlane(plane);
+ free(layer_data);
+ continue;
+ }
+
+ layer_data->display_data = display_data;
+ layer_data->output_data = output_data;
+ layer_data->plane_id = display_data->plane_res->planes[i];
+ layer_data->acquire_fence = -1;
+
+ if (type == DRM_PLANE_TYPE_CURSOR) {
+ layer_data->capabilities = TDM_MESON_LAYER_CAPABILITY_CURSOR |
+ TDM_MESON_LAYER_CAPABILITY_GRAPHIC;
+ layer_data->zpos = output_data->layer_count;
+ output_data->layer_count++;
+ } else if (type == DRM_PLANE_TYPE_OVERLAY) {
+ layer_data->capabilities = TDM_MESON_LAYER_CAPABILITY_OVERLAY |
+ TDM_MESON_LAYER_CAPABILITY_GRAPHIC;
+ layer_data->zpos = output_data->layer_count;
+ output_data->layer_count++;
+ } else if (type == DRM_PLANE_TYPE_PRIMARY) {
+ layer_data->capabilities = TDM_MESON_LAYER_CAPABILITY_PRIMARY |
+ TDM_MESON_LAYER_CAPABILITY_GRAPHIC;
+ layer_data->zpos = output_data->layer_count;
+ output_data->layer_count++;
+ output_data->primary_layer = layer_data;
+ output_data->primary_zpos = layer_data->zpos;
+ } else {
+ drmModeFreePlane(plane);
+ free(layer_data);
+ continue;
+ }
+
+ TDM_BACKEND_INFO("layer_data(%p) plane_id(%d) crtc_id(%d) zpos(%d) capabilities(%x)",
+ layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
+ layer_data->zpos, layer_data->capabilities);
+
+ LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
+
+ /* get the atomic prop ids*/
+ if (display_data->has_atomic) {
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE, "FB_ID", &layer_data->atomic_props_ids.fb_id);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(layer_data);
+ goto failed_atomic_prop_id;
+ }
+
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE, "CRTC_ID", &layer_data->atomic_props_ids.crtc_id);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(layer_data);
+ goto failed_atomic_prop_id;
+ }
+
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE, "SRC_X", &layer_data->atomic_props_ids.src_x);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(layer_data);
+ goto failed_atomic_prop_id;
+ }
+
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE, "SRC_Y", &layer_data->atomic_props_ids.src_y);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(layer_data);
+ goto failed_atomic_prop_id;
+ }
+
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE, "SRC_W", &layer_data->atomic_props_ids.src_w);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(layer_data);
+ goto failed_atomic_prop_id;
+ }
+
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE, "SRC_H", &layer_data->atomic_props_ids.src_h);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(layer_data);
+ goto failed_atomic_prop_id;
+ }
+
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE, "CRTC_X", &layer_data->atomic_props_ids.crtc_x);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(layer_data);
+ goto failed_atomic_prop_id;
+ }
+
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE, "CRTC_Y", &layer_data->atomic_props_ids.crtc_y);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(layer_data);
+ goto failed_atomic_prop_id;
+ }
+
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE, "CRTC_W", &layer_data->atomic_props_ids.crtc_w);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(layer_data);
+ goto failed_atomic_prop_id;
+ }
+
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE, "CRTC_H", &layer_data->atomic_props_ids.crtc_h);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(layer_data);
+ goto failed_atomic_prop_id;
+ }
+
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE, "IN_FENCE_FD", &layer_data->atomic_props_ids.in_fence_fd);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(layer_data);
+ goto failed_atomic_prop_id;
+ }
+ }
+
+ drmModeFreePlane(plane);
+ }
+
+ return HAL_TDM_ERROR_NONE;
+
+failed_atomic_prop_id:
+ if (plane)
+ drmModeFreePlane(plane);
+
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+}
+#endif
+
+static int
+_get_primary_layer_zpos(tdm_meson_output *output_data)
+{
+ tdm_meson_layer *layer_data = NULL;
+
+ LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
+ if (layer_data->capabilities & TDM_MESON_LAYER_CAPABILITY_PRIMARY)
+ return layer_data->zpos;
+ }
+
+ return -1;
+}
+
+hal_tdm_error
+tdm_meson_display_create_layer_list(tdm_meson_display *display_data)
+{
+ hal_tdm_error ret;
+
+#if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
+ if (display_data->has_universal_plane)
+ ret = _tdm_meson_display_create_layer_list_type(display_data);
+ else
+#endif
+ ret = _tdm_meson_display_create_layer_list(display_data);
+
+ if (ret != HAL_TDM_ERROR_NONE)
+ return ret;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+void
+tdm_meson_display_destroy_output_list(tdm_meson_display *display_data)
+{
+ tdm_meson_output *o = NULL, *oo = NULL;
+ tdm_meson_hwc *hwc_data = NULL;
+
+ if (LIST_IS_EMPTY(&display_data->output_list))
+ return;
+
+ LIST_FOR_EACH_ENTRY_SAFE(o, oo, &display_data->output_list, link) {
+ hwc_data = o->hwc_data;
+ if (hwc_data && hwc_data->target_hwc_window)
+ meson_hwc_window_destroy(hwc_data->target_hwc_window);
+
+ LIST_DEL(&o->link);
+ if (!LIST_IS_EMPTY(&o->layer_list)) {
+ tdm_meson_layer *l = NULL, *ll = NULL;
+ LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
+ LIST_DEL(&l->link);
+ if (l->display_buffer)
+ tbm_surface_internal_unref(l->display_buffer->buffer);
+ free(l);
+ }
+ }
+ free(o->meson_modes);
+ free(o->output_modes);
+ free(o);
+ }
+}
+
+void
+tdm_meson_display_update_output_status(tdm_meson_display *display_data)
+{
+ tdm_meson_output *output_data = NULL;
+
+ if (LIST_IS_EMPTY(&display_data->output_list))
+ return;
+
+ LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link) {
+ drmModeConnectorPtr connector;
+ hal_tdm_output_conn_status new_status;
+
+ connector = drmModeGetConnector(display_data->drm_fd,
+ output_data->connector_id);
+ if (!connector) {
+ TDM_BACKEND_ERR("no connector: %d", output_data->connector_id);
+ continue;
+ }
+
+ if (connector->connection == DRM_MODE_CONNECTED)
+ new_status = HAL_TDM_OUTPUT_CONN_STATUS_CONNECTED;
+ else
+ new_status = HAL_TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
+
+ _tdm_meson_output_update_status(output_data, new_status);
+
+ drmModeFreeConnector(connector);
+ }
+}
+
+hal_tdm_error
+tdm_meson_display_create_output_list(tdm_meson_display *display_data)
+{
+ tdm_meson_output *output_data;
+ int i;
+ hal_tdm_error ret;
+ int allocated = 0;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&display_data->output_list),
+ HAL_TDM_ERROR_OPERATION_FAILED);
+
+ for (i = 0; i < display_data->mode_res->count_connectors; i++) {
+ drmModeConnectorPtr connector;
+ drmModeEncoderPtr encoder;
+ int crtc_id = 0, c, j;
+
+ connector = drmModeGetConnector(display_data->drm_fd,
+ display_data->mode_res->connectors[i]);
+ if (!connector) {
+ TDM_BACKEND_ERR("no connector");
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto failed_create;
+ }
+
+ if (connector->count_encoders != 1) {
+ TDM_BACKEND_ERR("too many encoders: %d", connector->count_encoders);
+ drmModeFreeConnector(connector);
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto failed_create;
+ }
+
+ encoder = drmModeGetEncoder(display_data->drm_fd, connector->encoders[0]);
+ if (!encoder) {
+ TDM_BACKEND_ERR("no encoder");
+ drmModeFreeConnector(connector);
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto failed_create;
+ }
+
+ for (c = 0; c < display_data->mode_res->count_crtcs; c++) {
+ if (allocated & (1 << c))
+ continue;
+
+ if ((encoder->possible_crtcs & (1 << c)) == 0)
+ continue;
+
+ crtc_id = display_data->mode_res->crtcs[c];
+ allocated |= (1 << c);
+ break;
+ }
+
+ if (crtc_id == 0) {
+ TDM_BACKEND_ERR("no possible crtc");
+ drmModeFreeConnector(connector);
+ drmModeFreeEncoder(encoder);
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto failed_create;
+ }
+
+ output_data = calloc(1, sizeof(tdm_meson_output));
+ if (!output_data) {
+ TDM_BACKEND_ERR("alloc failed");
+ drmModeFreeConnector(connector);
+ drmModeFreeEncoder(encoder);
+ ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ goto failed_create;
+ }
+
+ LIST_INITHEAD(&output_data->layer_list);
+
+ output_data->display_data = display_data;
+ output_data->connector_id = display_data->mode_res->connectors[i];
+ output_data->encoder_id = encoder->encoder_id;
+ output_data->crtc_id = crtc_id;
+ output_data->pipe = c;
+ output_data->connector_type = connector->connector_type;
+ output_data->connector_type_id = connector->connector_type_id;
+ output_data->commit_fence = -1;
+
+ if (connector->connection == DRM_MODE_CONNECTED)
+ output_data->status = HAL_TDM_OUTPUT_CONN_STATUS_CONNECTED;
+ else
+ output_data->status = HAL_TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
+
+ for (j = 0; j < connector->count_props; j++) {
+ drmModePropertyPtr prop = drmModeGetProperty(display_data->drm_fd,
+ connector->props[j]);
+ if (!prop)
+ continue;
+ if (!strcmp(prop->name, "DPMS")) {
+ output_data->dpms_prop_id = connector->props[j];
+ drmModeFreeProperty(prop);
+ break;
+ }
+ drmModeFreeProperty(prop);
+ }
+
+ output_data->count_modes = connector->count_modes;
+ output_data->meson_modes = calloc(connector->count_modes, sizeof(drmModeModeInfo));
+ if (!output_data->meson_modes) {
+ TDM_BACKEND_ERR("alloc failed");
+ free(output_data);
+ drmModeFreeConnector(connector);
+ drmModeFreeEncoder(encoder);
+ ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ goto failed_create;
+ }
+
+ output_data->output_modes = calloc(connector->count_modes, sizeof(hal_tdm_output_mode));
+ if (!output_data->output_modes) {
+ TDM_BACKEND_ERR("alloc failed");
+ free(output_data->meson_modes);
+ free(output_data);
+ drmModeFreeConnector(connector);
+ drmModeFreeEncoder(encoder);
+ ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ goto failed_create;
+ }
+
+ for (j = 0; j < connector->count_modes; j++) {
+ output_data->meson_modes[j] = connector->modes[j];
+ _tdm_meson_display_to_tdm_mode(&output_data->meson_modes[j],
+ &output_data->output_modes[j]);
+ }
+
+ LIST_ADDTAIL(&output_data->link, &display_data->output_list);
+
+ TDM_BACKEND_INFO("output_data(%p) connector_id(%d:%d:%d-%d) encoder_id(%d) crtc_id(%d) pipe(%d) dpms_id(%d) count_modes(%d)",
+ output_data, output_data->connector_id, output_data->status,
+ output_data->connector_type,
+ output_data->connector_type_id, output_data->encoder_id, output_data->crtc_id,
+ output_data->pipe, output_data->dpms_prop_id, output_data->count_modes);
+
+ drmModeFreeEncoder(encoder);
+ drmModeFreeConnector(connector);
+
+ /* get the atomic prop ids*/
+ if (display_data->has_atomic) {
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, output_data->connector_id,
+ DRM_MODE_OBJECT_CONNECTOR, "CRTC_ID", &output_data->atomic_props_ids.crtc_id);
+ if (ret != HAL_TDM_ERROR_NONE)
+ goto failed_atomic_prop_id;
+
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, output_data->crtc_id,
+ DRM_MODE_OBJECT_CRTC, "MODE_ID", &output_data->atomic_props_ids.crtc_mode_id);
+ if (ret != HAL_TDM_ERROR_NONE)
+ goto failed_atomic_prop_id;
+
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, output_data->crtc_id,
+ DRM_MODE_OBJECT_CRTC, "ACTIVE", &output_data->atomic_props_ids.crtc_active);
+ if (ret != HAL_TDM_ERROR_NONE)
+ goto failed_atomic_prop_id;
+
+ ret = _meson_output_get_atomic_prop_id(display_data->drm_fd, output_data->crtc_id,
+ DRM_MODE_OBJECT_CRTC, "OUT_FENCE_PTR", &output_data->atomic_props_ids.out_fence_ptr);
+ if (ret != HAL_TDM_ERROR_NONE)
+ goto failed_atomic_prop_id;
+ }
+ }
+
+ TDM_BACKEND_INFO("output count: %d", display_data->mode_res->count_connectors);
+
+ return HAL_TDM_ERROR_NONE;
+failed_atomic_prop_id:
+failed_create:
+ tdm_meson_display_destroy_output_list(display_data);
+ return ret;
+}
+
+hal_tdm_error
+meson_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_output **
+meson_display_get_outputs(hal_tdm_display *display, int *count, hal_tdm_error *error)
+{
+ tdm_meson_display *display_data = display;
+ tdm_meson_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_meson_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
+meson_display_get_fd(hal_tdm_display *display, int *fd)
+{
+ tdm_meson_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
+meson_display_handle_events(hal_tdm_display *display)
+{
+ tdm_meson_display *display_data = display;
+ drmEventContext ctx;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ memset(&ctx, 0, sizeof(drmEventContext));
+
+ ctx.version = DRM_EVENT_CONTEXT_VERSION;
+ ctx.page_flip_handler = _tdm_meson_display_cb_event;
+ ctx.vblank_handler = _tdm_meson_display_cb_event;
+
+ drmHandleEvent(display_data->drm_fd, &ctx);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_output_get_capability(hal_tdm_output *output, hal_tdm_caps_output *caps)
+{
+ tdm_meson_output *output_data = output;
+ tdm_meson_display *display_data;
+ drmModeConnectorPtr connector = NULL;
+ drmModeCrtcPtr crtc = NULL;
+ drmModeObjectPropertiesPtr props = NULL;
+ int i;
+ hal_tdm_error ret;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(caps, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ memset(caps, 0, sizeof(hal_tdm_caps_output));
+
+ display_data = output_data->display_data;
+
+ 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;
+
+ connector = drmModeGetConnector(display_data->drm_fd, output_data->connector_id);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(connector, HAL_TDM_ERROR_OPERATION_FAILED);
+
+ caps->mode_count = connector->count_modes;
+ if (caps->mode_count != 0) {
+ 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");
+ goto failed_get;
+ }
+
+ output_data->count_drm_modes = connector->count_modes;
+ output_data->count_modes = caps->mode_count;
+
+ drmModeModeInfoPtr new_drm_modes;
+ hal_tdm_output_mode *new_output_modes;
+
+ new_drm_modes = calloc(connector->count_modes,
+ sizeof(drmModeModeInfo));
+ if (!new_drm_modes) {
+ ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ TDM_BACKEND_ERR("alloc failed drm_modes\n");
+ goto failed_get;
+ }
+ new_output_modes = calloc(caps->mode_count,
+ sizeof(hal_tdm_output_mode));
+ if (!new_output_modes) {
+ ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ TDM_BACKEND_ERR("alloc failed output_modes\n");
+ free(new_drm_modes);
+ goto failed_get;
+ }
+ if (output_data->meson_modes)
+ free(output_data->meson_modes);
+ if (output_data->output_modes)
+ free(output_data->output_modes);
+
+ output_data->meson_modes = new_drm_modes;
+ output_data->output_modes = new_output_modes;
+
+ for (i = 0; i < connector->count_modes; i++) {
+ output_data->meson_modes[i] = connector->modes[i];
+ _tdm_meson_display_to_tdm_mode(&output_data->meson_modes[i],
+ &output_data->output_modes[i]);
+ caps->modes[i] = output_data->output_modes[i];
+ }
+ } else {
+ caps->modes = NULL;
+ output_data->count_drm_modes = connector->count_modes;
+ output_data->count_modes = caps->mode_count;
+
+ if (output_data->meson_modes)
+ free(output_data->meson_modes);
+ if (output_data->output_modes)
+ free(output_data->output_modes);
+
+ output_data->meson_modes = NULL;
+ output_data->output_modes = NULL;
+ }
+
+ caps->mmWidth = connector->mmWidth;
+ caps->mmHeight = connector->mmHeight;
+ caps->subpixel = connector->subpixel;
+
+ caps->min_w = display_data->mode_res->min_width;
+ caps->min_h = display_data->mode_res->min_height;
+ caps->max_w = display_data->mode_res->max_width;
+ caps->max_h = display_data->mode_res->max_height;
+ caps->preferred_align = -1;
+
+ crtc = drmModeGetCrtc(display_data->drm_fd, output_data->crtc_id);
+ if (!crtc) {
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ TDM_BACKEND_ERR("get crtc failed: %m\n");
+ goto failed_get;
+ }
+
+ props = drmModeObjectGetProperties(display_data->drm_fd, output_data->crtc_id,
+ DRM_MODE_OBJECT_CRTC);
+ if (!props) {
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ TDM_BACKEND_ERR("get crtc properties failed: %m\n");
+ goto failed_get;
+ }
+
+ caps->props = calloc(1, sizeof(hal_tdm_prop) * props->count_props);
+ if (!caps->props) {
+ ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ TDM_BACKEND_ERR("alloc failed\n");
+ goto failed_get;
+ }
+
+ caps->prop_count = 0;
+ for (i = 0; i < props->count_props; i++) {
+ drmModePropertyPtr prop = drmModeGetProperty(display_data->drm_fd, props->props[i]);
+ if (!prop)
+ continue;
+ snprintf(caps->props[caps->prop_count].name, HAL_TDM_NAME_LEN, "%s", prop->name);
+ caps->props[caps->prop_count].id = props->props[i];
+ caps->prop_count++;
+ drmModeFreeProperty(prop);
+ }
+
+ caps->capabilities |= HAL_TDM_OUTPUT_CAPABILITY_HWC;
+
+ drmModeFreeObjectProperties(props);
+ drmModeFreeCrtc(crtc);
+ drmModeFreeConnector(connector);
+
+ return HAL_TDM_ERROR_NONE;
+failed_get:
+ drmModeFreeCrtc(crtc);
+ drmModeFreeObjectProperties(props);
+ drmModeFreeConnector(connector);
+ free(caps->modes);
+ free(caps->props);
+ memset(caps, 0, sizeof(hal_tdm_caps_output));
+ return ret;
+}
+
+hal_tdm_error
+meson_output_set_property(hal_tdm_output *output, unsigned int id, hal_tdm_value value)
+{
+ tdm_meson_output *output_data = output;
+ tdm_meson_display *display_data;
+ int ret;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ display_data = output_data->display_data;
+ ret = drmModeObjectSetProperty(display_data->drm_fd,
+ output_data->crtc_id, DRM_MODE_OBJECT_CRTC,
+ id, value.u32);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("set property failed: %m");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_output_get_property(hal_tdm_output *output, unsigned int id, hal_tdm_value *value)
+{
+ tdm_meson_output *output_data = output;
+ tdm_meson_display *display_data;
+ drmModeObjectPropertiesPtr props;
+ int i;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(value, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ display_data = output_data->display_data;
+ props = drmModeObjectGetProperties(display_data->drm_fd, output_data->crtc_id,
+ DRM_MODE_OBJECT_CRTC);
+ if (props == NULL) {
+ TDM_BACKEND_ERR("get property failed: %m");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ for (i = 0; i < props->count_props; i++)
+ if (props->props[i] == id) {
+ (*value).u32 = (uint)props->prop_values[i];
+ break;
+ }
+
+ drmModeFreeObjectProperties(props);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_output_wait_vblank(hal_tdm_output *output, int interval, int sync,
+ void *user_data)
+{
+ tdm_meson_output *output_data = output;
+ tdm_meson_display *display_data;
+ tdm_meson_event *event_data;
+ uint target_msc;
+ hal_tdm_error ret;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ event_data = calloc(1, sizeof(tdm_meson_event));
+ if (!event_data) {
+ TDM_BACKEND_ERR("alloc failed");
+ return HAL_TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ display_data = output_data->display_data;
+
+ ret = _tdm_meson_display_get_cur_msc(display_data->drm_fd, output_data->pipe,
+ &target_msc);
+ if (ret != HAL_TDM_ERROR_NONE)
+ goto failed_vblank;
+
+ target_msc += interval;
+
+ event_data->type = TDM_DRM_EVENT_TYPE_WAIT;
+ event_data->output_data = output_data;
+ event_data->user_data = user_data;
+
+ ret = _tdm_meson_display_wait_vblank(display_data->drm_fd, output_data->pipe,
+ &target_msc, event_data);
+ if (ret != HAL_TDM_ERROR_NONE)
+ goto failed_vblank;
+
+ return HAL_TDM_ERROR_NONE;
+failed_vblank:
+ free(event_data);
+ return ret;
+}
+
+hal_tdm_error
+meson_output_set_vblank_handler(hal_tdm_output *output,
+ hal_tdm_output_vblank_handler func)
+{
+ tdm_meson_output *output_data = 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;
+}
+
+static hal_tdm_error
+_meson_layer_add_atomic_properties(tdm_meson_layer *layer_data, drmModeAtomicReqPtr request,
+ uint32_t fb_id, uint32_t crtc_id, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h,
+ uint32_t crtc_x, uint32_t crtc_y, uint32_t crtc_w, uint32_t crtc_h, int acquire_fence)
+{
+ hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+ ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.fb_id, fb_id);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to add the atomic prop. fb_id(%u)", fb_id);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_id, crtc_id);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to add the atomic prop. crtc_id(%u)", crtc_id);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_x, src_x);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to add the atomic prop. src_x(%u)", src_x);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_y, src_y);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to add the atomic prop. src_y(%u)", src_y);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_w, src_w);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to add the atomic prop. src_w(%u)", src_w);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.src_h, src_h);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to add the atomic prop. src_h(%u)", src_h);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_x, crtc_x);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to add the atomic prop. crtc_x(%u)", crtc_x);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_y, crtc_y);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to add the atomic prop. crtc_y(%u)", crtc_y);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_w, crtc_w);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to add the atomic prop. crtc_w(%u)", crtc_w);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.crtc_h, crtc_h);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to add the atomic prop. crtc_h(%u)", crtc_h);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ ret = drmModeAtomicAddProperty(request, layer_data->plane_id, layer_data->atomic_props_ids.in_fence_fd, acquire_fence);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to add the atomic prop. acquire_fence(%d)", acquire_fence);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_meson_layer_make_atomic_request(tdm_meson_layer *layer_data, drmModeAtomicReqPtr request)
+{
+ tdm_meson_display *display_data = layer_data->display_data;
+ tdm_meson_output *output_data = layer_data->output_data;
+ uint32_t fx, fy, fw, fh;
+ tdm_meson_layer_info layer_info = layer_data->info;
+ hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+ if (!layer_data->display_buffer_changed && !layer_data->info_changed)
+ return HAL_TDM_ERROR_NONE;
+
+ layer_data->display_buffer_changed = 0;
+ layer_data->info_changed = 0;
+
+ if (!layer_data->display_buffer) {
+ TDM_BACKEND_DBG("MakeAtomicRequest: drm_fd(%d) plane_id(%u) crtc_id(%u) off",
+ display_data->drm_fd, layer_data->plane_id, output_data->crtc_id);
+
+ ret = _meson_layer_add_atomic_properties(layer_data, request, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("_meson_layer_add_atomic_properties failed.");
+ return ret;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+ }
+
+ /* Source values are 16.16 fixed point */
+ fx = ((unsigned int)layer_info.src_config.pos.x) << 16;
+ fy = ((unsigned int)layer_info.src_config.pos.y) << 16;
+ fw = ((unsigned int)layer_info.src_config.pos.w) << 16;
+ fh = ((unsigned int)layer_info.src_config.pos.h) << 16;
+
+ TDM_BACKEND_DBG("MakeAtomicRequest: drm_fd(%d) plane_id(%u) zpos(%d) crtc_id(%u) fb_id(%u) src(%u,%u %ux%u) dst(%u,%u %ux%u)",
+ display_data->drm_fd, layer_data->plane_id, layer_data->zpos,
+ output_data->crtc_id, layer_data->display_buffer->fb_id,
+ layer_info.src_config.pos.x, layer_info.src_config.pos.y,
+ layer_info.src_config.pos.w, layer_info.src_config.pos.h,
+ layer_info.dst_pos.x, layer_info.dst_pos.y,
+ layer_info.dst_pos.w, layer_info.dst_pos.h);
+
+ ret = _meson_layer_add_atomic_properties(layer_data, request,
+ layer_data->display_buffer->fb_id, output_data->crtc_id,
+ fx, fy, fw, fh,
+ layer_info.dst_pos.x, layer_info.dst_pos.y,
+ layer_info.dst_pos.w, layer_info.dst_pos.h, layer_data->acquire_fence);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("MakeAtomicRequest failed");
+ return ret;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_meson_output_make_atomic_request(tdm_meson_output *output_data, drmModeAtomicReqPtr request, int *out_fence_fd)
+{
+ tdm_meson_layer *layer_data;
+ drmModeModeInfoPtr current_mode;
+ int ret;
+
+ if (!output_data->crtc_enabled || output_data->mode_changed) {
+ current_mode = _tdm_meson_display_get_mode(output_data);
+ if (!current_mode) {
+ TDM_BACKEND_ERR("couldn't find proper mode");
+ drmModeAtomicFree(request);
+ return HAL_TDM_ERROR_BAD_REQUEST;
+ }
+
+#if 0
+ if (output_data->current_mode_blob_id > 0)
+ drmModeDestroyPropertyBlob(output_data->display_data->drm_fd, output_data->current_mode_blob_id);
+
+ if (drmModeCreatePropertyBlob(output_data->display_data->drm_fd, current_mode,
+ sizeof(drmModeModeInfo), &output_data->current_mode_blob_id)) {
+ TDM_BACKEND_ERR("fail to drmModeCreatePropertyBlob mode");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ ret = drmModeAtomicAddProperty(request, output_data->connector_id,
+ output_data->atomic_props_ids.crtc_id, output_data->crtc_id);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to set crtc error:%d", errno);
+ drmModeAtomicFree(request);
+ return ret;
+ }
+
+ ret = drmModeAtomicAddProperty(request, output_data->crtc_id,
+ output_data->atomic_props_ids.crtc_mode_id, output_data->current_mode_blob_id);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to set mode error:%d", errno);
+ drmModeAtomicFree(request);
+ return ret;
+ }
+
+ ret = drmModeAtomicAddProperty(request, output_data->crtc_id,
+ output_data->atomic_props_ids.crtc_active, 1);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to set active error:%d", errno);
+ drmModeAtomicFree(request);
+ return ret;
+ }
+#endif
+ layer_data = output_data->primary_layer;
+ if (!layer_data) {
+ TDM_BACKEND_ERR("no primary layer");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ if (drmModeSetCrtc(output_data->display_data->drm_fd, output_data->crtc_id,
+ layer_data->display_buffer->fb_id,
+ layer_data->info.src_config.pos.x, layer_data->info.src_config.pos.y,
+ &output_data->connector_id, 1, current_mode)) {
+ TDM_BACKEND_ERR("set crtc failed: %m");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ output_data->crtc_enabled = 1;
+ output_data->mode_changed = 0;
+
+ _tdm_meson_output_update_status(output_data, HAL_TDM_OUTPUT_CONN_STATUS_MODE_SETTED);
+ }
+
+ ret = drmModeAtomicAddProperty(request, output_data->crtc_id,
+ output_data->atomic_props_ids.out_fence_ptr, (uintptr_t)out_fence_fd);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("fail to out fence ptr error:%d", errno);
+ drmModeAtomicFree(request);
+ return ret;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_meson_output_atomic_commit(hal_tdm_output *output, int sync, void *user_data)
+{
+ tdm_meson_output *output_data = output;
+ tdm_meson_layer *layer_data = NULL;
+ tdm_meson_event *event_data;
+ drmModeAtomicReqPtr request;
+ int out_fence_fd = -1;
+ uint32_t flags = 0;
+ hal_tdm_error ret;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ request = drmModeAtomicAlloc();
+ if (!request) {
+ TDM_BACKEND_ERR("drmModeAtomicAlloc failed.");
+ return HAL_TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
+
+ ret = _meson_output_make_atomic_request(output_data, request, &out_fence_fd);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("_meson_output_make_atomic_request failed.");
+ drmModeAtomicFree(request);
+ return ret;
+ }
+
+ LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
+ ret = _meson_layer_make_atomic_request(layer_data, request);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("_meson_layer_make_atomic_request failed.");
+ drmModeAtomicFree(request);
+ return ret;
+ }
+ }
+
+ event_data = calloc(1, sizeof(tdm_meson_event));
+ if (!event_data) {
+ TDM_BACKEND_ERR("fail to alloc event_data.");
+ drmModeAtomicFree(request);
+ return HAL_TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
+ event_data->output_data = output_data;
+ event_data->user_data = user_data;
+
+ TDM_BACKEND_DBG("==== Atomic Commit pipe, %u, crtc_id, %u connector_id, %u",
+ output_data->pipe, output_data->crtc_id, output_data->connector_id);
+
+ if (drmModeAtomicCommit(output_data->display_data->drm_fd, request, flags, event_data) < 0) {
+ TDM_BACKEND_ERR("drmModeAtomicCommit failed.");
+ drmModeAtomicFree(request);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ if (output_data->commit_fence >= 0)
+ close(output_data->commit_fence);
+
+ output_data->commit_fence = out_fence_fd;
+
+ drmModeAtomicFree(request);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+static hal_tdm_error
+_meson_output_layers_commit(hal_tdm_output *output, int sync, void *user_data)
+{
+ tdm_meson_output *output_data = output;
+ tdm_meson_display *display_data;
+ tdm_meson_layer *layer_data = NULL;
+ hal_tdm_error ret;
+ int do_waitvblank = 1;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ display_data = output_data->display_data;
+
+ LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
+ if (layer_data == output_data->primary_layer)
+ ret = _tdm_meson_output_commit_primary_layer(layer_data, user_data, &do_waitvblank);
+ else
+ ret = _tdm_meson_display_commit_layer(layer_data);
+
+ if (ret != HAL_TDM_ERROR_NONE)
+ return ret;
+ }
+
+ if (do_waitvblank == 1) {
+ tdm_meson_event *event_data = calloc(1, sizeof(tdm_meson_event));
+ uint target_msc;
+
+ if (!event_data) {
+ TDM_BACKEND_ERR("alloc failed");
+ return HAL_TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ ret = _tdm_meson_display_get_cur_msc(display_data->drm_fd, output_data->pipe,
+ &target_msc);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(event_data);
+ return ret;
+ }
+
+ target_msc++;
+
+ event_data->type = TDM_DRM_EVENT_TYPE_COMMIT;
+ event_data->output_data = output_data;
+ event_data->user_data = user_data;
+
+ ret = _tdm_meson_display_wait_vblank(display_data->drm_fd, output_data->pipe,
+ &target_msc, event_data);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ free(event_data);
+ return ret;
+ }
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_output_commit(hal_tdm_output *output, int sync, void *user_data)
+{
+ tdm_meson_output *output_data = output;
+ tdm_meson_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;
+
+ /* check the atomic pageflip */
+ if (display_data->has_atomic) {
+ ret = _meson_output_atomic_commit(output, sync, user_data);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("_meson_output_atomic_commit failed.");
+ return ret;
+ }
+ } else {
+ ret = _meson_output_layers_commit(output, sync, user_data);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("_meson_output_layers_commit failed.");
+ return ret;
+ }
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_output_set_commit_handler(hal_tdm_output *output,
+ hal_tdm_output_commit_handler func)
+{
+ tdm_meson_output *output_data = 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
+meson_output_set_dpms(hal_tdm_output *output, hal_tdm_output_dpms dpms_value)
+{
+ tdm_meson_output *output_data = output;
+ tdm_meson_display *display_data;
+ int ret;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ if (output_data->dpms_prop_id == 0) {
+ TDM_BACKEND_WRN("not support DPMS");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ display_data = output_data->display_data;
+ ret = drmModeObjectSetProperty(display_data->drm_fd,
+ output_data->connector_id, DRM_MODE_OBJECT_CONNECTOR,
+ output_data->dpms_prop_id, dpms_value);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("set dpms failed: %m");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_output_get_dpms(hal_tdm_output *output, hal_tdm_output_dpms *dpms_value)
+{
+ tdm_meson_output *output_data = output;
+ tdm_meson_display *display_data;
+ drmModeObjectPropertiesPtr props;
+ int i;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(dpms_value, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ display_data = output_data->display_data;
+ props = drmModeObjectGetProperties(display_data->drm_fd, output_data->connector_id,
+ DRM_MODE_OBJECT_CONNECTOR);
+ if (props == NULL) {
+ TDM_BACKEND_ERR("get property failed: %m");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ for (i = 0; i < props->count_props; i++)
+ if (props->props[i] == output_data->dpms_prop_id) {
+ *dpms_value = (uint)props->prop_values[i];
+ break;
+ }
+
+ drmModeFreeObjectProperties(props);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_output_set_mode(hal_tdm_output *output, const hal_tdm_output_mode *mode)
+{
+ tdm_meson_output *output_data = output;
+ hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(mode, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ /* create or replace the target_window when the output mode is set */
+ ret = meson_hwc_target_window_set_info(output_data->hwc_data, mode->hdisplay, mode->vdisplay);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("set info target hwc window failed (%d)", ret);
+ return ret;
+ }
+
+ output_data->current_mode = mode;
+ output_data->mode_changed = 1;
+
+ TDM_BACKEND_INFO("Set the output mode: %s, %d, %d, %d, %d, %d",
+ mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags, mode->type);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_output_get_mode(hal_tdm_output *output, const hal_tdm_output_mode **mode)
+{
+ tdm_meson_output *output_data = 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_hwc *
+meson_output_get_hwc(hal_tdm_output *output, hal_tdm_error *error)
+{
+ tdm_meson_hwc *hwc_data = NULL;
+ tdm_meson_output *output_data = output;
+ hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+ 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_meson_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;
+
+ ret = meson_hwc_initialize_target_window(output_data->hwc_data);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("create target hwc window failed (%d)", ret);
+ free(hwc_data);
+ if (error)
+ *error = ret;
+ return NULL;
+ }
+
+ if (error)
+ *error = HAL_TDM_ERROR_NONE;
+
+ return hwc_data;
+}
+
+
+hal_tdm_error
+meson_output_set_status_handler(hal_tdm_output *output,
+ hal_tdm_output_status_handler func,
+ void *user_data)
+{
+ tdm_meson_output *output_data = output;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ output_data->status_func = func;
+ output_data->status_user_data = user_data;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_layer_get_capability(tdm_meson_layer *layer, tdm_meson_caps_layer *caps)
+{
+ tdm_meson_layer *layer_data = layer;
+ tdm_meson_display *display_data;
+ drmModePlanePtr plane = NULL;
+ drmModeObjectPropertiesPtr props = NULL;
+ int i, format_count = 0;
+ int primary_zpos = _get_primary_layer_zpos(layer_data->output_data);
+ 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_meson_caps_layer));
+
+ display_data = layer_data->display_data;
+ plane = drmModeGetPlane(display_data->drm_fd, layer_data->plane_id);
+ if (!plane) {
+ TDM_BACKEND_ERR("get plane failed: %m");
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ goto failed_get;
+ }
+
+ caps->capabilities = layer_data->capabilities;
+ caps->zpos = layer_data->zpos;
+
+ caps->format_count = plane->count_formats;
+ caps->formats = calloc(1, sizeof(tbm_format) * caps->format_count);
+ if (!caps->formats) {
+ ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ TDM_BACKEND_ERR("alloc failed\n");
+ goto failed_get;
+ }
+
+ for (i = 0; i < caps->format_count; i++) {
+ /* Changing between RGB and YUV format for a plane doesn't work properly
+ * only support AR24, XR24 for primary, overlay
+ */
+ if (layer_data->zpos >= primary_zpos) {
+ if (plane->formats[i] != DRM_FORMAT_XRGB8888 && plane->formats[i] != DRM_FORMAT_ARGB8888)
+ continue;
+ } else {
+ /* only support NV12 for underlay */
+ if (plane->formats[i] != DRM_FORMAT_NV12)
+ continue;
+ }
+
+ caps->formats[format_count] = tdm_meson_format_to_tbm_format(plane->formats[i]);
+ format_count++;
+ }
+
+ caps->format_count = format_count;
+
+ props = drmModeObjectGetProperties(display_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE);
+ if (!props) {
+ ret = HAL_TDM_ERROR_OPERATION_FAILED;
+ TDM_BACKEND_ERR("get plane properties failed: %m\n");
+ goto failed_get;
+ }
+
+ caps->props = calloc(1, sizeof(hal_tdm_prop) * props->count_props);
+ if (!caps->props) {
+ ret = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ TDM_BACKEND_ERR("alloc failed\n");
+ goto failed_get;
+ }
+
+ caps->prop_count = 0;
+ for (i = 0; i < props->count_props; i++) {
+ drmModePropertyPtr prop = drmModeGetProperty(display_data->drm_fd, props->props[i]);
+ if (!prop)
+ continue;
+ if (!strncmp(prop->name, "type", HAL_TDM_NAME_LEN)) {
+ drmModeFreeProperty(prop);
+ continue;
+ }
+ if (!strncmp(prop->name, "zpos", HAL_TDM_NAME_LEN)) {
+ drmModeFreeProperty(prop);
+ continue;
+ }
+ snprintf(caps->props[caps->prop_count].name, HAL_TDM_NAME_LEN, "%s", prop->name);
+ caps->props[caps->prop_count].id = props->props[i];
+ caps->prop_count++;
+ drmModeFreeProperty(prop);
+ }
+
+ drmModeFreeObjectProperties(props);
+ drmModeFreePlane(plane);
+
+ return HAL_TDM_ERROR_NONE;
+failed_get:
+ drmModeFreeObjectProperties(props);
+ drmModeFreePlane(plane);
+ free(caps->formats);
+ free(caps->props);
+ memset(caps, 0, sizeof(tdm_meson_caps_layer));
+ return ret;
+}
+
+hal_tdm_error
+meson_layer_set_property(tdm_meson_layer *layer, unsigned int id, hal_tdm_value value)
+{
+ tdm_meson_layer *layer_data = layer;
+ tdm_meson_display *display_data;
+ int ret;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ display_data = layer_data->display_data;
+ ret = drmModeObjectSetProperty(display_data->drm_fd,
+ layer_data->plane_id, DRM_MODE_OBJECT_PLANE,
+ id, value.u32);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("set property failed: %m");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_layer_get_property(tdm_meson_layer *layer, unsigned int id, hal_tdm_value *value)
+{
+ tdm_meson_layer *layer_data = layer;
+ tdm_meson_display *display_data;
+ drmModeObjectPropertiesPtr props;
+ int i;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(value, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ display_data = layer_data->display_data;
+ props = drmModeObjectGetProperties(display_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE);
+ if (props == NULL) {
+ TDM_BACKEND_ERR("get property failed: %m");
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ for (i = 0; i < props->count_props; i++)
+ if (props->props[i] == id) {
+ (*value).u32 = (uint)props->prop_values[i];
+ break;
+ }
+
+ drmModeFreeObjectProperties(props);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_layer_set_info(tdm_meson_layer *layer, tdm_meson_layer_info *info)
+{
+ tdm_meson_layer *layer_data = layer;
+
+ 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
+meson_layer_get_info(tdm_meson_layer *layer, tdm_meson_layer_info *info)
+{
+ tdm_meson_layer *layer_data = layer;
+
+ 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;
+}
+
+static tdm_meson_display_buffer *
+_tdm_meson_display_find_buffer(tdm_meson_display *display_data, tbm_surface_h buffer)
+{
+ tdm_meson_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 void
+_tdm_meson_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data)
+{
+ tdm_meson_display *display_data;
+ tdm_meson_display_buffer *display_buffer;
+ tdm_meson_layer *layer_data = NULL;
+ tdm_meson_output *output_data = NULL;
+ char buf[256] = {0,};
+ char *ret_tmp;
+
+ if (!user_data) {
+ TDM_BACKEND_ERR("no user_data");
+ return;
+ }
+ if (!buffer) {
+ TDM_BACKEND_ERR("no buffer");
+ return;
+ }
+
+ display_data = (tdm_meson_display *) user_data;
+
+ display_buffer = _tdm_meson_display_find_buffer(display_data, buffer);
+ if (!display_buffer) {
+ TDM_BACKEND_ERR("no display_buffer");
+ return;
+ }
+
+ LIST_FOR_EACH_ENTRY(output_data, &display_data->output_list, link) {
+ LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) {
+ if (display_buffer == layer_data->display_buffer)
+ layer_data->display_buffer = NULL;
+ }
+ }
+
+ if (display_buffer->fb_id > 0) {
+ if (drmModeRmFB(display_data->drm_fd, display_buffer->fb_id) < 0) {
+ ret_tmp = strerror_r(errno, buf, sizeof(buf));
+ TDM_BACKEND_ERR("rm fb failed: %d(%s,%s)\n", errno, buf, ret_tmp);
+ }
+ }
+
+ TDM_BACKEND_DBG("destroy buffer:%p", display_buffer->buffer);
+
+ LIST_DEL(&display_buffer->link);
+ free(display_buffer);
+}
+
+static tdm_meson_display_buffer *
+_tdm_meson_display_create_buffer(tdm_meson_display *display_data, tbm_surface_h buffer, hal_tdm_error *err)
+{
+ tdm_meson_display_buffer *display_buffer = NULL;
+ hal_tdm_error res = HAL_TDM_ERROR_NONE;
+ int count, i, ret;
+
+ display_buffer = calloc(1, sizeof(tdm_meson_display_buffer));
+ if (!display_buffer) {
+ TDM_BACKEND_ERR("alloc failed");
+ if (err)
+ *err = HAL_TDM_ERROR_OUT_OF_MEMORY;
+ return NULL;
+ }
+
+ display_buffer->buffer = buffer;
+
+ ret = tbm_surface_internal_add_destroy_handler(buffer, _tdm_meson_display_cb_destroy_buffer, display_data);
+ if (!ret) {
+ TDM_BACKEND_ERR("add destroy handler fail");
+ free(display_buffer);
+ if (err)
+ *err = res;
+ return NULL;
+ }
+
+ display_buffer->width = tbm_surface_get_width(buffer);
+ display_buffer->height = tbm_surface_get_height(buffer);
+ display_buffer->format = tbm_surface_get_format(buffer);
+ display_buffer->count = tbm_surface_internal_get_num_bos(buffer);
+ count = tbm_surface_internal_get_num_planes(display_buffer->format);
+ TDM_BACKEND_DBG("create buffer:%p %dx%d %c%c%c%c bo_num:%d plane_num:%d",
+ buffer, display_buffer->width, display_buffer->height,
+ FOURCC_STR(display_buffer->format), display_buffer->count, count);
+
+ for (i = 0; i < count; i++) {
+ int bo_idx = 0;
+ tbm_bo bo = NULL;
+
+ bo_idx = tbm_surface_internal_get_plane_bo_idx(buffer, i);
+ bo = tbm_surface_internal_get_bo(buffer, bo_idx);
+ display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+
+ tbm_surface_internal_get_plane_data(buffer, i, &display_buffer->size,
+ &display_buffer->offsets[i],
+ &display_buffer->pitches[i]);
+ TDM_BACKEND_DBG(" create buffer:%p plane%d(size:%d offset:%d pitch:%d) bo%d(handle:%d)",
+ buffer, i, display_buffer->size, display_buffer->offsets[i],
+ display_buffer->pitches[i], bo_idx, display_buffer->handles[i]);
+ }
+
+ ret = drmModeAddFB2(display_data->drm_fd, display_buffer->width, display_buffer->height,
+ display_buffer->format, display_buffer->handles, display_buffer->pitches,
+ display_buffer->offsets, &display_buffer->fb_id, 0);
+ if (ret < 0) {
+ TDM_BACKEND_ERR("add fb failed: %m");
+ free(display_buffer);
+ if (err)
+ *err = HAL_TDM_ERROR_OPERATION_FAILED;
+ return NULL;
+ }
+
+ TDM_BACKEND_DBG("display_data->drm_fd : %d, display_buffer->fb_id:%u", display_data->drm_fd,
+ display_buffer->fb_id);
+
+ if (IS_RGB(display_buffer->format))
+ display_buffer->width = display_buffer->pitches[0] >> 2;
+ else
+ display_buffer->width = display_buffer->pitches[0];
+
+ LIST_ADDTAIL(&display_buffer->link, &display_data->buffer_list);
+
+ if (err)
+ *err = HAL_TDM_ERROR_NONE;
+
+ return display_buffer;
+}
+
+void
+tdm_meson_destroy_buffer_list(tdm_meson_display *display_data)
+{
+ tdm_meson_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_meson_display_cb_destroy_buffer, display_data);
+ _tdm_meson_display_cb_destroy_buffer(b->buffer, display_data);
+ }
+}
+
+hal_tdm_error
+meson_layer_set_buffer(tdm_meson_layer *layer, tbm_surface_h buffer)
+{
+ tdm_meson_layer *layer_data = layer;
+ tdm_meson_display *display_data;
+ tdm_meson_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(buffer, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ TDM_BACKEND_DBG("layer[%p]zpos[%d] buffer:%p", layer, layer_data->zpos, buffer);
+
+ display_data = layer_data->display_data;
+ display_buffer = _tdm_meson_display_find_buffer(display_data, buffer);
+ if (!display_buffer) {
+ display_buffer = _tdm_meson_display_create_buffer(display_data, buffer, &err);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
+ }
+
+ if (layer_data->display_buffer != display_buffer) {
+ if (layer_data->display_buffer)
+ tbm_surface_internal_unref(layer_data->display_buffer->buffer);
+
+ layer_data->display_buffer = display_buffer;
+ tbm_surface_internal_ref(layer_data->display_buffer->buffer);
+ layer_data->display_buffer_changed = 1;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_layer_unset_buffer(tdm_meson_layer *layer)
+{
+ tdm_meson_layer *layer_data = layer;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ TDM_BACKEND_DBG("layer[%p]zpos[%d]", layer, layer_data->zpos);
+
+ if (layer_data->display_buffer)
+ tbm_surface_internal_unref(layer_data->display_buffer->buffer);
+
+ layer_data->display_buffer = NULL;
+ layer_data->display_buffer_changed = 1;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+tdm_meson_layer *
+meson_output_data_get_layer_data(tdm_meson_output *output_data, int layer_zpos)
+{
+ tdm_meson_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;
+}
+
+hal_tdm_error
+meson_layer_set_acquire_fence(tdm_meson_layer *layer, int acquire_fence)
+{
+ tdm_meson_layer *layer_data = layer;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ TDM_BACKEND_DBG("layer[%p]zpos[%d] acquire_fence:%d", layer, layer_data->zpos, acquire_fence);
+
+ if (layer_data->acquire_fence != acquire_fence)
+ layer_data->acquire_fence = acquire_fence;
+
+ return HAL_TDM_ERROR_NONE;
+}
--- /dev/null
+/**************************************************************************
+
+libtdm_meson
+
+Copyright 2021 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: SooChan Lim <sc1.lim@samsung.com>,
+ Junkyeong Kim <jk0430.kim@samsung.com>,
+ Changyeon Lee <cyeon.lee@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.
+
+**************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <drm_fourcc.h>
+#include <tbm_surface.h>
+
+#include "tdm_backend_meson.h"
+
+typedef struct {
+ tbm_format tbm_format;
+ uint32_t drm_format;
+} tbm_meson_format_data;
+
+static const tbm_meson_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},
+};
+
+#define NUM_FORMATS (sizeof(formats) / sizeof(formats[0]))
+
+uint32_t
+tdm_meson_format_to_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_meson_format_to_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
+/**************************************************************************
+
+libtdm_meson
+
+Copyright 2021 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: SooChan Lim <sc1.lim@samsung.com>,
+ Junkyeong Kim <jk0430.kim@samsung.com>,
+ Changyeon Lee <cyeon.lee@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.
+
+**************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_meson.h"
+#include <pixman.h>
+
+#define NUM_BUFFERS 3
+#define ZPOS_NONE -999
+
+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 tbm_surface_queue_h
+_meson_hwc_window_get_tbm_buffer_queue(hal_tdm_hwc_window *hwc_window, hal_tdm_error *error)
+{
+ tdm_meson_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);
+
+ if (error)
+ *error = HAL_TDM_ERROR_NONE;
+
+ return tqueue;
+}
+
+static tbm_surface_queue_h
+_meson_hwc_window_get_cursor_tbm_buffer_queue(hal_tdm_hwc_window *hwc_window, hal_tdm_error *error)
+{
+ tdm_meson_hwc_window *hwc_window_data = NULL;
+ tbm_surface_queue_h tqueue = NULL;
+ int width, height;
+
+ if (error)
+ *error = HAL_TDM_ERROR_INVALID_PARAMETER;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window != NULL, NULL);
+
+ hwc_window_data = hwc_window;
+
+ switch (hwc_window_data->info.transform) {
+ case HAL_TDM_TRANSFORM_90:
+ case HAL_TDM_TRANSFORM_FLIPPED_90:
+ case HAL_TDM_TRANSFORM_270:
+ case HAL_TDM_TRANSFORM_FLIPPED_270:
+ width = hwc_window_data->cursor_img.height;
+ height = hwc_window_data->cursor_img.width;
+ break;
+ default:
+ width = hwc_window_data->cursor_img.width;
+ height = hwc_window_data->cursor_img.height;
+ break;
+ }
+
+ tqueue = tbm_surface_queue_create(NUM_BUFFERS, width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
+ if (error)
+ *error = HAL_TDM_ERROR_OPERATION_FAILED;
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(tqueue != NULL, NULL);
+
+ tbm_surface_queue_set_modes(tqueue, TBM_SURFACE_QUEUE_MODE_GUARANTEE_CYCLE);
+
+ if (error)
+ *error = HAL_TDM_ERROR_NONE;
+
+ return tqueue;
+}
+
+static int
+_meson_hwc_cursor_buffer_image_render(tdm_meson_hwc *hwc_data, tdm_meson_hwc_window *hwc_window_data)
+{
+ tbm_surface_info_s tsurface_info;
+ tbm_surface_error_e ret = TBM_SURFACE_ERROR_NONE;
+ void *src_ptr = NULL, *dst_ptr = NULL;
+ int src_stride, transform, img_w, img_h;
+ pixman_image_t *src_img = NULL, *dst_img = NULL;
+ pixman_transform_t t;
+ struct pixman_f_transform ft;
+ int c = 0, s = 0, tx = 0, ty = 0;
+ int i;
+
+ ret = tbm_surface_map(hwc_data->cursor_tsurface, TBM_SURF_OPTION_WRITE, &tsurface_info);
+ if (ret != TBM_SURFACE_ERROR_NONE) {
+ TDM_BACKEND_ERR("Failed to map tsurface\n");
+ return 0;
+ }
+
+ src_ptr = hwc_window_data->cursor_img.ptr;
+ src_stride = hwc_window_data->cursor_img.stride;
+ img_w = hwc_window_data->cursor_img.width;
+ img_h = hwc_window_data->cursor_img.height;
+ transform = hwc_window_data->info.transform;
+
+ dst_ptr = tsurface_info.planes[0].ptr;
+
+ memset(dst_ptr, 0, tsurface_info.planes[0].stride * tsurface_info.height);
+
+ if (transform) {
+ src_img = pixman_image_create_bits(PIXMAN_a8r8g8b8, img_w, img_h, (uint32_t*)src_ptr, src_stride);
+ if (!src_img) {
+ TDM_BACKEND_ERR("Failed to create src pixman\n");
+ return 0;
+ }
+
+ dst_img = pixman_image_create_bits(PIXMAN_a8r8g8b8, tsurface_info.width, tsurface_info.height,
+ (uint32_t*)dst_ptr, tsurface_info.planes[0].stride);
+ if (!dst_img) {
+ TDM_BACKEND_ERR("Failed to create dst pixman\n");
+ pixman_image_unref(src_img);
+ return 0;
+ }
+
+ 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, tsurface_info.width, 0);
+ }
+
+ switch (transform) {
+ case HAL_TDM_TRANSFORM_90:
+ case HAL_TDM_TRANSFORM_FLIPPED_90:
+ c = 0, s = 1, ty = -tsurface_info.height;
+ break;
+ case HAL_TDM_TRANSFORM_180:
+ case HAL_TDM_TRANSFORM_FLIPPED_180:
+ c = -1, s = 0, tx = -tsurface_info.width, ty = -tsurface_info.height;
+ break;
+ case HAL_TDM_TRANSFORM_270:
+ case HAL_TDM_TRANSFORM_FLIPPED_270:
+ c = 0, s = -1, tx = -tsurface_info.width;
+ break;
+ default:
+ break;
+ }
+
+ pixman_f_transform_translate(&ft, NULL, tx, ty);
+ pixman_f_transform_rotate(&ft, NULL, c, s);
+ pixman_transform_from_pixman_f_transform(&t, &ft);
+ pixman_image_set_transform(src_img, &t);
+ pixman_image_composite(PIXMAN_OP_SRC, src_img, NULL, dst_img, 0, 0, 0, 0, 0, 0,
+ tsurface_info.width, tsurface_info.height);
+ pixman_image_unref(src_img);
+ pixman_image_unref(dst_img);
+ }
+ else {
+ for (i = 0 ; i < img_h ; i++) {
+ memcpy(dst_ptr, src_ptr, src_stride);
+ dst_ptr += tsurface_info.planes[0].stride;
+ src_ptr += src_stride;
+ }
+ }
+
+ tbm_surface_unmap(hwc_data->cursor_tsurface);
+
+ return 1;
+}
+
+static int
+_meson_hwc_cursor_window_surface_clear(tdm_meson_hwc_window *hwc_window_data)
+{
+ hwc_window_data->surface = NULL;
+ hwc_window_data->cursor_img_surface = 0;
+
+ hwc_window_data->info.src_config.pos.w = hwc_window_data->cursor_img.width;
+ hwc_window_data->info.src_config.pos.h = hwc_window_data->cursor_img.height;
+ hwc_window_data->info.dst_pos.w = hwc_window_data->cursor_img.width;
+ hwc_window_data->info.dst_pos.h = hwc_window_data->cursor_img.height;
+
+ return 1;
+}
+
+static void
+_meson_hwc_cursor_buffer_unset(tdm_meson_hwc *hwc_data)
+{
+ if (hwc_data->cursor_tsurface) {
+ tbm_surface_queue_release(hwc_data->cursor_tqueue, hwc_data->cursor_tsurface);
+ hwc_data->cursor_tsurface = NULL;
+ }
+
+ if (hwc_data->cursor_tqueue) {
+ tbm_surface_queue_destroy(hwc_data->cursor_tqueue);
+ hwc_data->cursor_tqueue = NULL;
+ }
+}
+
+static void
+_meson_hwc_cursor_adjust_pos(tdm_meson_hwc *hwc_data, tdm_meson_hwc_window *hwc_window_data)
+{
+ int x, y, width, height;
+
+ width = tbm_surface_get_width(hwc_data->cursor_tsurface);
+ height = tbm_surface_get_height(hwc_data->cursor_tsurface);
+
+ hwc_window_data->info.src_config.pos.w = width;
+ hwc_window_data->info.src_config.pos.h = height;
+ hwc_window_data->info.dst_pos.w = width;
+ hwc_window_data->info.dst_pos.h = height;
+
+ /* dst pos of cursor is possible set by negative value
+ * this is temporary code.
+ */
+ x = hwc_window_data->info.dst_pos.x;
+ y = hwc_window_data->info.dst_pos.y;
+
+ if (x < 0) hwc_window_data->info.dst_pos.x = 0;
+ if (y < 0) hwc_window_data->info.dst_pos.y = 0;
+}
+
+static int
+_meson_hwc_cursor_buffer_set(tdm_meson_hwc *hwc_data, tdm_meson_hwc_window *hwc_window_data)
+{
+ tbm_surface_h cursor_tsurface = NULL;
+ tbm_surface_queue_error_e tsq_error = TBM_SURFACE_QUEUE_ERROR_NONE;
+ int img_w, img_h;
+ int tqueue_w, tqueue_h;
+ hal_tdm_error error;
+
+ if (hwc_window_data->cursor_img_refresh || !hwc_window_data->surface) {
+ switch (hwc_window_data->info.transform) {
+ case HAL_TDM_TRANSFORM_90:
+ case HAL_TDM_TRANSFORM_FLIPPED_90:
+ case HAL_TDM_TRANSFORM_270:
+ case HAL_TDM_TRANSFORM_FLIPPED_270:
+ img_w = hwc_window_data->cursor_img.height;
+ img_h = hwc_window_data->cursor_img.width;
+ break;
+ default:
+ img_w = hwc_window_data->cursor_img.width;
+ img_h = hwc_window_data->cursor_img.height;
+ break;
+ }
+
+ if (!hwc_data->cursor_tqueue) {
+ hwc_data->cursor_tqueue = _meson_hwc_window_get_cursor_tbm_buffer_queue(hwc_window_data, &error);
+ if (error != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("Failed to create cursor buffer queue error:%d", error);
+ return 0;
+ }
+ } else {
+ tqueue_w = tbm_surface_queue_get_width(hwc_data->cursor_tqueue);
+ tqueue_h = tbm_surface_queue_get_height(hwc_data->cursor_tqueue);
+ if ((img_w != tqueue_w) || (img_h != tqueue_h))
+ tbm_surface_queue_reset(hwc_data->cursor_tqueue, img_w, img_h, TBM_FORMAT_ARGB8888);
+ }
+
+ if (hwc_data->cursor_tsurface) {
+ tbm_surface_queue_release(hwc_data->cursor_tqueue, hwc_data->cursor_tsurface);
+ hwc_data->cursor_tsurface = NULL;
+ }
+
+ if (!tbm_surface_queue_can_dequeue(hwc_data->cursor_tqueue, 0)) {
+ TDM_BACKEND_ERR("Can't dequeue cursor tqueue");
+ return 0;
+ }
+
+ tsq_error = tbm_surface_queue_dequeue(hwc_data->cursor_tqueue, &cursor_tsurface);
+ if (tsq_error != TBM_SURFACE_QUEUE_ERROR_NONE) {
+ TDM_BACKEND_ERR("Failed to dequeue cursor tqueue error:%d", tsq_error);
+ return 0;
+ }
+
+ hwc_data->cursor_tsurface = cursor_tsurface;
+
+ _meson_hwc_cursor_buffer_image_render(hwc_data, hwc_window_data);
+
+ hwc_window_data->surface = cursor_tsurface;
+ hwc_window_data->cursor_img_surface = 1;
+ hwc_window_data->cursor_img_refresh = 0;
+ }
+
+ _meson_hwc_cursor_adjust_pos(hwc_data, hwc_window_data);
+
+ return 1;
+}
+
+static void
+_print_validate_result(tdm_meson_hwc *hwc_data, hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds)
+{
+ tdm_meson_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;
+ }
+ }
+}
+
+#if 0
+static int
+_meson_hwc_window_can_set_on_hw_layer(tdm_meson_hwc_window *hwc_window_data)
+{
+ if (!hwc_window_data->surface)
+ return 0;
+
+ if (hwc_window_data->info.transform != HAL_TDM_TRANSFORM_NORMAL)
+ return 0;
+
+ if (hwc_window_data->info.src_config.pos.w != hwc_window_data->info.dst_pos.w)
+ return 0;
+
+ if (hwc_window_data->info.src_config.pos.h != hwc_window_data->info.dst_pos.h)
+ return 0;
+
+ if (!IS_RGB(hwc_window_data->info.src_config.format))
+ return 0;
+
+ if (hwc_window_data->info.dst_pos.x > hwc_window_data->hwc_data->output_data->current_mode->hdisplay ||
+ hwc_window_data->info.dst_pos.y > hwc_window_data->hwc_data->output_data->current_mode->vdisplay)
+ return 0;
+
+ return 1;
+}
+#endif
+
+static hal_tdm_error
+_meson_hwc_layer_attach_window(tdm_meson_layer *layer_data, tdm_meson_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 = meson_layer_unset_buffer(layer_data);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret);
+
+ if (layer_data->acquire_fence >= 0)
+ ret = meson_layer_set_acquire_fence(layer_data, -1);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret);
+ } else {
+ ret = meson_layer_set_info(layer_data, (tdm_meson_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 = meson_layer_set_buffer(layer_data, hwc_window_data->surface);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret);
+ ret = meson_layer_set_acquire_fence(layer_data, hwc_window_data->acquire_fence);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret);
+ }
+
+ return ret;
+}
+
+static hal_tdm_error
+_meson_hwc_prepare_commit(tdm_meson_hwc *hwc_data)
+{
+ tdm_meson_hwc_window *hwc_window_data = NULL;
+ tdm_meson_output *output_data = hwc_data->output_data;
+ tdm_meson_layer *layer_data = NULL;
+ int *use_layers_zpos;
+ int lzpos = 0;
+ int cursor_enabled = 0;
+
+ use_layers_zpos = calloc(output_data->layer_count, sizeof(int));
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(use_layers_zpos, HAL_TDM_ERROR_OUT_OF_MEMORY);
+
+ /* set target hwc window to the layer */
+ if (hwc_data->need_target_window) {
+ layer_data = meson_output_data_get_layer_data(hwc_data->output_data, hwc_data->target_hwc_window->lzpos);
+ _meson_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) {
+ if (hwc_window_data->cursor_img_surface)
+ _meson_hwc_cursor_window_surface_clear(hwc_window_data);
+
+ continue;
+ }
+
+ if (hwc_window_data == hwc_data->target_hwc_window)
+ continue;
+
+ /* set the cursor buffer HERE if it needs */
+ if (hwc_window_data->validated_type == HAL_TDM_HWC_WIN_COMPOSITION_CURSOR) {
+ _meson_hwc_cursor_buffer_set(hwc_data, hwc_window_data);
+ cursor_enabled = 1;
+ }
+
+ layer_data = meson_output_data_get_layer_data(hwc_data->output_data, hwc_window_data->lzpos);
+ _meson_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 < output_data->layer_count; lzpos++) {
+ if (use_layers_zpos[lzpos])
+ continue;
+
+ layer_data = meson_output_data_get_layer_data(hwc_data->output_data, lzpos);
+ if (!layer_data)
+ continue;
+
+ _meson_hwc_layer_attach_window(layer_data, NULL);
+ }
+
+ if (!cursor_enabled)
+ _meson_hwc_cursor_buffer_unset(hwc_data);
+
+ /* for debug */
+ for (lzpos = output_data->layer_count -1 ; lzpos >= 0; lzpos--) {
+ if (use_layers_zpos[lzpos])
+ TDM_BACKEND_DBG(" lzpos(%d) : %s", lzpos, use_layers_zpos[lzpos] ? "SET" : "UNSET");
+ }
+
+ free(use_layers_zpos);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+/* assign the validated_type to the composited_wnds
+ * assign the layer_zpos to the composited_wnds
+ */
+static void
+_meson_hwc_apply_policy(tdm_meson_hwc *hwc_data , hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds)
+{
+ tdm_meson_hwc_window *hwc_window_data = NULL;
+ tdm_meson_hwc_window **composited_list = NULL;
+ tdm_meson_output *output_data = hwc_data->output_data;
+ int client_count = 0, device_count = 0, video_count = 0, cursor_count = 0;
+ int ui_lzpos_top = 0, ui_lzpos_bottom = 0, cursor_lzpos = 0, video_lzpos_top = -1;
+ int num_ui_layers = 0;
+ int i = 0;
+
+ composited_list = (tdm_meson_hwc_window **)composited_wnds;
+
+ ui_lzpos_top = output_data->layer_count - output_data->primary_zpos - 1;
+ ui_lzpos_bottom = output_data->primary_zpos;
+ num_ui_layers = output_data->layer_count - output_data->primary_zpos;
+ cursor_lzpos = output_data->layer_count - 1;
+
+ /* initialize the need_target_window */
+ hwc_data->need_target_window = 0;
+
+ /* initialize the validated_types */
+ LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) {
+ if (hwc_window_data->validated_type != HAL_TDM_HWC_WIN_COMPOSITION_NONE)
+ hwc_window_data->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_NONE;
+ }
+
+ /* use the target_window to commit when there is no window. */
+ if (num_wnds == 0) {
+ hwc_data->need_target_window = 1;
+ hwc_data->target_hwc_window->lzpos = ui_lzpos_bottom;
+ return;
+ }
+
+ /* 1. check validate_type video windows without target_window */
+ for (i = num_wnds - 1; i > 0; i--) {
+ switch(composited_list[i]->client_type) {
+ case HAL_TDM_HWC_WIN_COMPOSITION_VIDEO:
+ if (video_count > output_data->primary_zpos) break;
+
+ composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_VIDEO;
+ video_count++;
+ video_lzpos_top++;
+ continue;
+ default:
+ continue;
+ }
+
+ composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_CLIENT;
+ client_count++;
+ }
+
+ /* 2. check validate_type ui windows without target_window */
+ for (i = 0; i < num_wnds; i++) {
+ switch (composited_list[i]->client_type) {
+ case HAL_TDM_HWC_WIN_COMPOSITION_CURSOR:
+ /* temporary always use gl compositing */
+ break;
+#if 0
+ if (cursor_count > 0) break;
+ if (set_clients_below) break;
+ if (num_ui_layers <= 1) break; //need 1 layer for ui
+
+ composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_CURSOR;
+ cursor_count++;
+ ui_lzpos_top--;
+ num_ui_layers--;
+ continue;
+#endif
+ case HAL_TDM_HWC_WIN_COMPOSITION_DEVICE:
+ /* temporary always use gl compositing */
+ break;
+#if 0
+ if (set_clients_below) break;
+ if (num_ui_layers <= 0) break;
+ if (!_meson_hwc_window_can_set_on_hw_layer(composited_list[i])) break;
+
+ composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_DEVICE;
+ device_count++;
+ num_ui_layers--;
+ continue;
+#endif
+ case HAL_TDM_HWC_WIN_COMPOSITION_VIDEO:
+ continue;
+ case HAL_TDM_HWC_WIN_COMPOSITION_CLIENT:
+ break;
+ default:
+ continue;
+ }
+
+ composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_CLIENT;
+ client_count++;
+ }
+
+ /* 3. check need target window and set ui_lzpos top and bottom */
+ num_ui_layers = output_data->layer_count - video_count - cursor_count;
+
+ if (client_count > 0) {
+ hwc_data->need_target_window = 1;
+ hwc_data->target_hwc_window->lzpos = ui_lzpos_bottom;
+ ui_lzpos_bottom++;
+ num_ui_layers--;
+ }
+
+ if (num_ui_layers > device_count)
+ ui_lzpos_top = ui_lzpos_bottom + device_count - 1;
+
+ /* 4. set lzpos and modify validate_type with target_window */
+ for (i = 0; i < num_wnds; i++) {
+ switch (composited_list[i]->validated_type) {
+ case HAL_TDM_HWC_WIN_COMPOSITION_VIDEO:
+ composited_list[i]->lzpos = video_lzpos_top;
+ video_lzpos_top--;
+ continue;
+ case HAL_TDM_HWC_WIN_COMPOSITION_CURSOR:
+ composited_list[i]->lzpos = cursor_lzpos;
+ continue;
+ case HAL_TDM_HWC_WIN_COMPOSITION_DEVICE:
+ if (num_ui_layers <= 0) break;
+ composited_list[i]->lzpos = ui_lzpos_top;
+ ui_lzpos_top--;
+ num_ui_layers--;
+ continue;
+ default:
+ break;
+ }
+
+ composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_CLIENT;
+ composited_list[i]->lzpos = ZPOS_NONE;
+ }
+}
+
+static int
+_meson_hwc_get_changed_number(tdm_meson_hwc *hwc_data)
+{
+ int num = 0;
+ tdm_meson_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;
+}
+
+hal_tdm_hwc_window *
+_meson_hwc_create_window(hal_tdm_hwc *hwc, hal_tdm_hwc_window_info *info, hal_tdm_error *error)
+{
+ tdm_meson_hwc *hwc_data = hwc;
+ tdm_meson_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_meson_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;
+ hwc_window_data->acquire_fence = -1;
+
+ 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 *
+meson_hwc_create_window(hal_tdm_hwc *hwc, hal_tdm_error *error)
+{
+ tdm_meson_hwc *hwc_data = hwc;
+ tdm_meson_hwc_window *hwc_window_data = NULL;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, NULL);
+
+ hwc_window_data = _meson_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
+meson_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
+meson_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_SCALE;
+
+ /* temporary enable/disable */
+ char *env;
+
+ env = getenv("TDM_HWC_FENCE");
+ if (env) {
+ if (atoi(env))
+ *capabilities |= HAL_TDM_HWC_CAPABILITY_FENCE;
+ }
+ /* temporary enable/disable */
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_hwc_get_available_properties(hal_tdm_hwc *hwc, const hal_tdm_prop **props, int *count)
+{
+ tdm_meson_hwc *hwc_data = hwc;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(props != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(count != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ *props = NULL;
+ *count = 0;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+tbm_surface_queue_h
+meson_hwc_get_client_target_buffer_queue(hal_tdm_hwc *hwc, hal_tdm_error *error)
+{
+ tdm_meson_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 = _meson_hwc_window_get_tbm_buffer_queue(hwc_data->target_hwc_window, error);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(tqueue, NULL);
+
+ if (error)
+ *error = HAL_TDM_ERROR_NONE;
+
+ return tqueue;
+}
+
+hal_tdm_error
+meson_hwc_set_client_target_buffer(hal_tdm_hwc *hwc, tbm_surface_h buffer, hal_tdm_region damage)
+{
+ tdm_meson_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 = meson_hwc_window_set_buffer(hwc_data->target_hwc_window, buffer);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(err == HAL_TDM_ERROR_NONE, err);
+
+ err = meson_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
+meson_hwc_set_client_target_acquire_fence(hal_tdm_hwc *hwc, int acquire_fence)
+{
+ tdm_meson_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 = meson_hwc_window_set_acquire_fence(hwc_data->target_hwc_window, acquire_fence);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(err == HAL_TDM_ERROR_NONE, err);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_hwc_validate(hal_tdm_hwc *hwc, hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types)
+{
+ tdm_meson_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=================================");
+
+ _meson_hwc_apply_policy(hwc_data, composited_wnds, num_wnds);
+
+ *num_types = _meson_hwc_get_changed_number(hwc_data);
+
+ _print_validate_result(hwc_data, composited_wnds, num_wnds);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_hwc_get_changed_composition_types(hal_tdm_hwc *hwc, uint32_t *num_elements,
+ hal_tdm_hwc_window **hwc_wnds, hal_tdm_hwc_window_composition *composition_types)
+{
+ tdm_meson_hwc *hwc_data = hwc;
+ tdm_meson_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_wnds == NULL) || (composition_types == NULL)) {
+ *num_elements = _meson_hwc_get_changed_number(hwc_data);
+ return HAL_TDM_ERROR_NONE;
+ }
+
+ LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) {
+ if (hwc_window_data->client_type == HAL_TDM_HWC_WIN_COMPOSITION_NONE)
+ continue;
+
+ if (num >= *num_elements)
+ break;
+
+ if (hwc_window_data->client_type != hwc_window_data->validated_type) {
+ composition_types[num] = hwc_window_data->validated_type;
+ hwc_wnds[num] = hwc_window_data;
+ num++;
+ }
+ }
+
+ /* set real num of changed composition types */
+ *num_elements = num;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_hwc_accept_validation(hal_tdm_hwc *hwc)
+{
+ tdm_meson_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_DBG(" ==============Accept Changes Done=================================");
+
+ ret = _meson_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
+meson_hwc_commit(hal_tdm_hwc *hwc, int sync, void *user_data)
+{
+ tdm_meson_hwc *hwc_data = hwc;
+ tdm_meson_output *output_data = NULL;
+ hal_tdm_error ret;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ output_data = hwc_data->output_data;
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ TDM_BACKEND_DBG(" ==============COMMIT=================================");
+
+ ret = meson_output_commit(output_data, sync, user_data);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_hwc_set_commit_handler(hal_tdm_hwc *hwc, hal_tdm_hwc_commit_handler func)
+{
+ tdm_meson_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
+meson_hwc_get_commit_fence(hal_tdm_hwc *hwc, int *commit_fence)
+{
+ tdm_meson_hwc *hwc_data = hwc;
+ tdm_meson_output *output_data;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(commit_fence, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ output_data = hwc_data->output_data;
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ *commit_fence = dup(output_data->commit_fence);
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_hwc_get_release_fences(hal_tdm_hwc *hwc, uint32_t *num_elements,
+ hal_tdm_hwc_window **hwc_wnds, int *fences)
+{
+ tdm_meson_hwc *hwc_data = hwc;
+ tdm_meson_output *output_data;
+ tdm_meson_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);
+
+ output_data = hwc_data->output_data;
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ 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_DEVICE) &&
+ (hwc_window_data->validated_type != HAL_TDM_HWC_WIN_COMPOSITION_VIDEO))
+ continue;
+
+ if (hwc_wnds && fences) {
+ fences[num] = dup(output_data->commit_fence);
+ hwc_wnds[num] = hwc_window_data;
+ }
+
+ num++;
+ }
+
+ *num_elements = num;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_hwc_target_window_set_info(tdm_meson_hwc *hwc_data, int width, int height)
+{
+ hal_tdm_hwc_window_info info = {0};
+ tdm_meson_hwc_window *target_hwc_window;
+ hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data->target_hwc_window, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ target_hwc_window = hwc_data->target_hwc_window;
+
+ info.dst_pos.x = 0;
+ info.dst_pos.y = 0;
+ info.dst_pos.w = width;
+ info.dst_pos.h = height;
+
+ info.src_config.pos.x = 0;
+ info.src_config.pos.y = 0;
+ info.src_config.pos.w = width;
+ info.src_config.pos.h = height;
+
+ info.src_config.size.h = width;
+ info.src_config.size.v = height;
+ info.src_config.format = TBM_FORMAT_ARGB8888;
+
+ ret = meson_hwc_window_set_info(target_hwc_window, &info);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("set info target hwc window failed (%d)", ret);
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_hwc_initialize_target_window(tdm_meson_hwc *hwc_data)
+{
+ hal_tdm_hwc_window_info info = {0};
+ hal_tdm_error ret = HAL_TDM_ERROR_NONE;
+ tdm_meson_hwc_window *target_hwc_window;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ info.dst_pos.x = 0;
+ info.dst_pos.y = 0;
+ info.dst_pos.w = 2;
+ info.dst_pos.h = 1;
+
+ info.src_config.pos.x = 0;
+ info.src_config.pos.y = 0;
+ info.src_config.pos.w = 2;
+ info.src_config.pos.h = 1;
+
+ info.src_config.size.h = 2;
+ info.src_config.size.v = 1;
+ info.src_config.format = TBM_FORMAT_ARGB8888;
+
+ target_hwc_window = _meson_hwc_create_window(hwc_data, &info, &ret);
+ if (ret != HAL_TDM_ERROR_NONE) {
+ TDM_BACKEND_ERR("create target hwc window failed (%d)", ret);
+ if (target_hwc_window)
+ meson_hwc_window_destroy(target_hwc_window);
+
+ return HAL_TDM_ERROR_OPERATION_FAILED;
+ }
+
+ if (hwc_data->target_hwc_window)
+ meson_hwc_window_destroy(hwc_data->target_hwc_window);
+
+ hwc_data->target_hwc_window = target_hwc_window;
+ hwc_data->need_set_crtc = 1;
+
+ return HAL_TDM_ERROR_NONE;
+}
--- /dev/null
+/**************************************************************************
+
+libtdm_meson
+
+Copyright 2021 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: SooChan Lim <sc1.lim@samsung.com>,
+ Junkyeong Kim <jk0430.kim@samsung.com>,
+ Changyeon Lee <cyeon.lee@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.
+
+**************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_backend_meson.h"
+
+void
+meson_hwc_window_destroy(hal_tdm_hwc_window *hwc_window)
+{
+ tdm_meson_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
+meson_hwc_window_set_composition_type(hal_tdm_hwc_window *hwc_window,
+ hal_tdm_hwc_window_composition comp_type)
+{
+ tdm_meson_hwc_window *hwc_window_data = hwc_window;
+ tdm_meson_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
+meson_hwc_window_set_buffer_damage(hal_tdm_hwc_window *hwc_window, hal_tdm_region damage)
+{
+ tdm_meson_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
+meson_hwc_window_set_info(hal_tdm_hwc_window *hwc_window, hal_tdm_hwc_window_info *info)
+{
+ tdm_meson_hwc_window *hwc_window_data = hwc_window;
+ tdm_meson_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
+meson_hwc_window_set_buffer(hal_tdm_hwc_window *hwc_window, tbm_surface_h surface)
+{
+ tdm_meson_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
+meson_hwc_window_set_property(hal_tdm_hwc_window *hwc_window, unsigned int id, hal_tdm_value value)
+{
+ tdm_meson_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
+meson_hwc_window_get_property(hal_tdm_hwc_window *hwc_window, unsigned int id, hal_tdm_value *value)
+{
+ tdm_meson_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
+meson_hwc_window_get_constraints(hal_tdm_hwc_window *hwc_window, int *constraints)
+{
+ tdm_meson_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);
+
+ // no constraints
+ *constraints = 0;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_hwc_window_set_name(hal_tdm_hwc_window *hwc_window, const char *name)
+{
+ tdm_meson_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;
+}
+
+hal_tdm_error
+meson_hwc_window_set_cursor_image(hal_tdm_hwc_window *hwc_window, int width, int height, int stride, void *ptr)
+{
+ tdm_meson_hwc_window *hwc_window_data = hwc_window;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ hwc_window_data->cursor_img.width = width;
+ hwc_window_data->cursor_img.height = height;
+ hwc_window_data->cursor_img.stride = stride;
+ hwc_window_data->cursor_img.ptr = ptr;
+
+ hwc_window_data->cursor_img_refresh = 1;
+
+ return HAL_TDM_ERROR_NONE;
+}
+
+hal_tdm_error
+meson_hwc_window_set_acquire_fence(hal_tdm_hwc_window *hwc_window, int acquire_fence)
+{
+ tdm_meson_hwc_window *hwc_window_data = hwc_window;
+
+ TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
+
+ if (hwc_window_data->acquire_fence >= 0) {
+ close(hwc_window_data->acquire_fence);
+ hwc_window_data->acquire_fence = -1;
+ }
+
+ if (acquire_fence >= 0)
+ hwc_window_data->acquire_fence = dup(acquire_fence);
+
+ return HAL_TDM_ERROR_NONE;
+}