// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
 * drivers/amlogic/media/di_multi/nr_downscale.c
 *
 * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/dma-map-ops.h>
#include <linux/amlogic/iomap.h>
#include <linux/amlogic/media/canvas/canvas.h>
#include <linux/amlogic/media/canvas/canvas_mgr.h>
#include <linux/amlogic/media/ppmgr/tbff.h>
#include <linux/amlogic/media/codec_mm/codec_mm.h>
#include "register.h"
#include "nr_downscale.h"
#include "di_data_l.h"
#include "di_sys.h"
#include "di_api.h"
#include "di_dbg.h"
#include "di_prc.h"
#include "di_reg_v3.h"

#ifdef DIM_TB_DETECT
struct tb_core_s {
	unsigned int di_tb_quit_flag	: 1,
			first_frame	: 1,
			reset_tb	: 1,
			cur_invert	: 2,
			cur_invert_a	: 2,
			cur_invert_b	: 2,
			cur_invert_c	: 2,
			nr_dump_en	: 1,
			rev	: 20;
	u8 dim_tb_detect_last_flag;
	unsigned int di_tb_buff_wptr;
	unsigned int di_tb_buff_rptr;
	s8 di_tb_buffer_status;
	unsigned int di_tb_buffer_start;
	void	*virt;
	unsigned int di_tb_buffer_size;
	unsigned int di_tb_buffer_len;
	u8 di_tb_first_frame_type;
	int first_frame_type;
	unsigned int skip_picture;
	u8 last_type;
	unsigned int last_width;
	unsigned int last_height;
	unsigned int di_tb_init_mute;
	unsigned int init_mute;
	atomic_t di_tb_sem;
	atomic_t dim_detect_status;
	atomic_t dim_tb_detect_flag;
	atomic_t di_tb_reset_flag;
	atomic_t di_tb_skip_flag;
	atomic_t di_tb_run_flag;
	struct dim_tb_buf_s di_detect_buf[DIM_TB_BUFFER_MAX_SIZE];
	struct dim_tb_buf_s di_detect_wbuf[DIM_TB_BUFFER_MAX_SIZE];
	unsigned int nr_dump_count;
	int di_init;
	unsigned char flg_from;
};

//static struct tb_core_s dim_tbs[DI_CHANNEL_NUB];
static struct tb_core_s *dim_tbs[DI_CHANNEL_NUB];

//struct tb_core_s *get_dim_tb(void)
//{
//	return dim_tbs;
//}

static DEFINE_MUTEX(di_tb_mutex);

static s32 di_tb_canvas = -1;
static struct TB_DetectFuncPtr *digfunc;
static struct tbff_stats *di_tb_reg[DI_CHANNEL_NUB];

//static u32 di_tb_src_canvas;
#endif

#define NR_DETECT_DUMP_CNT 150

#ifdef DIM_TB_DETECT
static int diwrite_to_file(unsigned long  dump_adr, int size, unsigned int ch)
{
#ifdef CONFIG_AMLOGIC_ENABLE_MEDIA_FILE
	int ret = 0;
	struct file *fp = NULL;
	mm_segment_t old_fs;
	bool bflg_vmap = false;
	void *buff = NULL;
	loff_t pos = 0;
	int nwrite = 0;
	int offset = 0;
	char parm[64];
	/* change to KERNEL_DS address limit */
	old_fs = get_fs();
	set_fs(KERNEL_DS);
	//PR_ERR("11%s: open file ok\n", __func__);
	/* open file to write */
	//fp = filp_open("/storage/A2DC-E6BA/tb.yuv",
		//O_WRONLY | O_CREAT | O_APPEND, 0777);
	sprintf(parm, "/storage/A2DC-E6BA/tb%d.yuv", ch);
	fp = filp_open(parm, O_WRONLY | O_CREAT | O_APPEND, 0777);
	//sprintf(parm, "/storage/A2DC-E6BA/TEST4/yuv00%d", didump_tb_cont++);
	//fp = filp_open(parm, O_WRONLY | O_CREAT, 0666);
	//PR_ERR("22%s: open file ok\n", __func__);
	if (IS_ERR_OR_NULL(fp)) {
		PR_ERR("%s: open file error\n", __func__);
		ret = -1;
		goto exit;
	}
	buff = dim_vmap(dump_adr, size, &bflg_vmap);
	//PR_ERR("%s:vmap:0x%x\n", __func__, (unsigned int *)buff);

	pos = (unsigned long)offset;
	//buff = codec_mm_vmap(dump_adr, size);
	//PR_ERR("%s:vmap:0x%p\n", __func__, buff);
	/* Write buf to file */
	if (IS_ERR_OR_NULL(buff))
		PR_ERR("%s: ioremap error.\n", __func__);

	nwrite = vfs_write(fp, buff, size, &pos);
	offset += nwrite;
	vfs_fsync(fp, 0);
	if (bflg_vmap)
		dim_unmap_phyaddr(buff);

	filp_close(fp, NULL);

	//PR_ERR("33%s: open file ok\n", __func__);
exit:
	set_fs(old_fs);
#endif
	return 0; //ret;
}

int dim_tb_detect(struct vframe_tb_s *vf, int data1, unsigned int ch)
{
	bool is_top;
	const struct reg_acc *op = &di_pre_regset;
	struct tb_core_s *pcfg;
	struct di_dev_s *di_devp = get_dim_de_devp();

	dbg_tb("%s :step 3 s\n", __func__);

	pcfg = dim_tbs[ch];

	if (!di_devp->tb_flag_int)
		return -1;

	if (unlikely(!vf))
		return -1;

	if (pcfg->di_tb_buff_wptr & 1)
		is_top = false;
	else
		is_top = true;

	if (data1 == 0) {
		if ((vf->type & VIDTYPE_TYPEMASK) == VIDTYPE_INTERLACE_BOTTOM) {
			pcfg->di_detect_buf[0].paddr =
				pcfg->di_detect_wbuf[1].paddr;
			pcfg->di_detect_buf[1].paddr =
				pcfg->di_detect_wbuf[0].paddr;
			pcfg->di_detect_buf[2].paddr =
				pcfg->di_detect_wbuf[3].paddr;
			pcfg->di_detect_buf[3].paddr =
				pcfg->di_detect_wbuf[2].paddr;
			pcfg->di_detect_buf[4].paddr =
				pcfg->di_detect_wbuf[5].paddr;
			pcfg->di_detect_buf[5].paddr =
				pcfg->di_detect_wbuf[4].paddr;
			pcfg->di_detect_buf[6].paddr =
				pcfg->di_detect_wbuf[7].paddr;
			pcfg->di_detect_buf[7].paddr =
				pcfg->di_detect_wbuf[6].paddr;
			pcfg->cur_invert_a = 1;//dump
			pcfg->cur_invert_b = 1;//revert
			pcfg->cur_invert_c = 1;//normal
			dbg_tb("%s:NR01A %x\n", __func__, data1);
		} else	{
			pcfg->di_detect_buf[0].paddr =
				pcfg->di_detect_wbuf[0].paddr;
			pcfg->di_detect_buf[1].paddr =
				pcfg->di_detect_wbuf[1].paddr;
			pcfg->di_detect_buf[2].paddr =
				pcfg->di_detect_wbuf[2].paddr;
			pcfg->di_detect_buf[3].paddr =
				pcfg->di_detect_wbuf[3].paddr;
			pcfg->di_detect_buf[4].paddr =
				pcfg->di_detect_wbuf[4].paddr;
			pcfg->di_detect_buf[5].paddr =
				pcfg->di_detect_wbuf[5].paddr;
			pcfg->di_detect_buf[6].paddr =
				pcfg->di_detect_wbuf[6].paddr;
			pcfg->di_detect_buf[7].paddr =
				pcfg->di_detect_wbuf[7].paddr;
			pcfg->cur_invert_a = 0;
			pcfg->cur_invert_b = 2;
			pcfg->cur_invert_c = 2;
			dbg_tb("%s:NR01B %x\n", __func__, data1);
		}
	}
	if (pcfg->cur_invert  && pcfg->cur_invert_b) {
		if (pcfg->cur_invert_b == 1) {
			pcfg->di_detect_buf[0].paddr =
				pcfg->di_detect_wbuf[0].paddr;
			pcfg->di_detect_buf[1].paddr =
				pcfg->di_detect_wbuf[1].paddr;
			pcfg->di_detect_buf[2].paddr =
				pcfg->di_detect_wbuf[2].paddr;
			pcfg->di_detect_buf[3].paddr =
				pcfg->di_detect_wbuf[3].paddr;
			pcfg->di_detect_buf[4].paddr =
				pcfg->di_detect_wbuf[4].paddr;
			pcfg->di_detect_buf[5].paddr =
				pcfg->di_detect_wbuf[5].paddr;
			pcfg->di_detect_buf[6].paddr =
				pcfg->di_detect_wbuf[6].paddr;
			pcfg->di_detect_buf[7].paddr =
				pcfg->di_detect_wbuf[7].paddr;
			pcfg->cur_invert_a = 0;
			pcfg->cur_invert_c = 1;
			dbg_tb("%s:NR01C %x\n", __func__, data1);

		} else {
			pcfg->di_detect_buf[0].paddr =
				pcfg->di_detect_wbuf[1].paddr;
			pcfg->di_detect_buf[1].paddr =
				pcfg->di_detect_wbuf[0].paddr;
			pcfg->di_detect_buf[2].paddr =
				pcfg->di_detect_wbuf[3].paddr;
			pcfg->di_detect_buf[3].paddr =
				pcfg->di_detect_wbuf[2].paddr;
			pcfg->di_detect_buf[4].paddr =
				pcfg->di_detect_wbuf[5].paddr;
			pcfg->di_detect_buf[5].paddr =
				pcfg->di_detect_wbuf[4].paddr;
			pcfg->di_detect_buf[6].paddr =
				pcfg->di_detect_wbuf[7].paddr;
			pcfg->di_detect_buf[7].paddr =
				pcfg->di_detect_wbuf[6].paddr;
			pcfg->cur_invert_a = 1;
			pcfg->cur_invert_c = 2;
			dbg_tb("%s:NR01D %x\n", __func__, data1);
		}
		pcfg->cur_invert_b = 0;
	}
	if (!pcfg->cur_invert  && !pcfg->cur_invert_b && pcfg->cur_invert_c) {
		if (pcfg->cur_invert_c == 1) {
			pcfg->di_detect_buf[0].paddr =
				pcfg->di_detect_wbuf[1].paddr;
			pcfg->di_detect_buf[1].paddr =
				pcfg->di_detect_wbuf[0].paddr;
			pcfg->di_detect_buf[2].paddr =
				pcfg->di_detect_wbuf[3].paddr;
			pcfg->di_detect_buf[3].paddr =
				pcfg->di_detect_wbuf[2].paddr;
			pcfg->di_detect_buf[4].paddr =
				pcfg->di_detect_wbuf[5].paddr;
			pcfg->di_detect_buf[5].paddr =
				pcfg->di_detect_wbuf[4].paddr;
			pcfg->di_detect_buf[6].paddr =
				pcfg->di_detect_wbuf[7].paddr;
			pcfg->di_detect_buf[7].paddr =
				pcfg->di_detect_wbuf[6].paddr;
			pcfg->cur_invert_a = 1;
			pcfg->cur_invert_b = 1;
			dbg_tb("%s:NR01E %x\n", __func__, data1);
		} else {
			pcfg->di_detect_buf[0].paddr =
				pcfg->di_detect_wbuf[0].paddr;
			pcfg->di_detect_buf[1].paddr =
				pcfg->di_detect_wbuf[1].paddr;
			pcfg->di_detect_buf[2].paddr =
				pcfg->di_detect_wbuf[2].paddr;
			pcfg->di_detect_buf[3].paddr =
				pcfg->di_detect_wbuf[3].paddr;
			pcfg->di_detect_buf[4].paddr =
				pcfg->di_detect_wbuf[4].paddr;
			pcfg->di_detect_buf[5].paddr =
				pcfg->di_detect_wbuf[5].paddr;
			pcfg->di_detect_buf[6].paddr =
				pcfg->di_detect_wbuf[6].paddr;
			pcfg->di_detect_buf[7].paddr =
				pcfg->di_detect_wbuf[7].paddr;
			pcfg->cur_invert_a = 0;
			pcfg->cur_invert_b = 2;
			dbg_tb("%s:NR01F %x\n", __func__, data1);
		}
			pcfg->cur_invert_c = 0;
	}

	canvas_config(di_tb_canvas,
		      pcfg->di_detect_buf[pcfg->di_tb_buff_wptr].paddr,
		      DIM_TB_DETECT_W, DIM_TB_DETECT_H,
		      CANVAS_ADDR_NOWRAP,
		      CANVAS_BLKMODE_LINEAR);
	op->bwr(NRDSWR_CTRL, di_tb_canvas, 0, 8);
	if (DIM_IS_IC_EF(T7))
		di_mif1_linear_wr_cfgds
			(pcfg->di_detect_buf[pcfg->di_tb_buff_wptr].paddr,
			 NRDSWR_STRIDE, NRDSWR_BADDR);
	//dim_nr_ds_hw_ctrl(true);
	dbg_tb("%s:e:ch[%d]dump %x frames start\n", __func__, ch,
		pcfg->di_tb_buff_wptr);
	return 1;
}

void dim_ds_detect(struct vframe_tb_s *vf, int data1, unsigned int ch)
{
	struct di_dev_s *di_devp = get_dim_de_devp();
	struct tb_core_s *pcfg;
	struct di_ch_s *pch;
	int ret = 0;

	pch = get_chdata(ch);

	if (!di_devp->tb_flag_int)
		return;
	if (!pch->en_tb) {
		//dim_nr_ds_hw_ctrl(false);
		return;
	}
	dbg_tb("%s :step 2 s\n", __func__);
	pcfg = dim_tbs[ch];

	if (vf->source_type !=
		VFRAME_SOURCE_TYPE_OTHERS)
		return;
	if ((vf->width * vf->height)
		> (1920 * 1088)) {
		// greater than (1920 * 1088), do not detect
		return;
	}

	if (pcfg->di_tb_buff_wptr < pcfg->di_tb_buffer_len) {
		ret = dim_tb_detect(vf, data1, ch);
		dbg_tb("%s:TB tb detect00,data1=%X\n", __func__, data1);
	} else {
		dbg_tb("%s :TB tb detect skip case2\n", __func__);
		atomic_set(&pcfg->di_tb_skip_flag, 1);
		pcfg->skip_picture++;
	}
	if (ret > 0) {
		pcfg->di_tb_buff_wptr++;
		if (pcfg->di_tb_buff_wptr >= DIM_TB_ALGO_COUNT &&
		    (atomic_read(&pcfg->dim_detect_status)
			== di_tb_idle)) {
			atomic_set
				(&pcfg->dim_detect_status,
				di_tb_running);
			dbg_tb("%s:TB tb detect01=%d\n", __func__,
			       pcfg->di_tb_buff_wptr);
		}
		if (pcfg->di_tb_buff_wptr >= DIM_TB_ALGO_COUNT) {
			atomic_set(&pcfg->di_tb_sem, 1);
			dbg_tb("%s:TB tb detect02=%d\n", __func__,
			       pcfg->di_tb_buff_wptr);
		}
	}
}

void dim_tb_function(struct vframe_tb_s *vf, int data1, unsigned int ch)
{
	int ret = 0;
	struct di_dev_s *di_devp = get_dim_de_devp();
	struct tb_core_s *pcfg;
	struct di_ch_s *pch;
	//const struct reg_acc *op = &di_pre_regset;

	pch = get_chdata(ch);

	if (!di_devp->tb_flag_int)
		return;
	if (!pch->en_tb) {
		//dim_nr_ds_hw_ctrl(false);
		return;
	}
	//dbg_tb("%s :s\n", __func__);
	pcfg = dim_tbs[ch];

	if (vf->source_type !=
		VFRAME_SOURCE_TYPE_OTHERS)
		goto SKIP_DETECT;
	if ((vf->width * vf->height)
		> (1920 * 1088)) {
		// greater than (1920 * 1088), do not detect
		goto SKIP_DETECT;
	}

	dbg_tb("%s:step 1 ch[%d]type=%x,cur_invert=%x,%x,%x,%x\n", __func__,
		ch, vf->type, pcfg->cur_invert, vf->width, vf->height, data1);

	//op->bwr(NR_DS_CTRL, vf->width / NR_DS_WIDTH, 16, 6);
	//op->bwr(NR_DS_CTRL, vf->height / 2 / NR_DS_HEIGHT, 24, 6);

	//if (data1 == 0)
		//pcfg->first_frame = 1;
	if (pcfg->first_frame) {
		pcfg->last_type = vf->type & VIDTYPE_TYPEMASK;
		pcfg->last_width = vf->width;
		pcfg->last_height = vf->height;
		pcfg->first_frame_type = pcfg->last_type;
		pcfg->di_tb_first_frame_type = pcfg->last_type;
		pcfg->first_frame = 0;
		pcfg->reset_tb = 0;
		pcfg->skip_picture = 0;
		pcfg->cur_invert = 0;
		pcfg->init_mute = pcfg->di_tb_init_mute;
		atomic_set(&pcfg->di_tb_skip_flag, 1);
		atomic_set(&pcfg->di_tb_reset_flag, 0);
		dbg_tb("%s:first f type:%x,first_frame_type %X\n", __func__,
		       pcfg->last_type, pcfg->first_frame_type);
	} else if ((pcfg->last_type ==
		   (vf->type & VIDTYPE_TYPEMASK)) && pcfg->last_type) {
		/* interlace seq changed */
		pcfg->first_frame_type =
			vf->type & VIDTYPE_TYPEMASK;
		pcfg->di_tb_first_frame_type =
			pcfg->first_frame_type;
		pcfg->reset_tb = 1;
		data1 = 0;
		/* keep old invert */
		dbg_tb("%s:DI:TB interlace seq chg,old:%d,new:%d,invert: %d\n",
		__func__,
		pcfg->last_type,
		pcfg->first_frame_type,
		pcfg->cur_invert);
	} else if ((pcfg->last_type == 0) &&
		((vf->type & VIDTYPE_TYPEMASK) != 0)) {
		/* prog -> interlace changed */
		pcfg->first_frame_type =
			vf->type & VIDTYPE_TYPEMASK;
		pcfg->di_tb_first_frame_type =
			pcfg->first_frame_type;
		pcfg->reset_tb = 1;
		dbg_tb("%s:TB prog -> interlace, new type: %d, invert: %d\n",
		       __func__, pcfg->first_frame_type, pcfg->cur_invert);
		/* not invert */
		pcfg->cur_invert = 0;
	} else if (((pcfg->last_width != vf->width) ||
		   (pcfg->last_height != vf->height)) &&
		   ((vf->type & VIDTYPE_TYPEMASK) != 0)) {
		/* size changed and next seq is interlace */
		pcfg->first_frame_type =
			vf->type & VIDTYPE_TYPEMASK;
		pcfg->di_tb_first_frame_type =
			pcfg->first_frame_type;
		pcfg->reset_tb = 1;
		/* keep old invert */
		dbg_tb("%s:TB tb size change new type: %d, invert: %d\n",
		__func__, pcfg->first_frame_type, pcfg->cur_invert);
	} else if ((pcfg->last_type != 0) &&
		((vf->type & VIDTYPE_TYPEMASK) == 0)) {
		/* interlace -> prog changed */
		dbg_tb("%s:TB tb interlace -> prog, invert: %d\n",
		       __func__, pcfg->cur_invert);
		/* not invert */
		pcfg->cur_invert = 0;
	}
	pcfg->last_type = vf->type & VIDTYPE_TYPEMASK;
	pcfg->last_width = vf->width;
	pcfg->last_height = vf->height;
	dbg_tb("%s:S frame type: %x,first_frame_type %X,cur_invert=%x\n", __func__,
		pcfg->last_type, pcfg->first_frame_type, pcfg->cur_invert);
	if (di_devp->tb_flag_int) {
		ret = 0;
		if (pcfg->di_tb_buffer_status <= 0)
			goto SKIP_DETECT;
		di_devp->tb_detect_buf_len = pcfg->di_tb_buffer_len;
		vf->type = (vf->type & ~TB_DETECT_MASK);
		if (pcfg->init_mute > 0) {
			pcfg->init_mute--;
			atomic_set(&pcfg->di_tb_skip_flag, 1);
			goto SKIP_DETECT;
		}
		if (pcfg->last_type == 0) {/* cur type is prog */
			pcfg->skip_picture++;
			pcfg->cur_invert = 0;
			goto SKIP_DETECT;
		}
		vf->type |=
			pcfg->cur_invert <<
			TB_DETECT_MASK_BIT;
		dbg_tb("%s: M first f type:%x,first_frame_type %X\n", __func__,
		       pcfg->last_type, pcfg->first_frame_type);

		if (pcfg->reset_tb) {
			/* wait tb task done */
			while ((pcfg->di_tb_buff_wptr >= DIM_TB_ALGO_COUNT) &&
				(pcfg->di_tb_buff_rptr <=
				 pcfg->di_tb_buff_wptr - DIM_TB_ALGO_COUNT) &&
				(atomic_read(&pcfg->di_tb_run_flag) == 1))
				usleep_range(100, 200);
			//usleep_range(4000, 5000);
			atomic_set(&pcfg->dim_detect_status, di_tb_idle);
			pcfg->di_tb_buff_wptr = 0;
			pcfg->di_tb_buff_rptr = 0;
			atomic_set(&pcfg->dim_tb_detect_flag, TB_DETECT_NC);
			atomic_set(&pcfg->di_tb_reset_flag, 1);
			atomic_set(&pcfg->di_tb_skip_flag, 1);
			pcfg->skip_picture = 0;
			pcfg->reset_tb  = 0;
			dbg_tb("%s reset once\n", __func__);
		}
		if ((atomic_read(&pcfg->dim_detect_status) == di_tb_done) &&
		    pcfg->skip_picture >=
		     di_devp->tb_detect_period &&
		    pcfg->last_type == pcfg->first_frame_type) {
			int tbf_flag =
				atomic_read(&pcfg->dim_tb_detect_flag);
			u8 old_invert = pcfg->cur_invert;

			atomic_set(&pcfg->dim_detect_status, di_tb_idle);
			pcfg->di_tb_buff_wptr = 0;
			pcfg->di_tb_buff_rptr = 0;
			pcfg->skip_picture = 0;
			if (tbf_flag == TB_DETECT_TBF &&
			    pcfg->first_frame_type == VIDTYPE_INTERLACE_TOP) {
				/* TBF sams as BFF */
				vf->type |=
					TB_DETECT_INVERT
					<< TB_DETECT_MASK_BIT;
				pcfg->cur_invert = 1;
			} else if ((tbf_flag == TB_DETECT_BFF) &&
				   (pcfg->first_frame_type ==
				    VIDTYPE_INTERLACE_TOP)) {
				vf->type |=
					TB_DETECT_INVERT
					<< TB_DETECT_MASK_BIT;
				pcfg->cur_invert = 1;
			} else if ((tbf_flag == TB_DETECT_TFF) &&
				   (pcfg->first_frame_type ==
				    VIDTYPE_INTERLACE_BOTTOM)) {
				vf->type |=
					TB_DETECT_INVERT
					<< TB_DETECT_MASK_BIT;
				pcfg->cur_invert = 1;
			} else if (tbf_flag != TB_DETECT_NC) {
				pcfg->cur_invert = 0;
			}
			vf->type = (vf->type & ~TB_DETECT_MASK);
			vf->type |=
				pcfg->cur_invert <<
				TB_DETECT_MASK_BIT;
			dbg_tb("%s process mask:vf[0x%x] type=0x%x\n",
			       __func__, vf->omx_index, vf->type);
			if (old_invert != pcfg->cur_invert)
				dbg_tb
				("%s:flag00: %d->%d, invert: %d->%d\n",
				__func__,
				pcfg->dim_tb_detect_last_flag,
				tbf_flag,
				old_invert,
				pcfg->cur_invert);
			else if (pcfg->dim_tb_detect_last_flag != tbf_flag)
				dbg_tb
				("%s:flag01:  %d->%d, invert: %d\n",
				__func__,
				pcfg->dim_tb_detect_last_flag,
				tbf_flag,
				pcfg->cur_invert);
			pcfg->dim_tb_detect_last_flag = tbf_flag;
			atomic_set(&pcfg->dim_tb_detect_flag, TB_DETECT_NC);
		}

		if (pcfg->di_tb_buff_wptr == 0 &&
		    pcfg->last_type != pcfg->first_frame_type) {
			pcfg->skip_picture++;
			atomic_set(&pcfg->di_tb_skip_flag, 1);
			dbg_tb("%s:TB tb detect skip case1\n", __func__);
			goto SKIP_DETECT;
		}
	} else {
		pcfg->reset_tb = 1;
		pcfg->skip_picture++;
		pcfg->cur_invert = 0;
		if (pcfg->init_mute > 0)
			pcfg->init_mute--;
		dbg_tb("%s :step 1 else\n", __func__);
	}
	dbg_tb("%s :step 1 e\n", __func__);

SKIP_DETECT:
	if (pcfg->skip_picture >
		di_devp->tb_detect_period) {
		pcfg->skip_picture =
			di_devp->tb_detect_period;
		dbg_tb("%s :skip\n", __func__);
	}
}

int dim_tb_buffer_init(unsigned int ch)
{
	int i;
	//int flags = CODEC_MM_FLAGS_DMA_CPU | CODEC_MM_FLAGS_CMA_CLEAR;
	//int flags = 0;
	struct di_dev_s *di_devp = get_dim_de_devp();
	struct tb_core_s *pcfg;
	struct dim_mm_s omm;
	//struct div2_mm_s *mm;
	bool ret;
	struct di_ch_s *pch;

	PR_INF("%s :s\n", __func__);

	if (!di_devp->tb_flag_int)
		return -1;

	pch = get_chdata(ch);
	if (!pch->en_tb)
		return -1;

	pcfg = dim_tbs[ch];

	di_tb_reg[ch] = kmalloc(sizeof(*di_tb_reg[ch]), GFP_KERNEL);
	if (!di_tb_reg[ch])
		return -1;

	memset(di_tb_reg[ch], 0, sizeof(struct tbff_stats));

	if (pcfg->di_tb_buffer_status)
		return pcfg->di_tb_buffer_status;

	if (di_tb_canvas < 0)
		di_tb_canvas =
			canvas_pool_map_alloc_canvas("tb_detect_dst");

	if (di_tb_canvas < 0)
		return -1;

	if (pcfg->di_tb_buffer_start == 0 && pch->en_tb) {
		if (!di_devp->tb_detect_buf_len)
			di_devp->tb_detect_buf_len = 8;
		pcfg->di_tb_buffer_len = di_devp->tb_detect_buf_len;
		pcfg->di_tb_buffer_size = DIM_TB_DETECT_H * DIM_TB_DETECT_W
			* pcfg->di_tb_buffer_len;
		pcfg->di_tb_buffer_size = PAGE_ALIGN(pcfg->di_tb_buffer_size);
		ret = mm_cma_alloc(NULL,
				   pcfg->di_tb_buffer_size >> PAGE_SHIFT,
				   &omm);
		pcfg->flg_from = 1;
		if (!ret) {
			pcfg->flg_from = 2;
			ret = mm_cma_alloc(&di_devp->pdev->dev,
				   pcfg->di_tb_buffer_size >> PAGE_SHIFT,
				   &omm);
			if (!ret) {
				PR_ERR("%s:cma\n", __func__);
				pcfg->flg_from = 0;
				return -1;
			}
		}
		pcfg->di_tb_buffer_start = omm.addr;
		pcfg->virt = omm.ppage;

		dbg_tb("%s:ch[%d] %x, size %x, item %d\n", __func__, ch,
			(unsigned int)pcfg->di_tb_buffer_start,
			(unsigned int)pcfg->di_tb_buffer_size,
			pcfg->di_tb_buffer_len);
		if (pcfg->di_tb_buffer_start == 0) {
			PR_ERR("di:err:DI:TB cma memory config fail\n");
			pcfg->di_tb_buffer_status = -1;
			return -1;
		}
		for (i = 0; i < pcfg->di_tb_buffer_len; i++) {
			pcfg->di_detect_buf[i].paddr =
				pcfg->di_tb_buffer_start +
				DIM_TB_DETECT_H * DIM_TB_DETECT_W * i;
			pcfg->di_detect_buf[i].vaddr =
				(ulong)codec_mm_vmap
				(pcfg->di_detect_buf[i].paddr,
				DIM_TB_DETECT_H * DIM_TB_DETECT_W);
			pcfg->di_detect_wbuf[i].paddr =
				pcfg->di_detect_buf[i].paddr;
			dbg_tb("%s:TBbuf(%d)paddr:%lx,vaddr: %lx,vaddr: %lx\n",
			       __func__, i, pcfg->di_detect_buf[i].paddr,
			       pcfg->di_detect_buf[i].vaddr,
			       pcfg->di_detect_wbuf[i].paddr);
		}
	}
	pcfg->di_tb_buffer_status = 1;
	dbg_tb("%s :e\n", __func__);
	return 1;
}

int dim_tb_buffer_uninit(unsigned int ch)
{
	int i;
	struct tb_core_s *pcfg;
	struct di_dev_s *di_devp = get_dim_de_devp();
	struct di_ch_s *pch;

	dbg_tb("%s :s\n", __func__);

	pch = get_chdata(ch);
	pcfg = dim_tbs[ch];

	if (!di_devp->tb_flag_int)
		return 0;
	if (!pch->en_tb)
		return 0;
	if (pcfg->di_tb_buffer_status <= 0)
		return 0;

	if (di_tb_canvas >= 0)
		canvas_pool_map_free_canvas(di_tb_canvas);
	di_tb_canvas = -1;
	if (pcfg->di_tb_buffer_start) {
		dbg_tb("%s:ch[%d] free addr is %x, size is %x\n", __func__, ch,
			(unsigned int)pcfg->di_tb_buffer_start,
			(unsigned int)pcfg->di_tb_buffer_size);
		for (i = 0; i < pcfg->di_tb_buffer_len; i++) {
			if (pcfg->di_detect_buf[i].vaddr) {
				codec_mm_unmap_phyaddr
					((u8 *)pcfg->di_detect_buf[i].vaddr);
				pcfg->di_detect_buf[i].vaddr = 0;
			}
		}
		if (pcfg->flg_from == 2)
			dma_release_from_contiguous
				(&di_devp->pdev->dev,
				 (struct page *)pcfg->virt,
				 pcfg->di_tb_buffer_size >> PAGE_SHIFT);
		else
			dma_release_from_contiguous
				(NULL,
				 (struct page *)pcfg->virt,
				 pcfg->di_tb_buffer_size >> PAGE_SHIFT);
		pcfg->di_tb_buffer_start = 0;
		pcfg->di_tb_buffer_size = 0;
		pcfg->virt = NULL;
	}
	pcfg->di_tb_buffer_status = 0;

	kfree(di_tb_reg[ch]);
	di_tb_reg[ch] = NULL;
	//di_devp->tb_detect = 0x8;
	dbg_tb("%s :e\n", __func__);
	return 0;
}

void dim_tb_reg_init(struct vframe_tb_s *vfm, unsigned int on, unsigned int ch)
{
	int val = 0;
	struct di_dev_s *di_devp = get_dim_de_devp();
	struct tb_core_s *pcfg;
	struct di_ch_s *pch;

	dbg_tb("%s :s\n", __func__);

	pch = get_chdata(ch);

	if (vfm->source_type !=
		VFRAME_SOURCE_TYPE_OTHERS)
		return;
	if ((vfm->width * vfm->height) > (1920 * 1088))
		return;
	if (!di_devp->tb_flag_int)
		return;
	if (!pch->en_tb)
		return;
	if (!(vfm->type & VIDTYPE_TYPEMASK))
		return;

	pcfg = dim_tbs[ch];

	if (on) {
		atomic_set(&pcfg->di_tb_sem, val);
		memset(pcfg->di_detect_buf, 0, sizeof(pcfg->di_detect_buf));
		memset(pcfg->di_detect_wbuf, 0, sizeof(pcfg->di_detect_wbuf));
		atomic_set(&pcfg->dim_detect_status, di_tb_idle);
		atomic_set(&pcfg->dim_tb_detect_flag, TB_DETECT_NC);
		atomic_set(&pcfg->di_tb_reset_flag, 0);
		atomic_set(&pcfg->di_tb_skip_flag, 0);
		atomic_set(&pcfg->di_tb_run_flag, 1);
		//di_devp->tb_detect = 0x8;
		di_devp->tb_detect_period = 0;
		di_devp->tb_detect_buf_len = 8;
		di_devp->tb_detect_init_mute = 0;

		pcfg->dim_tb_detect_last_flag = TB_DETECT_NC;
		pcfg->di_tb_buff_wptr = 0;
		pcfg->di_tb_buff_rptr = 0;
		pcfg->di_tb_buffer_status = 0;
		pcfg->di_tb_buffer_start = 0;
		pcfg->di_tb_buffer_size = 0;
		pcfg->di_tb_first_frame_type = 0;
		pcfg->di_tb_quit_flag = 0;
		pcfg->di_tb_init_mute = di_devp->tb_detect_init_mute;
		pcfg->cur_invert_b = 0;
		pcfg->cur_invert_a = 0;
		pcfg->first_frame = 1;
		pcfg->di_tb_buffer_len = DIM_TB_BUFFER_MAX_SIZE;
		pcfg->nr_dump_en = 0;
		pcfg->nr_dump_count = 0;
		pcfg->skip_picture = 0;
		pcfg->cur_invert = 0;
		dbg_tb("%s :ch[%d] TB init\n", __func__, ch);
	}
	dbg_tb("%s :e\n", __func__);
}

bool dim_tb_t_try_alloc(struct di_ch_s *pch)
{
	if (pch->tb_busy)
		return false;

	pch->tb_busy = true;
	pch->tb_owner = pch->ch_id;
	dbg_tb("%s :a:ch[%d]:alloc:ok\n", __func__, pch->ch_id);
	return true;
}

void dim_tb_polling_active(struct di_ch_s *pch)
{
	if (pch->en_tb_buf && pch->en_tb) {
		if (dim_tb_t_try_alloc(pch))
			pch->en_tb = true;
	}
}

void dim_tb_t_release(struct di_ch_s *pch)
{
	struct di_dev_s *di_devp = get_dim_de_devp();

	dbg_tb("%s :s\n", __func__);

	if (!di_devp->tb_flag_int)
		return;

	if (!pch->en_tb)
		return;

	if (pch->en_tb) {
		if (pch->ch_id == pch->tb_owner) {
			pch->tb_owner = 0xff;
			pch->tb_busy = false;
		} else {
			PR_ERR("%s:%d->%d\n",
			       __func__, pch->ch_id, pch->tb_owner);
		}
		pch->en_tb = false;
	}

	if (pch->en_tb_buf) {
		get_datal()->tb_src_cnt--;
		pch->en_tb_buf = false;
	}
	kfree(dim_tbs[pch->ch_id]);

	dbg_tb("%s :e:r:ch[%d]:cnt[%d]\n", __func__,
		pch->ch_id,
		get_datal()->tb_src_cnt);
}

void dim_tb_alloc(struct vframe_tb_s *vf, struct di_ch_s *pch)
{
	unsigned char tb_cnt, tb_nub;
	struct di_dev_s *di_devp = get_dim_de_devp();

	dbg_tb("%s 0:s = %d\n", __func__, pch->ch_id);

	if (!di_devp->tb_flag_int)
		return;

	pch->en_tb	= false;
	pch->en_tb_buf	= false;

	if (vf->source_type !=
		VFRAME_SOURCE_TYPE_OTHERS)
		return;
	if ((vf->width * vf->height) > (1920 * 1088))
		return;
	if (!(vf->type & VIDTYPE_TYPEMASK))
		return;

	tb_nub = cfgg(TB);
	if (!tb_nub)
		return;

	tb_cnt = get_datal()->tb_src_cnt;
	tb_cnt++;
	if (tb_cnt > tb_nub)
		return;

	if (!dim_tb_t_try_alloc(pch))
		return;

	pch->en_tb = true;
	pch->en_tb_buf = true;
	get_datal()->tb_src_cnt = tb_cnt;
	dbg_tb("%s s = %d\n", __func__, get_datal()->tb_src_cnt);

	dim_tbs[pch->ch_id] = kmalloc(sizeof(*dim_tbs[pch->ch_id]), GFP_KERNEL);
	if (!dim_tbs[pch->ch_id])
		return;
	//memset(dim_tbs[pch->ch_id], 0, sizeof(struct tb_core_s));

	dbg_tb("%s :e:ch[%d]:cnt[%d]\n", __func__,
		pch->ch_id,
		get_datal()->tb_src_cnt);
}

int dim_tb_task_process(struct vframe_tb_s *vf, u32 data, unsigned int ch)
{
	int tbff_flag = 0;
	ulong y5fld[5] = {0};
	int is_top = 0;
	int i;
	int di_inter_flag = 0;
	struct di_dev_s *di_devp = get_dim_de_devp();
	static const char * const detect_type[] = {"NC", "TFF", "BFF", "TBF"};
	struct tb_core_s *pcfg;
	struct di_ch_s *pch;

	dbg_tb("%s :step 4 s\n", __func__);

	if (!di_devp->tb_flag_int)
		return 1;
	if (vf->source_type !=
		VFRAME_SOURCE_TYPE_OTHERS)
		return 1;
	if ((vf->width * vf->height) > (1920 * 1088))
		return 1;

	pch = get_chdata(ch);
	if (!pch->en_tb)
		return 1;

	if (digfunc)
		digfunc->stats_init(di_tb_reg[ch],
				    DIM_TB_DETECT_H, DIM_TB_DETECT_W);

	pcfg = dim_tbs[ch];

	if (atomic_read(&pcfg->di_tb_sem) != 0) {
		if (pcfg->di_tb_quit_flag)
			return 1;

		if (pcfg->di_tb_buff_rptr == 0) {
			if (atomic_read(&pcfg->di_tb_reset_flag) != 0)
				pcfg->di_init = 0;
			atomic_set(&pcfg->di_tb_reset_flag, 0);
			if (digfunc)
				digfunc->fwalg_init(pcfg->di_init, ch);
		}
		pcfg->di_init = 1;
		is_top = (pcfg->di_tb_buff_rptr & 1) ? 0 : 1;

	if (pcfg->di_tb_buff_rptr == 0) {
		codec_mm_dma_flush
		((void *)pcfg->di_detect_buf[pcfg->di_tb_buff_rptr + 5].vaddr,
		DIM_TB_DETECT_W * DIM_TB_DETECT_H,
		DMA_FROM_DEVICE);
		codec_mm_dma_flush
		((void *)pcfg->di_detect_buf[pcfg->di_tb_buff_rptr + 4].vaddr,
		DIM_TB_DETECT_W * DIM_TB_DETECT_H,
		DMA_FROM_DEVICE);
		codec_mm_dma_flush
		((void *)pcfg->di_detect_buf[pcfg->di_tb_buff_rptr + 3].vaddr,
		DIM_TB_DETECT_W * DIM_TB_DETECT_H,
		DMA_FROM_DEVICE);
		codec_mm_dma_flush
		((void *)pcfg->di_detect_buf[pcfg->di_tb_buff_rptr + 2].vaddr,
		DIM_TB_DETECT_W * DIM_TB_DETECT_H,
		DMA_FROM_DEVICE);
		codec_mm_dma_flush
		((void *)pcfg->di_detect_buf[pcfg->di_tb_buff_rptr + 1].vaddr,
		DIM_TB_DETECT_W * DIM_TB_DETECT_H,
		DMA_FROM_DEVICE);
		codec_mm_dma_flush
		((void *)pcfg->di_detect_buf[pcfg->di_tb_buff_rptr].vaddr,
		DIM_TB_DETECT_W * DIM_TB_DETECT_H,
		DMA_FROM_DEVICE);
		if (data >= dimp_get(edi_mp_tb_dump) &&
		    dimp_get(edi_mp_tb_dump)) {
			pcfg->nr_dump_en = 1;
			if (pcfg->cur_invert_a == 1) {
				dim_dump_tb(1, ch);
				dim_dump_tb(0, ch);
				dim_dump_tb(3, ch);
				dim_dump_tb(2, ch);
			} else {
				dim_dump_tb(0, ch);
				dim_dump_tb(1, ch);
				dim_dump_tb(2, ch);
				dim_dump_tb(3, ch);
			}
		}
	} else if (pcfg->di_tb_buff_rptr == 1) {
		codec_mm_dma_flush((void *)pcfg->di_detect_buf[6].vaddr,
			DIM_TB_DETECT_W * DIM_TB_DETECT_H,
			DMA_FROM_DEVICE);
		if (pcfg->nr_dump_en) {
			if (pcfg->cur_invert_a == 1) {
				dim_dump_tb(5, ch);
				dim_dump_tb(4, ch);
			} else {
				dim_dump_tb(4, ch);
				dim_dump_tb(5, ch);
			}
		}

	} else if (pcfg->di_tb_buff_rptr == 2) {
		codec_mm_dma_flush((void *)pcfg->di_detect_buf[7].vaddr,
			DIM_TB_DETECT_W * DIM_TB_DETECT_H,
			DMA_FROM_DEVICE);
		if (pcfg->nr_dump_en) {
			if (pcfg->cur_invert_a == 1) {
				dim_dump_tb(7, ch);
				dim_dump_tb(6, ch);
			} else {
				dim_dump_tb(6, ch);
				dim_dump_tb(7, ch);
			}
		}

	} else if (pcfg->di_tb_buff_rptr == 3) {
		codec_mm_dma_flush((void *)pcfg->di_detect_buf[7].vaddr,
			DIM_TB_DETECT_W * DIM_TB_DETECT_H,
			DMA_FROM_DEVICE);
		if (pcfg->nr_dump_en) {
			dim_dump_tb(6, ch);
			dim_dump_tb(7, ch);
		}
	}
		/* new -> old */
		y5fld[0] = pcfg->di_detect_buf[pcfg->di_tb_buff_rptr + 4].vaddr;
		y5fld[1] = pcfg->di_detect_buf[pcfg->di_tb_buff_rptr + 3].vaddr;
		y5fld[2] = pcfg->di_detect_buf[pcfg->di_tb_buff_rptr + 2].vaddr;
		y5fld[3] = pcfg->di_detect_buf[pcfg->di_tb_buff_rptr + 1].vaddr;
		y5fld[4] = pcfg->di_detect_buf[pcfg->di_tb_buff_rptr].vaddr;

		if (digfunc) {
			if (IS_ERR_OR_NULL(di_tb_reg[ch])) {
				kfree(di_tb_reg[ch]);
				PR_ERR("di:err:DI:TB di_tb_reg is NULL!\n");
				return 1;
			}
			for (i = 0; i < 5; i++) {
				if (IS_ERR_OR_NULL((void *)y5fld[i])) {
					PR_ERR("di:err:DI:TB y5fld[%d]isNULL\n",
					       i);
					di_inter_flag = 1;
					break;
				}
			}
			if (di_inter_flag) {
				di_inter_flag = 0;
				return 1;
			}
			digfunc->stats_get(y5fld, di_tb_reg[ch]);
		}
		is_top = is_top ^ 1;
		tbff_flag = -1;
		if (digfunc)
			tbff_flag = digfunc->fwalg_get(di_tb_reg[ch], is_top,
				(pcfg->di_tb_first_frame_type == 3) ? 0 : 1,
				pcfg->di_tb_buff_rptr,
				atomic_read(&pcfg->di_tb_skip_flag),
				(dimp_get(edi_mp_nrds_en)) ? 1 : 0, ch);
		dbg_tb("%s TB=%x,=%x,=%x,=%x,=%x,data=%x,ch=%x\n", __func__,
			is_top,
			pcfg->di_tb_first_frame_type, pcfg->di_tb_buff_rptr,
			atomic_read(&pcfg->di_tb_skip_flag),
			tbff_flag, data, ch);
		if (pcfg->di_tb_buff_rptr == 0)
			atomic_set(&pcfg->di_tb_skip_flag, 0);

		if ((tbff_flag < -1) || tbff_flag > 2) {
			PR_ERR("di:err:DI:TB get tb detect flag error: %d\n",
			       tbff_flag);
		}

		if ((tbff_flag == -1) && (digfunc))
			tbff_flag =
				digfunc->majority_get(ch);

		if (tbff_flag == -1)
			tbff_flag =
				TB_DETECT_NC;
		else if (tbff_flag == 0)
			tbff_flag =
				TB_DETECT_TFF;
		else if (tbff_flag == 1)
			tbff_flag =
				TB_DETECT_BFF;
		else if (tbff_flag == 2)
			tbff_flag =
				TB_DETECT_TBF;
		else
			tbff_flag =
				TB_DETECT_NC;

		//tbff_flag =
			//TB_DETECT_NC;//mark for dis di tb

		pcfg->di_tb_buff_rptr++;
		dbg_tb("%s:task %d,%d\n", __func__,
		       pcfg->di_tb_buff_rptr, pcfg->di_tb_buffer_len);

		if ((pcfg->di_tb_buff_rptr >
		     pcfg->di_tb_buffer_len - DIM_TB_ALGO_COUNT) &&
		    (atomic_read(&pcfg->dim_detect_status) == di_tb_running)) {
			atomic_set(&pcfg->dim_tb_detect_flag, tbff_flag);
			dbg_tb("%s:TB get tb detect final flag: %s\n",
			       __func__, detect_type[tbff_flag]);
			atomic_set(&pcfg->dim_detect_status, di_tb_done);
		}
		atomic_set(&pcfg->di_tb_sem, 0);
	}
	atomic_set(&pcfg->di_tb_run_flag, 0);
	dbg_tb("%s :e\n", __func__);
	return 0;
}

void dim_tb_ext_cmd(struct vframe_s *vf, int data1, unsigned int ch,
		unsigned int cmd)
{
	struct tb_task_cmd_s tb_blk_cmd;
	struct vframe_tb_s cfg_data;
	struct vframe_tb_s *cfg = &cfg_data;

	memset(cfg, 0, sizeof(struct vframe_tb_s));
	if (!IS_ERR_OR_NULL(vf)) {
		cfg->height = vf->height;
		cfg->width = vf->width;
		cfg->source_type = vf->source_type;
		cfg->type = vf->type;
	}

	dbg_tb("%s :S\n", __func__);
	if (cmd == ECMD_TB_REG)
		dim_tb_alloc(cfg, get_chdata(ch));
	tb_blk_cmd.cmd = cmd;
	tb_blk_cmd.field_count = data1;
	tb_blk_cmd.ch = ch;
	tb_blk_cmd.in_buf_vf = vf;
	tb_task_alloc_block(ch, &tb_blk_cmd);
	if (cmd == ECMD_TB_PROC)
		dim_ds_detect(cfg, data1, ch);
}
#endif

#ifdef DIM_TB_DETECT
int RegisterTB_Function(struct TB_DetectFuncPtr *func, const char *ver)
{
	int ret = -1;

	mutex_lock(&di_tb_mutex);
	pr_info("DI:TB RegDITB digfunc %p, func: %p, ver:%s\n", digfunc,
		func, ver);
	if (!digfunc && func) {
		digfunc = func;
		ret = 0;
	}
	mutex_unlock(&di_tb_mutex);

	return ret;
}
EXPORT_SYMBOL(RegisterTB_Function);

int UnRegisterTB_Function(struct TB_DetectFuncPtr *func)
{
	int ret = -1;

	mutex_lock(&di_tb_mutex);
	pr_info("DI:TB UnRegDITB: digfunc %p, func: %p\n", digfunc, func);
	if (func && func == digfunc) {
		digfunc = NULL;
		ret = 0;
	}
	mutex_unlock(&di_tb_mutex);

	return ret;
}
EXPORT_SYMBOL(UnRegisterTB_Function);

void dim_nr_ds_hw_init(unsigned int width, unsigned int height, unsigned int ch)
{
	unsigned char h_step = 0, v_step = 0;
	unsigned int width_out, height_out;
	const struct reg_acc *op = &di_pre_regset;
	struct di_dev_s *di_devp = get_dim_de_devp();
	struct di_ch_s *pch;

	dbg_tb("%s :s\n", __func__);

	if (!di_devp->tb_flag_int)
		return;

	pch = get_chdata(ch);
	if (!pch->en_tb)
		return;

	width_out = NR_DS_WIDTH;
	height_out = NR_DS_HEIGHT;

	h_step = width / width_out;
	v_step = height / height_out;

	/*Switch MIF to NR_DS*/
	op->bwr(VIUB_MISC_CTRL0, 3, 5, 2);
	/* config dsbuf_ocol*/
	op->bwr(NR_DS_BUF_SIZE_REG, width_out, 0, 8);
	/* config dsbuf_orow*/
	op->bwr(NR_DS_BUF_SIZE_REG, height_out, 8, 8);

	op->bwr(NRDSWR_X, (width_out - 1), 0, 13);
	op->bwr(NRDSWR_Y, (height_out - 1), 0, 13);

	op->bwr(NRDSWR_CAN_SIZE, (height_out - 1), 0, 13);
	op->bwr(NRDSWR_CAN_SIZE, (width_out - 1), 16, 13);
	/* little endian */
	op->bwr(NRDSWR_CAN_SIZE, 1, 13, 1);

	op->bwr(NR_DS_CTRL, v_step, 16, 6);
	op->bwr(NR_DS_CTRL, h_step, 24, 6);
	op->bwr(NR_DS_CTRL, (dimp_get(edi_mp_blend_mode) >> 24) & 0xf, 12, 3);
	op->bwr(NR_DS_CTRL, (dimp_get(edi_mp_blend_mode) >> 24) & 0xf, 8, 3);
	//op->bwr(NR_DS_CTRL, 2, 8, 3);

	op->bwr(NR_DS_BLD_COEF, (dimp_get(edi_mp_blend_mode) >> 16) & 0xff,
		16, 8);
	op->bwr(NR_DS_BLD_COEF, (dimp_get(edi_mp_blend_mode) >> 8) & 0xff,
		8, 8);
	op->bwr(NR_DS_BLD_COEF, dimp_get(edi_mp_blend_mode) & 0xff, 0, 8);

	op->bwr(NR_DS_CTRL, (dimp_get(edi_mp_blend_mode) >> 28) & 0xf, 0, 1);
	dbg_tb("%s:e:done\n", __func__);
}

void dim_dump_tb(unsigned int data, unsigned int ch)
{
	struct tb_core_s *pcfg;

	pcfg = dim_tbs[ch];

	if (pcfg->nr_dump_en) {
		if (pcfg->nr_dump_count < NR_DETECT_DUMP_CNT) {
			diwrite_to_file(pcfg->di_detect_buf[data].paddr,
				NR_DS_WIDTH * NR_DS_HEIGHT
				* 1, ch);
			dbg_tb("%s:dump NR1 %d %d done\n", __func__,
			       pcfg->nr_dump_count, data);
			pcfg->nr_dump_count++;
		} else {
			dbg_tb("%s:dump done\n", __func__);
			pcfg->nr_dump_en = 0;
		}
	}
}

/*
 * 0x37f9 ~ 0x37fc 0x3740 ~ 0x3743 8 regs
 */
void dim_dump_nrds_reg(unsigned int base_addr)
{
	unsigned int i = 0x37f9;

	pr_info("-----nrds reg start-----\n");
	pr_info("[0x%x][0x%x]=0x%x\n",
		base_addr + (0x2006 << 2), i, DIM_RDMA_RD(0x2006));
	for (i = 0x37f9; i < 0x37fd; i++)
		pr_info("[0x%x][0x%x]=0x%x\n",
			base_addr + (i << 2), i, DIM_RDMA_RD(i));
	for (i = 0x3740; i < 0x3744; i++)
		pr_info("[0x%x][0x%x]=0x%x\n",
			base_addr + (i << 2), i, DIM_RDMA_RD(i));
	pr_info("-----nrds reg end-----\n");
}
#endif

/*
 * enable/disable nr ds mif&hw
 */
void dim_nr_ds_hw_ctrl(bool enable)
{
	/*Switch MIF to NR_DS*/
	const struct reg_acc *op = &di_pre_regset;
#ifdef DIM_TB_DETECT
	struct di_dev_s *di_devp = get_dim_de_devp();

	if (!di_devp->tb_flag_int)
		enable = 0;
#endif
	op->bwr(VIUB_MISC_CTRL0, enable ? 3 : 2, 5, 2);
	op->bwr(NRDSWR_CTRL, enable ? 1 : 0, 12, 1);
	op->bwr(NR_DS_CTRL, enable ? 1 : 0, 30, 1);
	dbg_tb("%s TB %d\n", __func__, enable);
}

void dim_tb_prob(void)
{
#ifdef DIM_TB_DETECT
	struct di_dev_s *di_devp = get_dim_de_devp();

	if (IS_IC_SUPPORT(TB))
		di_devp->tb_flag_int = 1;
	else
		di_devp->tb_flag_int = 0;
	PR_INF("%s:end=%d\n", __func__, di_devp->tb_flag_int);
#endif
}

