// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2015 MediaTek Inc.
 */

#include <linux/types.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>
#include <linux/sched.h>
#include <linux/sched/clock.h>
#include <linux/mm.h>
#include <linux/seq_file.h>
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
#include <linux/dma-buf.h>

#include "camera_mfb.h"
#include "engine_request.h"

#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>

#include <linux/soc/mediatek/mtk-cmdq-ext.h>
#if IS_ENABLED(CONFIG_MTK_CMDQ_MBOX_EXT)
#include <cmdq-util.h>
#endif
#include <soc/mediatek/smi.h>

#define TODO
#ifndef TODO
#define MFB_PMQOS
#endif
#ifdef MFB_PMQOS
#include <linux/pm_qos.h>
#include <mmdvfs_pmqos.h>
#endif

#define USE_SW_TOKEN

//#define __MFB_EP_NO_CLKMGR__
/* #define BYPASS_REG */
/* Measure the kernel performance */
/* #define __MFB_KERNEL_PERFORMANCE_MEASURE__ */
#ifdef __MFB_KERNEL_PERFORMANCE_MEASURE__
#include <linux/met_drv.h>
#include <linux/mtk_ftrace.h>
#endif

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

#ifdef CONFIG_COMPAT
/* 64 bit */
#include <linux/fs.h>
#include <linux/compat.h>
#endif

#ifdef MFB_USE_WAKELOCK
#include <linux/pm_wakeup.h>
#endif

/*GKI*/
#define CHECK_SERVICE_IF_0	0
#define CHECK_SERVICE_IF_1	1

#define CMDQ_COMMON
#define CLK_COMMON

#undef CONFIG_COMPAT
/* CCF */
#ifndef __MFB_EP_NO_CLKMGR__
#if !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK) /*CCF*/
#include <linux/clk.h>
#if (MTK_MFB_REG_VERSION == 3)
struct MFB_CLK_STRUCT {
	struct clk *CG_IMG2_LARB11;
	struct clk *CG_IMG2_MSS;
	struct clk *CG_IMG2_MFB;
	struct clk *CG_IMG2_GALS;
	struct clk *CG_IMG1_GALS;
};
struct MFB_CLK_STRUCT mfb_clk;
#elif (MTK_MFB_REG_VERSION == 2)
struct MFB_CLK_STRUCT {
	struct clk *CG_IMG2_LARB11;
	struct clk *CG_IMG2_MSS;
	struct clk *CG_IMG2_MFB;
	struct clk *CG_IMG2_GALS;
};
struct MFB_CLK_STRUCT mfb_clk;
#else
struct MFB_CLK_STRUCT {
	struct clk *CG_IMG1_LARB9;
	struct clk *CG_IMG1_MSS;
	struct clk *CG_IMG1_MFB;
};
struct MFB_CLK_STRUCT mfb_clk;
#endif
#endif	/* !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK)  */
#endif

#ifndef MTRUE
#define MTRUE               1
#endif
#ifndef MFALSE
#define MFALSE              0
#endif

#define MFB_DEV_NAME                "camera-mfb"

/* #define MFB_WAITIRQ_LOG */
#define MFB_USE_GCE
/* #define MFB_DEBUG_USE */
/*I can' test the situation in FPGA, because the velocity of FPGA is so slow. */
#define MyTag "[MFB]"
#define IRQTag "KEEPER"

#define LOG_VRB(format,	args...)    pr_debug(MyTag format, ##args)

#ifdef MFB_DEBUG_USE
#define LOG_DBG(format, args...)    pr_info(MyTag format, ##args)
#else
#define LOG_DBG(format, args...)
#endif

#define LOG_INF(format, args...)    pr_info(MyTag format,  ##args)
#define LOG_NOTICE(format, args...) pr_notice(MyTag format,  ##args)
#define LOG_WRN(format, args...)    pr_info(MyTag format,  ##args)
#define LOG_ERR(format, args...)    pr_info(MyTag format,  ##args)
#define LOG_AST(format, args...)    pr_info(MyTag format, ##args)


/******************************************************************************
 *
 ******************************************************************************/
/* #define MFB_WR32(addr, data)  iowrite32(data, addr) // For other projects. */
/* For 89 Only.   // NEED_TUNING_BY_PROJECT */
#define MFB_WR32(addr, data)    writel(data, addr)
#define MFB_RD32(addr)          readl(addr)
/******************************************************************************
 *
 ******************************************************************************/
/* dynamic log level *//*YWtodo*/
#define MFB_DBG_DBGLOG              (0x00000001)
#define MFB_DBG_INFLOG              (0x00000002)
#define MFB_DBG_INT                 (0x00000004)
#define MFB_DBG_READ_REG            (0x00000008)
#define MFB_DBG_WRITE_REG           (0x00000010)
#define MFB_DBG_TASKLET             (0x00000020)


/* ///////////////////////////////////////////////////////////////// */

/******************************************************************************
 *
 ******************************************************************************/

/* CAM interrupt status */
/* IRQ signal mask */

#define INT_ST_MASK_MSS     ( \
			MSS_INT_ST)
#define INT_ST_MASK_MSF     ( \
			MSF_INT_ST)

#define CMDQ_REG_MASK 0xffffffff

static irqreturn_t ISP_Irq_MSS(signed int Irq, void *DeviceId);
static irqreturn_t ISP_Irq_MSF(signed int Irq, void *DeviceId);
static void MFB_ScheduleMssWork(struct work_struct *data);
static void vmss_do_work(struct work_struct *data);
static void MFB_ScheduleMsfWork(struct work_struct *data);
static void vmsf_do_work(struct work_struct *data);
static signed int MSS_DumpReg(void);
static signed int MSF_DumpReg(void);

typedef irqreturn_t(*IRQ_CB) (signed int, void *);

struct ISR_TABLE {
	IRQ_CB isr_fp;
	unsigned int int_number;
	char device_name[16];
};

#ifndef CONFIG_OF
const struct ISR_TABLE MFB_IRQ_CB_TBL[MFB_IRQ_TYPE_AMOUNT] = {
	{ISP_Irq_MSS, MSS_IRQ_BIT_ID, "mss"},
	{ISP_Irq_MSF, MSF_IRQ_BIT_ID, "msf"},
};

#else
/* int number is got from kernel api */
const struct ISR_TABLE MFB_IRQ_CB_TBL[MFB_IRQ_TYPE_AMOUNT] = {
	{ISP_Irq_MSS, 0, "mss"},
	{ISP_Irq_MSF, 0, "msf"},
};

#endif
/* ////////////////////////////////////////////////////////////////////////// */

typedef void (*tasklet_cb) (unsigned long);
struct Tasklet_table {
	tasklet_cb tkt_cb;
	struct tasklet_struct *pMFB_tkt;
};

struct tasklet_struct Mfbtkt[MFB_IRQ_TYPE_AMOUNT];

static void ISP_TaskletFunc_MSS(unsigned long data);
static void ISP_TaskletFunc_MSF(unsigned long data);

static struct Tasklet_table MFB_tasklet[MFB_IRQ_TYPE_AMOUNT] = {
	{ISP_TaskletFunc_MSS, &Mfbtkt[MFB_IRQ_TYPE_INT_MSS_ST]},
	{ISP_TaskletFunc_MSF, &Mfbtkt[MFB_IRQ_TYPE_INT_MSF_ST]},
};
static struct work_struct logWork;
static void logPrint(struct work_struct *data);

struct wakeup_source MSS_wake_lock;
struct wakeup_source MSF_wake_lock;

static DEFINE_MUTEX(gMfbMssMutex);
static DEFINE_MUTEX(gMfbMssDequeMutex);

static DEFINE_MUTEX(gMfbMsfMutex);
static DEFINE_MUTEX(gMfbMsfDequeMutex);

static DEFINE_MUTEX(MutexMFBRef);
static DEFINE_MUTEX(Mutexgkibuf); //gki
#ifdef CONFIG_OF

struct MFB_device {
	void __iomem *regs;
	struct device *dev;
	int irq;
	struct device *larb;
};

static struct MFB_device *MFB_devs;
static int nr_MFB_devs;

static struct device *MFB_cmdq_dev;
static struct cmdq_client *mss_clt, *msf_clt;
static u16 mss_done_event_id, msf_done_event_id;
static u16 mss_token_id, msf_token_id;


/* Get HW modules' base address from device nodes */
#define MSS_DEV_NODE_IDX 1
#define MSF_DEV_NODE_IDX 0
#define IMGSYS_DEV_MODE_IDX 2

/* static unsigned long gISPSYS_Reg[MFB_IRQ_TYPE_AMOUNT]; */


#define ISP_MSS_BASE		(MFB_devs[MSS_DEV_NODE_IDX].regs)
#define ISP_MSF_BASE		(MFB_devs[MSF_DEV_NODE_IDX].regs)
#define ISP_IMGSYS_BASE		(MFB_devs[IMGSYS_DEV_MODE_IDX].regs)
/* #define ISP_MFB_BASE	(gISPSYS_Reg[MFB_DEV_NODE_IDX]) */

#else
#define ISP_MSS_BASE		(0x15012000)/*YWtodo*/
#define ISP_MSF_BASE		(0x15010000)/*YWtodo*/

#endif


static unsigned int g_u4EnableClockCount;
static unsigned int g_SuspendCnt;

/* maximum number for supporting user to do interrupt operation */
/* index 0 is for all the user that do not do register irq first */
#define IRQ_USER_NUM_MAX 31
#define GKI_BUF_NUM_MAX 200

#ifdef MFB_PMQOS
static struct pm_qos_request mfb_pmqos_request;
static u64 max_img_freq[4];
struct plist_head module_request_list;  /* all module list */
struct mm_qos_request mfb_mmqos_request;

static spinlock_t SpinLockMfbPmqos;
static unsigned int qos_scen[4];
static unsigned int qos_total;
#endif

struct  MSS_CONFIG_STRUCT {
	struct MFB_MSSConfig MssFrameConfig[_SUPPORT_MAX_MFB_FRAME_REQUEST_];
	struct MFB_MSSConfig vMssFrameConfig[_SUPPORT_MAX_MFB_FRAME_REQUEST_];
};

static struct MSS_CONFIG_STRUCT g_MssEnqueReq_Struct;
static struct MSS_CONFIG_STRUCT g_MssDequeReq_Struct;

struct  MSF_CONFIG_STRUCT {
	struct MFB_MSFConfig MsfFrameConfig[_SUPPORT_MAX_MFB_FRAME_REQUEST_];
};

static struct MSF_CONFIG_STRUCT g_MsfEnqueReq_Struct;
static struct MSF_CONFIG_STRUCT g_MsfDequeReq_Struct;

static struct engine_requests mss_reqs;
static struct engine_requests vmss_reqs;
static struct MFB_MSSRequest kMssReq;
static struct engine_requests msf_reqs;
static struct engine_requests vmsf_reqs;
static struct MFB_MSFRequest kMsfReq;

//gki
struct gki_buf {
	unsigned int isUse;
	unsigned int bfd;
	struct dma_buf *dma_buf;
	struct dma_buf_attachment *attach;
	struct sg_table *sgt;
};
static int qq_get_cnt;
static int qq_put_cnt;

/******************************************************************************
 *
 ******************************************************************************/
enum MFB_PROCESS_ID_ENUM {
	MFB_PROCESS_ID_NONE,
	MFB_PROCESS_ID_MSS,
	MFB_PROCESS_ID_vMSS,
	MFB_PROCESS_ID_MSF,
	MFB_PROCESS_ID_vMSF,
	MFB_PROCESS_ID_AMOUNT
};

struct  MFB_USER_INFO_STRUCT {
	pid_t Pid;
	pid_t Tid;
	struct engine_requests *reqs;
	enum MFB_PROCESS_ID_ENUM streamtag;
	struct gki_buf gkiBuf[GKI_BUF_NUM_MAX]; /* gki */
};

/******************************************************************************
 *
 ******************************************************************************/
struct MFB_IRQ_INFO_STRUCT {
	unsigned int Status[MFB_IRQ_TYPE_AMOUNT];
	signed int MssIrqCnt[IRQ_USER_NUM_MAX];
	signed int MssIrqUse[IRQ_USER_NUM_MAX];
	signed int MsfIrqCnt[IRQ_USER_NUM_MAX];
	pid_t ProcessID[IRQ_USER_NUM_MAX];
	pid_t ProcessFD[IRQ_USER_NUM_MAX];
	unsigned int Mask[MFB_IRQ_TYPE_AMOUNT];
};

struct MFB_INFO_STRUCT {
	spinlock_t SpinLockMFB;
	spinlock_t SpinLockIrq[MFB_IRQ_TYPE_AMOUNT];
	wait_queue_head_t WaitQueueHeadMss;
	wait_queue_head_t WaitQueueHeadMsf;
	struct work_struct ScheduleMssWork;
	struct work_struct vmsswork;
	struct work_struct ScheduleMsfWork;
	struct work_struct vmsfwork;
	struct workqueue_struct *wkqueueMss;
	struct workqueue_struct *wkqueueMsf;
	unsigned int UserCount;	/* User Count */
	unsigned int DebugMaskMss;	/* Debug Mask */
	unsigned int DebugMaskMsf;	/* Debug Mask */
	struct MFB_IRQ_INFO_STRUCT IrqInfo;
};

static struct MFB_INFO_STRUCT MFBInfo;

enum _eLOG_TYPE {
	_LOG_DBG = 0,	/* currently, only used at ipl_buf_ctrl.
			 * to protect critical section
			 */
	_LOG_INF = 1,
	_LOG_ERR = 2,
	_LOG_MAX = 3,
};

#define NORMAL_STR_LEN (512)
#define ERR_PAGE 2
#define DBG_PAGE 2
#define INF_PAGE 4
/* #define SV_LOG_STR_LEN NORMAL_STR_LEN */

#define LOG_PPNUM 2
static unsigned int m_CurrentPPB;
struct SV_LOG_STR {
	unsigned int _cnt[LOG_PPNUM][_LOG_MAX];
	/* char   _str[_LOG_MAX][SV_LOG_STR_LEN]; */
	char *_str[LOG_PPNUM][_LOG_MAX];
};

static void *pLog_kmalloc;
static struct SV_LOG_STR gSvLog[MFB_IRQ_TYPE_AMOUNT];

/* for irq used,keep log until IRQ_LOG_PRINTER being involked, */
/*    limited: */
/*    each log must shorter than 512 bytes */
/*    total log length in each irq/logtype can't over 1024 bytes */

#define IRQ_LOG_KEEPER(irq, ppb, logT, fmt, ...) do {\
	char *ptr; \
	char *pDes;\
	int avaLen;\
	unsigned int *ptr2 = &gSvLog[irq]._cnt[ppb][logT];\
	unsigned int str_leng;\
	unsigned int logi;\
	struct SV_LOG_STR *pSrc = &gSvLog[irq];\
	if (logT == _LOG_ERR) {\
		str_leng = NORMAL_STR_LEN*ERR_PAGE; \
	} else if (logT == _LOG_DBG) {\
		str_leng = NORMAL_STR_LEN*DBG_PAGE; \
	} else if (logT == _LOG_INF) {\
		str_leng = NORMAL_STR_LEN*INF_PAGE;\
	} else {\
		str_leng = 0;\
	} \
	ptr = pDes = (char *)&(gSvLog[irq].\
			_str[ppb][logT][gSvLog[irq].\
			_cnt[ppb][logT]]);    \
	avaLen = str_leng - 1 - gSvLog[irq]._cnt[ppb][logT];\
	if (avaLen > 1) {\
		snprintf((char *)(pDes), avaLen, fmt,\
			##__VA_ARGS__);   \
		if ('\0' != gSvLog[irq]._str[ppb][logT][str_leng - 1]) {\
			LOG_ERR("log str over flow(%d)", irq);\
		} \
		while (*ptr++ != '\0') {        \
			(*ptr2)++;\
		}     \
	} else { \
		LOG_INF("(%d)(%d)log str avalible=0, print log\n", irq, logT);\
		ptr = pSrc->_str[ppb][logT];\
		if (pSrc->_cnt[ppb][logT] != 0) {\
			if (logT == _LOG_DBG) {\
				for (logi = 0; logi < DBG_PAGE; logi++) {\
					if (ptr[NORMAL_STR_LEN*(logi+1) - 1] !=\
					    '\0') {\
						ptr[NORMAL_STR_LEN*(logi+1)\
						    - 1] = '\0';\
						LOG_DBG("%s",\
						    &ptr[NORMAL_STR_LEN*logi]);\
					} else {\
						LOG_DBG("%s",\
						    &ptr[NORMAL_STR_LEN*logi]);\
						break;\
					} \
				} \
			} \
			else if (logT == _LOG_INF) {\
				for (logi = 0; logi < INF_PAGE; logi++) {\
					if (ptr[NORMAL_STR_LEN*(logi+1) - 1] !=\
					    '\0') {\
						ptr[NORMAL_STR_LEN*(logi+1)\
						    - 1] = '\0';\
						LOG_INF("%s",\
						    &ptr[NORMAL_STR_LEN*logi]);\
					} else {\
						LOG_INF("%s",\
						    &ptr[NORMAL_STR_LEN*logi]);\
						break;\
					} \
				} \
			} \
			else if (logT == _LOG_ERR) {\
				for (logi = 0; logi < ERR_PAGE; logi++) {\
					if (ptr[NORMAL_STR_LEN*(logi+1) - 1] !=\
					    '\0') {\
						ptr[NORMAL_STR_LEN*(logi+1)\
						    - 1] = '\0';\
						LOG_INF("%s",\
						    &ptr[NORMAL_STR_LEN*logi]);\
					} else {\
						LOG_INF("%s",\
						    &ptr[NORMAL_STR_LEN*logi]);\
						break;\
					} \
				} \
			} \
			else {\
				LOG_INF("N.S.%d", logT);\
			} \
			ptr[0] = '\0';\
			pSrc->_cnt[ppb][logT] = 0;\
			avaLen = str_leng - 1;\
			ptr = pDes = (char *)&(\
			     pSrc->_str[ppb][logT][pSrc->_cnt[ppb][logT]]);\
			ptr2 = &(pSrc->_cnt[ppb][logT]);\
			snprintf((char *)(pDes), avaLen, fmt, ##__VA_ARGS__);\
			while (*ptr++ != '\0') {\
				(*ptr2)++;\
			} \
		} \
	} \
} while (0)

#define IRQ_LOG_PRINTER(irq, ppb_in, logT_in) do {\
	struct SV_LOG_STR *pSrc = &gSvLog[irq];\
	char *ptr;\
	unsigned int i;\
	signed int ppb = 0;\
	signed int logT = 0;\
	if (ppb_in > 1) {\
		ppb = 1;\
	} else {\
		ppb = ppb_in;\
	} \
	if (logT_in > _LOG_ERR) {\
		logT = _LOG_ERR;\
	} else {\
		logT = logT_in;\
	} \
	ptr = pSrc->_str[ppb][logT];\
	if (pSrc->_cnt[ppb][logT] != 0) {\
		if (logT == _LOG_DBG) {\
			for (i = 0; i < DBG_PAGE; i++) {\
				if (ptr[NORMAL_STR_LEN*(i+1) - 1] != '\0') {\
					ptr[NORMAL_STR_LEN*(i+1) - 1] = '\0';\
					LOG_DBG("%s", &ptr[NORMAL_STR_LEN*i]);\
				} else {\
					LOG_DBG("%s", &ptr[NORMAL_STR_LEN*i]);\
					break;\
				} \
			} \
		} \
	else if (logT == _LOG_INF) {\
		for (i = 0; i < INF_PAGE; i++) {\
			if (ptr[NORMAL_STR_LEN*(i+1) - 1] != '\0') {\
				ptr[NORMAL_STR_LEN*(i+1) - 1] = '\0';\
				LOG_INF("%s", &ptr[NORMAL_STR_LEN*i]);\
			} else {\
				LOG_INF("%s", &ptr[NORMAL_STR_LEN*i]);\
				break;\
			} \
		} \
	} \
	else if (logT == _LOG_ERR) {\
		for (i = 0; i < ERR_PAGE; i++) {\
			if (ptr[NORMAL_STR_LEN*(i+1) - 1] != '\0') {\
				ptr[NORMAL_STR_LEN*(i+1) - 1] = '\0';\
				LOG_ERR("%s", &ptr[NORMAL_STR_LEN*i]);\
			} else {\
				LOG_ERR("%s", &ptr[NORMAL_STR_LEN*i]);\
				break;\
			} \
		} \
	} \
	else {\
		LOG_ERR("N.S.%d", logT);\
	} \
		ptr[0] = '\0';\
		pSrc->_cnt[ppb][logT] = 0;\
	} \
} while (0)

/******************************************************************************
 *
 ******************************************************************************/
#define IMGSYS_REG_CG_CON      (ISP_IMGSYS_BASE + 0x0)
#define IMGSYS_REG_CG_SET      (ISP_IMGSYS_BASE + 0x4)
#define IMGSYS_REG_CG_CLR      (ISP_IMGSYS_BASE + 0x8)
#define IMGSYS_REG_SW_RST      (ISP_IMGSYS_BASE + 0xc)

#define MFB_MSS_INT_STATUS_REG  (ISP_MSS_BASE + 0x508)
#define MFB_MSF_INT_STATUS_REG  (ISP_MSF_BASE + 0x7c8)

#define MFB_MSS_TDRI_BASE_REG  (ISP_MSS_BASE + 0x804)
#define MFB_MSF_TDRI_BASE_REG  (ISP_MSF_BASE + 0x804)

#define MFB_MSS_TDRI_OFST_REG  (ISP_MSS_BASE + 0x808)
#define MFB_MSF_TDRI_OFST_REG  (ISP_MSF_BASE + 0x808)

#define MFB_MSS_CMDQ_BASE_ADDR_REG  (ISP_MSS_BASE + 0x500)
#define MFB_MSF_CMDQ_BASE_ADDR_REG  (ISP_MSF_BASE + 0x7C0)

#define MFB_MSS_CQLP_CMD_NUM_REG  (ISP_MSS_BASE + 0x600)
#define MFB_MSF_CQLP_CMD_NUM_REG  (ISP_MSF_BASE + 0x7F0)

#define MSSTOP_DMA_STOP_REG     (ISP_MSS_BASE + 0x414)
#define MSSTOP_DMA_STOP_STA_REG (ISP_MSS_BASE + 0x418)

#define MFBTOP_DMA_STOP_REG     (ISP_MSF_BASE + 0x4A4)
#define MFBTOP_DMA_STOP_STA_REG (ISP_MSF_BASE + 0x4A8)
#define MFBTOP_RESET_REG        (ISP_MSF_BASE + 0x4AC)
#define MFB_MSF_CMDQ_ENABLE_REG (ISP_MSF_BASE + 0x7C4)

#define MFB_MSF_TOP_DEBUG_SEL   (ISP_MSF_BASE + 0x4D0)
#define MFB_MSF_TOP_DEBUG_STA   (ISP_MSF_BASE + 0x4D4)
#define MFB_MSF_DMA_DEBUG_SEL   (ISP_MSF_BASE + 0x888)
#define MFB_MSF_TOP_CRC_1       (ISP_MSF_BASE + 0x4CC)

#define MFB_MSS_TOP_DBG_CTL0    (ISP_MSS_BASE + 0x434)
#define MFB_MSS_TOP_DBG_OUT2    (ISP_MSS_BASE + 0x440)
#define MFB_MSS_TOP_DBG_OUT3    (ISP_MSS_BASE + 0x444)
#define MFB_MSS_DMA_DEBUG_SEL   (ISP_MSS_BASE + 0x888)

#if (MTK_MFB_REG_VERSION >= 2)
#define MSS_BASE 0x15812000
#define MSF_BASE 0x15810000
#else
#define MSS_BASE 0x15012000
#define MSF_BASE 0x15010000
#endif

#define MFB_MSS_INT_STATUS_HW  (MSS_BASE + 0x508)
#define MFB_MSF_INT_STATUS_HW  (MSF_BASE + 0x7c8)

#define ISP_MSS_BASE_HW    (MSS_BASE + 0x000)
#define ISP_MSF_BASE_HW    (MSF_BASE + 0x000)

#define MFB_MSS_START_HW   (MSS_BASE + 0x50c)
#define MFB_MSF_START_HW   (MSF_BASE + 0x7cc)

#define MFB_MSS_INT_STA_HW  (MSS_BASE + 0x508)
#define MFB_MSF_INT_STA_HW  (MSF_BASE + 0x7c8)

#define MFB_MSS_CMDQ_ENABLE_HW  (MSS_BASE + 0x504)
#define MFB_MSF_CMDQ_ENABLE_HW  (MSF_BASE + 0x7C4)

#define MFB_MSS_CMDQ_BASE_ADDR_HW  (MSS_BASE + 0x500)
#define MFB_MSF_CMDQ_BASE_ADDR_HW  (MSF_BASE + 0x7C0)

#define MFB_MSS_CQLP_CMD_NUM_HW  (MSS_BASE + 0x600)
#define MFB_MSF_CQLP_CMD_NUM_HW  (MSF_BASE + 0x7F0)

#define MFB_MSS_CQLP_ENG_EN_HW  (MSS_BASE + 0x604)
#define MFB_MSF_CQLP_ENG_EN_HW  (MSF_BASE + 0x7F4)

#define MFB_MSS_TDRI_BASE_HW  (MSS_BASE + 0x804)
#define MFB_MSS_TDRI_OFST_HW  (MSS_BASE + 0x808)
#define MFB_MSF_TDRI_BASE_HW  (MSF_BASE + 0x804)
#define MFB_MSF_TDRI_OFST_HW  (MSF_BASE + 0x808)

#define MFB_MSS_IY_BASE_HW  (MSS_BASE + 0xA00)
#define MFB_MSS_IC_BASE_HW  (MSS_BASE + 0xA40)
#define MFB_MSS_OY_BASE_HW  (MSS_BASE + 0x900)
#define MFB_MSS_OC_BASE_HW  (MSS_BASE + 0x940)

/******************************************************************************
 *
 ******************************************************************************/
static inline unsigned int MFB_MsToJiffies(unsigned int Ms)
{
	return ((Ms * HZ + 512) >> 10);
}

/******************************************************************************
 *
 ******************************************************************************/
static inline unsigned int MFB_UsToJiffies(unsigned int Us)
{
	return (((Us / 1000) * HZ + 512) >> 10);
}

/******************************************************************************
 *
 ******************************************************************************/
static inline unsigned int MSS_GetIRQState(
	unsigned int type, unsigned int *userNumber, unsigned int stus,
	enum MFB_PROCESS_ID_ENUM whichReq, int ProcessID)
{
	unsigned int ret = 0;
	unsigned int p;
	unsigned long flags; /* old: unsigned int flags;*/
			     /* FIX to avoid build warning */

	p = ProcessID % IRQ_USER_NUM_MAX;
	spin_lock_irqsave(&(MFBInfo.SpinLockIrq[type]), flags);
	if (stus & MSS_INT_ST) {
		LOG_DBG("%s MssIrqCnt[%d] is %d for pid %d", __func__,
			p,
			MFBInfo.IrqInfo.MssIrqCnt[p],
			MFBInfo.IrqInfo.ProcessID[p]);
		ret = ((MFBInfo.IrqInfo.MssIrqCnt[p] > 0)
		       && (MFBInfo.IrqInfo.ProcessID[p] == ProcessID));
	} else {
		LOG_ERR(
		"WaitIRQ Status Error, type:%d, userNumber:%d, status:%d, whichReq:%d, ProcessID:0x%x\n",
		     type, *userNumber, stus, p, ProcessID);
	}
	*userNumber = ret;
	if (ret == 1 && MFBInfo.IrqInfo.MssIrqCnt[p] == 1) {
		LOG_DBG("%s last mssirqcnt %d clearing pid %d for proc %d",
			__func__,
			MFBInfo.IrqInfo.MssIrqCnt[p],
			MFBInfo.IrqInfo.ProcessID[p],
			p);
		MFBInfo.IrqInfo.ProcessID[p] = 0;
	}
	spin_unlock_irqrestore(&(MFBInfo.SpinLockIrq[type]), flags);

	return ret;
}

/******************************************************************************
 *
 ******************************************************************************/
static inline unsigned int MSF_GetIRQState(
	unsigned int type, unsigned int userNumber, unsigned int stus,
	enum MFB_PROCESS_ID_ENUM whichReq, int ProcessID)
{
	unsigned int ret = 0;
	unsigned int p;
	unsigned long flags; /* old: unsigned int flags;*/
			     /* FIX to avoid build warning */

	p = ProcessID % IRQ_USER_NUM_MAX;
	spin_lock_irqsave(&(MFBInfo.SpinLockIrq[type]), flags);
	if (stus & MSF_INT_ST) {
		LOG_DBG("%s MsfIrqCnt is %d for pid %d", __func__,
			MFBInfo.IrqInfo.MsfIrqCnt[p],
			MFBInfo.IrqInfo.ProcessFD[p]);
		ret = ((MFBInfo.IrqInfo.MsfIrqCnt[p] > 0)
		       && (MFBInfo.IrqInfo.ProcessFD[p] == ProcessID));
	} else {
		LOG_ERR(
		"WaitIRQ Status Error, type:%d, userNumber:%d, status:%d, whichReq:%d, ProcessID:0x%x\n",
		     type, userNumber, stus, p, ProcessID);
	}
	spin_unlock_irqrestore(&(MFBInfo.SpinLockIrq[type]), flags);
	if (ret == 1) {
		LOG_DBG("%s last msfirqcnt %d not clearing pid %d for proc %d",
			__func__,
			MFBInfo.IrqInfo.MsfIrqCnt[p],
			MFBInfo.IrqInfo.ProcessFD[p],
			p);
	}

	return ret;
}

/******************************************************************************
 *
 ******************************************************************************/
static inline unsigned int MFB_JiffiesToMs(unsigned int Jiffies)
{
	return ((Jiffies * 1000) / HZ);
}

#ifdef MFB_PMQOS
void MFBQOS_Init(void)
{
	s32 result = 0;
	u64 img_freq_steps[MAX_FREQ_STEP];
	u32 step_size;

	/* Call pm_qos_add_request when initialize module or driver prob */
	pm_qos_add_request(
		&mfb_pmqos_request,
		PM_QOS_IMG_FREQ,
		PM_QOS_MM_FREQ_DEFAULT_VALUE);

	/* Call mmdvfs_qos_get_freq_steps to get supported frequency */
	result = mmdvfs_qos_get_freq_steps(
		PM_QOS_IMG_FREQ,
		img_freq_steps,
		&step_size);

	if (result < 0 || step_size == 0)
		LOG_INF("get MMDVFS freq steps failed, result: %d\n", result);
	else {
		max_img_freq[0] = img_freq_steps[0];
		max_img_freq[1] = img_freq_steps[1];
		max_img_freq[2] = img_freq_steps[2];
		max_img_freq[3] = img_freq_steps[3];
	}

	/* Initialize owner list */
	plist_head_init(&module_request_list);

	/* Call mm_qos_add_request */
	/* when initialize module or driver prob */
#if (MTK_MFB_REG_VERSION >= 2)
	mm_qos_add_request(&module_request_list,
		&mfb_mmqos_request, M4U_PORT_L11_IMG_MFB_RDMA0);
#else
	mm_qos_add_request(&module_request_list,
		&mfb_mmqos_request, M4U_PORT_L9_IMG_MFB_RDMA0_MDP);
#endif
}

void MFBQOS_Uninit(void)
{
	pm_qos_remove_request(&mfb_pmqos_request);

	/* Call mm_qos_remove_request */
	/* when de-initialize module or driver remove */
	mm_qos_remove_all_request(&module_request_list);
}

void MFBQOS_Update(bool start, unsigned int scen, unsigned long bw)
{
	LOG_DBG("start: %d, MFB scen: %d, bw: %lu", start, scen, bw);
	if (start) { /* start MFB, configure MMDVFS to highest CLK */
		LOG_DBG("MFB total: %ld", qos_total);
		spin_lock(&(SpinLockMfbPmqos));
		if (bw != 0)
			qos_scen[scen] = bw;
		qos_total = qos_total + bw;
		if (qos_total > 600000000) {
			spin_unlock(&(SpinLockMfbPmqos));
			pm_qos_update_request(&mfb_pmqos_request,
						max_img_freq[0]);
		} else if (qos_total > 300000000) {
			spin_unlock(&(SpinLockMfbPmqos));
			pm_qos_update_request(&mfb_pmqos_request,
						max_img_freq[1]);
		} else if (qos_total > 100000000) {
			spin_unlock(&(SpinLockMfbPmqos));
			pm_qos_update_request(&mfb_pmqos_request,
						max_img_freq[2]);
		} else {
			spin_unlock(&(SpinLockMfbPmqos));
			pm_qos_update_request(&mfb_pmqos_request, 0);
		}
	} else { /* finish MFB, config MMDVFS to lowest CLK */
		LOG_DBG("MFB total: %ld", qos_total);
		spin_lock(&(SpinLockMfbPmqos));
		qos_total = qos_total - qos_scen[scen];
		if (qos_total > 600000000) {
			spin_unlock(&(SpinLockMfbPmqos));
			pm_qos_update_request(&mfb_pmqos_request,
						max_img_freq[0]);
		} else if (qos_total > 300000000) {
			spin_unlock(&(SpinLockMfbPmqos));
			pm_qos_update_request(&mfb_pmqos_request,
						max_img_freq[1]);
		} else if (qos_total > 100000000) {
			spin_unlock(&(SpinLockMfbPmqos));
			pm_qos_update_request(&mfb_pmqos_request,
						max_img_freq[2]);
		} else {
			spin_unlock(&(SpinLockMfbPmqos));
			pm_qos_update_request(&mfb_pmqos_request, 0);
		}
	}
#if CHECK_SERVICE_IF_0 /*YWtodo*/
	if (start) {
		/* Call mm_qos_set_request API to setup estimated data bw */
		mm_qos_set_request(&mfb_mmqos_request,
					bw/1000000, 0, BW_COMP_NONE);
		/* Call mm_qos_update_all_requests API */
		/* update necessary HW configuration for MM BW */
		mm_qos_update_all_request(&module_request_list);
	} else {
		mm_qos_set_request(&mfb_mmqos_request, 0, 0, BW_COMP_NONE);
		mm_qos_update_all_request(&module_request_list);
	}
#endif
}
#endif

#if CHECK_SERVICE_IF_0/*YWtodo*/
static int cmdq_engine_secured(struct cmdqRecStruct *handle,
						enum CMDQ_ENG_ENUM engine)
{
	cmdqRecSetSecure(handle, 1);
	cmdqRecSecureEnablePortSecurity(handle, (1LL << engine));
	cmdqRecSecureEnableDAPC(handle, (1LL << engine));

	return 0;
}
#endif

/*TODO : M4U_PORT */
#if CHECK_SERVICE_IF_0
static int cmdq_sec_base(struct cmdqRecStruct *handle, unsigned int dma_sec,
			unsigned int reg, unsigned int val, unsigned int size)
{
	if (dma_sec != 0)
		cmdqRecWriteSecure(handle, reg, CMDQ_SAM_H_2_MVA, val, 0, size,
							M4U_PORT_MFB_RDMA);
	else
		cmdqRecWrite(handle, reg, val, CMDQ_REG_MASK);

	return 0;
}
#endif

static int mfb_get_dma_buf(struct gki_buf *gbf, int fd)
{
	struct dma_buf *buf;

	buf = dma_buf_get(fd);
	if (IS_ERR(buf))
		return -1;

	gbf->dma_buf = buf;
	gbf->attach = dma_buf_attach(gbf->dma_buf, MFB_devs[0].dev);
	if (IS_ERR(gbf->attach))
		goto err_attach;

	gbf->sgt = dma_buf_map_attachment(gbf->attach, DMA_BIDIRECTIONAL);
	if (IS_ERR(gbf->sgt))
		goto err_map;
	LOG_DBG("QQ get_dma: dma_buf=%p, attach=%p, sgt=%p", gbf->dma_buf, gbf->attach, gbf->sgt);
	return 0;

err_map:
	dma_buf_detach(gbf->dma_buf, gbf->attach);
err_attach:
	dma_buf_put(gbf->dma_buf);

	return -1;
}

static void mfb_put_dma_buf(struct gki_buf *gbf)
{
	LOG_DBG("QX put_dma: dma_buf=%p, attach=%p, sgt=%p", gbf->dma_buf, gbf->attach, gbf->sgt);
	dma_buf_unmap_attachment(gbf->attach, gbf->sgt, DMA_BIDIRECTIONAL);
	dma_buf_detach(gbf->dma_buf, gbf->attach);
	dma_buf_put(gbf->dma_buf);
}

static void mss_pkt_tcmds(struct cmdq_pkt *handle,
				struct MFB_MSSConfig *pMssConfig)
{
#ifdef CMDQ_COMMON
	unsigned int t;

	if (pMssConfig->tpipe_used > TPIPE_NUM_PER_FRAME) {
		pMssConfig->tpipe_used = TPIPE_NUM_PER_FRAME;
		LOG_ERR("tpipe_used %d over limit of %d",
				pMssConfig->tpipe_used, TPIPE_NUM_PER_FRAME);
	}

	/* fixed 0x0000 0001: [0] MSS, [1] P2*/
	cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSS_CQLP_ENG_EN_HW,
			pMssConfig->MSSCQLP_ENG_EN, CMDQ_REG_MASK);
	for (t = 0; t < pMssConfig->tpipe_used; t++) {
		/* cq */
		if (pMssConfig->MSSCMDQ_BASE[t] == 0) {
			LOG_ERR("tpipe_used = %d MSSCMDQ_BASE = 0",
					pMssConfig->tpipe_used);
			break;
		}
		cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSS_CMDQ_ENABLE_HW,
				pMssConfig->MSSCMDQ_ENABLE[t], CMDQ_REG_MASK);
		cmdq_pkt_write(handle, NULL,
				(dma_addr_t)MFB_MSS_CMDQ_BASE_ADDR_HW,
				pMssConfig->MSSCMDQ_BASE[t], CMDQ_REG_MASK);
		cmdq_pkt_write(handle, NULL,
				(dma_addr_t)MFB_MSS_CQLP_CMD_NUM_HW,
				pMssConfig->MSSCQLP_CMD_NUM[t], CMDQ_REG_MASK);
		/* tdr */
		cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSS_TDRI_BASE_HW,
				pMssConfig->MSSDMT_TDRI_BASE[t], CMDQ_REG_MASK);

		/* I/O */
		if (pMssConfig->update_dma_en[t] == 1) {
			cmdq_pkt_write(handle, NULL,
				(dma_addr_t)MFB_MSS_IY_BASE_HW,
				pMssConfig->dmas[t].MSSDMT_IY_BASE,
				CMDQ_REG_MASK);
			cmdq_pkt_write(handle, NULL,
				(dma_addr_t)MFB_MSS_IC_BASE_HW,
				pMssConfig->dmas[t].MSSDMT_IC_BASE,
				CMDQ_REG_MASK);
			cmdq_pkt_write(handle, NULL,
				(dma_addr_t)MFB_MSS_OY_BASE_HW,
				pMssConfig->dmas[t].MSSDMT_OY_BASE,
				CMDQ_REG_MASK);
			cmdq_pkt_write(handle, NULL,
				(dma_addr_t)MFB_MSS_OC_BASE_HW,
				pMssConfig->dmas[t].MSSDMT_OC_BASE,
				CMDQ_REG_MASK);
		}
		/* start */
		cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSS_START_HW,
				0x1, CMDQ_REG_MASK);
		/* wfe */
		cmdq_pkt_wfe(handle, mss_done_event_id);
		cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSS_INT_STA_HW,
				0x1, CMDQ_REG_MASK);
		LOG_DBG("MSS_CMDQ_ENABLE%d = 0x%x", t,
						pMssConfig->MSSCMDQ_ENABLE[t]);
		LOG_DBG("MSSCMDQ_BASE%d = 0x%x", t,
						pMssConfig->MSSCMDQ_BASE[t]);
		LOG_DBG("MSSCQLP_CMD_NUM%d = 0x%x", t,
						pMssConfig->MSSCQLP_CMD_NUM[t]);
		LOG_DBG("MSSDMT_TDRI_BASE%d = 0x%x", t,
					pMssConfig->MSSDMT_TDRI_BASE[t]);
	}
	LOG_DBG("%s: tpipe_used is %d", __func__, pMssConfig->tpipe_used);
	LOG_INF("mss cmdq write done %d", pMssConfig->tpipe_used);
#endif
}

static void mss_norm_sirq(struct cmdq_cb_data data)
{
#ifdef CMDQ_COMMON
	struct cmdq_pkt *pkt;
	bool bResulst = MFALSE;
	pid_t ProcessID;
	unsigned long flag;
	unsigned int p = 0;

	pkt = (struct cmdq_pkt *) data.data;
	if (data.err < 0) {
		mfb_request_dump(&mss_reqs);
		MSS_DumpReg();
		LOG_ERR("%s_mss: call back error(%d)", __func__, data.err);
		goto EXIT;
	}

	spin_lock_irqsave(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]),
									flag);
	if (mfb_update_request(&mss_reqs, &ProcessID) == 0)
		bResulst = MTRUE;
	/* Config the Next frame */
	if (bResulst == MTRUE) {
		#if REQUEST_REGULATION == REQUEST_BASE_REGULATION
		queue_work(MFBInfo.wkqueueMss, &MFBInfo.ScheduleMssWork);
		#endif
		p = ProcessID % IRQ_USER_NUM_MAX;
		MFBInfo.IrqInfo
		    .Status[MFB_IRQ_TYPE_INT_MSS_ST] |= MSS_INT_ST;
		MFBInfo.IrqInfo
		    .ProcessID[p] = ProcessID;
		MFBInfo.IrqInfo.MssIrqCnt[p]++;
	}
	spin_unlock_irqrestore(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]),
									flag);
	if (bResulst == MTRUE) {
#ifdef MFB_PMQOS
		MFBQOS_Update(0, 0, 0);
#endif
		wake_up_interruptible(&MFBInfo.WaitQueueHeadMss);
	}

	/* dump log, use tasklet */
	IRQ_LOG_KEEPER(MFB_IRQ_TYPE_INT_MSS_ST, m_CurrentPPB, _LOG_INF,
		       "%s: bResulst:%d, MssIrqCnt[%d]:0x%x\n",
		       __func__, bResulst, p,
			MFBInfo.IrqInfo.MssIrqCnt[p]);

	#if (REQUEST_REGULATION == FRAME_BASE_REGULATION)
	queue_work(MFBInfo.wkqueueMss, &MFBInfo.ScheduleMssWork);
	#endif

	tasklet_schedule(MFB_tasklet[MFB_IRQ_TYPE_INT_MSS_ST].pMFB_tkt);
EXIT:
	cmdq_pkt_destroy(pkt);
#endif
}

signed int CmdqMSSHW(struct frame *frame)
{
#ifdef CMDQ_COMMON
	struct MFB_MSSConfig *pMssConfig;
	struct cmdq_pkt *handle;

	if (frame == NULL || frame->data == NULL)
		return -1;

	LOG_DBG("%s request sent to CMDQ driver", __func__);
	pMssConfig = (struct MFB_MSSConfig *) frame->data;

	if (MFB_DBG_DBGLOG == (MFB_DBG_DBGLOG & MFBInfo.DebugMaskMss))
		LOG_DBG("ConfigMSSHW Start!\n");

	/*cmdq_pkt_cl_create(&handle, mss_clt);*/
	handle = cmdq_pkt_create(mss_clt);

	handle->priority = 20;

	/*if (pMssConfig->eng_secured == 1)*//*YWtodo*/
		/*cmdq_engine_secured(handle, CMDQ_ENG_MSS);*/
#ifdef USE_SW_TOKEN
	cmdq_pkt_acquire_event(handle, mss_token_id);
#endif
#define TPIPE_MODE_PREVIEW
#ifdef TPIPE_MODE_PREVIEW
	mss_pkt_tcmds(handle, pMssConfig);
#else
	cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSS_CMDQ_ENABLE_HW,
			pMssConfig->MSSCMDQ_ENABLE[0], CMDQ_REG_MASK);
	cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSS_CMDQ_BASE_ADDR_HW,
			pMssConfig->MSSCMDQ_BASE[0], CMDQ_REG_MASK);
	cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSS_CQLP_CMD_NUM_HW,
			pMssConfig->MSSCQLP_CMD_NUM[0], CMDQ_REG_MASK);
	/* fixed 0x0000 0001: [0] MSS, [1] P2*/
	cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSS_CQLP_ENG_EN_HW,
			pMssConfig->MSSCQLP_ENG_EN, CMDQ_REG_MASK);
#ifndef BYPASS_REG
	cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSS_START_HW,
			0x1, CMDQ_REG_MASK);
	cmdq_pkt_wfe(handle, mss_done_event_id);
	/* non-blocking API, Please  use cmdqRecFlushAsync() */
#endif
#endif
#ifdef USE_SW_TOKEN
	cmdq_pkt_clear_event(handle, mss_token_id);
#endif
#ifdef MFB_PMQOS
	MFBQOS_Update(1, 0, pMssConfig->qos);
#endif
	cmdq_pkt_flush_threaded(handle, mss_norm_sirq, (void *)handle);
#endif
	return 0;
}

signed int mss_enque_cb(struct frame *frames, void *req)
{
	unsigned int f, fcnt;
	struct MFB_MSSRequest *_req;
	struct MFB_MSSConfig *pcfg;

	_req = (struct MFB_MSSRequest *) req;

	if (frames == NULL || _req == NULL)
		return -1;

	fcnt = _req->m_ReqNum;
	for (f = 0; f < fcnt; f++) {
		LOG_DBG("[%s]request enque frame(%d/%d) 0x%p",
					__func__, f, fcnt, frames[f].data);
		memcpy(frames[f].data, &_req->m_pMssConfig[f],
						sizeof(struct MFB_MSSConfig));
		pcfg = &_req->m_pMssConfig[f];
	}

	return 0;
}

signed int mss_deque_cb(struct frame *frames, void *req)
{
	unsigned int f, fcnt;
	struct MFB_MSSRequest *_req;
	struct MFB_MSSConfig *pcfg;

	_req = (struct MFB_MSSRequest *) req;

	if (frames == NULL || _req == NULL)
		return -1;

	fcnt = _req->m_ReqNum;
	for (f = 0; f < fcnt; f++) {
		memcpy(&_req->m_pMssConfig[f], frames[f].data,
						sizeof(struct MFB_MSSConfig));
		LOG_DBG("[%s]request deque frame(%d/%d).", __func__, f, fcnt);
		pcfg = &_req->m_pMssConfig[f];
	}

	return 0;
}

static void mss_vss_sirq(struct cmdq_cb_data data)
{
#ifdef CMDQ_COMMON
	struct cmdq_pkt *pkt;
	bool bResulst = MFALSE;
	pid_t ProcessID;
	unsigned long flag;
	unsigned int p = 0;

	pkt = (struct cmdq_pkt *) data.data;
	if (data.err < 0) {
		mfb_request_dump(&vmss_reqs);
		MSS_DumpReg();
		LOG_ERR("%s_mss: call back error(%d)", __func__, data.err);
		goto EXIT;
	}

	spin_lock_irqsave(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]),
									flag);
	if (mfb_update_request(&vmss_reqs, &ProcessID) == 0)
		bResulst = MTRUE;
	/* Config the Next frame */
	if (bResulst == MTRUE) {
		#if REQUEST_REGULATION == REQUEST_BASE_REGULATION
		queue_work(MFBInfo.wkqueueMss, &MFBInfo.vmsswork);
		#endif
		p = ProcessID % IRQ_USER_NUM_MAX;
		MFBInfo.IrqInfo
		    .Status[MFB_IRQ_TYPE_INT_MSS_ST] |= MSS_INT_ST;
		MFBInfo.IrqInfo
		    .ProcessID[p] = ProcessID;
		MFBInfo.IrqInfo.MssIrqCnt[p]++;
	}
	spin_unlock_irqrestore(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]),
									flag);
	if (bResulst == MTRUE) {
#ifdef MFB_PMQOS
		MFBQOS_Update(0, 1, 0);
#endif
		wake_up_interruptible(&MFBInfo.WaitQueueHeadMss);
	}

	/* dump log, use tasklet */
	IRQ_LOG_KEEPER(MFB_IRQ_TYPE_INT_MSS_ST, m_CurrentPPB, _LOG_INF,
		       "%s: bResulst:%d, MssIrqCnt[%d]:0x%x\n",
		       __func__, bResulst, p,
			MFBInfo.IrqInfo.MssIrqCnt[p]);
	tasklet_schedule(MFB_tasklet[MFB_IRQ_TYPE_INT_MSS_ST].pMFB_tkt);

	#if (REQUEST_REGULATION == FRAME_BASE_REGULATION)
	queue_work(MFBInfo.wkqueueMss, &MFBInfo.vmsswork);
	#endif
EXIT:
	cmdq_pkt_destroy(pkt);
#endif
}

signed int vCmdqMSSHW(struct frame *frame)
{
#ifdef CMDQ_COMMON
	struct MFB_MSSConfig *pMssConfig;
	struct cmdq_pkt *handle;

	if (frame == NULL || frame->data == NULL)
		return -1;

	LOG_DBG("%s request sent to CMDQ driver", __func__);
	pMssConfig = (struct MFB_MSSConfig *) frame->data;

	if (MFB_DBG_DBGLOG == (MFB_DBG_DBGLOG & MFBInfo.DebugMaskMss))
		LOG_DBG("ConfigMSSHW Start!\n");

	/*cmdq_pkt_cl_create(&handle, mss_clt);*/
	handle = cmdq_pkt_create(mss_clt);
	handle->priority = 0;
#ifdef USE_SW_TOKEN
	cmdq_pkt_acquire_event(handle, mss_token_id);
#endif
	mss_pkt_tcmds(handle, pMssConfig);
#ifdef USE_SW_TOKEN
	cmdq_pkt_clear_event(handle, mss_token_id);
#endif
#ifdef MFB_PMQOS
	MFBQOS_Update(1, 1, pMssConfig->qos);
#endif
	cmdq_pkt_flush_threaded(handle, mss_vss_sirq, (void *)handle);
#endif
	return 0;
}

static const struct engine_ops mss_ops = {
	.req_enque_cb = mss_enque_cb,
	.req_deque_cb = mss_deque_cb,
	.frame_handler = CmdqMSSHW,
	.req_feedback_cb = NULL,
};

static const struct engine_ops vmss_ops = {
	.req_enque_cb = mss_enque_cb,
	.req_deque_cb = mss_deque_cb,
	.frame_handler = vCmdqMSSHW,
	.req_feedback_cb = NULL,
};


static void msf_pkt_tcmds(struct cmdq_pkt *handle,
				struct MFB_MSFConfig *pMsfConfig)
{
#ifdef CMDQ_COMMON
	unsigned int t;

	if (pMsfConfig->tpipe_used > TPIPE_NUM_PER_FRAME) {
		pMsfConfig->tpipe_used = TPIPE_NUM_PER_FRAME;
		LOG_ERR("tpipe_used %d over limit of %d",
				pMsfConfig->tpipe_used, TPIPE_NUM_PER_FRAME);
	}

	/* fixed 0x0000 0001: [0] MSS, [1] P2*/
	cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSF_CQLP_ENG_EN_HW,
			pMsfConfig->MSFCQLP_ENG_EN, CMDQ_REG_MASK);
	for (t = 0; t < pMsfConfig->tpipe_used; t++) {
		cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSF_CMDQ_ENABLE_HW,
				pMsfConfig->MSFCMDQ_ENABLE[t], CMDQ_REG_MASK);
		cmdq_pkt_write(handle, NULL,
				(dma_addr_t)MFB_MSF_CMDQ_BASE_ADDR_HW,
				pMsfConfig->MSFCMDQ_BASE[t], CMDQ_REG_MASK);
		cmdq_pkt_write(handle, NULL,
				(dma_addr_t)MFB_MSF_CQLP_CMD_NUM_HW,
				pMsfConfig->MSFCQLP_CMD_NUM[t], CMDQ_REG_MASK);
		/* tdr */
		cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSF_TDRI_BASE_HW,
				pMsfConfig->MFBDMT_TDRI_BASE[t], CMDQ_REG_MASK);
		/* start */
		cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSF_START_HW,
				0x1, CMDQ_REG_MASK);
		/* wfe */
		cmdq_pkt_wfe(handle, msf_done_event_id);
		cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSF_INT_STA_HW,
				0x1, CMDQ_REG_MASK);
		LOG_DBG("MSF_CMDQ_ENABLE%d = 0x%x", t,
						pMsfConfig->MSFCMDQ_ENABLE[t]);
		LOG_DBG("MSFCMDQ_BASE%d = 0x%x", t,
						pMsfConfig->MSFCMDQ_BASE[t]);
		LOG_DBG("MSFCQLP_CMD_NUM%d = 0x%x", t,
						pMsfConfig->MSFCQLP_CMD_NUM[t]);
		LOG_DBG("MSFDMT_TDRI_BASE%d = 0x%x", t,
					pMsfConfig->MFBDMT_TDRI_BASE[t]);
	}
	LOG_DBG("%s: tpipe_used is %d", __func__, pMsfConfig->tpipe_used);
#endif
}

static void msf_norm_sirq(struct cmdq_cb_data data)
{
#ifdef CMDQ_COMMON
	struct cmdq_pkt *pkt;
	bool bResulst = MFALSE;
	pid_t ProcessID;
	unsigned long flag;
	unsigned int p = 0;

	pkt = (struct cmdq_pkt *) data.data;
	if (data.err < 0) {
		mfb_request_dump(&msf_reqs);
		MSF_DumpReg();
		LOG_ERR("%s: call back error(%d)", __func__, data.err);
		goto EXIT;
	}

	spin_lock_irqsave(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]),
									flag);
	if (mfb_update_request(&msf_reqs, &ProcessID) == 0)
		bResulst = MTRUE;
	/* Config the Next frame */
	if (bResulst == MTRUE) {
		#if REQUEST_REGULATION == REQUEST_BASE_REGULATION
		queue_work(MFBInfo.wkqueueMsf, &MFBInfo.ScheduleMsfWork);
		#endif
		p = ProcessID % IRQ_USER_NUM_MAX;
		MFBInfo.IrqInfo
		    .Status[MFB_IRQ_TYPE_INT_MSF_ST] |= MSF_INT_ST;
		MFBInfo.IrqInfo
		    .ProcessFD[p] = ProcessID;
		MFBInfo.IrqInfo.MsfIrqCnt[p]++;
	}
	spin_unlock_irqrestore(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]),
									flag);
	if (bResulst == MTRUE) {
#ifdef MFB_PMQOS
		MFBQOS_Update(0, 2, 0);
#endif
		wake_up_interruptible(&MFBInfo.WaitQueueHeadMsf);
	}

	/* dump log, use tasklet */
	IRQ_LOG_KEEPER(MFB_IRQ_TYPE_INT_MSF_ST, m_CurrentPPB, _LOG_INF,
		       "%s, bResulst:%d, MsfIrqCnt[%d]:0x%x\n",
		       __func__, bResulst, p, MFBInfo.IrqInfo.MsfIrqCnt[p]);
	tasklet_schedule(MFB_tasklet[MFB_IRQ_TYPE_INT_MSF_ST].pMFB_tkt);

	#if (REQUEST_REGULATION == FRAME_BASE_REGULATION)
	queue_work(MFBInfo.wkqueueMsf, &MFBInfo.ScheduleMsfWork);
	#endif
EXIT:
	cmdq_pkt_destroy(pkt);
#endif
}

signed int CmdqMSFHW(struct frame *frame)
{
#ifdef CMDQ_COMMON
	struct MFB_MSFConfig *pMsfConfig;
	struct cmdq_pkt *handle;

	if (frame == NULL || frame->data == NULL)
		return -1;

	LOG_DBG("%s request sent to CMDQ driver", __func__);
	pMsfConfig = (struct MFB_MSFConfig *) frame->data;

	if (MFB_DBG_DBGLOG == (MFB_DBG_DBGLOG & MFBInfo.DebugMaskMsf))
		LOG_DBG("ConfigMSFHW Start!\n");

	/*cmdq_pkt_cl_create(&handle, msf_clt);*/
	handle = cmdq_pkt_create(msf_clt);

	/*if (pMssConfig->eng_secured == 1)*//*YWtodo*/
		/*cmdq_engine_secured(handle, CMDQ_ENG_MSS);*/
	handle->priority = 20;
#ifdef USE_SW_TOKEN
	cmdq_pkt_acquire_event(handle, msf_token_id);
#endif
#ifdef TPIPE_MODE_PREVIEW
	msf_pkt_tcmds(handle, pMsfConfig);
#else
	cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSF_CMDQ_ENABLE_HW,
			pMsfConfig->MSFCMDQ_ENABLE[0], CMDQ_REG_MASK);
	cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSF_CMDQ_BASE_ADDR_HW,
			pMsfConfig->MSFCMDQ_BASE[0], CMDQ_REG_MASK);
	cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSF_CQLP_CMD_NUM_HW,
			pMsfConfig->MSFCQLP_CMD_NUM[0], CMDQ_REG_MASK);
	cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSF_CQLP_ENG_EN_HW,
			pMsfConfig->MSFCQLP_ENG_EN, CMDQ_REG_MASK);

#ifndef BYPASS_REG
	cmdq_pkt_write(handle, NULL, (dma_addr_t)MFB_MSF_START_HW,
			0x1, CMDQ_REG_MASK);
	cmdq_pkt_wfe(handle, msf_done_event_id);

	/* non-blocking API, Please  use cmdqRecFlushAsync() */
#endif
#endif
#ifdef USE_SW_TOKEN
	cmdq_pkt_clear_event(handle, msf_token_id);
#endif
#ifdef MFB_PMQOS
	MFBQOS_Update(1, 2, pMsfConfig->qos);
#endif
	cmdq_pkt_flush_threaded(handle, msf_norm_sirq, (void *)handle);
#endif
	return 0;
}

signed int msf_enque_cb(struct frame *frames, void *req)
{
	unsigned int f, fcnt;
	struct MFB_MSFRequest *_req;
	struct MFB_MSFConfig *pcfg;

	_req = (struct MFB_MSFRequest *) req;

	if (frames == NULL || _req == NULL)
		return -1;

	fcnt = _req->m_ReqNum;
	for (f = 0; f < fcnt; f++) {
		memcpy(frames[f].data, &_req->m_pMsfConfig[f],
			sizeof(struct MFB_MSFConfig));
		pcfg = &_req->m_pMsfConfig[f];
	}

	return 0;
}

signed int msf_deque_cb(struct frame *frames, void *req)
{
	unsigned int f, fcnt;
	struct MFB_MSFRequest *_req;
	struct MFB_MSFConfig *pcfg;

	_req = (struct MFB_MSFRequest *) req;

	if (frames == NULL || _req == NULL)
		return -1;

	fcnt = _req->m_ReqNum;
	for (f = 0; f < fcnt; f++) {
		memcpy(&_req->m_pMsfConfig[f], frames[f].data,
			sizeof(struct MFB_MSFConfig));
		LOG_DBG("[%s]request dequeued frame(%d/%d).",
			__func__, f, fcnt);
		pcfg = &_req->m_pMsfConfig[f];
	}

	return 0;
}

static void msf_vss_sirq(struct cmdq_cb_data data)
{
#ifdef CMDQ_COMMON
	struct cmdq_pkt *pkt;
	bool bResulst = MFALSE;
	pid_t ProcessID;
	unsigned long flag;
	unsigned int p = 0;

	pkt = (struct cmdq_pkt *) data.data;
	if (data.err < 0) {
		mfb_request_dump(&vmsf_reqs);
		MSF_DumpReg();
		LOG_ERR("%s: call back error(%d)", __func__, data.err);
		goto EXIT;
	}

	spin_lock_irqsave(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]),
									flag);
	if (mfb_update_request(&vmsf_reqs, &ProcessID) == 0)
		bResulst = MTRUE;
	/* Config the Next frame */
	if (bResulst == MTRUE) {
		#if REQUEST_REGULATION == REQUEST_BASE_REGULATION
		queue_work(MFBInfo.wkqueueMsf, &MFBInfo.vmsfwork);
		#endif
		p = ProcessID % IRQ_USER_NUM_MAX;
		MFBInfo.IrqInfo
		    .Status[MFB_IRQ_TYPE_INT_MSF_ST] |= MSF_INT_ST;
		MFBInfo.IrqInfo
		    .ProcessFD[p] = ProcessID;
		MFBInfo.IrqInfo.MsfIrqCnt[p]++;
	}
	spin_unlock_irqrestore(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]),
									flag);
	if (bResulst == MTRUE) {
#ifdef MFB_PMQOS
		MFBQOS_Update(0, 3, 0);
#endif
		wake_up_interruptible(&MFBInfo.WaitQueueHeadMsf);
	}

	/* dump log, use tasklet */
	IRQ_LOG_KEEPER(MFB_IRQ_TYPE_INT_MSF_ST, m_CurrentPPB, _LOG_INF,
		       "%s: bResulst:%d, MsfIrqCnt[%d]:0x%x\n",
		       __func__, bResulst, p, MFBInfo.IrqInfo.MsfIrqCnt[p]);
	tasklet_schedule(MFB_tasklet[MFB_IRQ_TYPE_INT_MSF_ST].pMFB_tkt);

	#if (REQUEST_REGULATION == FRAME_BASE_REGULATION)
	queue_work(MFBInfo.wkqueueMsf, &MFBInfo.vmsfwork);
	#endif
EXIT:
	cmdq_pkt_destroy(pkt);
#endif
}

signed int vCmdqMSFHW(struct frame *frame)
{
#ifdef CMDQ_COMMON
	struct MFB_MSFConfig *pMsfConfig;
	struct cmdq_pkt *handle;

	if (frame == NULL || frame->data == NULL)
		return -1;

	LOG_DBG("%s request sent to CMDQ driver", __func__);
	pMsfConfig = (struct MFB_MSFConfig *) frame->data;

	if (MFB_DBG_DBGLOG == (MFB_DBG_DBGLOG & MFBInfo.DebugMaskMsf))
		LOG_DBG("ConfigMSFHW Start!\n");

	/*cmdq_pkt_cl_create(&handle, msf_clt);*/
	handle = cmdq_pkt_create(msf_clt);
	handle->priority = 0;
#ifdef USE_SW_TOKEN
	cmdq_pkt_acquire_event(handle, msf_token_id);
#endif
	msf_pkt_tcmds(handle, pMsfConfig);
#ifdef USE_SW_TOKEN
	cmdq_pkt_clear_event(handle, msf_token_id);
#endif
#ifdef MFB_PMQOS
	MFBQOS_Update(1, 3, pMsfConfig->qos);
#endif
	cmdq_pkt_flush_threaded(handle, msf_vss_sirq, (void *)handle);
#endif
	return 0;
}

static const struct engine_ops msf_ops = {
	.req_enque_cb = msf_enque_cb,
	.req_deque_cb = msf_deque_cb,
	.frame_handler = CmdqMSFHW,
	.req_feedback_cb = NULL,
};

static const struct engine_ops vmsf_ops = {
	.req_enque_cb = msf_enque_cb,
	.req_deque_cb = msf_deque_cb,
	.frame_handler = vCmdqMSFHW,
	.req_feedback_cb = NULL,
};

/*
 *
 */
static signed int MSS_DumpReg(void)
{
	signed int Ret = 0;
#ifdef CMDQ_COMMON
	unsigned int i = 0;

	cmdq_util_err("- E.");
	cmdq_util_err("MSS Config Info\n");
	if (g_u4EnableClockCount == 0)
		return Ret;
	for (i = 0; i < MSS_REG_RANGE; i = i + 0x10) {
		cmdq_util_err(
		"[0x%08X %08X][0x%08X %08X][0x%08X %08X][0x%08X %08X]",
		ISP_MSS_BASE_HW + i + 0x0, MFB_RD32(ISP_MSS_BASE + i + 0x0),
		ISP_MSS_BASE_HW + i + 0x4, MFB_RD32(ISP_MSS_BASE + i + 0x4),
		ISP_MSS_BASE_HW + i + 0x8, MFB_RD32(ISP_MSS_BASE + i + 0x8),
		ISP_MSS_BASE_HW + i + 0xC, MFB_RD32(ISP_MSS_BASE + i + 0xC));
	}
#if CHECK_SERVICE_IF_0 /*YWtodo sel*/
for (i = 0; i < 3; i++) {
	for (j = 1; j < 7; j++) {
		MFB_WR32(MFB_MSS_DMA_DEBUG_SEL,
			0x000F3F1F & ((i << 16) + (j << 8) + 0));
		cmdq_util_err("debug_mux_data_%d 0x%08X\n",
			i, MFB_RD32(MFB_MSS_TOP_DBG_OUT2));
	}
}
for (i = 1; i < 7; i++) {
	MFB_WR32(MFB_MSS_DMA_DEBUG_SEL, 0x0000001F & i);
	cmdq_util_err("dma_debug_data_%d 0x%08X\n",
			i, MFB_RD32(MFB_MSS_TOP_DBG_OUT2));
}
for (i = 0; i < 16; i++) {
	MFB_WR32(MFB_MSS_DMA_DEBUG_SEL, 0x000F001F & ((i << 16) + 7));
	cmdq_util_err("debug_cnt_data_%d 0x%08X\n",
			i, MFB_RD32(MFB_MSS_TOP_DBG_OUT2));
}
for (i = 0; i < 24; i++) {
	MFB_WR32(MFB_MSS_DMA_DEBUG_SEL, 0x00003F1F & ((i << 8) + 8));
	cmdq_util_err("check_sum_debug_data_%d 0x%08X\n",
			i, MFB_RD32(MFB_MSS_TOP_DBG_OUT2));
}
for (i = 0; i < 15; i++) {
	MFB_WR32(MFB_MSS_TOP_DBG_CTL0, 0x0000FF00 & (0x0 << 8));
	cmdq_util_err("mod_debug_%d 0x%08X\n",
			i, MFB_RD32(MFB_MSS_TOP_DBG_OUT3));
}
#endif
	cmdq_util_err("- X.");
#endif
	return Ret;
}

static signed int MSF_DumpReg(void)
{
	signed int Ret = 0;
#ifdef CMDQ_COMMON
	unsigned int i = 0;

	cmdq_util_err("- E.");
	cmdq_util_err("MSF Config Info\n");
	if (g_u4EnableClockCount == 0)
		return Ret;
	for (i = 0; i < MSF_REG_RANGE; i = i + 0x10) {
		cmdq_util_err(
		"[0x%08X %08X][0x%08X %08X][0x%08X %08X][0x%08X %08X]",
		ISP_MSF_BASE_HW + i + 0x0, MFB_RD32(ISP_MSF_BASE + i + 0x0),
		ISP_MSF_BASE_HW + i + 0x4, MFB_RD32(ISP_MSF_BASE + i + 0x4),
		ISP_MSF_BASE_HW + i + 0x8, MFB_RD32(ISP_MSF_BASE + i + 0x8),
		ISP_MSF_BASE_HW + i + 0xC, MFB_RD32(ISP_MSF_BASE + i + 0xC));
	}
#if CHECK_SERVICE_IF_0 /*YWtodo sel*/
	for (i = 28; i < 32; i++) {
		MFB_WR32(MFB_MSF_TOP_DEBUG_SEL, 0xFF000000 & (i << 24));
		cmdq_util_err("mfb_top_rdy_ack_debug_%d 0x%08X\n",
				i, MFB_RD32(MFB_MSF_TOP_DEBUG_STA));
	}
	for (i = 1; i < 28; i++) {
		MFB_WR32(MFB_MSF_TOP_DEBUG_SEL, 0xFF000000 & (i << 24));
		cmdq_util_err("submodule_debug_sel_%d 0x%08X\n",
				i, MFB_RD32(MFB_MSF_TOP_DEBUG_STA));
	}
	MFB_WR32(MFB_MSF_TOP_DEBUG_SEL, 0xFF000000 & (0x0 << 24));
	MFB_WR32(MFB_MSF_DMA_DEBUG_SEL, 0x0000001F & 18);
	cmdq_util_err("dma_req_st 0x%08X\n", MFB_RD32(MFB_MSF_TOP_DEBUG_STA));
	MFB_WR32(MFB_MSF_DMA_DEBUG_SEL, 0x0000001F & 19);
	cmdq_util_err("dma_rdy_st 0x%08X\n", MFB_RD32(MFB_MSF_TOP_DEBUG_STA));
	for (i = 0; i < 3; i++) {
		for (j = 1; j < 20; j++) {
			MFB_WR32(MFB_MSF_DMA_DEBUG_SEL,
				0x000F3F1F & ((i << 16) + (j << 8) + 0));
			cmdq_util_err("debug_mux_data_%d 0x%08X\n",
				i, MFB_RD32(MFB_MSF_TOP_DEBUG_STA));
		}
	}
	for (i = 0; i < 16; i++) {
		MFB_WR32(MFB_MSF_DMA_DEBUG_SEL, 0x000F001F & ((i << 16) + 16));
		cmdq_util_err("debug_cnt_data_%d 0x%08X\n",
				i, MFB_RD32(MFB_MSF_TOP_DEBUG_STA));
	}
	for (i = 0; i < 60; i++) {
		MFB_WR32(MFB_MSF_DMA_DEBUG_SEL, 0x00003F1F & ((i << 8) + 17));
		cmdq_util_err("check_sum_debug_data_%d 0x%08X\n",
				i, MFB_RD32(MFB_MSF_TOP_DEBUG_STA));
	}
	for (i = 1; i < 16; i++) {
		MFB_WR32(MFB_MSF_DMA_DEBUG_SEL, 0x0000001F & i);
		cmdq_util_err("dma_debug_data_%d 0x%08X\n",
				i, MFB_RD32(MFB_MSF_TOP_DEBUG_STA));
	}
	MFB_WR32(MFB_MSF_DMA_DEBUG_SEL, 0x0000001F & 20);
	cmdq_util_err("wdma_otf_overflow 0x%08X\n",
				MFB_RD32(MFB_MSF_TOP_DEBUG_STA));

	for (i = 0; i < 112; i++) {
		MFB_WR32(MFB_MSF_TOP_DEBUG_SEL,
				0xFFFF0000 & ((3 << 24) + (i << 16)));
		cmdq_util_err("submodule_check_sum_%d 0x%08X\n",
				i, MFB_RD32(MFB_MSF_TOP_CRC_1));
	}
	for (i = 0; i < 29; i++) {
		MFB_WR32(MFB_MSF_TOP_DEBUG_SEL,
				0xFFFF0000 & ((4 << 24) + (i << 16)));
		cmdq_util_err("submodule_CRC_%d 0x%08X\n",
				i, MFB_RD32(MFB_MSF_TOP_CRC_1));
	}
#endif
	cmdq_util_err("- X.");
#endif
	return Ret;
}

/******************************************************************************
 *
 ******************************************************************************/
#ifndef __MFB_EP_NO_CLKMGR__
#if !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK) /*CCF*/
static inline void MFB_Prepare_Enable_ccf_clock(void)
{
	int ret;
	/* must keep this clk open order:
	 * CG_SCP_SYS_DIS-> CG_MM_SMI_COMMON -> CG_SCP_SYS_ISP -> MFB clk
	 */
	pm_runtime_get_sync(MFB_devs[0].dev);
	ret = mtk_smi_larb_get(MFB_devs[0].larb);
	if (ret)
		LOG_ERR("mtk_smi_larb_get error\n");
#if (MTK_MFB_REG_VERSION == 3)
	//smi_bus_prepare_enable(SMI_LARB11, MFB_DEV_NAME);
	ret = clk_prepare_enable(mfb_clk.CG_IMG2_LARB11);
	if (ret)
		LOG_ERR("cannot prepare and enable CG_IMG2_LARB11 clock\n");

	ret = clk_prepare_enable(mfb_clk.CG_IMG2_MSS);
	if (ret)
		LOG_ERR("cannot prepare and enable CG_IMG2_MSS clock\n");

	ret = clk_prepare_enable(mfb_clk.CG_IMG2_MFB);
	if (ret)
		LOG_ERR("cannot prepare and enable CG_IMG2_MFB clock\n");

	ret = clk_prepare_enable(mfb_clk.CG_IMG2_GALS);
	if (ret)
		LOG_ERR("cannot prepare and enable CG_IMG2_GALS clock\n");

	ret = clk_prepare_enable(mfb_clk.CG_IMG1_GALS);
	if (ret)
		LOG_ERR("cannot prepare and enable CG_IMG1_GALS clock\n");
#elif (MTK_MFB_REG_VERSION == 2)
	//smi_bus_prepare_enable(SMI_LARB11, MFB_DEV_NAME);
	ret = clk_prepare_enable(mfb_clk.CG_IMG2_LARB11);
	if (ret)
		LOG_ERR("cannot prepare and enable CG_IMG2_LARB11 clock\n");

	ret = clk_prepare_enable(mfb_clk.CG_IMG2_MSS);
	if (ret)
		LOG_ERR("cannot prepare and enable CG_IMG2_MSS clock\n");

	ret = clk_prepare_enable(mfb_clk.CG_IMG2_MFB);
	if (ret)
		LOG_ERR("cannot prepare and enable CG_IMG2_MFB clock\n");

	ret = clk_prepare_enable(mfb_clk.CG_IMG2_GALS);
	if (ret)
		LOG_ERR("cannot prepare and enable CG_IMG2_GALS clock\n");
#else
	//smi_bus_prepare_enable(SMI_LARB9, MFB_DEV_NAME);
	ret = clk_prepare_enable(mfb_clk.CG_IMG1_LARB9);
	if (ret)
		LOG_ERR("cannot prepare and enable CG_IMG1_LARB9 clock\n");

	ret = clk_prepare_enable(mfb_clk.CG_IMG1_MSS);
	if (ret)
		LOG_ERR("cannot prepare and enable CG_IMG1_MSS clock\n");

	ret = clk_prepare_enable(mfb_clk.CG_IMG1_MFB);
	if (ret)
		LOG_ERR("cannot prepare and enable CG_IMG1_MFB clock\n");
#endif
}

static inline void MFB_Disable_Unprepare_ccf_clock(void)
{
	/* must keep this clk close order:
	 * MFB clk -> CG_SCP_SYS_ISP -> CG_MM_SMI_COMMON -> CG_SCP_SYS_DIS
	 */
#if (MTK_MFB_REG_VERSION == 3)
	clk_disable_unprepare(mfb_clk.CG_IMG1_GALS);
	clk_disable_unprepare(mfb_clk.CG_IMG2_GALS);
	clk_disable_unprepare(mfb_clk.CG_IMG2_MFB);
	clk_disable_unprepare(mfb_clk.CG_IMG2_MSS);
	clk_disable_unprepare(mfb_clk.CG_IMG2_LARB11);
	/*smi_bus_disable_unprepare(SMI_LARB11, MFB_DEV_NAME);*/
#elif (MTK_MFB_REG_VERSION == 2)
	clk_disable_unprepare(mfb_clk.CG_IMG2_GALS);
	clk_disable_unprepare(mfb_clk.CG_IMG2_MFB);
	clk_disable_unprepare(mfb_clk.CG_IMG2_MSS);
	clk_disable_unprepare(mfb_clk.CG_IMG2_LARB11);
	/*smi_bus_disable_unprepare(SMI_LARB11, MFB_DEV_NAME);*/
#else
	clk_disable_unprepare(mfb_clk.CG_IMG1_MFB);
	clk_disable_unprepare(mfb_clk.CG_IMG1_MSS);
	clk_disable_unprepare(mfb_clk.CG_IMG1_LARB9);
	/*smi_bus_disable_unprepare(SMI_LARB9, MFB_DEV_NAME);*/
#endif
	mtk_smi_larb_put(MFB_devs[0].larb);
	pm_runtime_put_sync(MFB_devs[0].dev);
}
#endif
#endif

/******************************************************************************
 *
 ******************************************************************************/
static void MFB_EnableClock(bool En)
{
	if (En) {/* Enable clock. */
		/* LOG_DBG("Mfb clock enbled. g_u4EnableClockCount: %d.", */
		/* g_u4EnableClockCount); */
		switch (g_u4EnableClockCount) {
		case 0:
#ifndef __MFB_EP_NO_CLKMGR__
#if !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK) /*CCF*/
			MFB_Prepare_Enable_ccf_clock();
#else/*YWtodo*/
			enable_clock(MT_CG_DOWE0_SMI_COMMON, "CAMERA");
			enable_clock(MT_CG_IMAGE_CAM_SMI, "CAMERA");
			enable_clock(MT_CG_IMAGE_CAM_CAM, "CAMERA");
			enable_clock(MT_CG_IMAGE_SEN_TG, "CAMERA");
			enable_clock(MT_CG_IMAGE_SEN_CAM, "CAMERA");
			enable_clock(MT_CG_IMAGE_CAM_SV, "CAMERA");
			/* enable_clock(MT_CG_IMAGE_FD, "CAMERA"); */
			enable_clock(MT_CG_IMAGE_LARB2_SMI, "CAMERA");
#endif	/* #if !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK)  */

#else
			/*MFB_WR32(IMGSYS_REG_CG_CLR, 0xFFFFFFFF);*//*YWtodo*/
#endif
			break;
		default:
			break;
		}
		spin_lock(&(MFBInfo.SpinLockMFB));
		g_u4EnableClockCount++;
		spin_unlock(&(MFBInfo.SpinLockMFB));

	} else {		/* Disable clock. */

		/* LOG_DBG("Mfb clock disabled. g_u4EnableClockCount: %d.", */
		/* g_u4EnableClockCount); */
		spin_lock(&(MFBInfo.SpinLockMFB));
		g_u4EnableClockCount--;
		spin_unlock(&(MFBInfo.SpinLockMFB));
		switch (g_u4EnableClockCount) {
		case 0:
#ifndef __MFB_EP_NO_CLKMGR__
#if !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK) /*CCF*/
			MFB_Disable_Unprepare_ccf_clock();
#else/*YWtodo*/
			/* do disable clock */
			disable_clock(MT_CG_IMAGE_CAM_SMI, "CAMERA");
			disable_clock(MT_CG_IMAGE_CAM_CAM, "CAMERA");
			disable_clock(MT_CG_IMAGE_SEN_TG, "CAMERA");
			disable_clock(MT_CG_IMAGE_SEN_CAM, "CAMERA");
			disable_clock(MT_CG_IMAGE_CAM_SV, "CAMERA");
			/* disable_clock(MT_CG_IMAGE_FD, "CAMERA"); */
			disable_clock(MT_CG_IMAGE_LARB2_SMI, "CAMERA");
			disable_clock(MT_CG_DOWE0_SMI_COMMON, "CAMERA");
#endif	/* #if !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK) */

#else
			/*MFB_WR32(IMGSYS_REG_CG_SET, 0xFFFFFFFF);*//*YWtodo*/
#endif
			break;
		default:
			break;
		}
	}
}

/*****************************************************************************
 *
 ******************************************************************************/
static inline void MSS_Reset(void)
{
#if CHECK_SERVICE_IF_0/*YWtodo*/
	LOG_DBG("- E.");
	LOG_DBG(" MSS Reset start!\n");
	mutex_lock(&(MutexMFBRef));

	if (MFBInfo.UserCount > 1) {
		mutex_unlock(&(MutexMFBRef));
		LOG_DBG("Curr UserCount(%d) users exist", MFBInfo.UserCount);
	} else {
		mutex_unlock(&(MutexMFBRef));

		/* Reset MSS flow */
		MFB_WR32(MSSTOP_DMA_STOP_REG, 0x100);
		while ((MFB_RD32(MSSTOP_DMA_STOP_STA_REG) & 0x100) != 0x100)
			LOG_DBG("MSS resetting...\n");
		/*Use IMGSYS1*/
		MFB_WR32(IMGSYS_REG_SW_RST, 0x10000);
		udelay(1);
		MFB_WR32(MSSTOP_DMA_STOP_REG, 0x0);
		udelay(1);
		MFB_WR32(IMGSYS_REG_SW_RST, 0x0);
		LOG_DBG(" MSS Reset end!\n");
	}
#endif
}

/*****************************************************************************
 *
 ******************************************************************************/
static inline void MSF_Reset(void)
{
#if CHECK_SERVICE_IF_0/*YWtodo*/
	unsigned int temp;

	LOG_DBG("- E.");
	LOG_DBG(" MSF Reset start!\n");
	mutex_lock(&(MutexMFBRef));

	if (MFBInfo.UserCount > 1) {
		mutex_unlock(&(MutexMFBRef));
		LOG_DBG("Curr UserCount(%d) users exist", MFBInfo.UserCount);
	} else {
		mutex_unlock(&(MutexMFBRef));

		/* Reset MSF flow */
		MFB_WR32(MFBTOP_DMA_STOP_REG, 0x80000000);
		while ((MFB_RD32(MFBTOP_DMA_STOP_STA_REG) & 0x80000000)
				!= 0x80000000)
			LOG_DBG("MSF resetting...\n");

		MFB_WR32(MFBTOP_RESET_REG, 0x1);
		udelay(1);
		temp = MFB_RD32(MFB_MSF_CMDQ_ENABLE_REG);
		MFB_WR32(MFB_MSF_CMDQ_ENABLE_REG, temp | 0x100);
		udelay(1);
		MFB_WR32(MFBTOP_DMA_STOP_REG, 0x0);
		udelay(1);
		MFB_WR32(MFBTOP_RESET_REG, 0x0);
		udelay(1);
		MFB_WR32(MFB_MSF_CMDQ_ENABLE_REG, temp & 0xFFFFFEFF);
		LOG_DBG(" MSF Reset end!\n");
	}
#endif
}

/******************************************************************************
 *
 ******************************************************************************/
static signed int MSS_ReadReg(struct MFB_REG_IO_STRUCT *pRegIo)
{
	unsigned int i;
	signed int Ret = 0;
	/* unsigned int* pData = (unsigned int*)pRegIo->Data; */
	struct MFB_REG_STRUCT *pData = NULL;
	struct MFB_REG_STRUCT *pTmpData = NULL;

	if ((pRegIo->pData == NULL) || (pRegIo->Count == 0) ||
		(pRegIo->Count > (MSS_REG_RANGE>>2))) {
		LOG_ERR("pRegIo->pData is NULL, Count:%d!!",
			pRegIo->Count);
		Ret = -EFAULT;
		goto EXIT;
	}
	pData = kmalloc(
		(pRegIo->Count) * sizeof(struct MFB_REG_STRUCT), GFP_KERNEL);
	if (pData == NULL) {
		LOG_ERR("ERROR: kmalloc failed, cnt:%d\n",
			pRegIo->Count);
		Ret = -ENOMEM;
		goto EXIT;
	}
	pTmpData = pData;
	if (copy_from_user(pData, (void *)pRegIo->pData,
		(pRegIo->Count) * sizeof(struct MFB_REG_STRUCT)) == 0) {
		for (i = 0; i < pRegIo->Count; i++) {
			if ((ISP_MSS_BASE + pData->Addr >= ISP_MSS_BASE)
			    && (ISP_MSS_BASE + pData->Addr <
				(ISP_MSS_BASE + MSS_REG_RANGE))
			    && ((pData->Addr & 0x3) == 0)) {
				pData->Val =
					MFB_RD32(ISP_MSS_BASE + pData->Addr);
			} else {
				LOG_ERR("Wrong address(0x%p)",
					(ISP_MSS_BASE + pData->Addr));
				pData->Val = 0;
			}
			pData++;
		}
		pData = pTmpData;
		if (copy_to_user((void *)pRegIo->pData, pData,
			(pRegIo->Count) * sizeof(struct MFB_REG_STRUCT)) != 0) {
			LOG_ERR("copy_to_user failed\n");
			Ret = -EFAULT;
			goto EXIT;
		}
	} else {
		LOG_ERR("MFB_READ_REGISTER copy_from_user failed");
		Ret = -EFAULT;
		goto EXIT;
	}

EXIT:
	if (pData != NULL) {
		kfree(pData);
		pData = NULL;
	}
	return Ret;
}

/******************************************************************************
 *
 ******************************************************************************/
static signed int MSF_ReadReg(struct MFB_REG_IO_STRUCT *pRegIo)
{
	unsigned int i;
	signed int Ret = 0;
	/* unsigned int* pData = (unsigned int*)pRegIo->Data; */
	struct MFB_REG_STRUCT *pData = NULL;
	struct MFB_REG_STRUCT *pTmpData = NULL;

	if ((pRegIo->pData == NULL) || (pRegIo->Count == 0) ||
		(pRegIo->Count > (MSF_REG_RANGE>>2))) {
		LOG_ERR("pRegIo->pData is NULL, Count:%d!!",
			pRegIo->Count);
		Ret = -EFAULT;
		goto EXIT;
	}
	pData = kmalloc(
		(pRegIo->Count) * sizeof(struct MFB_REG_STRUCT), GFP_KERNEL);
	if (pData == NULL) {
		LOG_ERR("ERROR: kmalloc failed, cnt:%d\n",
			pRegIo->Count);
		Ret = -ENOMEM;
		goto EXIT;
	}
	pTmpData = pData;
	if (copy_from_user(pData, (void *)pRegIo->pData,
		(pRegIo->Count) * sizeof(struct MFB_REG_STRUCT)) == 0) {
		for (i = 0; i < pRegIo->Count; i++) {
			if ((ISP_MSF_BASE + pData->Addr >= ISP_MSF_BASE)
			    && (ISP_MSF_BASE + pData->Addr <
				(ISP_MSF_BASE + MSF_REG_RANGE))
			    && ((pData->Addr & 0x3) == 0)) {
				pData->Val =
					MFB_RD32(ISP_MSF_BASE + pData->Addr);
			} else {
				LOG_ERR("Wrong address(0x%p)",
					(ISP_MSF_BASE + pData->Addr));
				pData->Val = 0;
			}
			pData++;
		}
		pData = pTmpData;
		if (copy_to_user((void *)pRegIo->pData, pData,
			(pRegIo->Count) * sizeof(struct MFB_REG_STRUCT)) != 0) {
			LOG_ERR("copy_to_user failed\n");
			Ret = -EFAULT;
			goto EXIT;
		}
	} else {
		LOG_ERR("MFB_READ_REGISTER copy_from_user failed");
		Ret = -EFAULT;
		goto EXIT;
	}

EXIT:
	if (pData != NULL) {
		kfree(pData);
		pData = NULL;
	}
	return Ret;
}

/******************************************************************************
 *
 ******************************************************************************/
/* Can write sensor's test model only, if need write to other modules,
 * need modify current code flow
 */
static signed int MSS_WriteRegToHw(
	struct MFB_REG_STRUCT *pReg, unsigned int Count)
{
	signed int Ret = 0;
	unsigned int i;
	bool dbgWriteReg;

	/* Use local variable to store MFBInfo.DebugMask & MFB_DBG_WRITE_REG
	 * for saving lock time
	 */
	spin_lock(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]));
	dbgWriteReg = MFBInfo.DebugMaskMss & MFB_DBG_WRITE_REG;
	spin_unlock(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]));

	if (dbgWriteReg)
		LOG_DBG("- E.\n");

	for (i = 0; i < Count; i++) {
		if (dbgWriteReg) {
			LOG_DBG("Addr(0x%lx), Val(0x%x)\n",
				(unsigned long)(ISP_MSS_BASE + pReg[i].Addr),
				(unsigned int) (pReg[i].Val));
		}

		if (((ISP_MSS_BASE + pReg[i].Addr) <
			(ISP_MSS_BASE + MSS_REG_RANGE))
			&& ((pReg[i].Addr & 0x3) == 0)) {
			MFB_WR32(ISP_MSS_BASE + pReg[i].Addr, pReg[i].Val);
		} else {
			LOG_ERR("wrong address(0x%lx)\n",
				(unsigned long)(ISP_MSS_BASE + pReg[i].Addr));
		}
	}

	return Ret;
}

/******************************************************************************
 *
 ******************************************************************************/
/* Can write sensor's test model only, if need write to other modules,
 * need modify current code flow
 */
static signed int MSF_WriteRegToHw(
	struct MFB_REG_STRUCT *pReg, unsigned int Count)
{
	signed int Ret = 0;
	unsigned int i;
	bool dbgWriteReg;

	/* Use local variable to store MFBInfo.DebugMask & MFB_DBG_WRITE_REG
	 * for saving lock time
	 */
	spin_lock(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]));
	dbgWriteReg = MFBInfo.DebugMaskMsf & MFB_DBG_WRITE_REG;
	spin_unlock(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]));

	if (dbgWriteReg)
		LOG_DBG("- E.\n");

	for (i = 0; i < Count; i++) {
		if (dbgWriteReg) {
			LOG_DBG("Addr(0x%lx), Val(0x%x)\n",
				(unsigned long)(ISP_MSF_BASE + pReg[i].Addr),
				(unsigned int) (pReg[i].Val));
		}

		if (((ISP_MSF_BASE + pReg[i].Addr) <
			(ISP_MSF_BASE + MSF_REG_RANGE))
			&& ((pReg[i].Addr & 0x3) == 0)) {
			MFB_WR32(ISP_MSF_BASE + pReg[i].Addr, pReg[i].Val);
		} else {
			LOG_ERR("wrong address(0x%lx)\n",
				(unsigned long)(ISP_MSF_BASE + pReg[i].Addr));
		}
	}

	return Ret;
}

/******************************************************************************
 *
 ******************************************************************************/
static signed int MSS_WriteReg(struct MFB_REG_IO_STRUCT *pRegIo)
{
	signed int Ret = 0;
	/* unsigned char* pData = NULL; */
	struct MFB_REG_STRUCT *pData = NULL;

	if (MFBInfo.DebugMaskMss & MFB_DBG_WRITE_REG)
		LOG_DBG("Data(0x%p), Count(%d)\n",
			(pRegIo->pData), (pRegIo->Count));

	if ((pRegIo->pData == NULL) || (pRegIo->Count == 0) ||
			(pRegIo->Count > (MSS_REG_RANGE>>2))) {
		LOG_ERR("ERROR: pRegIo->pData is NULL or Count:%d\n",
			pRegIo->Count);
		Ret = -EFAULT;
		goto EXIT;
	}
	/* pData = (unsigned char*)kmalloc( */
	/*	(pRegIo->Count)*sizeof(MFB_REG_STRUCT), GFP_ATOMIC); */
	pData = kmalloc(
		(pRegIo->Count) * sizeof(struct MFB_REG_STRUCT), GFP_KERNEL);
	if (pData == NULL) {
		LOG_ERR(
			"ERROR: kmalloc failed, (process, pid, tgid)=(%s, %d, %d)\n",
			current->comm,
			current->pid, current->tgid);
		Ret = -ENOMEM;
		goto EXIT;
	}
	if (copy_from_user(pData, (void __user *)(pRegIo->pData),
		pRegIo->Count * sizeof(struct MFB_REG_STRUCT)) != 0) {
		LOG_ERR("copy_from_user failed\n");
		Ret = -EFAULT;
		goto EXIT;
	}
	Ret = MSS_WriteRegToHw(pData, pRegIo->Count);
EXIT:
	if (pData != NULL) {
		kfree(pData);
		pData = NULL;
	}
	return Ret;
}

/******************************************************************************
 *
 ******************************************************************************/
static signed int MSF_WriteReg(struct MFB_REG_IO_STRUCT *pRegIo)
{
	signed int Ret = 0;
	/* unsigned char* pData = NULL; */
	struct MFB_REG_STRUCT *pData = NULL;

	if (MFBInfo.DebugMaskMsf & MFB_DBG_WRITE_REG)
		LOG_DBG("Data(0x%p), Count(%d)\n",
			(pRegIo->pData), (pRegIo->Count));

	if ((pRegIo->pData == NULL) || (pRegIo->Count == 0) ||
			(pRegIo->Count > (MSF_REG_RANGE>>2))) {
		LOG_ERR("ERROR: pRegIo->pData is NULL or Count:%d\n",
			pRegIo->Count);
		Ret = -EFAULT;
		goto EXIT;
	}
	/* pData = (unsigned char*)kmalloc( */
	/*	(pRegIo->Count)*sizeof(MFB_REG_STRUCT), GFP_ATOMIC); */
	pData = kmalloc(
		(pRegIo->Count) * sizeof(struct MFB_REG_STRUCT), GFP_KERNEL);
	if (pData == NULL) {
		LOG_ERR(
			"ERROR: kmalloc failed, (process, pid, tgid)=(%s, %d, %d)\n",
			current->comm,
			current->pid, current->tgid);
		Ret = -ENOMEM;
		goto EXIT;
	}
	if (copy_from_user(pData, (void __user *)(pRegIo->pData),
		pRegIo->Count * sizeof(struct MFB_REG_STRUCT)) != 0) {
		LOG_ERR("copy_from_user failed\n");
		Ret = -EFAULT;
		goto EXIT;
	}
	Ret = MSF_WriteRegToHw(pData, pRegIo->Count);
EXIT:
	if (pData != NULL) {
		kfree(pData);
		pData = NULL;
	}
	return Ret;
}

/******************************************************************************
 *
 ******************************************************************************/
static signed int MSS_WaitIrq(struct MFB_WAIT_IRQ_STRUCT *WaitIrq,
					enum MFB_PROCESS_ID_ENUM whichReq)
{

	signed int Ret = 0;
	signed int Timeout = WaitIrq->Timeout;

	/*unsigned int i;*/
	unsigned long flags; /* old: unsigned int flags;*/
			     /* FIX to avoid build warning */
	unsigned int irqStatus;
	/*int cnt = 0;*/
	struct timespec64 time_getrequest;
	unsigned int p;

	ktime_get_ts64(&time_getrequest);

	/* Debug interrupt */
	if (MFBInfo.DebugMaskMss & MFB_DBG_INT) {
		if (WaitIrq->Status & MFBInfo.IrqInfo.Mask[WaitIrq->Type]) {
			if (WaitIrq->UserKey > 0) {
				LOG_DBG(
					"+WaitIrq Clr(%d),Type(%d),Sta(0x%08X),Timeout(%d),user(%d),PID(%d)\n",
					WaitIrq->Clear,
					WaitIrq->Type,
					WaitIrq->Status,
					WaitIrq->Timeout,
					WaitIrq->UserKey,
					WaitIrq->ProcessID);
			}
		}
	}


	/* 1. wait type update */
	if (WaitIrq->Clear == MFB_IRQ_CLEAR_STATUS) {
		spin_lock_irqsave(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
		MFBInfo.IrqInfo.Status[WaitIrq->Type] &= (~WaitIrq->Status);
		spin_unlock_irqrestore(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
		return Ret;
	}

	if (WaitIrq->Clear == MFB_IRQ_CLEAR_WAIT) {
		spin_lock_irqsave(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
		if (MFBInfo.IrqInfo.Status[WaitIrq->Type] & WaitIrq->Status)
			MFBInfo.IrqInfo.Status[WaitIrq->Type] &=
				(~WaitIrq->Status);

		spin_unlock_irqrestore(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
	} else if (WaitIrq->Clear == MFB_IRQ_CLEAR_ALL) {
		spin_lock_irqsave(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);

		MFBInfo.IrqInfo.Status[WaitIrq->Type] = 0;
		spin_unlock_irqrestore(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
	}
	/* MFB_IRQ_WAIT_CLEAR ==> do nothing */


	/* Store irqinfo status in here to redeuce time of spin_lock_irqsave */
	spin_lock_irqsave(&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
	irqStatus = MFBInfo.IrqInfo.Status[WaitIrq->Type];
	spin_unlock_irqrestore(&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);

	if (WaitIrq->Type != MFB_IRQ_TYPE_INT_MSS_ST) {
		LOG_ERR(
			"No Such Stats can be waited!! irq Type/User/Sts/Pid(0x%x/%d/0x%x/%d)\n",
			WaitIrq->Type,
			WaitIrq->UserKey,
			WaitIrq->Status,
			WaitIrq->ProcessID);
	}


#ifdef MFB_WAITIRQ_LOG
	LOG_INF(
		"before wait_event! Timeout(%d)Clear(%d),Type(%d),IrqSta(0x%08X), WaitSta(0x%08X)\n",
		WaitIrq->Timeout, WaitIrq->Clear,
		WaitIrq->Type, irqStatus, WaitIrq->Status);
	LOG_INF(
		"urKey(%d),whReq(%d),PID(%d)\n",
		WaitIrq->UserKey, whichReq, WaitIrq->ProcessID);
	LOG_INF(
		"MssIrqCnt(0x%08X)\n",
		MFBInfo.IrqInfo.MssIrqCnt);
#endif

	/* 2. start to wait signal */
	Timeout = wait_event_interruptible_timeout(MFBInfo.WaitQueueHeadMss,
				MSS_GetIRQState(WaitIrq->Type,
				&WaitIrq->UserKey,
				WaitIrq->Status, whichReq,
				WaitIrq->ProcessID),
				MFB_MsToJiffies(WaitIrq->Timeout));

	/* check if user is interrupted by system signal */
	if ((Timeout != 0) &&
	    (!WaitIrq->UserKey)) {
		LOG_INF(
			"waked up by sys. signal,ret(%d),irq Type/User/Sts/whReq/Pid(0x%x/%d/0x%x/%d/%d)\n",
			Timeout, WaitIrq->Type, WaitIrq->UserKey,
			WaitIrq->Status, whichReq,
			WaitIrq->ProcessID);
		Ret = -ERESTARTSYS;	/* actually it should be -ERESTARTSYS */
		goto EXIT;
	}
	/* timeout */
	if (Timeout == 0) {
		/* Store irqinfo status in here to redeuce time of
		 * spin_lock_irqsave
		 */
		spin_lock_irqsave(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
		irqStatus = MFBInfo.IrqInfo.Status[WaitIrq->Type];
		spin_unlock_irqrestore(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);

		LOG_ERR(
			"ERRRR Timeout!Timeout(%d)Clear(%d),Type(%d),IrqSta(0x%08X), WaitSta(0x%08X)\n",
			WaitIrq->Timeout, WaitIrq->Clear,
			WaitIrq->Type, irqStatus, WaitIrq->Status);
		LOG_ERR("urKey(%d),whReq(%d),PID(%d)\n",
			WaitIrq->UserKey, whichReq, WaitIrq->ProcessID);
		LOG_ERR(
			"MssIrqCnt(0x%08X)\n",
			MFBInfo.IrqInfo.MssIrqCnt[whichReq]);

		if (WaitIrq->bDumpReg)
			MSS_DumpReg();

		Ret = -EFAULT;
		goto EXIT;
	} else {
		/* Store irqinfo status in here to redeuce time of
		 * spin_lock_irqsave
		 */
#ifdef __MFB_KERNEL_PERFORMANCE_MEASURE__
		mt_kernel_trace_begin("MFB WaitIrq");
#endif

		spin_lock_irqsave(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
		irqStatus = MFBInfo.IrqInfo.Status[WaitIrq->Type];
		spin_unlock_irqrestore(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);

		if (WaitIrq->Clear == MFB_IRQ_WAIT_CLEAR) {
			spin_lock_irqsave(
				&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);

			if (WaitIrq->Status & MSS_INT_ST) {
				p = WaitIrq->ProcessID % IRQ_USER_NUM_MAX;
				MFBInfo.IrqInfo.MssIrqCnt[p]--;
				if (MFBInfo.IrqInfo.MssIrqCnt[p] == 0)
					MFBInfo.IrqInfo.Status[WaitIrq->Type] &=
						(~WaitIrq->Status);
			} else {
				LOG_ERR(
				"MFB_IRQ_WAIT_CLEAR Error, Type(%d), WaitStatus(0x%08X)",
					WaitIrq->Type, WaitIrq->Status);
			}
			spin_unlock_irqrestore(
				&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
		}

#ifdef MFB_WAITIRQ_LOG
		LOG_INF(
			"no Timeout!Timeout(%d)Clear(%d),Type(%d),IrqSta(0x%08X), WaitSta(0x%08X)\n",
			WaitIrq->Timeout, WaitIrq->Clear,
			WaitIrq->Type, irqStatus, WaitIrq->Status);
		LOG_INF("urKey(%d),whReq(%d),PID(%d)\n",
			WaitIrq->UserKey, whichReq, WaitIrq->ProcessID);
		LOG_INF(
			"MssIrqCnt(0x%08X)\n",
			MFBInfo.IrqInfo.MssIrqCnt);

#endif

#ifdef __MFB_KERNEL_PERFORMANCE_MEASURE__
		mt_kernel_trace_end();
#endif

	}


EXIT:


	return Ret;
}

/******************************************************************************
 *
 ******************************************************************************/
static signed int MSF_WaitIrq(struct MFB_WAIT_IRQ_STRUCT *WaitIrq)
{

	signed int Ret = 0;
	signed int Timeout = WaitIrq->Timeout;
	enum MFB_PROCESS_ID_ENUM whichReq = MFB_PROCESS_ID_MSF;

	/*unsigned int i;*/
	unsigned long flags; /* old: unsigned int flags;*/
			     /* FIX to avoid build warning */
	unsigned int irqStatus;
	/*int cnt = 0;*/
	struct timespec64 time_getrequest;
	unsigned int p;

	ktime_get_ts64(&time_getrequest);

	/* Debug interrupt */
	if (MFBInfo.DebugMaskMsf & MFB_DBG_INT) {
		if (WaitIrq->Status & MFBInfo.IrqInfo.Mask[WaitIrq->Type]) {
			if (WaitIrq->UserKey > 0) {
				LOG_DBG(
					"+WaitIrq Clr(%d),Type(%d),Sta(0x%08X),Timeout(%d),user(%d),PID(%d)\n",
					WaitIrq->Clear,
					WaitIrq->Type,
					WaitIrq->Status,
					WaitIrq->Timeout,
					WaitIrq->UserKey,
					WaitIrq->ProcessID);
			}
		}
	}


	/* 1. wait type update */
	if (WaitIrq->Clear == MFB_IRQ_CLEAR_STATUS) {
		spin_lock_irqsave(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
		MFBInfo.IrqInfo.Status[WaitIrq->Type] &= (~WaitIrq->Status);
		spin_unlock_irqrestore(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
		return Ret;
	}

	if (WaitIrq->Clear == MFB_IRQ_CLEAR_WAIT) {
		spin_lock_irqsave(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
		if (MFBInfo.IrqInfo.Status[WaitIrq->Type] & WaitIrq->Status)
			MFBInfo.IrqInfo.Status[WaitIrq->Type] &=
				(~WaitIrq->Status);

		spin_unlock_irqrestore(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
	} else if (WaitIrq->Clear == MFB_IRQ_CLEAR_ALL) {
		spin_lock_irqsave(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);

		MFBInfo.IrqInfo.Status[WaitIrq->Type] = 0;
		spin_unlock_irqrestore(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
	}
	/* MFB_IRQ_WAIT_CLEAR ==> do nothing */


	/* Store irqinfo status in here to redeuce time of spin_lock_irqsave */
	spin_lock_irqsave(&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
	irqStatus = MFBInfo.IrqInfo.Status[WaitIrq->Type];
	spin_unlock_irqrestore(&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);

	if (WaitIrq->Type != MFB_IRQ_TYPE_INT_MSF_ST) {
		LOG_ERR(
			"No Such Stats can be waited!! irq Type/User/Sts/Pid(0x%x/%d/0x%x/%d)\n",
			WaitIrq->Type,
			WaitIrq->UserKey,
			WaitIrq->Status,
			WaitIrq->ProcessID);
	}


#ifdef MFB_WAITIRQ_LOG
	LOG_INF(
		"before wait_event! Timeout(%d)Clear(%d),Type(%d),IrqSta(0x%08X), WaitSta(0x%08X)\n",
		WaitIrq->Timeout, WaitIrq->Clear,
		WaitIrq->Type, irqStatus, WaitIrq->Status);
	LOG_INF(
		"urKey(%d),whReq(%d),PID(%d)\n",
		WaitIrq->UserKey, whichReq, WaitIrq->ProcessID);
	LOG_INF(
		"MsfIrqCnt(0x%08X)\n",
		MFBInfo.IrqInfo.MsfIrqCnt);
#endif

	/* 2. start to wait signal */
	Timeout = wait_event_interruptible_timeout(MFBInfo.WaitQueueHeadMsf,
				MSF_GetIRQState(WaitIrq->Type, WaitIrq->UserKey,
				WaitIrq->Status, whichReq,
				WaitIrq->ProcessID),
				MFB_MsToJiffies(WaitIrq->Timeout));

	p = WaitIrq->ProcessID % IRQ_USER_NUM_MAX;
	/* check if user is interrupted by system signal */
	if ((Timeout != 0) &&
	    (!MSF_GetIRQState(
		WaitIrq->Type,
		WaitIrq->UserKey,
		WaitIrq->Status,
		whichReq,
		WaitIrq->ProcessID))) {
		LOG_INF(
			"waked up by sys. signal,ret(%d),irq Type/User/Sts/whReq/Pid(0x%x/%d/0x%x/%d/%d)\n",
			Timeout, WaitIrq->Type, WaitIrq->UserKey,
			WaitIrq->Status, whichReq,
			WaitIrq->ProcessID);
		Ret = -ERESTARTSYS;	/* actually it should be -ERESTARTSYS */
		goto EXIT;
	}
	/* timeout */
	if (Timeout == 0) {
		/* Store irqinfo status in here to redeuce time of
		 * spin_lock_irqsave
		 */
		spin_lock_irqsave(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
		irqStatus = MFBInfo.IrqInfo.Status[WaitIrq->Type];
		spin_unlock_irqrestore(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);

		LOG_ERR(
			"ERRRR Timeout!Timeout(%d)Clear(%d),Type(%d),IrqSta(0x%08X), WaitSta(0x%08X)\n",
			WaitIrq->Timeout, WaitIrq->Clear,
			WaitIrq->Type, irqStatus, WaitIrq->Status);
		LOG_ERR("urKey(%d),whReq(%d),PID(%d)\n",
			WaitIrq->UserKey, whichReq, WaitIrq->ProcessID);
		LOG_ERR(
			"MsfIrqCnt(0x%08X)\n",
			MFBInfo.IrqInfo.MsfIrqCnt[p]);

		if (WaitIrq->bDumpReg)
			MSF_DumpReg();

		Ret = -EFAULT;
		goto EXIT;
	} else {
		/* Store irqinfo status in here to redeuce time of
		 * spin_lock_irqsave
		 */
#ifdef __MFB_KERNEL_PERFORMANCE_MEASURE__
		mt_kernel_trace_begin("MFB WaitIrq");
#endif

		spin_lock_irqsave(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
		irqStatus = MFBInfo.IrqInfo.Status[WaitIrq->Type];
		spin_unlock_irqrestore(
			&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);

		if (WaitIrq->Clear == MFB_IRQ_WAIT_CLEAR) {
			spin_lock_irqsave(
				&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);

			if (WaitIrq->Status & MSF_INT_ST) {
				MFBInfo.IrqInfo.MsfIrqCnt[p]--;
				if (MFBInfo.IrqInfo.MsfIrqCnt[p] == 0)
					MFBInfo.IrqInfo.Status[WaitIrq->Type] &=
						(~WaitIrq->Status);
			} else {
				LOG_ERR(
				"MFB_IRQ_WAIT_CLEAR Error, Type(%d), WaitStatus(0x%08X)",
					WaitIrq->Type, WaitIrq->Status);
			}
			spin_unlock_irqrestore(
				&(MFBInfo.SpinLockIrq[WaitIrq->Type]), flags);
		}

#ifdef MFB_WAITIRQ_LOG
		LOG_INF(
			"no Timeout!Timeout(%d)Clear(%d),Type(%d),IrqSta(0x%08X), WaitSta(0x%08X)\n",
			WaitIrq->Timeout, WaitIrq->Clear,
			WaitIrq->Type, irqStatus, WaitIrq->Status);
		LOG_INF("urKey(%d),whReq(%d),PID(%d)\n",
			WaitIrq->UserKey, whichReq, WaitIrq->ProcessID);
		LOG_INF(
			"MsfIrqCnt(0x%08X)\n",
			MFBInfo.IrqInfo.MsfIrqCnt);

#endif

#ifdef __MFB_KERNEL_PERFORMANCE_MEASURE__
		mt_kernel_trace_end();
#endif

	}


EXIT:


	return Ret;
}

/******************************************************************************
 *
 ******************************************************************************/
static enum MFB_PROCESS_ID_ENUM mss_get_reqs(enum exec_mode exec,
					struct engine_requests **reqs)
{
	enum MFB_PROCESS_ID_ENUM tag;

	switch (exec) {
	case EXEC_MODE_NORM:
		*reqs = &mss_reqs;
		tag = MFB_PROCESS_ID_MSS;
		break;
	case EXEC_MODE_VSS:
		*reqs = &vmss_reqs;
		tag = MFB_PROCESS_ID_vMSS;
		break;
	default:
		tag = MFB_PROCESS_ID_NONE;
		LOG_ERR("invalid tile irq mode\n");
		break;
	}

	return tag;
}

static unsigned int msf_get_reqs(enum exec_mode exec,
					struct engine_requests **reqs)
{
	unsigned int ret = 0;

	switch (exec) {
	case EXEC_MODE_NORM:
		*reqs = &msf_reqs;
		break;
	case EXEC_MODE_VSS:
		*reqs = &vmsf_reqs;
		break;
	default:
		ret = 1;
		LOG_ERR("invalid tile irq mode\n");
		break;
	}

	return ret;
}


static long MFB_ioctl(struct file *pFile, unsigned int Cmd, unsigned long Param)
{
	signed int Ret = 0;

	/*unsigned int pid = 0;*/
	struct MFB_REG_IO_STRUCT RegIo;
	struct MFB_WAIT_IRQ_STRUCT IrqInfo;
	struct MFB_CLEAR_IRQ_STRUCT ClearIrq;
	struct MFB_MSSRequest mfb_MssReq;
	struct MFB_MSFRequest mfb_MsfReq;
	struct MFB_USER_INFO_STRUCT *pUserInfo;
	struct engine_requests *reqs = NULL;
	struct MFB_MSSConfig *msscfgs = NULL;
	int dequeNum;
	unsigned long flags; /* old: unsigned int flags;*/
			     /* FIX to avoid build warning */
	struct MFB_MapTable mfb_maptable;
	unsigned int i = 0;

	if (pFile->private_data == NULL) {
		LOG_WRN(
			"private_data is NULL,(process, pid, tgid)=(%s, %d, %d)",
			current->comm,
			current->pid, current->tgid);
		return -EFAULT;
	}
	pUserInfo = (struct MFB_USER_INFO_STRUCT *) (pFile->private_data);
	switch (Cmd) {
	case MFB_MSS_RESET:
		{
			spin_lock(
			&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]));
			MSS_Reset();
			spin_unlock(
			&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]));
			break;
		}
	case MFB_MSF_RESET:
		{
			spin_lock(
			&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]));
			MSF_Reset();
			spin_unlock(
			&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]));
			break;
		}
	case MFB_MSS_DUMP_REG:
		{
			Ret = MSS_DumpReg();
			break;
		}
	case MFB_MSF_DUMP_REG:
		{
			Ret = MSF_DumpReg();
			break;
		}
	case MFB_MSS_DUMP_ISR_LOG:
		{
			unsigned int currentPPB = m_CurrentPPB;

			spin_lock_irqsave(
				&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]),
				flags);
			m_CurrentPPB = (m_CurrentPPB + 1) % LOG_PPNUM;
			spin_unlock_irqrestore(
				&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]),
				flags);

			IRQ_LOG_PRINTER(MFB_IRQ_TYPE_INT_MSS_ST,
				currentPPB, _LOG_INF);
			IRQ_LOG_PRINTER(MFB_IRQ_TYPE_INT_MSS_ST,
				currentPPB, _LOG_ERR);
			break;
		}
	case MFB_MSF_DUMP_ISR_LOG:
		{
			unsigned int currentPPB = m_CurrentPPB;

			spin_lock_irqsave(
				&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]),
				flags);
			m_CurrentPPB = (m_CurrentPPB + 1) % LOG_PPNUM;
			spin_unlock_irqrestore(
				&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]),
				flags);

			IRQ_LOG_PRINTER(MFB_IRQ_TYPE_INT_MSF_ST,
				currentPPB, _LOG_INF);
			IRQ_LOG_PRINTER(MFB_IRQ_TYPE_INT_MSF_ST,
				currentPPB, _LOG_ERR);
			break;
		}
	case MFB_MSS_READ_REGISTER:
		{
			if (copy_from_user(&RegIo, (void *)Param,
				sizeof(struct MFB_REG_IO_STRUCT)) == 0) {
				/* 2nd layer behavoir of copy from user is
				 * implemented in MFB_ReadReg(...)
				 */
				Ret = MSS_ReadReg(&RegIo);
			} else {
				LOG_ERR(
					"MFB_MSS_READ_REGISTER copy_from_user failed");
				Ret = -EFAULT;
			}
			break;
		}
	case MFB_MSF_READ_REGISTER:
		{
			if (copy_from_user(&RegIo, (void *)Param,
				sizeof(struct MFB_REG_IO_STRUCT)) == 0) {
				/* 2nd layer behavoir of copy from user is
				 * implemented in MFB_ReadReg(...)
				 */
				Ret = MSF_ReadReg(&RegIo);
			} else {
				LOG_ERR(
					"MFB_MSF_READ_REGISTER copy_from_user failed");
				Ret = -EFAULT;
			}
			break;
		}
	case MFB_MSS_WRITE_REGISTER:
		{
			if (copy_from_user(&RegIo, (void *)Param,
				sizeof(struct MFB_REG_IO_STRUCT)) == 0) {
				/* 2nd layer behavoir of copy from user is
				 * implemented in MFB_WriteReg(...)
				 */
				Ret = MSS_WriteReg(&RegIo);
			} else {
				LOG_ERR(
					"MFB_MSS_WRITE_REGISTER copy_from_user failed");
				Ret = -EFAULT;
			}
			break;
		}
	case MFB_MSF_WRITE_REGISTER:
		{
			if (copy_from_user(&RegIo, (void *)Param,
				sizeof(struct MFB_REG_IO_STRUCT)) == 0) {
				/* 2nd layer behavoir of copy from user is
				 * implemented in MFB_WriteReg(...)
				 */
				Ret = MSF_WriteReg(&RegIo);
			} else {
				LOG_ERR(
					"MFB_MSF_WRITE_REGISTER copy_from_user failed");
				Ret = -EFAULT;
			}
			break;
		}
	case MFB_MSS_WAIT_IRQ:
		{
			if (copy_from_user(&IrqInfo, (void *)Param,
				sizeof(struct MFB_WAIT_IRQ_STRUCT)) == 0) {
				if ((IrqInfo.Type >= MFB_IRQ_TYPE_AMOUNT) ||
					(IrqInfo.Type < 0)) {
					Ret = -EFAULT;
					LOG_ERR("invalid type(%d)",
						IrqInfo.Type);
					goto EXIT;
				}

				if ((IrqInfo.UserKey >= IRQ_USER_NUM_MAX) ||
					(IrqInfo.UserKey < 0)) {
					LOG_ERR(
						"invalid userKey(%d), max(%d), force userkey = 0\n",
						IrqInfo.UserKey,
						IRQ_USER_NUM_MAX);
					IrqInfo.UserKey = 0;
				}

				LOG_DBG(
					"MSS IRQ clear(%d), type(%d), userKey(%d), timeout(%d), status(%d), streamtag(%d)\n",
					IrqInfo.Clear, IrqInfo.Type,
					IrqInfo.UserKey, IrqInfo.Timeout,
					IrqInfo.Status, pUserInfo->streamtag);

				IrqInfo.ProcessID = pUserInfo->Pid;
				Ret = MSS_WaitIrq(&IrqInfo,
							pUserInfo->streamtag);
				if (Ret < 0) {
					mfb_request_dump(&mss_reqs);
					mfb_request_dump(&vmss_reqs);
					MSS_DumpReg();
				}

				if (copy_to_user((void *)Param, &IrqInfo,
				    sizeof(struct MFB_WAIT_IRQ_STRUCT)) != 0) {
					LOG_ERR("copy_to_user failed\n");
					Ret = -EFAULT;
				}
			} else {
				LOG_ERR("MFB_WAIT_IRQ copy_from_user failed");
				Ret = -EFAULT;
			}
			break;
		}
	case MFB_MSF_WAIT_IRQ:
		{
			if (copy_from_user(&IrqInfo, (void *)Param,
				sizeof(struct MFB_WAIT_IRQ_STRUCT)) == 0) {
				if ((IrqInfo.Type >= MFB_IRQ_TYPE_AMOUNT) ||
					(IrqInfo.Type < 0)) {
					Ret = -EFAULT;
					LOG_ERR("invalid type(%d)",
						IrqInfo.Type);
					goto EXIT;
				}

				if ((IrqInfo.UserKey >= IRQ_USER_NUM_MAX) ||
					(IrqInfo.UserKey < 0)) {
					LOG_ERR(
						"invalid userKey(%d), max(%d), force userkey = 0\n",
						IrqInfo.UserKey,
						IRQ_USER_NUM_MAX);
					IrqInfo.UserKey = 0;
				}

				LOG_INF(
					"MSF IRQ clear(%d), type(%d), userKey(%d), timeout(%d), status(%d)\n",
					IrqInfo.Clear, IrqInfo.Type,
					IrqInfo.UserKey, IrqInfo.Timeout,
					IrqInfo.Status);

				IrqInfo.ProcessID = pUserInfo->Pid;
				Ret = MSF_WaitIrq(&IrqInfo);
				if (Ret < 0) {
					mfb_request_dump(&vmsf_reqs);
					mfb_request_dump(&msf_reqs);
					MSF_DumpReg();
				}

				if (copy_to_user((void *)Param, &IrqInfo,
				    sizeof(struct MFB_WAIT_IRQ_STRUCT)) != 0) {
					LOG_ERR("copy_to_user failed\n");
					Ret = -EFAULT;
				}
			} else {
				LOG_ERR("MFB_WAIT_IRQ copy_from_user failed");
				Ret = -EFAULT;
			}
			break;
		}
	case MFB_MSS_CLEAR_IRQ:
		{
			if (copy_from_user(&ClearIrq, (void *)Param,
				sizeof(struct MFB_CLEAR_IRQ_STRUCT)) == 0) {
				LOG_DBG("MFB_MSS_CLEAR_IRQ Type(%d)",
					ClearIrq.Type);

				if ((ClearIrq.Type >= MFB_IRQ_TYPE_AMOUNT) ||
					(ClearIrq.Type < 0)) {
					Ret = -EFAULT;
					LOG_ERR("invalid type(%d)",
						ClearIrq.Type);
					goto EXIT;
				}

				if ((ClearIrq.UserKey >= IRQ_USER_NUM_MAX)
				    || (ClearIrq.UserKey < 0)) {
					LOG_ERR("errUserEnum(%d)",
						ClearIrq.UserKey);
					Ret = -EFAULT;
					goto EXIT;
				}

				LOG_DBG(
					"MFB_MSS_CLEAR_IRQ:Type(%d),Status(0x%08X),IrqStatus(0x%08X)\n",
					ClearIrq.Type, ClearIrq.Status,
					MFBInfo.IrqInfo.Status[ClearIrq.Type]);
				spin_lock_irqsave(
					&(MFBInfo.SpinLockIrq[ClearIrq.Type]),
					flags);
				MFBInfo.IrqInfo.Status[ClearIrq.Type] &=
					(~ClearIrq.Status);
				spin_unlock_irqrestore(
					&(MFBInfo.SpinLockIrq[ClearIrq.Type]),
					flags);
			} else {
				LOG_ERR(
					"MFB_MSS_CLEAR_IRQ copy_from_user failed\n");
				Ret = -EFAULT;
			}
			break;
		}
	case MFB_MSF_CLEAR_IRQ:
		{
			if (copy_from_user(&ClearIrq, (void *)Param,
				sizeof(struct MFB_CLEAR_IRQ_STRUCT)) == 0) {
				LOG_DBG("MFB_MSF_CLEAR_IRQ Type(%d)",
					ClearIrq.Type);

				if ((ClearIrq.Type >= MFB_IRQ_TYPE_AMOUNT) ||
					(ClearIrq.Type < 0)) {
					Ret = -EFAULT;
					LOG_ERR("invalid type(%d)",
						ClearIrq.Type);
					goto EXIT;
				}

				if ((ClearIrq.UserKey >= IRQ_USER_NUM_MAX)
				    || (ClearIrq.UserKey < 0)) {
					LOG_ERR("errUserEnum(%d)",
						ClearIrq.UserKey);
					Ret = -EFAULT;
					goto EXIT;
				}

				LOG_DBG(
					"MFB_MSF_CLEAR_IRQ:Type(%d),Status(0x%08X),IrqStatus(0x%08X)\n",
					ClearIrq.Type, ClearIrq.Status,
					MFBInfo.IrqInfo.Status[ClearIrq.Type]);
				spin_lock_irqsave(
					&(MFBInfo.SpinLockIrq[ClearIrq.Type]),
					flags);
				MFBInfo.IrqInfo.Status[ClearIrq.Type] &=
					(~ClearIrq.Status);
				spin_unlock_irqrestore(
					&(MFBInfo.SpinLockIrq[ClearIrq.Type]),
					flags);
			} else {
				LOG_ERR(
					"MFB_MSF_CLEAR_IRQ copy_from_user failed\n");
				Ret = -EFAULT;
			}
			break;
		}
	case MFB_MSS_ENQUE_REQ:
		{
		if (copy_from_user(&mfb_MssReq, (void *)Param,
			sizeof(struct MFB_MSSRequest)) == 0) {
			LOG_DBG("MSS_ENQNUE_NUM:%d, pid:%d\n",
				mfb_MssReq.m_ReqNum,
				pUserInfo->Pid);
			if (mfb_MssReq.m_ReqNum >
				_SUPPORT_MAX_MFB_FRAME_REQUEST_) {
				LOG_ERR(
					"MSS Enque Num is bigger than enqueNum:%d\n",
					mfb_MssReq.m_ReqNum);
				Ret = -EFAULT;
				goto EXIT;
			}

			if (mfb_MssReq.m_pMssConfig == NULL) {
				LOG_ERR("NULL MSS user Config\n");
				Ret = -EFAULT;
				goto EXIT;
			}

			mutex_lock(&gMfbMssMutex);/* Protect the Multi Process*/
			switch (mfb_MssReq.exec) {
			case EXEC_MODE_NORM:
				msscfgs = g_MssEnqueReq_Struct.MssFrameConfig;
				break;
			case EXEC_MODE_VSS:
				msscfgs = g_MssEnqueReq_Struct.vMssFrameConfig;
				break;
			default:
				msscfgs = g_MssEnqueReq_Struct.MssFrameConfig;
				LOG_WRN("invalid irq mode\n");
				break;
			}

			if (copy_from_user(msscfgs,
				(void *)mfb_MssReq.m_pMssConfig,
				mfb_MssReq.m_ReqNum * sizeof(
					struct MFB_MSSConfig)
				) != 0) {
				LOG_ERR(
					"copy MSSConfig from request is fail!!\n");
				Ret = -EFAULT;
				goto EXIT;
			}

			pUserInfo->streamtag = mss_get_reqs(mfb_MssReq.exec,
									&reqs);
			pUserInfo->reqs = reqs;

			spin_lock_irqsave(
				&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]),
				flags);
			kMssReq.m_ReqNum = mfb_MssReq.m_ReqNum;
			kMssReq.m_pMssConfig = msscfgs;
			mfb_enque_request(reqs, kMssReq.m_ReqNum, &kMssReq,
								pUserInfo->Pid);
			spin_unlock_irqrestore(
				&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]),
				flags);
			LOG_DBG("ConfigMSS Request!!\n");
			if (!mfb_request_running(reqs)) {
				LOG_DBG("direct mfb_request_handler\n");
				mfb_request_handler(reqs,
						&(MFBInfo.SpinLockIrq[
						MFB_IRQ_TYPE_INT_MSS_ST]));
			}
			mutex_unlock(&gMfbMssMutex);
		} else {
			LOG_ERR("MFB_MSS_ENQUE copy_from_user failed\n");
			Ret = -EFAULT;
		}
		break;
		}
	case MFB_MSS_DEQUE_REQ:
		{
			if (copy_from_user(&mfb_MssReq, (void *)Param,
					sizeof(struct MFB_MSSRequest)) == 0) {
				reqs = pUserInfo->reqs;
				mutex_lock(&gMfbMssDequeMutex);
				/* Protect the Multi Process */

				spin_lock_irqsave(&(MFBInfo.SpinLockIrq[
						MFB_IRQ_TYPE_INT_MSS_ST]),
						  flags);
				kMssReq.m_pMssConfig =
					g_MssDequeReq_Struct.MssFrameConfig;
				mfb_deque_request(reqs, &kMssReq.m_ReqNum,
					&kMssReq);
				dequeNum = kMssReq.m_ReqNum;
				mfb_MssReq.m_ReqNum = dequeNum;
				spin_unlock_irqrestore(
					&(MFBInfo.SpinLockIrq[
						MFB_IRQ_TYPE_INT_MSS_ST]),
					flags);

				mutex_unlock(&gMfbMssDequeMutex);

				if (mfb_MssReq.m_pMssConfig == NULL) {
					LOG_ERR("NULL MSS user Config\n");
					Ret = -EFAULT;
					goto EXIT;
				}

				if (copy_to_user(
					(void *)mfb_MssReq.m_pMssConfig,
					&g_MssDequeReq_Struct.MssFrameConfig[0],
					dequeNum * sizeof(
						struct MFB_MSSConfig)) != 0) {
					LOG_ERR(
						"MFB_CMD_MSS_DEQUE_REQ copy_to_user frameconfig failed\n");
					Ret = -EFAULT;
				}
				if (copy_to_user((void *)Param, &mfb_MssReq,
					sizeof(struct MFB_MSSRequest)) != 0) {
					LOG_ERR(
						"MFB_CMD_MSS_DEQUE_REQ copy_to_user failed\n");
					Ret = -EFAULT;
				}
			} else {
				LOG_ERR(
					"MFB_CMD_MSS_DEQUE_REQ copy_from_user failed\n");
				Ret = -EFAULT;
			}
			break;
		}
	case MFB_MSF_ENQUE_REQ:
		{
		if (copy_from_user(&mfb_MsfReq, (void *)Param,
			sizeof(struct MFB_MSFRequest)) == 0) {
			LOG_DBG("MSF_ENQNUE_NUM:%d, pid:%d\n",
				mfb_MsfReq.m_ReqNum,
				pUserInfo->Pid);
			if (mfb_MsfReq.m_ReqNum >
				_SUPPORT_MAX_MFB_FRAME_REQUEST_) {
				LOG_ERR(
					"MSF Enque Num is bigger than enqueNum:%d\n",
					mfb_MsfReq.m_ReqNum);
				Ret = -EFAULT;
				goto EXIT;
			}

			if (mfb_MsfReq.m_pMsfConfig == NULL) {
				LOG_ERR("NULL MSF user Config\n");
				Ret = -EFAULT;
				goto EXIT;
			}

			/* Protect the Multi Process */
			mutex_lock(&gMfbMsfMutex);

			if (copy_from_user(
				g_MsfEnqueReq_Struct.MsfFrameConfig,
				(void *)mfb_MsfReq.m_pMsfConfig,
				mfb_MsfReq.m_ReqNum *
					sizeof(struct MFB_MSFConfig)) != 0) {
				LOG_ERR(
					"copy MSFConfig from request is fail!!\n");
				Ret = -EFAULT;
				goto EXIT;
			}
			msf_get_reqs(mfb_MsfReq.exec, &reqs);
			pUserInfo->reqs = reqs;

			spin_lock_irqsave(
				&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]),
				flags);
			kMsfReq.m_ReqNum = mfb_MsfReq.m_ReqNum;
			kMsfReq.m_pMsfConfig =
				g_MsfEnqueReq_Struct.MsfFrameConfig;
			mfb_enque_request(reqs,
				kMsfReq.m_ReqNum,
				&kMsfReq, pUserInfo->Pid);
			spin_unlock_irqrestore(
				&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]),
				flags);

			LOG_DBG("ConfigMSF Request!!\n");
			if (!mfb_request_running(reqs)) {
				LOG_DBG("direct mfb_request_handler\n");
				mfb_request_handler(
					reqs,
					&(MFBInfo.SpinLockIrq[
						MFB_IRQ_TYPE_INT_MSF_ST])
					);
			}
			mutex_unlock(&gMfbMsfMutex);
		} else {
			LOG_ERR("MFB_MSF_ENQUE copy_from_user failed\n");
			Ret = -EFAULT;
		}

			break;
		}
	case MFB_MSF_DEQUE_REQ:
		{
			if (copy_from_user(&mfb_MsfReq, (void *)Param,
				sizeof(struct MFB_MSFRequest)) == 0) {
				reqs = pUserInfo->reqs;
				mutex_lock(&gMfbMsfDequeMutex);
				/* Protect the Multi Process */
				spin_lock_irqsave(
					&(MFBInfo.SpinLockIrq[
						MFB_IRQ_TYPE_INT_MSF_ST]),
					flags);
				kMsfReq.m_pMsfConfig =
					g_MsfDequeReq_Struct.MsfFrameConfig;
				mfb_deque_request(
					reqs,
					&kMsfReq.m_ReqNum,
					&kMsfReq);
				dequeNum = kMsfReq.m_ReqNum;
				mfb_MsfReq.m_ReqNum = dequeNum;

				spin_unlock_irqrestore(
					&(MFBInfo.SpinLockIrq[
						MFB_IRQ_TYPE_INT_MSF_ST]),
					flags);

				mutex_unlock(&gMfbMsfDequeMutex);

				if (mfb_MsfReq.m_pMsfConfig == NULL) {
					LOG_ERR("NULL MSF user Config\n");
					Ret = -EFAULT;
					goto EXIT;
				}

				if (copy_to_user(
					(void *)mfb_MsfReq.m_pMsfConfig,
				     &g_MsfDequeReq_Struct.MsfFrameConfig[0],
				     dequeNum *
					sizeof(struct MFB_MSFConfig)) != 0) {
					LOG_ERR(
						"MFB_MSF_DEQUE_REQ copy_to_user frameconfig failed\n");
					Ret = -EFAULT;
				}
				if (copy_to_user(
					(void *)Param, &mfb_MsfReq,
					sizeof(struct MFB_MSFRequest)) != 0) {
					LOG_ERR(
						"MFB_MSF_DEQUE_REQ copy_to_user failed\n");
					Ret = -EFAULT;
				}
			} else {
				LOG_ERR(
					"MFB_CMD_MSF_DEQUE_REQ copy_from_user failed\n");
				Ret = -EFAULT;
			}

			break;
		}
	case MFB_MAP:
		{
		if (copy_from_user(&mfb_maptable, (void *)Param,
			sizeof(struct MFB_MapTable)) == 0) {

			if (mfb_maptable.buf_fd == 0) {
				LOG_ERR("buf_fd equal 0\n");
				Ret = -EFAULT;
				goto EXIT;
			}
			mutex_lock(&(Mutexgkibuf));
			for (i = 0; i < GKI_BUF_NUM_MAX; i++) {
				if (pUserInfo->gkiBuf[i].isUse == 0) {
					pUserInfo->gkiBuf[i].isUse = 1;
					break;
				}
			}
			if (i == GKI_BUF_NUM_MAX) {
				LOG_ERR("gkiBuf full\n");
				mutex_unlock(&(Mutexgkibuf));
				Ret = -EFAULT;
				goto EXIT;
			}
			pUserInfo->gkiBuf[i].bfd = mfb_maptable.buf_fd;
			if (mfb_get_dma_buf(&pUserInfo->gkiBuf[i], mfb_maptable.buf_fd) != 0) {
				LOG_ERR("get_dma fail\n");
				mutex_unlock(&(Mutexgkibuf));
				Ret = -EFAULT;
				goto EXIT;
			}
			mfb_maptable.buf_pa =
				(unsigned int)sg_dma_address((pUserInfo->gkiBuf[i].sgt)->sgl);
			qq_get_cnt++;
			LOG_DBG("qq_get_cnt = %d pa = 0x%lx\n", qq_get_cnt, mfb_maptable.buf_pa);
			mutex_unlock(&(Mutexgkibuf));
		} else {
			LOG_ERR("MFB_MAP copy_from_user failed\n");
			Ret = -EFAULT;
		}
		return mfb_maptable.buf_pa;
			break;
		}
	case MFB_UNMAP:
		{
		if (copy_from_user(&mfb_maptable, (void *)Param,
			sizeof(struct MFB_MapTable)) == 0) {

			if (mfb_maptable.buf_fd == 0) {
				LOG_ERR("buf_fd equal 0\n");
				Ret = -EFAULT;
				goto EXIT;
			}
			mutex_lock(&(Mutexgkibuf));
			for (i = 0; i < GKI_BUF_NUM_MAX; i++) {
				if (pUserInfo->gkiBuf[i].bfd == mfb_maptable.buf_fd) {
					if (pUserInfo->gkiBuf[i].isUse == 1) {
						pUserInfo->gkiBuf[i].isUse = 0;
						break;
					}
				}
			}
			if (i == GKI_BUF_NUM_MAX) {
				LOG_ERR("gkiBuf full\n");
				mutex_unlock(&(Mutexgkibuf));
				Ret = -EFAULT;
				goto EXIT;
			}
			mfb_put_dma_buf(&pUserInfo->gkiBuf[i]);
			mutex_unlock(&(Mutexgkibuf));
			qq_put_cnt++;
			LOG_DBG("qq_put_cnt = %d\n", qq_put_cnt);
		} else {
			LOG_ERR("MFB_MAP copy_from_user failed\n");
			Ret = -EFAULT;
		}
			break;
		}
	default:
		{
			LOG_ERR("Unknown Cmd(%d)", Cmd);
			LOG_ERR(
				"Fail, Cmd(%d), Dir(%d), Type(%d), Nr(%d),Size(%d)\n",
				Cmd, _IOC_DIR(Cmd),
				_IOC_TYPE(Cmd), _IOC_NR(Cmd), _IOC_SIZE(Cmd));
			Ret = -EPERM;
			break;
		}
	}
EXIT:
	if (Ret != 0) {
		LOG_ERR(
			"Fail, Cmd(%d), Pid(%d), (process, pid, tgid)=(%s, %d, %d)",
			Cmd,
			pUserInfo->Pid, current->comm,
			current->pid, current->tgid);
	}
	return Ret;
}

#ifdef CONFIG_COMPAT

/******************************************************************************
 *
 ******************************************************************************/
static int compat_get_MFB_read_register_data(
	struct compat_MFB_REG_IO_STRUCT __user *data32,
	struct MFB_REG_IO_STRUCT __user *data)
{
	compat_uint_t count;
	compat_uptr_t uptr;
	int err;

	err = get_user(uptr, &data32->pData);
	err |= put_user(compat_ptr(uptr), &data->pData);
	err |= get_user(count, &data32->Count);
	err |= put_user(count, &data->Count);
	return err;
}

static int compat_put_MFB_read_register_data(
	struct compat_MFB_REG_IO_STRUCT __user *data32,
	struct MFB_REG_IO_STRUCT __user *data)
{
	compat_uint_t count;
	/*compat_uptr_t uptr;*/
	int err = 0;
	/* Assume data pointer is unchanged. */
	/* err = get_user(compat_ptr(uptr), &data->pData); */
	/* err |= put_user(uptr, &data32->pData); */
	err |= get_user(count, &data->Count);
	err |= put_user(count, &data32->Count);
	return err;
}

static int compat_get_MFB_mss_enque_req_data(
	struct compat_MFB_MSSRequest __user *data32,
	struct MFB_MSSRequest __user *data)
{
	compat_uint_t count;
	compat_uptr_t uptr;
	int err = 0;

	err = get_user(uptr, &data32->m_pMssConfig);
	err |= put_user(compat_ptr(uptr), &data->m_pMssConfig);
	err |= get_user(count, &data32->m_ReqNum);
	err |= put_user(count, &data->m_ReqNum);
	return err;
}


static int compat_put_MFB_mss_enque_req_data(
	struct compat_MFB_MSSRequest __user *data32,
	struct MFB_MSSRequest __user *data)
{
	compat_uint_t count;
	/*compat_uptr_t uptr;*/
	int err = 0;
	/* Assume data pointer is unchanged. */
	/* err = get_user(compat_ptr(uptr), &data->m_pMssConfig); */
	/* err |= put_user(uptr, &data32->m_pMssConfig); */
	err |= get_user(count, &data->m_ReqNum);
	err |= put_user(count, &data32->m_ReqNum);
	return err;
}


static int compat_get_MFB_mss_deque_req_data(
	struct compat_MFB_MSSRequest __user *data32,
	struct MFB_MSSRequest __user *data)
{
	compat_uint_t count;
	compat_uptr_t uptr;
	int err = 0;

	err = get_user(uptr, &data32->m_pMssConfig);
	err |= put_user(compat_ptr(uptr), &data->m_pMssConfig);
	err |= get_user(count, &data32->m_ReqNum);
	err |= put_user(count, &data->m_ReqNum);
	return err;
}


static int compat_put_MFB_mss_deque_req_data(
	struct compat_MFB_MSSRequest __user *data32,
	struct MFB_MSSRequest __user *data)
{
	compat_uint_t count;
	/*compat_uptr_t uptr;*/
	int err = 0;
	/* Assume data pointer is unchanged. */
	/* err = get_user(compat_ptr(uptr), &data->m_pMssConfig); */
	/* err |= put_user(uptr, &data32->m_pMssConfig); */
	err |= get_user(count, &data->m_ReqNum);
	err |= put_user(count, &data32->m_ReqNum);
	return err;
}

static int compat_get_MFB_msf_enque_req_data(
	struct compat_MFB_MSFRequest __user *data32,
	struct MFB_MSFRequest __user *data)
{
	compat_uint_t count;
	compat_uptr_t uptr;
	int err = 0;

	err = get_user(uptr, &data32->m_pMsfConfig);
	err |= put_user(compat_ptr(uptr), &data->m_pMsfConfig);
	err |= get_user(count, &data32->m_ReqNum);
	err |= put_user(count, &data->m_ReqNum);
	return err;
}


static int compat_put_MFB_msf_enque_req_data(
	struct compat_MFB_MSFRequest __user *data32,
	struct MFB_MSFRequest __user *data)
{
	compat_uint_t count;
	/*compat_uptr_t uptr;*/
	int err = 0;
	/* Assume data pointer is unchanged. */
	/* err = get_user(compat_ptr(uptr), &data->m_pMsfConfig); */
	/* err |= put_user(uptr, &data32->m_pMsfConfig); */
	err |= get_user(count, &data->m_ReqNum);
	err |= put_user(count, &data32->m_ReqNum);
	return err;
}


static int compat_get_MFB_msf_deque_req_data(
	struct compat_MFB_MSFRequest __user *data32,
	struct MFB_MSFRequest __user *data)
{
	compat_uint_t count;
	compat_uptr_t uptr;
	int err = 0;

	err = get_user(uptr, &data32->m_pMsfConfig);
	err |= put_user(compat_ptr(uptr), &data->m_pMsfConfig);
	err |= get_user(count, &data32->m_ReqNum);
	err |= put_user(count, &data->m_ReqNum);
	return err;
}


static int compat_put_MFB_msf_deque_req_data(
	struct compat_MFB_MSFRequest __user *data32,
	struct MFB_MSFRequest __user *data)
{
	compat_uint_t count;
	/*compat_uptr_t uptr;*/
	int err = 0;
	/* Assume data pointer is unchanged. */
	/* err = get_user(compat_ptr(uptr), &data->m_pMsfConfig); */
	/* err |= put_user(uptr, &data32->m_pMsfConfig); */
	err |= get_user(count, &data->m_ReqNum);
	err |= put_user(count, &data32->m_ReqNum);
	return err;
}

static long MFB_ioctl_compat(struct file *filp,
	unsigned int cmd, unsigned long arg)
{
	long ret;


	if (!filp->f_op || !filp->f_op->unlocked_ioctl) {
		LOG_ERR("no f_op !!!\n");
		return -ENOTTY;
	}
	switch (cmd) {
	case COMPAT_MFB_MSS_READ_REGISTER:
		{
			struct compat_MFB_REG_IO_STRUCT __user *data32;
			struct MFB_REG_IO_STRUCT __user *data;
			int err;

			data32 = compat_ptr(arg);
			data = compat_alloc_user_space(sizeof(*data));
			if (data == NULL)
				return -EFAULT;

			err = compat_get_MFB_read_register_data(data32, data);
			if (err) {
				LOG_INF(
					"compat_get_MFB_MSS_read_register_data error!!!\n");
				return err;
			}
			ret =
			    filp->f_op->unlocked_ioctl(filp,
				MFB_MSS_READ_REGISTER, (unsigned long)data);
			err = compat_put_MFB_read_register_data(data32, data);
			if (err) {
				LOG_INF(
					"compat_put_MFB_MSS_read_register_data error!!!\n");
				return err;
			}
			return ret;
		}
	case COMPAT_MFB_MSF_READ_REGISTER:
		{
			struct compat_MFB_REG_IO_STRUCT __user *data32;
			struct MFB_REG_IO_STRUCT __user *data;
			int err;

			data32 = compat_ptr(arg);
			data = compat_alloc_user_space(sizeof(*data));
			if (data == NULL)
				return -EFAULT;

			err = compat_get_MFB_read_register_data(data32, data);
			if (err) {
				LOG_INF(
					"compat_get_MFB_read_register_data error!!!\n");
				return err;
			}
			ret =
			    filp->f_op->unlocked_ioctl(filp,
				MFB_MSF_READ_REGISTER, (unsigned long)data);
			err = compat_put_MFB_read_register_data(data32, data);
			if (err) {
				LOG_INF(
					"compat_put_MFB_read_register_data error!!!\n");
				return err;
			}
			return ret;
		}
	case COMPAT_MFB_MSS_WRITE_REGISTER:
		{
			struct compat_MFB_REG_IO_STRUCT __user *data32;
			struct MFB_REG_IO_STRUCT __user *data;
			int err;

			data32 = compat_ptr(arg);
			data = compat_alloc_user_space(sizeof(*data));
			if (data == NULL)
				return -EFAULT;

			err = compat_get_MFB_read_register_data(data32, data);
			if (err) {
				LOG_INF(
				"COMPAT_MFB_MSS_WRITE_REGISTER error!!!\n");
				return err;
			}
			ret =
			    filp->f_op->unlocked_ioctl(filp,
				MFB_MSS_WRITE_REGISTER, (unsigned long)data);
			return ret;
		}
	case COMPAT_MFB_MSF_WRITE_REGISTER:
		{
			struct compat_MFB_REG_IO_STRUCT __user *data32;
			struct MFB_REG_IO_STRUCT __user *data;
			int err;

			data32 = compat_ptr(arg);
			data = compat_alloc_user_space(sizeof(*data));
			if (data == NULL)
				return -EFAULT;

			err = compat_get_MFB_read_register_data(data32, data);
			if (err) {
				LOG_INF(
				"COMPAT_MFB_MSF_WRITE_REGISTER error!!!\n");
				return err;
			}
			ret =
			    filp->f_op->unlocked_ioctl(filp,
				MFB_MSF_WRITE_REGISTER, (unsigned long)data);
			return ret;
		}
	case COMPAT_MFB_MSS_ENQUE_REQ:
		{
			struct compat_MFB_MSSRequest __user *data32;
			struct MFB_MSSRequest __user *data;
			int err;

			data32 = compat_ptr(arg);
			data = compat_alloc_user_space(sizeof(*data));
			if (data == NULL)
				return -EFAULT;

			err = compat_get_MFB_mss_enque_req_data(data32, data);
			if (err) {
				LOG_INF("COMPAT_MFB_MSS_ENQUE_REQ error!!!\n");
				return err;
			}
			ret =
			    filp->f_op->unlocked_ioctl(filp, MFB_MSS_ENQUE_REQ,
						       (unsigned long)data);
			err = compat_put_MFB_mss_enque_req_data(data32, data);
			if (err) {
				LOG_INF("COMPAT_MFB_MSS_ENQUE_REQ error!!!\n");
				return err;
			}
			return ret;
		}
	case COMPAT_MFB_MSS_DEQUE_REQ:
		{
			struct compat_MFB_MSSRequest __user *data32;
			struct MFB_MSSRequest __user *data;
			int err;

			data32 = compat_ptr(arg);
			data = compat_alloc_user_space(sizeof(*data));
			if (data == NULL)
				return -EFAULT;

			err = compat_get_MFB_mss_deque_req_data(data32, data);
			if (err) {
				LOG_INF("COMPAT_MFB_MSS_DEQUE_REQ error!!!\n");
				return err;
			}
			ret =
			    filp->f_op->unlocked_ioctl(filp, MFB_MSS_DEQUE_REQ,
						       (unsigned long)data);
			err = compat_put_MFB_mss_deque_req_data(data32, data);
			if (err) {
				LOG_INF("COMPAT_MFB_MSS_DEQUE_REQ error!!!\n");
				return err;
			}
			return ret;
		}

	case COMPAT_MFB_MSF_ENQUE_REQ:
		{
			struct compat_MFB_MSFRequest __user *data32;
			struct MFB_MSFRequest __user *data;
			int err;

			data32 = compat_ptr(arg);
			data = compat_alloc_user_space(sizeof(*data));
			if (data == NULL)
				return -EFAULT;

			err = compat_get_MFB_msf_enque_req_data(data32, data);
			if (err) {
				LOG_INF("COMPAT_MFB_MSF_ENQUE_REQ error!!!\n");
				return err;
			}
			ret =
			    filp->f_op->unlocked_ioctl(filp, MFB_MSF_ENQUE_REQ,
						       (unsigned long)data);
			err = compat_put_MFB_msf_enque_req_data(data32, data);
			if (err) {
				LOG_INF("COMPAT_MFB_MSF_ENQUE_REQ error!!!\n");
				return err;
			}
			return ret;
		}
	case COMPAT_MFB_MSF_DEQUE_REQ:
		{
			struct compat_MFB_MSFRequest __user *data32;
			struct MFB_MSFRequest __user *data;
			int err;

			data32 = compat_ptr(arg);
			data = compat_alloc_user_space(sizeof(*data));
			if (data == NULL)
				return -EFAULT;

			err = compat_get_MFB_msf_deque_req_data(data32, data);
			if (err) {
				LOG_INF("COMPAT_MFB_MSF_DEQUE_REQ error!!!\n");
				return err;
			}
			ret =
			    filp->f_op->unlocked_ioctl(filp, MFB_MSF_DEQUE_REQ,
						       (unsigned long)data);
			err = compat_put_MFB_msf_deque_req_data(data32, data);
			if (err) {
				LOG_INF("COMPAT_MFB_MSF_DEQUE_REQ error!!!\n");
				return err;
			}
			return ret;
		}

	case MFB_MSS_WAIT_IRQ:
	case MFB_MSF_WAIT_IRQ:
	case MFB_MSS_CLEAR_IRQ:	/* structure (no pointer) */
	case MFB_MSF_CLEAR_IRQ:	/* structure (no pointer) */
	case MFB_MSS_RESET:
	case MFB_MSF_RESET:
	case MFB_MSS_DUMP_REG:
	case MFB_MSF_DUMP_REG:
	case MFB_MSS_DUMP_ISR_LOG:
	case MFB_MSF_DUMP_ISR_LOG:
		return filp->f_op->unlocked_ioctl(filp, cmd, arg);
	default:
		return -ENOIOCTLCMD;
		/* return MFB_ioctl(filep, cmd, arg); */
	}
}

#endif

/******************************************************************************
 *
 ******************************************************************************/
static signed int MFB_open(struct inode *pInode, struct file *pFile)
{
	signed int Ret = 0, i = 0;
	/*int q = 0, p = 0;*/
	struct MFB_USER_INFO_STRUCT *pUserInfo = NULL;
	unsigned long flags;

	LOG_DBG("- E. UserCount: %d.", MFBInfo.UserCount);


	mutex_lock(&(MutexMFBRef));

	pFile->private_data = NULL;
	pFile->private_data =
		kmalloc(sizeof(struct MFB_USER_INFO_STRUCT), GFP_ATOMIC);
	if (pFile->private_data == NULL) {
		LOG_DBG(
			"ERROR: kmalloc failed, (process, pid, tgid)=(%s, %d, %d)",
			current->comm,
			current->pid,
			current->tgid);
		Ret = -ENOMEM;
		mutex_unlock(&(MutexMFBRef));
		goto EXIT;
	} else {
		pUserInfo = (struct MFB_USER_INFO_STRUCT *) pFile->private_data;
		pUserInfo->Tid = current->tgid;
		pUserInfo->streamtag = MFB_PROCESS_ID_NONE;
	}
	if (MFBInfo.UserCount > 0) {
		MFBInfo.UserCount++;
		for (i = 0;  i < IRQ_USER_NUM_MAX; i++) {
			if (MFBInfo.IrqInfo.MssIrqUse[i] == -1)
				break;
		}
		if (i == IRQ_USER_NUM_MAX) {
			mutex_unlock(&(MutexMFBRef));
			LOG_DBG("ERROR: MssIrqUse is full (%d)", i);
			goto EXIT;
		}
		MFBInfo.IrqInfo.MssIrqUse[i] = 1;
		pUserInfo->Pid = i;
		mutex_unlock(&(MutexMFBRef));
		LOG_DBG(
			"Curr UserCount(%d), (process, pid, tgid)=(%s, %d, %d), users exist",
			MFBInfo.UserCount, current->comm,
			current->pid, current->tgid);
		goto EXIT;
	} else {
		MFBInfo.UserCount++;

		for (i = 0; i < IRQ_USER_NUM_MAX; i++) {
			MFBInfo.IrqInfo.MssIrqCnt[i] = 0;
			MFBInfo.IrqInfo.MsfIrqCnt[i] = 0;
			MFBInfo.IrqInfo.MssIrqUse[i] = -1;
		}
		MFBInfo.IrqInfo.MssIrqUse[0] = 1;
		pUserInfo->Pid = 0;
		//gki
		for (i = 0; i < GKI_BUF_NUM_MAX; i++)
			pUserInfo->gkiBuf[i].isUse = 0;
		qq_get_cnt = 0;
		qq_put_cnt = 0;

		mfb_register_requests(&mss_reqs, sizeof(struct MFB_MSSConfig));
		mfb_set_engine_ops(&mss_reqs, &mss_ops);
		mfb_register_requests(&vmss_reqs, sizeof(struct MFB_MSSConfig));
		mfb_set_engine_ops(&vmss_reqs, &vmss_ops);

		mfb_register_requests(&msf_reqs, sizeof(struct MFB_MSFConfig));
		mfb_set_engine_ops(&msf_reqs, &msf_ops);
		mfb_register_requests(&vmsf_reqs, sizeof(struct MFB_MSFConfig));
		mfb_set_engine_ops(&vmsf_reqs, &vmsf_ops);

#ifdef MFB_PMQOS
		qos_total = 0;
		for (i = 0; i < 4; i++)
			qos_scen[i] = 0;
#endif
		mutex_unlock(&(MutexMFBRef));
		LOG_INF(
			"%s + 1st UserCount(%d), (process, pid, tgid)=(%s, %d, %d)",
			__func__, MFBInfo.UserCount, current->comm,
			current->pid, current->tgid);
	}

	/* Enable clock */
	MFB_EnableClock(MTRUE);
	g_SuspendCnt = 0;
	LOG_INF("MFB open g_u4EnableClockCount: %d", g_u4EnableClockCount);

	spin_lock_irqsave(
		&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]), flags);
		MFBInfo.IrqInfo.Status[MFB_IRQ_TYPE_INT_MSS_ST] = 0;
	spin_unlock_irqrestore(
		&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]), flags);

	spin_lock_irqsave(
		&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]), flags);
		MFBInfo.IrqInfo.Status[MFB_IRQ_TYPE_INT_MSF_ST] = 0;
	spin_unlock_irqrestore(
		&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]), flags);

#ifdef KERNEL_LOG
    /* In EP, Add MFB_DBG_WRITE_REG for debug. Should remove it after EP */
	MFBInfo.DebugMaskMss =
		(MFB_DBG_INT | MFB_DBG_DBGLOG | MFB_DBG_WRITE_REG);
	MFBInfo.DebugMaskMsf =
		(MFB_DBG_INT | MFB_DBG_DBGLOG | MFB_DBG_WRITE_REG);
#endif

EXIT:
	LOG_DBG("- X. Ret: %d. UserCount: %d.", Ret, MFBInfo.UserCount);
	return Ret;

}

/******************************************************************************
 *
 ******************************************************************************/
static signed int MFB_release(struct inode *pInode, struct file *pFile)
{
	struct MFB_USER_INFO_STRUCT *pUserInfo = NULL;
	/*unsigned int Reg;*/

	LOG_DBG("- E. UserCount: %d.", MFBInfo.UserCount);

	if (pFile->private_data != NULL)
		pUserInfo = (struct MFB_USER_INFO_STRUCT *) pFile->private_data;
	else
		goto EXIT;

	mutex_lock(&(MutexMFBRef));
	MFBInfo.UserCount--;
	MFBInfo.IrqInfo.MssIrqUse[pUserInfo->Pid] = -1;

	if (MFBInfo.UserCount > 0) {
		mutex_unlock(&(MutexMFBRef));
		LOG_DBG(
			"Curr UserCount(%d), (process, pid, tgid)=(%s, %d, %d), users exist",
			MFBInfo.UserCount, current->comm,
			current->pid, current->tgid);

		if (pFile->private_data != NULL) {
			kfree(pFile->private_data);
			pFile->private_data = NULL;
		}
		goto EXIT;
	} else {
		mfb_unregister_requests(&mss_reqs);
		mfb_unregister_requests(&msf_reqs);
		mfb_unregister_requests(&vmss_reqs);
		mfb_unregister_requests(&vmsf_reqs);

		mutex_unlock(&(MutexMFBRef));
		LOG_INF(
			"%s - last UserCount(%d), (process, pid, tgid)=(%s, %d, %d)",
			__func__, MFBInfo.UserCount, current->comm,
			current->pid, current->tgid);

		if (pFile->private_data != NULL) {
			kfree(pFile->private_data);
			pFile->private_data = NULL;
		}
	}

	/* Disable clock. */
	MFB_EnableClock(MFALSE);
	LOG_DBG("MFB release g_u4EnableClockCount: %d", g_u4EnableClockCount);

EXIT:

	LOG_DBG("- X. UserCount: %d.", MFBInfo.UserCount);
	return 0;
}

/******************************************************************************
 *
 ******************************************************************************/

static dev_t MFBDevNo;
static struct cdev *pMFBCharDrv;
static struct class *pMFBClass;

static const struct file_operations MFBFileOper = {
	.owner = THIS_MODULE,
	.open = MFB_open,
	.release = MFB_release,
	/* .flush   = mt_MFB_flush, */
	/* .mmap = MFB_mmap, */
	.unlocked_ioctl = MFB_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = MFB_ioctl_compat,
#endif
};

/******************************************************************************
 *
 ******************************************************************************/
static inline void MFB_UnregCharDev(void)
{
	LOG_DBG("- E.");
	/* Release char driver */
	if (pMFBCharDrv != NULL) {
		cdev_del(pMFBCharDrv);
		pMFBCharDrv = NULL;
	}
	unregister_chrdev_region(MFBDevNo, 1);
}

/******************************************************************************
 *
 ******************************************************************************/
static inline signed int MFB_RegCharDev(void)
{
	signed int Ret = 0;

	LOG_DBG("- E.");
	Ret = alloc_chrdev_region(&MFBDevNo, 0, 1, MFB_DEV_NAME);
	if (Ret < 0) {
		LOG_ERR("alloc_chrdev_region failed, %d", Ret);
		return Ret;
	}
	/* Allocate driver */
	pMFBCharDrv = cdev_alloc();
	if (pMFBCharDrv == NULL) {
		LOG_ERR("cdev_alloc failed");
		Ret = -ENOMEM;
		goto EXIT;
	}
	/* Attatch file operation. */
	cdev_init(pMFBCharDrv, &MFBFileOper);
	pMFBCharDrv->owner = THIS_MODULE;
	/* Add to system */
	Ret = cdev_add(pMFBCharDrv, MFBDevNo, 1);
	if (Ret < 0) {
		LOG_ERR("Attatch file operation failed, %d", Ret);
		goto EXIT;
	}
EXIT:
	if (Ret < 0)
		MFB_UnregCharDev();

	LOG_DBG("- X.");
	return Ret;
}

/******************************************************************************
 *
 ******************************************************************************/
static signed int MFB_probe(struct platform_device *pDev)
{
	signed int Ret = 0;
	/*struct resource *pRes = NULL;*/
	signed int i = 0;
	unsigned char n;
	unsigned int irq_info[3];/* Record interrupts info from device tree */
	struct device *dev = NULL;
	struct MFB_device *_mfb_dev = NULL;
	struct device_node *node;
	struct platform_device *pdev;

#ifdef CONFIG_OF
	struct MFB_device *MFB_dev;
#endif

	LOG_INF("- E. MFB driver probe. nr_MFB_devs : %d.", nr_MFB_devs);

	/* Check platform_device parameters */
#ifdef CONFIG_OF

	if (pDev == NULL) {
		dev_dbg(&pDev->dev, "pDev is NULL");
		return -ENXIO;
	}

	nr_MFB_devs += 1;
	_mfb_dev = krealloc(MFB_devs,
		sizeof(struct MFB_device) * nr_MFB_devs, GFP_KERNEL);
	if (!_mfb_dev) {
		dev_dbg(&pDev->dev, "Unable to allocate MFB_devs\n");
		return -ENOMEM;
	}
	MFB_devs = _mfb_dev;

	MFB_dev = &(MFB_devs[nr_MFB_devs - 1]);
	MFB_dev->dev = &pDev->dev;

	/* iomap registers */
	MFB_dev->regs = of_iomap(pDev->dev.of_node, 0);
	/* gISPSYS_Reg[nr_MFB_devs - 1] = MFB_dev->regs; */

	if (!MFB_dev->regs) {
		dev_dbg(&pDev->dev,
			"Unable to ioremap registers, of_iomap fail, nr_MFB_devs=%d, devnode(%s).\n",
			nr_MFB_devs, pDev->dev.of_node->name);
		return -ENOMEM;
	}

#if defined(CONFIG_MTK_IOMMU_PGTABLE_EXT) && \
		(CONFIG_MTK_IOMMU_PGTABLE_EXT > 32)
			*(MFB_dev->dev->dma_mask) =
				(u64)DMA_BIT_MASK(CONFIG_MTK_IOMMU_PGTABLE_EXT);
			MFB_dev->dev->coherent_dma_mask =
				(u64)DMA_BIT_MASK(CONFIG_MTK_IOMMU_PGTABLE_EXT);
#endif
	LOG_INF("nr_MFB_devs=%d, devnode(%s), map_addr=0x%lx\n", nr_MFB_devs,
		pDev->dev.of_node->name, (unsigned long)MFB_dev->regs);

	/* get IRQ ID and request IRQ */
	MFB_dev->irq = irq_of_parse_and_map(pDev->dev.of_node, 0);

	if (MFB_dev->irq > 0) {
		/* Get IRQ Flag from device node */
		if (of_property_read_u32_array(
			pDev->dev.of_node, "interrupts",
			irq_info, ARRAY_SIZE(irq_info))) {
			dev_dbg(&pDev->dev, "get irq flags from DTS fail!!\n");
			return -ENODEV;
		}

		for (i = 0; i < MFB_IRQ_TYPE_AMOUNT; i++) {
			if (strcmp(pDev->dev.of_node->name,
				MFB_IRQ_CB_TBL[i].device_name) == 0) {
				Ret = request_irq(MFB_dev->irq,
				    (irq_handler_t) MFB_IRQ_CB_TBL[i].isr_fp,
				    irq_info[2],
				    (const char *)MFB_IRQ_CB_TBL[i].device_name,
				    NULL);

				if (Ret) {
					dev_dbg(&pDev->dev,
						"Unable to request IRQ, request_irq fail, nr_MFB_devs=%d, devnode(%s), irq=%d, ISR: %s\n",
						nr_MFB_devs,
						pDev->dev.of_node->name,
						MFB_dev->irq,
						MFB_IRQ_CB_TBL[i].device_name);
					return Ret;
				}

				LOG_INF(
					"nr_MFB_devs=%d, devnode(%s), irq=%d, ISR: %s\n",
					nr_MFB_devs, pDev->dev.of_node->name,
					MFB_dev->irq,
					MFB_IRQ_CB_TBL[i].device_name);
				break;
			}
		}

		if (i >= MFB_IRQ_TYPE_AMOUNT) {
			LOG_INF(
				"No corresponding ISR!!: nr_MFB_devs=%d, devnode(%s), irq=%d\n",
				nr_MFB_devs, pDev->dev.of_node->name,
				MFB_dev->irq);
		}


	} else {
		LOG_INF("No IRQ!!: nr_MFB_devs=%d, devnode(%s), irq=%d\n",
			nr_MFB_devs,
			pDev->dev.of_node->name, MFB_dev->irq);
	}
#ifdef CMDQ_COMMON
	/*cmdq*/
	MFB_cmdq_dev = &pDev->dev;
	if (nr_MFB_devs == 2) {
		mss_clt = cmdq_mbox_create(MFB_cmdq_dev, 0);
		LOG_INF("mss_clt: 0x%p\n", mss_clt);
		of_property_read_u16(MFB_cmdq_dev->of_node,
				"mss_frame_done", &mss_done_event_id);
		of_property_read_u16(MFB_cmdq_dev->of_node,
				"mss_token", &mss_token_id);

	}
	if (nr_MFB_devs == 1) {
		msf_clt = cmdq_mbox_create(MFB_cmdq_dev, 0);
		LOG_INF("msf_clt: 0x%p\n", msf_clt);
		of_property_read_u16(MFB_cmdq_dev->of_node,
				"msf_frame_done", &msf_done_event_id);
		of_property_read_u16(MFB_cmdq_dev->of_node,
				"msf_token", &msf_token_id);
	}
#endif
#endif

	/* Only register char driver in the 1st time */
	if (nr_MFB_devs == 1) {/*YWtodo*/

		/* Register char driver */
		Ret = MFB_RegCharDev();
		if (Ret) {
			dev_dbg(&pDev->dev, "register char failed");
			return Ret;
		}
#ifndef __MFB_EP_NO_CLKMGR__
#if !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK) /*CCF*/
		    /*CCF: Grab clock pointer (struct clk*) */
#ifdef CLK_COMMON
#if (MTK_MFB_REG_VERSION == 3)
		mfb_clk.CG_IMG2_LARB11 = devm_clk_get(&pDev->dev,
				"MFB_CG_IMG2_LARB11");
		mfb_clk.CG_IMG2_MSS = devm_clk_get(&pDev->dev,
				"MFB_CG_IMG2_MSS");
		mfb_clk.CG_IMG2_MFB = devm_clk_get(&pDev->dev,
				"MFB_CG_IMG2_MFB");
		mfb_clk.CG_IMG2_GALS = devm_clk_get(&pDev->dev,
				"MFB_CG_IMG2_GALS");
		mfb_clk.CG_IMG1_GALS = devm_clk_get(&pDev->dev,
				"MFB_CG_IMG1_GALS");

		if (IS_ERR(mfb_clk.CG_IMG2_LARB11)) {
			LOG_ERR("cannot get CG_IMG2_LARB11 clock\n");
			return PTR_ERR(mfb_clk.CG_IMG2_LARB11);
		}
		if (IS_ERR(mfb_clk.CG_IMG2_MSS)) {
			LOG_ERR("cannot get CG_IMG2_MSS clock\n");
			return PTR_ERR(mfb_clk.CG_IMG2_MSS);
		}
		if (IS_ERR(mfb_clk.CG_IMG2_MFB)) {
			LOG_ERR("cannot get CG_IMG2_MFB clock\n");
			return PTR_ERR(mfb_clk.CG_IMG2_MFB);
		}
		if (IS_ERR(mfb_clk.CG_IMG2_GALS)) {
			LOG_ERR("cannot get CG_IMG2_GALS clock\n");
			return PTR_ERR(mfb_clk.CG_IMG2_GALS);
		}
		if (IS_ERR(mfb_clk.CG_IMG1_GALS)) {
			LOG_ERR("cannot get CG_IMG1_GALS clock\n");
			return PTR_ERR(mfb_clk.CG_IMG1_GALS);
		}
#elif (MTK_MFB_REG_VERSION == 2)
		mfb_clk.CG_IMG2_LARB11 = devm_clk_get(&pDev->dev,
				"MFB_CG_IMG2_LARB11");
		mfb_clk.CG_IMG2_MSS = devm_clk_get(&pDev->dev,
				"MFB_CG_IMG2_MSS");
		mfb_clk.CG_IMG2_MFB = devm_clk_get(&pDev->dev,
				"MFB_CG_IMG2_MFB");
		mfb_clk.CG_IMG2_GALS = devm_clk_get(&pDev->dev,
				"MFB_CG_IMG2_GALS");

		if (IS_ERR(mfb_clk.CG_IMG2_LARB11)) {
			LOG_ERR("cannot get CG_IMG2_LARB11 clock\n");
			return PTR_ERR(mfb_clk.CG_IMG2_LARB11);
		}
		if (IS_ERR(mfb_clk.CG_IMG2_MSS)) {
			LOG_ERR("cannot get CG_IMG2_MSS clock\n");
			return PTR_ERR(mfb_clk.CG_IMG2_MSS);
		}
		if (IS_ERR(mfb_clk.CG_IMG2_MFB)) {
			LOG_ERR("cannot get CG_IMG2_MFB clock\n");
			return PTR_ERR(mfb_clk.CG_IMG2_MFB);
		}
		if (IS_ERR(mfb_clk.CG_IMG2_GALS)) {
			LOG_ERR("cannot get CG_IMG2_GALS clock\n");
			return PTR_ERR(mfb_clk.CG_IMG2_GALS);
		}
#else
		mfb_clk.CG_IMG1_LARB9 = devm_clk_get(&pDev->dev,
				"MFB_CG_IMG1_LARB9");
		mfb_clk.CG_IMG1_MSS = devm_clk_get(&pDev->dev,
				"MFB_CG_IMG1_MSS");
		mfb_clk.CG_IMG1_MFB = devm_clk_get(&pDev->dev,
				"MFB_CG_IMG1_MFB");

		if (IS_ERR(mfb_clk.CG_IMG1_LARB9)) {
			LOG_ERR("cannot get CG_IMG1_LARB9 clock\n");
			return PTR_ERR(mfb_clk.CG_IMG1_LARB9);
		}
		if (IS_ERR(mfb_clk.CG_IMG1_MSS)) {
			LOG_ERR("cannot get CG_IMG1_MSS clock\n");
			return PTR_ERR(mfb_clk.CG_IMG1_MSS);
		}
		if (IS_ERR(mfb_clk.CG_IMG1_MFB)) {
			LOG_ERR("cannot get CG_IMG1_MFB clock\n");
			return PTR_ERR(mfb_clk.CG_IMG1_MFB);
		}
#endif
#endif
#endif	/* !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK)  */
#endif
		/*gki iommu*/
		dma_set_mask_and_coherent(MFB_dev->dev, DMA_BIT_MASK(34));
		/*gki pm*/
		pm_runtime_enable(MFB_dev->dev);
		if (!pm_runtime_enabled(MFB_dev->dev))
			goto EXIT;
		/*gki smi larb*/
		node = of_parse_phandle(MFB_dev->dev->of_node, "mediatek,larb", 0);
		if (!node)
			return -EINVAL;
		pdev = of_find_device_by_node(node);
		if (WARN_ON(!pdev)) {
			of_node_put(node);
			return -EINVAL;
		}
		of_node_put(node);
		MFB_dev->larb = &pdev->dev;

		/* Create class register */
		pMFBClass = class_create(THIS_MODULE, "MFBdrv");
		if (IS_ERR(pMFBClass)) {
			Ret = PTR_ERR(pMFBClass);
			LOG_ERR("Unable to create class, err = %d", Ret);
			goto EXIT;
		}

		dev = device_create(
			pMFBClass, NULL, MFBDevNo, NULL, MFB_DEV_NAME);

		if (IS_ERR(dev)) {
			Ret = PTR_ERR(dev);
			dev_dbg(&pDev->dev, "Failed to create device: /dev/%s, err = %d",
				MFB_DEV_NAME, Ret);
			goto EXIT;
		}

		/* Init spinlocks */
		spin_lock_init(&(MFBInfo.SpinLockMFB));
		for (n = 0; n < MFB_IRQ_TYPE_AMOUNT; n++)
			spin_lock_init(&(MFBInfo.SpinLockIrq[n]));
#ifdef MFB_PMQOS
		spin_lock_init(&(SpinLockMfbPmqos));
#endif
		init_waitqueue_head(&MFBInfo.WaitQueueHeadMss);
		init_waitqueue_head(&MFBInfo.WaitQueueHeadMsf);
		INIT_WORK(&MFBInfo.ScheduleMssWork, MFB_ScheduleMssWork);
		INIT_WORK(&MFBInfo.vmsswork, vmss_do_work);
		INIT_WORK(&MFBInfo.ScheduleMsfWork, MFB_ScheduleMsfWork);
		INIT_WORK(&MFBInfo.vmsfwork, vmsf_do_work);

		MFBInfo.wkqueueMss =
			create_singlethread_workqueue("MSS-CMDQ-WQ");
		if (!MFBInfo.wkqueueMss)
			LOG_ERR("NULL MSS-CMDQ-WQ\n");
		MFBInfo.wkqueueMsf =
			create_singlethread_workqueue("MSF-CMDQ-WQ");
		if (!MFBInfo.wkqueueMsf)
			LOG_ERR("NULL MSF-CMDQ-WQ\n");
#ifdef WAKE_UP
		wakeup_source_init(&MSS_wake_lock, "mss_lock_wakelock");
		wakeup_source_init(&MSF_wake_lock, "msf_lock_wakelock");
#endif
		INIT_WORK(&logWork, logPrint);

		for (i = 0; i < MFB_IRQ_TYPE_AMOUNT; i++)
			tasklet_init(
				MFB_tasklet[i].pMFB_tkt,
				MFB_tasklet[i].tkt_cb, 0);

		/* Init MFBInfo */
		mutex_lock(&(MutexMFBRef));
		MFBInfo.UserCount = 0;
		mutex_unlock(&(MutexMFBRef));
		MFBInfo.IrqInfo.Mask[MFB_IRQ_TYPE_INT_MSS_ST] = INT_ST_MASK_MSS;
		MFBInfo.IrqInfo.Mask[MFB_IRQ_TYPE_INT_MSF_ST] = INT_ST_MASK_MSF;
	}

	seqlock_init(&(mss_reqs.seqlock));
	seqlock_init(&(vmss_reqs.seqlock));
	seqlock_init(&(msf_reqs.seqlock));
	seqlock_init(&(vmsf_reqs.seqlock));

EXIT:
	if (Ret < 0)
		MFB_UnregCharDev();


	LOG_INF("- X. MFB driver probe.");

	return Ret;
}

/******************************************************************************
 * Called when the device is being detached from the driver
 ******************************************************************************/
static signed int MFB_remove(struct platform_device *pDev)
{
	/*struct resource *pRes;*/
	signed int IrqNum;
	int i;

	LOG_DBG("- E.");

	destroy_workqueue(MFBInfo.wkqueueMss);
	MFBInfo.wkqueueMss = NULL;
	destroy_workqueue(MFBInfo.wkqueueMsf);
	MFBInfo.wkqueueMsf = NULL;

	/* unregister char driver. */
	MFB_UnregCharDev();

	/* Release IRQ */
	/*disable_irq(MFBInfo.IrqNum);*//*YWtoclr*/
	IrqNum = platform_get_irq(pDev, 0);
	free_irq(IrqNum, NULL);

	/* kill tasklet */
	for (i = 0; i < MFB_IRQ_TYPE_AMOUNT; i++)
		tasklet_kill(MFB_tasklet[i].pMFB_tkt);
#if CHECK_SERVICE_IF_0
	/* free all registered irq(child nodes) */
	MFB_UnRegister_AllregIrq();
	/* free father nodes of irq user list */
	struct my_list_head *head;
	struct my_list_head *father;

	head = ((struct my_list_head *)(&SupIrqUserListHead.list));
	while (1) {
		father = head;
		if (father->nextirq != father) {
			father = father->nextirq;
			REG_IRQ_NODE *accessNode;

			typeof(((REG_IRQ_NODE *) 0)->list) * __mptr = (father);
			accessNode =
			    ((REG_IRQ_NODE *) (
			    (char *)__mptr -
			    offsetof(REG_IRQ_NODE, list)));
			LOG_INF("free father,reg_T(%d)\n", accessNode->reg_T);
			if (father->nextirq != father) {
				head->nextirq = father->nextirq;
				father->nextirq = father;
			} else {	/* last father node */
				head->nextirq = head;
				LOG_INF("break\n");
				break;
			}
			kfree(accessNode);
		}
	}
#endif
	device_destroy(pMFBClass, MFBDevNo);
	class_destroy(pMFBClass);
	pMFBClass = NULL;
	return 0;
}

/******************************************************************************
 *
 ******************************************************************************/
static signed int bPass1_On_In_Resume_TG1;/*YWtodo*/

static signed int MFB_suspend(struct platform_device *pDev, pm_message_t Mesg)
{
	/*signed int ret = 0;*/

	if (g_u4EnableClockCount > 0) {
		MFB_EnableClock(MFALSE);
		g_SuspendCnt++;
	}
	bPass1_On_In_Resume_TG1 = 0;
	LOG_DBG("%s:g_u4EnableClockCount(%d) g_SuspendCnt(%d).\n", __func__,
				g_u4EnableClockCount, g_SuspendCnt);


	return 0;
}

/******************************************************************************
 *
 ******************************************************************************/
static signed int MFB_resume(struct platform_device *pDev)
{
	LOG_DBG("bPass1_On_In_Resume_TG1(%d).\n", bPass1_On_In_Resume_TG1);
	if (g_SuspendCnt > 0) {
		MFB_EnableClock(MTRUE);
		g_SuspendCnt--;
	}
	LOG_DBG("%s:g_u4EnableClockCount(%d) g_SuspendCnt(%d).\n", __func__,
				g_u4EnableClockCount, g_SuspendCnt);

	return 0;
}


/*---------------------------------------------------------------------------*/
#ifdef CONFIG_PM
/*---------------------------------------------------------------------------*/
int MFB_pm_suspend(struct device *device)
{
	struct platform_device *pdev = to_platform_device(device);

	WARN_ON(pdev == NULL);

	LOG_DBG("calling %s()\n", __func__);

	return MFB_suspend(pdev, PMSG_SUSPEND);
}

int MFB_pm_resume(struct device *device)
{
	struct platform_device *pdev = to_platform_device(device);

	WARN_ON(pdev == NULL);

	LOG_DBG("calling %s()\n", __func__);

	return MFB_resume(pdev);
}
#ifndef CONFIG_OF
/* extern void mt_irq_set_sens(unsigned int irq, unsigned int sens); */
/* extern void mt_irq_set_polarity(unsigned int irq, unsigned int polarity); */
#endif
int MFB_pm_restore_noirq(struct device *device)
{
	pr_debug("calling %s()\n", __func__);
#ifndef CONFIG_OF
	mt_irq_set_sens(MFB_IRQ_BIT_ID, MT_LEVEL_SENSITIVE);
	mt_irq_set_polarity(MFB_IRQ_BIT_ID, MT_POLARITY_LOW);
#endif
	return 0;

}

/*---------------------------------------------------------------------------*/
#else				/*CONFIG_PM */
/*---------------------------------------------------------------------------*/
#define MFB_pm_suspend NULL
#define MFB_pm_resume  NULL
#define MFB_pm_restore_noirq NULL
/*---------------------------------------------------------------------------*/
#endif				/*CONFIG_PM */
/*---------------------------------------------------------------------------*/
#ifdef CONFIG_OF
/*
 * Note!!! The order and member of .compatible must be the same with that in
 *  "MFB_DEV_NODE_ENUM" in camera_MFB.h
 */
#if (MTK_MFB_REG_VERSION >= 2)
static const struct of_device_id MFB_of_ids[] = {
	{.compatible = "mediatek,msf_b",},
	{.compatible = "mediatek,mss_b",},
	{.compatible = "mediatek,imgsys_mfb_b",},
	{}
};
#else
static const struct of_device_id MFB_of_ids[] = {
	{.compatible = "mediatek,msf",},
	{.compatible = "mediatek,mss",},
	{.compatible = "mediatek,imgsys_mfb",},
	{}
};
#endif
#endif

const struct dev_pm_ops MFB_pm_ops = {
	.suspend = MFB_pm_suspend,
	.resume = MFB_pm_resume,
	.freeze = MFB_pm_suspend,
	.thaw = MFB_pm_resume,
	/*.pmfbroff = MFB_pm_suspend,*//*YWtodo*/
	.restore = MFB_pm_resume,
	.restore_noirq = MFB_pm_restore_noirq,
};


/******************************************************************************
 *
 ******************************************************************************/
static struct platform_driver MFBDriver = {
	.probe = MFB_probe,
	.remove = MFB_remove,
	.suspend = MFB_suspend,
	.resume = MFB_resume,
	.driver = {
		   .name = MFB_DEV_NAME,
		   .owner = THIS_MODULE,
#ifdef CONFIG_OF
		   .of_match_table = MFB_of_ids,
#endif
#ifdef CONFIG_PM
		   .pm = &MFB_pm_ops,
#endif
	}
};

/******************************************************************************
 *
 ******************************************************************************/

int32_t MFB_ClockOnCallback(uint64_t engineFlag)
{
	/* LOG_DBG("MFB_ClockOnCallback"); */
	/* LOG_DBG("+CmdqEn:%d", g_u4EnableClockCount); */
	/* MFB_EnableClock(MTRUE); */

	return 0;
}

int32_t MFB_DumpCallback(uint64_t engineFlag, int level)
{
	LOG_DBG("MFB_DumpCallback");
	MSS_DumpReg();
	MSF_DumpReg();

	return 0;
}

int32_t MFB_ResetCallback(uint64_t engineFlag)
{
	LOG_DBG("MSS_ResetCallback");
	MSS_Reset();
	MSF_Reset();

	return 0;
}

int32_t MFB_ClockOffCallback(uint64_t engineFlag)
{
	/* LOG_DBG("MFB_ClockOffCallback"); */
	/* MFB_EnableClock(MFALSE); */
	/* LOG_DBG("-CmdqEn:%d", g_u4EnableClockCount); */
	return 0;
}

static signed int __init MFB_Init(void)
{
	signed int Ret = 0, j;
	void *tmp;
	int i;

	LOG_DBG("- E.");
	Ret = platform_driver_register(&MFBDriver);
	if (Ret < 0) {
		LOG_ERR("platform_driver_register fail");
		return Ret;
	}

#if CHECK_SERVICE_IF_0
	struct device_node *node = NULL;

	node = of_find_compatible_node(NULL, NULL, "mediatek,MFB");
	if (!node) {
		LOG_ERR("find mediatek,MFB node failed!!!\n");
		return -ENODEV;
	}
	ISP_MFB_BASE = of_iomap(node, 0);
	if (!ISP_MFB_BASE) {
		LOG_ERR("unable to map ISP_MFB_BASE registers!!!\n");
		return -ENODEV;
	}
	LOG_DBG("ISP_MFB_BASE: %lx\n", ISP_MFB_BASE);
#endif

	/* isr log */
	if (PAGE_SIZE < ((MFB_IRQ_TYPE_AMOUNT * NORMAL_STR_LEN * ((
	    DBG_PAGE + INF_PAGE + ERR_PAGE) + 1)) * LOG_PPNUM)) {
		i = 0;
		while (i <
		       ((MFB_IRQ_TYPE_AMOUNT * NORMAL_STR_LEN *
			 ((DBG_PAGE + INF_PAGE + ERR_PAGE) + 1)) * LOG_PPNUM)) {
			i += PAGE_SIZE;
		}
	} else {
		i = PAGE_SIZE;
	}
	pLog_kmalloc = kmalloc(i, GFP_KERNEL);
	if (pLog_kmalloc == NULL) {
		LOG_ERR("log mem not enough\n");
		return -ENOMEM;
	}
	memset(pLog_kmalloc, 0x00, i);
	tmp = pLog_kmalloc;
	for (i = 0; i < LOG_PPNUM; i++) {
		for (j = 0; j < MFB_IRQ_TYPE_AMOUNT; j++) {
			gSvLog[j]._str[i][_LOG_DBG] = (char *)tmp;
			/* tmp = (void*) ((unsigned int)tmp + */
			/*	(NORMAL_STR_LEN*DBG_PAGE)); */
			tmp = (void *)((char *)tmp +
				(NORMAL_STR_LEN * DBG_PAGE));
			gSvLog[j]._str[i][_LOG_INF] = (char *)tmp;
			/* tmp = (void*) ((unsigned int)tmp + */
			/*	(NORMAL_STR_LEN*INF_PAGE)); */
			tmp = (void *)((char *)tmp +
				(NORMAL_STR_LEN * INF_PAGE));
			gSvLog[j]._str[i][_LOG_ERR] = (char *)tmp;
			/* tmp = (void*) ((unsigned int)tmp + */
			/*	(NORMAL_STR_LEN*ERR_PAGE)); */
			tmp = (void *)((char *)tmp +
				(NORMAL_STR_LEN * ERR_PAGE));
		}
		/* tmp = (void*) ((unsigned int)tmp + NORMAL_STR_LEN); */
		/* log buffer ,in case of overflow */
		tmp = (void *)((char *)tmp + NORMAL_STR_LEN);
		/* log buffer ,in case of overflow */
	}

	/* Cmdq */
	/* Register MFB callback */
	LOG_DBG("register mfb callback for CMDQ");
#if CHECK_SERVICE_IF_0/*YWtodo*/
	cmdqCoreRegisterCB(CMDQ_GROUP_MDP,
			   MFB_ClockOnCallback,
			   MFB_DumpCallback, MFB_ResetCallback,
			   MFB_ClockOffCallback);
#endif

#ifdef MFB_PMQOS
	MFBQOS_Init();
#endif
	LOG_DBG("- X. Ret: %d.", Ret);
	return Ret;
}

/******************************************************************************
 *
 ******************************************************************************/
static void __exit MFB_Exit(void)
{
	/*int i;*/

	LOG_DBG("- E.");

#ifdef MFB_PMQOS
	MFBQOS_Uninit();
#endif
	platform_driver_unregister(&MFBDriver);
	/* Cmdq */
	/* Unregister MFB callback */
	/*cmdqCoreRegisterCB(CMDQ_GROUP_MDP, NULL, NULL, NULL, NULL);YWtodo*/

	kfree(pLog_kmalloc);
}


/******************************************************************************
 *
 ******************************************************************************/
static void MFB_ScheduleMssWork(struct work_struct *data)
{
	if (MFB_DBG_DBGLOG & MFBInfo.DebugMaskMss)
		LOG_DBG("- E.");
	mfb_request_handler(&mss_reqs, &(MFBInfo.SpinLockIrq[
						MFB_IRQ_TYPE_INT_MSS_ST]));
	if (!mfb_request_running(&mss_reqs))
		LOG_DBG("[%s]no more requests", __func__);
}

static void vmss_do_work(struct work_struct *data)
{
	if (MFB_DBG_DBGLOG & MFBInfo.DebugMaskMss)
		LOG_DBG("- E.");
	mfb_request_handler(&vmss_reqs, &(MFBInfo.SpinLockIrq[
						MFB_IRQ_TYPE_INT_MSS_ST]));
	if (!mfb_request_running(&vmss_reqs))
		LOG_DBG("[%s]no more requests", __func__);
}

/******************************************************************************
 *
 ******************************************************************************/
static void MFB_ScheduleMsfWork(struct work_struct *data)
{
	if (MFB_DBG_DBGLOG & MFBInfo.DebugMaskMsf)
		LOG_DBG("- E.");
	mfb_request_handler(&msf_reqs,
		&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]));
	if (!mfb_request_running(&msf_reqs))
		LOG_DBG("[%s]no more requests", __func__);
}

static void vmsf_do_work(struct work_struct *data)
{
	if (MFB_DBG_DBGLOG & MFBInfo.DebugMaskMsf)
		LOG_DBG("- E.");
	mfb_request_handler(&vmsf_reqs, &(MFBInfo.SpinLockIrq[
						MFB_IRQ_TYPE_INT_MSF_ST]));
	if (!mfb_request_running(&vmsf_reqs))
		LOG_DBG("[%s]no more requests", __func__);
}


static irqreturn_t ISP_Irq_MSS(signed int Irq, void *DeviceId)
{
#if CHECK_SERVICE_IF_1
	/*unsigned int MssStatus;*/

	/*MssStatus = MFB_RD32(MFB_MSS_INT_STATUS_REG);*//* MSS Status */
	/*MFB_WR32(MFB_MSS_INT_STATUS_REG, MssStatus);*//* MSS Status */
	LOG_DBG("%s:0x%x = 0x%x ", __func__,
			MFB_MSS_INT_STATUS_HW, MssStatus);

#else
	unsigned int MssStatus;
	bool bResulst = MFALSE;
	pid_t ProcessID;

	MssStatus = MFB_RD32(MFB_MSS_INT_STATUS_REG);	/* MSS Status */
	MFB_WR32(MFB_MSS_INT_STATUS_REG, MssStatus);	/* MSS Status */

	spin_lock(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]));
	if (MSS_INT_ST == (MSS_INT_ST & MssStatus)) {
#ifdef __MFB_KERNEL_PERFORMANCE_MEASURE__
		mt_kernel_trace_begin("mfb_mss_irq");
#endif

		if (mfb_update_request(&mss_reqs, &ProcessID) == 0)
			bResulst = MTRUE;
		/* Config the Next frame */
		if (bResulst == MTRUE) {
			#if REQUEST_REGULATION == REQUEST_BASE_REGULATION
			/* schedule_work(&&MFBInfo.ScheduleMssWork); */
			queue_work(MFBInfo.wkqueue, &MFBInfo.ScheduleMssWork);
			#endif

			MFBInfo.IrqInfo
			    .Status[MFB_IRQ_TYPE_INT_MSS_ST] |= MSS_INT_ST;
			MFBInfo.IrqInfo
			    .ProcessID[MFB_PROCESS_ID_MSS] = ProcessID;
			MFBInfo.IrqInfo.MssIrqCnt++;
		}
#ifdef __MFB_KERNEL_PERFORMANCE_MEASURE__
		mt_kernel_trace_end();
#endif
	}
	spin_unlock(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSS_ST]));
	if (bResulst == MTRUE)
		wake_up_interruptible(&MFBInfo.WaitQueueHeadMss);

	/* dump log, use tasklet */
	IRQ_LOG_KEEPER(MFB_IRQ_TYPE_INT_MSS_ST, m_CurrentPPB, _LOG_INF,
		       "Irq_MSS:%d, reg 0x%x : 0x%x, bResulst:%d, MssIrqCnt:0x%x\n",
		       Irq, MFB_MSS_INT_STATUS_REG, MssStatus,
		       bResulst, MFBInfo.IrqInfo.MssIrqCnt);

	#if (REQUEST_REGULATION == FRAME_BASE_REGULATION)
	/* schedule_work(&MFBInfo.ScheduleMssWork); */
	if (MSS_INT_ST == (MSS_INT_ST & MssStatus))
		queue_work(MFBInfo.wkqueueMss, &MFBInfo.ScheduleMssWork);
	#endif

	if (MssStatus & MSS_INT_ST)
		tasklet_schedule(MFB_tasklet[MFB_IRQ_TYPE_INT_MSS_ST].pMFB_tkt);

#endif
	return IRQ_HANDLED;
}

static irqreturn_t ISP_Irq_MSF(signed int Irq, void *DeviceId)
{
#if CHECK_SERVICE_IF_1
	/*unsigned int MsfStatus;*/

	/*MsfStatus = MFB_RD32(MFB_MSF_INT_STATUS_REG);*//* MSF Status */
	/*MFB_WR32(MFB_MSF_INT_STATUS_REG, MsfStatus);*//* MSF Status */
	LOG_DBG("%s:0x%x = 0x%x ", __func__,
			MFB_MSF_INT_STATUS_HW, MsfStatus);
#else
	unsigned int MsfStatus;
	bool bResulst = MFALSE;
	pid_t ProcessID;

	MsfStatus = MFB_RD32(MFB_MSF_INT_STATUS_REG);	/* MSF Status */
	MFB_WR32(MFB_MSF_INT_STATUS_REG, MsfStatus);	/* MSF Status */

	spin_lock(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]));
	if (MSF_INT_ST == (MSF_INT_ST & MsfStatus)) {
#ifdef __MFB_KERNEL_PERFORMANCE_MEASURE__
		mt_kernel_trace_begin("mfb_msf_irq");
#endif

		if (mfb_update_request(&msf_reqs, &ProcessID) == 0)
			bResulst = MTRUE;
		/* Config the Next frame */
		if (bResulst == MTRUE) {
			#if REQUEST_REGULATION == REQUEST_BASE_REGULATION
			/* schedule_work(&&MFBInfo.ScheduleMsfWork); */
			queue_work(MFBInfo.wkqueue, &MFBInfo.ScheduleMsfWork);
			#endif

			MFBInfo.IrqInfo
			    .Status[MFB_IRQ_TYPE_INT_MSF_ST] |= MSF_INT_ST;
			MFBInfo.IrqInfo
			    .ProcessID[MFB_PROCESS_ID_MSF] = ProcessID;
			MFBInfo.IrqInfo.MsfIrqCnt++;
		}
#ifdef __MFB_KERNEL_PERFORMANCE_MEASURE__
		mt_kernel_trace_end();
#endif
	}
	spin_unlock(&(MFBInfo.SpinLockIrq[MFB_IRQ_TYPE_INT_MSF_ST]));
	if (bResulst == MTRUE)
		wake_up_interruptible(&MFBInfo.WaitQueueHeadMsf);

	/* dump log, use tasklet */
	IRQ_LOG_KEEPER(MFB_IRQ_TYPE_INT_MSF_ST, m_CurrentPPB, _LOG_INF,
		       "Irq_MSF:%d, reg 0x%x : 0x%x, bResulst:%d, MsfIrqCnt:0x%x\n",
		       Irq, MFB_MSF_INT_STATUS_REG, MsfStatus,
		       bResulst, MFBInfo.IrqInfo.MsfIrqCnt);

	#if (REQUEST_REGULATION == FRAME_BASE_REGULATION)
	/* schedule_work(&MFBInfo.ScheduleMsfWork); */
	if (MSF_INT_ST == (MSF_INT_ST & MsfStatus))
		queue_work(MFBInfo.wkqueueMsf, &MFBInfo.ScheduleMsfWork);
	#endif

	if (MsfStatus & MSF_INT_ST)
		tasklet_schedule(MFB_tasklet[MFB_IRQ_TYPE_INT_MSF_ST].pMFB_tkt);


#endif
	return IRQ_HANDLED;
}

static void ISP_TaskletFunc_MSS(unsigned long data)
{
	IRQ_LOG_PRINTER(MFB_IRQ_TYPE_INT_MSS_ST, m_CurrentPPB, _LOG_DBG);
	IRQ_LOG_PRINTER(MFB_IRQ_TYPE_INT_MSS_ST, m_CurrentPPB, _LOG_INF);
	IRQ_LOG_PRINTER(MFB_IRQ_TYPE_INT_MSS_ST, m_CurrentPPB, _LOG_ERR);

}

static void ISP_TaskletFunc_MSF(unsigned long data)
{
	IRQ_LOG_PRINTER(MFB_IRQ_TYPE_INT_MSF_ST, m_CurrentPPB, _LOG_DBG);
	IRQ_LOG_PRINTER(MFB_IRQ_TYPE_INT_MSF_ST, m_CurrentPPB, _LOG_INF);
	IRQ_LOG_PRINTER(MFB_IRQ_TYPE_INT_MSF_ST, m_CurrentPPB, _LOG_ERR);

}
static void logPrint(struct work_struct *data)
{
	unsigned long arg = 0;

	ISP_TaskletFunc_MSS(arg);
	ISP_TaskletFunc_MSF(arg);
}

/******************************************************************************
 *
 ******************************************************************************/
module_init(MFB_Init);
module_exit(MFB_Exit);
MODULE_DESCRIPTION("Camera MFB driver");
MODULE_AUTHOR("MM3SW5");
MODULE_LICENSE("GPL");
