[PATCH] libdrm/exynos: add test application for 2d gpu.

Rob Clark robdclark at gmail.com
Fri Mar 1 05:38:51 PST 2013


On Fri, Mar 1, 2013 at 1:52 AM, Inki Dae <inki.dae at samsung.com> wrote:
> 2013/3/1 Rob Clark <robdclark at gmail.com>:
>> Just curious, but the 2d blitter have it's own sort of
>> command-processor, ie. can you feed it a list of different blits in
>> one batch and then it will process them one after another?
>>
>
> Right, the command lists are processed by the dma. One command list
> links up with another one so the dma can process these command lists
> in sequence.

hmm, does this mean cmd-list entries have paddr to next cmdlist entry?

for EXA you could end up with everything from very small blits to
large ones..  ideally you want to minimize the overhead for blit n+1
which is why I'm not hugely fond of the one ioctl per blit.

>> If so, that would make the separate ioctls for SET_CMDLIST on each
>> blit operation, and then EXEC a bit awkward, and give you a huge # of
>> ioctls for something like EXA/x11 trying to use the blitter.
>>
>
> Yes, it's possible scenario. But the g2d driver can have maximum 64
> command list nodes which are processed by the dma directly so if
> exceeded then it returns some error.

well, the 64 limit can be handled, I suspect, on the kernel side.
Maybe the limitation is different on some future different version of
the blitter, etc.

> For detail, one command list from user(through SET_CMDLIST ioctl) is
> copied to a free command list node got from a free list that has
> maximum 64 command list nodes. And then the command list is placed in
> inuse_cmdlist and then if EXEC ioctl is called by user, all nodes of
> the inuse_cmdlist are moved to run_cmdlist and then the nodes of the
> run_cmdlist are processed by the dma in sequence.
>
>> Is there some documentation about G2D somewhere that I could read?
>
> Do you need some documents about G2D hardware? If so, I'm afriad that
> I couldn't give you the document because I have no any public version
> document about it. Sorry for this.

hmm, it certainly would be easier to write the EXA/userspace parts,
and maybe even make some improvements on the kernel side if needed,
with a bit of documentation about what the blitter can do and how to
program it..  granted I've written drivers with less information, but
it is a more time consuming process (and at least in that case I had a
userspace blob that I could observe via LD_PRELOAD shim)..

BR,
-R

> Thanks,
> Inki Dae
>
>> Just curious, because I have a chromebook on the way and was wondering
>> about trying to give x11 a bit help by means of G2D..
>>
>> BR,
>> -R
>>
>>
>> On Mon, Feb 18, 2013 at 7:51 AM, Inki Dae <inki.dae at samsung.com> wrote:
>>> This patch adds library and test application for g2d gpu(fimg2d).
>>>
>>> The fimg2d hardware is a 2D graphics accelerator(G2D) that
>>> supports Bit Block Transfer(BitBLT).
>>>
>>> The library includes the following primitive drawing operations:
>>> .solid fill - This operation fills the given buffer with
>>>         the given color data.
>>> .copy - This operation copies contents in source buffer to
>>>         destination buffer.
>>> .copy_with_scale - This operation copies contents in source buffer
>>>         to destination buffer scaling up or down properly.
>>> .blend - This operation blends contents in source buffer with
>>>         the ones in destination buffer.
>>>
>>> And the above operations uses gem handle or user space address
>>> allocated by malloc() as source or destination buffer.
>>>
>>> And the test application includes just simple primitive drawing
>>> tests with the above library.
>>> And the guide to test is as the following,
>>>         "#exynos_fimg2d_test -s connector_id at crtc_id:mode"
>>>
>>> With this above simple command, four primitive drawing operations
>>> would be called step by step and also rendered on the output device
>>> to the given connector and crtc id.
>>>
>>> Signed-off-by: Inki Dae <inki.dae at samsung.com>
>>> Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
>>> ---
>>>  configure.ac                      |    1 +
>>>  exynos/Makefile.am                |    2 +-
>>>  exynos/exynos_drm.h               |   52 +++
>>>  exynos/exynos_fimg2d.c            |  630 +++++++++++++++++++++++++++++++++
>>>  exynos/fimg2d.h                   |  325 +++++++++++++++++
>>>  exynos/fimg2d_reg.h               |  114 ++++++
>>>  tests/Makefile.am                 |    4 +
>>>  tests/exynos/Makefile.am          |   19 +
>>>  tests/exynos/exynos_fimg2d_test.c |  695 +++++++++++++++++++++++++++++++++++++
>>>  9 files changed, 1841 insertions(+), 1 deletions(-)
>>>  create mode 100644 exynos/exynos_fimg2d.c
>>>  create mode 100644 exynos/fimg2d.h
>>>  create mode 100644 exynos/fimg2d_reg.h
>>>  create mode 100644 tests/exynos/Makefile.am
>>>  create mode 100644 tests/exynos/exynos_fimg2d_test.c
>>>
>>> diff --git a/configure.ac b/configure.ac
>>> index e2e3466..2896f91 100644
>>> --- a/configure.ac
>>> +++ b/configure.ac
>>> @@ -364,6 +364,7 @@ AC_CONFIG_FILES([
>>>         tests/kmstest/Makefile
>>>         tests/radeon/Makefile
>>>         tests/vbltest/Makefile
>>> +       tests/exynos/Makefile
>>>         include/Makefile
>>>         include/drm/Makefile
>>>         man/Makefile
>>> diff --git a/exynos/Makefile.am b/exynos/Makefile.am
>>> index e782d34..539aea0 100644
>>> --- a/exynos/Makefile.am
>>> +++ b/exynos/Makefile.am
>>> @@ -10,7 +10,7 @@ libdrm_exynos_ladir = $(libdir)
>>>  libdrm_exynos_la_LDFLAGS = -version-number 1:0:0 -no-undefined
>>>  libdrm_exynos_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
>>>
>>> -libdrm_exynos_la_SOURCES = exynos_drm.c
>>> +libdrm_exynos_la_SOURCES = exynos_drm.c exynos_fimg2d.c
>>>
>>>  libdrm_exynoscommonincludedir = ${includedir}/exynos
>>>  libdrm_exynoscommoninclude_HEADERS = exynos_drm.h
>>> diff --git a/exynos/exynos_drm.h b/exynos/exynos_drm.h
>>> index aa97b22..c3c6579 100644
>>> --- a/exynos/exynos_drm.h
>>> +++ b/exynos/exynos_drm.h
>>> @@ -123,6 +123,46 @@ enum e_drm_exynos_gem_mem_type {
>>>                                         EXYNOS_BO_WC
>>>  };
>>>
>>> +struct drm_exynos_g2d_get_ver {
>>> +       __u32   major;
>>> +       __u32   minor;
>>> +};
>>> +
>>> +struct drm_exynos_g2d_cmd {
>>> +       __u32   offset;
>>> +       __u32   data;
>>> +};
>>> +
>>> +enum drm_exynos_g2d_buf_type {
>>> +       G2D_BUF_USERPTR = 1 << 31,
>>> +};
>>> +
>>> +enum drm_exynos_g2d_event_type {
>>> +       G2D_EVENT_NOT,
>>> +       G2D_EVENT_NONSTOP,
>>> +       G2D_EVENT_STOP,         /* not yet */
>>> +};
>>> +
>>> +struct drm_exynos_g2d_userptr {
>>> +       unsigned long userptr;
>>> +       unsigned long size;
>>> +};
>>> +
>>> +struct drm_exynos_g2d_set_cmdlist {
>>> +       __u64                                   cmd;
>>> +       __u64                                   cmd_buf;
>>> +       __u32                                   cmd_nr;
>>> +       __u32                                   cmd_buf_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
>>> @@ -130,6 +170,11 @@ enum e_drm_exynos_gem_mem_type {
>>>  #define DRM_EXYNOS_GEM_GET             0x04
>>>  #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)
>>>
>>> @@ -145,4 +190,11 @@ enum e_drm_exynos_gem_mem_type {
>>>  #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)
>>> +
>>>  #endif
>>> diff --git a/exynos/exynos_fimg2d.c b/exynos/exynos_fimg2d.c
>>> new file mode 100644
>>> index 0000000..cf712a8
>>> --- /dev/null
>>> +++ b/exynos/exynos_fimg2d.c
>>> @@ -0,0 +1,630 @@
>>> +/*
>>> + * Copyright (C) 2013 Samsung Electronics Co.Ltd
>>> + * Authors:
>>> + *     Inki Dae <inki.dae at samsung.com>
>>> + *
>>> + * This program is free software; you can redistribute  it and/or modify it
>>> + * under  the terms of  the GNU General  Public License as published by the
>>> + * Free Software Foundation;  either version 2 of the  License, or (at your
>>> + * option) any later version.
>>> + *
>>> + */
>>> +
>>> +#ifdef HAVE_CONFIG_H
>>> +#include "config.h"
>>> +#endif
>>> +
>>> +#include <stdlib.h>
>>> +#include <stdio.h>
>>> +#include <string.h>
>>> +#include <errno.h>
>>> +
>>> +#include <sys/mman.h>
>>> +#include <linux/stddef.h>
>>> +
>>> +#include <xf86drm.h>
>>> +
>>> +#include "exynos_drm.h"
>>> +#include "fimg2d_reg.h"
>>> +#include "fimg2d.h"
>>> +
>>> +#define                SET_BF(val, sc, si, scsa, scda, dc, di, dcsa, dcda) \
>>> +                       val.data.src_coeff = sc;                \
>>> +                       val.data.inv_src_color_coeff = si;      \
>>> +                       val.data.src_coeff_src_a = scsa;        \
>>> +                       val.data.src_coeff_dst_a = scda;        \
>>> +                       val.data.dst_coeff = dc;                \
>>> +                       val.data.inv_dst_color_coeff = di;      \
>>> +                       val.data.dst_coeff_src_a = dcsa;        \
>>> +                       val.data.dst_coeff_dst_a = dcda;
>>> +
>>> +#define MIN(a, b)      ((a) < (b) ? (a) : (b))
>>> +
>>> +static unsigned int g2d_get_blend_op(enum e_g2d_op op)
>>> +{
>>> +       union g2d_blend_func_val val;
>>> +
>>> +       val.val = 0;
>>> +
>>> +       switch (op) {
>>> +       case G2D_OP_CLEAR:
>>> +       case G2D_OP_DISJOINT_CLEAR:
>>> +       case G2D_OP_CONJOINT_CLEAR:
>>> +               SET_BF(val, G2D_COEFF_MODE_ZERO, 0, 0, 0, G2D_COEFF_MODE_ZERO,
>>> +                               0, 0, 0);
>>> +               break;
>>> +       case G2D_OP_SRC:
>>> +       case G2D_OP_DISJOINT_SRC:
>>> +       case G2D_OP_CONJOINT_SRC:
>>> +               SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, G2D_COEFF_MODE_ZERO,
>>> +                               0, 0, 0);
>>> +               break;
>>> +       case G2D_OP_DST:
>>> +       case G2D_OP_DISJOINT_DST:
>>> +       case G2D_OP_CONJOINT_DST:
>>> +               SET_BF(val, G2D_COEFF_MODE_ZERO, 0, 0, 0, G2D_COEFF_MODE_ONE,
>>> +                               0, 0, 0);
>>> +               break;
>>> +       case G2D_OP_OVER:
>>> +               SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0,
>>> +                               G2D_COEFF_MODE_SRC_ALPHA, 1, 0, 0);
>>> +               break;
>>> +       default:
>>> +               fprintf(stderr, "Not support operation(%d).\n", op);
>>> +               SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, G2D_COEFF_MODE_ZERO,
>>> +                               0, 0, 0);
>>> +               break;
>>> +       }
>>> +
>>> +       return val.val;
>>> +}
>>> +
>>> +/*
>>> + * g2d_add_cmd - set given command and value to user side command buffer.
>>> + *
>>> + * @ctx: a pointer to g2d_context structure.
>>> + * @cmd: command data.
>>> + * @value: value data.
>>> + */
>>> +static int g2d_add_cmd(struct g2d_context *ctx, unsigned long cmd,
>>> +                       unsigned long value)
>>> +{
>>> +       switch (cmd & ~(G2D_BUF_USERPTR)) {
>>> +       case SRC_BASE_ADDR_REG:
>>> +       case SRC_PLANE2_BASE_ADDR_REG:
>>> +       case DST_BASE_ADDR_REG:
>>> +       case DST_PLANE2_BASE_ADDR_REG:
>>> +       case PAT_BASE_ADDR_REG:
>>> +       case MASK_BASE_ADDR_REG:
>>> +               if (ctx->cmd_buf_nr >= G2D_MAX_GEM_CMD_NR) {
>>> +                       fprintf(stderr, "Overflow cmd_gem size.\n");
>>> +                       return -EINVAL;
>>> +               }
>>> +
>>> +               ctx->cmd_buf[ctx->cmd_buf_nr].offset = cmd;
>>> +               ctx->cmd_buf[ctx->cmd_buf_nr].data = value;
>>> +               ctx->cmd_buf_nr++;
>>> +               break;
>>> +       default:
>>> +               if (ctx->cmd_nr >= G2D_MAX_CMD_NR) {
>>> +                       fprintf(stderr, "Overflow cmd size.\n");
>>> +                       return -EINVAL;
>>> +               }
>>> +
>>> +               ctx->cmd[ctx->cmd_nr].offset = cmd;
>>> +               ctx->cmd[ctx->cmd_nr].data = value;
>>> +               ctx->cmd_nr++;
>>> +               break;
>>> +       }
>>> +
>>> +       return TRUE;
>>> +}
>>> +
>>> +/*
>>> + * g2d_reset - reset fimg2d hardware.
>>> + *
>>> + * @ctx: a pointer to g2d_context structure.
>>> + *
>>> + */
>>> +static void g2d_reset(struct g2d_context *ctx)
>>> +{
>>> +       ctx->cmd_nr = 0;
>>> +       ctx->cmd_buf_nr = 0;
>>> +
>>> +       g2d_add_cmd(ctx, SOFT_RESET_REG, 0x01);
>>> +}
>>> +
>>> +/*
>>> + * g2d_flush - summit all commands and values in user side command buffer
>>> + *             to command queue aware of fimg2d dma.
>>> + *
>>> + * @ctx: a pointer to g2d_context structure.
>>> + *
>>> + * This function should be called after all commands and values to user
>>> + * side command buffer is set to summit that buffer to kernel side driver.
>>> + */
>>> +static int g2d_flush(struct g2d_context *ctx)
>>> +{
>>> +       int ret;
>>> +       struct drm_exynos_g2d_set_cmdlist cmdlist;
>>> +
>>> +       if (ctx->cmd_nr  == 0 && ctx->cmd_buf_nr == 0)
>>> +               return FALSE;
>>> +
>>> +       if (ctx->cmdlist_nr >= G2D_MAX_CMD_LIST_NR) {
>>> +               fprintf(stderr, "Overflow cmdlist.\n");
>>> +               return -EINVAL;
>>> +       }
>>> +
>>> +       memset(&cmdlist, 0, sizeof(struct drm_exynos_g2d_set_cmdlist));
>>> +
>>> +       cmdlist.cmd = (unsigned int)&ctx->cmd[0];
>>> +       cmdlist.cmd_buf = (unsigned int)&ctx->cmd_buf[0];
>>> +       cmdlist.cmd_nr = ctx->cmd_nr;
>>> +       cmdlist.cmd_buf_nr = ctx->cmd_buf_nr;
>>> +       cmdlist.event_type = G2D_EVENT_NOT;
>>> +       cmdlist.user_data = 0;
>>> +
>>> +       ctx->cmd_nr = 0;
>>> +       ctx->cmd_buf_nr = 0;
>>> +
>>> +       ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST, &cmdlist);
>>> +       if (ret < 0) {
>>> +               fprintf(stderr, "failed to set cmdlist.\n");
>>> +               return ret;
>>> +       }
>>> +
>>> +       ctx->cmdlist_nr++;
>>> +
>>> +       return ret;
>>> +}
>>> +
>>> +/**
>>> + * g2d_init - create a new g2d context and get hardware version.
>>> + *
>>> + * fd: a file descriptor to drm device driver opened.
>>> + */
>>> +struct g2d_context *g2d_init(int fd)
>>> +{
>>> +       struct drm_exynos_g2d_get_ver ver;
>>> +       struct g2d_context *ctx;
>>> +       int ret;
>>> +
>>> +       ctx = calloc(1, sizeof(*ctx));
>>> +       if (!ctx) {
>>> +               fprintf(stderr, "failed to allocate context.\n");
>>> +               return NULL;
>>> +       }
>>> +
>>> +       ctx->fd = fd;
>>> +
>>> +       ret = drmIoctl(fd, DRM_IOCTL_EXYNOS_G2D_GET_VER, &ver);
>>> +       if (ret < 0) {
>>> +               fprintf(stderr, "failed to get version.\n");
>>> +               free(ctx);
>>> +               return NULL;
>>> +       }
>>> +
>>> +       ctx->major = ver.major;
>>> +       ctx->minor = ver.minor;
>>> +
>>> +       printf("g2d version(%d.%d).\n", ctx->major, ctx->minor);
>>> +       return ctx;
>>> +}
>>> +
>>> +void g2d_fini(struct g2d_context *ctx)
>>> +{
>>> +       if (ctx)
>>> +               free(ctx);
>>> +}
>>> +
>>> +/**
>>> + * g2d_exec - start the dma to process all commands summited by g2d_flush().
>>> + *
>>> + * @ctx: a pointer to g2d_context structure.
>>> + */
>>> +int g2d_exec(struct g2d_context *ctx)
>>> +{
>>> +       struct drm_exynos_g2d_exec exec;
>>> +       int ret;
>>> +
>>> +       if (ctx->cmdlist_nr == 0)
>>> +               return -EINVAL;
>>> +
>>> +       exec.async = 0;
>>> +
>>> +       ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_EXEC, &exec);
>>> +       if (ret < 0) {
>>> +               fprintf(stderr, "failed to execute.\n");
>>> +               return ret;
>>> +       }
>>> +
>>> +       ctx->cmdlist_nr = 0;
>>> +
>>> +       return ret;
>>> +}
>>> +
>>> +/**
>>> + * g2d_solid_fill - fill given buffer with given color data.
>>> + *
>>> + * @ctx: a pointer to g2d_context structure.
>>> + * @img: a pointer to g2d_image structure including image and buffer
>>> + *     information.
>>> + * @x: x start position to buffer filled with given color data.
>>> + * @y: y start position to buffer filled with given color data.
>>> + * @w: width value to buffer filled with given color data.
>>> + * @h: height value to buffer filled with given color data.
>>> + */
>>> +int g2d_solid_fill(struct g2d_context *ctx, struct g2d_image *img,
>>> +                       unsigned int x, unsigned int y, unsigned int w,
>>> +                       unsigned int h)
>>> +{
>>> +       union g2d_bitblt_cmd_val bitblt;
>>> +       union g2d_point_val pt;
>>> +
>>> +       g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL);
>>> +       g2d_add_cmd(ctx, DST_COLOR_MODE_REG, img->color_mode);
>>> +
>>> +       if (img->buf_type == G2D_IMGBUF_USERPTR)
>>> +               g2d_add_cmd(ctx, DST_BASE_ADDR_REG | G2D_BUF_USERPTR,
>>> +                               (unsigned long)&img->user_ptr[0]);
>>> +       else
>>> +               g2d_add_cmd(ctx, DST_BASE_ADDR_REG, img->bo[0]);
>>> +
>>> +       g2d_add_cmd(ctx, DST_STRIDE_REG, img->stride);
>>> +
>>> +       if (x + w > img->width)
>>> +               w = img->width - x;
>>> +       if (y + h > img->height)
>>> +               h = img->height - y;
>>> +
>>> +       pt.val = 0;
>>> +       pt.data.x = x;
>>> +       pt.data.y = y;
>>> +       g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val);
>>> +
>>> +       pt.val = 0;
>>> +       pt.data.x = x + w;
>>> +       pt.data.y = y + h;
>>> +
>>> +       g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val);
>>> +
>>> +       g2d_add_cmd(ctx, SF_COLOR_REG, img->color);
>>> +
>>> +       bitblt.val = 0;
>>> +       bitblt.data.fast_solid_color_fill_en = 1;
>>> +       g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val);
>>> +
>>> +       g2d_flush(ctx);
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +/**
>>> + * g2d_copy - copy contents in source buffer to destination buffer.
>>> + *
>>> + * @ctx: a pointer to g2d_context structure.
>>> + * @src: a pointer to g2d_image structure including image and buffer
>>> + *     information to source.
>>> + * @dst: a pointer to g2d_image structure including image and buffer
>>> + *     information to destination.
>>> + * @src_x: x start position to source buffer.
>>> + * @src_y: y start position to source buffer.
>>> + * @dst_x: x start position to destination buffer.
>>> + * @dst_y: y start position to destination buffer.
>>> + * @w: width value to source and destination buffers.
>>> + * @h: height value to source and destination buffers.
>>> + */
>>> +int g2d_copy(struct g2d_context *ctx, struct g2d_image *src,
>>> +               struct g2d_image *dst, unsigned int src_x, unsigned int src_y,
>>> +               unsigned int dst_x, unsigned dst_y, unsigned int w,
>>> +               unsigned int h)
>>> +{
>>> +       union g2d_rop4_val rop4;
>>> +       union g2d_point_val pt;
>>> +       unsigned int src_w = 0, src_h = 0, dst_w = 0, dst_h = 0;
>>> +
>>> +       g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR);
>>> +       g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode);
>>> +       if (dst->buf_type == G2D_IMGBUF_USERPTR)
>>> +               g2d_add_cmd(ctx, DST_BASE_ADDR_REG | G2D_BUF_USERPTR,
>>> +                               (unsigned long)&dst->user_ptr[0]);
>>> +       else
>>> +               g2d_add_cmd(ctx, DST_BASE_ADDR_REG, dst->bo[0]);
>>> +
>>> +       g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride);
>>> +
>>> +       g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL);
>>> +       g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode);
>>> +       if (src->buf_type == G2D_IMGBUF_USERPTR)
>>> +               g2d_add_cmd(ctx, SRC_BASE_ADDR_REG | G2D_BUF_USERPTR,
>>> +                               (unsigned long)&src->user_ptr[0]);
>>> +       else
>>> +               g2d_add_cmd(ctx, SRC_BASE_ADDR_REG, src->bo[0]);
>>> +
>>> +       g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride);
>>> +
>>> +       src_w = w;
>>> +       src_h = h;
>>> +       if (src_x + src->width > w)
>>> +               src_w = src->width - src_x;
>>> +       if (src_y + src->height > h)
>>> +               src_h = src->height - src_y;
>>> +
>>> +       dst_w = w;
>>> +       dst_h = w;
>>> +       if (dst_x + dst->width > w)
>>> +               dst_w = dst->width - dst_x;
>>> +       if (dst_y + dst->height > h)
>>> +               dst_h = dst->height - dst_y;
>>> +
>>> +       w = MIN(src_w, dst_w);
>>> +       h = MIN(src_h, dst_h);
>>> +
>>> +       if (w <= 0 || h <= 0) {
>>> +               fprintf(stderr, "invalid width or height.\n");
>>> +               g2d_reset(ctx);
>>> +               return -EINVAL;
>>> +       }
>>> +
>>> +       pt.val = 0;
>>> +       pt.data.x = src_x;
>>> +       pt.data.y = src_y;
>>> +       g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val);
>>> +       pt.val = 0;
>>> +       pt.data.x = src_x + w;
>>> +       pt.data.y = src_y + h;
>>> +       g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val);
>>> +
>>> +       pt.val = 0;
>>> +       pt.data.x = dst_x;
>>> +       pt.data.y = dst_y;
>>> +       g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val);
>>> +       pt.val = 0;
>>> +       pt.data.x = dst_x + w;
>>> +       pt.data.y = dst_x + h;
>>> +       g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val);
>>> +
>>> +       rop4.val = 0;
>>> +       rop4.data.unmasked_rop3 = G2D_ROP3_SRC;
>>> +       g2d_add_cmd(ctx, ROP4_REG, rop4.val);
>>> +
>>> +       g2d_flush(ctx);
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +/**
>>> + * g2d_copy_with_scale - copy contents in source buffer to destination buffer
>>> + *     scaling up or down properly.
>>> + *
>>> + * @ctx: a pointer to g2d_context structure.
>>> + * @src: a pointer to g2d_image structure including image and buffer
>>> + *     information to source.
>>> + * @dst: a pointer to g2d_image structure including image and buffer
>>> + *     information to destination.
>>> + * @src_x: x start position to source buffer.
>>> + * @src_y: y start position to source buffer.
>>> + * @src_w: width value to source buffer.
>>> + * @src_h: height value to source buffer.
>>> + * @dst_x: x start position to destination buffer.
>>> + * @dst_y: y start position to destination buffer.
>>> + * @dst_w: width value to destination buffer.
>>> + * @dst_h: height value to destination buffer.
>>> + * @negative: indicate that it uses color negative to source and
>>> + *     destination buffers.
>>> + */
>>> +int g2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src,
>>> +                               struct g2d_image *dst, unsigned int src_x,
>>> +                               unsigned int src_y, unsigned int src_w,
>>> +                               unsigned int src_h, unsigned int dst_x,
>>> +                               unsigned int dst_y, unsigned int dst_w,
>>> +                               unsigned int dst_h, unsigned int negative)
>>> +{
>>> +       union g2d_rop4_val rop4;
>>> +       union g2d_point_val pt;
>>> +       unsigned int scale;
>>> +       double scale_x = 0.0f, scale_y = 0.0f;
>>> +
>>> +       g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR);
>>> +       g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode);
>>> +       if (dst->buf_type == G2D_IMGBUF_USERPTR)
>>> +               g2d_add_cmd(ctx, DST_BASE_ADDR_REG | G2D_BUF_USERPTR,
>>> +                               (unsigned long)&dst->user_ptr[0]);
>>> +       else
>>> +               g2d_add_cmd(ctx, DST_BASE_ADDR_REG, dst->bo[0]);
>>> +
>>> +       g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride);
>>> +
>>> +       g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL);
>>> +       g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode);
>>> +       if (src->buf_type == G2D_IMGBUF_USERPTR)
>>> +               g2d_add_cmd(ctx, SRC_BASE_ADDR_REG | G2D_BUF_USERPTR,
>>> +                               (unsigned long)&src->user_ptr[0]);
>>> +       else
>>> +               g2d_add_cmd(ctx, SRC_BASE_ADDR_REG, src->bo[0]);
>>> +
>>> +       g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride);
>>> +
>>> +       if (src_w == dst_w && src_h == dst_h)
>>> +               scale = 0;
>>> +       else {
>>> +               scale = 1;
>>> +               scale_x = (double)src_w / (double)dst_w;
>>> +               scale_y = (double)src_w / (double)dst_h;
>>> +       }
>>> +
>>> +       if (src_x + src_w > src->width)
>>> +               src_w = src->width - src_x;
>>> +       if (src_y + src_h > src->height)
>>> +               src_h = src->height - src_y;
>>> +
>>> +       if (dst_x + dst_w > dst->width)
>>> +               dst_w = dst->width - dst_x;
>>> +       if (dst_y + dst_h > dst->height)
>>> +               dst_h = dst->height - dst_y;
>>> +
>>> +       if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) {
>>> +               fprintf(stderr, "invalid width or height.\n");
>>> +               g2d_reset(ctx);
>>> +               return -EINVAL;
>>> +       }
>>> +
>>> +       if (negative) {
>>> +               g2d_add_cmd(ctx, BG_COLOR_REG, 0x00FFFFFF);
>>> +               rop4.val = 0;
>>> +               rop4.data.unmasked_rop3 = G2D_ROP3_SRC^G2D_ROP3_DST;
>>> +               g2d_add_cmd(ctx, ROP4_REG, rop4.val);
>>> +       } else {
>>> +               rop4.val = 0;
>>> +               rop4.data.unmasked_rop3 = G2D_ROP3_SRC;
>>> +               g2d_add_cmd(ctx, ROP4_REG, rop4.val);
>>> +       }
>>> +
>>> +       if (scale) {
>>> +               g2d_add_cmd(ctx, SRC_SCALE_CTRL_REG, G2D_SCALE_MODE_BILINEAR);
>>> +               g2d_add_cmd(ctx, SRC_XSCALE_REG, G2D_DOUBLE_TO_FIXED(scale_x));
>>> +               g2d_add_cmd(ctx, SRC_YSCALE_REG, G2D_DOUBLE_TO_FIXED(scale_y));
>>> +       }
>>> +
>>> +       pt.val = 0;
>>> +       pt.data.x = src_x;
>>> +       pt.data.y = src_y;
>>> +       g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val);
>>> +       pt.val = 0;
>>> +       pt.data.x = src_x + src_w;
>>> +       pt.data.y = src_y + src_h;
>>> +       g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val);
>>> +
>>> +       pt.val = 0;
>>> +       pt.data.x = dst_x;
>>> +       pt.data.y = dst_y;
>>> +       g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val);
>>> +       pt.val = 0;
>>> +       pt.data.x = dst_x + dst_w;
>>> +       pt.data.y = dst_y + dst_h;
>>> +       g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val);
>>> +
>>> +       g2d_flush(ctx);
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +/**
>>> + * g2d_blend - blend image data in source and destion buffers
>>> + *
>>> + * @ctx: a pointer to g2d_context structure.
>>> + * @src: a pointer to g2d_image structure including image and buffer
>>> + *     information to source.
>>> + * @dst: a pointer to g2d_image structure including image and buffer
>>> + *     information to destination.
>>> + * @src_x: x start position to source buffer.
>>> + * @src_y: y start position to source buffer.
>>> + * @dst_x: x start position to destination buffer.
>>> + * @dst_y: y start position to destination buffer.
>>> + * @w: width value to source and destination buffer.
>>> + * @h: height value to source and destination buffer.
>>> + * @op: blend operation type.
>>> + */
>>> +int g2d_blend(struct g2d_context *ctx, struct g2d_image *src,
>>> +               struct g2d_image *dst, unsigned int src_x,
>>> +               unsigned int src_y, unsigned int dst_x, unsigned int dst_y,
>>> +               unsigned int w, unsigned int h, enum e_g2d_op op)
>>> +{
>>> +       union g2d_point_val pt;
>>> +       union g2d_bitblt_cmd_val bitblt;
>>> +       union g2d_blend_func_val blend;
>>> +       unsigned int src_w = 0, src_h = 0, dst_w = 0, dst_h = 0;
>>> +
>>> +       bitblt.val = 0;
>>> +       blend.val = 0;
>>> +
>>> +       if (op == G2D_OP_SRC || op == G2D_OP_CLEAR)
>>> +               g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR);
>>> +       else
>>> +               g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL);
>>> +
>>> +       g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode);
>>> +       if (dst->buf_type == G2D_IMGBUF_USERPTR)
>>> +               g2d_add_cmd(ctx, DST_BASE_ADDR_REG | G2D_BUF_USERPTR,
>>> +                               (unsigned long)&dst->user_ptr[0]);
>>> +       else
>>> +               g2d_add_cmd(ctx, DST_BASE_ADDR_REG, dst->bo[0]);
>>> +
>>> +       g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride);
>>> +
>>> +       g2d_add_cmd(ctx, SRC_SELECT_REG, src->select_mode);
>>> +       g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode);
>>> +
>>> +       switch (src->select_mode) {
>>> +       case G2D_SELECT_MODE_NORMAL:
>>> +               if (src->buf_type == G2D_IMGBUF_USERPTR)
>>> +                       g2d_add_cmd(ctx, SRC_BASE_ADDR_REG | G2D_BUF_USERPTR,
>>> +                                       (unsigned long)&src->user_ptr[0]);
>>> +               else
>>> +                       g2d_add_cmd(ctx, SRC_BASE_ADDR_REG, src->bo[0]);
>>> +
>>> +               g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride);
>>> +               break;
>>> +       case G2D_SELECT_MODE_FGCOLOR:
>>> +               g2d_add_cmd(ctx, FG_COLOR_REG, src->color);
>>> +               break;
>>> +       case G2D_SELECT_MODE_BGCOLOR:
>>> +               g2d_add_cmd(ctx, BG_COLOR_REG, src->color);
>>> +               break;
>>> +       default:
>>> +               fprintf(stderr , "failed to set src.\n");
>>> +               return -EINVAL;
>>> +       }
>>> +
>>> +       src_w = w;
>>> +       src_h = h;
>>> +       if (src_x + w > src->width)
>>> +               src_w = src->width - src_x;
>>> +       if (src_y + h > src->height)
>>> +               src_h = src->height - src_y;
>>> +
>>> +       dst_w = w;
>>> +       dst_h = h;
>>> +       if (dst_x + w > dst->width)
>>> +               dst_w = dst->width - dst_x;
>>> +       if (dst_y + h > dst->height)
>>> +               dst_h = dst->height - dst_y;
>>> +
>>> +       w = MIN(src_w, dst_w);
>>> +       h = MIN(src_h, dst_h);
>>> +
>>> +       if (w <= 0 || h <= 0) {
>>> +               fprintf(stderr, "invalid width or height.\n");
>>> +               g2d_reset(ctx);
>>> +               return -EINVAL;
>>> +       }
>>> +
>>> +       bitblt.data.alpha_blend_mode = G2D_ALPHA_BLEND_MODE_ENABLE;
>>> +       blend.val = g2d_get_blend_op(op);
>>> +       g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val);
>>> +       g2d_add_cmd(ctx, BLEND_FUNCTION_REG, blend.val);
>>> +
>>> +       pt.val = 0;
>>> +       pt.data.x = src_x;
>>> +       pt.data.y = src_y;
>>> +       g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val);
>>> +       pt.val = 0;
>>> +       pt.data.x = src_x + w;
>>> +       pt.data.y = src_y + h;
>>> +       g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val);
>>> +
>>> +       pt.val = 0;
>>> +       pt.data.x = dst_x;
>>> +       pt.data.y = dst_y;
>>> +       g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val);
>>> +       pt.val = 0;
>>> +       pt.data.x = dst_x + w;
>>> +       pt.data.y = dst_y + h;
>>> +       g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val);
>>> +
>>> +       g2d_flush(ctx);
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> diff --git a/exynos/fimg2d.h b/exynos/fimg2d.h
>>> new file mode 100644
>>> index 0000000..8770dcd
>>> --- /dev/null
>>> +++ b/exynos/fimg2d.h
>>> @@ -0,0 +1,325 @@
>>> +/*
>>> + * Copyright (C) 2013 Samsung Electronics Co.Ltd
>>> + * Authors:
>>> + *     Inki Dae <inki.dae at samsung.com>
>>> + *
>>> + * This program is free software; you can redistribute  it and/or modify it
>>> + * under  the terms of  the GNU General  Public License as published by the
>>> + * Free Software Foundation;  either version 2 of the  License, or (at your
>>> + * option) any later version.
>>> + *
>>> + */
>>> +
>>> +#ifndef _FIMG2D_H_
>>> +#define _FIMG2D_H_
>>> +
>>> +#ifndef TRUE
>>> +#define TRUE 0
>>> +#endif
>>> +#ifndef FALSE
>>> +#define FALSE -1
>>> +#endif
>>> +
>>> +#define G2D_MAX_CMD_NR         64
>>> +#define G2D_MAX_GEM_CMD_NR     64
>>> +#define G2D_MAX_CMD_LIST_NR    64
>>> +#define G2D_PLANE_MAX_NR       2
>>> +
>>> +#define G2D_DOUBLE_TO_FIXED(d)         ((unsigned int)(d) * 65536.0)
>>> +
>>> +enum e_g2d_color_mode {
>>> +       /* 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,
>>> +       /* alpha 8bit */
>>> +       G2D_COLOR_FMT_A8,
>>> +       /* Luminance 8bit: gray color */
>>> +       G2D_COLOR_FMT_L8,
>>> +       /* alpha 1bit */
>>> +       G2D_COLOR_FMT_A1,
>>> +       /* alpha 4bit */
>>> +       G2D_COLOR_FMT_A4,
>>> +       G2D_COLOR_FMT_MASK,                             /* 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_CrCb = G2D_YCbCr_ORDER_CrY1CbY0,        /* VER4.1 */
>>> +       G2D_YCbCr_ORDER_CbCr = G2D_YCbCr_ORDER_CbY1CrY0,        /* 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,
>>> +};
>>> +
>>> +enum e_g2d_select_mode {
>>> +       G2D_SELECT_MODE_NORMAL  = (0 << 0),
>>> +       G2D_SELECT_MODE_FGCOLOR = (1 << 0),
>>> +       G2D_SELECT_MODE_BGCOLOR = (2 << 0),
>>> +};
>>> +
>>> +enum e_g2d_repeat_mode {
>>> +       G2D_REPEAT_MODE_REPEAT,
>>> +       G2D_REPEAT_MODE_PAD,
>>> +       G2D_REPEAT_MODE_REFLECT,
>>> +       G2D_REPEAT_MODE_CLAMP,
>>> +       G2D_REPEAT_MODE_NONE,
>>> +};
>>> +
>>> +enum e_g2d_scale_mode {
>>> +       G2D_SCALE_MODE_NONE = 0,
>>> +       G2D_SCALE_MODE_NEAREST,
>>> +       G2D_SCALE_MODE_BILINEAR,
>>> +       G2D_SCALE_MODE_MAX,
>>> +};
>>> +
>>> +enum e_g2d_buf_type {
>>> +       G2D_IMGBUF_COLOR,
>>> +       G2D_IMGBUF_GEM,
>>> +       G2D_IMGBUF_USERPTR,
>>> +};
>>> +
>>> +enum e_g2d_rop3_type {
>>> +       G2D_ROP3_DST = 0xAA,
>>> +       G2D_ROP3_SRC = 0xCC,
>>> +       G2D_ROP3_3RD = 0xF0,
>>> +       G2D_ROP3_MASK = 0xFF,
>>> +};
>>> +
>>> +enum e_g2d_select_alpha_src {
>>> +       G2D_SELECT_SRC_FOR_ALPHA_BLEND, /* VER4.1 */
>>> +       G2D_SELECT_ROP_FOR_ALPHA_BLEND, /* VER4.1 */
>>> +};
>>> +
>>> +enum e_g2d_transparent_mode {
>>> +       G2D_TRANSPARENT_MODE_OPAQUE,
>>> +       G2D_TRANSPARENT_MODE_TRANSPARENT,
>>> +       G2D_TRANSPARENT_MODE_BLUESCREEN,
>>> +       G2D_TRANSPARENT_MODE_MAX,
>>> +};
>>> +
>>> +enum e_g2d_color_key_mode {
>>> +       G2D_COLORKEY_MODE_DISABLE       = 0,
>>> +       G2D_COLORKEY_MODE_SRC_RGBA      = (1<<0),
>>> +       G2D_COLORKEY_MODE_DST_RGBA      = (1<<1),
>>> +       G2D_COLORKEY_MODE_SRC_YCbCr     = (1<<2),               /* VER4.1 */
>>> +       G2D_COLORKEY_MODE_DST_YCbCr     = (1<<3),               /* VER4.1 */
>>> +       G2D_COLORKEY_MODE_MASK          = 15,
>>> +};
>>> +
>>> +enum e_g2d_alpha_blend_mode {
>>> +       G2D_ALPHA_BLEND_MODE_DISABLE,
>>> +       G2D_ALPHA_BLEND_MODE_ENABLE,
>>> +       G2D_ALPHA_BLEND_MODE_FADING,                            /* VER3.0 */
>>> +       G2D_ALPHA_BLEND_MODE_MAX,
>>> +};
>>> +
>>> +enum e_g2d_op {
>>> +       G2D_OP_CLEAR                    = 0x00,
>>> +       G2D_OP_SRC                      = 0x01,
>>> +       G2D_OP_DST                      = 0x02,
>>> +       G2D_OP_OVER                     = 0x03,
>>> +       G2D_OP_DISJOINT_CLEAR           = 0x10,
>>> +       G2D_OP_DISJOINT_SRC             = 0x11,
>>> +       G2D_OP_DISJOINT_DST             = 0x12,
>>> +       G2D_OP_CONJOINT_CLEAR           = 0x20,
>>> +       G2D_OP_CONJOINT_SRC             = 0x21,
>>> +       G2D_OP_CONJOINT_DST             = 0x22,
>>> +};
>>> +
>>> +enum e_g2d_coeff_mode {
>>> +       G2D_COEFF_MODE_ONE,
>>> +       G2D_COEFF_MODE_ZERO,
>>> +       G2D_COEFF_MODE_SRC_ALPHA,
>>> +       G2D_COEFF_MODE_SRC_COLOR,
>>> +       G2D_COEFF_MODE_DST_ALPHA,
>>> +       G2D_COEFF_MODE_DST_COLOR,
>>> +       /* Global Alpha : Set by ALPHA_REG(0x618) */
>>> +       G2D_COEFF_MODE_GB_ALPHA,
>>> +       /* Global Alpha : Set by ALPHA_REG(0x618) */
>>> +       G2D_COEFF_MODE_GB_COLOR,
>>> +       /* (1-SRC alpha)/DST Alpha */
>>> +       G2D_COEFF_MODE_DISJOINT_S,
>>> +       /* (1-DST alpha)/SRC Alpha */
>>> +       G2D_COEFF_MODE_DISJOINT_D,
>>> +       /* SRC alpha/DST alpha */
>>> +       G2D_COEFF_MODE_CONJOINT_S,
>>> +       /* DST alpha/SRC alpha */
>>> +       G2D_COEFF_MODE_CONJOINT_D,
>>> +       /* DST alpha/SRC alpha */
>>> +       G2D_COEFF_MODE_MASK
>>> +};
>>> +
>>> +enum e_g2d_acoeff_mode {
>>> +       G2D_ACOEFF_MODE_A,          /* alpha */
>>> +       G2D_ACOEFF_MODE_APGA,   /* alpha + global alpha */
>>> +       G2D_ACOEFF_MODE_AMGA,   /* alpha * global alpha */
>>> +       G2D_ACOEFF_MODE_MASK
>>> +};
>>> +
>>> +union g2d_point_val {
>>> +       unsigned int val;
>>> +       struct {
>>> +               /*
>>> +                * Coordinate of Source Image
>>> +                * Range: 0 ~ 8000 (Requirement: SrcLeftX < SrcRightX)
>>> +                * In YCbCr 422 and YCbCr 420 format with even number.
>>> +                */
>>> +               unsigned int x:16;
>>> +               /*
>>> +                * Y Coordinate of Source Image
>>> +                * Range: 0 ~ 8000 (Requirement: SrcTopY < SrcBottomY)
>>> +                * In YCbCr 420 format with even number.
>>> +                */
>>> +               unsigned int y:16;
>>> +       } data;
>>> +};
>>> +
>>> +union g2d_rop4_val {
>>> +       unsigned int val;
>>> +       struct {
>>> +               enum e_g2d_rop3_type    unmasked_rop3:8;
>>> +               enum e_g2d_rop3_type    masked_rop3:8;
>>> +               unsigned int            reserved:16;
>>> +       } data;
>>> +};
>>> +
>>> +union g2d_bitblt_cmd_val {
>>> +       unsigned int val;
>>> +       struct {
>>> +               /* [0:3] */
>>> +               unsigned int                    mask_rop4_en:1;
>>> +               unsigned int                    masking_en:1;
>>> +               enum e_g2d_select_alpha_src     rop4_alpha_en:1;
>>> +               unsigned int                    dither_en:1;
>>> +               /* [4:7] */
>>> +               unsigned int                    resolved1:4;
>>> +               /* [8:11] */
>>> +               unsigned int                    cw_en:4;
>>> +               /* [12:15] */
>>> +               enum e_g2d_transparent_mode     transparent_mode:4;
>>> +               /* [16:19] */
>>> +               enum e_g2d_color_key_mode       color_key_mode:4;
>>> +               /* [20:23] */
>>> +               enum e_g2d_alpha_blend_mode     alpha_blend_mode:4;
>>> +               /* [24:27] */
>>> +               unsigned int src_pre_multiply:1;
>>> +               unsigned int pat_pre_multiply:1;
>>> +               unsigned int dst_pre_multiply:1;
>>> +               unsigned int dst_depre_multiply:1;
>>> +               /* [28:31] */
>>> +               unsigned int fast_solid_color_fill_en:1;
>>> +               unsigned int reserved:3;
>>> +       } data;
>>> +};
>>> +
>>> +union g2d_blend_func_val {
>>> +       unsigned int val;
>>> +       struct {
>>> +               /* [0:15] */
>>> +               enum e_g2d_coeff_mode src_coeff:4;
>>> +               enum e_g2d_acoeff_mode src_coeff_src_a:2;
>>> +               enum e_g2d_acoeff_mode src_coeff_dst_a:2;
>>> +               enum e_g2d_coeff_mode dst_coeff:4;
>>> +               enum e_g2d_acoeff_mode dst_coeff_src_a:2;
>>> +               enum e_g2d_acoeff_mode dst_coeff_dst_a:2;
>>> +               /* [16:19] */
>>> +               unsigned int inv_src_color_coeff:1;
>>> +               unsigned int resoled1:1;
>>> +               unsigned int inv_dst_color_coeff:1;
>>> +               unsigned int resoled2:1;
>>> +               /* [20:23] */
>>> +               unsigned int lighten_en:1;
>>> +               unsigned int darken_en:1;
>>> +               unsigned int win_ce_src_over_en:2;
>>> +               /* [24:31] */
>>> +               unsigned int reserved:8;
>>> +       } data;
>>> +};
>>> +
>>> +struct g2d_image {
>>> +       enum e_g2d_select_mode          select_mode;
>>> +       enum e_g2d_color_mode           color_mode;
>>> +       enum e_g2d_repeat_mode          repeat_mode;
>>> +       enum e_g2d_scale_mode           scale_mode;
>>> +       unsigned int                    xscale;
>>> +       unsigned int                    yscale;
>>> +       unsigned char                   rotate_90;
>>> +       unsigned char                   x_dir;
>>> +       unsigned char                   y_dir;
>>> +       unsigned char                   component_alpha;
>>> +       unsigned int                    width;
>>> +       unsigned int                    height;
>>> +       unsigned int                    stride;
>>> +       unsigned int                    need_free;
>>> +       unsigned int                    color;
>>> +       enum e_g2d_buf_type             buf_type;
>>> +       unsigned int                    bo[G2D_PLANE_MAX_NR];
>>> +       struct drm_exynos_g2d_userptr   user_ptr[G2D_PLANE_MAX_NR];
>>> +       void                            *mapped_ptr[G2D_PLANE_MAX_NR];
>>> +};
>>> +
>>> +struct g2d_context {
>>> +       int                             fd;
>>> +       unsigned int                    major;
>>> +       unsigned int                    minor;
>>> +       struct drm_exynos_g2d_cmd       cmd[G2D_MAX_CMD_NR];
>>> +       struct drm_exynos_g2d_cmd       cmd_buf[G2D_MAX_GEM_CMD_NR];
>>> +       unsigned int                    cmd_nr;
>>> +       unsigned int                    cmd_buf_nr;
>>> +       unsigned int                    cmdlist_nr;
>>> +};
>>> +
>>> +struct g2d_context *g2d_init(int fd);
>>> +void g2d_fini(struct g2d_context *ctx);
>>> +int g2d_exec(struct g2d_context *ctx);
>>> +int g2d_solid_fill(struct g2d_context *ctx, struct g2d_image *img,
>>> +                       unsigned int x, unsigned int y, unsigned int w,
>>> +                       unsigned int h);
>>> +int g2d_copy(struct g2d_context *ctx, struct g2d_image *src,
>>> +               struct g2d_image *dst, unsigned int src_x,
>>> +               unsigned int src_y, unsigned int dst_x, unsigned int dst_y,
>>> +               unsigned int w, unsigned int h);
>>> +int g2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src,
>>> +                               struct g2d_image *dst, unsigned int src_x,
>>> +                               unsigned int src_y, unsigned int src_w,
>>> +                               unsigned int src_h, unsigned int dst_x,
>>> +                               unsigned int dst_y, unsigned int dst_w,
>>> +                               unsigned int dst_h, unsigned int negative);
>>> +int g2d_blend(struct g2d_context *ctx, struct g2d_image *src,
>>> +               struct g2d_image *dst, unsigned int src_x,
>>> +               unsigned int src_y, unsigned int dst_x, unsigned int dst_y,
>>> +               unsigned int w, unsigned int h, enum e_g2d_op op);
>>> +#endif /* _FIMG2D_H_ */
>>> diff --git a/exynos/fimg2d_reg.h b/exynos/fimg2d_reg.h
>>> new file mode 100644
>>> index 0000000..5782488
>>> --- /dev/null
>>> +++ b/exynos/fimg2d_reg.h
>>> @@ -0,0 +1,114 @@
>>> +/*
>>> + * Copyright (C) 2013 Samsung Electronics Co.Ltd
>>> + * Authors:
>>> + *     Inki Dae <inki.dae at samsung.com>
>>> + *
>>> + * This program is free software; you can redistribute  it and/or modify it
>>> + * under  the terms of  the GNU General  Public License as published by the
>>> + * Free Software Foundation;  either version 2 of the  License, or (at your
>>> + * option) any later version.
>>> + *
>>> + */
>>> +
>>> +#ifndef _FIMG2D_REG_H_
>>> +#define _FIMG2D_REG_H_
>>> +
>>> +#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 */
>>> +#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 */
>>> +/*Y CbCr 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 */
>>> +
>>> +#endif
>>> +
>>> diff --git a/tests/Makefile.am b/tests/Makefile.am
>>> index a3a59bd..cd11491 100644
>>> --- a/tests/Makefile.am
>>> +++ b/tests/Makefile.am
>>> @@ -20,6 +20,10 @@ if HAVE_RADEON
>>>  SUBDIRS += radeon
>>>  endif
>>>
>>> +if HAVE_EXYNOS
>>> +SUBDIRS += exynos
>>> +endif
>>> +
>>>  if HAVE_LIBUDEV
>>>
>>>  check_LTLIBRARIES = libdrmtest.la
>>> diff --git a/tests/exynos/Makefile.am b/tests/exynos/Makefile.am
>>> new file mode 100644
>>> index 0000000..bf9ad82
>>> --- /dev/null
>>> +++ b/tests/exynos/Makefile.am
>>> @@ -0,0 +1,19 @@
>>> +AM_CFLAGS = \
>>> +       -I $(top_srcdir)/include/drm \
>>> +       -I $(top_srcdir)/libkms/ \
>>> +       -I $(top_srcdir)/exynos \
>>> +       -I $(top_srcdir)
>>> +
>>> +noinst_PROGRAMS = \
>>> +       exynos_fimg2d_test
>>> +
>>> +exynos_fimg2d_test_LDADD = \
>>> +       $(top_builddir)/libdrm.la \
>>> +       $(top_builddir)/libkms/libkms.la \
>>> +       $(top_builddir)/exynos/libdrm_exynos.la
>>> +
>>> +exynos_fimg2d_test_SOURCES = \
>>> +       exynos_fimg2d_test.c
>>> +
>>> +run: exynos_fimg2d_test
>>> +       ./exynos_fimg2d_test
>>> diff --git a/tests/exynos/exynos_fimg2d_test.c b/tests/exynos/exynos_fimg2d_test.c
>>> new file mode 100644
>>> index 0000000..7813468
>>> --- /dev/null
>>> +++ b/tests/exynos/exynos_fimg2d_test.c
>>> @@ -0,0 +1,695 @@
>>> +/*
>>> + * Copyright (C) 2013 Samsung Electronics Co.Ltd
>>> + * Authors:
>>> + *     Inki Dae <inki.dae at samsung.com>
>>> + *
>>> + * This program is free software; you can redistribute  it and/or modify it
>>> + * under  the terms of  the GNU General  Public License as published by the
>>> + * Free Software Foundation;  either version 2 of the  License, or (at your
>>> + * option) any later version.
>>> + *
>>> + */
>>> +
>>> +#ifdef HAVE_CONFIG_H
>>> +#include "config.h"
>>> +#endif
>>> +
>>> +#include <stdlib.h>
>>> +#include <stdio.h>
>>> +#include <string.h>
>>> +#include <errno.h>
>>> +
>>> +#include <sys/mman.h>
>>> +#include <linux/stddef.h>
>>> +
>>> +#include <xf86drm.h>
>>> +#include <xf86drmMode.h>
>>> +#include <libkms.h>
>>> +#include <drm_fourcc.h>
>>> +
>>> +#include "exynos_drm.h"
>>> +#include "exynos_drmif.h"
>>> +#include "fimg2d.h"
>>> +
>>> +#define DRM_MODULE_NAME                "exynos"
>>> +#define MAX_TEST_CASE          8
>>> +
>>> +static unsigned int screen_width, screen_height;
>>> +
>>> +/*
>>> + * A structure to test fimg2d hw.
>>> + *
>>> + * @solid_fild: fill given color data to source buffer.
>>> + * @copy: copy source to destination buffer.
>>> + * @copy_with_scale: copy source to destination buffer scaling up or
>>> + *     down properly.
>>> + * @blend: blend source to destination buffer.
>>> + */
>>> +struct fimg2d_test_case {
>>> +       int (*solid_fill)(struct exynos_device *dev, struct exynos_bo *dst);
>>> +       int (*copy)(struct exynos_device *dev, struct exynos_bo *src,
>>> +                       struct exynos_bo *dst, enum e_g2d_buf_type);
>>> +       int (*copy_with_scale)(struct exynos_device *dev,
>>> +                               struct exynos_bo *src, struct exynos_bo *dst,
>>> +                               enum e_g2d_buf_type);
>>> +       int (*blend)(struct exynos_device *dev,
>>> +                               struct exynos_bo *src, struct exynos_bo *dst,
>>> +                               enum e_g2d_buf_type);
>>> +};
>>> +
>>> +struct connector {
>>> +       uint32_t id;
>>> +       char mode_str[64];
>>> +       char format_str[5];
>>> +       unsigned int fourcc;
>>> +       drmModeModeInfo *mode;
>>> +       drmModeEncoder *encoder;
>>> +       int crtc;
>>> +       int pipe;
>>> +       int plane_zpos;
>>> +       unsigned int fb_id[2], current_fb_id;
>>> +       struct timeval start;
>>> +
>>> +       int swap_count;
>>> +};
>>> +
>>> +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 drm_set_crtc(struct exynos_device *dev, struct connector *c,
>>> +                       unsigned int fb_id)
>>> +{
>>> +       int ret;
>>> +
>>> +       ret = drmModeSetCrtc(dev->fd, c->crtc,
>>> +                       fb_id, 0, 0, &c->id, 1, c->mode);
>>> +       if (ret) {
>>> +               drmMsg("failed to set mode: %s\n", strerror(errno));
>>> +               goto err;
>>> +       }
>>> +
>>> +       return 0;
>>> +
>>> +err:
>>> +       return ret;
>>> +}
>>> +
>>> +static struct exynos_bo *exynos_create_buffer(struct exynos_device *dev,
>>> +                                               unsigned long size,
>>> +                                               unsigned int flags)
>>> +{
>>> +       struct exynos_bo *bo;
>>> +
>>> +       bo = exynos_bo_create(dev, size, flags);
>>> +       if (!bo)
>>> +               return bo;
>>> +
>>> +       if (!exynos_bo_map(bo)) {
>>> +               exynos_bo_destroy(bo);
>>> +               return NULL;
>>> +       }
>>> +
>>> +       return bo;
>>> +}
>>> +
>>> +static void exynos_destroy_buffer(struct exynos_bo *bo)
>>> +{
>>> +       exynos_bo_destroy(bo);
>>> +}
>>> +
>>> +static int g2d_solid_fill_test(struct exynos_device *dev, struct exynos_bo *dst)
>>> +{
>>> +       struct g2d_context *ctx;
>>> +       struct g2d_image img;
>>> +       unsigned int count, img_w, img_h;
>>> +       int ret = 0;
>>> +
>>> +       ctx = g2d_init(dev->fd);
>>> +       if (!ctx)
>>> +               return -EFAULT;
>>> +
>>> +       memset(&img, 0, sizeof(struct g2d_image));
>>> +       img.bo[0] = dst->handle;
>>> +
>>> +       printf("soild fill test.\n");
>>> +
>>> +       srand(time(NULL));
>>> +       img_w = screen_width;
>>> +       img_h = screen_height;
>>> +
>>> +       for (count = 0; count < 2; count++) {
>>> +               unsigned int x, y, w, h;
>>> +
>>> +               x = rand() % (img_w / 2);
>>> +               y = rand() % (img_h / 2);
>>> +               w = rand() % (img_w - x);
>>> +               h = rand() % (img_h - y);
>>> +
>>> +               img.width = img_w;
>>> +               img.height = img_h;
>>> +               img.stride = img.width * 4;
>>> +               img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
>>> +               img.color = 0xff000000 + (random() & 0xffffff);
>>> +
>>> +               ret = g2d_solid_fill(ctx, &img, x, y, w, h);
>>> +               if (ret < 0)
>>> +                       goto err_fini;
>>> +
>>> +               ret = g2d_exec(ctx);
>>> +               if (ret < 0)
>>> +                       break;
>>> +       }
>>> +
>>> +err_fini:
>>> +       g2d_fini(ctx);
>>> +
>>> +       return ret;
>>> +}
>>> +
>>> +static int g2d_copy_test(struct exynos_device *dev, struct exynos_bo *src,
>>> +                               struct exynos_bo *dst,
>>> +                               enum e_g2d_buf_type type)
>>> +{
>>> +       struct g2d_context *ctx;
>>> +       struct g2d_image src_img, dst_img;
>>> +       unsigned int count;
>>> +       unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
>>> +       unsigned long userptr, size;
>>> +       int ret;
>>> +
>>> +       ctx = g2d_init(dev->fd);
>>> +       if (!ctx)
>>> +               return -EFAULT;
>>> +
>>> +       memset(&src_img, 0, sizeof(struct g2d_image));
>>> +       memset(&dst_img, 0, sizeof(struct g2d_image));
>>> +       dst_img.bo[0] = dst->handle;
>>> +
>>> +       src_x = 0;
>>> +       src_y = 0;
>>> +       dst_x = 0;
>>> +       dst_y = 0;
>>> +       img_w = screen_width;
>>> +       img_h = screen_height;
>>> +
>>> +       switch (type) {
>>> +       case G2D_IMGBUF_GEM:
>>> +               src_img.bo[0] = src->handle;
>>> +               break;
>>> +       case G2D_IMGBUF_USERPTR:
>>> +               size = img_w * img_h * 4;
>>> +
>>> +               userptr = (unsigned long)malloc(size);
>>> +               if (!userptr) {
>>> +                       fprintf(stderr, "failed to allocate userptr.\n");
>>> +                       return -EFAULT;
>>> +               }
>>> +
>>> +               src_img.user_ptr[0].userptr = userptr;
>>> +               src_img.user_ptr[0].size = size;
>>> +               break;
>>> +       default:
>>> +               type = G2D_IMGBUF_GEM;
>>> +               break;
>>> +       }
>>> +
>>> +       printf("copy test with %s.\n",
>>> +                       type == G2D_IMGBUF_GEM ? "gem" : "userptr");
>>> +
>>> +       src_img.width = img_w;
>>> +       src_img.height = img_h;
>>> +       src_img.stride = src_img.width * 4;
>>> +       src_img.buf_type = type;
>>> +       src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
>>> +       src_img.color = 0xffff0000;
>>> +       ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h);
>>> +       if (ret < 0)
>>> +               goto err_free_userptr;
>>> +
>>> +       dst_img.width = img_w;
>>> +       dst_img.height = img_h;
>>> +       dst_img.stride = dst_img.width * 4;
>>> +       dst_img.buf_type = G2D_IMGBUF_GEM;
>>> +       dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
>>> +
>>> +       ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y,
>>> +                       img_w - 4, img_h - 4);
>>> +       if (ret < 0)
>>> +               goto err_free_userptr;
>>> +
>>> +       g2d_exec(ctx);
>>> +
>>> +err_free_userptr:
>>> +       if (type == G2D_IMGBUF_USERPTR)
>>> +               if (userptr)
>>> +                       free((void *)userptr);
>>> +
>>> +       g2d_fini(ctx);
>>> +
>>> +       return ret;
>>> +}
>>> +
>>> +static int g2d_copy_with_scale_test(struct exynos_device *dev,
>>> +                                       struct exynos_bo *src,
>>> +                                       struct exynos_bo *dst,
>>> +                                       enum e_g2d_buf_type type)
>>> +{
>>> +       struct g2d_context *ctx;
>>> +       struct g2d_image src_img, dst_img;
>>> +       unsigned int count;
>>> +       unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
>>> +       unsigned long userptr, size;
>>> +       int ret;
>>> +
>>> +       ctx = g2d_init(dev->fd);
>>> +       if (!ctx)
>>> +               return -EFAULT;
>>> +
>>> +       memset(&src_img, 0, sizeof(struct g2d_image));
>>> +       memset(&dst_img, 0, sizeof(struct g2d_image));
>>> +       dst_img.bo[0] = dst->handle;
>>> +
>>> +       src_x = 0;
>>> +       src_y = 0;
>>> +       dst_x = 0;
>>> +       dst_y = 0;
>>> +       img_w = screen_width;
>>> +       img_h = screen_height;
>>> +
>>> +       switch (type) {
>>> +       case G2D_IMGBUF_GEM:
>>> +               src_img.bo[0] = src->handle;
>>> +               break;
>>> +       case G2D_IMGBUF_USERPTR:
>>> +               size = img_w * img_h * 4;
>>> +
>>> +               userptr = (unsigned long)malloc(size);
>>> +               if (!userptr) {
>>> +                       fprintf(stderr, "failed to allocate userptr.\n");
>>> +                       return -EFAULT;
>>> +               }
>>> +
>>> +               src_img.user_ptr[0].userptr = userptr;
>>> +               src_img.user_ptr[0].size = size;
>>> +               break;
>>> +       default:
>>> +               type = G2D_IMGBUF_GEM;
>>> +               break;
>>> +       }
>>> +
>>> +       printf("copy and scale test with %s.\n",
>>> +                       type == G2D_IMGBUF_GEM ? "gem" : "userptr");
>>> +
>>> +       src_img.width = img_w;
>>> +       src_img.height = img_h;
>>> +       src_img.stride = src_img.width * 4;
>>> +       src_img.buf_type = type;
>>> +       src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
>>> +       src_img.color = 0xffffffff;
>>> +       ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w ,  img_h);
>>> +       if (ret < 0)
>>> +               goto err_free_userptr;
>>> +
>>> +       src_img.color = 0xff00ff00;
>>> +       ret = g2d_solid_fill(ctx, &src_img, 5, 5, 100, 100);
>>> +       if (ret < 0)
>>> +               goto err_free_userptr;
>>> +
>>> +       dst_img.width = img_w;
>>> +       dst_img.height = img_h;
>>> +       dst_img.buf_type = G2D_IMGBUF_GEM;
>>> +       dst_img.stride = dst_img.width * 4;
>>> +       dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
>>> +
>>> +       ret = g2d_copy_with_scale(ctx, &src_img, &dst_img, 5, 5, 100, 100,
>>> +                                       100, 100, 200, 200, 0);
>>> +       if (ret < 0)
>>> +               goto err_free_userptr;
>>> +
>>> +       g2d_exec(ctx);
>>> +
>>> +err_free_userptr:
>>> +       if (type == G2D_IMGBUF_USERPTR)
>>> +               if (userptr)
>>> +                       free((void *)userptr);
>>> +
>>> +       g2d_fini(ctx);
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static int g2d_blend_test(struct exynos_device *dev,
>>> +                                       struct exynos_bo *src,
>>> +                                       struct exynos_bo *dst,
>>> +                                       enum e_g2d_buf_type type)
>>> +{
>>> +       struct g2d_context *ctx;
>>> +       struct g2d_image src_img, dst_img;
>>> +       unsigned int count;
>>> +       unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
>>> +       unsigned long userptr, size;
>>> +       int ret;
>>> +
>>> +       ctx = g2d_init(dev->fd);
>>> +       if (!ctx)
>>> +               return -EFAULT;
>>> +
>>> +       memset(&src_img, 0, sizeof(struct g2d_image));
>>> +       memset(&dst_img, 0, sizeof(struct g2d_image));
>>> +       dst_img.bo[0] = dst->handle;
>>> +
>>> +       src_x = 0;
>>> +       src_y = 0;
>>> +       dst_x = 0;
>>> +       dst_y = 0;
>>> +       img_w = screen_width;
>>> +       img_h = screen_height;
>>> +
>>> +       switch (type) {
>>> +       case G2D_IMGBUF_GEM:
>>> +               src_img.bo[0] = src->handle;
>>> +               break;
>>> +       case G2D_IMGBUF_USERPTR:
>>> +               size = img_w * img_h * 4;
>>> +
>>> +               userptr = (unsigned long)malloc(size);
>>> +               if (!userptr) {
>>> +                       fprintf(stderr, "failed to allocate userptr.\n");
>>> +                       return -EFAULT;
>>> +               }
>>> +
>>> +               src_img.user_ptr[0].userptr = userptr;
>>> +               src_img.user_ptr[0].size = size;
>>> +               break;
>>> +       default:
>>> +               type = G2D_IMGBUF_GEM;
>>> +               break;
>>> +       }
>>> +
>>> +       printf("blend test with %s.\n",
>>> +                       type == G2D_IMGBUF_GEM ? "gem" : "userptr");
>>> +
>>> +       src_img.width = img_w;
>>> +       src_img.height = img_h;
>>> +       src_img.stride = src_img.width * 4;
>>> +       src_img.buf_type = type;
>>> +       src_img.select_mode = G2D_SELECT_MODE_NORMAL;
>>> +       src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
>>> +       src_img.color = 0xffffffff;
>>> +       ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h);
>>> +       if (ret < 0)
>>> +               goto err_free_userptr;
>>> +
>>> +       src_img.color = 0x770000ff;
>>> +       ret = g2d_solid_fill(ctx, &src_img, 5, 5, 200, 200);
>>> +       if (ret < 0)
>>> +               goto err_free_userptr;
>>> +
>>> +       dst_img.width = img_w;
>>> +       dst_img.height = img_h;
>>> +       dst_img.stride = dst_img.width * 4;
>>> +       dst_img.buf_type = G2D_IMGBUF_GEM;
>>> +       dst_img.select_mode = G2D_SELECT_MODE_NORMAL;
>>> +       dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
>>> +       dst_img.color = 0xffffffff;
>>> +       ret = g2d_solid_fill(ctx, &dst_img, dst_x, dst_y, img_w, img_h);
>>> +       if (ret < 0)
>>> +               goto err_free_userptr;
>>> +
>>> +       dst_img.color = 0x77ff0000;
>>> +       ret = g2d_solid_fill(ctx, &dst_img, 105, 105, 200, 200);
>>> +       if (ret < 0)
>>> +               goto err_free_userptr;
>>> +
>>> +       ret = g2d_blend(ctx, &src_img, &dst_img, 5, 5, 105, 105, 200, 200,
>>> +                       G2D_OP_OVER);
>>> +       if (ret < 0)
>>> +               goto err_free_userptr;
>>> +
>>> +       g2d_exec(ctx);
>>> +
>>> +err_free_userptr:
>>> +       if (type == G2D_IMGBUF_USERPTR)
>>> +               if (userptr)
>>> +                       free((void *)userptr);
>>> +
>>> +       g2d_fini(ctx);
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static struct fimg2d_test_case test_case = {
>>> +       .solid_fill = &g2d_solid_fill_test,
>>> +       .copy = &g2d_copy_test,
>>> +       .copy_with_scale = &g2d_copy_with_scale_test,
>>> +       .blend = &g2d_blend_test,
>>> +};
>>> +
>>> +static void usage(char *name)
>>> +{
>>> +       fprintf(stderr, "usage: %s [-s]\n", name);
>>> +       fprintf(stderr, "-s <connector_id>@<crtc_id>:<mode>\n");
>>> +       exit(0);
>>> +}
>>> +
>>> +extern char *optarg;
>>> +static const char optstr[] = "s:";
>>> +
>>> +int main(int argc, char **argv)
>>> +{
>>> +       struct exynos_device *dev;
>>> +       struct exynos_bo *bo, *src;
>>> +       struct connector con;
>>> +       char *modeset = NULL;
>>> +       unsigned int fb_id;
>>> +       uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
>>> +       drmModeRes *resources;
>>> +       int ret, fd, c;
>>> +
>>> +       memset(&con, 0, sizeof(struct connector));
>>> +
>>> +       if (argc != 3) {
>>> +               usage(argv[0]);
>>> +               return -EINVAL;
>>> +       }
>>> +
>>> +       while ((c = getopt(argc, argv, optstr)) != -1) {
>>> +               switch (c) {
>>> +               case 's':
>>> +                       modeset = strdup(optarg);
>>> +                       con.crtc = -1;
>>> +                       if (sscanf(optarg, "%d:0x%64s",
>>> +                                               &con.id,
>>> +                                               con.mode_str) != 2 &&
>>> +                                       sscanf(optarg, "%d@%d:%64s",
>>> +                                               &con.id,
>>> +                                               &con.crtc,
>>> +                                               con.mode_str) != 3)
>>> +                               usage(argv[0]);
>>> +                       break;
>>> +               default:
>>> +                       usage(argv[0]);
>>> +                       return -EINVAL;
>>> +               }
>>> +       }
>>> +
>>> +       fd = drmOpen(DRM_MODULE_NAME, NULL);
>>> +       if (fd < 0) {
>>> +               fprintf(stderr, "failed to open.\n");
>>> +               return fd;
>>> +       }
>>> +
>>> +       dev = exynos_device_create(fd);
>>> +       if (!dev) {
>>> +               drmClose(dev->fd);
>>> +               return -EFAULT;
>>> +       }
>>> +
>>> +       resources = drmModeGetResources(dev->fd);
>>> +       if (!resources) {
>>> +               fprintf(stderr, "drmModeGetResources failed: %s\n",
>>> +                               strerror(errno));
>>> +               ret = -EFAULT;
>>> +               goto err_drm_close;
>>> +       }
>>> +
>>> +       connector_find_mode(dev->fd, &con, resources);
>>> +       drmModeFreeResources(resources);
>>> +
>>> +       screen_width = con.mode->hdisplay;
>>> +       screen_height = con.mode->vdisplay;
>>> +
>>> +       printf("screen width  = %d, screen height = %d\n", screen_width,
>>> +                       screen_height);
>>> +
>>> +       bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
>>> +       if (!bo) {
>>> +               ret = -EFAULT;
>>> +               goto err_drm_close;
>>> +       }
>>> +
>>> +       handles[0] = bo->handle;
>>> +       pitches[0] = screen_width * 4;
>>> +       offsets[0] = 0;
>>> +
>>> +       ret = drmModeAddFB2(dev->fd, screen_width, screen_height,
>>> +                               DRM_FORMAT_RGBA8888, handles,
>>> +                               pitches, offsets, &fb_id, 0);
>>> +       if (ret < 0)
>>> +               goto err_destroy_buffer;
>>> +
>>> +       con.plane_zpos = -1;
>>> +
>>> +       memset(bo->vaddr, 0xff, screen_width * screen_height * 4);
>>> +
>>> +       ret = drm_set_crtc(dev, &con, fb_id);
>>> +       if (ret < 0)
>>> +               goto err_rm_fb;
>>> +
>>> +       ret = test_case.solid_fill(dev, bo);
>>> +       if (ret < 0) {
>>> +               fprintf(stderr, "failed to solid fill operation.\n");
>>> +               goto err_rm_fb;
>>> +       }
>>> +
>>> +       getchar();
>>> +
>>> +       src = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
>>> +       if (!src) {
>>> +               ret = -EFAULT;
>>> +               goto err_rm_fb;
>>> +       }
>>> +
>>> +       ret = test_case.copy(dev, src, bo, G2D_IMGBUF_GEM);
>>> +       if (ret < 0) {
>>> +               fprintf(stderr, "failed to test copy operation.\n");
>>> +               goto err_free_src;
>>> +       }
>>> +
>>> +       getchar();
>>> +
>>> +       ret = test_case.copy_with_scale(dev, src, bo, G2D_IMGBUF_GEM);
>>> +       if (ret < 0) {
>>> +               fprintf(stderr, "failed to test copy and scale operation.\n");
>>> +               goto err_free_src;
>>> +       }
>>> +
>>> +       getchar();
>>> +
>>> +       ret  = test_case.blend(dev, src, bo, G2D_IMGBUF_USERPTR);
>>> +       if (ret < 0)
>>> +               fprintf(stderr, "failed to test blend operation.\n");
>>> +
>>> +       getchar();
>>> +
>>> +err_free_src:
>>> +       if (src)
>>> +               exynos_destroy_buffer(src);
>>> +
>>> +err_rm_fb:
>>> +       drmModeRmFB(fb_id, bo->handle);
>>> +
>>> +err_destroy_buffer:
>>> +       exynos_destroy_buffer(bo);
>>> +
>>> +err_drm_close:
>>> +       drmClose(dev->fd);
>>> +       exynos_device_destroy(dev);
>>> +
>>> +       return 0;
>>> +}
>>> --
>>> 1.7.4.1
>>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel


More information about the dri-devel mailing list