xref: /rockchip-linux_mpp/mpp/vproc/rga/rga.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
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