1 /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2 /*
3 * Copyright (c) 2015 Rockchip Electronics Co., Ltd.
4 */
5
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <sys/ioctl.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <stdint.h>
12
13 #include "mpp_mem.h"
14 #include "mpp_debug.h"
15 #include "mpp_common.h"
16
17 #include "rga.h"
18 #include "rga_api.h"
19
20 static RK_U32 rga_debug = 0;
21
22 #define RGB_DBG_FUNCTION (0x00000001)
23 #define RGB_DBG_COPY (0x00000002)
24 #define RGB_DBG_DUP_FIELD (0x00000004)
25
26 #define rga_dbg(flag, fmt, ...) _mpp_dbg(rga_debug, flag, fmt, ## __VA_ARGS__)
27 #define rga_dbg_func(fmt, ...) _mpp_dbg_f(rga_debug, RGB_DBG_FUNCTION, fmt, ## __VA_ARGS__)
28 #define rga_dbg_copy(fmt, ...) _mpp_dbg(rga_debug, RGB_DBG_COPY, fmt, ## __VA_ARGS__)
29 #define rga_dbg_dup(fmt, ...) _mpp_dbg(rga_debug, RGB_DBG_COPY, fmt, ## __VA_ARGS__)
30
31 #define DEFAULT_RGA_DEV "/dev/rga"
32
33 typedef struct RgaCtxImpl_t {
34 RK_S32 rga_fd;
35
36 // context holds only one request structure and serial process all input
37 RgaReq request;
38 } RgaCtxImpl;
39
is_yuv_format(int fmt)40 static int is_yuv_format(int fmt)
41 {
42 if (fmt >= RGA_FMT_YCbCr_422_SP && fmt <= RGA_FMT_YCrCb_420_P) {
43 return 1;
44 }
45
46 return 0;
47 }
48
is_rgb_format(int fmt)49 static int is_rgb_format(int fmt)
50 {
51 if (fmt >= RGA_FMT_RGBA_8888 && fmt <= RGA_FMT_BGR_888) {
52 return 1;
53 }
54
55 return 0;
56 }
57
rga_fmt_map(MppFrameFormat fmt)58 static RgaFormat rga_fmt_map(MppFrameFormat fmt)
59 {
60 RgaFormat ret;
61
62 switch (fmt) {
63 case MPP_FMT_YUV420P:
64 ret = RGA_FMT_YCbCr_420_P;
65 break;
66 case MPP_FMT_YUV420SP:
67 ret = RGA_FMT_YCbCr_420_SP;
68 break;
69 case MPP_FMT_YUV422P:
70 ret = RGA_FMT_YCbCr_422_P;
71 break;
72 case MPP_FMT_YUV422SP:
73 ret = RGA_FMT_YCrCb_422_SP;
74 break;
75 case MPP_FMT_RGB565:
76 ret = RGA_FMT_RGB_565;
77 break;
78 case MPP_FMT_RGB888:
79 ret = RGA_FMT_RGB_888;
80 break;
81 case MPP_FMT_ARGB8888:
82 ret = RGA_FMT_RGBA_8888;
83 break;
84 default:
85 ret = RGA_FMT_BUTT;
86 mpp_err("unsupport mpp fmt %d found\n", fmt);
87 break;
88 }
89
90 return ret;
91 }
92
rga_init(RgaCtx * ctx)93 MPP_RET rga_init(RgaCtx *ctx)
94 {
95 MPP_RET ret = MPP_OK;
96 RgaCtxImpl *impl = NULL;
97
98 rga_dbg_func("in\n");
99
100 *ctx = NULL;
101
102 impl = mpp_malloc(RgaCtxImpl, 1);
103 if (!impl) {
104 mpp_err_f("malloc context failed\n");
105 ret = MPP_ERR_NULL_PTR;
106 goto END;
107 }
108
109 impl->rga_fd = open(DEFAULT_RGA_DEV, O_RDWR | O_CLOEXEC, 0);
110 if (impl->rga_fd < 0) {
111 mpp_err_f("open device failed\n");
112 mpp_free(impl);
113 impl = NULL;
114 ret = MPP_ERR_OPEN_FILE;
115 goto END;
116 }
117
118 END:
119 *ctx = impl;
120 rga_dbg_func("out\n");
121 return ret;
122 }
123
rga_deinit(RgaCtx ctx)124 MPP_RET rga_deinit(RgaCtx ctx)
125 {
126 MPP_RET ret = MPP_OK;
127 RgaCtxImpl *impl = NULL;
128
129 rga_dbg_func("in\n");
130
131 impl = (RgaCtxImpl *)ctx;
132 if (!impl) {
133 mpp_err_f("invalid input");
134 ret = MPP_ERR_NULL_PTR;
135 goto END;
136 }
137
138 if (impl->rga_fd >= 0) {
139 close(impl->rga_fd);
140 impl->rga_fd = -1;
141 }
142
143 mpp_free(impl);
144 END:
145 rga_dbg_func("out\n");
146 return ret;
147 }
148
rga_ioctl(RgaCtxImpl * impl)149 static MPP_RET rga_ioctl(RgaCtxImpl *impl)
150 {
151 int io_ret = ioctl(impl->rga_fd, RGA_BLIT_SYNC, &impl->request);
152 if (io_ret) {
153 mpp_err("rga ioctl failed errno:%d %s", errno, strerror(errno));
154 return MPP_NOK;
155 }
156
157 return MPP_OK;
158 }
159
config_rga_image(RgaImg * img,MppFrame frame)160 static MPP_RET config_rga_image(RgaImg *img, MppFrame frame)
161 {
162 RgaFormat fmt = rga_fmt_map(mpp_frame_get_fmt(frame));
163 MppBuffer buf = mpp_frame_get_buffer(frame);
164 RK_U32 width = mpp_frame_get_width(frame);
165 RK_U32 height = mpp_frame_get_height(frame);
166 RK_U32 h_str = mpp_frame_get_hor_stride(frame);
167 RK_U32 v_str = mpp_frame_get_ver_stride(frame);
168 RK_S32 fd = mpp_buffer_get_fd(buf);
169
170 if (fmt >= RGA_FMT_BUTT) {
171 mpp_err("invalid input format for rga process %d\n", fmt);
172 return MPP_NOK;
173 }
174
175 memset(img, 0, sizeof(RgaImg));
176 img->yrgb_addr = fd;
177 img->format = (RK_U32)fmt;
178 img->act_w = width;
179 img->act_h = height;
180 img->vir_w = h_str;
181 img->vir_h = v_str;
182
183 return MPP_OK;
184 }
185
config_rga_yuv2rgb_mode(RgaCtx ctx)186 static MPP_RET config_rga_yuv2rgb_mode(RgaCtx ctx)
187 {
188 RgaCtxImpl *impl = (RgaCtxImpl *)ctx;
189 RgaReq *request = &impl->request;
190
191 /*
192 * yuv2rgb_mode only set when translate yuv to rgb, or rga to yuv.
193 * If format of input and output are both yuv or rga, set yuv2rgb_mode to 0.
194 */
195 int src_format = request->src.format;
196 int dst_format = request->dst.format;
197
198 request->yuv2rgb_mode = 0;
199 if (is_yuv_format(src_format) && is_rgb_format(dst_format)) {
200 /* Special config for yuv to rgb */
201 request->yuv2rgb_mode |= 0x1 << 0;
202 } else if (is_rgb_format(src_format) && is_yuv_format(dst_format)) {
203 /* Special config for rgb to yuv */
204 request->yuv2rgb_mode = (2 << 4);
205 }
206
207 return MPP_OK;
208 }
209
rga_control(RgaCtx ctx,RgaCmd cmd,void * param)210 MPP_RET rga_control(RgaCtx ctx, RgaCmd cmd, void *param)
211 {
212 if (NULL == ctx) {
213 mpp_err_f("invalid NULL input\n");
214 return MPP_ERR_NULL_PTR;
215 }
216
217 rga_dbg_func("in\n");
218
219 MPP_RET ret = MPP_OK;
220 RgaCtxImpl *impl = (RgaCtxImpl *)ctx;
221 RgaReq *request = &impl->request;
222
223 switch (cmd) {
224 case RGA_CMD_INIT : {
225 memset(request, 0, sizeof(*request));
226 request->mmu_info.mmu_en = 1;
227 request->mmu_info.mmu_flag = 1;
228 request->mmu_info.mmu_flag = ((2 & 0x3) << 4) | 1;
229 request->mmu_info.mmu_flag |= (1 << 31) | (1 << 10) | (1 << 8);
230 } break;
231 case RGA_CMD_SET_SRC : {
232 if (NULL == param) {
233 mpp_err("invalid NULL param for setup source\n");
234 ret = MPP_NOK;
235 break;
236 }
237
238 MppFrame *src = (MppFrame *)param;
239 ret = config_rga_image(&request->src, src);
240 } break;
241 case RGA_CMD_SET_DST : {
242 if (NULL == param) {
243 mpp_err("invalid NULL param for setup destination\n");
244 ret = MPP_NOK;
245 break;
246 }
247
248 MppFrame *dst = (MppFrame *)param;
249 ret = config_rga_image(&request->dst, dst);
250 // When config dst setup default clip
251 RK_U32 width = mpp_frame_get_width(dst);
252 RK_U32 height = mpp_frame_get_height(dst);
253 request->clip.xmin = 0;
254 request->clip.xmax = width - 1;
255 request->clip.ymin = 0;
256 request->clip.ymax = height - 1;
257 } break;
258 case RGA_CMD_RUN_SYNC : {
259 config_rga_yuv2rgb_mode(ctx);
260 ret = rga_ioctl(impl);
261 } break;
262 default : {
263 mpp_err("invalid command %d\n", cmd);
264 ret = MPP_NOK;
265 } break;
266 }
267
268 rga_dbg_func("out\n");
269 return ret;
270 }
271
272 // sample for copy function
rga_copy(RgaCtx ctx,MppFrame src,MppFrame dst)273 MPP_RET rga_copy(RgaCtx ctx, MppFrame src, MppFrame dst)
274 {
275 MPP_RET ret = MPP_OK;
276 RgaCtxImpl *impl = (RgaCtxImpl *)ctx;
277 MppBuffer src_buf = mpp_frame_get_buffer(src);
278 MppBuffer dst_buf = mpp_frame_get_buffer(dst);
279 RK_U32 src_w = mpp_frame_get_width(src);
280 RK_U32 src_h = mpp_frame_get_height(src);
281 RK_U32 dst_w = mpp_frame_get_width(dst);
282 RK_U32 dst_h = mpp_frame_get_height(dst);
283 RK_S32 src_fd = mpp_buffer_get_fd(src_buf);
284 RK_S32 dst_fd = mpp_buffer_get_fd(dst_buf);
285 RgaReq *request = &impl->request;
286
287 RgaFormat src_fmt = rga_fmt_map(mpp_frame_get_fmt(src));
288 RgaFormat dst_fmt = rga_fmt_map(mpp_frame_get_fmt(dst));
289
290 rga_dbg_func("in\n");
291
292 if (src_fmt >= RGA_FMT_BUTT || dst_fmt >= RGA_FMT_BUTT) {
293 mpp_err("invalid input format for rga process src %d dst %d\n",
294 src_fmt, dst_fmt);
295 ret = MPP_NOK;
296 goto END;
297 }
298
299 mpp_assert(src_w > 0 && src_h > 0);
300
301 if (dst_w == 0 || dst_h == 0) {
302 dst_w = src_w;
303 dst_h = src_h;
304 }
305
306 rga_dbg_copy("[fd:w:h:fmt] src - %d:%d:%d:%d dst - %d:%d:%d:%d\n",
307 src_fd, src_w, src_h, src_fmt,
308 dst_fd, dst_w, dst_h, dst_fmt);
309
310 memset(request, 0, sizeof(*request));
311 request->src.yrgb_addr = src_fd;
312 request->src.format = (RK_U32)src_fmt;
313 request->src.vir_w = mpp_frame_get_hor_stride(src);
314 request->src.vir_h = mpp_frame_get_ver_stride(src);
315 request->src.act_w = src_w;
316 request->src.act_h = src_h;
317
318 request->dst.yrgb_addr = dst_fd;
319 request->dst.vir_w = dst_w;
320 request->dst.vir_h = dst_h;
321 request->dst.format = (RK_U32)dst_fmt;
322 request->clip.xmin = 0;
323 request->clip.xmax = dst_w - 1;
324 request->clip.ymin = 0;
325 request->clip.ymax = dst_h - 1;
326 request->dst.act_w = dst_w;
327 request->dst.act_h = dst_h;
328
329 config_rga_yuv2rgb_mode(ctx);
330
331 request->mmu_info.mmu_en = 1;
332 request->mmu_info.mmu_flag = 1;
333 request->mmu_info.mmu_flag = ((2 & 0x3) << 4) | 1;
334 request->mmu_info.mmu_flag |= (1 << 31) | (1 << 10) | (1 << 8);
335
336 ret = rga_ioctl(impl);
337 END:
338 rga_dbg_func("out\n");
339 return ret;
340 }
341
342 // sample for duplicate field to frame function
rga_dup_field(RgaCtx ctx,MppFrame frame)343 MPP_RET rga_dup_field(RgaCtx ctx, MppFrame frame)
344 {
345 MPP_RET ret = MPP_OK;
346 RgaCtxImpl *impl = (RgaCtxImpl *)ctx;
347 MppBuffer buf = mpp_frame_get_buffer(frame);
348 RK_U32 width = mpp_frame_get_width(frame);
349 RK_U32 height = mpp_frame_get_height(frame);
350 RK_U32 h_str = mpp_frame_get_hor_stride(frame);
351 RK_U32 v_str = mpp_frame_get_ver_stride(frame);
352 RK_S32 fd = mpp_buffer_get_fd(buf);
353 void *ptr = mpp_buffer_get_ptr(buf);
354 RgaFormat fmt = rga_fmt_map(mpp_frame_get_fmt(frame));
355 RgaReq *request = &impl->request;
356
357 rga_dbg_func("in\n");
358
359 mpp_assert(fmt == RGA_FMT_YCbCr_420_SP);
360 mpp_assert(width > 0 && height > 0);
361 if (fmt != RGA_FMT_YCbCr_420_SP || width == 0 || height == 0) {
362 ret = MPP_NOK;
363 goto END;
364 }
365
366 rga_dbg_dup("[fd:w:h:h_str:v_str:fmt] %d:%d:%d:%d:%d:%d\n",
367 fd, width, height, h_str, v_str, fmt);
368
369 memset(request, 0, sizeof(*request));
370 request->src.yrgb_addr = fd;
371 request->src.format = (RK_U32)fmt;
372 request->src.vir_w = h_str * 2;
373 request->src.vir_h = v_str / 2;
374 request->src.act_w = width;
375 request->src.act_h = height / 2;
376
377 request->dst.yrgb_addr = 0;
378 request->dst.uv_addr = (RK_U32)((uintptr_t)ptr) + h_str; // special process here
379 request->dst.vir_w = h_str * 2;
380 request->dst.vir_h = v_str / 2;
381 request->dst.format = (RK_U32)fmt;
382 request->dst.act_w = width;
383 request->dst.act_h = height / 2;
384
385 request->clip.xmin = 0;
386 request->clip.xmax = h_str * 2 - 1;
387 request->clip.ymin = 0;
388 request->clip.ymax = v_str / 2 - 1;
389
390 request->mmu_info.mmu_en = 1;
391 request->mmu_info.mmu_flag = ((2 & 0x3) << 4) | 1;
392 request->mmu_info.mmu_flag |= (1 << 31) | (1 << 10) | (1 << 8);
393
394 ret = rga_ioctl(impl);
395 END:
396 rga_dbg_func("out\n");
397 return ret;
398 }
399