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