Re: [PATCH 09/10] drm/exynos: add G2D driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 03/15/2012 07:50 PM, Dave Airlie wrote:
G2D is a 2D graphic accelerator that supports Bit Block Transfer. This
G2D driver is exynos drm specific and supports only exynos4x12 series.
user application fills command set in cmdlist and once dma start request
these cmdlists are parsed and performed by dma.
Where is this block documented or a pointer to the corresponding open
userspace user code?

I attach simple g2dtest program patch. The base of this patch is master
branch of lastest libdrm git.

This user progrem can test just solid color fill example.
I will cleanup and update it for more operations later.

Thanks.

Again the ioctls look like they need to be depointered and use __u64.

It would be nice if you could document how the command stream and engine work.

How does userspace pass addresses to it? straight or via gem objects?
how does it
stop userspace blt to places it shouldn't etc.

I'm getting the feeling this accel enabled driver needs a lot more of
a commit message
and lot more documentation on what it can be used for.

Dave.
_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/dri-devel


>From 845c0a1bbf67b342099c5eae6f573063af8fc023 Mon Sep 17 00:00:00 2001
From: Joonyoung Shim <jy0922.shim@xxxxxxxxxxx>
Date: Fri, 16 Mar 2012 15:13:45 +0900
Subject: [PATCH] Add simple g2dtest

This can test only solid color fill.

Signed-off-by: Joonyoung Shim <jy0922.shim@xxxxxxxxxxx>
---
 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@xxxxxxxxxxx>
+ *	Joonyoung Shim <jy0922.shim@xxxxxxxxxxx>
+ *	Seung-Woo Kim <sw0312.kim@xxxxxxxxxxx>
+ *
+ * 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

_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/dri-devel

[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux