This can test only solid color fill.

Signed-off-by: Joonyoung Shim <jy0922.shim at samsung.com>
---
 configure.ac              |    1 +
 include/drm/exynos_drm.h  |  185 ++++++++++++++
 tests/Makefile.am         |    2 +-
 tests/g2dtest/Makefile.am |   16 ++
 tests/g2dtest/g2d.h       |   64 +++++
 tests/g2dtest/g2d_reg.h   |  108 ++++++++
 tests/g2dtest/g2dtest.c   |  612 +++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 987 insertions(+), 1 deletions(-)
 create mode 100644 include/drm/exynos_drm.h
 create mode 100644 tests/g2dtest/Makefile.am
 create mode 100644 tests/g2dtest/g2d.h
 create mode 100644 tests/g2dtest/g2d_reg.h
 create mode 100644 tests/g2dtest/g2dtest.c

diff --git a/configure.ac b/configure.ac
index 71a596c..1b51b65 100644
--- a/configure.ac
+++ b/configure.ac
@@ -297,6 +297,7 @@ AC_CONFIG_FILES([
        tests/kmstest/Makefile
        tests/radeon/Makefile
        tests/vbltest/Makefile
+       tests/g2dtest/Makefile
        include/Makefile
        include/drm/Makefile
        libdrm.pc])
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
new file mode 100644
index 0000000..701dbd9
--- /dev/null
+++ b/include/drm/exynos_drm.h
@@ -0,0 +1,185 @@
+/* exynos_drm.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Authors:
+ *     Inki Dae <inki.dae at samsung.com>
+ *     Joonyoung Shim <jy0922.shim at samsung.com>
+ *     Seung-Woo Kim <sw0312.kim at samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _EXYNOS_DRM_H_
+#define _EXYNOS_DRM_H_
+
+#include "drm.h"
+
+/**
+ * User-desired buffer creation information structure.
+ *
+ * @size: user-desired memory allocation size.
+ *     - this size value would be page-aligned internally.
+ * @flags: user request for setting memory type or cache attributes.
+ * @handle: returned a handle to created gem object.
+ *     - this handle will be set by gem module of kernel side.
+ */
+struct drm_exynos_gem_create {
+       uint64_t size;
+       unsigned int flags;
+       unsigned int handle;
+};
+
+/**
+ * A structure for getting buffer offset.
+ *
+ * @handle: a pointer to gem object created.
+ * @pad: just padding to be 64-bit aligned.
+ * @offset: relatived offset value of the memory region allocated.
+ *     - this value should be set by user.
+ */
+struct drm_exynos_gem_map_off {
+       unsigned int handle;
+       unsigned int pad;
+       uint64_t offset;
+};
+
+/**
+ * A structure for mapping buffer.
+ *
+ * @handle: a handle to gem object created.
+ * @size: memory size to be mapped.
+ * @mapped: having user virtual address mmaped.
+ *     - this variable would be filled by exynos gem module
+ *     of kernel side with user virtual address which is allocated
+ *     by do_mmap().
+ */
+struct drm_exynos_gem_mmap {
+       unsigned int handle;
+       unsigned int size;
+       uint64_t mapped;
+};
+
+/**
+ * A structure for user connection request of virtual display.
+ *
+ * @connection: indicate whether doing connetion or not by user.
+ * @extensions: if this value is 1 then the vidi driver would need additional
+ *     128bytes edid data.
+ * @pad: just padding to be 64-bit aligned.
+ * @edid: the edid data pointer from user side.
+ */
+struct drm_exynos_vidi_connection {
+       unsigned int connection;
+       unsigned int extensions;
+       unsigned int pad;
+       void *edid;
+};
+
+struct drm_exynos_plane_set_zpos {
+       __u32 crtc_id;
+       __u32 plane_id;
+       __s32 zpos;
+       __u32 pad;
+};
+
+/* memory type definitions. */
+enum e_drm_exynos_gem_mem_type {
+       /* Physically Non-Continuous memory. */
+       EXYNOS_BO_NONCONTIG     = 1 << 0
+};
+
+struct drm_exynos_g2d_get_ver {
+       __u32   major;
+       __u32   minor;
+};
+
+struct drm_exynos_g2d_cmd {
+       __u32   offset;
+       __u32   data;
+};
+
+enum drm_exynos_g2d_event_type {
+       G2D_EVENT_NOT,
+       G2D_EVENT_NONSTOP,
+       G2D_EVENT_STOP,         /* not yet */
+};
+
+struct drm_exynos_g2d_set_cmdlist {
+       struct drm_exynos_g2d_cmd               *cmd;
+       struct drm_exynos_g2d_cmd               *cmd_gem;
+       __u32                                   cmd_nr;
+       __u32                                   cmd_gem_nr;
+
+       /* for g2d event */
+       __u64                                   event_type;
+       __u64                                   user_data;
+};
+
+struct drm_exynos_g2d_exec {
+       __u64                                   async;
+};
+
+#define DRM_EXYNOS_GEM_CREATE          0x00
+#define DRM_EXYNOS_GEM_MAP_OFFSET      0x01
+#define DRM_EXYNOS_GEM_MMAP            0x02
+/* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
+#define DRM_EXYNOS_PLANE_SET_ZPOS      0x06
+#define DRM_EXYNOS_VIDI_CONNECTION     0x07
+
+/* G2D */
+#define DRM_EXYNOS_G2D_GET_VER         0x20
+#define DRM_EXYNOS_G2D_SET_CMDLIST     0x21
+#define DRM_EXYNOS_G2D_EXEC            0x22
+
+#define DRM_IOCTL_EXYNOS_GEM_CREATE            DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create)
+
+#define DRM_IOCTL_EXYNOS_GEM_MAP_OFFSET        DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_EXYNOS_GEM_MAP_OFFSET, struct drm_exynos_gem_map_off)
+
+#define DRM_IOCTL_EXYNOS_GEM_MMAP      DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_EXYNOS_GEM_MMAP, struct drm_exynos_gem_mmap)
+
+#define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS        DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos)
+
+#define DRM_IOCTL_EXYNOS_VIDI_CONNECTION       DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection)
+
+#define DRM_IOCTL_EXYNOS_G2D_GET_VER           DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_EXYNOS_G2D_GET_VER, struct drm_exynos_g2d_get_ver)
+#define DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST       DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_EXYNOS_G2D_SET_CMDLIST, struct drm_exynos_g2d_set_cmdlist)
+#define DRM_IOCTL_EXYNOS_G2D_EXEC              DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_EXYNOS_G2D_EXEC, struct drm_exynos_g2d_exec)
+
+/* EXYNOS specific events */
+#define DRM_EXYNOS_G2D_EVENT           0x80000000
+
+struct drm_exynos_g2d_event {
+       struct drm_event        base;
+       __u64                   user_data;
+       __u32                   tv_sec;
+       __u32                   tv_usec;
+       __u32                   cmdlist_no;
+       __u32                   reserved;
+};
+
+#endif
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a3a59bd..58a4d36 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -13,7 +13,7 @@ check_PROGRAMS = \
 SUBDIRS = modeprint

 if HAVE_LIBKMS
-SUBDIRS += kmstest modetest
+SUBDIRS += kmstest modetest g2dtest
 endif

 if HAVE_RADEON
diff --git a/tests/g2dtest/Makefile.am b/tests/g2dtest/Makefile.am
new file mode 100644
index 0000000..17d78cf
--- /dev/null
+++ b/tests/g2dtest/Makefile.am
@@ -0,0 +1,16 @@
+AM_CFLAGS = \
+       -I$(top_srcdir)/include/drm \
+       -I$(top_srcdir)/libkms/ \
+       -I$(top_srcdir) \
+       $(CAIRO_CFLAGS)
+
+noinst_PROGRAMS = \
+       g2dtest
+
+g2dtest_SOURCES = \
+       g2dtest.c
+
+g2dtest_LDADD = \
+       $(top_builddir)/libdrm.la \
+       $(top_builddir)/libkms/libkms.la \
+       $(CAIRO_LIBS)
diff --git a/tests/g2dtest/g2d.h b/tests/g2dtest/g2d.h
new file mode 100644
index 0000000..1a62880
--- /dev/null
+++ b/tests/g2dtest/g2d.h
@@ -0,0 +1,64 @@
+#ifndef _G2D_H_
+#define _G2D_H_
+
+#include "g2d_reg.h"
+
+typedef enum {
+       G2D_SELECT_MODE_NORMAL = (0 << 0),
+       G2D_SELECT_MODE_FGCOLOR = (1 << 0),
+       G2D_SELECT_MODE_BGCOLOR = (2 << 0),
+       G2D_SELECT_MODE_MAX = (3 << 0),
+} G2dSelectMode;
+
+typedef enum {
+       /* COLOR FORMAT */
+       G2D_COLOR_FMT_XRGB8888,
+       G2D_COLOR_FMT_ARGB8888,
+       G2D_COLOR_FMT_RGB565,
+       G2D_COLOR_FMT_XRGB1555,
+       G2D_COLOR_FMT_ARGB1555,
+       G2D_COLOR_FMT_XRGB4444,
+       G2D_COLOR_FMT_ARGB4444,
+       G2D_COLOR_FMT_PRGB888,
+       G2D_COLOR_FMT_YCbCr444,
+       G2D_COLOR_FMT_YCbCr422,
+       G2D_COLOR_FMT_YCbCr420 = 10,
+       G2D_COLOR_FMT_A8,                       /* alpha 8bit */
+       G2D_COLOR_FMT_L8,                       /* Luminance 8bit: gray color */
+       G2D_COLOR_FMT_A1,                       /* alpha 1bit */
+       G2D_COLOR_FMT_A4,                       /* alpha 4bit */
+       G2D_COLOR_FMT_MASK = (15 << 0),         /* VER4.1 */
+
+       /* COLOR ORDER */
+       G2D_ORDER_AXRGB = (0 << 4),                     /* VER4.1 */
+       G2D_ORDER_RGBAX = (1 << 4),                     /* VER4.1 */
+       G2D_ORDER_AXBGR = (2 << 4),                     /* VER4.1 */
+       G2D_ORDER_BGRAX = (3 << 4),                     /* VER4.1 */
+       G2D_ORDER_MASK = (3 << 4),                      /* VER4.1 */
+
+       /* Number of YCbCr plane */
+       G2D_YCbCr_1PLANE = (0 << 8),                    /* VER4.1 */
+       G2D_YCbCr_2PLANE = (1 << 8),                    /* VER4.1 */
+       G2D_YCbCr_PLANE_MASK = (3 << 8),                /* VER4.1 */
+
+       /* Order in YCbCr */
+       G2D_YCbCr_ORDER_CrY1CbY0 = (0 << 12),           /* VER4.1 */
+       G2D_YCbCr_ORDER_CbY1CrY0 = (1 << 12),           /* VER4.1 */
+       G2D_YCbCr_ORDER_Y1CrY0Cb = (2 << 12),           /* VER4.1 */
+       G2D_YCbCr_ORDER_Y1CbY0Cr = (3 << 12),           /* VER4.1 */
+       G2D_YCbCr_ORDER_MASK = (3 < 12),                /* VER4.1 */
+
+       /* CSC */
+       G2D_CSC_601 = (0 << 16),                        /* VER4.1 */
+       G2D_CSC_709 = (1 << 16),                        /* VER4.1 */
+       G2D_CSC_MASK = (1 << 16),                       /* VER4.1 */
+
+       /* Valid value range of YCbCr */
+       G2D_YCbCr_RANGE_NARROW = (0 << 17),             /* VER4.1 */
+       G2D_YCbCr_RANGE_WIDE = (1 << 17),               /* VER4.1 */
+       G2D_YCbCr_RANGE_MASK= (1 << 17),                /* VER4.1 */
+
+       G2D_COLOR_MODE_MASK = 0xFFFFFFFF
+} G2dColorMode;
+
+#endif /* _G2D_H_ */
diff --git a/tests/g2dtest/g2d_reg.h b/tests/g2dtest/g2d_reg.h
new file mode 100644
index 0000000..b991681
--- /dev/null
+++ b/tests/g2dtest/g2d_reg.h
@@ -0,0 +1,108 @@
+#ifndef _G2D_REG_H_
+#define _G2D_REG_H_
+
+/* Registers */
+/* GEBERAL REGISTER */
+#define SOFT_RESET_REG                 (0x0000)
+#define INTEN_REG                      (0x0004)
+#define INTC_PEND_REG                  (0x000c)
+#define FIFO_STAT_REG                  (0x0010)
+#define AXI_MODE_REG                   (0x001C)
+#define DMA_SFR_BASE_ADDR_REG          (0x0080)
+#define DMA_COMMAND_REG                        (0x0084)
+#define DMA_EXE_LIST_NUM_REG           (0x0088)
+#define DMA_STATUS_REG                 (0x008C)
+#define DMA_HOLD_CMD_REG               (0x0090)
+
+/* COMMAND REGISTER */
+#define BITBLT_START_REG               (0x0100)
+#define BITBLT_COMMAND_REG             (0x0104)
+#define BLEND_FUNCTION_REG             (0x0108)        /* VER4.1 */
+#define ROUND_MODE_REG                 (0x010C)        /* VER4.1 */
+
+/* PARAMETER SETTING REGISTER */
+
+/*     ROTATE and DIRECTION    */
+#define ROTATE_REG                     (0x0200)
+#define SRC_MASK_DIRECT_REG            (0x0204)
+#define DST_PAT_DIRECT_REG             (0x0208)
+
+/*     SOURCE  */
+#define SRC_SELECT_REG                 (0x0300)
+#define SRC_BASE_ADDR_REG              (0x0304)
+#define SRC_STRIDE_REG                 (0x0308)
+#define SRC_COLOR_MODE_REG             (0x030c)
+#define SRC_LEFT_TOP_REG               (0x0310)
+#define SRC_RIGHT_BOTTOM_REG           (0x0314)
+#define SRC_PLANE2_BASE_ADDR_REG       (0x0318)        /* VER4.1 */
+#define SRC_REPEAT_MODE_REG            (0x031C)
+#define SRC_PAD_VALUE_REG              (0x0320)
+#define SRC_A8_RGB_EXT_REG             (0x0324)
+#define SRC_SCALE_CTRL_REG             (0x0328)
+#define SRC_XSCALE_REG                 (0x032C)
+#define SRC_YSCALE_REG                 (0x0330)
+
+/*     DESTINATION     */
+#define DST_SELECT_REG                 (0x0400)
+#define DST_BASE_ADDR_REG              (0x0404)
+#define DST_STRIDE_REG                 (0x0408)
+#define DST_COLOR_MODE_REG             (0x040C)
+#define DST_LEFT_TOP_REG               (0x0410)
+#define DST_RIGHT_BOTTOM_REG           (0x0414)
+#define DST_PLANE2_BASE_ADDR_REG       (0x0418)        /* VER4.1 */
+#define DST_A8_RGB_EXT_REG             (0x041C)
+
+/*     PATTERN */
+#define PAT_BASE_ADDR_REG              (0x0500)
+#define PAT_SIZE_REG                   (0x0504)
+#define PAT_COLOR_MODE_REG             (0x0508)
+#define PAT_OFFSET_REG                 (0x050C)
+#define PAT_STRIDE_REG                 (0x0510)
+
+/*     MASK    */
+#define MASK_BASE_ADDR_REG             (0x0520)
+#define MASK_STRIDE_REG                        (0x0524)
+#define MASK_LEFT_TOP_REG              (0x0528)        /* VER4.1 */
+#define MASK_RIGHT_BOTTOM_REG          (0x052C)        /* VER4.1 */
+#define MASK_MODE_REG                  (0x0530)        /* VER4.1 */
+#define MASK_REPEAT_MODE_REG           (0x0534)
+#define MASK_PAD_VALUE_REG             (0x0538)
+#define MASK_SCALE_CTRL_REG            (0x053C)
+#define MASK_XSCALE_REG                        (0x0540)
+#define MASK_YSCALE_REG                        (0x0544)
+
+/* CLIPPING WINDOW */
+#define CW_LT_REG                      (0x0600)
+#define CW_RB_REG                      (0x0604)
+
+/* ROP & ALPHA SETTING */
+#define THIRD_OPERAND_REG              (0x0610)
+#define ROP4_REG                       (0x0614)
+#define ALPHA_REG                      (0x0618)
+
+/* COLOR SETTING */
+#define FG_COLOR_REG                   (0x0700)
+#define BG_COLOR_REG                   (0x0704)
+#define BS_COLOR_REG                   (0x0708)
+#define SF_COLOR_REG                   (0x070C)        /* VER4.1 */
+
+/* COLOR KEY */
+#define SRC_COLORKEY_CTRL_REG          (0x0710)
+#define SRC_COLORKEY_DR_MIN_REG                (0x0714)
+#define SRC_COLORKEY_DR_MAX_REG                (0x0718)
+#define DST_COLORKEY_CTRL_REG          (0x071C)
+#define DST_COLORKEY_DR_MIN_REG                (0x0720)
+#define DST_COLORKEY_DR_MAX_REG                (0x0724)
+/*     YCbCr src Color Key     */
+#define YCbCr_SRC_COLORKEY_CTRL_REG    (0x0728)        /* VER4.1 */
+#define YCbCr_SRC_COLORKEY_DR_MIN_REG  (0x072C)        /* VER4.1 */
+#define YCbCr_SRC_COLORKEY_DR_MAX_REG  (0x0730)        /* VER4.1 */
+/*     YCbCr dst Color Key     */
+#define YCbCr_DST_COLORKEY_CTRL_REG    (0x0734)        /* VER4.1 */
+#define YCbCr_DST_COLORKEY_DR_MIN_REG  (0x0738)        /* VER4.1 */
+#define YCbCr_DST_COLORKEY_DR_MAX_REG  (0x073C)        /* VER4.1 */
+
+/* bits of BITBLT_COMMAND_REG */
+#define        G2D_FAST_SOLID_COLOR_FILL       (1 << 28)
+
+#endif /* _G2D_REG_H_ */
diff --git a/tests/g2dtest/g2dtest.c b/tests/g2dtest/g2dtest.c
new file mode 100644
index 0000000..4521cd4
--- /dev/null
+++ b/tests/g2dtest/g2dtest.c
@@ -0,0 +1,612 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+#include "exynos_drm.h"
+#include "drm_fourcc.h"
+#include "g2d.h"
+
+#define DRM_MODULE_NAME                "exynos-drm"
+
+struct connector {
+       uint32_t id;
+       char mode_str[64];
+       drmModeModeInfo *mode;
+       drmModeEncoder *encoder;
+       int crtc;
+       int plane_zpos;
+       unsigned int fb_id[2], current_fb_id;
+       struct timeval start;
+
+       int swap_count;
+};
+
+struct drm_buffer {
+       struct drm_exynos_gem_create    gem;
+       struct drm_exynos_gem_mmap      gem_mmap;
+};
+
+struct drm_fb {
+       uint32_t                        id;
+       struct drm_buffer               drm_buffer;
+};
+
+struct drm_desc {
+       int                             fd;
+       struct connector                connector;
+       int                             plane_id[5];
+       int                             width;
+       int                             height;
+};
+
+enum format {
+       FMT_RGB565,
+       FMT_RGB888,
+       FMT_NV12M,
+};
+
+static void connector_find_mode(int fd, struct connector *c,
+                               drmModeRes *resources)
+{
+       drmModeConnector *connector;
+       int i, j;
+
+       /* First, find the connector & mode */
+       c->mode = NULL;
+       for (i = 0; i < resources->count_connectors; i++) {
+               connector = drmModeGetConnector(fd, resources->connectors[i]);
+
+               if (!connector) {
+                       fprintf(stderr, "could not get connector %i: %s\n",
+                               resources->connectors[i], strerror(errno));
+                       drmModeFreeConnector(connector);
+                       continue;
+               }
+
+               if (!connector->count_modes) {
+                       drmModeFreeConnector(connector);
+                       continue;
+               }
+
+               if (connector->connector_id != c->id) {
+                       drmModeFreeConnector(connector);
+                       continue;
+               }
+
+               for (j = 0; j < connector->count_modes; j++) {
+                       c->mode = &connector->modes[j];
+                       if (!strcmp(c->mode->name, c->mode_str))
+                               break;
+               }
+
+               /* Found it, break out */
+               if (c->mode)
+                       break;
+
+               drmModeFreeConnector(connector);
+       }
+
+       if (!c->mode) {
+               fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str);
+               return;
+       }
+
+       /* Now get the encoder */
+       for (i = 0; i < resources->count_encoders; i++) {
+               c->encoder = drmModeGetEncoder(fd, resources->encoders[i]);
+
+               if (!c->encoder) {
+                       fprintf(stderr, "could not get encoder %i: %s\n",
+                               resources->encoders[i], strerror(errno));
+                       drmModeFreeEncoder(c->encoder);
+                       continue;
+               }
+
+               if (c->encoder->encoder_id  == connector->encoder_id)
+                       break;
+
+               drmModeFreeEncoder(c->encoder);
+       }
+
+       if (c->crtc == -1)
+               c->crtc = c->encoder->crtc_id;
+}
+
+static int connector_find_plane(int fd, unsigned int *plane_id)
+{
+       drmModePlaneRes *plane_resources;
+       drmModePlane *ovr;
+       int i;
+
+       plane_resources = drmModeGetPlaneResources(fd);
+       if (!plane_resources) {
+               fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
+                       strerror(errno));
+               return -1;
+       }
+
+       for (i = 0; i < plane_resources->count_planes; i++) {
+               plane_id[i] = 0;
+
+               ovr = drmModeGetPlane(fd, plane_resources->planes[i]);
+               if (!ovr) {
+                       fprintf(stderr, "drmModeGetPlane failed: %s\n",
+                               strerror(errno));
+                       continue;
+               }
+
+               if (ovr->possible_crtcs & (1 << 0))
+                       plane_id[i] = ovr->plane_id;
+               drmModeFreePlane(ovr);
+       }
+
+       return 0;
+}
+
+static int exynos_g2d_get_ver(int fd, struct drm_exynos_g2d_get_ver *ver)
+{
+       int ret;
+
+       ret = ioctl(fd, DRM_IOCTL_EXYNOS_G2D_GET_VER, ver);
+       if (ret < 0) {
+               fprintf(stderr, "failed to get version: %s\n", strerror(-ret));
+               return ret;
+       }
+
+       return 0;
+}
+
+static int exynos_g2d_set_cmdlist(int fd,
+                                 struct drm_exynos_g2d_set_cmdlist *cmdlist)
+{
+       int ret;
+
+       ret = ioctl(fd, DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST, cmdlist);
+       if (ret < 0) {
+               fprintf(stderr, "failed to set cmdlist: %s\n", strerror(-ret));
+               return ret;
+       }
+
+       return 0;
+}
+
+static int exynos_g2d_exec(int fd, int async)
+{
+       struct drm_exynos_g2d_exec exec;
+       int ret;
+
+       exec.async = async;
+       ret = ioctl(fd, DRM_IOCTL_EXYNOS_G2D_EXEC, &exec);
+       if (ret < 0) {
+               fprintf(stderr, "failed to execute: %s\n", strerror(-ret));
+               return ret;
+       }
+
+       return 0;
+}
+
+static int exynos_plane_set_zpos(int fd, unsigned int plane_id, int zpos)
+{
+       struct drm_exynos_plane_set_zpos zpos_req;
+       int ret;
+
+       zpos_req.plane_id = plane_id;
+       zpos_req.zpos = zpos;
+
+       ret = ioctl(fd, DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS, &zpos_req);
+       if (ret < 0) {
+               fprintf(stderr, "failed to set plane zpos: %s\n",
+                               strerror(-ret));
+               return ret;
+       }
+
+       return 0;
+}
+
+static int exynos_gem_create(int fd, struct drm_exynos_gem_create *gem)
+{
+       int ret;
+
+       if (!gem)
+               return -EINVAL;
+
+       ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_CREATE, gem);
+       if (ret < 0)
+               perror("ioctl failed\n");
+
+       return ret;
+}
+
+static int exynos_gem_map_offset(int fd, struct drm_exynos_gem_map_off 
*map_off)
+{
+       int ret;
+
+       if (!map_off)
+               return -EINVAL;
+
+       ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_MAP_OFFSET, map_off);
+       if (ret < 0)
+               perror("ioctl failed\n");
+
+       return ret;
+}
+
+static int exynos_gem_mmap(int fd, struct drm_exynos_gem_mmap *in_mmap)
+{
+       int ret;
+
+       if (!in_mmap)
+               return -EINVAL;
+
+       ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_MMAP, in_mmap);
+       if (ret < 0)
+               perror("ioctl failed\n");
+
+       return ret;
+}
+
+static int exynos_gem_close(int fd, struct drm_gem_close *gem_close)
+{
+       int ret;
+
+       if (!gem_close)
+               return -EINVAL;
+
+       ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, gem_close);
+       if (ret < 0)
+               perror("ioctl failed\n");
+
+       return ret;
+}
+
+static struct drm_desc *drm_alloc_desc(void)
+{
+       struct drm_desc *drm_desc;
+
+       drm_desc = malloc(sizeof(struct drm_desc));
+       if (!drm_desc) {
+               perror("memory alloc error\n");
+               return NULL;
+       }
+       memset(drm_desc, 0, sizeof(struct drm_desc));
+
+       return drm_desc;
+}
+
+static int drm_open(struct drm_desc *drm_desc)
+{
+       if (!drm_desc) {
+               fprintf(stderr, "drm_desc is NULL\n");
+               return -EINVAL;
+       }
+
+       drm_desc->fd = drmOpen(DRM_MODULE_NAME, NULL);
+       if (drm_desc->fd < 0) {
+               printf("Failed to open %s module\n", DRM_MODULE_NAME);
+               return drm_desc->fd;
+       }
+
+       return 0;
+}
+
+static int drm_create_buffer(struct drm_desc *drm_desc, struct drm_fb *drm_fb,
+                            int width, int height)
+{
+       struct drm_buffer *drm_buffer;
+       unsigned int num_planes;
+       unsigned long size;
+       int i;
+       int ret;
+
+       if (!drm_desc)
+               return -EINVAL;
+
+       size = width * height * 4;
+
+       drm_buffer = &drm_fb->drm_buffer;
+
+       {
+               struct drm_exynos_gem_create *gem = &drm_buffer->gem;
+               struct drm_exynos_gem_mmap *gem_mmap = &drm_buffer->gem_mmap;
+
+               memset(gem, 0, sizeof(struct drm_exynos_gem_create));
+               gem->size = size;
+
+               ret = exynos_gem_create(drm_desc->fd, gem);
+               if (ret < 0) {
+                       printf("failed to create gem\n");
+                       goto err_gem;
+               }
+
+               gem_mmap->handle = gem->handle;
+               gem_mmap->size = gem->size;
+               ret = exynos_gem_mmap(drm_desc->fd, gem_mmap);
+               if (ret < 0) {
+                       printf("failed to mmap gem directly\n");
+                       goto err_gem;
+               }
+
+               /* init gem buffer */
+               memset((void *)(unsigned long)gem_mmap->mapped, 0,
+                               gem_mmap->size);
+       }
+
+       return 0;
+
+err_gem:
+       {
+               struct drm_exynos_gem_create *gem = &drm_buffer->gem;
+               struct drm_gem_close gem_close;
+
+               gem_close.handle = gem->handle;
+               exynos_gem_close(drm_desc->fd, &gem_close);
+       }
+
+       return ret;
+}
+
+static int drm_create_fb(struct drm_desc *drm_desc, struct drm_fb *drm_fb,
+                        int width, int height)
+{
+       unsigned int pixel_format;
+       unsigned int num_planes;
+       unsigned int pitch;
+       int i;
+       int j;
+       int ret;
+
+       if (!drm_desc)
+               return -EINVAL;
+
+       drm_desc->width = width;
+       drm_desc->height = height;
+
+       pixel_format = DRM_FORMAT_RGBA8888;
+       num_planes = 1;
+       pitch = width * 4;
+
+       {
+               uint32_t bo[4] = {0,};
+               uint32_t pitches[4] = {0,};
+               uint32_t offset[4] = {0,};
+
+               ret = drm_create_buffer(drm_desc, drm_fb, width, height);
+               if (ret < 0)
+                       goto err;
+
+               for (j = 0; j < num_planes; j++) {
+                       struct drm_buffer *drm_buffer = &drm_fb->drm_buffer;
+                       struct drm_exynos_gem_create *gem = &drm_buffer->gem;
+
+                       bo[j] = gem->handle;
+                       pitches[j] = pitch;
+               }
+
+               ret = drmModeAddFB2(drm_desc->fd, width, height, pixel_format,
+                               bo, pitches, offset, &drm_fb->id,
+                               0);
+               if (ret < 0) {
+                       perror("failed to add fb\n");
+                       goto err;
+               }
+       }
+
+       return 0;
+
+err:
+       /* TODO: free buffer */
+       return ret;
+}
+
+static int drm_set_crtc(struct drm_desc *drm_desc, struct connector *c,
+                       struct drm_fb *drm_fb)
+{
+       drmModeRes *resources;
+       int ret;
+
+       memcpy(&drm_desc->connector, c, sizeof(struct connector));
+
+       resources = drmModeGetResources(drm_desc->fd);
+       if (!resources) {
+               fprintf(stderr, "drmModeGetResources failed: %s\n",
+                       strerror(errno));
+               ret = -EFAULT;
+               goto err;
+       }
+
+       connector_find_mode(drm_desc->fd, &drm_desc->connector, resources);
+       drmModeFreeResources(resources);
+
+       ret = drmModeSetCrtc(drm_desc->fd, drm_desc->connector.crtc,
+                       drm_fb->id, 0, 0,
+                       &drm_desc->connector.id, 1,
+                       drm_desc->connector.mode);
+       if (ret) {
+               fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
+               goto err;
+       }
+
+       return 0;
+
+err:
+       /* TODO */
+       return ret;
+}
+
+static inline void set_cmd(struct drm_exynos_g2d_cmd *cmd,
+                                     __u32 offset, __u32 data)
+{
+       cmd->offset = offset;
+       cmd->data = data;
+}
+
+static int exynos_g2d_test_solid_fill(struct drm_desc *drm_desc, int x, int y,
+                                     int color, int gem_handle)
+{
+       struct drm_exynos_g2d_set_cmdlist cmdlist;
+       struct drm_exynos_g2d_cmd cmd[20];
+       struct drm_exynos_g2d_cmd cmd_gem[5];
+       int nr = 0;
+       int gem_nr = 0;
+       int ret;
+
+       memset(&cmdlist, 0, sizeof(struct drm_exynos_g2d_set_cmdlist));
+       memset(cmd, 0, sizeof(struct drm_exynos_g2d_cmd) * 20);
+       memset(cmd_gem, 0, sizeof(struct drm_exynos_g2d_cmd) * 5);
+
+       cmdlist.cmd = cmd;
+       cmdlist.cmd_gem = cmd_gem;
+
+       set_cmd(&cmd[nr++], BITBLT_COMMAND_REG, G2D_FAST_SOLID_COLOR_FILL);
+       /* [14:10] R, [9:5] G, [4:0] B */
+       set_cmd(&cmd[nr++], SF_COLOR_REG, color);
+
+       /* DST */
+       set_cmd(&cmd[nr++], DST_SELECT_REG, G2D_SELECT_MODE_FGCOLOR);
+       set_cmd(&cmd_gem[gem_nr++], DST_BASE_ADDR_REG, gem_handle);
+       set_cmd(&cmd[nr++], DST_STRIDE_REG, 720 * 4);
+       set_cmd(&cmd[nr++], DST_COLOR_MODE_REG, G2D_COLOR_FMT_ARGB8888 |
+                                               G2D_ORDER_AXRGB);
+       set_cmd(&cmd[nr++], DST_LEFT_TOP_REG, (0 << 16) | 0);
+       set_cmd(&cmd[nr++], DST_RIGHT_BOTTOM_REG, (y << 16) | x);
+       set_cmd(&cmd[nr++], DST_PLANE2_BASE_ADDR_REG, 0);
+       set_cmd(&cmd[nr++], DST_A8_RGB_EXT_REG, 0);
+
+       cmdlist.cmd_nr = nr;
+       cmdlist.cmd_gem_nr = gem_nr;
+
+       cmdlist.event_type = G2D_EVENT_NONSTOP;
+       cmdlist.user_data = 1234;
+
+       ret = exynos_g2d_set_cmdlist(drm_desc->fd, &cmdlist);
+       if (ret < 0)
+               return ret;
+}
+
+static int exynos_g2d_event(int fd)
+{
+       char buffer[1024];
+       int len, i;
+       struct drm_event *e;
+       struct drm_exynos_g2d_event *g2d_event;
+
+       len = read(fd, buffer, sizeof buffer);
+       if (len == 0)
+               return 0;
+       if (len < sizeof *e)
+               return -1;
+
+       i = 0;
+       while (i < len) {
+               e = (struct drm_event *) &buffer[i];
+               switch (e->type) {
+               case DRM_EXYNOS_G2D_EVENT:
+                       g2d_event = (struct drm_exynos_g2d_event *) e;
+                       printf("cmdlist_no: %d\n", g2d_event->cmdlist_no);
+                       printf("user_data: %lld\n", g2d_event->user_data);
+                       break;
+               default:
+                       break;
+               }
+               i += e->length;
+       }
+
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       struct connector con_args;
+       struct drm_desc *drm_desc;
+       struct drm_fb drm_fb;
+       struct drm_exynos_g2d_get_ver ver;
+       int x, y;
+       int ret;
+
+       /* default set of connector */
+       memset(&con_args, 0, sizeof(struct connector));
+       con_args.id = 12;
+       con_args.crtc = 3;
+       con_args.plane_zpos = -1;
+       strcpy(con_args.mode_str, "720x1280");
+       x = 720;
+       y = 1280;
+
+       drm_desc = drm_alloc_desc();
+       if (!drm_desc) {
+               ret = -1;
+               goto err_free;
+       }
+
+       ret = drm_open(drm_desc);
+       if (ret < 0)
+               goto err_free;
+
+       /* check version */
+       ret = exynos_g2d_get_ver(drm_desc->fd, &ver);
+       if (ret < 0)
+               return ret;
+
+       if (ver.major != 4 || ver.minor != 1) {
+               fprintf(stderr, "version(%d.%d) mismatch\n", ver.major, 
ver.minor);
+               return -1;
+       }
+       printf("g2d hw version: %d.%d\n", ver.major, ver.minor);
+
+       ret = drm_create_fb(drm_desc, &drm_fb, x, y);
+       if (ret < 0)
+               goto err_drm_close;
+
+       ret = drm_set_crtc(drm_desc, &con_args, &drm_fb);
+       if (ret < 0)
+               goto err;
+
+       getchar();
+
+       ret = exynos_g2d_test_solid_fill(drm_desc, x, y, 0x1f,
+                                        drm_fb.drm_buffer.gem.handle);
+       if (ret < 0)
+               goto err;
+
+       ret = exynos_g2d_exec(drm_desc->fd, 1);
+       if (ret < 0)
+               return ret;
+
+       while (1) {
+               struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
+               fd_set fds;
+               int ret;
+
+               FD_ZERO(&fds);
+               FD_SET(0, &fds);
+               FD_SET(drm_desc->fd, &fds);
+               ret = select(drm_desc->fd + 1, &fds, NULL, NULL, &timeout);
+
+               if (ret <= 0) {
+                       fprintf(stderr, "select timed out or error (ret %d)\n",
+                               ret);
+                       continue;
+               } else if (FD_ISSET(0, &fds)) {
+                       break;
+               }
+
+               exynos_g2d_event(drm_desc->fd);
+       }
+
+       getchar();
+
+       /* TODO */
+
+err:
+       /* TODO */
+err_drm_close:
+       drmClose(drm_desc->fd);
+err_free:
+       if (drm_desc)
+               free(drm_desc);
+
+       return ret;
+}
-- 
1.7.5.4


--------------040707050107050602080100--

Reply via email to