// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015 MediaTek Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "camera_mfb.h" #include "engine_request.h" #include #include #include #include #if IS_ENABLED(CONFIG_MTK_CMDQ_MBOX_EXT) #include #endif #include #define TODO #ifndef TODO #define MFB_PMQOS #endif #ifdef MFB_PMQOS #include #include #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 #include #endif #include #include #include #ifdef CONFIG_COMPAT /* 64 bit */ #include #include #endif #ifdef MFB_USE_WAKELOCK #include #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 #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");