exynos_fimg2d.c revision 3f012e29
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> 213f012e29Smrg#include <assert.h> 22e88f27b3Smrg 23e88f27b3Smrg#include <sys/mman.h> 24e88f27b3Smrg#include <linux/stddef.h> 25e88f27b3Smrg 26e88f27b3Smrg#include <xf86drm.h> 27e88f27b3Smrg 28e6188e58Smrg#include "libdrm_macros.h" 29e88f27b3Smrg#include "exynos_drm.h" 30e88f27b3Smrg#include "fimg2d_reg.h" 31e6188e58Smrg#include "exynos_fimg2d.h" 32e88f27b3Smrg 33e88f27b3Smrg#define SET_BF(val, sc, si, scsa, scda, dc, di, dcsa, dcda) \ 34e88f27b3Smrg val.data.src_coeff = sc; \ 35e88f27b3Smrg val.data.inv_src_color_coeff = si; \ 36e88f27b3Smrg val.data.src_coeff_src_a = scsa; \ 37e88f27b3Smrg val.data.src_coeff_dst_a = scda; \ 38e88f27b3Smrg val.data.dst_coeff = dc; \ 39e88f27b3Smrg val.data.inv_dst_color_coeff = di; \ 40e88f27b3Smrg val.data.dst_coeff_src_a = dcsa; \ 41e88f27b3Smrg val.data.dst_coeff_dst_a = dcda; 42e88f27b3Smrg 43e88f27b3Smrg#define MIN(a, b) ((a) < (b) ? (a) : (b)) 44e88f27b3Smrg 453f012e29Smrg#define MSG_PREFIX "exynos/fimg2d: " 463f012e29Smrg 473f012e29Smrg#define G2D_MAX_CMD_NR 64 483f012e29Smrg#define G2D_MAX_GEM_CMD_NR 64 493f012e29Smrg#define G2D_MAX_CMD_LIST_NR 64 503f012e29Smrg 513f012e29Smrgstruct g2d_context { 523f012e29Smrg int fd; 533f012e29Smrg unsigned int major; 543f012e29Smrg unsigned int minor; 553f012e29Smrg struct drm_exynos_g2d_cmd cmd[G2D_MAX_CMD_NR]; 563f012e29Smrg struct drm_exynos_g2d_cmd cmd_buf[G2D_MAX_GEM_CMD_NR]; 573f012e29Smrg unsigned int cmd_nr; 583f012e29Smrg unsigned int cmd_buf_nr; 593f012e29Smrg unsigned int cmdlist_nr; 603f012e29Smrg void *event_userdata; 613f012e29Smrg}; 623f012e29Smrg 63e6188e58Smrgenum g2d_base_addr_reg { 64e6188e58Smrg g2d_dst = 0, 65e6188e58Smrg g2d_src 66e6188e58Smrg}; 67e6188e58Smrg 683f012e29Smrgenum e_g2d_dir_mode { 693f012e29Smrg G2D_DIR_MODE_POSITIVE = 0, 703f012e29Smrg G2D_DIR_MODE_NEGATIVE = 1 713f012e29Smrg}; 723f012e29Smrg 733f012e29Smrgunion g2d_direction_val { 743f012e29Smrg unsigned int val[2]; 753f012e29Smrg struct { 763f012e29Smrg /* SRC_MSK_DIRECT_REG [0:1] (source) */ 773f012e29Smrg enum e_g2d_dir_mode src_x_direction:1; 783f012e29Smrg enum e_g2d_dir_mode src_y_direction:1; 793f012e29Smrg 803f012e29Smrg /* SRC_MSK_DIRECT_REG [2:3] */ 813f012e29Smrg unsigned int reversed1:2; 823f012e29Smrg 833f012e29Smrg /* SRC_MSK_DIRECT_REG [4:5] (mask) */ 843f012e29Smrg enum e_g2d_dir_mode mask_x_direction:1; 853f012e29Smrg enum e_g2d_dir_mode mask_y_direction:1; 863f012e29Smrg 873f012e29Smrg /* SRC_MSK_DIRECT_REG [6:31] */ 883f012e29Smrg unsigned int padding1:26; 893f012e29Smrg 903f012e29Smrg /* DST_PAT_DIRECT_REG [0:1] (destination) */ 913f012e29Smrg enum e_g2d_dir_mode dst_x_direction:1; 923f012e29Smrg enum e_g2d_dir_mode dst_y_direction:1; 933f012e29Smrg 943f012e29Smrg /* DST_PAT_DIRECT_REG [2:3] */ 953f012e29Smrg unsigned int reversed2:2; 963f012e29Smrg 973f012e29Smrg /* DST_PAT_DIRECT_REG [4:5] (pattern) */ 983f012e29Smrg enum e_g2d_dir_mode pat_x_direction:1; 993f012e29Smrg enum e_g2d_dir_mode pat_y_direction:1; 1003f012e29Smrg 1013f012e29Smrg /* DST_PAT_DIRECT_REG [6:31] */ 1023f012e29Smrg unsigned int padding2:26; 1033f012e29Smrg } data; 1043f012e29Smrg}; 1053f012e29Smrg 106e6188e58Smrgstatic unsigned int g2d_get_scaling(unsigned int src, unsigned int dst) 107e6188e58Smrg{ 108e6188e58Smrg /* 109e6188e58Smrg * The G2D hw scaling factor is a normalized inverse of the scaling factor. 110e6188e58Smrg * For example: When source width is 100 and destination width is 200 111e6188e58Smrg * (scaling of 2x), then the hw factor is NC * 100 / 200. 112e6188e58Smrg * The normalization factor (NC) is 2^16 = 0x10000. 113e6188e58Smrg */ 114e6188e58Smrg 115e6188e58Smrg return ((src << 16) / dst); 116e6188e58Smrg} 117e6188e58Smrg 118e88f27b3Smrgstatic unsigned int g2d_get_blend_op(enum e_g2d_op op) 119e88f27b3Smrg{ 120e88f27b3Smrg union g2d_blend_func_val val; 121e88f27b3Smrg 122e88f27b3Smrg val.val = 0; 123e88f27b3Smrg 1243f012e29Smrg /* 1253f012e29Smrg * The switch statement is missing the default branch since 1263f012e29Smrg * we assume that the caller checks the blending operation 1273f012e29Smrg * via g2d_validate_blending_op() first. 1283f012e29Smrg */ 129e88f27b3Smrg switch (op) { 130e88f27b3Smrg case G2D_OP_CLEAR: 131e88f27b3Smrg case G2D_OP_DISJOINT_CLEAR: 132e88f27b3Smrg case G2D_OP_CONJOINT_CLEAR: 133e88f27b3Smrg SET_BF(val, G2D_COEFF_MODE_ZERO, 0, 0, 0, G2D_COEFF_MODE_ZERO, 134e88f27b3Smrg 0, 0, 0); 135e88f27b3Smrg break; 136e88f27b3Smrg case G2D_OP_SRC: 137e88f27b3Smrg case G2D_OP_DISJOINT_SRC: 138e88f27b3Smrg case G2D_OP_CONJOINT_SRC: 139e88f27b3Smrg SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, G2D_COEFF_MODE_ZERO, 140e88f27b3Smrg 0, 0, 0); 141e88f27b3Smrg break; 142e88f27b3Smrg case G2D_OP_DST: 143e88f27b3Smrg case G2D_OP_DISJOINT_DST: 144e88f27b3Smrg case G2D_OP_CONJOINT_DST: 145e88f27b3Smrg SET_BF(val, G2D_COEFF_MODE_ZERO, 0, 0, 0, G2D_COEFF_MODE_ONE, 146e88f27b3Smrg 0, 0, 0); 147e88f27b3Smrg break; 148e88f27b3Smrg case G2D_OP_OVER: 149e88f27b3Smrg SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, 150e88f27b3Smrg G2D_COEFF_MODE_SRC_ALPHA, 1, 0, 0); 151e88f27b3Smrg break; 152e6188e58Smrg case G2D_OP_INTERPOLATE: 153e6188e58Smrg SET_BF(val, G2D_COEFF_MODE_SRC_ALPHA, 0, 0, 0, 154e6188e58Smrg G2D_COEFF_MODE_SRC_ALPHA, 1, 0, 0); 155e6188e58Smrg break; 156e88f27b3Smrg } 157e88f27b3Smrg 158e88f27b3Smrg return val.val; 159e88f27b3Smrg} 160e88f27b3Smrg 1613f012e29Smrg/* 1623f012e29Smrg * g2d_check_space - check if command buffers have enough space left. 1633f012e29Smrg * 1643f012e29Smrg * @ctx: a pointer to g2d_context structure. 1653f012e29Smrg * @num_cmds: number of (regular) commands. 1663f012e29Smrg * @num_gem_cmds: number of GEM commands. 1673f012e29Smrg */ 1683f012e29Smrgstatic unsigned int g2d_check_space(const struct g2d_context *ctx, 1693f012e29Smrg unsigned int num_cmds, unsigned int num_gem_cmds) 1703f012e29Smrg{ 1713f012e29Smrg if (ctx->cmd_nr + num_cmds >= G2D_MAX_CMD_NR || 1723f012e29Smrg ctx->cmd_buf_nr + num_gem_cmds >= G2D_MAX_GEM_CMD_NR) 1733f012e29Smrg return 1; 1743f012e29Smrg else 1753f012e29Smrg return 0; 1763f012e29Smrg} 1773f012e29Smrg 1783f012e29Smrg/* 1793f012e29Smrg * g2d_validate_select_mode - validate select mode. 1803f012e29Smrg * 1813f012e29Smrg * @mode: the mode to validate 1823f012e29Smrg * 1833f012e29Smrg * Returns zero for an invalid mode and one otherwise. 1843f012e29Smrg */ 1853f012e29Smrgstatic int g2d_validate_select_mode( 1863f012e29Smrg enum e_g2d_select_mode mode) 1873f012e29Smrg{ 1883f012e29Smrg switch (mode) { 1893f012e29Smrg case G2D_SELECT_MODE_NORMAL: 1903f012e29Smrg case G2D_SELECT_MODE_FGCOLOR: 1913f012e29Smrg case G2D_SELECT_MODE_BGCOLOR: 1923f012e29Smrg return 1; 1933f012e29Smrg } 1943f012e29Smrg 1953f012e29Smrg return 0; 1963f012e29Smrg} 1973f012e29Smrg 1983f012e29Smrg/* 1993f012e29Smrg * g2d_validate_blending_op - validate blending operation. 2003f012e29Smrg * 2013f012e29Smrg * @operation: the operation to validate 2023f012e29Smrg * 2033f012e29Smrg * Returns zero for an invalid mode and one otherwise. 2043f012e29Smrg */ 2053f012e29Smrgstatic int g2d_validate_blending_op( 2063f012e29Smrg enum e_g2d_op operation) 2073f012e29Smrg{ 2083f012e29Smrg switch (operation) { 2093f012e29Smrg case G2D_OP_CLEAR: 2103f012e29Smrg case G2D_OP_SRC: 2113f012e29Smrg case G2D_OP_DST: 2123f012e29Smrg case G2D_OP_OVER: 2133f012e29Smrg case G2D_OP_INTERPOLATE: 2143f012e29Smrg case G2D_OP_DISJOINT_CLEAR: 2153f012e29Smrg case G2D_OP_DISJOINT_SRC: 2163f012e29Smrg case G2D_OP_DISJOINT_DST: 2173f012e29Smrg case G2D_OP_CONJOINT_CLEAR: 2183f012e29Smrg case G2D_OP_CONJOINT_SRC: 2193f012e29Smrg case G2D_OP_CONJOINT_DST: 2203f012e29Smrg return 1; 2213f012e29Smrg } 2223f012e29Smrg 2233f012e29Smrg return 0; 2243f012e29Smrg} 2253f012e29Smrg 226e88f27b3Smrg/* 227e88f27b3Smrg * g2d_add_cmd - set given command and value to user side command buffer. 228e88f27b3Smrg * 229e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 230e88f27b3Smrg * @cmd: command data. 231e88f27b3Smrg * @value: value data. 2323f012e29Smrg * 2333f012e29Smrg * The caller has to make sure that the commands buffers have enough space 2343f012e29Smrg * left to hold the command. Use g2d_check_space() to ensure this. 235e88f27b3Smrg */ 2363f012e29Smrgstatic void g2d_add_cmd(struct g2d_context *ctx, unsigned long cmd, 237e88f27b3Smrg unsigned long value) 238e88f27b3Smrg{ 239e88f27b3Smrg switch (cmd & ~(G2D_BUF_USERPTR)) { 240e88f27b3Smrg case SRC_BASE_ADDR_REG: 241e88f27b3Smrg case SRC_PLANE2_BASE_ADDR_REG: 242e88f27b3Smrg case DST_BASE_ADDR_REG: 243e88f27b3Smrg case DST_PLANE2_BASE_ADDR_REG: 244e88f27b3Smrg case PAT_BASE_ADDR_REG: 245e88f27b3Smrg case MASK_BASE_ADDR_REG: 2463f012e29Smrg assert(ctx->cmd_buf_nr < G2D_MAX_GEM_CMD_NR); 247e88f27b3Smrg 248e88f27b3Smrg ctx->cmd_buf[ctx->cmd_buf_nr].offset = cmd; 249e88f27b3Smrg ctx->cmd_buf[ctx->cmd_buf_nr].data = value; 250e88f27b3Smrg ctx->cmd_buf_nr++; 251e88f27b3Smrg break; 252e88f27b3Smrg default: 2533f012e29Smrg assert(ctx->cmd_nr < G2D_MAX_CMD_NR); 254e88f27b3Smrg 255e88f27b3Smrg ctx->cmd[ctx->cmd_nr].offset = cmd; 256e88f27b3Smrg ctx->cmd[ctx->cmd_nr].data = value; 257e88f27b3Smrg ctx->cmd_nr++; 258e88f27b3Smrg break; 259e88f27b3Smrg } 260e6188e58Smrg} 261e6188e58Smrg 262e6188e58Smrg/* 263e6188e58Smrg * g2d_add_base_addr - helper function to set dst/src base address register. 264e6188e58Smrg * 265e6188e58Smrg * @ctx: a pointer to g2d_context structure. 266e6188e58Smrg * @img: a pointer to the dst/src g2d_image structure. 267e6188e58Smrg * @reg: the register that should be set. 268e6188e58Smrg */ 269e6188e58Smrgstatic void g2d_add_base_addr(struct g2d_context *ctx, struct g2d_image *img, 270e6188e58Smrg enum g2d_base_addr_reg reg) 271e6188e58Smrg{ 272e6188e58Smrg const unsigned long cmd = (reg == g2d_dst) ? 273e6188e58Smrg DST_BASE_ADDR_REG : SRC_BASE_ADDR_REG; 274e6188e58Smrg 275e6188e58Smrg if (img->buf_type == G2D_IMGBUF_USERPTR) 276e6188e58Smrg g2d_add_cmd(ctx, cmd | G2D_BUF_USERPTR, 277e6188e58Smrg (unsigned long)&img->user_ptr[0]); 278e6188e58Smrg else 279e6188e58Smrg g2d_add_cmd(ctx, cmd, img->bo[0]); 280e88f27b3Smrg} 281e88f27b3Smrg 2823f012e29Smrg/* 2833f012e29Smrg * g2d_set_direction - setup direction register (useful for overlapping blits). 2843f012e29Smrg * 2853f012e29Smrg * @ctx: a pointer to g2d_context structure. 2863f012e29Smrg * @dir: a pointer to the g2d_direction_val structure. 2873f012e29Smrg */ 2883f012e29Smrgstatic void g2d_set_direction(struct g2d_context *ctx, 2893f012e29Smrg const union g2d_direction_val *dir) 2903f012e29Smrg{ 2913f012e29Smrg g2d_add_cmd(ctx, SRC_MASK_DIRECT_REG, dir->val[0]); 2923f012e29Smrg g2d_add_cmd(ctx, DST_PAT_DIRECT_REG, dir->val[1]); 2933f012e29Smrg} 2943f012e29Smrg 295e88f27b3Smrg/* 296e88f27b3Smrg * g2d_reset - reset fimg2d hardware. 297e88f27b3Smrg * 298e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 299e88f27b3Smrg * 300e88f27b3Smrg */ 301e88f27b3Smrgstatic void g2d_reset(struct g2d_context *ctx) 302e88f27b3Smrg{ 303e88f27b3Smrg ctx->cmd_nr = 0; 304e88f27b3Smrg ctx->cmd_buf_nr = 0; 305e88f27b3Smrg 306e88f27b3Smrg g2d_add_cmd(ctx, SOFT_RESET_REG, 0x01); 307e88f27b3Smrg} 308e88f27b3Smrg 309e88f27b3Smrg/* 310e6188e58Smrg * g2d_flush - submit all commands and values in user side command buffer 311e88f27b3Smrg * to command queue aware of fimg2d dma. 312e88f27b3Smrg * 313e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 314e88f27b3Smrg * 315e88f27b3Smrg * This function should be called after all commands and values to user 316e6188e58Smrg * side command buffer are set. It submits that buffer to the kernel side driver. 317e88f27b3Smrg */ 318e88f27b3Smrgstatic int g2d_flush(struct g2d_context *ctx) 319e88f27b3Smrg{ 320e88f27b3Smrg int ret; 321e6188e58Smrg struct drm_exynos_g2d_set_cmdlist cmdlist = {0}; 322e88f27b3Smrg 323e6188e58Smrg if (ctx->cmd_nr == 0 && ctx->cmd_buf_nr == 0) 3243f012e29Smrg return 0; 325e88f27b3Smrg 326e88f27b3Smrg if (ctx->cmdlist_nr >= G2D_MAX_CMD_LIST_NR) { 3273f012e29Smrg fprintf(stderr, MSG_PREFIX "command list overflow.\n"); 328e88f27b3Smrg return -EINVAL; 329e88f27b3Smrg } 330e88f27b3Smrg 331baaff307Smrg cmdlist.cmd = (uint64_t)(uintptr_t)&ctx->cmd[0]; 332baaff307Smrg cmdlist.cmd_buf = (uint64_t)(uintptr_t)&ctx->cmd_buf[0]; 333e88f27b3Smrg cmdlist.cmd_nr = ctx->cmd_nr; 334e88f27b3Smrg cmdlist.cmd_buf_nr = ctx->cmd_buf_nr; 3353f012e29Smrg 3363f012e29Smrg if (ctx->event_userdata) { 3373f012e29Smrg cmdlist.event_type = G2D_EVENT_NONSTOP; 3383f012e29Smrg cmdlist.user_data = (uint64_t)(uintptr_t)(ctx->event_userdata); 3393f012e29Smrg ctx->event_userdata = NULL; 3403f012e29Smrg } else { 3413f012e29Smrg cmdlist.event_type = G2D_EVENT_NOT; 3423f012e29Smrg cmdlist.user_data = 0; 3433f012e29Smrg } 344e88f27b3Smrg 345e88f27b3Smrg ctx->cmd_nr = 0; 346e88f27b3Smrg ctx->cmd_buf_nr = 0; 347e88f27b3Smrg 348e88f27b3Smrg ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST, &cmdlist); 349e88f27b3Smrg if (ret < 0) { 3503f012e29Smrg fprintf(stderr, MSG_PREFIX "failed to set cmdlist.\n"); 351e88f27b3Smrg return ret; 352e88f27b3Smrg } 353e88f27b3Smrg 354e88f27b3Smrg ctx->cmdlist_nr++; 355e88f27b3Smrg 356e88f27b3Smrg return ret; 357e88f27b3Smrg} 358e88f27b3Smrg 359e88f27b3Smrg/** 360e88f27b3Smrg * g2d_init - create a new g2d context and get hardware version. 361e88f27b3Smrg * 362e6188e58Smrg * fd: a file descriptor to an opened drm device. 363e88f27b3Smrg */ 364e6188e58Smrgstruct g2d_context *g2d_init(int fd) 365e88f27b3Smrg{ 366e88f27b3Smrg struct drm_exynos_g2d_get_ver ver; 367e88f27b3Smrg struct g2d_context *ctx; 368e88f27b3Smrg int ret; 369e88f27b3Smrg 370e88f27b3Smrg ctx = calloc(1, sizeof(*ctx)); 371e88f27b3Smrg if (!ctx) { 3723f012e29Smrg fprintf(stderr, MSG_PREFIX "failed to allocate context.\n"); 373e88f27b3Smrg return NULL; 374e88f27b3Smrg } 375e88f27b3Smrg 376e88f27b3Smrg ctx->fd = fd; 377e88f27b3Smrg 378e88f27b3Smrg ret = drmIoctl(fd, DRM_IOCTL_EXYNOS_G2D_GET_VER, &ver); 379e88f27b3Smrg if (ret < 0) { 3803f012e29Smrg fprintf(stderr, MSG_PREFIX "failed to get version.\n"); 381e88f27b3Smrg free(ctx); 382e88f27b3Smrg return NULL; 383e88f27b3Smrg } 384e88f27b3Smrg 385e88f27b3Smrg ctx->major = ver.major; 386e88f27b3Smrg ctx->minor = ver.minor; 387e88f27b3Smrg 3883f012e29Smrg printf(MSG_PREFIX "G2D version (%d.%d).\n", ctx->major, ctx->minor); 389e88f27b3Smrg return ctx; 390e88f27b3Smrg} 391e88f27b3Smrg 392e6188e58Smrgvoid g2d_fini(struct g2d_context *ctx) 393e88f27b3Smrg{ 394e6188e58Smrg free(ctx); 395e88f27b3Smrg} 396e88f27b3Smrg 3973f012e29Smrg/** 3983f012e29Smrg * g2d_config_event - setup userdata configuration for a g2d event. 3993f012e29Smrg * The next invocation of a g2d call (e.g. g2d_solid_fill) is 4003f012e29Smrg * then going to flag the command buffer as 'nonstop'. 4013f012e29Smrg * Completion of the command buffer execution can then be 4023f012e29Smrg * determined by using drmHandleEvent on the DRM fd. 4033f012e29Smrg * The userdata is 'consumed' in the process. 4043f012e29Smrg * 4053f012e29Smrg * @ctx: a pointer to g2d_context structure. 4063f012e29Smrg * @userdata: a pointer to the user data 4073f012e29Smrg */ 4083f012e29Smrgvoid g2d_config_event(struct g2d_context *ctx, void *userdata) 4093f012e29Smrg{ 4103f012e29Smrg ctx->event_userdata = userdata; 4113f012e29Smrg} 4123f012e29Smrg 413e88f27b3Smrg/** 414e88f27b3Smrg * g2d_exec - start the dma to process all commands summited by g2d_flush(). 415e88f27b3Smrg * 416e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 417e88f27b3Smrg */ 418e6188e58Smrgint g2d_exec(struct g2d_context *ctx) 419e88f27b3Smrg{ 420e88f27b3Smrg struct drm_exynos_g2d_exec exec; 421e88f27b3Smrg int ret; 422e88f27b3Smrg 423e88f27b3Smrg if (ctx->cmdlist_nr == 0) 424e88f27b3Smrg return -EINVAL; 425e88f27b3Smrg 426e88f27b3Smrg exec.async = 0; 427e88f27b3Smrg 428e88f27b3Smrg ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_EXEC, &exec); 429e88f27b3Smrg if (ret < 0) { 4303f012e29Smrg fprintf(stderr, MSG_PREFIX "failed to execute.\n"); 431e88f27b3Smrg return ret; 432e88f27b3Smrg } 433e88f27b3Smrg 434e88f27b3Smrg ctx->cmdlist_nr = 0; 435e88f27b3Smrg 436e88f27b3Smrg return ret; 437e88f27b3Smrg} 438e88f27b3Smrg 439e88f27b3Smrg/** 440e88f27b3Smrg * g2d_solid_fill - fill given buffer with given color data. 441e88f27b3Smrg * 442e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 443e88f27b3Smrg * @img: a pointer to g2d_image structure including image and buffer 444e88f27b3Smrg * information. 445e88f27b3Smrg * @x: x start position to buffer filled with given color data. 446e88f27b3Smrg * @y: y start position to buffer filled with given color data. 447e88f27b3Smrg * @w: width value to buffer filled with given color data. 448e88f27b3Smrg * @h: height value to buffer filled with given color data. 449e88f27b3Smrg */ 450e6188e58Smrgint 451baaff307Smrgg2d_solid_fill(struct g2d_context *ctx, struct g2d_image *img, 452e88f27b3Smrg unsigned int x, unsigned int y, unsigned int w, 453e88f27b3Smrg unsigned int h) 454e88f27b3Smrg{ 455e88f27b3Smrg union g2d_bitblt_cmd_val bitblt; 456e88f27b3Smrg union g2d_point_val pt; 457e88f27b3Smrg 4583f012e29Smrg if (g2d_check_space(ctx, 7, 1)) 4593f012e29Smrg return -ENOSPC; 4603f012e29Smrg 461e88f27b3Smrg g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); 462e88f27b3Smrg g2d_add_cmd(ctx, DST_COLOR_MODE_REG, img->color_mode); 463e6188e58Smrg g2d_add_base_addr(ctx, img, g2d_dst); 464e88f27b3Smrg g2d_add_cmd(ctx, DST_STRIDE_REG, img->stride); 465e88f27b3Smrg 466e88f27b3Smrg if (x + w > img->width) 467e88f27b3Smrg w = img->width - x; 468e88f27b3Smrg if (y + h > img->height) 469e88f27b3Smrg h = img->height - y; 470e88f27b3Smrg 471e88f27b3Smrg pt.data.x = x; 472e88f27b3Smrg pt.data.y = y; 473e88f27b3Smrg g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 474e88f27b3Smrg 475e88f27b3Smrg pt.data.x = x + w; 476e88f27b3Smrg pt.data.y = y + h; 477e88f27b3Smrg g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 478e88f27b3Smrg 479e88f27b3Smrg g2d_add_cmd(ctx, SF_COLOR_REG, img->color); 480e88f27b3Smrg 481e88f27b3Smrg bitblt.val = 0; 482e88f27b3Smrg bitblt.data.fast_solid_color_fill_en = 1; 483e88f27b3Smrg g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val); 484e88f27b3Smrg 485e6188e58Smrg return g2d_flush(ctx); 486e88f27b3Smrg} 487e88f27b3Smrg 488e88f27b3Smrg/** 489e88f27b3Smrg * g2d_copy - copy contents in source buffer to destination buffer. 490e88f27b3Smrg * 491e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 492e88f27b3Smrg * @src: a pointer to g2d_image structure including image and buffer 493e88f27b3Smrg * information to source. 494e88f27b3Smrg * @dst: a pointer to g2d_image structure including image and buffer 495e88f27b3Smrg * information to destination. 496e88f27b3Smrg * @src_x: x start position to source buffer. 497e88f27b3Smrg * @src_y: y start position to source buffer. 498e88f27b3Smrg * @dst_x: x start position to destination buffer. 499e88f27b3Smrg * @dst_y: y start position to destination buffer. 500e88f27b3Smrg * @w: width value to source and destination buffers. 501e88f27b3Smrg * @h: height value to source and destination buffers. 502e88f27b3Smrg */ 503e6188e58Smrgint 504baaff307Smrgg2d_copy(struct g2d_context *ctx, struct g2d_image *src, 505e88f27b3Smrg struct g2d_image *dst, unsigned int src_x, unsigned int src_y, 506e88f27b3Smrg unsigned int dst_x, unsigned dst_y, unsigned int w, 507e88f27b3Smrg unsigned int h) 508e88f27b3Smrg{ 509e88f27b3Smrg union g2d_rop4_val rop4; 510e88f27b3Smrg union g2d_point_val pt; 5113f012e29Smrg unsigned int src_w, src_h, dst_w, dst_h; 5123f012e29Smrg 5133f012e29Smrg src_w = w; 5143f012e29Smrg src_h = h; 5153f012e29Smrg if (src_x + src->width > w) 5163f012e29Smrg src_w = src->width - src_x; 5173f012e29Smrg if (src_y + src->height > h) 5183f012e29Smrg src_h = src->height - src_y; 5193f012e29Smrg 5203f012e29Smrg dst_w = w; 5213f012e29Smrg dst_h = w; 5223f012e29Smrg if (dst_x + dst->width > w) 5233f012e29Smrg dst_w = dst->width - dst_x; 5243f012e29Smrg if (dst_y + dst->height > h) 5253f012e29Smrg dst_h = dst->height - dst_y; 5263f012e29Smrg 5273f012e29Smrg w = MIN(src_w, dst_w); 5283f012e29Smrg h = MIN(src_h, dst_h); 5293f012e29Smrg 5303f012e29Smrg if (w <= 0 || h <= 0) { 5313f012e29Smrg fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); 5323f012e29Smrg return -EINVAL; 5333f012e29Smrg } 5343f012e29Smrg 5353f012e29Smrg if (g2d_check_space(ctx, 11, 2)) 5363f012e29Smrg return -ENOSPC; 537e88f27b3Smrg 538e88f27b3Smrg g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); 539e88f27b3Smrg g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); 540e6188e58Smrg g2d_add_base_addr(ctx, dst, g2d_dst); 541e88f27b3Smrg g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); 542e88f27b3Smrg 543e88f27b3Smrg g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); 544e88f27b3Smrg g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); 545e6188e58Smrg g2d_add_base_addr(ctx, src, g2d_src); 546e88f27b3Smrg g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); 547e88f27b3Smrg 5483f012e29Smrg pt.data.x = src_x; 5493f012e29Smrg pt.data.y = src_y; 5503f012e29Smrg g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); 5513f012e29Smrg pt.data.x = src_x + w; 5523f012e29Smrg pt.data.y = src_y + h; 5533f012e29Smrg g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); 5543f012e29Smrg 5553f012e29Smrg pt.data.x = dst_x; 5563f012e29Smrg pt.data.y = dst_y; 5573f012e29Smrg g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 5583f012e29Smrg pt.data.x = dst_x + w; 5593f012e29Smrg pt.data.y = dst_y + h; 5603f012e29Smrg g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 5613f012e29Smrg 5623f012e29Smrg rop4.val = 0; 5633f012e29Smrg rop4.data.unmasked_rop3 = G2D_ROP3_SRC; 5643f012e29Smrg g2d_add_cmd(ctx, ROP4_REG, rop4.val); 5653f012e29Smrg 5663f012e29Smrg return g2d_flush(ctx); 5673f012e29Smrg} 5683f012e29Smrg 5693f012e29Smrg/** 5703f012e29Smrg * g2d_move - copy content inside single buffer. 5713f012e29Smrg * Similar to libc's memmove() this copies a rectangular 5723f012e29Smrg * region of the provided buffer to another location, while 5733f012e29Smrg * properly handling the situation where source and 5743f012e29Smrg * destination rectangle overlap. 5753f012e29Smrg * 5763f012e29Smrg * @ctx: a pointer to g2d_context structure. 5773f012e29Smrg * @img: a pointer to g2d_image structure providing 5783f012e29Smrg * buffer information. 5793f012e29Smrg * @src_x: x position of source rectangle. 5803f012e29Smrg * @src_y: y position of source rectangle. 5813f012e29Smrg * @dst_x: x position of destination rectangle. 5823f012e29Smrg * @dst_y: y position of destination rectangle. 5833f012e29Smrg * @w: width of rectangle to move. 5843f012e29Smrg * @h: height of rectangle to move. 5853f012e29Smrg */ 5863f012e29Smrgint 5873f012e29Smrgg2d_move(struct g2d_context *ctx, struct g2d_image *img, 5883f012e29Smrg unsigned int src_x, unsigned int src_y, 5893f012e29Smrg unsigned int dst_x, unsigned dst_y, unsigned int w, 5903f012e29Smrg unsigned int h) 5913f012e29Smrg{ 5923f012e29Smrg union g2d_rop4_val rop4; 5933f012e29Smrg union g2d_point_val pt; 5943f012e29Smrg union g2d_direction_val dir; 5953f012e29Smrg unsigned int src_w, src_h, dst_w, dst_h; 5963f012e29Smrg 597e88f27b3Smrg src_w = w; 598e88f27b3Smrg src_h = h; 5993f012e29Smrg if (src_x + img->width > w) 6003f012e29Smrg src_w = img->width - src_x; 6013f012e29Smrg if (src_y + img->height > h) 6023f012e29Smrg src_h = img->height - src_y; 603e88f27b3Smrg 604e88f27b3Smrg dst_w = w; 605e88f27b3Smrg dst_h = w; 6063f012e29Smrg if (dst_x + img->width > w) 6073f012e29Smrg dst_w = img->width - dst_x; 6083f012e29Smrg if (dst_y + img->height > h) 6093f012e29Smrg dst_h = img->height - dst_y; 610e88f27b3Smrg 611e88f27b3Smrg w = MIN(src_w, dst_w); 612e88f27b3Smrg h = MIN(src_h, dst_h); 613e88f27b3Smrg 6143f012e29Smrg if (w == 0 || h == 0) { 6153f012e29Smrg fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); 616e88f27b3Smrg return -EINVAL; 617e88f27b3Smrg } 618e88f27b3Smrg 6193f012e29Smrg if (g2d_check_space(ctx, 13, 2)) 6203f012e29Smrg return -ENOSPC; 6213f012e29Smrg 6223f012e29Smrg g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); 6233f012e29Smrg g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); 6243f012e29Smrg 6253f012e29Smrg g2d_add_cmd(ctx, DST_COLOR_MODE_REG, img->color_mode); 6263f012e29Smrg g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, img->color_mode); 6273f012e29Smrg 6283f012e29Smrg g2d_add_base_addr(ctx, img, g2d_dst); 6293f012e29Smrg g2d_add_base_addr(ctx, img, g2d_src); 6303f012e29Smrg 6313f012e29Smrg g2d_add_cmd(ctx, DST_STRIDE_REG, img->stride); 6323f012e29Smrg g2d_add_cmd(ctx, SRC_STRIDE_REG, img->stride); 6333f012e29Smrg 6343f012e29Smrg dir.val[0] = dir.val[1] = 0; 6353f012e29Smrg 6363f012e29Smrg if (dst_x >= src_x) 6373f012e29Smrg dir.data.src_x_direction = dir.data.dst_x_direction = 1; 6383f012e29Smrg if (dst_y >= src_y) 6393f012e29Smrg dir.data.src_y_direction = dir.data.dst_y_direction = 1; 6403f012e29Smrg 6413f012e29Smrg g2d_set_direction(ctx, &dir); 6423f012e29Smrg 643e88f27b3Smrg pt.data.x = src_x; 644e88f27b3Smrg pt.data.y = src_y; 645e88f27b3Smrg g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); 646e88f27b3Smrg pt.data.x = src_x + w; 647e88f27b3Smrg pt.data.y = src_y + h; 648e88f27b3Smrg g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); 649e88f27b3Smrg 650e88f27b3Smrg pt.data.x = dst_x; 651e88f27b3Smrg pt.data.y = dst_y; 652e88f27b3Smrg g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 653e88f27b3Smrg pt.data.x = dst_x + w; 654baaff307Smrg pt.data.y = dst_y + h; 655e88f27b3Smrg g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 656e88f27b3Smrg 657e88f27b3Smrg rop4.val = 0; 658e88f27b3Smrg rop4.data.unmasked_rop3 = G2D_ROP3_SRC; 659e88f27b3Smrg g2d_add_cmd(ctx, ROP4_REG, rop4.val); 660e88f27b3Smrg 661e6188e58Smrg return g2d_flush(ctx); 662e88f27b3Smrg} 663e88f27b3Smrg 664e88f27b3Smrg/** 665e88f27b3Smrg * g2d_copy_with_scale - copy contents in source buffer to destination buffer 666e88f27b3Smrg * scaling up or down properly. 667e88f27b3Smrg * 668e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 669e88f27b3Smrg * @src: a pointer to g2d_image structure including image and buffer 670e88f27b3Smrg * information to source. 671e88f27b3Smrg * @dst: a pointer to g2d_image structure including image and buffer 672e88f27b3Smrg * information to destination. 673e88f27b3Smrg * @src_x: x start position to source buffer. 674e88f27b3Smrg * @src_y: y start position to source buffer. 675e88f27b3Smrg * @src_w: width value to source buffer. 676e88f27b3Smrg * @src_h: height value to source buffer. 677e88f27b3Smrg * @dst_x: x start position to destination buffer. 678e88f27b3Smrg * @dst_y: y start position to destination buffer. 679e88f27b3Smrg * @dst_w: width value to destination buffer. 680e88f27b3Smrg * @dst_h: height value to destination buffer. 681e88f27b3Smrg * @negative: indicate that it uses color negative to source and 682e88f27b3Smrg * destination buffers. 683e88f27b3Smrg */ 684e6188e58Smrgint 685baaff307Smrgg2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src, 686e88f27b3Smrg struct g2d_image *dst, unsigned int src_x, 687e88f27b3Smrg unsigned int src_y, unsigned int src_w, 688e88f27b3Smrg unsigned int src_h, unsigned int dst_x, 689e88f27b3Smrg unsigned int dst_y, unsigned int dst_w, 690e88f27b3Smrg unsigned int dst_h, unsigned int negative) 691e88f27b3Smrg{ 692e88f27b3Smrg union g2d_rop4_val rop4; 693e88f27b3Smrg union g2d_point_val pt; 6943f012e29Smrg unsigned int scale, repeat_pad; 695e6188e58Smrg unsigned int scale_x, scale_y; 696e88f27b3Smrg 6973f012e29Smrg /* Sanitize this parameter to facilitate space computation below. */ 6983f012e29Smrg if (negative) 6993f012e29Smrg negative = 1; 700e88f27b3Smrg 701e88f27b3Smrg if (src_w == dst_w && src_h == dst_h) 702e88f27b3Smrg scale = 0; 703e88f27b3Smrg else { 704e88f27b3Smrg scale = 1; 705e6188e58Smrg scale_x = g2d_get_scaling(src_w, dst_w); 706e6188e58Smrg scale_y = g2d_get_scaling(src_h, dst_h); 707e88f27b3Smrg } 708e88f27b3Smrg 7093f012e29Smrg repeat_pad = src->repeat_mode == G2D_REPEAT_MODE_PAD ? 1 : 0; 7103f012e29Smrg 711e88f27b3Smrg if (src_x + src_w > src->width) 712e88f27b3Smrg src_w = src->width - src_x; 713e88f27b3Smrg if (src_y + src_h > src->height) 714e88f27b3Smrg src_h = src->height - src_y; 715e88f27b3Smrg 716e88f27b3Smrg if (dst_x + dst_w > dst->width) 717e88f27b3Smrg dst_w = dst->width - dst_x; 718e88f27b3Smrg if (dst_y + dst_h > dst->height) 719e88f27b3Smrg dst_h = dst->height - dst_y; 720e88f27b3Smrg 721e88f27b3Smrg if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) { 7223f012e29Smrg fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); 723e88f27b3Smrg return -EINVAL; 724e88f27b3Smrg } 725e88f27b3Smrg 7263f012e29Smrg if (g2d_check_space(ctx, 12 + scale * 3 + negative + repeat_pad, 2)) 7273f012e29Smrg return -ENOSPC; 7283f012e29Smrg 7293f012e29Smrg g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); 7303f012e29Smrg g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); 7313f012e29Smrg g2d_add_base_addr(ctx, dst, g2d_dst); 7323f012e29Smrg g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); 7333f012e29Smrg 7343f012e29Smrg g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); 7353f012e29Smrg g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); 7363f012e29Smrg 7373f012e29Smrg g2d_add_cmd(ctx, SRC_REPEAT_MODE_REG, src->repeat_mode); 7383f012e29Smrg if (repeat_pad) 7393f012e29Smrg g2d_add_cmd(ctx, SRC_PAD_VALUE_REG, dst->color); 7403f012e29Smrg 7413f012e29Smrg g2d_add_base_addr(ctx, src, g2d_src); 7423f012e29Smrg g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); 7433f012e29Smrg 7443f012e29Smrg rop4.val = 0; 7453f012e29Smrg rop4.data.unmasked_rop3 = G2D_ROP3_SRC; 7463f012e29Smrg 747e88f27b3Smrg if (negative) { 748e88f27b3Smrg g2d_add_cmd(ctx, BG_COLOR_REG, 0x00FFFFFF); 7493f012e29Smrg rop4.data.unmasked_rop3 ^= G2D_ROP3_DST; 750e88f27b3Smrg } 751e88f27b3Smrg 7523f012e29Smrg g2d_add_cmd(ctx, ROP4_REG, rop4.val); 7533f012e29Smrg 754e88f27b3Smrg if (scale) { 755e88f27b3Smrg g2d_add_cmd(ctx, SRC_SCALE_CTRL_REG, G2D_SCALE_MODE_BILINEAR); 756e6188e58Smrg g2d_add_cmd(ctx, SRC_XSCALE_REG, scale_x); 757e6188e58Smrg g2d_add_cmd(ctx, SRC_YSCALE_REG, scale_y); 758e88f27b3Smrg } 759e88f27b3Smrg 760e88f27b3Smrg pt.data.x = src_x; 761e88f27b3Smrg pt.data.y = src_y; 762e88f27b3Smrg g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); 763e88f27b3Smrg pt.data.x = src_x + src_w; 764e88f27b3Smrg pt.data.y = src_y + src_h; 765e88f27b3Smrg g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); 766e88f27b3Smrg 767e88f27b3Smrg pt.data.x = dst_x; 768e88f27b3Smrg pt.data.y = dst_y; 769e88f27b3Smrg g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 770e88f27b3Smrg pt.data.x = dst_x + dst_w; 771e88f27b3Smrg pt.data.y = dst_y + dst_h; 772e88f27b3Smrg g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 773e88f27b3Smrg 774e6188e58Smrg return g2d_flush(ctx); 775e88f27b3Smrg} 776e88f27b3Smrg 777e88f27b3Smrg/** 778e6188e58Smrg * g2d_blend - blend image data in source and destination buffers. 779e88f27b3Smrg * 780e88f27b3Smrg * @ctx: a pointer to g2d_context structure. 781e88f27b3Smrg * @src: a pointer to g2d_image structure including image and buffer 782e88f27b3Smrg * information to source. 783e88f27b3Smrg * @dst: a pointer to g2d_image structure including image and buffer 784e88f27b3Smrg * information to destination. 785e88f27b3Smrg * @src_x: x start position to source buffer. 786e88f27b3Smrg * @src_y: y start position to source buffer. 787e88f27b3Smrg * @dst_x: x start position to destination buffer. 788e88f27b3Smrg * @dst_y: y start position to destination buffer. 789e88f27b3Smrg * @w: width value to source and destination buffer. 790e88f27b3Smrg * @h: height value to source and destination buffer. 791e88f27b3Smrg * @op: blend operation type. 792e88f27b3Smrg */ 793e6188e58Smrgint 794baaff307Smrgg2d_blend(struct g2d_context *ctx, struct g2d_image *src, 795e88f27b3Smrg struct g2d_image *dst, unsigned int src_x, 796e88f27b3Smrg unsigned int src_y, unsigned int dst_x, unsigned int dst_y, 797e88f27b3Smrg unsigned int w, unsigned int h, enum e_g2d_op op) 798e88f27b3Smrg{ 799e88f27b3Smrg union g2d_point_val pt; 800e88f27b3Smrg union g2d_bitblt_cmd_val bitblt; 801e88f27b3Smrg union g2d_blend_func_val blend; 8023f012e29Smrg unsigned int gem_space; 8033f012e29Smrg unsigned int src_w, src_h, dst_w, dst_h; 8043f012e29Smrg 8053f012e29Smrg src_w = w; 8063f012e29Smrg src_h = h; 8073f012e29Smrg if (src_x + w > src->width) 8083f012e29Smrg src_w = src->width - src_x; 8093f012e29Smrg if (src_y + h > src->height) 8103f012e29Smrg src_h = src->height - src_y; 8113f012e29Smrg 8123f012e29Smrg dst_w = w; 8133f012e29Smrg dst_h = h; 8143f012e29Smrg if (dst_x + w > dst->width) 8153f012e29Smrg dst_w = dst->width - dst_x; 8163f012e29Smrg if (dst_y + h > dst->height) 8173f012e29Smrg dst_h = dst->height - dst_y; 8183f012e29Smrg 8193f012e29Smrg w = MIN(src_w, dst_w); 8203f012e29Smrg h = MIN(src_h, dst_h); 8213f012e29Smrg 8223f012e29Smrg if (w <= 0 || h <= 0) { 8233f012e29Smrg fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); 8243f012e29Smrg return -EINVAL; 8253f012e29Smrg } 8263f012e29Smrg 8273f012e29Smrg if (!g2d_validate_select_mode(src->select_mode)) { 8283f012e29Smrg fprintf(stderr , MSG_PREFIX "invalid select mode for source.\n"); 8293f012e29Smrg return -EINVAL; 8303f012e29Smrg } 8313f012e29Smrg 8323f012e29Smrg if (!g2d_validate_blending_op(op)) { 8333f012e29Smrg fprintf(stderr , MSG_PREFIX "unsupported blending operation.\n"); 8343f012e29Smrg return -EINVAL; 8353f012e29Smrg } 8363f012e29Smrg 8373f012e29Smrg gem_space = src->select_mode == G2D_SELECT_MODE_NORMAL ? 2 : 1; 8383f012e29Smrg 8393f012e29Smrg if (g2d_check_space(ctx, 12, gem_space)) 8403f012e29Smrg return -ENOSPC; 841e88f27b3Smrg 842e88f27b3Smrg bitblt.val = 0; 843e88f27b3Smrg blend.val = 0; 844e88f27b3Smrg 845e88f27b3Smrg if (op == G2D_OP_SRC || op == G2D_OP_CLEAR) 846e88f27b3Smrg g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); 847e88f27b3Smrg else 848e88f27b3Smrg g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); 849e88f27b3Smrg 850e88f27b3Smrg g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); 851e6188e58Smrg g2d_add_base_addr(ctx, dst, g2d_dst); 852e88f27b3Smrg g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); 853e88f27b3Smrg 854e88f27b3Smrg g2d_add_cmd(ctx, SRC_SELECT_REG, src->select_mode); 855e88f27b3Smrg g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); 856e88f27b3Smrg 857e88f27b3Smrg switch (src->select_mode) { 858e88f27b3Smrg case G2D_SELECT_MODE_NORMAL: 859e6188e58Smrg g2d_add_base_addr(ctx, src, g2d_src); 860e88f27b3Smrg g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); 861e88f27b3Smrg break; 862e88f27b3Smrg case G2D_SELECT_MODE_FGCOLOR: 863e88f27b3Smrg g2d_add_cmd(ctx, FG_COLOR_REG, src->color); 864e88f27b3Smrg break; 865e88f27b3Smrg case G2D_SELECT_MODE_BGCOLOR: 866e88f27b3Smrg g2d_add_cmd(ctx, BG_COLOR_REG, src->color); 867e88f27b3Smrg break; 868e88f27b3Smrg } 869e88f27b3Smrg 870e88f27b3Smrg bitblt.data.alpha_blend_mode = G2D_ALPHA_BLEND_MODE_ENABLE; 871e88f27b3Smrg blend.val = g2d_get_blend_op(op); 872e88f27b3Smrg g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val); 873e88f27b3Smrg g2d_add_cmd(ctx, BLEND_FUNCTION_REG, blend.val); 874e88f27b3Smrg 875e88f27b3Smrg pt.data.x = src_x; 876e88f27b3Smrg pt.data.y = src_y; 877e88f27b3Smrg g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); 878e88f27b3Smrg pt.data.x = src_x + w; 879e88f27b3Smrg pt.data.y = src_y + h; 880e88f27b3Smrg g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); 881e88f27b3Smrg 882e88f27b3Smrg pt.data.x = dst_x; 883e88f27b3Smrg pt.data.y = dst_y; 884e88f27b3Smrg g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 885e88f27b3Smrg pt.data.x = dst_x + w; 886e88f27b3Smrg pt.data.y = dst_y + h; 887e88f27b3Smrg g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 888e88f27b3Smrg 889e6188e58Smrg return g2d_flush(ctx); 890e88f27b3Smrg} 891e88f27b3Smrg 892e6188e58Smrg/** 893e6188e58Smrg * g2d_scale_and_blend - apply scaling to source buffer and then blend to destination buffer 894e6188e58Smrg * 895e6188e58Smrg * @ctx: a pointer to g2d_context structure. 896e6188e58Smrg * @src: a pointer to g2d_image structure including image and buffer 897e6188e58Smrg * information to source. 898e6188e58Smrg * @dst: a pointer to g2d_image structure including image and buffer 899e6188e58Smrg * information to destination. 900e6188e58Smrg * @src_x: x start position to source buffer. 901e6188e58Smrg * @src_y: y start position to source buffer. 902e6188e58Smrg * @src_w: width value to source buffer. 903e6188e58Smrg * @src_h: height value to source buffer. 904e6188e58Smrg * @dst_x: x start position to destination buffer. 905e6188e58Smrg * @dst_y: y start position to destination buffer. 906e6188e58Smrg * @dst_w: width value to destination buffer. 907e6188e58Smrg * @dst_h: height value to destination buffer. 908e6188e58Smrg * @op: blend operation type. 909e6188e58Smrg */ 910e6188e58Smrgint 911e6188e58Smrgg2d_scale_and_blend(struct g2d_context *ctx, struct g2d_image *src, 912e6188e58Smrg struct g2d_image *dst, unsigned int src_x, unsigned int src_y, 913e6188e58Smrg unsigned int src_w, unsigned int src_h, unsigned int dst_x, 914e6188e58Smrg unsigned int dst_y, unsigned int dst_w, unsigned int dst_h, 915e6188e58Smrg enum e_g2d_op op) 916e6188e58Smrg{ 917e6188e58Smrg union g2d_point_val pt; 918e6188e58Smrg union g2d_bitblt_cmd_val bitblt; 919e6188e58Smrg union g2d_blend_func_val blend; 9203f012e29Smrg unsigned int scale, gem_space; 921e6188e58Smrg unsigned int scale_x, scale_y; 922e6188e58Smrg 9233f012e29Smrg if (src_w == dst_w && src_h == dst_h) 9243f012e29Smrg scale = 0; 9253f012e29Smrg else { 9263f012e29Smrg scale = 1; 9273f012e29Smrg scale_x = g2d_get_scaling(src_w, dst_w); 9283f012e29Smrg scale_y = g2d_get_scaling(src_h, dst_h); 9293f012e29Smrg } 9303f012e29Smrg 9313f012e29Smrg if (src_x + src_w > src->width) 9323f012e29Smrg src_w = src->width - src_x; 9333f012e29Smrg if (src_y + src_h > src->height) 9343f012e29Smrg src_h = src->height - src_y; 9353f012e29Smrg 9363f012e29Smrg if (dst_x + dst_w > dst->width) 9373f012e29Smrg dst_w = dst->width - dst_x; 9383f012e29Smrg if (dst_y + dst_h > dst->height) 9393f012e29Smrg dst_h = dst->height - dst_y; 9403f012e29Smrg 9413f012e29Smrg if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) { 9423f012e29Smrg fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); 9433f012e29Smrg return -EINVAL; 9443f012e29Smrg } 9453f012e29Smrg 9463f012e29Smrg if (!g2d_validate_select_mode(src->select_mode)) { 9473f012e29Smrg fprintf(stderr , MSG_PREFIX "invalid select mode for source.\n"); 9483f012e29Smrg return -EINVAL; 9493f012e29Smrg } 9503f012e29Smrg 9513f012e29Smrg if (!g2d_validate_blending_op(op)) { 9523f012e29Smrg fprintf(stderr , MSG_PREFIX "unsupported blending operation.\n"); 9533f012e29Smrg return -EINVAL; 9543f012e29Smrg } 9553f012e29Smrg 9563f012e29Smrg gem_space = src->select_mode == G2D_SELECT_MODE_NORMAL ? 2 : 1; 9573f012e29Smrg 9583f012e29Smrg if (g2d_check_space(ctx, 12 + scale * 3, gem_space)) 9593f012e29Smrg return -ENOSPC; 9603f012e29Smrg 961e6188e58Smrg bitblt.val = 0; 962e6188e58Smrg blend.val = 0; 963e6188e58Smrg 964e6188e58Smrg if (op == G2D_OP_SRC || op == G2D_OP_CLEAR) 965e6188e58Smrg g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); 966e6188e58Smrg else 967e6188e58Smrg g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); 968e6188e58Smrg 969e6188e58Smrg g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); 9703f012e29Smrg g2d_add_base_addr(ctx, dst, g2d_dst); 971e6188e58Smrg g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); 972e6188e58Smrg 973e6188e58Smrg g2d_add_cmd(ctx, SRC_SELECT_REG, src->select_mode); 974e6188e58Smrg g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); 975e6188e58Smrg 976e6188e58Smrg switch (src->select_mode) { 977e6188e58Smrg case G2D_SELECT_MODE_NORMAL: 9783f012e29Smrg g2d_add_base_addr(ctx, src, g2d_src); 979e6188e58Smrg g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); 980e6188e58Smrg break; 981e6188e58Smrg case G2D_SELECT_MODE_FGCOLOR: 982e6188e58Smrg g2d_add_cmd(ctx, FG_COLOR_REG, src->color); 983e6188e58Smrg break; 984e6188e58Smrg case G2D_SELECT_MODE_BGCOLOR: 985e6188e58Smrg g2d_add_cmd(ctx, BG_COLOR_REG, src->color); 986e6188e58Smrg break; 987e6188e58Smrg } 988e6188e58Smrg 989e6188e58Smrg if (scale) { 990e6188e58Smrg g2d_add_cmd(ctx, SRC_SCALE_CTRL_REG, G2D_SCALE_MODE_BILINEAR); 991e6188e58Smrg g2d_add_cmd(ctx, SRC_XSCALE_REG, scale_x); 992e6188e58Smrg g2d_add_cmd(ctx, SRC_YSCALE_REG, scale_y); 993e6188e58Smrg } 994e6188e58Smrg 995e6188e58Smrg bitblt.data.alpha_blend_mode = G2D_ALPHA_BLEND_MODE_ENABLE; 996e6188e58Smrg blend.val = g2d_get_blend_op(op); 997e6188e58Smrg g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val); 998e6188e58Smrg g2d_add_cmd(ctx, BLEND_FUNCTION_REG, blend.val); 999e6188e58Smrg 1000e6188e58Smrg pt.data.x = src_x; 1001e6188e58Smrg pt.data.y = src_y; 1002e6188e58Smrg g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); 1003e6188e58Smrg pt.data.x = src_x + src_w; 1004e6188e58Smrg pt.data.y = src_y + src_h; 1005e6188e58Smrg g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); 1006e6188e58Smrg 1007e6188e58Smrg pt.data.x = dst_x; 1008e6188e58Smrg pt.data.y = dst_y; 1009e6188e58Smrg g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); 1010e6188e58Smrg pt.data.x = dst_x + dst_w; 1011e6188e58Smrg pt.data.y = dst_y + dst_h; 1012e6188e58Smrg g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); 1013e6188e58Smrg 1014e6188e58Smrg return g2d_flush(ctx); 1015e6188e58Smrg} 1016