[PATCH] Add simple g2dtest
Joonyoung Shim
jy0922.shim at samsung.com
Thu Mar 15 23:13:45 PDT 2012
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--
More information about the dri-devel
mailing list