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", ¶ms->md_theta, ctx->params.md_theta);
60 mpp_env_get_u32("md_r", ¶ms->md_r, ctx->params.md_r);
61 mpp_env_get_u32("md_lambda", ¶ms->md_lambda, ctx->params.md_lambda);
62
63 mpp_env_get_u32("mv_similar_thr", ¶ms->mv_similar_thr, ctx->params.mv_similar_thr);
64 mpp_env_get_u32("mv_similar_num_thr0", ¶ms->mv_similar_num_thr0, ctx->params.mv_similar_num_thr0);
65
66 mpp_env_get_u32("eedi_thr0", ¶ms->eedi_thr0, ctx->params.eedi_thr0);
67 mpp_env_get_u32("comb_t_thr", ¶ms->comb_t_thr, ctx->params.comb_t_thr);
68 mpp_env_get_u32("comb_feature_thr", ¶ms->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 mpp_buffer_put(ctx->mv_buf);
220 mpp_buffer_put(ctx->md_buf);
221
222 if (ctx->memGroup) {
223 mpp_buffer_group_put(ctx->memGroup);
224 ctx->memGroup = NULL;
225 }
226
227 return MPP_OK;
228 }
229
iep2_done(struct iep2_api_ctx * ctx)230 static MPP_RET iep2_done(struct iep2_api_ctx *ctx)
231 {
232 iep_dbg_trace("deinterlace detect osd cnt %d, combo %d\n",
233 ctx->output.dect_osd_cnt,
234 ctx->output.out_osd_comb_cnt);
235
236 if (ctx->params.dil_mode == IEP2_DIL_MODE_I5O2 ||
237 ctx->params.dil_mode == IEP2_DIL_MODE_I5O1T ||
238 ctx->params.dil_mode == IEP2_DIL_MODE_I5O1B) {
239 struct mv_list ls;
240
241 #if IEP2_OSD_EN
242 iep2_set_osd(ctx, &ls);
243 #else
244 memset(&ls, 0, sizeof(struct mv_list));
245 #endif
246 iep2_update_gmv(ctx, &ls);
247 iep2_check_ffo(ctx);
248 iep2_check_pd(ctx);
249 get_param_from_env(ctx);
250 #if 0
251 if (ctx->params.roi_en && ctx->params.osd_area_num > 0) {
252 struct iep2_rect r;
253
254 ctx->params.roi_layer_num = 0;
255
256 r.x = 0;
257 r.y = 0;
258 r.w = ctx->params.tile_cols;
259 r.h = ctx->params.tile_rows;
260 iep2_set_roi(ctx, &r, ROI_MODE_MA);
261
262 r.x = ctx->params.osd_x_sta[0];
263 r.y = ctx->params.osd_y_sta[0];
264 r.w = ctx->params.osd_x_end[0] - ctx->params.osd_x_sta[0];
265 r.h = ctx->params.osd_y_end[0] - ctx->params.osd_y_sta[0];
266 iep2_set_roi(ctx, &r, ROI_MODE_MA_MC);
267 }
268 #endif
269 }
270
271 if (ctx->params.dil_mode == IEP2_DIL_MODE_DECT ||
272 ctx->params.dil_mode == IEP2_DIL_MODE_PD) {
273 iep2_check_ffo(ctx);
274 iep2_check_pd(ctx);
275 get_param_from_env(ctx);
276 }
277
278 if (ctx->pd_inf.pdtype != PD_TYPES_UNKNOWN) {
279 ctx->params.dil_mode = IEP2_DIL_MODE_PD;
280 ctx->params.pd_mode = iep2_pd_get_output(&ctx->pd_inf);
281 } else {
282 // TODO, revise others mode replace by I5O2
283 //ctx->params.dil_mode = IEP2_DIL_MODE_I5O2;
284 }
285
286 return 0;
287 }
288
iep2_set_param(struct iep2_api_ctx * ctx,union iep2_api_content * param,enum IEP2_PARAM_TYPE type)289 static void iep2_set_param(struct iep2_api_ctx *ctx,
290 union iep2_api_content *param,
291 enum IEP2_PARAM_TYPE type)
292 {
293 switch (type) {
294 case IEP2_PARAM_TYPE_COM:
295 ctx->params.src_fmt = param->com.sfmt;
296 ctx->params.src_yuv_swap = param->com.sswap;
297 ctx->params.dst_fmt = param->com.dfmt;
298 ctx->params.dst_yuv_swap = param->com.dswap;
299 ctx->params.src_y_stride = param->com.hor_stride;
300 ctx->params.src_y_stride /= 4;
301 ctx->params.src_uv_stride =
302 param->com.sswap == IEP2_YUV_SWAP_P ?
303 (param->com.hor_stride / 2 + 15) / 16 * 16 : param->com.hor_stride;
304 ctx->params.src_uv_stride /= 4;
305 ctx->params.dst_y_stride = param->com.hor_stride;
306 ctx->params.dst_y_stride /= 4;
307 ctx->params.tile_cols = (param->com.width + 15) / 16;
308 ctx->params.tile_rows = (param->com.height + 3) / 4;
309 iep_dbg_trace("set tile size (%d, %d)\n", param->com.width, param->com.height);
310 ctx->params.osd_pec_thr = (param->com.width * 26) >> 7;
311 break;
312 case IEP2_PARAM_TYPE_MODE:
313 ctx->params.dil_mode = param->mode.dil_mode;
314 ctx->params.dil_out_mode = param->mode.out_mode;
315 if (!ctx->ff_inf.fo_detected) {
316 ctx->params.dil_field_order = param->mode.dil_order;
317 }
318
319 iep_dbg_trace("deinterlace, mode %d, out mode %d, fo_detected %d, dil_order %d\n",
320 param->mode.dil_mode, param->mode.out_mode, ctx->ff_inf.fo_detected, param->mode.dil_order);
321
322 if (param->mode.dil_order == IEP2_FIELD_ORDER_UND) {
323 ctx->ff_inf.frm_offset = 6;
324 ctx->ff_inf.fie_offset = 0;
325 } else {
326 ctx->ff_inf.frm_offset = 0;
327 ctx->ff_inf.fie_offset = 10;
328 }
329
330 if (param->mode.dil_order == IEP2_FIELD_ORDER_TFF) {
331 ctx->ff_inf.tff_offset = 3;
332 ctx->ff_inf.bff_offset = 0;
333 } else {
334 ctx->ff_inf.tff_offset = 0;
335 ctx->ff_inf.bff_offset = 3;
336 }
337 break;
338 case IEP2_PARAM_TYPE_MD:
339 ctx->params.md_theta = param->md.md_theta;
340 ctx->params.md_r = param->md.md_r;
341 ctx->params.md_lambda = param->md.md_lambda;
342 break;
343 case IEP2_PARAM_TYPE_DECT:
344 case IEP2_PARAM_TYPE_OSD:
345 case IEP2_PARAM_TYPE_ME:
346 case IEP2_PARAM_TYPE_EEDI:
347 case IEP2_PARAM_TYPE_BLE:
348 case IEP2_PARAM_TYPE_COMB:
349 break;
350 case IEP2_PARAM_TYPE_ROI:
351 ctx->params.roi_en = param->roi.roi_en;
352 break;
353 default:
354 ;
355 }
356 }
357
iep2_param_check(struct iep2_api_ctx * ctx)358 static MPP_RET iep2_param_check(struct iep2_api_ctx *ctx)
359 {
360 if (ctx->params.tile_cols <= 0 || ctx->params.tile_cols > IEP2_TILE_W_MAX ||
361 ctx->params.tile_rows <= 0 || ctx->params.tile_rows > IEP2_TILE_H_MAX) {
362 mpp_err("invalidate size (%u, %u)\n",
363 ctx->params.tile_cols, ctx->params.tile_rows);
364 return MPP_NOK;
365 }
366
367 return MPP_OK;
368 }
369
iep2_start(struct iep2_api_ctx * ctx)370 static MPP_RET iep2_start(struct iep2_api_ctx *ctx)
371 {
372 MPP_RET ret;
373 MppReqV1 mpp_req[2];
374
375 mpp_assert(ctx);
376
377 mpp_req[0].cmd = MPP_CMD_SET_REG_WRITE;
378 mpp_req[0].flag = MPP_FLAGS_MULTI_MSG;
379 mpp_req[0].size = sizeof(ctx->params);
380 mpp_req[0].offset = 0;
381 mpp_req[0].data_ptr = REQ_DATA_PTR(&ctx->params);
382
383 mpp_req[1].cmd = MPP_CMD_SET_REG_READ;
384 mpp_req[1].flag = MPP_FLAGS_MULTI_MSG | MPP_FLAGS_LAST_MSG;
385 mpp_req[1].size = sizeof(ctx->output);
386 mpp_req[1].offset = 0;
387 mpp_req[1].data_ptr = REQ_DATA_PTR(&ctx->output);
388
389 iep_dbg_func("in\n");
390
391 ret = (RK_S32)ioctl(ctx->fd, MPP_IOC_CFG_V1, &mpp_req[0]);
392
393 if (ret) {
394 mpp_err_f("ioctl SET_REG failed ret %d errno %d %s\n",
395 ret, errno, strerror(errno));
396 ret = errno;
397 }
398
399 return ret;
400 }
401
iep2_wait(struct iep2_api_ctx * ctx)402 static MPP_RET iep2_wait(struct iep2_api_ctx *ctx)
403 {
404 MppReqV1 mpp_req;
405 MPP_RET ret;
406
407 memset(&mpp_req, 0, sizeof(mpp_req));
408 mpp_req.cmd = MPP_CMD_POLL_HW_FINISH;
409 mpp_req.flag |= MPP_FLAGS_LAST_MSG;
410
411 ret = (RK_S32)ioctl(ctx->fd, MPP_IOC_CFG_V1, &mpp_req);
412
413 return ret;
414 }
415
set_addr(struct iep2_addr * addr,IepImg * img)416 static inline void set_addr(struct iep2_addr *addr, IepImg *img)
417 {
418 addr->y = img->mem_addr;
419 addr->cbcr = img->uv_addr;
420 addr->cr = img->v_addr;
421 }
422
iep2_control(IepCtx ictx,IepCmd cmd,void * iparam)423 static MPP_RET iep2_control(IepCtx ictx, IepCmd cmd, void *iparam)
424 {
425 struct iep2_api_ctx *ctx = ictx;
426
427 switch (cmd) {
428 case IEP_CMD_SET_DEI_CFG: {
429 struct iep2_api_params *param = (struct iep2_api_params *)iparam;
430
431 iep2_set_param(ctx, ¶m->param, param->ptype);
432 }
433 break;
434 case IEP_CMD_SET_SRC:
435 set_addr(&ctx->params.src[0], (IepImg *)iparam);
436 break;
437 case IEP_CMD_SET_DEI_SRC1:
438 set_addr(&ctx->params.src[1], (IepImg *)iparam);
439 break;
440 case IEP_CMD_SET_DEI_SRC2:
441 set_addr(&ctx->params.src[2], (IepImg *)iparam);
442 break;
443 case IEP_CMD_SET_DST:
444 set_addr(&ctx->params.dst[0], (IepImg *)iparam);
445 break;
446 case IEP_CMD_SET_DEI_DST1:
447 set_addr(&ctx->params.dst[1], (IepImg *)iparam);
448 break;
449 case IEP_CMD_RUN_SYNC: {
450 struct iep2_api_info *inf = (struct iep2_api_info*)iparam;
451
452 if (0 > iep2_param_check(ctx))
453 break;
454 if (0 > iep2_start(ctx))
455 return MPP_NOK;
456 iep2_wait(ctx);
457
458 if (ctx->params.dil_mode == IEP2_DIL_MODE_PD) {
459 ctx->params.dil_mode = IEP2_DIL_MODE_DECT;
460 if (0 > iep2_start(ctx))
461 return MPP_NOK;
462 iep2_wait(ctx);
463 }
464
465 // store current pd mode;
466 if (inf)
467 inf->pd_flag = ctx->params.pd_mode;
468 iep2_done(ctx);
469 if (inf) {
470 inf->dil_order = ctx->params.dil_field_order;
471 inf->frm_mode = ctx->ff_inf.is_frm;
472 inf->pd_types = ctx->pd_inf.pdtype;
473 inf->dil_order_confidence_ratio = ctx->ff_inf.fo_ratio_avg;
474 }
475 }
476 break;
477 default:
478 ;
479 }
480
481 return MPP_OK;
482 }
483
484 static iep_com_ops iep2_ops = {
485 .init = iep2_init,
486 .deinit = iep2_deinit,
487 .control = iep2_control,
488 .release = NULL,
489 };
490
rockchip_iep2_api_alloc_ctx(void)491 iep_com_ctx* rockchip_iep2_api_alloc_ctx(void)
492 {
493 iep_com_ctx *com_ctx = calloc(sizeof(*com_ctx), 1);
494 struct iep2_api_ctx *iep2_ctx = calloc(sizeof(*iep2_ctx), 1);
495
496 mpp_assert(com_ctx && iep2_ctx);
497
498 com_ctx->ops = &iep2_ops;
499 com_ctx->priv = iep2_ctx;
500
501 return com_ctx;
502 }
503
rockchip_iep2_api_release_ctx(iep_com_ctx * com_ctx)504 void rockchip_iep2_api_release_ctx(iep_com_ctx *com_ctx)
505 {
506 if (com_ctx->priv) {
507 free(com_ctx->priv);
508 com_ctx->priv = NULL;
509 }
510
511 free(com_ctx);
512 }
513
514