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