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--