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