xref: /rockchip-linux_mpp/mpp/vproc/iep2/iep2.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
1 /*
2  * Copyright 2020 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 "iep2_api.h"
18 
19 #include <sys/ioctl.h>
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 
27 #include "mpp_env.h"
28 #include "mpp_debug.h"
29 #include "mpp_buffer.h"
30 
31 #include "iep2_ff.h"
32 #include "iep2_pd.h"
33 #include "iep2_gmv.h"
34 #include "iep2_osd.h"
35 #include "iep2_roi.h"
36 
37 #include "iep2.h"
38 #include "mpp_service.h"
39 #include "mpp_platform.h"
40 
41 #define IEP2_TILE_W_MAX     120
42 #define IEP2_TILE_H_MAX     480
43 #define IEP2_OSD_EN         0
44 
45 RK_U32 iep_debug = 0;
46 RK_U32 iep_md_pre_en = 0;
47 
48 /* default iep2 mtn table */
49 static RK_U32 iep2_mtn_tab[] = {
50     0x00000000, 0x00000000, 0x00000000, 0x00000000,
51     0x01010000, 0x06050302, 0x0f0d0a08, 0x1c191512,
52     0x2b282420, 0x3634312e, 0x3d3c3a38, 0x40403f3e,
53     0x40404040, 0x40404040, 0x40404040, 0x40404040
54 };
55 
get_param_from_env(struct iep2_api_ctx * ctx)56 static MPP_RET get_param_from_env(struct iep2_api_ctx *ctx)
57 {
58     struct iep2_params *params = &ctx->params;
59     mpp_env_get_u32("md_theta", &params->md_theta, ctx->params.md_theta);
60     mpp_env_get_u32("md_r", &params->md_r, ctx->params.md_r);
61     mpp_env_get_u32("md_lambda", &params->md_lambda, ctx->params.md_lambda);
62 
63     mpp_env_get_u32("mv_similar_thr", &params->mv_similar_thr, ctx->params.mv_similar_thr);
64     mpp_env_get_u32("mv_similar_num_thr0", &params->mv_similar_num_thr0, ctx->params.mv_similar_num_thr0);
65 
66     mpp_env_get_u32("eedi_thr0", &params->eedi_thr0, ctx->params.eedi_thr0);
67     mpp_env_get_u32("comb_t_thr", &params->comb_t_thr, ctx->params.comb_t_thr);
68     mpp_env_get_u32("comb_feature_thr", &params->comb_feature_thr, ctx->params.comb_feature_thr);
69     return MPP_OK;
70 }
71 
iep2_init(IepCtx * ictx)72 static MPP_RET iep2_init(IepCtx *ictx)
73 {
74     MPP_RET ret;
75     struct iep2_api_ctx *ctx = *ictx;
76     MppReqV1 mpp_req;
77     RK_U32 client_data = IEP_CLIENT_TYPE;
78 
79     mpp_env_get_u32("iep_debug", &iep_debug, 0);
80 
81     ctx->fd = open("/dev/mpp_service", O_RDWR | O_CLOEXEC);
82     if (ctx->fd < 0) {
83         mpp_err("can NOT find device /dev/iep2\n");
84         return MPP_NOK;
85     }
86 
87     mpp_req.cmd = MPP_CMD_INIT_CLIENT_TYPE;
88     mpp_req.flag = 0;
89     mpp_req.size = sizeof(client_data);
90     mpp_req.data_ptr = REQ_DATA_PTR(&client_data);
91 
92     ret = (RK_S32)ioctl(ctx->fd, MPP_IOC_CFG_V1, &mpp_req);
93     if (ret) {
94         mpp_err("ioctl set_client failed\n");
95         return MPP_NOK;
96     }
97 
98     // set default parameters.
99     ctx->params.src_fmt = IEP2_FMT_YUV420;
100     ctx->params.src_yuv_swap = IEP2_YUV_SWAP_SP_UV;
101     ctx->params.dst_fmt = IEP2_FMT_YUV420;
102     ctx->params.dst_yuv_swap = IEP2_YUV_SWAP_SP_UV;
103 
104     ctx->params.src_y_stride = 720 / 4;
105     ctx->params.src_uv_stride = 720 / 4;
106     ctx->params.dst_y_stride = 720 / 4;
107 
108     ctx->params.tile_cols = 720 / 16;
109     ctx->params.tile_rows = 480 / 4;
110 
111     ctx->params.dil_mode = IEP2_DIL_MODE_I1O1T;
112 
113     ctx->params.dil_out_mode = IEP2_OUT_MODE_LINE;
114     ctx->params.dil_field_order = IEP2_FIELD_ORDER_TFF;
115 
116     ctx->params.md_theta = 1;
117     ctx->params.md_r = 6;
118 
119     if (mpp_get_soc_type() == ROCKCHIP_SOC_RK3528) {
120         mpp_env_get_u32("iep_md_pre_en", &iep_md_pre_en, 0);
121         if (iep_md_pre_en) {
122             ctx->params.md_lambda = 4;
123         } else {
124             ctx->params.md_lambda = 8;
125         }
126     } else {
127         ctx->params.md_lambda = 4;
128     }
129 
130     ctx->params.dect_resi_thr = 30;
131     ctx->params.osd_area_num = 0;
132     ctx->params.osd_gradh_thr = 60;
133     ctx->params.osd_gradv_thr = 60;
134 
135     ctx->params.osd_pos_limit_en = 0;
136     ctx->params.osd_pos_limit_num = 0;
137 
138     ctx->params.osd_pec_thr = 20;
139     ctx->params.osd_line_num = 2;
140 
141     ctx->params.me_pena = 5;
142     ctx->params.mv_similar_thr = 4;
143     ctx->params.mv_similar_num_thr0 = 4;
144     ctx->params.mv_bonus = 10;
145     ctx->params.me_thr_offset = 20;
146 
147     ctx->params.mv_left_limit = 28;
148     ctx->params.mv_right_limit = 27;
149 
150     ctx->params.eedi_thr0 = 12;
151 
152     memset(ctx->params.comb_osd_vld, 1, sizeof(ctx->params.comb_osd_vld));
153     ctx->params.comb_t_thr = 4;
154     ctx->params.comb_feature_thr = 16;
155     ctx->params.comb_cnt_thr = 0;
156 
157     ctx->params.ble_backtoma_num = 1;
158 
159     ctx->params.mtn_en = 1;
160     memcpy(ctx->params.mtn_tab, iep2_mtn_tab, sizeof(ctx->params.mtn_tab));
161 
162     ctx->params.roi_en = 0;
163     ctx->params.roi_layer_num = 0;
164 
165     ctx->params.dil_mode = IEP2_DIL_MODE_I1O1T;
166     ctx->params.src_fmt = IEP2_FMT_YUV420;
167     ctx->params.src_yuv_swap = IEP2_YUV_SWAP_SP_UV;
168     ctx->params.dst_fmt = IEP2_FMT_YUV420;
169     ctx->params.dst_yuv_swap = IEP2_YUV_SWAP_SP_UV;
170     ctx->params.src_y_stride = 720 / 4;
171     ctx->params.src_uv_stride = 720 / 4;
172     ctx->params.dst_y_stride = 720 / 4;
173     ctx->params.tile_cols = 720 / 16;
174     ctx->params.tile_rows = 480 / 4;
175 
176     memset(&ctx->ff_inf, 0, sizeof(ctx->ff_inf));
177 
178     memset(&ctx->pd_inf, 0, sizeof(ctx->pd_inf));
179     ctx->pd_inf.pdtype = PD_TYPES_UNKNOWN;
180     ctx->pd_inf.step = -1;
181 
182     ret = mpp_buffer_group_get_internal(&ctx->memGroup, MPP_BUFFER_TYPE_DRM);
183     if (MPP_OK != ret) {
184         close(ctx->fd);
185         mpp_err("memGroup mpp_buffer_group_get failed\n");
186         return ret;
187     }
188 
189     ret = mpp_buffer_get(ctx->memGroup, &ctx->mv_buf,
190                          IEP2_TILE_W_MAX * IEP2_TILE_H_MAX);
191     if (ret) {
192         close(ctx->fd);
193         mpp_buffer_group_put(ctx->memGroup);
194         mpp_err_f("allocate mv buffer failed\n");
195         return MPP_NOK;
196     }
197 
198     ret = mpp_buffer_get(ctx->memGroup, &ctx->md_buf, 1920 * 1088);
199     if (ret) {
200         close(ctx->fd);
201         mpp_buffer_group_put(ctx->memGroup);
202         mpp_buffer_put(ctx->mv_buf);
203         mpp_err_f("allocate md buffer failed\n");
204         return MPP_NOK;
205     }
206 
207     ctx->params.mv_addr = mpp_buffer_get_fd(ctx->mv_buf);
208     ctx->params.md_addr = mpp_buffer_get_fd(ctx->md_buf);
209 
210     return MPP_OK;
211 }
212 
iep2_deinit(IepCtx ictx)213 static MPP_RET iep2_deinit(IepCtx ictx)
214 {
215     struct iep2_api_ctx *ctx = ictx;
216 
217     close(ctx->fd);
218 
219     if (ctx->mv_buf) {
220         mpp_buffer_put(ctx->mv_buf);
221         ctx->mv_buf = NULL;
222     }
223 
224     if (ctx->md_buf) {
225         mpp_buffer_put(ctx->md_buf);
226         ctx->md_buf = NULL;
227     }
228 
229     if (ctx->memGroup) {
230         mpp_buffer_group_put(ctx->memGroup);
231         ctx->memGroup = NULL;
232     }
233 
234     return MPP_OK;
235 }
236 
iep2_done(struct iep2_api_ctx * ctx)237 static MPP_RET iep2_done(struct iep2_api_ctx *ctx)
238 {
239     iep_dbg_trace("deinterlace detect osd cnt %d, combo %d\n",
240                   ctx->output.dect_osd_cnt,
241                   ctx->output.out_osd_comb_cnt);
242 
243     if (ctx->params.dil_mode == IEP2_DIL_MODE_I5O2 ||
244         ctx->params.dil_mode == IEP2_DIL_MODE_I5O1T ||
245         ctx->params.dil_mode == IEP2_DIL_MODE_I5O1B) {
246         struct mv_list ls;
247 
248 #if IEP2_OSD_EN
249         iep2_set_osd(ctx, &ls);
250 #else
251         memset(&ls, 0, sizeof(struct mv_list));
252 #endif
253         iep2_update_gmv(ctx, &ls);
254         iep2_check_ffo(ctx);
255         iep2_check_pd(ctx);
256         get_param_from_env(ctx);
257 #if 0
258         if (ctx->params.roi_en && ctx->params.osd_area_num > 0) {
259             struct iep2_rect r;
260 
261             ctx->params.roi_layer_num = 0;
262 
263             r.x = 0;
264             r.y = 0;
265             r.w = ctx->params.tile_cols;
266             r.h = ctx->params.tile_rows;
267             iep2_set_roi(ctx, &r, ROI_MODE_MA);
268 
269             r.x = ctx->params.osd_x_sta[0];
270             r.y = ctx->params.osd_y_sta[0];
271             r.w = ctx->params.osd_x_end[0] - ctx->params.osd_x_sta[0];
272             r.h = ctx->params.osd_y_end[0] - ctx->params.osd_y_sta[0];
273             iep2_set_roi(ctx, &r, ROI_MODE_MA_MC);
274         }
275 #endif
276     }
277 
278     if (ctx->params.dil_mode == IEP2_DIL_MODE_DECT ||
279         ctx->params.dil_mode == IEP2_DIL_MODE_PD) {
280         iep2_check_ffo(ctx);
281         iep2_check_pd(ctx);
282         get_param_from_env(ctx);
283     }
284 
285     if (ctx->pd_inf.pdtype != PD_TYPES_UNKNOWN) {
286         ctx->params.dil_mode = IEP2_DIL_MODE_PD;
287         ctx->params.pd_mode = iep2_pd_get_output(&ctx->pd_inf);
288     } else {
289         // TODO, revise others mode replace by I5O2
290         //ctx->params.dil_mode = IEP2_DIL_MODE_I5O2;
291     }
292 
293     return 0;
294 }
295 
iep2_set_param(struct iep2_api_ctx * ctx,union iep2_api_content * param,enum IEP2_PARAM_TYPE type)296 static void iep2_set_param(struct iep2_api_ctx *ctx,
297                            union iep2_api_content *param,
298                            enum IEP2_PARAM_TYPE type)
299 {
300     switch (type) {
301     case IEP2_PARAM_TYPE_COM:
302             ctx->params.src_fmt = param->com.sfmt;
303         ctx->params.src_yuv_swap = param->com.sswap;
304         ctx->params.dst_fmt = param->com.dfmt;
305         ctx->params.dst_yuv_swap = param->com.dswap;
306         ctx->params.src_y_stride = param->com.hor_stride;
307         ctx->params.src_y_stride /= 4;
308         ctx->params.src_uv_stride =
309             param->com.sswap == IEP2_YUV_SWAP_P ?
310             (param->com.hor_stride / 2 + 15) / 16 * 16 : param->com.hor_stride;
311         ctx->params.src_uv_stride /= 4;
312         ctx->params.dst_y_stride = param->com.hor_stride;
313         ctx->params.dst_y_stride /= 4;
314         ctx->params.tile_cols = (param->com.width + 15) / 16;
315         ctx->params.tile_rows = (param->com.height + 3) / 4;
316         iep_dbg_trace("set tile size (%d, %d)\n", param->com.width, param->com.height);
317         ctx->params.osd_pec_thr = (param->com.width * 26) >> 7;
318         break;
319     case IEP2_PARAM_TYPE_MODE:
320         ctx->params.dil_mode = param->mode.dil_mode;
321         ctx->params.dil_out_mode = param->mode.out_mode;
322         ctx->params.dil_field_order = param->mode.dil_order;
323 
324         iep_dbg_trace("deinterlace, mode %d, out mode %d, dil_order %d\n",
325                       param->mode.dil_mode, param->mode.out_mode, param->mode.dil_order);
326 
327         if (param->mode.dil_order == IEP2_FIELD_ORDER_UND) {
328             ctx->ff_inf.frm_offset = 6;
329             ctx->ff_inf.fie_offset = 0;
330         } else {
331             ctx->ff_inf.frm_offset = 0;
332             ctx->ff_inf.fie_offset = 10;
333         }
334 
335         if (param->mode.dil_order == IEP2_FIELD_ORDER_TFF) {
336             ctx->ff_inf.tff_offset = 3;
337             ctx->ff_inf.bff_offset = 0;
338         } else {
339             ctx->ff_inf.tff_offset = 0;
340             ctx->ff_inf.bff_offset = 3;
341         }
342         break;
343     case IEP2_PARAM_TYPE_MD:
344         ctx->params.md_theta = param->md.md_theta;
345         ctx->params.md_r = param->md.md_r;
346         ctx->params.md_lambda = param->md.md_lambda;
347         break;
348     case IEP2_PARAM_TYPE_DECT:
349     case IEP2_PARAM_TYPE_OSD:
350     case IEP2_PARAM_TYPE_ME:
351     case IEP2_PARAM_TYPE_EEDI:
352     case IEP2_PARAM_TYPE_BLE:
353     case IEP2_PARAM_TYPE_COMB:
354         break;
355     case IEP2_PARAM_TYPE_ROI:
356         ctx->params.roi_en = param->roi.roi_en;
357         break;
358     default:
359         ;
360     }
361 }
362 
iep2_param_check(struct iep2_api_ctx * ctx)363 static MPP_RET iep2_param_check(struct iep2_api_ctx *ctx)
364 {
365     if (ctx->params.tile_cols <= 0 || ctx->params.tile_cols > IEP2_TILE_W_MAX ||
366         ctx->params.tile_rows <= 0 || ctx->params.tile_rows > IEP2_TILE_H_MAX) {
367         mpp_err("invalidate size (%u, %u)\n",
368                 ctx->params.tile_cols, ctx->params.tile_rows);
369         return MPP_NOK;
370     }
371 
372     return MPP_OK;
373 }
374 
iep2_start(struct iep2_api_ctx * ctx)375 static MPP_RET iep2_start(struct iep2_api_ctx *ctx)
376 {
377     MPP_RET ret;
378     MppReqV1 mpp_req[2];
379 
380     mpp_assert(ctx);
381 
382     mpp_req[0].cmd = MPP_CMD_SET_REG_WRITE;
383     mpp_req[0].flag = MPP_FLAGS_MULTI_MSG;
384     mpp_req[0].size =  sizeof(ctx->params);
385     mpp_req[0].offset = 0;
386     mpp_req[0].data_ptr = REQ_DATA_PTR(&ctx->params);
387 
388     mpp_req[1].cmd = MPP_CMD_SET_REG_READ;
389     mpp_req[1].flag = MPP_FLAGS_MULTI_MSG | MPP_FLAGS_LAST_MSG;
390     mpp_req[1].size =  sizeof(ctx->output);
391     mpp_req[1].offset = 0;
392     mpp_req[1].data_ptr = REQ_DATA_PTR(&ctx->output);
393 
394     iep_dbg_func("in\n");
395 
396     ret = (RK_S32)ioctl(ctx->fd, MPP_IOC_CFG_V1, &mpp_req[0]);
397 
398     if (ret) {
399         mpp_err_f("ioctl SET_REG failed ret %d errno %d %s\n",
400                   ret, errno, strerror(errno));
401         ret = errno;
402     }
403 
404     return ret;
405 }
406 
iep2_wait(struct iep2_api_ctx * ctx)407 static MPP_RET iep2_wait(struct iep2_api_ctx *ctx)
408 {
409     MppReqV1 mpp_req;
410     MPP_RET ret;
411 
412     memset(&mpp_req, 0, sizeof(mpp_req));
413     mpp_req.cmd = MPP_CMD_POLL_HW_FINISH;
414     mpp_req.flag |= MPP_FLAGS_LAST_MSG;
415 
416     ret = (RK_S32)ioctl(ctx->fd, MPP_IOC_CFG_V1, &mpp_req);
417 
418     return ret;
419 }
420 
set_addr(struct iep2_addr * addr,IepImg * img)421 static inline void set_addr(struct iep2_addr *addr, IepImg *img)
422 {
423     addr->y = img->mem_addr;
424     addr->cbcr = img->uv_addr;
425     addr->cr = img->v_addr;
426 }
427 
iep2_control(IepCtx ictx,IepCmd cmd,void * iparam)428 static MPP_RET iep2_control(IepCtx ictx, IepCmd cmd, void *iparam)
429 {
430     struct iep2_api_ctx *ctx = ictx;
431 
432     switch (cmd) {
433     case IEP_CMD_SET_DEI_CFG: {
434         struct iep2_api_params *param = (struct iep2_api_params *)iparam;
435 
436         iep2_set_param(ctx, &param->param, param->ptype);
437     }
438     break;
439     case IEP_CMD_SET_SRC:
440         set_addr(&ctx->params.src[0], (IepImg *)iparam);
441         break;
442     case IEP_CMD_SET_DEI_SRC1:
443         set_addr(&ctx->params.src[1], (IepImg *)iparam);
444         break;
445     case IEP_CMD_SET_DEI_SRC2:
446         set_addr(&ctx->params.src[2], (IepImg *)iparam);
447         break;
448     case IEP_CMD_SET_DST:
449         set_addr(&ctx->params.dst[0], (IepImg *)iparam);
450         break;
451     case IEP_CMD_SET_DEI_DST1:
452         set_addr(&ctx->params.dst[1], (IepImg *)iparam);
453         break;
454     case IEP_CMD_RUN_SYNC: {
455         struct iep2_api_info *inf = (struct iep2_api_info*)iparam;
456 
457         if (0 > iep2_param_check(ctx))
458             break;
459         if (0 > iep2_start(ctx))
460             return MPP_NOK;
461         iep2_wait(ctx);
462 
463         if (ctx->params.dil_mode == IEP2_DIL_MODE_PD) {
464             ctx->params.dil_mode = IEP2_DIL_MODE_DECT;
465             if (0 > iep2_start(ctx))
466                 return MPP_NOK;
467             iep2_wait(ctx);
468         }
469 
470         // store current pd mode;
471         if (inf)
472             inf->pd_flag = ctx->params.pd_mode;
473         iep2_done(ctx);
474         if (inf) {
475             inf->dil_order = ctx->ff_inf.field_order;
476             inf->frm_mode = ctx->ff_inf.frm_mode;
477             inf->pd_types = ctx->pd_inf.pdtype;
478             inf->dil_order_confidence_ratio = ctx->ff_inf.fo_ratio_avg;
479         }
480     }
481     break;
482     default:
483         ;
484     }
485 
486     return MPP_OK;
487 }
488 
iep2_reset(IepCtx ictx)489 static MPP_RET iep2_reset(IepCtx ictx)
490 {
491     struct iep2_api_ctx *ctx = ictx;
492 
493     memset(&ctx->ff_inf, 0, sizeof(ctx->ff_inf));
494 
495     return MPP_OK;
496 }
497 
498 static iep_com_ops iep2_ops = {
499     .init = iep2_init,
500     .deinit = iep2_deinit,
501     .control = iep2_control,
502     .reset = iep2_reset,
503     .release = NULL,
504 };
505 
rockchip_iep2_api_alloc_ctx(void)506 iep_com_ctx* rockchip_iep2_api_alloc_ctx(void)
507 {
508     iep_com_ctx *com_ctx = calloc(sizeof(*com_ctx), 1);
509     struct iep2_api_ctx *iep2_ctx = calloc(sizeof(*iep2_ctx), 1);
510 
511     mpp_assert(com_ctx && iep2_ctx);
512 
513     com_ctx->ops = &iep2_ops;
514     com_ctx->priv = iep2_ctx;
515 
516     return com_ctx;
517 }
518 
rockchip_iep2_api_release_ctx(iep_com_ctx * com_ctx)519 void rockchip_iep2_api_release_ctx(iep_com_ctx *com_ctx)
520 {
521     if (com_ctx->priv) {
522         free(com_ctx->priv);
523         com_ctx->priv = NULL;
524     }
525 
526     free(com_ctx);
527 }
528 
529