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