exynos_fimg2d.c revision e88f27b3
1e88f27b3Smrg/* 2e88f27b3Smrg * Copyright (C) 2013 Samsung Electronics Co.Ltd 3e88f27b3Smrg * Authors: 4e88f27b3Smrg * Inki Dae <inki.dae@samsung.com> 5e88f27b3Smrg * 6e88f27b3Smrg * This program is free software; you can redistribute it and/or modify it 7e88f27b3Smrg * under the terms of the GNU General Public License as published by the 8e88f27b3Smrg * Free Software Foundation; either version 2 of the License, or (at your 9e88f27b3Smrg * option) any later version. 10e88f27b3Smrg * 11e88f27b3Smrg */ 12e88f27b3Smrg 13e88f27b3Smrg#ifdef HAVE_CONFIG_H 14e88f27b3Smrg#include "config.h" 15e88f27b3Smrg#endif 16e88f27b3Smrg 17e88f27b3Smrg#include <stdlib.h> 18e88f27b3Smrg#include <stdio.h> 19e88f27b3Smrg#include <string.h> 20e88f27b3Smrg#include <errno.h> 21e88f27b3Smrg 22e88f27b3Smrg#include <sys/mman.h> 23e88f27b3Smrg#include <linux/stddef.h> 24e88f27b3Smrg 25e88f27b3Smrg#include <xf86drm.h> 26e88f27b3Smrg 27e88f27b3Smrg#include "exynos_drm.h" 28e88f27b3Smrg#include "fimg2d_reg.h" 29e88f27b3Smrg#include "fimg2d.h" 30e88f27b3Smrg 31e88f27b3Smrg#define SET_BF(val, sc, si, scsa, scda, dc, di, dcsa, dcda) \ 32e88f27b3Smrg val.data.src_coeff = sc; \ 33e88f27b3Smrg val.data.inv_src_color_coeff = si; \ 34e88f27b3Smrg val.data.src_coeff_src_a = scsa; \ 35e88f27b3Smrg val.data.src_coeff_dst_a = scda; \ 36e88f27b3Smrg val.data.dst_coeff = dc; \ 37e88f27b3Smrg val.data.inv_dst_color_coeff = di; \ 38e88f27b3Smrg val.data.dst_coeff_src_a = dcsa; \ 39e88f27b3Smrg val.data.dst_coeff_dst_a = dcda; 40e88f27b3Smrg 41e88f27b3Smrg#define MIN(a, b) ((a) < (b) ? (a) : (b)) 42e88f27b3Smrg 43e88f27b3Smrgstatic unsigned int g2d_get_blend_op(enum e_g2d_op op) 44e88f27b3Smrg{ 45e88f27b3Smrg union g2d_blend_func_val val; 46e88f27b3Smrg 47e88f27b3Smrg val.val = 0; 48e88f27b3Smrg 49e88f27b3Smrg switch (op) { 50e88f27b3Smrg case G2D_OP_CLEAR: 51e88f27b3Smrg case G2D_OP_DISJOINT_CLEAR: 52e88f27b3Smrg case G2D_OP_CONJOINT_CLEAR: 53e88f27b3Smrg SET_BF(val, G2D_COEFF_MODE_ZERO, 0, 0, 0, G2D_COEFF_MODE_ZERO, 54e88f27b3Smrg 0, 0, 0); 55e88f27b3Smrg break; 56e88f27b3Smrg case G2D_OP_SRC: 57e88f27b3Smrg case G2D_OP_DISJOINT_SRC: 58e88f27b3Smrg case G2D_OP_CONJOINT_SRC: 59e88f27b3Smrg SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, G2D_COEFF_MODE_ZERO, 60e88f27b3Smrg 0, 0, 0); 61e88f27b3Smrg break; 62e88f27b3Smrg case G2D_OP_DST: 63e88f27b3Smrg case G2D_OP_DISJOINT_DST: 64e88f27b3Smrg case G2D_OP_CONJOINT_DST: 65e88f27b3Smrg SET_BF(val, G2D_COEFF_MODE_ZERO, 0, 0, 0, G2D_COEFF_MODE_ONE, 66e88f27b3Smrg 0, 0, 0); 67e88f27b3Smrg break; 68e88f27b3Smrg case G2D_OP_OVER: 69e88f27b3Smrg SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, 70e88f27b3Smrg G2D_COEFF_MODE_SRC_ALPHA, 1, 0, 0); 71e88f27b3Smrg break; 72e88f27b3Smrg default: 73e88f27b3Smrg fprintf(stderr, "Not support operation(%d).\n", op); 74e88f27b3Smrg SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, G2D_COEFF_MODE_ZERO, 75e88f27b3Smrg 0, 0, 0); 76e88f27b3Smrg break; 77e88f27b3Smrg } 78e88f27b3Smrg 79e88f27b3Smrg return val.val; 80e88f27b3Smrg} 81e88f27b3Smrg 82e88f27b3Smrg/* 83e88f27b3Smrg * g2d_add_cmd - set given command and value to user side command buffer. 84e88f27b3Smrg * 85e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 86e88f27b3Smrg * @cmd: command data. 87e88f27b3Smrg * @value: value data. 88e88f27b3Smrg */ 89e88f27b3Smrgstatic int g2d_add_cmd(struct g2d_context *ctx, unsigned long cmd, 90e88f27b3Smrg unsigned long value) 91e88f27b3Smrg{ 92e88f27b3Smrg switch (cmd & ~(G2D_BUF_USERPTR)) { 93e88f27b3Smrg case SRC_BASE_ADDR_REG: 94e88f27b3Smrg case SRC_PLANE2_BASE_ADDR_REG: 95e88f27b3Smrg case DST_BASE_ADDR_REG: 96e88f27b3Smrg case DST_PLANE2_BASE_ADDR_REG: 97e88f27b3Smrg case PAT_BASE_ADDR_REG: 98e88f27b3Smrg case MASK_BASE_ADDR_REG: 99e88f27b3Smrg if (ctx->cmd_buf_nr >= G2D_MAX_GEM_CMD_NR) { 100e88f27b3Smrg fprintf(stderr, "Overflow cmd_gem size.\n"); 101e88f27b3Smrg return -EINVAL; 102e88f27b3Smrg } 103e88f27b3Smrg 104e88f27b3Smrg ctx->cmd_buf[ctx->cmd_buf_nr].offset = cmd; 105e88f27b3Smrg ctx->cmd_buf[ctx->cmd_buf_nr].data = value; 106e88f27b3Smrg ctx->cmd_buf_nr++; 107e88f27b3Smrg break; 108e88f27b3Smrg default: 109e88f27b3Smrg if (ctx->cmd_nr >= G2D_MAX_CMD_NR) { 110e88f27b3Smrg fprintf(stderr, "Overflow cmd size.\n"); 111e88f27b3Smrg return -EINVAL; 112e88f27b3Smrg } 113e88f27b3Smrg 114e88f27b3Smrg ctx->cmd[ctx->cmd_nr].offset = cmd; 115e88f27b3Smrg ctx->cmd[ctx->cmd_nr].data = value; 116e88f27b3Smrg ctx->cmd_nr++; 117e88f27b3Smrg break; 118e88f27b3Smrg } 119e88f27b3Smrg 120e88f27b3Smrg return TRUE; 121e88f27b3Smrg} 122e88f27b3Smrg 123e88f27b3Smrg/* 124e88f27b3Smrg * g2d_reset - reset fimg2d hardware. 125e88f27b3Smrg * 126e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 127e88f27b3Smrg * 128e88f27b3Smrg */ 129e88f27b3Smrgstatic void g2d_reset(struct g2d_context *ctx) 130e88f27b3Smrg{ 131e88f27b3Smrg ctx->cmd_nr = 0; 132e88f27b3Smrg ctx->cmd_buf_nr = 0; 133e88f27b3Smrg 134e88f27b3Smrg g2d_add_cmd(ctx, SOFT_RESET_REG, 0x01); 135e88f27b3Smrg} 136e88f27b3Smrg 137e88f27b3Smrg/* 138e88f27b3Smrg * g2d_flush - summit all commands and values in user side command buffer 139e88f27b3Smrg * to command queue aware of fimg2d dma. 140e88f27b3Smrg * 141e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 142e88f27b3Smrg * 143e88f27b3Smrg * This function should be called after all commands and values to user 144e88f27b3Smrg * side command buffer is set to summit that buffer to kernel side driver. 145e88f27b3Smrg */ 146e88f27b3Smrgstatic int g2d_flush(struct g2d_context *ctx) 147e88f27b3Smrg{ 148e88f27b3Smrg int ret; 149e88f27b3Smrg struct drm_exynos_g2d_set_cmdlist cmdlist; 150e88f27b3Smrg 151e88f27b3Smrg if (ctx->cmd_nr == 0 && ctx->cmd_buf_nr == 0) 152e88f27b3Smrg return FALSE; 153e88f27b3Smrg 154e88f27b3Smrg if (ctx->cmdlist_nr >= G2D_MAX_CMD_LIST_NR) { 155e88f27b3Smrg fprintf(stderr, "Overflow cmdlist.\n"); 156e88f27b3Smrg return -EINVAL; 157e88f27b3Smrg } 158e88f27b3Smrg 159e88f27b3Smrg memset(&cmdlist, 0, sizeof(struct drm_exynos_g2d_set_cmdlist)); 160e88f27b3Smrg 161e88f27b3Smrg cmdlist.cmd = (unsigned int)&ctx->cmd[0]; 162e88f27b3Smrg cmdlist.cmd_buf = (unsigned int)&ctx->cmd_buf[0]; 163e88f27b3Smrg cmdlist.cmd_nr = ctx->cmd_nr; 164e88f27b3Smrg cmdlist.cmd_buf_nr = ctx->cmd_buf_nr; 165e88f27b3Smrg cmdlist.event_type = G2D_EVENT_NOT; 166e88f27b3Smrg cmdlist.user_data = 0; 167e88f27b3Smrg 168e88f27b3Smrg ctx->cmd_nr = 0; 169e88f27b3Smrg ctx->cmd_buf_nr = 0; 170e88f27b3Smrg 171e88f27b3Smrg ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST, &cmdlist); 172e88f27b3Smrg if (ret < 0) { 173e88f27b3Smrg fprintf(stderr, "failed to set cmdlist.\n"); 174e88f27b3Smrg return ret; 175e88f27b3Smrg } 176e88f27b3Smrg 177e88f27b3Smrg ctx->cmdlist_nr++; 178e88f27b3Smrg 179e88f27b3Smrg return ret; 180e88f27b3Smrg} 181e88f27b3Smrg 182e88f27b3Smrg/** 183e88f27b3Smrg * g2d_init - create a new g2d context and get hardware version. 184e88f27b3Smrg * 185e88f27b3Smrg * fd: a file descriptor to drm device driver opened. 186e88f27b3Smrg */ 187e88f27b3Smrgstruct g2d_context *g2d_init(int fd) 188e88f27b3Smrg{ 189e88f27b3Smrg struct drm_exynos_g2d_get_ver ver; 190e88f27b3Smrg struct g2d_context *ctx; 191e88f27b3Smrg int ret; 192e88f27b3Smrg 193e88f27b3Smrg ctx = calloc(1, sizeof(*ctx)); 194e88f27b3Smrg if (!ctx) { 195e88f27b3Smrg fprintf(stderr, "failed to allocate context.\n"); 196e88f27b3Smrg return NULL; 197e88f27b3Smrg } 198e88f27b3Smrg 199e88f27b3Smrg ctx->fd = fd; 200e88f27b3Smrg 201e88f27b3Smrg ret = drmIoctl(fd, DRM_IOCTL_EXYNOS_G2D_GET_VER, &ver); 202e88f27b3Smrg if (ret < 0) { 203e88f27b3Smrg fprintf(stderr, "failed to get version.\n"); 204e88f27b3Smrg free(ctx); 205e88f27b3Smrg return NULL; 206e88f27b3Smrg } 207e88f27b3Smrg 208e88f27b3Smrg ctx->major = ver.major; 209e88f27b3Smrg ctx->minor = ver.minor; 210e88f27b3Smrg 211e88f27b3Smrg printf("g2d version(%d.%d).\n", ctx->major, ctx->minor); 212e88f27b3Smrg return ctx; 213e88f27b3Smrg} 214e88f27b3Smrg 215e88f27b3Smrgvoid g2d_fini(struct g2d_context *ctx) 216e88f27b3Smrg{ 217e88f27b3Smrg if (ctx) 218e88f27b3Smrg free(ctx); 219e88f27b3Smrg} 220e88f27b3Smrg 221e88f27b3Smrg/** 222e88f27b3Smrg * g2d_exec - start the dma to process all commands summited by g2d_flush(). 223e88f27b3Smrg * 224e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 225e88f27b3Smrg */ 226e88f27b3Smrgint g2d_exec(struct g2d_context *ctx) 227e88f27b3Smrg{ 228e88f27b3Smrg struct drm_exynos_g2d_exec exec; 229e88f27b3Smrg int ret; 230e88f27b3Smrg 231e88f27b3Smrg if (ctx->cmdlist_nr == 0) 232e88f27b3Smrg return -EINVAL; 233e88f27b3Smrg 234e88f27b3Smrg exec.async = 0; 235e88f27b3Smrg 236e88f27b3Smrg ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_EXEC, &exec); 237e88f27b3Smrg if (ret < 0) { 238e88f27b3Smrg fprintf(stderr, "failed to execute.\n"); 239e88f27b3Smrg return ret; 240e88f27b3Smrg } 241e88f27b3Smrg 242e88f27b3Smrg ctx->cmdlist_nr = 0; 243e88f27b3Smrg 244e88f27b3Smrg return ret; 245e88f27b3Smrg} 246e88f27b3Smrg 247e88f27b3Smrg/** 248e88f27b3Smrg * g2d_solid_fill - fill given buffer with given color data. 249e88f27b3Smrg * 250e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 251e88f27b3Smrg * @img: a pointer to g2d_image structure including image and buffer 252e88f27b3Smrg * information. 253e88f27b3Smrg * @x: x start position to buffer filled with given color data. 254e88f27b3Smrg * @y: y start position to buffer filled with given color data. 255e88f27b3Smrg * @w: width value to buffer filled with given color data. 256e88f27b3Smrg * @h: height value to buffer filled with given color data. 257e88f27b3Smrg */ 258e88f27b3Smrgint g2d_solid_fill(struct g2d_context *ctx, struct g2d_image *img, 259e88f27b3Smrg unsigned int x, unsigned int y, unsigned int w, 260e88f27b3Smrg unsigned int h) 261e88f27b3Smrg{ 262e88f27b3Smrg union g2d_bitblt_cmd_val bitblt; 263e88f27b3Smrg union g2d_point_val pt; 264e88f27b3Smrg 265e88f27b3Smrg g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); 266e88f27b3Smrg g2d_add_cmd(ctx, DST_COLOR_MODE_REG, img->color_mode); 267e88f27b3Smrg 268e88f27b3Smrg if (img->buf_type == G2D_IMGBUF_USERPTR) 269e88f27b3Smrg g2d_add_cmd(ctx, DST_BASE_ADDR_REG | G2D_BUF_USERPTR, 270e88f27b3Smrg (unsigned long)&img->user_ptr[0]); 271e88f27b3Smrg else 272e88f27b3Smrg g2d_add_cmd(ctx, DST_BASE_ADDR_REG, img->bo[0]); 273e88f27b3Smrg 274e88f27b3Smrg g2d_add_cmd(ctx, DST_STRIDE_REG, img->stride); 275e88f27b3Smrg 276e88f27b3Smrg if (x + w > img->width) 277e88f27b3Smrg w = img->width - x; 278e88f27b3Smrg if (y + h > img->height) 279e88f27b3Smrg h = img->height - y; 280e88f27b3Smrg 281e88f27b3Smrg pt.val = 0; 282e88f27b3Smrg pt.data.x = x; 283e88f27b3Smrg pt.data.y = y; 284e88f27b3Smrg g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 285e88f27b3Smrg 286e88f27b3Smrg pt.val = 0; 287e88f27b3Smrg pt.data.x = x + w; 288e88f27b3Smrg pt.data.y = y + h; 289e88f27b3Smrg 290e88f27b3Smrg g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 291e88f27b3Smrg 292e88f27b3Smrg g2d_add_cmd(ctx, SF_COLOR_REG, img->color); 293e88f27b3Smrg 294e88f27b3Smrg bitblt.val = 0; 295e88f27b3Smrg bitblt.data.fast_solid_color_fill_en = 1; 296e88f27b3Smrg g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val); 297e88f27b3Smrg 298e88f27b3Smrg g2d_flush(ctx); 299e88f27b3Smrg 300e88f27b3Smrg return 0; 301e88f27b3Smrg} 302e88f27b3Smrg 303e88f27b3Smrg/** 304e88f27b3Smrg * g2d_copy - copy contents in source buffer to destination buffer. 305e88f27b3Smrg * 306e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 307e88f27b3Smrg * @src: a pointer to g2d_image structure including image and buffer 308e88f27b3Smrg * information to source. 309e88f27b3Smrg * @dst: a pointer to g2d_image structure including image and buffer 310e88f27b3Smrg * information to destination. 311e88f27b3Smrg * @src_x: x start position to source buffer. 312e88f27b3Smrg * @src_y: y start position to source buffer. 313e88f27b3Smrg * @dst_x: x start position to destination buffer. 314e88f27b3Smrg * @dst_y: y start position to destination buffer. 315e88f27b3Smrg * @w: width value to source and destination buffers. 316e88f27b3Smrg * @h: height value to source and destination buffers. 317e88f27b3Smrg */ 318e88f27b3Smrgint g2d_copy(struct g2d_context *ctx, struct g2d_image *src, 319e88f27b3Smrg struct g2d_image *dst, unsigned int src_x, unsigned int src_y, 320e88f27b3Smrg unsigned int dst_x, unsigned dst_y, unsigned int w, 321e88f27b3Smrg unsigned int h) 322e88f27b3Smrg{ 323e88f27b3Smrg union g2d_rop4_val rop4; 324e88f27b3Smrg union g2d_point_val pt; 325e88f27b3Smrg unsigned int src_w = 0, src_h = 0, dst_w = 0, dst_h = 0; 326e88f27b3Smrg 327e88f27b3Smrg g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); 328e88f27b3Smrg g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); 329e88f27b3Smrg if (dst->buf_type == G2D_IMGBUF_USERPTR) 330e88f27b3Smrg g2d_add_cmd(ctx, DST_BASE_ADDR_REG | G2D_BUF_USERPTR, 331e88f27b3Smrg (unsigned long)&dst->user_ptr[0]); 332e88f27b3Smrg else 333e88f27b3Smrg g2d_add_cmd(ctx, DST_BASE_ADDR_REG, dst->bo[0]); 334e88f27b3Smrg 335e88f27b3Smrg g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); 336e88f27b3Smrg 337e88f27b3Smrg g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); 338e88f27b3Smrg g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); 339e88f27b3Smrg if (src->buf_type == G2D_IMGBUF_USERPTR) 340e88f27b3Smrg g2d_add_cmd(ctx, SRC_BASE_ADDR_REG | G2D_BUF_USERPTR, 341e88f27b3Smrg (unsigned long)&src->user_ptr[0]); 342e88f27b3Smrg else 343e88f27b3Smrg g2d_add_cmd(ctx, SRC_BASE_ADDR_REG, src->bo[0]); 344e88f27b3Smrg 345e88f27b3Smrg g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); 346e88f27b3Smrg 347e88f27b3Smrg src_w = w; 348e88f27b3Smrg src_h = h; 349e88f27b3Smrg if (src_x + src->width > w) 350e88f27b3Smrg src_w = src->width - src_x; 351e88f27b3Smrg if (src_y + src->height > h) 352e88f27b3Smrg src_h = src->height - src_y; 353e88f27b3Smrg 354e88f27b3Smrg dst_w = w; 355e88f27b3Smrg dst_h = w; 356e88f27b3Smrg if (dst_x + dst->width > w) 357e88f27b3Smrg dst_w = dst->width - dst_x; 358e88f27b3Smrg if (dst_y + dst->height > h) 359e88f27b3Smrg dst_h = dst->height - dst_y; 360e88f27b3Smrg 361e88f27b3Smrg w = MIN(src_w, dst_w); 362e88f27b3Smrg h = MIN(src_h, dst_h); 363e88f27b3Smrg 364e88f27b3Smrg if (w <= 0 || h <= 0) { 365e88f27b3Smrg fprintf(stderr, "invalid width or height.\n"); 366e88f27b3Smrg g2d_reset(ctx); 367e88f27b3Smrg return -EINVAL; 368e88f27b3Smrg } 369e88f27b3Smrg 370e88f27b3Smrg pt.val = 0; 371e88f27b3Smrg pt.data.x = src_x; 372e88f27b3Smrg pt.data.y = src_y; 373e88f27b3Smrg g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); 374e88f27b3Smrg pt.val = 0; 375e88f27b3Smrg pt.data.x = src_x + w; 376e88f27b3Smrg pt.data.y = src_y + h; 377e88f27b3Smrg g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); 378e88f27b3Smrg 379e88f27b3Smrg pt.val = 0; 380e88f27b3Smrg pt.data.x = dst_x; 381e88f27b3Smrg pt.data.y = dst_y; 382e88f27b3Smrg g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 383e88f27b3Smrg pt.val = 0; 384e88f27b3Smrg pt.data.x = dst_x + w; 385e88f27b3Smrg pt.data.y = dst_x + h; 386e88f27b3Smrg g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 387e88f27b3Smrg 388e88f27b3Smrg rop4.val = 0; 389e88f27b3Smrg rop4.data.unmasked_rop3 = G2D_ROP3_SRC; 390e88f27b3Smrg g2d_add_cmd(ctx, ROP4_REG, rop4.val); 391e88f27b3Smrg 392e88f27b3Smrg g2d_flush(ctx); 393e88f27b3Smrg 394e88f27b3Smrg return 0; 395e88f27b3Smrg} 396e88f27b3Smrg 397e88f27b3Smrg/** 398e88f27b3Smrg * g2d_copy_with_scale - copy contents in source buffer to destination buffer 399e88f27b3Smrg * scaling up or down properly. 400e88f27b3Smrg * 401e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 402e88f27b3Smrg * @src: a pointer to g2d_image structure including image and buffer 403e88f27b3Smrg * information to source. 404e88f27b3Smrg * @dst: a pointer to g2d_image structure including image and buffer 405e88f27b3Smrg * information to destination. 406e88f27b3Smrg * @src_x: x start position to source buffer. 407e88f27b3Smrg * @src_y: y start position to source buffer. 408e88f27b3Smrg * @src_w: width value to source buffer. 409e88f27b3Smrg * @src_h: height value to source buffer. 410e88f27b3Smrg * @dst_x: x start position to destination buffer. 411e88f27b3Smrg * @dst_y: y start position to destination buffer. 412e88f27b3Smrg * @dst_w: width value to destination buffer. 413e88f27b3Smrg * @dst_h: height value to destination buffer. 414e88f27b3Smrg * @negative: indicate that it uses color negative to source and 415e88f27b3Smrg * destination buffers. 416e88f27b3Smrg */ 417e88f27b3Smrgint g2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src, 418e88f27b3Smrg struct g2d_image *dst, unsigned int src_x, 419e88f27b3Smrg unsigned int src_y, unsigned int src_w, 420e88f27b3Smrg unsigned int src_h, unsigned int dst_x, 421e88f27b3Smrg unsigned int dst_y, unsigned int dst_w, 422e88f27b3Smrg unsigned int dst_h, unsigned int negative) 423e88f27b3Smrg{ 424e88f27b3Smrg union g2d_rop4_val rop4; 425e88f27b3Smrg union g2d_point_val pt; 426e88f27b3Smrg unsigned int scale; 427e88f27b3Smrg double scale_x = 0.0f, scale_y = 0.0f; 428e88f27b3Smrg 429e88f27b3Smrg g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); 430e88f27b3Smrg g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); 431e88f27b3Smrg if (dst->buf_type == G2D_IMGBUF_USERPTR) 432e88f27b3Smrg g2d_add_cmd(ctx, DST_BASE_ADDR_REG | G2D_BUF_USERPTR, 433e88f27b3Smrg (unsigned long)&dst->user_ptr[0]); 434e88f27b3Smrg else 435e88f27b3Smrg g2d_add_cmd(ctx, DST_BASE_ADDR_REG, dst->bo[0]); 436e88f27b3Smrg 437e88f27b3Smrg g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); 438e88f27b3Smrg 439e88f27b3Smrg g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); 440e88f27b3Smrg g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); 441e88f27b3Smrg if (src->buf_type == G2D_IMGBUF_USERPTR) 442e88f27b3Smrg g2d_add_cmd(ctx, SRC_BASE_ADDR_REG | G2D_BUF_USERPTR, 443e88f27b3Smrg (unsigned long)&src->user_ptr[0]); 444e88f27b3Smrg else 445e88f27b3Smrg g2d_add_cmd(ctx, SRC_BASE_ADDR_REG, src->bo[0]); 446e88f27b3Smrg 447e88f27b3Smrg g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); 448e88f27b3Smrg 449e88f27b3Smrg if (src_w == dst_w && src_h == dst_h) 450e88f27b3Smrg scale = 0; 451e88f27b3Smrg else { 452e88f27b3Smrg scale = 1; 453e88f27b3Smrg scale_x = (double)src_w / (double)dst_w; 454e88f27b3Smrg scale_y = (double)src_w / (double)dst_h; 455e88f27b3Smrg } 456e88f27b3Smrg 457e88f27b3Smrg if (src_x + src_w > src->width) 458e88f27b3Smrg src_w = src->width - src_x; 459e88f27b3Smrg if (src_y + src_h > src->height) 460e88f27b3Smrg src_h = src->height - src_y; 461e88f27b3Smrg 462e88f27b3Smrg if (dst_x + dst_w > dst->width) 463e88f27b3Smrg dst_w = dst->width - dst_x; 464e88f27b3Smrg if (dst_y + dst_h > dst->height) 465e88f27b3Smrg dst_h = dst->height - dst_y; 466e88f27b3Smrg 467e88f27b3Smrg if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) { 468e88f27b3Smrg fprintf(stderr, "invalid width or height.\n"); 469e88f27b3Smrg g2d_reset(ctx); 470e88f27b3Smrg return -EINVAL; 471e88f27b3Smrg } 472e88f27b3Smrg 473e88f27b3Smrg if (negative) { 474e88f27b3Smrg g2d_add_cmd(ctx, BG_COLOR_REG, 0x00FFFFFF); 475e88f27b3Smrg rop4.val = 0; 476e88f27b3Smrg rop4.data.unmasked_rop3 = G2D_ROP3_SRC^G2D_ROP3_DST; 477e88f27b3Smrg g2d_add_cmd(ctx, ROP4_REG, rop4.val); 478e88f27b3Smrg } else { 479e88f27b3Smrg rop4.val = 0; 480e88f27b3Smrg rop4.data.unmasked_rop3 = G2D_ROP3_SRC; 481e88f27b3Smrg g2d_add_cmd(ctx, ROP4_REG, rop4.val); 482e88f27b3Smrg } 483e88f27b3Smrg 484e88f27b3Smrg if (scale) { 485e88f27b3Smrg g2d_add_cmd(ctx, SRC_SCALE_CTRL_REG, G2D_SCALE_MODE_BILINEAR); 486e88f27b3Smrg g2d_add_cmd(ctx, SRC_XSCALE_REG, G2D_DOUBLE_TO_FIXED(scale_x)); 487e88f27b3Smrg g2d_add_cmd(ctx, SRC_YSCALE_REG, G2D_DOUBLE_TO_FIXED(scale_y)); 488e88f27b3Smrg } 489e88f27b3Smrg 490e88f27b3Smrg pt.val = 0; 491e88f27b3Smrg pt.data.x = src_x; 492e88f27b3Smrg pt.data.y = src_y; 493e88f27b3Smrg g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); 494e88f27b3Smrg pt.val = 0; 495e88f27b3Smrg pt.data.x = src_x + src_w; 496e88f27b3Smrg pt.data.y = src_y + src_h; 497e88f27b3Smrg g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); 498e88f27b3Smrg 499e88f27b3Smrg pt.val = 0; 500e88f27b3Smrg pt.data.x = dst_x; 501e88f27b3Smrg pt.data.y = dst_y; 502e88f27b3Smrg g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 503e88f27b3Smrg pt.val = 0; 504e88f27b3Smrg pt.data.x = dst_x + dst_w; 505e88f27b3Smrg pt.data.y = dst_y + dst_h; 506e88f27b3Smrg g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 507e88f27b3Smrg 508e88f27b3Smrg g2d_flush(ctx); 509e88f27b3Smrg 510e88f27b3Smrg return 0; 511e88f27b3Smrg} 512e88f27b3Smrg 513e88f27b3Smrg/** 514e88f27b3Smrg * g2d_blend - blend image data in source and destion buffers 515e88f27b3Smrg * 516e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 517e88f27b3Smrg * @src: a pointer to g2d_image structure including image and buffer 518e88f27b3Smrg * information to source. 519e88f27b3Smrg * @dst: a pointer to g2d_image structure including image and buffer 520e88f27b3Smrg * information to destination. 521e88f27b3Smrg * @src_x: x start position to source buffer. 522e88f27b3Smrg * @src_y: y start position to source buffer. 523e88f27b3Smrg * @dst_x: x start position to destination buffer. 524e88f27b3Smrg * @dst_y: y start position to destination buffer. 525e88f27b3Smrg * @w: width value to source and destination buffer. 526e88f27b3Smrg * @h: height value to source and destination buffer. 527e88f27b3Smrg * @op: blend operation type. 528e88f27b3Smrg */ 529e88f27b3Smrgint g2d_blend(struct g2d_context *ctx, struct g2d_image *src, 530e88f27b3Smrg struct g2d_image *dst, unsigned int src_x, 531e88f27b3Smrg unsigned int src_y, unsigned int dst_x, unsigned int dst_y, 532e88f27b3Smrg unsigned int w, unsigned int h, enum e_g2d_op op) 533e88f27b3Smrg{ 534e88f27b3Smrg union g2d_point_val pt; 535e88f27b3Smrg union g2d_bitblt_cmd_val bitblt; 536e88f27b3Smrg union g2d_blend_func_val blend; 537e88f27b3Smrg unsigned int src_w = 0, src_h = 0, dst_w = 0, dst_h = 0; 538e88f27b3Smrg 539e88f27b3Smrg bitblt.val = 0; 540e88f27b3Smrg blend.val = 0; 541e88f27b3Smrg 542e88f27b3Smrg if (op == G2D_OP_SRC || op == G2D_OP_CLEAR) 543e88f27b3Smrg g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); 544e88f27b3Smrg else 545e88f27b3Smrg g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); 546e88f27b3Smrg 547e88f27b3Smrg g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); 548e88f27b3Smrg if (dst->buf_type == G2D_IMGBUF_USERPTR) 549e88f27b3Smrg g2d_add_cmd(ctx, DST_BASE_ADDR_REG | G2D_BUF_USERPTR, 550e88f27b3Smrg (unsigned long)&dst->user_ptr[0]); 551e88f27b3Smrg else 552e88f27b3Smrg g2d_add_cmd(ctx, DST_BASE_ADDR_REG, dst->bo[0]); 553e88f27b3Smrg 554e88f27b3Smrg g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); 555e88f27b3Smrg 556e88f27b3Smrg g2d_add_cmd(ctx, SRC_SELECT_REG, src->select_mode); 557e88f27b3Smrg g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); 558e88f27b3Smrg 559e88f27b3Smrg switch (src->select_mode) { 560e88f27b3Smrg case G2D_SELECT_MODE_NORMAL: 561e88f27b3Smrg if (src->buf_type == G2D_IMGBUF_USERPTR) 562e88f27b3Smrg g2d_add_cmd(ctx, SRC_BASE_ADDR_REG | G2D_BUF_USERPTR, 563e88f27b3Smrg (unsigned long)&src->user_ptr[0]); 564e88f27b3Smrg else 565e88f27b3Smrg g2d_add_cmd(ctx, SRC_BASE_ADDR_REG, src->bo[0]); 566e88f27b3Smrg 567e88f27b3Smrg g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); 568e88f27b3Smrg break; 569e88f27b3Smrg case G2D_SELECT_MODE_FGCOLOR: 570e88f27b3Smrg g2d_add_cmd(ctx, FG_COLOR_REG, src->color); 571e88f27b3Smrg break; 572e88f27b3Smrg case G2D_SELECT_MODE_BGCOLOR: 573e88f27b3Smrg g2d_add_cmd(ctx, BG_COLOR_REG, src->color); 574e88f27b3Smrg break; 575e88f27b3Smrg default: 576e88f27b3Smrg fprintf(stderr , "failed to set src.\n"); 577e88f27b3Smrg return -EINVAL; 578e88f27b3Smrg } 579e88f27b3Smrg 580e88f27b3Smrg src_w = w; 581e88f27b3Smrg src_h = h; 582e88f27b3Smrg if (src_x + w > src->width) 583e88f27b3Smrg src_w = src->width - src_x; 584e88f27b3Smrg if (src_y + h > src->height) 585e88f27b3Smrg src_h = src->height - src_y; 586e88f27b3Smrg 587e88f27b3Smrg dst_w = w; 588e88f27b3Smrg dst_h = h; 589e88f27b3Smrg if (dst_x + w > dst->width) 590e88f27b3Smrg dst_w = dst->width - dst_x; 591e88f27b3Smrg if (dst_y + h > dst->height) 592e88f27b3Smrg dst_h = dst->height - dst_y; 593e88f27b3Smrg 594e88f27b3Smrg w = MIN(src_w, dst_w); 595e88f27b3Smrg h = MIN(src_h, dst_h); 596e88f27b3Smrg 597e88f27b3Smrg if (w <= 0 || h <= 0) { 598e88f27b3Smrg fprintf(stderr, "invalid width or height.\n"); 599e88f27b3Smrg g2d_reset(ctx); 600e88f27b3Smrg return -EINVAL; 601e88f27b3Smrg } 602e88f27b3Smrg 603e88f27b3Smrg bitblt.data.alpha_blend_mode = G2D_ALPHA_BLEND_MODE_ENABLE; 604e88f27b3Smrg blend.val = g2d_get_blend_op(op); 605e88f27b3Smrg g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val); 606e88f27b3Smrg g2d_add_cmd(ctx, BLEND_FUNCTION_REG, blend.val); 607e88f27b3Smrg 608e88f27b3Smrg pt.val = 0; 609e88f27b3Smrg pt.data.x = src_x; 610e88f27b3Smrg pt.data.y = src_y; 611e88f27b3Smrg g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); 612e88f27b3Smrg pt.val = 0; 613e88f27b3Smrg pt.data.x = src_x + w; 614e88f27b3Smrg pt.data.y = src_y + h; 615e88f27b3Smrg g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); 616e88f27b3Smrg 617e88f27b3Smrg pt.val = 0; 618e88f27b3Smrg pt.data.x = dst_x; 619e88f27b3Smrg pt.data.y = dst_y; 620e88f27b3Smrg g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 621e88f27b3Smrg pt.val = 0; 622e88f27b3Smrg pt.data.x = dst_x + w; 623e88f27b3Smrg pt.data.y = dst_y + h; 624e88f27b3Smrg g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 625e88f27b3Smrg 626e88f27b3Smrg g2d_flush(ctx); 627e88f27b3Smrg 628e88f27b3Smrg return 0; 629e88f27b3Smrg} 630e88f27b3Smrg 631