xref: /third_party/libdrm/exynos/exynos_fimg2d.c (revision d722e3fb)
1d722e3fbSopenharmony_ci/*
2d722e3fbSopenharmony_ci * Copyright (C) 2013 Samsung Electronics Co.Ltd
3d722e3fbSopenharmony_ci * Authors:
4d722e3fbSopenharmony_ci *	Inki Dae <inki.dae@samsung.com>
5d722e3fbSopenharmony_ci *
6d722e3fbSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7d722e3fbSopenharmony_ci * copy of this software and associated documentation files (the "Software"),
8d722e3fbSopenharmony_ci * to deal in the Software without restriction, including without limitation
9d722e3fbSopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10d722e3fbSopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
11d722e3fbSopenharmony_ci * Software is furnished to do so, subject to the following conditions:
12d722e3fbSopenharmony_ci *
13d722e3fbSopenharmony_ci * The above copyright notice and this permission notice (including the next
14d722e3fbSopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
15d722e3fbSopenharmony_ci * Software.
16d722e3fbSopenharmony_ci *
17d722e3fbSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18d722e3fbSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19d722e3fbSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20d722e3fbSopenharmony_ci * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21d722e3fbSopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22d722e3fbSopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23d722e3fbSopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
24d722e3fbSopenharmony_ci */
25d722e3fbSopenharmony_ci
26d722e3fbSopenharmony_ci#include <stdlib.h>
27d722e3fbSopenharmony_ci#include <stdio.h>
28d722e3fbSopenharmony_ci#include <string.h>
29d722e3fbSopenharmony_ci#include <errno.h>
30d722e3fbSopenharmony_ci#include <assert.h>
31d722e3fbSopenharmony_ci
32d722e3fbSopenharmony_ci#include <sys/mman.h>
33d722e3fbSopenharmony_ci#include <linux/stddef.h>
34d722e3fbSopenharmony_ci
35d722e3fbSopenharmony_ci#include <xf86drm.h>
36d722e3fbSopenharmony_ci
37d722e3fbSopenharmony_ci#include "libdrm_macros.h"
38d722e3fbSopenharmony_ci#include "exynos_drm.h"
39d722e3fbSopenharmony_ci#include "fimg2d_reg.h"
40d722e3fbSopenharmony_ci#include "exynos_fimg2d.h"
41d722e3fbSopenharmony_ci
42d722e3fbSopenharmony_ci#define		SET_BF(val, sc, si, scsa, scda, dc, di, dcsa, dcda) \
43d722e3fbSopenharmony_ci			val.data.src_coeff = sc;		\
44d722e3fbSopenharmony_ci			val.data.inv_src_color_coeff = si;	\
45d722e3fbSopenharmony_ci			val.data.src_coeff_src_a = scsa;	\
46d722e3fbSopenharmony_ci			val.data.src_coeff_dst_a = scda;	\
47d722e3fbSopenharmony_ci			val.data.dst_coeff = dc;		\
48d722e3fbSopenharmony_ci			val.data.inv_dst_color_coeff = di;	\
49d722e3fbSopenharmony_ci			val.data.dst_coeff_src_a = dcsa;	\
50d722e3fbSopenharmony_ci			val.data.dst_coeff_dst_a = dcda;
51d722e3fbSopenharmony_ci
52d722e3fbSopenharmony_ci#define MIN(a, b)	((a) < (b) ? (a) : (b))
53d722e3fbSopenharmony_ci
54d722e3fbSopenharmony_ci#define MSG_PREFIX "exynos/fimg2d: "
55d722e3fbSopenharmony_ci
56d722e3fbSopenharmony_ci#define G2D_MAX_CMD_NR		64
57d722e3fbSopenharmony_ci#define G2D_MAX_GEM_CMD_NR	64
58d722e3fbSopenharmony_ci#define G2D_MAX_CMD_LIST_NR	64
59d722e3fbSopenharmony_ci
60d722e3fbSopenharmony_cistruct g2d_context {
61d722e3fbSopenharmony_ci	int				fd;
62d722e3fbSopenharmony_ci	unsigned int			major;
63d722e3fbSopenharmony_ci	unsigned int			minor;
64d722e3fbSopenharmony_ci	struct drm_exynos_g2d_cmd	cmd[G2D_MAX_CMD_NR];
65d722e3fbSopenharmony_ci	struct drm_exynos_g2d_cmd	cmd_buf[G2D_MAX_GEM_CMD_NR];
66d722e3fbSopenharmony_ci	unsigned int			cmd_nr;
67d722e3fbSopenharmony_ci	unsigned int			cmd_buf_nr;
68d722e3fbSopenharmony_ci	unsigned int			cmdlist_nr;
69d722e3fbSopenharmony_ci	void				*event_userdata;
70d722e3fbSopenharmony_ci};
71d722e3fbSopenharmony_ci
72d722e3fbSopenharmony_cienum g2d_base_addr_reg {
73d722e3fbSopenharmony_ci	g2d_dst = 0,
74d722e3fbSopenharmony_ci	g2d_src
75d722e3fbSopenharmony_ci};
76d722e3fbSopenharmony_ci
77d722e3fbSopenharmony_cienum e_g2d_dir_mode {
78d722e3fbSopenharmony_ci	G2D_DIR_MODE_POSITIVE = 0,
79d722e3fbSopenharmony_ci	G2D_DIR_MODE_NEGATIVE = 1
80d722e3fbSopenharmony_ci};
81d722e3fbSopenharmony_ci
82d722e3fbSopenharmony_ciunion g2d_direction_val {
83d722e3fbSopenharmony_ci	unsigned int val[2];
84d722e3fbSopenharmony_ci	struct {
85d722e3fbSopenharmony_ci		/* SRC_MSK_DIRECT_REG [0:1] (source) */
86d722e3fbSopenharmony_ci		enum e_g2d_dir_mode		src_x_direction:1;
87d722e3fbSopenharmony_ci		enum e_g2d_dir_mode		src_y_direction:1;
88d722e3fbSopenharmony_ci
89d722e3fbSopenharmony_ci		/* SRC_MSK_DIRECT_REG [2:3] */
90d722e3fbSopenharmony_ci		unsigned int			reversed1:2;
91d722e3fbSopenharmony_ci
92d722e3fbSopenharmony_ci		/* SRC_MSK_DIRECT_REG [4:5] (mask) */
93d722e3fbSopenharmony_ci		enum e_g2d_dir_mode		mask_x_direction:1;
94d722e3fbSopenharmony_ci		enum e_g2d_dir_mode		mask_y_direction:1;
95d722e3fbSopenharmony_ci
96d722e3fbSopenharmony_ci		/* SRC_MSK_DIRECT_REG [6:31] */
97d722e3fbSopenharmony_ci		unsigned int			padding1:26;
98d722e3fbSopenharmony_ci
99d722e3fbSopenharmony_ci		/* DST_PAT_DIRECT_REG [0:1] (destination) */
100d722e3fbSopenharmony_ci		enum e_g2d_dir_mode		dst_x_direction:1;
101d722e3fbSopenharmony_ci		enum e_g2d_dir_mode		dst_y_direction:1;
102d722e3fbSopenharmony_ci
103d722e3fbSopenharmony_ci		/* DST_PAT_DIRECT_REG [2:3] */
104d722e3fbSopenharmony_ci		unsigned int			reversed2:2;
105d722e3fbSopenharmony_ci
106d722e3fbSopenharmony_ci		/* DST_PAT_DIRECT_REG [4:5] (pattern) */
107d722e3fbSopenharmony_ci		enum e_g2d_dir_mode		pat_x_direction:1;
108d722e3fbSopenharmony_ci		enum e_g2d_dir_mode		pat_y_direction:1;
109d722e3fbSopenharmony_ci
110d722e3fbSopenharmony_ci		/* DST_PAT_DIRECT_REG [6:31] */
111d722e3fbSopenharmony_ci		unsigned int			padding2:26;
112d722e3fbSopenharmony_ci	} data;
113d722e3fbSopenharmony_ci};
114d722e3fbSopenharmony_ci
115d722e3fbSopenharmony_cistatic unsigned int g2d_get_scaling(unsigned int src, unsigned int dst)
116d722e3fbSopenharmony_ci{
117d722e3fbSopenharmony_ci	/*
118d722e3fbSopenharmony_ci	 * The G2D hw scaling factor is a normalized inverse of the scaling factor.
119d722e3fbSopenharmony_ci	 * For example: When source width is 100 and destination width is 200
120d722e3fbSopenharmony_ci	 * (scaling of 2x), then the hw factor is NC * 100 / 200.
121d722e3fbSopenharmony_ci	 * The normalization factor (NC) is 2^16 = 0x10000.
122d722e3fbSopenharmony_ci	 */
123d722e3fbSopenharmony_ci
124d722e3fbSopenharmony_ci	return ((src << 16) / dst);
125d722e3fbSopenharmony_ci}
126d722e3fbSopenharmony_ci
127d722e3fbSopenharmony_cistatic unsigned int g2d_get_blend_op(enum e_g2d_op op)
128d722e3fbSopenharmony_ci{
129d722e3fbSopenharmony_ci	union g2d_blend_func_val val;
130d722e3fbSopenharmony_ci
131d722e3fbSopenharmony_ci	val.val = 0;
132d722e3fbSopenharmony_ci
133d722e3fbSopenharmony_ci	/*
134d722e3fbSopenharmony_ci	 * The switch statement is missing the default branch since
135d722e3fbSopenharmony_ci	 * we assume that the caller checks the blending operation
136d722e3fbSopenharmony_ci	 * via g2d_validate_blending_op() first.
137d722e3fbSopenharmony_ci	 */
138d722e3fbSopenharmony_ci	switch (op) {
139d722e3fbSopenharmony_ci	case G2D_OP_CLEAR:
140d722e3fbSopenharmony_ci	case G2D_OP_DISJOINT_CLEAR:
141d722e3fbSopenharmony_ci	case G2D_OP_CONJOINT_CLEAR:
142d722e3fbSopenharmony_ci		SET_BF(val, G2D_COEFF_MODE_ZERO, 0, 0, 0, G2D_COEFF_MODE_ZERO,
143d722e3fbSopenharmony_ci				0, 0, 0);
144d722e3fbSopenharmony_ci		break;
145d722e3fbSopenharmony_ci	case G2D_OP_SRC:
146d722e3fbSopenharmony_ci	case G2D_OP_DISJOINT_SRC:
147d722e3fbSopenharmony_ci	case G2D_OP_CONJOINT_SRC:
148d722e3fbSopenharmony_ci		SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, G2D_COEFF_MODE_ZERO,
149d722e3fbSopenharmony_ci				0, 0, 0);
150d722e3fbSopenharmony_ci		break;
151d722e3fbSopenharmony_ci	case G2D_OP_DST:
152d722e3fbSopenharmony_ci	case G2D_OP_DISJOINT_DST:
153d722e3fbSopenharmony_ci	case G2D_OP_CONJOINT_DST:
154d722e3fbSopenharmony_ci		SET_BF(val, G2D_COEFF_MODE_ZERO, 0, 0, 0, G2D_COEFF_MODE_ONE,
155d722e3fbSopenharmony_ci				0, 0, 0);
156d722e3fbSopenharmony_ci		break;
157d722e3fbSopenharmony_ci	case G2D_OP_OVER:
158d722e3fbSopenharmony_ci		SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0,
159d722e3fbSopenharmony_ci				G2D_COEFF_MODE_SRC_ALPHA, 1, 0, 0);
160d722e3fbSopenharmony_ci		break;
161d722e3fbSopenharmony_ci	case G2D_OP_INTERPOLATE:
162d722e3fbSopenharmony_ci		SET_BF(val, G2D_COEFF_MODE_SRC_ALPHA, 0, 0, 0,
163d722e3fbSopenharmony_ci				G2D_COEFF_MODE_SRC_ALPHA, 1, 0, 0);
164d722e3fbSopenharmony_ci		break;
165d722e3fbSopenharmony_ci	}
166d722e3fbSopenharmony_ci
167d722e3fbSopenharmony_ci	return val.val;
168d722e3fbSopenharmony_ci}
169d722e3fbSopenharmony_ci
170d722e3fbSopenharmony_ci/*
171d722e3fbSopenharmony_ci * g2d_check_space - check if command buffers have enough space left.
172d722e3fbSopenharmony_ci *
173d722e3fbSopenharmony_ci * @ctx: a pointer to g2d_context structure.
174d722e3fbSopenharmony_ci * @num_cmds: number of (regular) commands.
175d722e3fbSopenharmony_ci * @num_gem_cmds: number of GEM commands.
176d722e3fbSopenharmony_ci */
177d722e3fbSopenharmony_cistatic unsigned int g2d_check_space(const struct g2d_context *ctx,
178d722e3fbSopenharmony_ci	unsigned int num_cmds, unsigned int num_gem_cmds)
179d722e3fbSopenharmony_ci{
180d722e3fbSopenharmony_ci	if (ctx->cmd_nr + num_cmds >= G2D_MAX_CMD_NR ||
181d722e3fbSopenharmony_ci	    ctx->cmd_buf_nr + num_gem_cmds >= G2D_MAX_GEM_CMD_NR)
182d722e3fbSopenharmony_ci		return 1;
183d722e3fbSopenharmony_ci	else
184d722e3fbSopenharmony_ci		return 0;
185d722e3fbSopenharmony_ci}
186d722e3fbSopenharmony_ci
187d722e3fbSopenharmony_ci/*
188d722e3fbSopenharmony_ci * g2d_validate_select_mode - validate select mode.
189d722e3fbSopenharmony_ci *
190d722e3fbSopenharmony_ci * @mode: the mode to validate
191d722e3fbSopenharmony_ci *
192d722e3fbSopenharmony_ci * Returns zero for an invalid mode and one otherwise.
193d722e3fbSopenharmony_ci */
194d722e3fbSopenharmony_cistatic int g2d_validate_select_mode(
195d722e3fbSopenharmony_ci	enum e_g2d_select_mode mode)
196d722e3fbSopenharmony_ci{
197d722e3fbSopenharmony_ci	switch (mode) {
198d722e3fbSopenharmony_ci	case G2D_SELECT_MODE_NORMAL:
199d722e3fbSopenharmony_ci	case G2D_SELECT_MODE_FGCOLOR:
200d722e3fbSopenharmony_ci	case G2D_SELECT_MODE_BGCOLOR:
201d722e3fbSopenharmony_ci		return 1;
202d722e3fbSopenharmony_ci	}
203d722e3fbSopenharmony_ci
204d722e3fbSopenharmony_ci	return 0;
205d722e3fbSopenharmony_ci}
206d722e3fbSopenharmony_ci
207d722e3fbSopenharmony_ci/*
208d722e3fbSopenharmony_ci * g2d_validate_blending_op - validate blending operation.
209d722e3fbSopenharmony_ci *
210d722e3fbSopenharmony_ci * @operation: the operation to validate
211d722e3fbSopenharmony_ci *
212d722e3fbSopenharmony_ci * Returns zero for an invalid mode and one otherwise.
213d722e3fbSopenharmony_ci */
214d722e3fbSopenharmony_cistatic int g2d_validate_blending_op(
215d722e3fbSopenharmony_ci	enum e_g2d_op operation)
216d722e3fbSopenharmony_ci{
217d722e3fbSopenharmony_ci	switch (operation) {
218d722e3fbSopenharmony_ci	case G2D_OP_CLEAR:
219d722e3fbSopenharmony_ci	case G2D_OP_SRC:
220d722e3fbSopenharmony_ci	case G2D_OP_DST:
221d722e3fbSopenharmony_ci	case G2D_OP_OVER:
222d722e3fbSopenharmony_ci	case G2D_OP_INTERPOLATE:
223d722e3fbSopenharmony_ci	case G2D_OP_DISJOINT_CLEAR:
224d722e3fbSopenharmony_ci	case G2D_OP_DISJOINT_SRC:
225d722e3fbSopenharmony_ci	case G2D_OP_DISJOINT_DST:
226d722e3fbSopenharmony_ci	case G2D_OP_CONJOINT_CLEAR:
227d722e3fbSopenharmony_ci	case G2D_OP_CONJOINT_SRC:
228d722e3fbSopenharmony_ci	case G2D_OP_CONJOINT_DST:
229d722e3fbSopenharmony_ci		return 1;
230d722e3fbSopenharmony_ci	}
231d722e3fbSopenharmony_ci
232d722e3fbSopenharmony_ci	return 0;
233d722e3fbSopenharmony_ci}
234d722e3fbSopenharmony_ci
235d722e3fbSopenharmony_ci/*
236d722e3fbSopenharmony_ci * g2d_add_cmd - set given command and value to user side command buffer.
237d722e3fbSopenharmony_ci *
238d722e3fbSopenharmony_ci * @ctx: a pointer to g2d_context structure.
239d722e3fbSopenharmony_ci * @cmd: command data.
240d722e3fbSopenharmony_ci * @value: value data.
241d722e3fbSopenharmony_ci *
242d722e3fbSopenharmony_ci * The caller has to make sure that the commands buffers have enough space
243d722e3fbSopenharmony_ci * left to hold the command. Use g2d_check_space() to ensure this.
244d722e3fbSopenharmony_ci */
245d722e3fbSopenharmony_cistatic void g2d_add_cmd(struct g2d_context *ctx, unsigned long cmd,
246d722e3fbSopenharmony_ci			unsigned long value)
247d722e3fbSopenharmony_ci{
248d722e3fbSopenharmony_ci	switch (cmd & ~(G2D_BUF_USERPTR)) {
249d722e3fbSopenharmony_ci	case SRC_BASE_ADDR_REG:
250d722e3fbSopenharmony_ci	case SRC_PLANE2_BASE_ADDR_REG:
251d722e3fbSopenharmony_ci	case DST_BASE_ADDR_REG:
252d722e3fbSopenharmony_ci	case DST_PLANE2_BASE_ADDR_REG:
253d722e3fbSopenharmony_ci	case PAT_BASE_ADDR_REG:
254d722e3fbSopenharmony_ci	case MASK_BASE_ADDR_REG:
255d722e3fbSopenharmony_ci		assert(ctx->cmd_buf_nr < G2D_MAX_GEM_CMD_NR);
256d722e3fbSopenharmony_ci
257d722e3fbSopenharmony_ci		ctx->cmd_buf[ctx->cmd_buf_nr].offset = cmd;
258d722e3fbSopenharmony_ci		ctx->cmd_buf[ctx->cmd_buf_nr].data = value;
259d722e3fbSopenharmony_ci		ctx->cmd_buf_nr++;
260d722e3fbSopenharmony_ci		break;
261d722e3fbSopenharmony_ci	default:
262d722e3fbSopenharmony_ci		assert(ctx->cmd_nr < G2D_MAX_CMD_NR);
263d722e3fbSopenharmony_ci
264d722e3fbSopenharmony_ci		ctx->cmd[ctx->cmd_nr].offset = cmd;
265d722e3fbSopenharmony_ci		ctx->cmd[ctx->cmd_nr].data = value;
266d722e3fbSopenharmony_ci		ctx->cmd_nr++;
267d722e3fbSopenharmony_ci		break;
268d722e3fbSopenharmony_ci	}
269d722e3fbSopenharmony_ci}
270d722e3fbSopenharmony_ci
271d722e3fbSopenharmony_ci/*
272d722e3fbSopenharmony_ci * g2d_add_base_addr - helper function to set dst/src base address register.
273d722e3fbSopenharmony_ci *
274d722e3fbSopenharmony_ci * @ctx: a pointer to g2d_context structure.
275d722e3fbSopenharmony_ci * @img: a pointer to the dst/src g2d_image structure.
276d722e3fbSopenharmony_ci * @reg: the register that should be set.
277d722e3fbSopenharmony_ci */
278d722e3fbSopenharmony_cistatic void g2d_add_base_addr(struct g2d_context *ctx, struct g2d_image *img,
279d722e3fbSopenharmony_ci			enum g2d_base_addr_reg reg)
280d722e3fbSopenharmony_ci{
281d722e3fbSopenharmony_ci	const unsigned long cmd = (reg == g2d_dst) ?
282d722e3fbSopenharmony_ci		DST_BASE_ADDR_REG : SRC_BASE_ADDR_REG;
283d722e3fbSopenharmony_ci
284d722e3fbSopenharmony_ci	if (img->buf_type == G2D_IMGBUF_USERPTR)
285d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, cmd | G2D_BUF_USERPTR,
286d722e3fbSopenharmony_ci				(unsigned long)&img->user_ptr[0]);
287d722e3fbSopenharmony_ci	else
288d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, cmd, img->bo[0]);
289d722e3fbSopenharmony_ci}
290d722e3fbSopenharmony_ci
291d722e3fbSopenharmony_ci/*
292d722e3fbSopenharmony_ci * g2d_set_direction - setup direction register (useful for overlapping blits).
293d722e3fbSopenharmony_ci *
294d722e3fbSopenharmony_ci * @ctx: a pointer to g2d_context structure.
295d722e3fbSopenharmony_ci * @dir: a pointer to the g2d_direction_val structure.
296d722e3fbSopenharmony_ci */
297d722e3fbSopenharmony_cistatic void g2d_set_direction(struct g2d_context *ctx,
298d722e3fbSopenharmony_ci			const union g2d_direction_val *dir)
299d722e3fbSopenharmony_ci{
300d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_MASK_DIRECT_REG, dir->val[0]);
301d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_PAT_DIRECT_REG, dir->val[1]);
302d722e3fbSopenharmony_ci}
303d722e3fbSopenharmony_ci
304d722e3fbSopenharmony_ci/*
305d722e3fbSopenharmony_ci * g2d_flush - submit all commands and values in user side command buffer
306d722e3fbSopenharmony_ci *		to command queue aware of fimg2d dma.
307d722e3fbSopenharmony_ci *
308d722e3fbSopenharmony_ci * @ctx: a pointer to g2d_context structure.
309d722e3fbSopenharmony_ci *
310d722e3fbSopenharmony_ci * This function should be called after all commands and values to user
311d722e3fbSopenharmony_ci * side command buffer are set. It submits that buffer to the kernel side driver.
312d722e3fbSopenharmony_ci */
313d722e3fbSopenharmony_cistatic int g2d_flush(struct g2d_context *ctx)
314d722e3fbSopenharmony_ci{
315d722e3fbSopenharmony_ci	int ret;
316d722e3fbSopenharmony_ci	struct drm_exynos_g2d_set_cmdlist cmdlist = {0};
317d722e3fbSopenharmony_ci
318d722e3fbSopenharmony_ci	if (ctx->cmd_nr == 0 && ctx->cmd_buf_nr == 0)
319d722e3fbSopenharmony_ci		return 0;
320d722e3fbSopenharmony_ci
321d722e3fbSopenharmony_ci	if (ctx->cmdlist_nr >= G2D_MAX_CMD_LIST_NR) {
322d722e3fbSopenharmony_ci		fprintf(stderr, MSG_PREFIX "command list overflow.\n");
323d722e3fbSopenharmony_ci		return -EINVAL;
324d722e3fbSopenharmony_ci	}
325d722e3fbSopenharmony_ci
326d722e3fbSopenharmony_ci	cmdlist.cmd = (uint64_t)(uintptr_t)&ctx->cmd[0];
327d722e3fbSopenharmony_ci	cmdlist.cmd_buf = (uint64_t)(uintptr_t)&ctx->cmd_buf[0];
328d722e3fbSopenharmony_ci	cmdlist.cmd_nr = ctx->cmd_nr;
329d722e3fbSopenharmony_ci	cmdlist.cmd_buf_nr = ctx->cmd_buf_nr;
330d722e3fbSopenharmony_ci
331d722e3fbSopenharmony_ci	if (ctx->event_userdata) {
332d722e3fbSopenharmony_ci		cmdlist.event_type = G2D_EVENT_NONSTOP;
333d722e3fbSopenharmony_ci		cmdlist.user_data = (uint64_t)(uintptr_t)(ctx->event_userdata);
334d722e3fbSopenharmony_ci		ctx->event_userdata = NULL;
335d722e3fbSopenharmony_ci	} else {
336d722e3fbSopenharmony_ci		cmdlist.event_type = G2D_EVENT_NOT;
337d722e3fbSopenharmony_ci		cmdlist.user_data = 0;
338d722e3fbSopenharmony_ci	}
339d722e3fbSopenharmony_ci
340d722e3fbSopenharmony_ci	ctx->cmd_nr = 0;
341d722e3fbSopenharmony_ci	ctx->cmd_buf_nr = 0;
342d722e3fbSopenharmony_ci
343d722e3fbSopenharmony_ci	ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST, &cmdlist);
344d722e3fbSopenharmony_ci	if (ret < 0) {
345d722e3fbSopenharmony_ci		fprintf(stderr, MSG_PREFIX "failed to set cmdlist.\n");
346d722e3fbSopenharmony_ci		return ret;
347d722e3fbSopenharmony_ci	}
348d722e3fbSopenharmony_ci
349d722e3fbSopenharmony_ci	ctx->cmdlist_nr++;
350d722e3fbSopenharmony_ci
351d722e3fbSopenharmony_ci	return ret;
352d722e3fbSopenharmony_ci}
353d722e3fbSopenharmony_ci
354d722e3fbSopenharmony_ci/**
355d722e3fbSopenharmony_ci * g2d_init - create a new g2d context and get hardware version.
356d722e3fbSopenharmony_ci *
357d722e3fbSopenharmony_ci * fd: a file descriptor to an opened drm device.
358d722e3fbSopenharmony_ci */
359d722e3fbSopenharmony_cidrm_public struct g2d_context *g2d_init(int fd)
360d722e3fbSopenharmony_ci{
361d722e3fbSopenharmony_ci	struct drm_exynos_g2d_get_ver ver;
362d722e3fbSopenharmony_ci	struct g2d_context *ctx;
363d722e3fbSopenharmony_ci	int ret;
364d722e3fbSopenharmony_ci
365d722e3fbSopenharmony_ci	ctx = calloc(1, sizeof(*ctx));
366d722e3fbSopenharmony_ci	if (!ctx) {
367d722e3fbSopenharmony_ci		fprintf(stderr, MSG_PREFIX "failed to allocate context.\n");
368d722e3fbSopenharmony_ci		return NULL;
369d722e3fbSopenharmony_ci	}
370d722e3fbSopenharmony_ci
371d722e3fbSopenharmony_ci	ctx->fd = fd;
372d722e3fbSopenharmony_ci
373d722e3fbSopenharmony_ci	ret = drmIoctl(fd, DRM_IOCTL_EXYNOS_G2D_GET_VER, &ver);
374d722e3fbSopenharmony_ci	if (ret < 0) {
375d722e3fbSopenharmony_ci		fprintf(stderr, MSG_PREFIX "failed to get version.\n");
376d722e3fbSopenharmony_ci		free(ctx);
377d722e3fbSopenharmony_ci		return NULL;
378d722e3fbSopenharmony_ci	}
379d722e3fbSopenharmony_ci
380d722e3fbSopenharmony_ci	ctx->major = ver.major;
381d722e3fbSopenharmony_ci	ctx->minor = ver.minor;
382d722e3fbSopenharmony_ci
383d722e3fbSopenharmony_ci	printf(MSG_PREFIX "G2D version (%d.%d).\n", ctx->major, ctx->minor);
384d722e3fbSopenharmony_ci	return ctx;
385d722e3fbSopenharmony_ci}
386d722e3fbSopenharmony_ci
387d722e3fbSopenharmony_cidrm_public void g2d_fini(struct g2d_context *ctx)
388d722e3fbSopenharmony_ci{
389d722e3fbSopenharmony_ci	free(ctx);
390d722e3fbSopenharmony_ci}
391d722e3fbSopenharmony_ci
392d722e3fbSopenharmony_ci/**
393d722e3fbSopenharmony_ci * g2d_config_event - setup userdata configuration for a g2d event.
394d722e3fbSopenharmony_ci *		The next invocation of a g2d call (e.g. g2d_solid_fill) is
395d722e3fbSopenharmony_ci *		then going to flag the command buffer as 'nonstop'.
396d722e3fbSopenharmony_ci *		Completion of the command buffer execution can then be
397d722e3fbSopenharmony_ci *		determined by using drmHandleEvent on the DRM fd.
398d722e3fbSopenharmony_ci *		The userdata is 'consumed' in the process.
399d722e3fbSopenharmony_ci *
400d722e3fbSopenharmony_ci * @ctx: a pointer to g2d_context structure.
401d722e3fbSopenharmony_ci * @userdata: a pointer to the user data
402d722e3fbSopenharmony_ci */
403d722e3fbSopenharmony_cidrm_public void g2d_config_event(struct g2d_context *ctx, void *userdata)
404d722e3fbSopenharmony_ci{
405d722e3fbSopenharmony_ci	ctx->event_userdata = userdata;
406d722e3fbSopenharmony_ci}
407d722e3fbSopenharmony_ci
408d722e3fbSopenharmony_ci/**
409d722e3fbSopenharmony_ci * g2d_exec - start the dma to process all commands summited by g2d_flush().
410d722e3fbSopenharmony_ci *
411d722e3fbSopenharmony_ci * @ctx: a pointer to g2d_context structure.
412d722e3fbSopenharmony_ci */
413d722e3fbSopenharmony_cidrm_public int g2d_exec(struct g2d_context *ctx)
414d722e3fbSopenharmony_ci{
415d722e3fbSopenharmony_ci	struct drm_exynos_g2d_exec exec;
416d722e3fbSopenharmony_ci	int ret;
417d722e3fbSopenharmony_ci
418d722e3fbSopenharmony_ci	if (ctx->cmdlist_nr == 0)
419d722e3fbSopenharmony_ci		return -EINVAL;
420d722e3fbSopenharmony_ci
421d722e3fbSopenharmony_ci	exec.async = 0;
422d722e3fbSopenharmony_ci
423d722e3fbSopenharmony_ci	ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_EXEC, &exec);
424d722e3fbSopenharmony_ci	if (ret < 0) {
425d722e3fbSopenharmony_ci		fprintf(stderr, MSG_PREFIX "failed to execute.\n");
426d722e3fbSopenharmony_ci		return ret;
427d722e3fbSopenharmony_ci	}
428d722e3fbSopenharmony_ci
429d722e3fbSopenharmony_ci	ctx->cmdlist_nr = 0;
430d722e3fbSopenharmony_ci
431d722e3fbSopenharmony_ci	return ret;
432d722e3fbSopenharmony_ci}
433d722e3fbSopenharmony_ci
434d722e3fbSopenharmony_ci/**
435d722e3fbSopenharmony_ci * g2d_solid_fill - fill given buffer with given color data.
436d722e3fbSopenharmony_ci *
437d722e3fbSopenharmony_ci * @ctx: a pointer to g2d_context structure.
438d722e3fbSopenharmony_ci * @img: a pointer to g2d_image structure including image and buffer
439d722e3fbSopenharmony_ci *	information.
440d722e3fbSopenharmony_ci * @x: x start position to buffer filled with given color data.
441d722e3fbSopenharmony_ci * @y: y start position to buffer filled with given color data.
442d722e3fbSopenharmony_ci * @w: width value to buffer filled with given color data.
443d722e3fbSopenharmony_ci * @h: height value to buffer filled with given color data.
444d722e3fbSopenharmony_ci */
445d722e3fbSopenharmony_cidrm_public int
446d722e3fbSopenharmony_cig2d_solid_fill(struct g2d_context *ctx, struct g2d_image *img,
447d722e3fbSopenharmony_ci			unsigned int x, unsigned int y, unsigned int w,
448d722e3fbSopenharmony_ci			unsigned int h)
449d722e3fbSopenharmony_ci{
450d722e3fbSopenharmony_ci	union g2d_bitblt_cmd_val bitblt;
451d722e3fbSopenharmony_ci	union g2d_point_val pt;
452d722e3fbSopenharmony_ci
453d722e3fbSopenharmony_ci	if (g2d_check_space(ctx, 7, 1))
454d722e3fbSopenharmony_ci		return -ENOSPC;
455d722e3fbSopenharmony_ci
456d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL);
457d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_COLOR_MODE_REG, img->color_mode);
458d722e3fbSopenharmony_ci	g2d_add_base_addr(ctx, img, g2d_dst);
459d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_STRIDE_REG, img->stride);
460d722e3fbSopenharmony_ci
461d722e3fbSopenharmony_ci	if (x + w > img->width)
462d722e3fbSopenharmony_ci		w = img->width - x;
463d722e3fbSopenharmony_ci	if (y + h > img->height)
464d722e3fbSopenharmony_ci		h = img->height - y;
465d722e3fbSopenharmony_ci
466d722e3fbSopenharmony_ci	pt.data.x = x;
467d722e3fbSopenharmony_ci	pt.data.y = y;
468d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val);
469d722e3fbSopenharmony_ci
470d722e3fbSopenharmony_ci	pt.data.x = x + w;
471d722e3fbSopenharmony_ci	pt.data.y = y + h;
472d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val);
473d722e3fbSopenharmony_ci
474d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SF_COLOR_REG, img->color);
475d722e3fbSopenharmony_ci
476d722e3fbSopenharmony_ci	bitblt.val = 0;
477d722e3fbSopenharmony_ci	bitblt.data.fast_solid_color_fill_en = 1;
478d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val);
479d722e3fbSopenharmony_ci
480d722e3fbSopenharmony_ci	return g2d_flush(ctx);
481d722e3fbSopenharmony_ci}
482d722e3fbSopenharmony_ci
483d722e3fbSopenharmony_ci/**
484d722e3fbSopenharmony_ci * g2d_copy - copy contents in source buffer to destination buffer.
485d722e3fbSopenharmony_ci *
486d722e3fbSopenharmony_ci * @ctx: a pointer to g2d_context structure.
487d722e3fbSopenharmony_ci * @src: a pointer to g2d_image structure including image and buffer
488d722e3fbSopenharmony_ci *	information to source.
489d722e3fbSopenharmony_ci * @dst: a pointer to g2d_image structure including image and buffer
490d722e3fbSopenharmony_ci *	information to destination.
491d722e3fbSopenharmony_ci * @src_x: x start position to source buffer.
492d722e3fbSopenharmony_ci * @src_y: y start position to source buffer.
493d722e3fbSopenharmony_ci * @dst_x: x start position to destination buffer.
494d722e3fbSopenharmony_ci * @dst_y: y start position to destination buffer.
495d722e3fbSopenharmony_ci * @w: width value to source and destination buffers.
496d722e3fbSopenharmony_ci * @h: height value to source and destination buffers.
497d722e3fbSopenharmony_ci */
498d722e3fbSopenharmony_cidrm_public int
499d722e3fbSopenharmony_cig2d_copy(struct g2d_context *ctx, struct g2d_image *src,
500d722e3fbSopenharmony_ci		struct g2d_image *dst, unsigned int src_x, unsigned int src_y,
501d722e3fbSopenharmony_ci		unsigned int dst_x, unsigned dst_y, unsigned int w,
502d722e3fbSopenharmony_ci		unsigned int h)
503d722e3fbSopenharmony_ci{
504d722e3fbSopenharmony_ci	union g2d_rop4_val rop4;
505d722e3fbSopenharmony_ci	union g2d_point_val pt;
506d722e3fbSopenharmony_ci	unsigned int src_w, src_h, dst_w, dst_h;
507d722e3fbSopenharmony_ci
508d722e3fbSopenharmony_ci	src_w = w;
509d722e3fbSopenharmony_ci	src_h = h;
510d722e3fbSopenharmony_ci	if (src_x + src->width > w)
511d722e3fbSopenharmony_ci		src_w = src->width - src_x;
512d722e3fbSopenharmony_ci	if (src_y + src->height > h)
513d722e3fbSopenharmony_ci		src_h = src->height - src_y;
514d722e3fbSopenharmony_ci
515d722e3fbSopenharmony_ci	dst_w = w;
516d722e3fbSopenharmony_ci	dst_h = w;
517d722e3fbSopenharmony_ci	if (dst_x + dst->width > w)
518d722e3fbSopenharmony_ci		dst_w = dst->width - dst_x;
519d722e3fbSopenharmony_ci	if (dst_y + dst->height > h)
520d722e3fbSopenharmony_ci		dst_h = dst->height - dst_y;
521d722e3fbSopenharmony_ci
522d722e3fbSopenharmony_ci	w = MIN(src_w, dst_w);
523d722e3fbSopenharmony_ci	h = MIN(src_h, dst_h);
524d722e3fbSopenharmony_ci
525d722e3fbSopenharmony_ci	if (w <= 0 || h <= 0) {
526d722e3fbSopenharmony_ci		fprintf(stderr, MSG_PREFIX "invalid width or height.\n");
527d722e3fbSopenharmony_ci		return -EINVAL;
528d722e3fbSopenharmony_ci	}
529d722e3fbSopenharmony_ci
530d722e3fbSopenharmony_ci	if (g2d_check_space(ctx, 11, 2))
531d722e3fbSopenharmony_ci		return -ENOSPC;
532d722e3fbSopenharmony_ci
533d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR);
534d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode);
535d722e3fbSopenharmony_ci	g2d_add_base_addr(ctx, dst, g2d_dst);
536d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride);
537d722e3fbSopenharmony_ci
538d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL);
539d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode);
540d722e3fbSopenharmony_ci	g2d_add_base_addr(ctx, src, g2d_src);
541d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride);
542d722e3fbSopenharmony_ci
543d722e3fbSopenharmony_ci	pt.data.x = src_x;
544d722e3fbSopenharmony_ci	pt.data.y = src_y;
545d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val);
546d722e3fbSopenharmony_ci	pt.data.x = src_x + w;
547d722e3fbSopenharmony_ci	pt.data.y = src_y + h;
548d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val);
549d722e3fbSopenharmony_ci
550d722e3fbSopenharmony_ci	pt.data.x = dst_x;
551d722e3fbSopenharmony_ci	pt.data.y = dst_y;
552d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val);
553d722e3fbSopenharmony_ci	pt.data.x = dst_x + w;
554d722e3fbSopenharmony_ci	pt.data.y = dst_y + h;
555d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val);
556d722e3fbSopenharmony_ci
557d722e3fbSopenharmony_ci	rop4.val = 0;
558d722e3fbSopenharmony_ci	rop4.data.unmasked_rop3 = G2D_ROP3_SRC;
559d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, ROP4_REG, rop4.val);
560d722e3fbSopenharmony_ci
561d722e3fbSopenharmony_ci	return g2d_flush(ctx);
562d722e3fbSopenharmony_ci}
563d722e3fbSopenharmony_ci
564d722e3fbSopenharmony_ci/**
565d722e3fbSopenharmony_ci * g2d_move - copy content inside single buffer.
566d722e3fbSopenharmony_ci *	Similar to libc's memmove() this copies a rectangular
567d722e3fbSopenharmony_ci *	region of the provided buffer to another location, while
568d722e3fbSopenharmony_ci *	properly handling the situation where source and
569d722e3fbSopenharmony_ci *	destination rectangle overlap.
570d722e3fbSopenharmony_ci *
571d722e3fbSopenharmony_ci * @ctx: a pointer to g2d_context structure.
572d722e3fbSopenharmony_ci * @img: a pointer to g2d_image structure providing
573d722e3fbSopenharmony_ci *	buffer information.
574d722e3fbSopenharmony_ci * @src_x: x position of source rectangle.
575d722e3fbSopenharmony_ci * @src_y: y position of source rectangle.
576d722e3fbSopenharmony_ci * @dst_x: x position of destination rectangle.
577d722e3fbSopenharmony_ci * @dst_y: y position of destination rectangle.
578d722e3fbSopenharmony_ci * @w: width of rectangle to move.
579d722e3fbSopenharmony_ci * @h: height of rectangle to move.
580d722e3fbSopenharmony_ci */
581d722e3fbSopenharmony_cidrm_public int
582d722e3fbSopenharmony_cig2d_move(struct g2d_context *ctx, struct g2d_image *img,
583d722e3fbSopenharmony_ci		unsigned int src_x, unsigned int src_y,
584d722e3fbSopenharmony_ci		unsigned int dst_x, unsigned dst_y, unsigned int w,
585d722e3fbSopenharmony_ci		unsigned int h)
586d722e3fbSopenharmony_ci{
587d722e3fbSopenharmony_ci	union g2d_rop4_val rop4;
588d722e3fbSopenharmony_ci	union g2d_point_val pt;
589d722e3fbSopenharmony_ci	union g2d_direction_val dir;
590d722e3fbSopenharmony_ci	unsigned int src_w, src_h, dst_w, dst_h;
591d722e3fbSopenharmony_ci
592d722e3fbSopenharmony_ci	src_w = w;
593d722e3fbSopenharmony_ci	src_h = h;
594d722e3fbSopenharmony_ci	if (src_x + img->width > w)
595d722e3fbSopenharmony_ci		src_w = img->width - src_x;
596d722e3fbSopenharmony_ci	if (src_y + img->height > h)
597d722e3fbSopenharmony_ci		src_h = img->height - src_y;
598d722e3fbSopenharmony_ci
599d722e3fbSopenharmony_ci	dst_w = w;
600d722e3fbSopenharmony_ci	dst_h = w;
601d722e3fbSopenharmony_ci	if (dst_x + img->width > w)
602d722e3fbSopenharmony_ci		dst_w = img->width - dst_x;
603d722e3fbSopenharmony_ci	if (dst_y + img->height > h)
604d722e3fbSopenharmony_ci		dst_h = img->height - dst_y;
605d722e3fbSopenharmony_ci
606d722e3fbSopenharmony_ci	w = MIN(src_w, dst_w);
607d722e3fbSopenharmony_ci	h = MIN(src_h, dst_h);
608d722e3fbSopenharmony_ci
609d722e3fbSopenharmony_ci	if (w == 0 || h == 0) {
610d722e3fbSopenharmony_ci		fprintf(stderr, MSG_PREFIX "invalid width or height.\n");
611d722e3fbSopenharmony_ci		return -EINVAL;
612d722e3fbSopenharmony_ci	}
613d722e3fbSopenharmony_ci
614d722e3fbSopenharmony_ci	if (g2d_check_space(ctx, 13, 2))
615d722e3fbSopenharmony_ci		return -ENOSPC;
616d722e3fbSopenharmony_ci
617d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR);
618d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL);
619d722e3fbSopenharmony_ci
620d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_COLOR_MODE_REG, img->color_mode);
621d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, img->color_mode);
622d722e3fbSopenharmony_ci
623d722e3fbSopenharmony_ci	g2d_add_base_addr(ctx, img, g2d_dst);
624d722e3fbSopenharmony_ci	g2d_add_base_addr(ctx, img, g2d_src);
625d722e3fbSopenharmony_ci
626d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_STRIDE_REG, img->stride);
627d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_STRIDE_REG, img->stride);
628d722e3fbSopenharmony_ci
629d722e3fbSopenharmony_ci	dir.val[0] = dir.val[1] = 0;
630d722e3fbSopenharmony_ci
631d722e3fbSopenharmony_ci	if (dst_x >= src_x)
632d722e3fbSopenharmony_ci		dir.data.src_x_direction = dir.data.dst_x_direction = 1;
633d722e3fbSopenharmony_ci	if (dst_y >= src_y)
634d722e3fbSopenharmony_ci		dir.data.src_y_direction = dir.data.dst_y_direction = 1;
635d722e3fbSopenharmony_ci
636d722e3fbSopenharmony_ci	g2d_set_direction(ctx, &dir);
637d722e3fbSopenharmony_ci
638d722e3fbSopenharmony_ci	pt.data.x = src_x;
639d722e3fbSopenharmony_ci	pt.data.y = src_y;
640d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val);
641d722e3fbSopenharmony_ci	pt.data.x = src_x + w;
642d722e3fbSopenharmony_ci	pt.data.y = src_y + h;
643d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val);
644d722e3fbSopenharmony_ci
645d722e3fbSopenharmony_ci	pt.data.x = dst_x;
646d722e3fbSopenharmony_ci	pt.data.y = dst_y;
647d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val);
648d722e3fbSopenharmony_ci	pt.data.x = dst_x + w;
649d722e3fbSopenharmony_ci	pt.data.y = dst_y + h;
650d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val);
651d722e3fbSopenharmony_ci
652d722e3fbSopenharmony_ci	rop4.val = 0;
653d722e3fbSopenharmony_ci	rop4.data.unmasked_rop3 = G2D_ROP3_SRC;
654d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, ROP4_REG, rop4.val);
655d722e3fbSopenharmony_ci
656d722e3fbSopenharmony_ci	return g2d_flush(ctx);
657d722e3fbSopenharmony_ci}
658d722e3fbSopenharmony_ci
659d722e3fbSopenharmony_ci/**
660d722e3fbSopenharmony_ci * g2d_copy_with_scale - copy contents in source buffer to destination buffer
661d722e3fbSopenharmony_ci *	scaling up or down properly.
662d722e3fbSopenharmony_ci *
663d722e3fbSopenharmony_ci * @ctx: a pointer to g2d_context structure.
664d722e3fbSopenharmony_ci * @src: a pointer to g2d_image structure including image and buffer
665d722e3fbSopenharmony_ci *	information to source.
666d722e3fbSopenharmony_ci * @dst: a pointer to g2d_image structure including image and buffer
667d722e3fbSopenharmony_ci *	information to destination.
668d722e3fbSopenharmony_ci * @src_x: x start position to source buffer.
669d722e3fbSopenharmony_ci * @src_y: y start position to source buffer.
670d722e3fbSopenharmony_ci * @src_w: width value to source buffer.
671d722e3fbSopenharmony_ci * @src_h: height value to source buffer.
672d722e3fbSopenharmony_ci * @dst_x: x start position to destination buffer.
673d722e3fbSopenharmony_ci * @dst_y: y start position to destination buffer.
674d722e3fbSopenharmony_ci * @dst_w: width value to destination buffer.
675d722e3fbSopenharmony_ci * @dst_h: height value to destination buffer.
676d722e3fbSopenharmony_ci * @negative: indicate that it uses color negative to source and
677d722e3fbSopenharmony_ci *	destination buffers.
678d722e3fbSopenharmony_ci */
679d722e3fbSopenharmony_cidrm_public int
680d722e3fbSopenharmony_cig2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src,
681d722e3fbSopenharmony_ci				struct g2d_image *dst, unsigned int src_x,
682d722e3fbSopenharmony_ci				unsigned int src_y, unsigned int src_w,
683d722e3fbSopenharmony_ci				unsigned int src_h, unsigned int dst_x,
684d722e3fbSopenharmony_ci				unsigned int dst_y, unsigned int dst_w,
685d722e3fbSopenharmony_ci				unsigned int dst_h, unsigned int negative)
686d722e3fbSopenharmony_ci{
687d722e3fbSopenharmony_ci	union g2d_rop4_val rop4;
688d722e3fbSopenharmony_ci	union g2d_point_val pt;
689d722e3fbSopenharmony_ci	unsigned int scale, repeat_pad;
690d722e3fbSopenharmony_ci	unsigned int scale_x, scale_y;
691d722e3fbSopenharmony_ci
692d722e3fbSopenharmony_ci	/* Sanitize this parameter to facilitate space computation below. */
693d722e3fbSopenharmony_ci	if (negative)
694d722e3fbSopenharmony_ci		negative = 1;
695d722e3fbSopenharmony_ci
696d722e3fbSopenharmony_ci	if (src_w == dst_w && src_h == dst_h)
697d722e3fbSopenharmony_ci		scale = 0;
698d722e3fbSopenharmony_ci	else {
699d722e3fbSopenharmony_ci		scale = 1;
700d722e3fbSopenharmony_ci		scale_x = g2d_get_scaling(src_w, dst_w);
701d722e3fbSopenharmony_ci		scale_y = g2d_get_scaling(src_h, dst_h);
702d722e3fbSopenharmony_ci	}
703d722e3fbSopenharmony_ci
704d722e3fbSopenharmony_ci	repeat_pad = src->repeat_mode == G2D_REPEAT_MODE_PAD ? 1 : 0;
705d722e3fbSopenharmony_ci
706d722e3fbSopenharmony_ci	if (src_x + src_w > src->width)
707d722e3fbSopenharmony_ci		src_w = src->width - src_x;
708d722e3fbSopenharmony_ci	if (src_y + src_h > src->height)
709d722e3fbSopenharmony_ci		src_h = src->height - src_y;
710d722e3fbSopenharmony_ci
711d722e3fbSopenharmony_ci	if (dst_x + dst_w > dst->width)
712d722e3fbSopenharmony_ci		dst_w = dst->width - dst_x;
713d722e3fbSopenharmony_ci	if (dst_y + dst_h > dst->height)
714d722e3fbSopenharmony_ci		dst_h = dst->height - dst_y;
715d722e3fbSopenharmony_ci
716d722e3fbSopenharmony_ci	if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) {
717d722e3fbSopenharmony_ci		fprintf(stderr, MSG_PREFIX "invalid width or height.\n");
718d722e3fbSopenharmony_ci		return -EINVAL;
719d722e3fbSopenharmony_ci	}
720d722e3fbSopenharmony_ci
721d722e3fbSopenharmony_ci	if (g2d_check_space(ctx, 12 + scale * 3 + negative + repeat_pad, 2))
722d722e3fbSopenharmony_ci		return -ENOSPC;
723d722e3fbSopenharmony_ci
724d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR);
725d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode);
726d722e3fbSopenharmony_ci	g2d_add_base_addr(ctx, dst, g2d_dst);
727d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride);
728d722e3fbSopenharmony_ci
729d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL);
730d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode);
731d722e3fbSopenharmony_ci
732d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_REPEAT_MODE_REG, src->repeat_mode);
733d722e3fbSopenharmony_ci	if (repeat_pad)
734d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, SRC_PAD_VALUE_REG, dst->color);
735d722e3fbSopenharmony_ci
736d722e3fbSopenharmony_ci	g2d_add_base_addr(ctx, src, g2d_src);
737d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride);
738d722e3fbSopenharmony_ci
739d722e3fbSopenharmony_ci	rop4.val = 0;
740d722e3fbSopenharmony_ci	rop4.data.unmasked_rop3 = G2D_ROP3_SRC;
741d722e3fbSopenharmony_ci
742d722e3fbSopenharmony_ci	if (negative) {
743d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, BG_COLOR_REG, 0x00FFFFFF);
744d722e3fbSopenharmony_ci		rop4.data.unmasked_rop3 ^= G2D_ROP3_DST;
745d722e3fbSopenharmony_ci	}
746d722e3fbSopenharmony_ci
747d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, ROP4_REG, rop4.val);
748d722e3fbSopenharmony_ci
749d722e3fbSopenharmony_ci	if (scale) {
750d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, SRC_SCALE_CTRL_REG, G2D_SCALE_MODE_BILINEAR);
751d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, SRC_XSCALE_REG, scale_x);
752d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, SRC_YSCALE_REG, scale_y);
753d722e3fbSopenharmony_ci	}
754d722e3fbSopenharmony_ci
755d722e3fbSopenharmony_ci	pt.data.x = src_x;
756d722e3fbSopenharmony_ci	pt.data.y = src_y;
757d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val);
758d722e3fbSopenharmony_ci	pt.data.x = src_x + src_w;
759d722e3fbSopenharmony_ci	pt.data.y = src_y + src_h;
760d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val);
761d722e3fbSopenharmony_ci
762d722e3fbSopenharmony_ci	pt.data.x = dst_x;
763d722e3fbSopenharmony_ci	pt.data.y = dst_y;
764d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val);
765d722e3fbSopenharmony_ci	pt.data.x = dst_x + dst_w;
766d722e3fbSopenharmony_ci	pt.data.y = dst_y + dst_h;
767d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val);
768d722e3fbSopenharmony_ci
769d722e3fbSopenharmony_ci	return g2d_flush(ctx);
770d722e3fbSopenharmony_ci}
771d722e3fbSopenharmony_ci
772d722e3fbSopenharmony_ci/**
773d722e3fbSopenharmony_ci * g2d_blend - blend image data in source and destination buffers.
774d722e3fbSopenharmony_ci *
775d722e3fbSopenharmony_ci * @ctx: a pointer to g2d_context structure.
776d722e3fbSopenharmony_ci * @src: a pointer to g2d_image structure including image and buffer
777d722e3fbSopenharmony_ci *	information to source.
778d722e3fbSopenharmony_ci * @dst: a pointer to g2d_image structure including image and buffer
779d722e3fbSopenharmony_ci *	information to destination.
780d722e3fbSopenharmony_ci * @src_x: x start position to source buffer.
781d722e3fbSopenharmony_ci * @src_y: y start position to source buffer.
782d722e3fbSopenharmony_ci * @dst_x: x start position to destination buffer.
783d722e3fbSopenharmony_ci * @dst_y: y start position to destination buffer.
784d722e3fbSopenharmony_ci * @w: width value to source and destination buffer.
785d722e3fbSopenharmony_ci * @h: height value to source and destination buffer.
786d722e3fbSopenharmony_ci * @op: blend operation type.
787d722e3fbSopenharmony_ci */
788d722e3fbSopenharmony_cidrm_public int
789d722e3fbSopenharmony_cig2d_blend(struct g2d_context *ctx, struct g2d_image *src,
790d722e3fbSopenharmony_ci		struct g2d_image *dst, unsigned int src_x,
791d722e3fbSopenharmony_ci		unsigned int src_y, unsigned int dst_x, unsigned int dst_y,
792d722e3fbSopenharmony_ci		unsigned int w, unsigned int h, enum e_g2d_op op)
793d722e3fbSopenharmony_ci{
794d722e3fbSopenharmony_ci	union g2d_point_val pt;
795d722e3fbSopenharmony_ci	union g2d_bitblt_cmd_val bitblt;
796d722e3fbSopenharmony_ci	union g2d_blend_func_val blend;
797d722e3fbSopenharmony_ci	unsigned int gem_space;
798d722e3fbSopenharmony_ci	unsigned int src_w, src_h, dst_w, dst_h;
799d722e3fbSopenharmony_ci
800d722e3fbSopenharmony_ci	src_w = w;
801d722e3fbSopenharmony_ci	src_h = h;
802d722e3fbSopenharmony_ci	if (src_x + w > src->width)
803d722e3fbSopenharmony_ci		src_w = src->width - src_x;
804d722e3fbSopenharmony_ci	if (src_y + h > src->height)
805d722e3fbSopenharmony_ci		src_h = src->height - src_y;
806d722e3fbSopenharmony_ci
807d722e3fbSopenharmony_ci	dst_w = w;
808d722e3fbSopenharmony_ci	dst_h = h;
809d722e3fbSopenharmony_ci	if (dst_x + w > dst->width)
810d722e3fbSopenharmony_ci		dst_w = dst->width - dst_x;
811d722e3fbSopenharmony_ci	if (dst_y + h > dst->height)
812d722e3fbSopenharmony_ci		dst_h = dst->height - dst_y;
813d722e3fbSopenharmony_ci
814d722e3fbSopenharmony_ci	w = MIN(src_w, dst_w);
815d722e3fbSopenharmony_ci	h = MIN(src_h, dst_h);
816d722e3fbSopenharmony_ci
817d722e3fbSopenharmony_ci	if (w <= 0 || h <= 0) {
818d722e3fbSopenharmony_ci		fprintf(stderr, MSG_PREFIX "invalid width or height.\n");
819d722e3fbSopenharmony_ci		return -EINVAL;
820d722e3fbSopenharmony_ci	}
821d722e3fbSopenharmony_ci
822d722e3fbSopenharmony_ci	if (!g2d_validate_select_mode(src->select_mode)) {
823d722e3fbSopenharmony_ci		fprintf(stderr , MSG_PREFIX "invalid select mode for source.\n");
824d722e3fbSopenharmony_ci		return -EINVAL;
825d722e3fbSopenharmony_ci	}
826d722e3fbSopenharmony_ci
827d722e3fbSopenharmony_ci	if (!g2d_validate_blending_op(op)) {
828d722e3fbSopenharmony_ci		fprintf(stderr , MSG_PREFIX "unsupported blending operation.\n");
829d722e3fbSopenharmony_ci		return -EINVAL;
830d722e3fbSopenharmony_ci	}
831d722e3fbSopenharmony_ci
832d722e3fbSopenharmony_ci	gem_space = src->select_mode == G2D_SELECT_MODE_NORMAL ? 2 : 1;
833d722e3fbSopenharmony_ci
834d722e3fbSopenharmony_ci	if (g2d_check_space(ctx, 12, gem_space))
835d722e3fbSopenharmony_ci		return -ENOSPC;
836d722e3fbSopenharmony_ci
837d722e3fbSopenharmony_ci	bitblt.val = 0;
838d722e3fbSopenharmony_ci	blend.val = 0;
839d722e3fbSopenharmony_ci
840d722e3fbSopenharmony_ci	if (op == G2D_OP_SRC || op == G2D_OP_CLEAR)
841d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR);
842d722e3fbSopenharmony_ci	else
843d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL);
844d722e3fbSopenharmony_ci
845d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode);
846d722e3fbSopenharmony_ci	g2d_add_base_addr(ctx, dst, g2d_dst);
847d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride);
848d722e3fbSopenharmony_ci
849d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_SELECT_REG, src->select_mode);
850d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode);
851d722e3fbSopenharmony_ci
852d722e3fbSopenharmony_ci	switch (src->select_mode) {
853d722e3fbSopenharmony_ci	case G2D_SELECT_MODE_NORMAL:
854d722e3fbSopenharmony_ci		g2d_add_base_addr(ctx, src, g2d_src);
855d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride);
856d722e3fbSopenharmony_ci		break;
857d722e3fbSopenharmony_ci	case G2D_SELECT_MODE_FGCOLOR:
858d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, FG_COLOR_REG, src->color);
859d722e3fbSopenharmony_ci		break;
860d722e3fbSopenharmony_ci	case G2D_SELECT_MODE_BGCOLOR:
861d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, BG_COLOR_REG, src->color);
862d722e3fbSopenharmony_ci		break;
863d722e3fbSopenharmony_ci	}
864d722e3fbSopenharmony_ci
865d722e3fbSopenharmony_ci	bitblt.data.alpha_blend_mode = G2D_ALPHA_BLEND_MODE_ENABLE;
866d722e3fbSopenharmony_ci	blend.val = g2d_get_blend_op(op);
867d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val);
868d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, BLEND_FUNCTION_REG, blend.val);
869d722e3fbSopenharmony_ci
870d722e3fbSopenharmony_ci	pt.data.x = src_x;
871d722e3fbSopenharmony_ci	pt.data.y = src_y;
872d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val);
873d722e3fbSopenharmony_ci	pt.data.x = src_x + w;
874d722e3fbSopenharmony_ci	pt.data.y = src_y + h;
875d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val);
876d722e3fbSopenharmony_ci
877d722e3fbSopenharmony_ci	pt.data.x = dst_x;
878d722e3fbSopenharmony_ci	pt.data.y = dst_y;
879d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val);
880d722e3fbSopenharmony_ci	pt.data.x = dst_x + w;
881d722e3fbSopenharmony_ci	pt.data.y = dst_y + h;
882d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val);
883d722e3fbSopenharmony_ci
884d722e3fbSopenharmony_ci	return g2d_flush(ctx);
885d722e3fbSopenharmony_ci}
886d722e3fbSopenharmony_ci
887d722e3fbSopenharmony_ci/**
888d722e3fbSopenharmony_ci * g2d_scale_and_blend - apply scaling to source buffer and then blend to destination buffer
889d722e3fbSopenharmony_ci *
890d722e3fbSopenharmony_ci * @ctx: a pointer to g2d_context structure.
891d722e3fbSopenharmony_ci * @src: a pointer to g2d_image structure including image and buffer
892d722e3fbSopenharmony_ci *	information to source.
893d722e3fbSopenharmony_ci * @dst: a pointer to g2d_image structure including image and buffer
894d722e3fbSopenharmony_ci *	information to destination.
895d722e3fbSopenharmony_ci * @src_x: x start position to source buffer.
896d722e3fbSopenharmony_ci * @src_y: y start position to source buffer.
897d722e3fbSopenharmony_ci * @src_w: width value to source buffer.
898d722e3fbSopenharmony_ci * @src_h: height value to source buffer.
899d722e3fbSopenharmony_ci * @dst_x: x start position to destination buffer.
900d722e3fbSopenharmony_ci * @dst_y: y start position to destination buffer.
901d722e3fbSopenharmony_ci * @dst_w: width value to destination buffer.
902d722e3fbSopenharmony_ci * @dst_h: height value to destination buffer.
903d722e3fbSopenharmony_ci * @op: blend operation type.
904d722e3fbSopenharmony_ci */
905d722e3fbSopenharmony_cidrm_public int
906d722e3fbSopenharmony_cig2d_scale_and_blend(struct g2d_context *ctx, struct g2d_image *src,
907d722e3fbSopenharmony_ci		struct g2d_image *dst, unsigned int src_x, unsigned int src_y,
908d722e3fbSopenharmony_ci		unsigned int src_w, unsigned int src_h, unsigned int dst_x,
909d722e3fbSopenharmony_ci		unsigned int dst_y, unsigned int dst_w, unsigned int dst_h,
910d722e3fbSopenharmony_ci		enum e_g2d_op op)
911d722e3fbSopenharmony_ci{
912d722e3fbSopenharmony_ci	union g2d_point_val pt;
913d722e3fbSopenharmony_ci	union g2d_bitblt_cmd_val bitblt;
914d722e3fbSopenharmony_ci	union g2d_blend_func_val blend;
915d722e3fbSopenharmony_ci	unsigned int scale, gem_space;
916d722e3fbSopenharmony_ci	unsigned int scale_x, scale_y;
917d722e3fbSopenharmony_ci
918d722e3fbSopenharmony_ci	if (src_w == dst_w && src_h == dst_h)
919d722e3fbSopenharmony_ci		scale = 0;
920d722e3fbSopenharmony_ci	else {
921d722e3fbSopenharmony_ci		scale = 1;
922d722e3fbSopenharmony_ci		scale_x = g2d_get_scaling(src_w, dst_w);
923d722e3fbSopenharmony_ci		scale_y = g2d_get_scaling(src_h, dst_h);
924d722e3fbSopenharmony_ci	}
925d722e3fbSopenharmony_ci
926d722e3fbSopenharmony_ci	if (src_x + src_w > src->width)
927d722e3fbSopenharmony_ci		src_w = src->width - src_x;
928d722e3fbSopenharmony_ci	if (src_y + src_h > src->height)
929d722e3fbSopenharmony_ci		src_h = src->height - src_y;
930d722e3fbSopenharmony_ci
931d722e3fbSopenharmony_ci	if (dst_x + dst_w > dst->width)
932d722e3fbSopenharmony_ci		dst_w = dst->width - dst_x;
933d722e3fbSopenharmony_ci	if (dst_y + dst_h > dst->height)
934d722e3fbSopenharmony_ci		dst_h = dst->height - dst_y;
935d722e3fbSopenharmony_ci
936d722e3fbSopenharmony_ci	if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) {
937d722e3fbSopenharmony_ci		fprintf(stderr, MSG_PREFIX "invalid width or height.\n");
938d722e3fbSopenharmony_ci		return -EINVAL;
939d722e3fbSopenharmony_ci	}
940d722e3fbSopenharmony_ci
941d722e3fbSopenharmony_ci	if (!g2d_validate_select_mode(src->select_mode)) {
942d722e3fbSopenharmony_ci		fprintf(stderr , MSG_PREFIX "invalid select mode for source.\n");
943d722e3fbSopenharmony_ci		return -EINVAL;
944d722e3fbSopenharmony_ci	}
945d722e3fbSopenharmony_ci
946d722e3fbSopenharmony_ci	if (!g2d_validate_blending_op(op)) {
947d722e3fbSopenharmony_ci		fprintf(stderr , MSG_PREFIX "unsupported blending operation.\n");
948d722e3fbSopenharmony_ci		return -EINVAL;
949d722e3fbSopenharmony_ci	}
950d722e3fbSopenharmony_ci
951d722e3fbSopenharmony_ci	gem_space = src->select_mode == G2D_SELECT_MODE_NORMAL ? 2 : 1;
952d722e3fbSopenharmony_ci
953d722e3fbSopenharmony_ci	if (g2d_check_space(ctx, 12 + scale * 3, gem_space))
954d722e3fbSopenharmony_ci		return -ENOSPC;
955d722e3fbSopenharmony_ci
956d722e3fbSopenharmony_ci	bitblt.val = 0;
957d722e3fbSopenharmony_ci	blend.val = 0;
958d722e3fbSopenharmony_ci
959d722e3fbSopenharmony_ci	if (op == G2D_OP_SRC || op == G2D_OP_CLEAR)
960d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR);
961d722e3fbSopenharmony_ci	else
962d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL);
963d722e3fbSopenharmony_ci
964d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode);
965d722e3fbSopenharmony_ci	g2d_add_base_addr(ctx, dst, g2d_dst);
966d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride);
967d722e3fbSopenharmony_ci
968d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_SELECT_REG, src->select_mode);
969d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode);
970d722e3fbSopenharmony_ci
971d722e3fbSopenharmony_ci	switch (src->select_mode) {
972d722e3fbSopenharmony_ci	case G2D_SELECT_MODE_NORMAL:
973d722e3fbSopenharmony_ci		g2d_add_base_addr(ctx, src, g2d_src);
974d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride);
975d722e3fbSopenharmony_ci		break;
976d722e3fbSopenharmony_ci	case G2D_SELECT_MODE_FGCOLOR:
977d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, FG_COLOR_REG, src->color);
978d722e3fbSopenharmony_ci		break;
979d722e3fbSopenharmony_ci	case G2D_SELECT_MODE_BGCOLOR:
980d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, BG_COLOR_REG, src->color);
981d722e3fbSopenharmony_ci		break;
982d722e3fbSopenharmony_ci	}
983d722e3fbSopenharmony_ci
984d722e3fbSopenharmony_ci	if (scale) {
985d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, SRC_SCALE_CTRL_REG, G2D_SCALE_MODE_BILINEAR);
986d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, SRC_XSCALE_REG, scale_x);
987d722e3fbSopenharmony_ci		g2d_add_cmd(ctx, SRC_YSCALE_REG, scale_y);
988d722e3fbSopenharmony_ci	}
989d722e3fbSopenharmony_ci
990d722e3fbSopenharmony_ci	bitblt.data.alpha_blend_mode = G2D_ALPHA_BLEND_MODE_ENABLE;
991d722e3fbSopenharmony_ci	blend.val = g2d_get_blend_op(op);
992d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val);
993d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, BLEND_FUNCTION_REG, blend.val);
994d722e3fbSopenharmony_ci
995d722e3fbSopenharmony_ci	pt.data.x = src_x;
996d722e3fbSopenharmony_ci	pt.data.y = src_y;
997d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val);
998d722e3fbSopenharmony_ci	pt.data.x = src_x + src_w;
999d722e3fbSopenharmony_ci	pt.data.y = src_y + src_h;
1000d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val);
1001d722e3fbSopenharmony_ci
1002d722e3fbSopenharmony_ci	pt.data.x = dst_x;
1003d722e3fbSopenharmony_ci	pt.data.y = dst_y;
1004d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val);
1005d722e3fbSopenharmony_ci	pt.data.x = dst_x + dst_w;
1006d722e3fbSopenharmony_ci	pt.data.y = dst_y + dst_h;
1007d722e3fbSopenharmony_ci	g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val);
1008d722e3fbSopenharmony_ci
1009d722e3fbSopenharmony_ci	return g2d_flush(ctx);
1010d722e3fbSopenharmony_ci}
1011