summaryrefslogtreecommitdiff
path: root/src/exynos.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/exynos.c')
-rwxr-xr-xsrc/exynos.c1933
1 files changed, 1933 insertions, 0 deletions
diff --git a/src/exynos.c b/src/exynos.c
new file mode 100755
index 0000000..608a843
--- /dev/null
+++ b/src/exynos.c
@@ -0,0 +1,1933 @@
+/**************************************************************************
+
+xserver-xorg-video-exynos
+
+Copyright 2011 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.
+
+**************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <xorg-server.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* all driver need this */
+#include "xf86.h"
+#include "xf86_OSproc.h"
+
+#include "fb.h"
+#include "mipointer.h"
+#include "micmap.h"
+#include "colormapst.h"
+#include "xf86cmap.h"
+#include "xf86xv.h"
+#include "xf86Crtc.h"
+#include "exynos.h"
+#include "exynos_display.h"
+#include "exynos_plane.h"
+#include "exynos_accel.h"
+#include "exynos_xberc.h"
+#include "exynos_util.h"
+#include "exynos_wb.h"
+#include "exynos_crtc.h"
+#include <tbm_bufmgr.h>
+#include "fimg2d.h"
+#include "exynos_output.h"
+#include "exynos_layer_manager.h"
+
+#define OPTION_FLIP_BUFFERS 0
+#define EXYNOS_DRM_NAME "exynos"
+
+/* prototypes */
+static const OptionInfoRec *EXYNOSAvailableOptions(int chipid, int busid);
+static void EXYNOSIdentify(int flags);
+static Bool EXYNOSProbe(DriverPtr pDrv, int flags);
+static Bool EXYNOSPreInit(ScrnInfoPtr pScrn, int flags);
+static Bool EXYNOSScreenInit(ScreenPtr pScreen, int argc, char **argv);
+static Bool EXYNOSSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr pMode);
+static void EXYNOSAdjustFrame(ScrnInfoPtr pScrn, int x, int y);
+static Bool EXYNOSEnterVT(ScrnInfoPtr pScrn);
+static void EXYNOSLeaveVT(ScrnInfoPtr pScrn);
+static ModeStatus EXYNOSValidMode(ScrnInfoPtr pScrn, DisplayModePtr pMode,
+ Bool verbose, int flags);
+static Bool EXYNOSCloseScreen(ScreenPtr pScreen);
+static Bool EXYNOSCreateScreenResources(ScreenPtr pScreen);
+
+#if HAVE_UDEV
+static void EXYNOSUdevEventsHandler(int fd, void *closure);
+#endif
+
+/* This DriverRec must be defined in the driver for Xserver to load this driver */
+_X_EXPORT DriverRec EXYNOS = {
+ EXYNOS_VERSION,
+ EXYNOS_DRIVER_NAME,
+ EXYNOSIdentify,
+ EXYNOSProbe,
+ EXYNOSAvailableOptions,
+ NULL,
+ 0,
+ NULL,
+};
+
+/* Supported "chipsets" */
+static SymTabRec EXYNOSChipsets[] = {
+ {0, "exynos"},
+ {-1, NULL}
+};
+
+/* Supported options */
+typedef enum {
+ OPTION_DRI2,
+ OPTION_EXA,
+ OPTION_SWEXA,
+ OPTION_ROTATE,
+ OPTION_SNAPSHOT,
+ OPTION_WB,
+#if OPTION_FLIP_BUFFERS
+ OPTION_FLIPBUFS,
+#endif
+ OPTION_CACHABLE,
+ OPTION_SCANOUT,
+ OPTION_ACCEL2D,
+ OPTION_PRESENT,
+ OPTION_DRI3,
+ OPTION_PARTIAL_UPDATE,
+ OPTION_HWC,
+ OPTION_HWA,
+ OPTION_SET_PLANE,
+ OPTION_PAGE_FLIP
+} EXYNOSOpts;
+
+static const OptionInfoRec EXYNOSOptions[] = {
+ {OPTION_DRI2, "dri2", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_EXA, "exa", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_SWEXA, "sw_exa", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_ROTATE, "rotate", OPTV_STRING, {0}, FALSE},
+ {OPTION_SNAPSHOT, "snapshot", OPTV_STRING, {0}, FALSE},
+ {OPTION_WB, "wb", OPTV_BOOLEAN, {0}, FALSE},
+#if OPTION_FLIP_BUFFERS
+ {OPTION_FLIPBUFS, "flip_bufs", OPTV_INTEGER, {0}, 3},
+#endif
+ {OPTION_CACHABLE, "cachable", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_SCANOUT, "scanout", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_ACCEL2D, "accel_2d", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_PRESENT, "present", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_DRI3, "dri3", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_PARTIAL_UPDATE, "partial_update", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_HWC, "hwc", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_HWA, "hwa", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_SET_PLANE, "set_plane", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_PAGE_FLIP, "flip", OPTV_BOOLEAN, {0}, FALSE},
+ {-1, NULL, OPTV_NONE, {0}, FALSE}
+};
+
+/* -------------------------------------------------------------------- */
+#ifdef XFree86LOADER
+
+MODULESETUPPROTO(EXYNOSSetup);
+
+static XF86ModuleVersionInfo EXYNOSVersRec = {
+ "exynos",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ PACKAGE_VERSION_MAJOR,
+ PACKAGE_VERSION_MINOR,
+ PACKAGE_VERSION_PATCHLEVEL,
+ ABI_CLASS_VIDEODRV,
+ ABI_VIDEODRV_VERSION,
+ NULL,
+ {0, 0, 0, 0}
+};
+
+_X_EXPORT XF86ModuleData exynosModuleData =
+ { &EXYNOSVersRec, EXYNOSSetup, NULL };
+
+pointer
+EXYNOSSetup(pointer module, pointer opts, int *errmaj, int *errmin)
+{
+ static Bool setupDone = FALSE;
+
+ if (!setupDone) {
+ setupDone = TRUE;
+ xf86AddDriver(&EXYNOS, module, HaveDriverFuncs);
+ return (pointer) 1;
+ }
+ else {
+ if (errmaj)
+ *errmaj = LDR_ONCEONLY;
+ return NULL;
+ }
+}
+
+#endif /* XFree86LOADER */
+/* -------------------------------------------------------------------- */
+
+static int
+_exynosOpenDRM(void)
+{
+ int fd = -1;
+
+ fd = drmOpen(EXYNOS_DRM_NAME, NULL);
+#ifdef HAVE_UDEV
+ if (fd < 0) {
+ struct udev *udev;
+ struct udev_enumerate *e;
+ struct udev_list_entry *entry;
+ struct udev_device *device, *drm_device, *device_parent;
+ const char *filename;
+
+ xf86Msg(X_WARNING, "[DRM] Cannot open drm device.. search by udev\n");
+ udev = udev_new();
+ if (!udev) {
+ xf86Msg(X_ERROR, "[DRM] fail to initialize udev context\n");
+ goto close_l;
+ }
+ /* Will try to find sys path /exynos-drm/drm/card0 */
+ e = udev_enumerate_new(udev);
+ udev_enumerate_add_match_subsystem(e, "drm");
+ udev_enumerate_add_match_sysname(e, "card[0-9]*");
+ udev_enumerate_scan_devices(e);
+
+ drm_device = NULL;
+ udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
+ device = udev_device_new_from_syspath(udev_enumerate_get_udev(e),
+ udev_list_entry_get_name
+ (entry));
+ device_parent = udev_device_get_parent(device);
+ /* Not need unref device_parent. device_parent and device have same refcnt */
+ if (device_parent) {
+ if (strcmp(udev_device_get_sysname(device_parent), "exynos-drm")
+ == 0) {
+ drm_device = device;
+ xf86Msg(X_INFO, "Found drm device: '%s' (%s)\n",
+ udev_device_get_syspath(drm_device),
+ udev_device_get_sysname(device_parent));
+ break;
+ }
+ }
+ udev_device_unref(device);
+ }
+
+ if (drm_device == NULL) {
+ xf86Msg(X_ERROR, "[DRM] fail to find drm device\n");
+ udev_enumerate_unref(e);
+ udev_unref(udev);
+ goto close_l;
+ }
+
+ filename = udev_device_get_devnode(drm_device);
+
+ fd = open(filename, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ xf86Msg(X_ERROR, "[DRM] Cannot open drm device(%s)\n", filename);
+ }
+ udev_device_unref(drm_device);
+ udev_enumerate_unref(e);
+ udev_unref(udev);
+ }
+#endif
+ close_l:
+ return fd;
+}
+
+static void
+_exynosCloseDRM(int fd)
+{
+ if (fd < 0)
+ return;
+ if (drmClose(fd) < 0) {
+ xf86Msg(X_ERROR, "[DRM] Cannot close drm device fd=%d\n", fd);
+ }
+}
+
+/*
+ * Probing the device with the device node, this probing depend on the specific hw.
+ * This function just verify whether the display hw is avaliable or not.
+ */
+static Bool
+_exynosHwProbe(struct pci_device *pPci, char *device, char **namep)
+{
+ int fd = -1;
+
+ fd = _exynosOpenDRM();
+ if (fd < 0) {
+ return FALSE;
+ }
+
+ _exynosCloseDRM(fd);
+ return TRUE;
+}
+
+static tbm_bufmgr
+_exynosInitBufmgr(int drm_fd, void *arg)
+{
+ tbm_bufmgr bufmgr = NULL;
+
+ /* get buffer manager */
+ setenv("BUFMGR_LOCK_TYPE", "once", 1);
+ setenv("BUFMGR_MAP_CACHE", "true", 1);
+ bufmgr = tbm_bufmgr_init(drm_fd);
+
+ if (bufmgr == NULL)
+ return NULL;
+
+ return bufmgr;
+}
+
+static void
+_exynosDeInitBufmgr(tbm_bufmgr bufmgr)
+{
+ if (bufmgr)
+ tbm_bufmgr_deinit(bufmgr);
+}
+
+/* open drm */
+static Bool
+_openDrmMaster(ScrnInfoPtr pScrn)
+{
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+ int ret;
+
+ /* open drm */
+ pExynos->drm_fd = _exynosOpenDRM();
+ if (pExynos->drm_fd < 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[DRM] Cannot open drm device\n");
+ goto fail_to_open_drm_master;
+ }
+
+ pExynos->drm_device_name = drmGetDeviceNameFromFd(pExynos->drm_fd);
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "[DRM] Succeed get drm device name:%s\n",
+ pExynos->drm_device_name);
+
+ /* enable drm vblank */
+ ret = drmCtlInstHandler(pExynos->drm_fd, 217);
+ if (ret) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "[DRM] Fail to enable drm VBlank(%d)\n", ret);
+ goto fail_to_open_drm_master;
+ }
+
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "[DRM] Enable drm VBlank(%d)\n", ret);
+
+ /* initialize drm bufmgr */
+ pExynos->tbm_bufmgr = _exynosInitBufmgr(pExynos->drm_fd, NULL);
+ if (pExynos->tbm_bufmgr == NULL) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "[DRM] Error : bufmgr initialization failed\n");
+ goto fail_to_open_drm_master;
+ }
+
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "[DRM] Enable buffer manager\n");
+
+ return TRUE;
+
+ fail_to_open_drm_master:
+
+ if (pExynos->tbm_bufmgr) {
+ _exynosDeInitBufmgr(pExynos->tbm_bufmgr);
+ pExynos->tbm_bufmgr = NULL;
+ }
+
+ if (pExynos->drm_device_name) {
+ free(pExynos->drm_device_name);
+ pExynos->drm_device_name = NULL;
+ }
+
+ if (pExynos->drm_fd >= 0) {
+ _exynosCloseDRM(pExynos->drm_fd);
+ pExynos->drm_fd = -1;
+ }
+
+ return FALSE;
+}
+
+/* close drm */
+static void
+_closeDrmMaster(ScrnInfoPtr pScrn)
+{
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+
+ if (pExynos->tbm_bufmgr) {
+ _exynosDeInitBufmgr(pExynos->tbm_bufmgr);
+ pExynos->tbm_bufmgr = NULL;
+ }
+
+ if (pExynos->drm_device_name) {
+ free(pExynos->drm_device_name);
+ pExynos->drm_device_name = NULL;
+ }
+
+ if (pExynos->drm_fd >= 0) {
+ _exynosCloseDRM(pExynos->drm_fd);
+ pExynos->drm_fd = -1;
+ }
+}
+
+/*
+ * Initialize the device Probing the device with the device node,
+ * this probing depend on the specific hw.
+ * This function just verify whether the display hw is avaliable or not.
+ */
+static Bool
+_exynosHwInit(ScrnInfoPtr pScrn, struct pci_device *pPci, char *device)
+{
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+
+ /* init drm master */
+ if (_openDrmMaster(pScrn) == TRUE)
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "DRM BLANK is enabled\n");
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "DRM BLANK is disabled\n");
+
+ if (g2d_init(pExynos->drm_fd)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "G2D is enabled\n");
+ pExynos->is_accel_2d = TRUE;
+ }
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "G2D is disabled\n");
+#ifdef NO_CRTC_MODE
+ /*** Temporary disable G2D acceleration for using PIXMAN ***/
+ pExynos->is_accel_2d = FALSE;
+#endif
+ return TRUE;
+}
+
+/* SigHook */
+OsSigWrapperPtr old_sig_wrapper;
+int
+_exynosOsSigWrapper(int sig)
+{
+ XDBG_KLOG(MSEC, "Catch SIG: %d\n", sig);
+
+ return old_sig_wrapper(sig); /*Contiue */
+}
+
+/*
+ * DeInitialize the hw
+ */
+static void
+_exynosHwDeinit(ScrnInfoPtr pScrn)
+{
+ g2d_fini();
+
+ /* deinit drm master */
+ _closeDrmMaster(pScrn);
+
+ return;
+}
+
+static Bool
+_allocScrnPrivRec(ScrnInfoPtr pScrn)
+{
+ if (pScrn->driverPrivate != NULL)
+ return TRUE;
+
+ pScrn->driverPrivate = calloc(sizeof(EXYNOSRec), 1);
+ if (!pScrn->driverPrivate)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+_freeScrnPrivRec(ScrnInfoPtr pScrn)
+{
+ if (pScrn->driverPrivate == NULL)
+ return;
+ free(pScrn->driverPrivate);
+ pScrn->driverPrivate = NULL;
+}
+
+/*
+ * Check the driver option.
+ * Set the option flags to the driver private
+ */
+static void
+_checkDriverOptions(ScrnInfoPtr pScrn)
+{
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+ const char *s;
+ int flip_bufs = 3;
+
+ /* exa */
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_EXA, TRUE))
+ pExynos->is_exa = TRUE;
+
+ /* sw exa */
+ if (pExynos->is_exa) {
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_SWEXA, TRUE))
+ pExynos->is_sw_exa = TRUE;
+ }
+
+ /* dri2 */
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_DRI2, FALSE)) {
+ pExynos->is_dri2 = TRUE;
+
+ /* number of the flip buffers */
+#if OPTION_FLIP_BUFFERS
+ if (xf86GetOptValInteger(pExynos->Options, OPTION_FLIPBUFS, &flip_bufs))
+ pExynos->flip_bufs = flip_bufs;
+ else
+#endif
+ {
+ /* default is 3 */
+ flip_bufs = 3;
+ pExynos->flip_bufs = flip_bufs;
+ }
+ }
+
+#ifdef HAVE_DRI3_PRESENT_H
+ /* present */
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_PRESENT, FALSE)) {
+ pExynos->is_present = TRUE;
+ }
+
+ /* dri3 */
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_DRI3, FALSE)) {
+ pExynos->is_dri3 = TRUE;
+ }
+#endif
+
+ /* rotate */
+ pExynos->rotate = RR_Rotate_0;
+ if ((s = xf86GetOptValString(pExynos->Options, OPTION_ROTATE))) {
+ if (!xf86NameCmp(s, "CW")) {
+ pExynos->rotate = RR_Rotate_90;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "rotating screen clockwise\n");
+ }
+ else if (!xf86NameCmp(s, "CCW")) {
+ pExynos->rotate = RR_Rotate_270;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "rotating screen counter-clockwise\n");
+ }
+ else if (!xf86NameCmp(s, "UD")) {
+ pExynos->rotate = RR_Rotate_180;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "rotating screen upside-down\n");
+ }
+ else {
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not valid option",
+ s);
+ }
+ }
+
+ /* wb */
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_WB, FALSE)) {
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_WB, TRUE))
+ pExynos->is_wb_clone = TRUE;
+ }
+
+ /* cachable */
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_CACHABLE, FALSE)) {
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_CACHABLE, TRUE)) {
+ pExynos->cachable = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Use cachable buffer.\n");
+ }
+ }
+
+ /* scanout */
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_SCANOUT, FALSE)) {
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_SCANOUT, TRUE)) {
+ pExynos->scanout = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Use scanout buffer.\n");
+ }
+ }
+
+ /* hw_2d */
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_ACCEL2D, FALSE)) {
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_ACCEL2D, TRUE)) {
+ pExynos->is_accel_2d = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Use 2d accelerator.\n");
+ }
+ }
+
+ /* use_partial_update */
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_PARTIAL_UPDATE, FALSE)) {
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_PARTIAL_UPDATE, TRUE)) {
+ pExynos->use_partial_update = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Use partial update.\n");
+ }
+ }
+
+ /* page_flip */
+ pExynos->use_flip = TRUE;
+ if (!xf86ReturnOptValBool(pExynos->Options, OPTION_PAGE_FLIP, TRUE)) {
+ pExynos->use_flip = FALSE;
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Page flip DISABLE\n");
+ }
+
+ /* HWC default */
+ pExynos->use_hwc = FALSE;
+ /* default value without HWC */
+ pExynos->use_setplane = FALSE;
+#ifdef HAVE_HWC_H
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_HWC, FALSE)) {
+ pExynos->use_hwc = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Use HWC extension.\n");
+ /* default value with HWC */
+ pExynos->use_setplane = TRUE;
+ }
+#endif
+
+#ifdef HAVE_HWA_H
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_HWA, FALSE)) {
+ pExynos->use_hwa = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Use HWA extension.\n");
+ }
+#endif
+
+ /* set_plane */
+ if (xf86ReturnOptValBool(pExynos->Options, OPTION_SET_PLANE, FALSE)) {
+ pExynos->use_setplane = TRUE;
+ }
+
+ if (pExynos->use_flip) {
+ if (pExynos->use_setplane)
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Page flip using plane\n");
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "Page flip using crtc (drmModePegeFlip())\n");
+ }
+
+}
+
+#if HAVE_UDEV
+static void
+_exynosUdevInit(ScrnInfoPtr pScrn)
+{
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+ struct udev *u;
+ struct udev_monitor *mon;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "hotplug detection\n");
+
+ u = udev_new();
+ if (!u)
+ return;
+
+ mon = udev_monitor_new_from_netlink(u, "udev");
+ if (!mon) {
+ udev_unref(u);
+ return;
+ }
+
+ if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor")
+ > 0 || udev_monitor_enable_receiving(mon) < 0) {
+ udev_monitor_unref(mon);
+ udev_unref(u);
+ return;
+ }
+
+ pExynos->uevent_handler =
+ xf86AddGeneralHandler(udev_monitor_get_fd(mon), EXYNOSUdevEventsHandler,
+ pScrn);
+ if (!pExynos->uevent_handler) {
+ udev_monitor_unref(mon);
+ udev_unref(u);
+ return;
+ }
+
+ pExynos->uevent_monitor = mon;
+}
+
+static void
+_exynosUdevDeinit(ScrnInfoPtr pScrn)
+{
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+
+ if (pExynos->uevent_handler) {
+ struct udev *u = udev_monitor_get_udev(pExynos->uevent_monitor);
+
+ udev_monitor_unref(pExynos->uevent_monitor);
+ udev_unref(u);
+ pExynos->uevent_handler = NULL;
+ pExynos->uevent_monitor = NULL;
+ }
+
+}
+
+static Bool
+EXYNOSSaveScreen(ScreenPtr pScreen, int mode)
+{
+ /* dummpy save screen */
+ return TRUE;
+}
+
+static void
+EXYNOSUdevEventsHandler(int fd, void *closure)
+{
+ ScrnInfoPtr pScrn = closure;
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+ struct udev_device *dev;
+ const char *hotplug;
+ struct stat s;
+ dev_t udev_devnum;
+ int ret;
+
+ dev = udev_monitor_receive_device(pExynos->uevent_monitor);
+ if (!dev)
+ return;
+
+ udev_devnum = udev_device_get_devnum(dev);
+
+ ret = fstat(pExynos->drm_fd, &s);
+ if (ret == -1)
+ return;
+
+ /*
+ * Check to make sure this event is directed at our
+ * device (by comparing dev_t values), then make
+ * sure it's a hotplug event (HOTPLUG=1)
+ */
+ hotplug = udev_device_get_property_value(dev, "HOTPLUG");
+
+ if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
+ hotplug && atoi(hotplug) == 1) {
+ XDBG_INFO(MSEC, "EXYNOS-UDEV: HotPlug\n");
+ exynosOutputDrmUpdate(pScrn);
+ RRGetInfo(xf86ScrnToScreen(pScrn), TRUE);
+#ifdef NO_CRTC_MODE
+// exynosDisplayChangeMode(pScrn);
+#endif
+ }
+
+ udev_device_unref(dev);
+}
+#endif /* UDEV_HAVE */
+
+static const OptionInfoRec *
+EXYNOSAvailableOptions(int chipid, int busid)
+{
+ return EXYNOSOptions;
+}
+
+static void
+EXYNOSIdentify(int flags)
+{
+ xf86PrintChipsets(EXYNOS_NAME, "driver for Exynos Chipsets",
+ EXYNOSChipsets);
+}
+
+/* The purpose of this function is to identify all instances of hardware supported
+ * by the driver. The probe must find the active device exynostions that match the driver
+ * by calling xf86MatchDevice().
+ */
+static Bool
+EXYNOSProbe(DriverPtr pDrv, int flags)
+{
+ int i;
+ ScrnInfoPtr pScrn;
+ GDevPtr *ppDevSections = NULL;
+ int numDevSections;
+ int entity;
+ Bool foundScreen = FALSE;
+
+ /* check the drm mode setting */
+ if (!_exynosHwProbe(NULL, NULL, NULL)) {
+ return FALSE;
+ }
+
+ numDevSections = xf86MatchDevice(EXYNOS_DRIVER_NAME, &ppDevSections);
+
+ if ((flags & PROBE_DETECT) && (numDevSections <= 0)) {
+ numDevSections = 1;
+ }
+
+ for (i = 0; i < numDevSections; i++) {
+
+ if (flags & PROBE_DETECT) {
+ xf86AddBusDeviceToConfigure(EXYNOS_DRIVER_NAME, BUS_NONE, NULL, i);
+ foundScreen = TRUE;
+ continue;
+ }
+
+ pScrn = xf86AllocateScreen(pDrv, flags);
+
+ if (ppDevSections) {
+ entity = xf86ClaimNoSlot(pDrv, 0, ppDevSections[i], TRUE);
+ xf86AddEntityToScreen(pScrn, entity);
+ }
+
+ if (pScrn) {
+ foundScreen = TRUE;
+
+ pScrn->driverVersion = EXYNOS_VERSION;
+ pScrn->driverName = EXYNOS_DRIVER_NAME;
+ pScrn->name = EXYNOS_NAME;
+ pScrn->Probe = EXYNOSProbe;
+ pScrn->PreInit = EXYNOSPreInit;
+ pScrn->ScreenInit = EXYNOSScreenInit;
+ pScrn->SwitchMode = EXYNOSSwitchMode;
+ pScrn->AdjustFrame = EXYNOSAdjustFrame;
+ pScrn->EnterVT = EXYNOSEnterVT;
+ pScrn->LeaveVT = EXYNOSLeaveVT;
+ pScrn->ValidMode = EXYNOSValidMode;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "using drm mode setting device\n");
+ }
+ }
+ if (ppDevSections) {
+ free(ppDevSections);
+ }
+
+ return foundScreen;
+}
+
+/*
+ * This is called before ScreenInit to probe the screen configuration.
+ * The main tasks to do in this funtion are probing, module loading, option handling,
+ * card mapping, and mode setting setup.
+ */
+static Bool
+EXYNOSPreInit(ScrnInfoPtr pScrn, int flags)
+{
+ EXYNOSPtr pExynos;
+ Gamma defualt_gamma = { 0.0, 0.0, 0.0 };
+ rgb default_weight = { 0, 0, 0 };
+ int flag24;
+
+ if (flags & PROBE_DETECT)
+ return FALSE;
+
+ /* allocate private */
+ if (!_allocScrnPrivRec(pScrn))
+ return FALSE;
+ pExynos = EXYNOSPTR(pScrn);
+
+ /* Check the number of entities, and fail if it isn't one. */
+ if (pScrn->numEntities != 1)
+ return FALSE;
+
+ pExynos->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
+
+ /* initialize the hardware specifics */
+ if (!_exynosHwInit(pScrn, NULL, NULL)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "fail to initialize hardware\n");
+ goto bail1;
+ }
+
+ pScrn->displayWidth = 640; /*default width */
+ pScrn->monitor = pScrn->confScreen->monitor;
+ pScrn->progClock = TRUE;
+ pScrn->rgbBits = 8;
+
+ /* set the depth and the bpp to pScrn */
+ flag24 = Support24bppFb | Support32bppFb;
+ if (!xf86SetDepthBpp(pScrn, 0, 0, 0, flag24)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "fail to find the depth\n");
+ goto bail1;
+ }
+ xf86PrintDepthBpp(pScrn); /* just print out the depth and the bpp */
+
+ /* color weight */
+ if (!xf86SetWeight(pScrn, default_weight, default_weight)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "fail to set the color weight of RGB\n");
+ goto bail1;
+ }
+
+ /* visual init, make a TrueColor, -1 */
+ if (!xf86SetDefaultVisual(pScrn, -1)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "fail to initialize the default visual\n");
+ goto bail1;
+ }
+
+ /* Collect all the option flags (fill in pScrn->options) */
+ xf86CollectOptions(pScrn, NULL);
+
+ /*
+ * Process the options based on the information EXYNOSOptions.
+ * The results are written to pExynos->Options. If all the options
+ * processing is done within this fuction a local variable "options"
+ * can be used instead of pExynos->Options
+ */
+ if (!(pExynos->Options = malloc(sizeof(EXYNOSOptions))))
+ goto bail1;
+ memcpy(pExynos->Options, EXYNOSOptions, sizeof(EXYNOSOptions));
+ xf86ProcessOptions(pScrn->scrnIndex, pExynos->pEnt->device->options,
+ pExynos->Options);
+
+ /* Check with the driver options */
+ _checkDriverOptions(pScrn);
+
+ /* use a fake root pixmap when rotation angle is 90 or 270 */
+ pExynos->fake_root =
+ ((pExynos->rotate & (RR_Rotate_90 | RR_Rotate_270)) != 0);
+
+ /* drm mode init:: Set the Crtc, the default Output, and the current Mode */
+ if (!exynosModePreInit(pScrn, pExynos->drm_fd)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "fail to initialize drm mode setting\n");
+ goto bail1;
+ }
+
+ /* set gamma */
+ if (!xf86SetGamma(pScrn, defualt_gamma)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "fail to set the gamma\n");
+ goto bail1;
+ }
+#ifdef NO_CRTC_MODE
+ if (pScrn->modes == NULL) {
+ pScrn->modes = xf86ModesAdd(pScrn->modes,
+ xf86CVTMode(pScrn->virtualX,
+ pScrn->virtualY, 60, 0, 0));
+ }
+#endif
+ pScrn->currentMode = pScrn->modes;
+
+ pScrn->displayWidth = pScrn->virtualX;
+ xf86PrintModes(pScrn); /* just print the current mode */
+
+ /* set dpi */
+ xf86SetDpi(pScrn, 0, 0);
+
+ /* Load modules */
+ if (!xf86LoadSubModule(pScrn, "fb")) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "fail to load fb module\n");
+ goto bail1;
+ }
+
+ if (!xf86LoadSubModule(pScrn, "exa")) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "fail to load exa module\n");
+ goto bail1;
+ }
+
+ if (!xf86LoadSubModule(pScrn, "dri2")) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "fail to load dri2 module\n");
+ goto bail1;
+ }
+
+ old_sig_wrapper = OsRegisterSigWrapper(_exynosOsSigWrapper);
+ return TRUE;
+
+ bail1:
+ _freeScrnPrivRec(pScrn);
+ _exynosHwDeinit(pScrn);
+ return FALSE;
+}
+
+static Bool
+EXYNOSScreenInit(ScreenPtr pScreen, int argc, char **argv)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+ VisualPtr visual;
+ int init_picture = 0;
+ EXYNOSFbPtr pFb = NULL;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Infomation of Visual is \n\tbitsPerPixel=%d, depth=%d, defaultVisual=%s\n"
+ "\tmask: %x,%x,%x, offset: %d,%d,%d\n",
+ pScrn->bitsPerPixel,
+ pScrn->depth,
+ xf86GetVisualName(pScrn->defaultVisual),
+ (unsigned int) pScrn->mask.red,
+ (unsigned int) pScrn->mask.green,
+ (unsigned int) pScrn->mask.blue,
+ (int) pScrn->offset.red,
+ (int) pScrn->offset.green, (int) pScrn->offset.blue);
+#ifdef LAYER_MANAGER
+ /* Init Layer manager */
+ if (!exynosLayerMngInit(pScrn)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Fail to initialize layer manager\n");
+ return FALSE;
+ }
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[LYRM] Initialized layer manager\n");
+#endif
+ /* initialize the framebuffer */
+ /* soolim :: think rotations */
+
+ pFb = exynosFbAllocate(pScrn, pScrn->virtualX, pScrn->virtualY);
+ if (!pFb) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "cannot allocate framebuffer\n");
+ return FALSE;
+ }
+ pExynos->pFb = pFb;
+
+ /* mi layer */
+ miClearVisualTypes();
+ if (!miSetVisualTypes
+ (pScrn->depth, TrueColorMask, pScrn->rgbBits, TrueColor)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "visual type setup failed for %d bits per pixel [1]\n",
+ pScrn->bitsPerPixel);
+ return FALSE;
+ }
+
+ if (!miSetPixmapDepths()) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "pixmap depth setup failed\n");
+ return FALSE;
+ }
+
+ switch (pScrn->bitsPerPixel) {
+ case 16:
+ case 24:
+ case 32:
+ if (!fbScreenInit(pScreen, (void *) ROOT_FB_ADDR, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->virtualX, /*Pixel width for framebuffer */
+ pScrn->bitsPerPixel))
+ return FALSE;
+
+ init_picture = 1;
+
+ break;
+ default:
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "internal error: invalid number of bits per pixel (%d) encountered\n",
+ pScrn->bitsPerPixel);
+ break;
+ }
+
+ if (pScrn->bitsPerPixel > 8) {
+ /* Fixup RGB ordering */
+ visual = pScreen->visuals + pScreen->numVisuals;
+ while (--visual >= pScreen->visuals) {
+ if ((visual->class | DynamicClass) == DirectColor) {
+ visual->offsetRed = pScrn->offset.red;
+ visual->offsetGreen = pScrn->offset.green;
+ visual->offsetBlue = pScrn->offset.blue;
+ visual->redMask = pScrn->mask.red;
+ visual->greenMask = pScrn->mask.green;
+ visual->blueMask = pScrn->mask.blue;
+ }
+ }
+ }
+
+ /* must be after RGB ordering fixed */
+ if (init_picture && !fbPictureInit(pScreen, NULL, 0)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Render extension initialisation failed\n");
+ }
+
+ /* init the exa */
+ if (pExynos->is_exa) {
+ if (!exynosExaInit(pScreen)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "EXA initialization failed\n");
+ }
+ else {
+ /* init the dri2 */
+ if (pExynos->is_dri2) {
+ if (!exynosDri2Init(pScreen)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "DRI2 initialization failed\n");
+ }
+ }
+
+#ifdef HAVE_DRI3_PRESENT_H
+ if (pExynos->is_present) {
+ if (!exynosPresentScreenInit(pScreen)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Present initialization failed\n");
+ }
+ }
+
+ /* init the dri3 */
+ if (pExynos->is_dri3) {
+ if (!exynosDri3ScreenInit(pScreen)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "DRI3 initialization failed\n");
+ }
+ }
+#endif
+ }
+ }
+
+#ifdef HAVE_HWC_H
+ if (pExynos->use_hwc) {
+ if (!exynosHwcInit(pScreen)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "HWC initialization failed\n");
+ }
+ else {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "HWC initialization succeed\n");
+ }
+ }
+#endif
+
+#ifdef HAVE_HWA_H
+ if (pExynos->use_hwa) {
+ if (!exynosHwaInit(pScreen)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "HWA initialization failed\n");
+ }
+ else {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "HWA initialization succeed\n");
+ }
+ }
+#endif
+
+ /* XVideo Initiailization here */
+ if (!exynosVideoInit(pScreen))
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "XVideo extention initialization failed\n");
+
+ xf86SetBlackWhitePixels(pScreen);
+ xf86SetBackingStore(pScreen);
+
+ /* use dummy hw_cursro instead of sw_cursor */
+ miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing HW Cursor\n");
+#if 1
+ if (!xf86_cursors_init(pScreen, EXYNOS_CURSOR_W, EXYNOS_CURSOR_H,
+ (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
+ HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
+ HARDWARE_CURSOR_INVERT_MASK |
+ HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
+ HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
+ HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 |
+ HARDWARE_CURSOR_ARGB))) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Hardware cursor initialization failed\n");
+ }
+#endif
+ /* crtc init */
+ if (!xf86CrtcScreenInit(pScreen))
+ return FALSE;
+
+ /* set the desire mode : set the mode to xf86crtc here */
+ xf86SetDesiredModes(pScrn);
+
+ /* colormap */
+ if (!miCreateDefColormap(pScreen)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "internal error: miCreateDefColormap failed \n");
+ return FALSE;
+ }
+
+ if (!xf86HandleColormaps(pScreen, 256, 8, exynosModeLoadPalette, NULL,
+ CMAP_PALETTED_TRUECOLOR))
+ return FALSE;
+
+ /* dpms */
+ xf86DPMSInit(pScreen, xf86DPMSSet, 0);
+
+ /* screen saver */
+ pScreen->SaveScreen = EXYNOSSaveScreen;
+
+ exynosModeInit(pScrn);
+
+ /* Wrap the current CloseScreen function */
+ pExynos->CloseScreen = pScreen->CloseScreen;
+ pScreen->CloseScreen = EXYNOSCloseScreen;
+
+ /* Wrap the current CloseScreen function */
+ pExynos->CreateScreenResources = pScreen->CreateScreenResources;
+ pScreen->CreateScreenResources = EXYNOSCreateScreenResources;
+
+#if HAVE_UDEV
+ _exynosUdevInit(pScrn);
+#endif
+
+#if 0
+ /* Init Hooks for memory flush */
+ exynosMemoryInstallHooks();
+#endif
+
+#if USE_XDBG
+ xDbgLogPListInit(pScreen);
+#endif
+#if 0
+ xDbgLogSetLevel(MDRI2, 0);
+ xDbgLogSetLevel(MEXA, 0);
+ xDbgLogSetLevel(MLYRM, 0);
+#endif
+#ifdef NO_CRTC_MODE
+ pExynos->isCrtcOn = exynosCrtcCheckInUseAll(pScrn);
+#endif
+ XDBG_KLOG(MSEC, "Init Screen\n");
+ return TRUE;
+}
+
+static Bool
+EXYNOSSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
+{
+ return xf86SetSingleMode(pScrn, pMode, RR_Rotate_0);
+}
+
+static void
+EXYNOSAdjustFrame(ScrnInfoPtr pScrn, int x, int y)
+{
+}
+
+static Bool
+EXYNOSEnterVT(ScrnInfoPtr pScrn)
+{
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+ xf86OutputPtr pOutput;
+ EXYNOSCrtcPrivPtr pCrtcPriv;
+ xf86CrtcConfigPtr pXf86CrtcConfig;
+ int ret;
+ int i;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "EnterVT::Hardware state at EnterVT:\n");
+
+ if (pExynos->drm_fd > 0) {
+ ret = drmSetMaster(pExynos->drm_fd);
+ if (ret)
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "EnterVT::failed to set drm_fd %d as master.\n",
+ pExynos->drm_fd);
+ }
+
+ pXf86CrtcConfig = XF86_CRTC_CONFIG_PTR(pScrn);
+ for (i = 0; i < pXf86CrtcConfig->num_output; i++) {
+ pOutput = pXf86CrtcConfig->output[i];
+ if (!strcmp(pOutput->name, "LVDS1") || !strcmp(pOutput->name, "HDMI1")) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EnterVT::Find %s Output:\n",
+ pOutput->name);
+
+ pCrtcPriv = pOutput->crtc->driver_private;
+
+ if (pCrtcPriv->bAccessibility ||
+ pCrtcPriv->screen_rotate_degree > 0) {
+ tbm_bo src_bo = pCrtcPriv->front_bo;
+ tbm_bo dst_bo = pCrtcPriv->accessibility_back_bo;
+
+ if (!exynosCrtcExecAccessibility(pOutput->crtc, src_bo, dst_bo)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "EnterVT::Fail execute accessibility(output name, %s)\n",
+ pOutput->name);
+ }
+ }
+
+ /* set current fb to crtc */
+ if (!exynosCrtcApply(pOutput->crtc)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "EnterVT::Fail crtc apply(output name, %s)\n",
+ pOutput->name);
+ }
+ return TRUE;
+ }
+ }
+
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "EnterVT::failed to find Output.\n");
+
+ return TRUE;
+}
+
+static void
+EXYNOSLeaveVT(ScrnInfoPtr pScrn)
+{
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+ int ret;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "LeaveVT::Hardware state at LeaveVT:\n");
+
+ if (pExynos->drm_fd > 0) {
+ ret = drmDropMaster(pExynos->drm_fd);
+ if (ret)
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "LeaveVT::drmDropMaster failed for drmFD %d: %s\n",
+ pExynos->drm_fd, strerror(errno));
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "LeaveVT::drmFD dropped master.\n");
+ }
+}
+
+static ModeStatus
+EXYNOSValidMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, Bool verbose,
+ int flags)
+{
+ return MODE_OK;
+}
+
+/**
+ * Adjust the screen pixmap for the current location of the front buffer.
+ * This is done at EnterVT when buffers are bound as long as the resources
+ * have already been created, but the first EnterVT happens before
+ * CreateScreenResources.
+ */
+static Bool
+EXYNOSCreateScreenResources(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+
+ pScreen->CreateScreenResources = pExynos->CreateScreenResources;
+ if (!(*pScreen->CreateScreenResources) (pScreen))
+ return FALSE;
+
+ /*
+ * [TODO]:::::
+ * create screen resources
+ * set the bo to the screen pixamp private here
+ * or create the shadow pixmap for the screen pixamp here
+ * or set the fake rotated screen infomation here.
+ */
+
+ return TRUE;
+}
+
+static Bool
+EXYNOSCloseScreen(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+
+ exynosWbDestroy();
+
+#if HAVE_UDEV
+ _exynosUdevDeinit(pScrn);
+#endif
+
+ exynosHwcDeinit(pScreen);
+#ifdef LAYER_MANAGER
+ exynosLayerMngDeInit(pScrn);
+#endif
+ exynosVideoFini(pScreen);
+ exynosExaDeinit(pScreen);
+ exynosModeDeinit(pScrn);
+ if (pExynos->pFb) {
+ exynosFbFree(pExynos->pFb);
+ pExynos->pFb = NULL;
+ }
+
+ _exynosHwDeinit(pScrn);
+
+ pScrn->vtSema = FALSE;
+
+ pScreen->CreateScreenResources = pExynos->CreateScreenResources;
+ pScreen->CloseScreen = pExynos->CloseScreen;
+
+ XDBG_KLOG(MSEC, "Close Screen\n");
+ return (*pScreen->CloseScreen) (pScreen);
+}
+
+#define CONV_POINT_TO_KEY(x, y, key) key = (unsigned long)((((unsigned short)(x&0xFFFF)) << 16) | ((unsigned short)(y&0xFFFF )))
+#define CONT_KEY_TO_POINT(key, x, y) x = (unsigned short)((key&0xFFFF0000)>>16); y=(unsigned short)(key&0xFFFF)
+
+typedef struct {
+ tbm_bo bo;
+ struct xorg_list link;
+} SecFbBoItem, *SecFbBoItemPtr;
+
+static void
+_exynosFbFreeBoData(void *data)
+{
+ XDBG_RETURN_IF_FAIL(data != NULL);
+
+ ScrnInfoPtr pScrn;
+ EXYNOSPtr pExynos;
+ EXYNOSFbBoDataPtr bo_data = (EXYNOSFbBoDataPtr) data;
+
+ pScrn = bo_data->pScrn;
+ pExynos = EXYNOSPTR(pScrn);
+
+ XDBG_DEBUG(MFB, "FreeRender bo_data gem:%d, fb_id:%d, %dx%d+%d+%d\n",
+ bo_data->gem_handle, bo_data->fb_id,
+ bo_data->pos.x2 - bo_data->pos.x1,
+ bo_data->pos.y2 - bo_data->pos.y1, bo_data->pos.x1,
+ bo_data->pos.y1);
+
+ if (bo_data->fb_id) {
+ drmModeRmFB(pExynos->drm_fd, bo_data->fb_id);
+ bo_data->fb_id = 0;
+ }
+
+ if (bo_data->pPixmap) {
+ pScrn->pScreen->DestroyPixmap(bo_data->pPixmap);
+ bo_data->pPixmap = NULL;
+ }
+
+ free(bo_data);
+ bo_data = NULL;
+}
+
+static tbm_bo
+_exynosFbCreateBo2(EXYNOSFbPtr pFb, int x, int y, int width, int height,
+ tbm_bo prev_bo, Bool clear)
+{
+ XDBG_RETURN_VAL_IF_FAIL((pFb != NULL), NULL);
+ XDBG_RETURN_VAL_IF_FAIL((width > 0), NULL);
+ XDBG_RETURN_VAL_IF_FAIL((height > 0), NULL);
+
+ EXYNOSPtr pExynos = EXYNOSPTR(pFb->pScrn);
+
+ tbm_bo bo = NULL;
+ tbm_bo_handle bo_handle2;
+ EXYNOSFbBoDataPtr bo_data = NULL;
+ unsigned int pitch;
+ unsigned int fb_id = 0;
+ int ret;
+ int flag;
+
+ pitch = width * 4;
+
+ if (!pExynos->cachable)
+ flag = TBM_BO_WC;
+ else
+ flag = TBM_BO_DEFAULT;
+
+ if (prev_bo != NULL) {
+ XDBG_RETURN_VAL_IF_FAIL(tbm_bo_size(prev_bo) >= (pitch * height), NULL);
+
+ tbm_bo_delete_user_data(prev_bo, TBM_BO_DATA_FB);
+
+ /* TODO: check flags */
+
+ bo = prev_bo;
+ }
+ else {
+ bo = tbm_bo_alloc(pExynos->tbm_bufmgr, pitch * height, flag);
+ XDBG_GOTO_IF_FAIL(bo != NULL, fail);
+ }
+
+ if (clear) {
+ tbm_bo_handle bo_handle1;
+
+ /* memset 0x0 */
+ bo_handle1 = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
+ XDBG_RETURN_VAL_IF_FAIL(bo_handle1.ptr != NULL, NULL);
+
+ memset(bo_handle1.ptr, 0x0, pitch * height);
+ tbm_bo_unmap(bo);
+ }
+
+ bo_handle2 = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT);
+
+ /* Create drm fb */
+ ret =
+ drmModeAddFB(pExynos->drm_fd, width, height, pFb->pScrn->bitsPerPixel,
+ pFb->pScrn->bitsPerPixel, pitch, bo_handle2.u32, &fb_id);
+ XDBG_GOTO_IF_ERRNO(ret == Success, fail, -ret);
+
+ if (x == -1)
+ x = 0;
+ if (y == -1)
+ y = 0;
+
+ /* Set bo user data */
+ bo_data = calloc(1, sizeof(EXYNOSFbBoDataRec));
+ XDBG_GOTO_IF_FAIL(bo_data != NULL, fail);
+ bo_data->pFb = pFb;
+ bo_data->gem_handle = bo_handle2.u32;
+ bo_data->pitch = pitch;
+ bo_data->fb_id = fb_id;
+ bo_data->pos.x1 = x;
+ bo_data->pos.y1 = y;
+ bo_data->pos.x2 = x + width;
+ bo_data->pos.y2 = y + height;
+ bo_data->size = tbm_bo_size(bo);
+ bo_data->pScrn = pFb->pScrn;
+ XDBG_GOTO_IF_FAIL(tbm_bo_add_user_data
+ (bo, TBM_BO_DATA_FB, _exynosFbFreeBoData), fail);
+ XDBG_GOTO_IF_FAIL(tbm_bo_set_user_data
+ (bo, TBM_BO_DATA_FB, (void *) bo_data), fail);
+
+ XDBG_DEBUG(MFB, "CreateRender bo(name:%d, gem:%d, fb_id:%d, %dx%d+%d+%d\n",
+ tbm_bo_export(bo), bo_data->gem_handle, bo_data->fb_id,
+ bo_data->pos.x2 - bo_data->pos.x1,
+ bo_data->pos.y2 - bo_data->pos.y1, bo_data->pos.x1,
+ bo_data->pos.y1);
+
+ return bo;
+ fail:
+ if (bo) {
+ exynosRenderBoUnref(bo);
+ }
+
+ if (fb_id) {
+ drmModeRmFB(pExynos->drm_fd, fb_id);
+ }
+
+ if (bo_data) {
+ free(bo_data);
+ bo_data = NULL;
+ }
+
+ return NULL;
+}
+
+static tbm_bo
+_exynosFbCreateBo(EXYNOSFbPtr pFb, int x, int y, int width, int height)
+{
+ return _exynosFbCreateBo2(pFb, x, y, width, height, NULL, TRUE);
+}
+
+static tbm_bo
+_exynosFbRefBo(tbm_bo bo)
+{
+ return tbm_bo_ref(bo);
+}
+
+static int
+_exynosFbUnrefBo(tbm_bo bo)
+{
+ tbm_bo_unref(bo);
+ bo = NULL;
+
+ return TRUE;
+}
+
+EXYNOSFbPtr
+exynosFbAllocate(ScrnInfoPtr pScrn, int width, int height)
+{
+ //exynosLogSetLevel(MFB, 0);
+
+ XDBG_RETURN_VAL_IF_FAIL((pScrn != NULL), NULL);
+ XDBG_RETURN_VAL_IF_FAIL((width > 0), NULL);
+ XDBG_RETURN_VAL_IF_FAIL((height > 0), NULL);
+
+ EXYNOSFbPtr pFb = calloc(1, sizeof(EXYNOSFbRec));
+
+ XDBG_GOTO_IF_FAIL((pFb != NULL), fail);
+
+ pFb->pScrn = pScrn;
+ pFb->num_bo = 0;
+ pFb->width = width;
+ pFb->height = height;
+
+ xorg_list_init(&pFb->list_bo);
+
+ /* Create default buffer */
+ pFb->default_bo = _exynosFbCreateBo(pFb, 0, 0, width, height);
+
+ XDBG_TRACE(MFB, "Allocate %dx%d\n", width, height);
+
+ return pFb;
+
+ fail:
+
+ return NULL;
+}
+
+void
+exynosFbFree(EXYNOSFbPtr pFb)
+{
+ XDBG_RETURN_IF_FAIL(pFb != NULL);
+
+ XDBG_TRACE(MFB, "Free %dx%d, num:%d\n", pFb->width, pFb->height,
+ pFb->num_bo);
+
+ if (!xorg_list_is_empty(&pFb->list_bo)) {
+ SecFbBoItemPtr item = NULL, tmp = NULL;
+
+ xorg_list_for_each_entry_safe(item, tmp, &pFb->list_bo, link) {
+ xorg_list_del(&item->link);
+ _exynosFbUnrefBo(item->bo);
+ free(item);
+ item = NULL;
+ }
+ }
+
+ if (pFb->default_bo) {
+ exynosRenderBoUnref(pFb->default_bo);
+ pFb->default_bo = NULL;
+ }
+
+ free(pFb);
+ pFb = NULL;
+}
+
+tbm_bo
+exynosFbGetBo(EXYNOSFbPtr pFb, int x, int y, int width, int height,
+ Bool onlyIfExists)
+{
+ EXYNOSFbBoDataPtr bo_data = NULL;
+ tbm_bo bo = NULL;
+ _X_UNUSED unsigned long key;
+ BoxRec box;
+ BoxPtr b1, b2;
+ int ret = rgnOUT;
+
+ box.x1 = x;
+ box.y1 = y;
+ box.x2 = x + width;
+ box.y2 = y + height;
+ b2 = &box;
+
+ if (!xorg_list_is_empty(&pFb->list_bo)) {
+ SecFbBoItemPtr item = NULL, tmp = NULL;
+
+ xorg_list_for_each_entry_safe(item, tmp, &pFb->list_bo, link) {
+ bo = item->bo;
+
+ tbm_bo_get_user_data(bo, TBM_BO_DATA_FB, (void * *) &bo_data);
+ b1 = &bo_data->pos;
+
+ ret = exynosUtilBoxInBox(b1, b2);
+
+ if (ret == rgnIN || ret == rgnSAME) {
+ return bo;
+ }
+#if 0
+ else if (ret == rgnPART) {
+ if (!onlyIfExists)
+ continue;
+
+ int r2 = exynosUtilBoxInBox(b2, b1);
+
+ if (r2 == rgnIN) {
+ xorg_list_del(&item->link);
+ _exynosFbUnrefBo(bo);
+ free(item);
+ item = NULL;
+ pFb->num_bo--;
+ ret = rgnOUT;
+ break;
+ }
+ }
+#endif
+ else if (ret == rgnOUT || ret == rgnPART) {
+ continue;
+ }
+ else {
+ return NULL;
+ }
+ }
+ }
+
+ if ((ret == rgnOUT || ret == rgnPART) && !onlyIfExists) {
+ SecFbBoItemPtr item;
+
+ CONV_POINT_TO_KEY(x, y, key);
+
+ item = calloc(1, sizeof(SecFbBoItem));
+ XDBG_RETURN_VAL_IF_FAIL(item != NULL, NULL);
+ if (width == pFb->width && height == pFb->height && x == 0 && y == 0) {
+ bo = _exynosFbRefBo(pFb->default_bo);
+ }
+ else {
+ bo = _exynosFbCreateBo(pFb, x, y, width, height);
+ if (!bo) {
+ free(item);
+ item = NULL;
+ return NULL;
+ }
+ }
+
+ item->bo = bo;
+ xorg_list_add(&item->link, &pFb->list_bo);
+ pFb->num_bo++;
+
+ XDBG_TRACE(MFB, "GetBO num:%d bo:%p name:%d, %dx%d+%d+%d\n",
+ pFb->num_bo, bo, tbm_bo_export(bo), width, height, x, y);
+ return bo;
+ }
+
+ return NULL;
+}
+
+tbm_bo
+exynosFbSwapBo(EXYNOSFbPtr pFb, tbm_bo back_bo)
+{
+ EXYNOSFbBoDataPtr back_bo_data = NULL;
+ EXYNOSFbBoDataPtr bo_data = NULL;
+ EXYNOSFbBoDataRec tmp_bo_data;
+ tbm_bo bo;
+ BoxPtr b1, b2;
+ SecFbBoItemPtr item = NULL, tmp = NULL;
+
+ XDBG_RETURN_VAL_IF_FAIL(pFb != NULL, NULL);
+ XDBG_RETURN_VAL_IF_FAIL(FALSE == xorg_list_is_empty(&pFb->list_bo), NULL);
+ XDBG_RETURN_VAL_IF_FAIL(tbm_bo_get_user_data
+ (back_bo, TBM_BO_DATA_FB, (void * *) &back_bo_data),
+ NULL);
+ XDBG_RETURN_VAL_IF_FAIL(back_bo_data, NULL);
+
+ b2 = &back_bo_data->pos;
+
+ xorg_list_for_each_entry_safe(item, tmp, &pFb->list_bo, link) {
+ bo = item->bo;
+
+ tbm_bo_get_user_data(bo, TBM_BO_DATA_FB, (void * *) &bo_data);
+ b1 = &bo_data->pos;
+ if (rgnSAME == exynosUtilBoxInBox(b1, b2)) {
+ XDBG_DEBUG(MFB, "SwapBO(Back:%d, Front:%d)\n",
+ tbm_bo_export(back_bo), tbm_bo_export(bo));
+
+ if (tbm_bo_swap(bo, back_bo)) {
+ memcpy(&tmp_bo_data, bo_data, sizeof(EXYNOSFbBoDataRec));
+ memcpy(bo_data, back_bo_data, sizeof(EXYNOSFbBoDataRec));
+ memcpy(back_bo_data, &tmp_bo_data, sizeof(EXYNOSFbBoDataRec));
+ }
+ else
+ return NULL;
+
+ return bo;
+ }
+ }
+
+ return NULL;
+}
+
+void
+exynosFbResize(EXYNOSFbPtr pFb, int width, int height)
+{
+ XDBG_RETURN_IF_FAIL(pFb != NULL);
+
+ EXYNOSFbBoDataPtr bo_data = NULL;
+ tbm_bo bo, old_bo;
+ int ret;
+ BoxRec box;
+ BoxPtr b1, b2;
+
+ if (pFb->width == width && pFb->height == height)
+ return;
+
+ old_bo = pFb->default_bo;
+
+ pFb->width = width;
+ pFb->height = height;
+ XDBG_TRACE(MFB, "Resize %dx%d, num:%d\n", pFb->width, pFb->height,
+ pFb->num_bo);
+
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = width;
+ box.y2 = height;
+ b1 = &box;
+
+ if (!xorg_list_is_empty(&pFb->list_bo)) {
+ SecFbBoItemPtr item = NULL, tmp = NULL;
+
+ xorg_list_for_each_entry_safe(item, tmp, &pFb->list_bo, link) {
+ bo = item->bo;
+
+ tbm_bo_get_user_data(bo, TBM_BO_DATA_FB, (void * *) &bo_data);
+ b2 = &bo_data->pos;
+ ret = exynosUtilBoxInBox(b1, b2);
+
+ if (ret == rgnIN || ret == rgnSAME)
+ continue;
+
+ /* Remove bo */
+ XDBG_DEBUG(MFB,
+ "\t unref bo(name:%d, gem:%d, fb_id:%d, %dx%d+%d+%d\n",
+ tbm_bo_export(bo), bo_data->gem_handle, bo_data->fb_id,
+ bo_data->pos.x2 - bo_data->pos.x1,
+ bo_data->pos.y2 - bo_data->pos.y1, bo_data->pos.x1,
+ bo_data->pos.y1);
+
+ xorg_list_del(&item->link);
+ exynosRenderBoUnref(bo);
+ pFb->num_bo--;
+ free(item);
+ item = NULL;
+ }
+ }
+
+ pFb->default_bo = _exynosFbCreateBo(pFb, 0, 0, width, height);
+ if (old_bo)
+ exynosRenderBoUnref(old_bo);
+}
+
+int
+exynosFbFindBo(EXYNOSFbPtr pFb, int x, int y, int width, int height,
+ int *num_bo, tbm_bo ** bos)
+{
+ EXYNOSFbBoDataPtr bo_data = NULL;
+ int num = 0;
+ tbm_bo *l = NULL;
+ tbm_bo bo;
+ int ret = rgnOUT;
+ BoxRec box;
+ BoxPtr b1, b2;
+ SecFbBoItemPtr item = NULL, tmp = NULL;
+
+ if (xorg_list_is_empty(&pFb->list_bo)) {
+ return rgnOUT;
+ }
+
+ box.x1 = x;
+ box.y1 = y;
+ box.x2 = x + width;
+ box.y2 = y + height;
+ b2 = &box;
+
+ l = calloc(pFb->num_bo, sizeof(tbm_bo));
+
+ xorg_list_for_each_entry_safe(item, tmp, &pFb->list_bo, link) {
+ bo = item->bo;
+
+ tbm_bo_get_user_data(bo, TBM_BO_DATA_FB, (void * *) &bo_data);
+ if (bo_data == NULL) {
+ free(l);
+ return rgnOUT;
+ }
+
+ b1 = &bo_data->pos;
+ ret = exynosUtilBoxInBox(b1, b2);
+ XDBG_DEBUG(MFB, "[%d/%d] ret:%d bo(%d,%d,%d,%d) fb(%d,%d,%d,%d)\n",
+ num + 1, pFb->num_bo, ret,
+ b1->x1, b1->y1, b1->x2, b1->y2,
+ b2->x1, b2->y1, b2->x2, b2->y2);
+
+ if (ret == rgnSAME || ret == rgnIN) {
+ l[num++] = bo;
+ break;
+ }
+ else if (ret == rgnPART) {
+// l[num++] = bo;
+ continue;
+ }
+ else {
+ continue;
+ }
+ }
+
+ if (num_bo)
+ *num_bo = num;
+ if (bos) {
+ *bos = l;
+ }
+ else {
+ free(l);
+ }
+
+ return ret;
+}
+
+tbm_bo
+exynosFbFindBoByPoint(EXYNOSFbPtr pFb, int x, int y)
+{
+ EXYNOSFbBoDataPtr bo_data = NULL;
+ tbm_bo bo;
+ SecFbBoItemPtr item = NULL, tmp = NULL;
+
+ if (xorg_list_is_empty(&pFb->list_bo)) {
+ return NULL;
+ }
+
+ xorg_list_for_each_entry_safe(item, tmp, &pFb->list_bo, link) {
+ bo = item->bo;
+ tbm_bo_get_user_data(bo, TBM_BO_DATA_FB, (void * *) &bo_data);
+ if ((x >= bo_data->pos.x1) &&
+ (x < bo_data->pos.x2) &&
+ (y >= bo_data->pos.y1) && (y < bo_data->pos.y2)) {
+ return bo;
+ }
+ }
+
+ return NULL;
+}
+
+PixmapPtr
+exynosRenderBoGetPixmap(EXYNOSFbPtr pFb, tbm_bo bo)
+{
+ ScreenPtr pScreen = pFb->pScrn->pScreen;
+ PixmapPtr pPixmap;
+ EXYNOSFbBoDataPtr bo_data;
+ int ret;
+
+ XDBG_RETURN_VAL_IF_FAIL(bo != NULL, NULL);
+ XDBG_RETURN_VAL_IF_FAIL(tbm_bo_get_user_data
+ (bo, TBM_BO_DATA_FB, (void **) &bo_data), NULL);
+
+ if (bo_data->pPixmap == NULL) {
+ pPixmap = pScreen->CreatePixmap(pFb->pScrn->pScreen, 0, 0,
+ pFb->pScrn->depth,
+ CREATE_PIXMAP_USAGE_SUB_FB);
+ XDBG_GOTO_IF_FAIL(pPixmap != NULL, fail);
+
+ ret = pScreen->ModifyPixmapHeader(pPixmap,
+ bo_data->pos.x2 - bo_data->pos.x1,
+ bo_data->pos.y2 - bo_data->pos.y1,
+ pFb->pScrn->depth,
+ pFb->pScrn->bitsPerPixel,
+ bo_data->pitch, (void *) bo);
+ XDBG_GOTO_IF_FAIL(ret != FALSE, fail);
+ bo_data->pPixmap = pPixmap;
+ XDBG_DEBUG(MFB, "CreateRenderPixmap:%p\n", pPixmap);
+ }
+
+ return bo_data->pPixmap;
+
+ fail:
+ XDBG_ERROR(MFB, "ERR: CreateRenderPixmap\n");
+ if (pPixmap) {
+ pScreen->DestroyPixmap(pPixmap);
+ }
+ return NULL;
+}
+
+tbm_bo
+exynosRenderBoCreate(ScrnInfoPtr pScrn, int width, int height)
+{
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+
+ return _exynosFbCreateBo(pExynos->pFb, -1, -1, width, height);
+}
+
+int
+exynosSwapToRenderBo(ScrnInfoPtr pScrn, int width, int height, tbm_bo carr_bo,
+ Bool clear)
+{
+ EXYNOSPtr pExynos = EXYNOSPTR(pScrn);
+
+ tbm_bo tbo =
+ _exynosFbCreateBo2(pExynos->pFb, -1, -1, width, height, carr_bo, clear);
+
+ return tbo ? 1 : 0;
+}
+
+tbm_bo
+exynosRenderBoRef(tbm_bo bo)
+{
+ return _exynosFbRefBo(bo);
+}
+
+void
+exynosRenderBoUnref(tbm_bo bo)
+{
+ _exynosFbUnrefBo(bo);
+}
+
+void
+exynosRenderBoSetPos(tbm_bo bo, int x, int y)
+{
+ EXYNOSFbBoDataPtr bo_data;
+ int width, height;
+
+ XDBG_RETURN_IF_FAIL(bo != NULL);
+ XDBG_RETURN_IF_FAIL(x >= 0);
+ XDBG_RETURN_IF_FAIL(y >= 0);
+ XDBG_RETURN_IF_FAIL(tbm_bo_get_user_data
+ (bo, TBM_BO_DATA_FB, (void **) &bo_data));
+
+ width = bo_data->pos.x2 - bo_data->pos.x1;
+ height = bo_data->pos.y2 - bo_data->pos.y1;
+
+ bo_data->pos.x1 = x;
+ bo_data->pos.y1 = y;
+ bo_data->pos.x2 = x + width;
+ bo_data->pos.y2 = y + height;
+}