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