// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015 MediaTek Inc. */ /****************************************************************************** * camera_RSC.c - Linux RSC Device Driver * * DESCRIPTION: * This file provid the other drivers RSC relative functions * ******************************************************************************/ #include #include #include #include #include /* #include */ /* #include */ #include /* proc file use */ #include #include /* #include */ #include #include #include #include #include #include #include #include #include #include #include /*#include For xlog_printk(). */ /*#include */ /* #include */ #include "camera_rsc.h" /*#include */ /* #include */ /* #if defined(CONFIG_MTK_LEGACY) */ /* For clock mgr APIS. enable_clock()/disable_clock(). */ /* #include */ /* #endif */ #define CHECK_SERVICE_IF_0 0 #define CHECK_SERVICE_IF_1 1 #define NUM_BASEADDR 7 #if CHECK_SERVICE_IF_0 #include /* For mt65xx_reg_sync_writel(). */ #endif /* For spm_enable_sodi()/spm_disable_sodi(). */ /* #include */ #include #include #include #include #ifdef CONFIG_MTK_IOMMU_V2 #include #else /* CONFIG_MTK_IOMMU_V2 */ #if CHECK_SERVICE_IF_0 #include #endif #endif /* CONFIG_MTK_IOMMU_V2 */ #if CHECK_SERVICE_IF_0 #include "mach/pseudo_m4u.h" #include #endif #include "../engine_request.h" #define RSC_PMQOS_EN #if defined(RSC_PMQOS_EN) && defined(CONFIG_MTK_QOS_SUPPORT) #include #endif /* Measure the kernel performance * #define __RSC_KERNEL_PERFORMANCE_MEASURE__ */ #ifdef __RSC_KERNEL_PERFORMANCE_MEASURE__ #include #include #endif #if CHECK_SERVICE_IF_0 /* Another Performance Measure Usage */ #include #include static unsigned long __read_mostly tracing_mark_write_addr; #define _kernel_trace_begin(name) \ { \ tracing_mark_write_addr = \ kallsyms_lookup_name("tracing_mark_write"); \ event_trace_printk(tracing_mark_write_addr, "B|%d|%s\n", \ current->tgid, name); \ } #define _kernel_trace_end() \ { \ event_trace_printk(tracing_mark_write_addr, "E\n"); \ } /* How to Use */ /* char strName[128]; */ /* sprintf(strName, "TAG_K_WAKEUP (%d)",sof_count[_PASS1]); */ /* _kernel_trace_begin(strName); */ /* _kernel_trace_end(); */ #endif #include #include #include #ifdef CONFIG_COMPAT /* 64 bit */ #include #include #endif /* #include "smi_common.h" */ #undef CONFIG_COMPAT #include /* CCF */ #if !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK) /*CCF*/ #include struct RSC_CLK_STRUCT { /* TODO */ #define SMI_CLK #ifndef SMI_CLK struct clk *CG_SCP_SYS_MM0; struct clk *CG_SCP_SYS_ISP; struct clk *CG_MM_SMI_COMMON; struct clk *CG_MM_SMI_COMMON_2X; struct clk *CG_MM_SMI_COMMON_GALS_M0_2X; struct clk *CG_MM_SMI_COMMON_GALS_M1_2X; struct clk *CG_MM_SMI_COMMON_UPSZ0; struct clk *CG_MM_SMI_COMMON_UPSZ1; struct clk *CG_MM_SMI_COMMON_FIFO0; struct clk *CG_MM_SMI_COMMON_FIFO1; struct clk *CG_MM_LARB5; struct clk *CG_IPESYS_LARB; #endif struct clk *CG_IPESYS_LARB20; struct clk *CG_IPESYS_RSC; }; struct RSC_CLK_STRUCT rsc_clk; #endif /* !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK) */ #ifndef MTRUE #define MTRUE 1 #endif #ifndef MFALSE #define MFALSE 0 #endif #ifndef M4U_PORT_L20_IPE_RSC_RDMA0_DISP #define M4U_PORT_L20_IPE_RSC_RDMA0_DISP M4U_PORT_L20_IPE_RSC_RDMA0 #endif /* M4U_PORT_L20_IPE_RSC_RDMA0_DISP */ #ifndef M4U_PORT_L20_IPE_RSC_WDMA_DISP #define M4U_PORT_L20_IPE_RSC_WDMA_DISP M4U_PORT_L20_IPE_RSC_WDMA #endif /* M4U_PORT_L20_IPE_RSC_WDMA_DISP */ #define RSC_DEV_NAME "camera-rsc" /*#define EP_NO_CLKMGR*/ #define BYPASS_REG (0) /*#define RSC_DEBUG_USE*/ #define DUMMY_RSC (0) /*I can' test the situation in FPGA due to slow FPGA. */ #define MyTag "[RSC]" #define IRQTag "KEEPER" #define LOG_VRB(format, args...) pr_debug(MyTag format, ##args) #ifdef RSC_DEBUG_USE #define LOG_DBG(format, args...) pr_debug(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 RSC_WR32(addr, data) iowrite32(data, addr) // For other projects. */ #define RSC_WR32(addr, data) writel(data, addr) #define RSC_RD32(addr) readl(addr) //#define RSC_WR32(addr, data) mt_reg_sync_writel(data, addr) //#define RSC_RD32(addr) ioread32(addr) /******************************************************************************* * ******************************************************************************/ /* dynamic log level */ #define RSC_DBG_DBGLOG (0x00000001) #define RSC_DBG_INFLOG (0x00000002) #define RSC_DBG_INT (0x00000004) #define RSC_DBG_READ_REG (0x00000008) #define RSC_DBG_WRITE_REG (0x00000010) #define RSC_DBG_TASKLET (0x00000020) /* * CAM interrupt status */ /* normal siganl : happens to be the same bit as register bit*/ /*#define RSC_INT_ST (1<<0)*/ /* * IRQ signal mask */ #define INT_ST_MASK_RSC (RSC_INT_ST) #define CMDQ_REG_MASK 0xffffffff #define RSC_START 0x1 #define RSC_ENABLE 0x1 #ifdef CONFIG_MTK_IOMMU_V2 static int RSC_MEM_USE_VIRTUL = 1; #endif /* static irqreturn_t RSC_Irq_CAM_A(signed int Irq,void *DeviceId); */ static irqreturn_t ISP_Irq_RSC(signed int Irq, void *DeviceId); static void RSC_ScheduleWork(struct work_struct *data); 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 RSC_IRQ_CB_TBL[RSC_IRQ_TYPE_AMOUNT] = { {ISP_Irq_RSC, RSC_IRQ_BIT_ID, "rsc"}, }; #else /* int number is got from kernel api */ const struct ISR_TABLE RSC_IRQ_CB_TBL[RSC_IRQ_TYPE_AMOUNT] = { #if DUMMY_RSC {ISP_Irq_RSC, 0, "rsc-dummy"}, #else {ISP_Irq_RSC, 0, "rsc"}, #endif }; #endif typedef void (*tasklet_cb)(unsigned long); struct Tasklet_table { tasklet_cb tkt_cb; struct tasklet_struct *pRSC_tkt; }; struct tasklet_struct Rsctkt[RSC_IRQ_TYPE_AMOUNT]; static void ISP_TaskletFunc_RSC(unsigned long data); static struct Tasklet_table RSC_tasklet[RSC_IRQ_TYPE_AMOUNT] = { {ISP_TaskletFunc_RSC, &Rsctkt[RSC_IRQ_TYPE_INT_RSC_ST]}, }; static struct work_struct logWork; static void logPrint(struct work_struct *data); struct wakeup_source RSC_wake_lock; static DEFINE_MUTEX(gRscMutex); static DEFINE_MUTEX(gRscDequeMutex); static DEFINE_MUTEX(gRscClkMutex); #ifdef CONFIG_OF struct RSC_device { void __iomem *regs; struct device *dev; int irq; struct device *larb; }; static struct RSC_device *RSC_devs; static int nr_RSC_devs; static struct cmdq_base *cmdq_base; static struct cmdq_client *cmdq_clt; static s32 cmdq_event_id; /* Get HW modules' base address from device nodes */ #define RSC_DEV_NODE_IDX 0 #define IPESYS_DEV_MODE_IDX 0 #define ISP_RSC_BASE (RSC_devs[RSC_DEV_NODE_IDX].regs) #define ISP_IPESYS_BASE (RSC_devs[IPESYS_DEV_MODE_IDX].regs) #else #define ISP_RSC_BASE (IPESYS_BASE + 0x2800) #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 32 enum RSC_FRAME_STATUS_ENUM { RSC_FRAME_STATUS_EMPTY, /* 0 */ RSC_FRAME_STATUS_ENQUE, /* 1 */ RSC_FRAME_STATUS_RUNNING, /* 2 */ RSC_FRAME_STATUS_FINISHED, /* 3 */ RSC_FRAME_STATUS_TOTAL }; enum RSC_REQUEST_STATE_ENUM { RSC_REQUEST_STATE_EMPTY, /* 0 */ RSC_REQUEST_STATE_PENDING, /* 1 */ RSC_REQUEST_STATE_RUNNING, /* 2 */ RSC_REQUEST_STATE_FINISHED, /* 3 */ RSC_REQUEST_STATE_TOTAL }; /* tee_mmu */ struct tee_mmu { /* ION case only */ struct dma_buf *dma_buf; struct dma_buf_attachment *attach; struct sg_table *sgt; }; struct RSC_REQUEST_STRUCT { enum RSC_REQUEST_STATE_ENUM State; pid_t processID; /* caller process ID */ unsigned int callerID; /* caller thread ID */ unsigned int enqueReqNum; /* to judge it belongs to which frame package */ signed int FrameWRIdx; /* Frame write Index */ signed int RrameRDIdx; /* Frame read Index */ enum RSC_FRAME_STATUS_ENUM RscFrameStatus[_SUPPORT_MAX_RSC_FRAME_REQUEST_]; struct RSC_Config RscFrameConfig[_SUPPORT_MAX_RSC_FRAME_REQUEST_]; }; struct RSC_REQUEST_RING_STRUCT { signed int WriteIdx; /* enque how many request */ signed int ReadIdx; /* read which request index */ signed int HWProcessIdx; /* HWWriteIdx */ struct RSC_REQUEST_STRUCT RSCReq_Struct[_SUPPORT_MAX_RSC_REQUEST_RING_SIZE_]; }; struct RSC_CONFIG_STRUCT { struct RSC_Config RscFrameConfig[_SUPPORT_MAX_RSC_FRAME_REQUEST_]; }; static struct RSC_REQUEST_RING_STRUCT g_RSC_ReqRing; static struct RSC_CONFIG_STRUCT g_RscEnqueReq_Struct; static struct RSC_CONFIG_STRUCT g_RscDequeReq_Struct; static struct engine_requests rsc_reqs; static struct RSC_Request kRscReq; /****************************************************************************** * ******************************************************************************/ struct RSC_USER_INFO_STRUCT { pid_t Pid; pid_t Tid; }; enum RSC_PROCESS_ID_ENUM { RSC_PROCESS_ID_NONE, RSC_PROCESS_ID_RSC, RSC_PROCESS_ID_AMOUNT }; /****************************************************************************** * ******************************************************************************/ struct RSC_IRQ_INFO_STRUCT { unsigned int Status[RSC_IRQ_TYPE_AMOUNT]; signed int RscIrqCnt; pid_t ProcessID[RSC_PROCESS_ID_AMOUNT]; unsigned int Mask[RSC_IRQ_TYPE_AMOUNT]; }; struct RSC_INFO_STRUCT { spinlock_t SpinLockRSCRef; spinlock_t SpinLockRSC; spinlock_t SpinLockIrq[RSC_IRQ_TYPE_AMOUNT]; wait_queue_head_t WaitQueueHead; struct work_struct ScheduleRscWork; struct workqueue_struct *wkqueue; unsigned int UserCount; /* User Count */ unsigned int DebugMask; /* Debug Mask */ signed int IrqNum; struct RSC_IRQ_INFO_STRUCT IrqInfo; signed int WriteReqIdx; signed int ReadReqIdx; pid_t ProcessID[_SUPPORT_MAX_RSC_FRAME_REQUEST_]; }; static struct RSC_INFO_STRUCT RSCInfo; #if defined(RSC_PMQOS_EN) && defined(CONFIG_MTK_QOS_SUPPORT) struct pm_qos_request rsc_pm_qos_request; #endif enum eLOG_TYPE { _LOG_DBG = 0, _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]; } *RSC_PSV_LOG_STR; static void *pLog_kmalloc; static struct SV_LOG_STR gSvLog[RSC_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 */ #if CHECK_SERVICE_IF_1 #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) #else #define IRQ_LOG_KEEPER(irq, ppb, logT, fmt, ...) \ xlog_printk(ANDROID_LOG_DEBUG,\ "KEEPER", "[%s] " fmt, __func__, ##__VA_ARGS__) #endif #if CHECK_SERVICE_IF_1 #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) #else #define IRQ_LOG_PRINTER(irq, ppb, logT) #endif #define IPESYS_REG_CG_CON (ISP_IPESYS_BASE + 0x0) #define IPESYS_REG_CG_SET (ISP_IPESYS_BASE + 0x4) #define IPESYS_REG_CG_CLR (ISP_IPESYS_BASE + 0x8) /* RSC unmapped base address macro for GCE to access */ #define RSC_RST_HW (RSC_BASE_HW) #define RSC_START_HW (RSC_BASE_HW + 0x04) #define RSC_DCM_CTL_HW (RSC_BASE_HW + 0x08) #define RSC_DCM_STAUS_HW (RSC_BASE_HW + 0x0C) #define RSC_INT_CTL_HW (RSC_BASE_HW + 0x10) #define RSC_INT_STATUS_HW (RSC_BASE_HW + 0x14) #define RSC_CTRL_HW (RSC_BASE_HW + 0x18) #define RSC_SIZE_HW (RSC_BASE_HW + 0x1C) #define RSC_SR_HW (RSC_BASE_HW + 0x20) #define RSC_BR_HW (RSC_BASE_HW + 0x24) #define RSC_MV_OFFSET_HW (RSC_BASE_HW + 0x28) #define RSC_GMV_OFFSET_HW (RSC_BASE_HW + 0x2c) #define RSC_PREPARE_MV_CTRL_HW (RSC_BASE_HW + 0x30) #define RSC_CAND_NUM_HW (RSC_BASE_HW + 0x34) #define RSC_EVEN_CAND_SEL_0_HW (RSC_BASE_HW + 0x38) #define RSC_EVEN_CAND_SEL_1_HW (RSC_BASE_HW + 0x3c) #define RSC_EVEN_CAND_SEL_2_HW (RSC_BASE_HW + 0x40) #define RSC_EVEN_CAND_SEL_3_HW (RSC_BASE_HW + 0x44) #define RSC_EVEN_CAND_SEL_4_HW (RSC_BASE_HW + 0x48) #define RSC_ODD_CAND_SEL_0_HW (RSC_BASE_HW + 0x4C) #define RSC_ODD_CAND_SEL_1_HW (RSC_BASE_HW + 0x50) #define RSC_ODD_CAND_SEL_2_HW (RSC_BASE_HW + 0x54) #define RSC_ODD_CAND_SEL_3_HW (RSC_BASE_HW + 0x58) #define RSC_ODD_CAND_SEL_4_HW (RSC_BASE_HW + 0x5C) #define RSC_RAND_HORZ_LUT_HW (RSC_BASE_HW + 0x60) #define RSC_RAND_VERT_LUT_HW (RSC_BASE_HW + 0x64) #define RSC_CURR_BLK_CTRL_HW (RSC_BASE_HW + 0x68) #define RSC_SAD_CTRL_HW (RSC_BASE_HW + 0x6C) #define RSC_SAD_EDGE_GAIN_CTRL_HW (RSC_BASE_HW + 0x70) #define RSC_SAD_CRNR_GAIN_CTRL_HW (RSC_BASE_HW + 0x74) #define RSC_STILL_STRIP_CTRL_0_HW (RSC_BASE_HW + 0x78) #define RSC_STILL_STRIP_CTRL_1_HW (RSC_BASE_HW + 0x7C) #define RSC_MV_PNLTY_CTRL_HW (RSC_BASE_HW + 0x80) #define RSC_ZERO_PNLTY_CTRL_HW (RSC_BASE_HW + 0x84) #define RSC_RAND_PNLTY_CTRL_HW (RSC_BASE_HW + 0x88) #define RSC_RAND_PNLTY_GAIN_CTRL_0_HW (RSC_BASE_HW + 0x8C) #define RSC_RAND_PNLTY_GAIN_CTRL_1_HW (RSC_BASE_HW + 0x90) #define RSC_TMPR_PNLTY_GAIN_CTRL_0_HW (RSC_BASE_HW + 0x94) #define RSC_TMPR_PNLTY_GAIN_CTRL_1_HW (RSC_BASE_HW + 0x98) #define RSC_IMGI_C_BASE_ADDR_HW (RSC_BASE_HW + 0x9C) #define RSC_IMGI_C_STRIDE_HW (RSC_BASE_HW + 0xA0) #define RSC_IMGI_P_BASE_ADDR_HW (RSC_BASE_HW + 0xA4) #define RSC_IMGI_P_STRIDE_HW (RSC_BASE_HW + 0xA8) #define RSC_MVI_BASE_ADDR_HW (RSC_BASE_HW + 0xAC) #define RSC_MVI_STRIDE_HW (RSC_BASE_HW + 0xB0) #define RSC_APLI_C_BASE_ADDR_HW (RSC_BASE_HW + 0xB4) #define RSC_APLI_P_BASE_ADDR_HW (RSC_BASE_HW + 0xB8) #define RSC_MVO_BASE_ADDR_HW (RSC_BASE_HW + 0xBC) #define RSC_MVO_STRIDE_HW (RSC_BASE_HW + 0xC0) #define RSC_BVO_BASE_ADDR_HW (RSC_BASE_HW + 0xC4) #define RSC_BVO_STRIDE_HW (RSC_BASE_HW + 0xC8) #define RSC_STA_0_HW (RSC_BASE_HW + 0x100) #define RSC_DBG_INFO_00_HW (RSC_BASE_HW + 0x120) #define RSC_DBG_INFO_01_HW (RSC_BASE_HW + 0x124) #define RSC_DBG_INFO_02_HW (RSC_BASE_HW + 0x128) #define RSC_DBG_INFO_03_HW (RSC_BASE_HW + 0x12C) #define RSC_DBG_INFO_04_HW (RSC_BASE_HW + 0x130) #define RSC_DBG_INFO_05_HW (RSC_BASE_HW + 0x134) #define RSC_DBG_INFO_06_HW (RSC_BASE_HW + 0x138) #define RSC_SPARE_0_HW (RSC_BASE_HW + 0x1F8) #define RSC_SPARE_1_HW (RSC_BASE_HW + 0x1FC) #define RSC_DMA_DBG_HW (RSC_BASE_HW + 0x7F4) #define RSC_DMA_REQ_STATUS_HW (RSC_BASE_HW + 0x7F8) #define RSC_DMA_RDY_STATUS_HW (RSC_BASE_HW + 0x7FC) #define RSC_DMA_DMA_SOFT_RSTSTAT_HW (RSC_BASE_HW + 0x800) #define RSC_DMA_VERTICAL_FLIP_EN_HW (RSC_BASE_HW + 0x804) #define RSC_DMA_DMA_SOFT_RESET_HW (RSC_BASE_HW + 0x808) #define RSC_DMA_LAST_ULTRA_HW (RSC_BASE_HW + 0x80C) #define RSC_DMA_SPECIAL_FUN_HW (RSC_BASE_HW + 0x810) #define RSC_DMA_RSCO_BASE_ADDR_HW (RSC_BASE_HW + 0x830) #define RSC_DMA_RSCO_BASE_ADDR_2_HW (RSC_BASE_HW + 0x834) #define RSC_DMA_RSCO_OFST_ADDR_HW (RSC_BASE_HW + 0x838) #define RSC_DMA_RSCO_OFST_ADDR_2_HW (RSC_BASE_HW + 0x83C) #define RSC_DMA_RSCO_XSIZE_HW (RSC_BASE_HW + 0x840) #define RSC_DMA_RSCO_YSIZE_HW (RSC_BASE_HW + 0x844) #define RSC_DMA_RSCO_STRIDE_HW (RSC_BASE_HW + 0x848) #define RSC_DMA_RSCO_CON_HW (RSC_BASE_HW + 0x84C) #define RSC_DMA_RSCO_CON2_HW (RSC_BASE_HW + 0x850) #define RSC_DMA_RSCO_CON3_HW (RSC_BASE_HW + 0x854) #define RSC_DMA_RSCI_BASE_ADDR_HW (RSC_BASE_HW + 0x890) #define RSC_DMA_RSCI_BASE_ADDR_2_HW (RSC_BASE_HW + 0x894) #define RSC_DMA_RSCI_OFST_ADDR_HW (RSC_BASE_HW + 0x898) #define RSC_DMA_RSCI_OFST_ADDR_2_HW (RSC_BASE_HW + 0x89C) #define RSC_DMA_RSCI_XSIZE_HW (RSC_BASE_HW + 0x8A0) #define RSC_DMA_RSCI_YSIZE_HW (RSC_BASE_HW + 0x8A4) #define RSC_DMA_RSCI_STRIDE_HW (RSC_BASE_HW + 0x8A8) #define RSC_DMA_RSCI_CON_HW (RSC_BASE_HW + 0x8AC) #define RSC_DMA_RSCI_CON2_HW (RSC_BASE_HW + 0x8B0) #define RSC_DMA_RSCI_CON3_HW (RSC_BASE_HW + 0x8B4) #define RSC_DMA_DMA_ERR_CTRL_HW (RSC_BASE_HW + 0x900) #define RSC_DMA_RSCO_ERR_STAT_HW (RSC_BASE_HW + 0x904) #define RSC_DMA_RSCI_ERR_STAT_HW (RSC_BASE_HW + 0x908) #define RSC_DMA_DMA_DEBUG_ADDR_HW (RSC_BASE_HW + 0x90C) #define RSC_DMA_DMA_DEBUG_SEL_HW (RSC_BASE_HW + 0x928) #define RSC_DMA_DMA_BW_SELF_TEST_HW (RSC_BASE_HW + 0x92C) /*SW Access Registers : using mapped base address from DTS*/ #define RSC_RST_REG (ISP_RSC_BASE) #define RSC_START_REG (ISP_RSC_BASE + 0x04) #define RSC_DCM_CTL_REG (ISP_RSC_BASE + 0x08) #define RSC_DCM_STAUS_REG (ISP_RSC_BASE + 0x0C) #define RSC_INT_CTL_REG (ISP_RSC_BASE + 0x10) #define RSC_INT_STATUS_REG (ISP_RSC_BASE + 0x14) #define RSC_CTRL_REG (ISP_RSC_BASE + 0x18) #define RSC_SIZE_REG (ISP_RSC_BASE + 0x1C) #define RSC_SR_REG (ISP_RSC_BASE + 0x20) #define RSC_BR_REG (ISP_RSC_BASE + 0x24) #define RSC_MV_OFFSET_REG (ISP_RSC_BASE + 0x28) #define RSC_GMV_OFFSET_REG (ISP_RSC_BASE + 0x2c) #define RSC_PREPARE_MV_CTRL_REG (ISP_RSC_BASE + 0x30) #define RSC_CAND_NUM_REG (ISP_RSC_BASE + 0x34) #define RSC_EVEN_CAND_SEL_0_REG (ISP_RSC_BASE + 0x38) #define RSC_EVEN_CAND_SEL_1_REG (ISP_RSC_BASE + 0x3c) #define RSC_EVEN_CAND_SEL_2_REG (ISP_RSC_BASE + 0x40) #define RSC_EVEN_CAND_SEL_3_REG (ISP_RSC_BASE + 0x44) #define RSC_EVEN_CAND_SEL_4_REG (ISP_RSC_BASE + 0x48) #define RSC_ODD_CAND_SEL_0_REG (ISP_RSC_BASE + 0x4C) #define RSC_ODD_CAND_SEL_1_REG (ISP_RSC_BASE + 0x50) #define RSC_ODD_CAND_SEL_2_REG (ISP_RSC_BASE + 0x54) #define RSC_ODD_CAND_SEL_3_REG (ISP_RSC_BASE + 0x58) #define RSC_ODD_CAND_SEL_4_REG (ISP_RSC_BASE + 0x5C) #define RSC_RAND_HORZ_LUT_REG (ISP_RSC_BASE + 0x60) #define RSC_RAND_VERT_LUT_REG (ISP_RSC_BASE + 0x64) #define RSC_CURR_BLK_CTRL_REG (ISP_RSC_BASE + 0x68) #define RSC_SAD_CTRL_REG (ISP_RSC_BASE + 0x6C) #define RSC_SAD_EDGE_GAIN_CTRL_REG (ISP_RSC_BASE + 0x70) #define RSC_SAD_CRNR_GAIN_CTRL_REG (ISP_RSC_BASE + 0x74) #define RSC_STILL_STRIP_CTRL_0_REG (ISP_RSC_BASE + 0x78) #define RSC_STILL_STRIP_CTRL_1_REG (ISP_RSC_BASE + 0x7C) #define RSC_MV_PNLTY_CTRL_REG (ISP_RSC_BASE + 0x80) #define RSC_ZERO_PNLTY_CTRL_REG (ISP_RSC_BASE + 0x84) #define RSC_RAND_PNLTY_CTRL_REG (ISP_RSC_BASE + 0x88) #define RSC_RAND_PNLTY_GAIN_CTRL_0_REG (ISP_RSC_BASE + 0x8C) #define RSC_RAND_PNLTY_GAIN_CTRL_1_REG (ISP_RSC_BASE + 0x90) #define RSC_TMPR_PNLTY_GAIN_CTRL_0_REG (ISP_RSC_BASE + 0x94) #define RSC_TMPR_PNLTY_GAIN_CTRL_1_REG (ISP_RSC_BASE + 0x98) #define RSC_IMGI_C_BASE_ADDR_REG (ISP_RSC_BASE + 0x9C) #define RSC_IMGI_C_STRIDE_REG (ISP_RSC_BASE + 0xA0) #define RSC_IMGI_P_BASE_ADDR_REG (ISP_RSC_BASE + 0xA4) #define RSC_IMGI_P_STRIDE_REG (ISP_RSC_BASE + 0xA8) #define RSC_MVI_BASE_ADDR_REG (ISP_RSC_BASE + 0xAC) #define RSC_MVI_STRIDE_REG (ISP_RSC_BASE + 0xB0) #define RSC_APLI_C_BASE_ADDR_REG (ISP_RSC_BASE + 0xB4) #define RSC_APLI_P_BASE_ADDR_REG (ISP_RSC_BASE + 0xB8) #define RSC_MVO_BASE_ADDR_REG (ISP_RSC_BASE + 0xBC) #define RSC_MVO_STRIDE_REG (ISP_RSC_BASE + 0xC0) #define RSC_BVO_BASE_ADDR_REG (ISP_RSC_BASE + 0xC4) #define RSC_BVO_STRIDE_REG (ISP_RSC_BASE + 0xC8) #define RSC_STA_0_REG (ISP_RSC_BASE + 0x100) #define RSC_DBG_INFO_00_REG (ISP_RSC_BASE + 0x120) #define RSC_DBG_INFO_01_REG (ISP_RSC_BASE + 0x124) #define RSC_DBG_INFO_02_REG (ISP_RSC_BASE + 0x128) #define RSC_DBG_INFO_03_REG (ISP_RSC_BASE + 0x12C) #define RSC_DBG_INFO_04_REG (ISP_RSC_BASE + 0x130) #define RSC_DBG_INFO_05_REG (ISP_RSC_BASE + 0x134) #define RSC_DBG_INFO_06_REG (ISP_RSC_BASE + 0x138) #define RSC_SPARE_0_REG (ISP_RSC_BASE + 0x1F8) #define RSC_SPARE_1_REG (ISP_RSC_BASE + 0x1FC) #define RSC_DMA_DBG_REG (ISP_RSC_BASE + 0x7F4) #define RSC_DMA_REQ_STATUS_REG (ISP_RSC_BASE + 0x7F8) #define RSC_DMA_RDY_STATUS_REG (ISP_RSC_BASE + 0x7FC) #define RSC_DMA_DMA_SOFT_RSTSTAT_REG (ISP_RSC_BASE + 0x800) #define RSC_DMA_VERTICAL_FLIP_EN_REG (ISP_RSC_BASE + 0x804) #define RSC_DMA_DMA_SOFT_RESET_REG (ISP_RSC_BASE + 0x808) #define RSC_DMA_LAST_ULTRA_REG (ISP_RSC_BASE + 0x80C) #define RSC_DMA_SPECIAL_FUN_REG (ISP_RSC_BASE + 0x810) #define RSC_DMA_RSCO_BASE_ADDR_REG (ISP_RSC_BASE + 0x830) #define RSC_DMA_RSCO_BASE_ADDR_2_REG (ISP_RSC_BASE + 0x834) #define RSC_DMA_RSCO_OFST_ADDR_REG (ISP_RSC_BASE + 0x838) #define RSC_DMA_RSCO_OFST_ADDR_2_REG (ISP_RSC_BASE + 0x83C) #define RSC_DMA_RSCO_XSIZE_REG (ISP_RSC_BASE + 0x840) #define RSC_DMA_RSCO_YSIZE_REG (ISP_RSC_BASE + 0x844) #define RSC_DMA_RSCO_STRIDE_REG (ISP_RSC_BASE + 0x848) #define RSC_DMA_RSCO_CON_REG (ISP_RSC_BASE + 0x84C) #define RSC_DMA_RSCO_CON2_REG (ISP_RSC_BASE + 0x850) #define RSC_DMA_RSCO_CON3_REG (ISP_RSC_BASE + 0x854) #define RSC_DMA_RSCI_BASE_ADDR_REG (ISP_RSC_BASE + 0x890) #define RSC_DMA_RSCI_BASE_ADDR_2_REG (ISP_RSC_BASE + 0x894) #define RSC_DMA_RSCI_OFST_ADDR_REG (ISP_RSC_BASE + 0x898) #define RSC_DMA_RSCI_OFST_ADDR_2_REG (ISP_RSC_BASE + 0x89C) #define RSC_DMA_RSCI_XSIZE_REG (ISP_RSC_BASE + 0x8A0) #define RSC_DMA_RSCI_YSIZE_REG (ISP_RSC_BASE + 0x8A4) #define RSC_DMA_RSCI_STRIDE_REG (ISP_RSC_BASE + 0x8A8) #define RSC_DMA_RSCI_CON_REG (ISP_RSC_BASE + 0x8AC) #define RSC_DMA_RSCI_CON2_REG (ISP_RSC_BASE + 0x8B0) #define RSC_DMA_RSCI_CON3_REG (ISP_RSC_BASE + 0x8B4) #define RSC_DMA_DMA_ERR_CTRL_REG (ISP_RSC_BASE + 0x900) #define RSC_DMA_RSCO_ERR_STAT_REG (ISP_RSC_BASE + 0x904) #define RSC_DMA_RSCI_ERR_STAT_REG (ISP_RSC_BASE + 0x908) #define RSC_DMA_DMA_DEBUG_ADDR_REG (ISP_RSC_BASE + 0x90C) #define RSC_DMA_DMA_DEBUG_SEL_REG (ISP_RSC_BASE + 0x928) #define RSC_DMA_DMA_BW_SELF_TEST_REG (ISP_RSC_BASE + 0x92C) /******************************************************************************* * ******************************************************************************/ static inline unsigned int RSC_MsToJiffies(unsigned int Ms) { return ((Ms * HZ + 512) >> 10); } /******************************************************************************* * ******************************************************************************/ static inline unsigned int RSC_UsToJiffies(unsigned int Us) { return (((Us / 1000) * HZ + 512) >> 10); } /******************************************************************************* * ******************************************************************************/ static inline unsigned int RSC_GetIRQState(unsigned int type, unsigned int userNumber, unsigned int stus, enum RSC_PROCESS_ID_ENUM whichReq, int ProcessID) { unsigned int ret = 0; unsigned long flags; spin_lock_irqsave(&(RSCInfo.SpinLockIrq[type]), flags); if (stus & RSC_INT_ST) { ret = ((RSCInfo.IrqInfo.RscIrqCnt > 0) && (RSCInfo.IrqInfo.ProcessID[whichReq] == ProcessID)); } else { LOG_ERR("EWIRQ,type:%d,u:%d,stat:%d,wReq:%d,PID:0x%x\n", type, userNumber, stus, whichReq, ProcessID); } spin_unlock_irqrestore(&(RSCInfo.SpinLockIrq[type]), flags); return ret; } /******************************************************************************* * ******************************************************************************/ static inline unsigned int RSC_JiffiesToMs(unsigned int Jiffies) { return ((Jiffies * 1000) / HZ); } #define RegDump(start, end) \ { \ unsigned int i; \ for (i = start; i <= end; i += 0x10) { \ LOG_DBG("[0x%08X %08X],[0x%08X %08X],[0x%08X %08X],[0x%08X %08X]", \ (unsigned int)(ISP_RSC_BASE + i), \ (unsigned int)RSC_RD32(ISP_RSC_BASE + i), \ (unsigned int)(ISP_RSC_BASE + i + 0x4), \ (unsigned int)RSC_RD32(ISP_RSC_BASE + i + \ 0x4), \ (unsigned int)(ISP_RSC_BASE + i + 0x8), \ (unsigned int)RSC_RD32(ISP_RSC_BASE + i + \ 0x8), \ (unsigned int)(ISP_RSC_BASE + i + 0xc), \ (unsigned int)RSC_RD32(ISP_RSC_BASE + i + \ 0xc)); \ } \ } signed int rsc_enque_cb(struct frame *frames, void *req) { unsigned int f, fcnt; /*TODO: define engine request struct */ struct RSC_Request *_req; struct RSC_Config *pRscConfig; _req = (struct RSC_Request *) req; if (frames == NULL || _req == NULL) return -1; /*TODO: m_ReqNum is FrmNum; FIFO only thus f starts from 0 */ fcnt = _req->m_ReqNum; for (f = 0; f < fcnt; f++) { memcpy(frames[f].data, &_req->m_pRscConfig[f], sizeof(struct RSC_Config)); pRscConfig = &_req->m_pRscConfig[f]; #if CHECK_SERVICE_IF_0 LOG_ERR("[%s] request queued with frame(%d)", __func__, f); LOG_DBG("[%s] RSC_CTRL_REG:0x%x!\n", __func__, pRscConfig->RSC_CTRL); LOG_DBG("[%s] RSC_SIZE_REG:0x%x!\n", __func__, pRscConfig->RSC_SIZE); LOG_DBG("[%s] RSC_IMGI_C_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_IMGI_C_BASE_ADDR); LOG_DBG("[%s] RSC_IMGI_C_STRIDE_REG:0x%x!\n", __func__, pRscConfig->RSC_IMGI_C_STRIDE); LOG_DBG("[%s] RSC_IMGI_P_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_IMGI_P_BASE_ADDR); LOG_DBG("[%s] RSC_IMGI_P_STRIDE_REG:0x%x!\n", __func__, pRscConfig->RSC_IMGI_P_STRIDE); LOG_DBG("[%s] RSC_MVI_C_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_MVI_BASE_ADDR); LOG_DBG("[%s] RSC_MVI_C_STRIDE_REG:0x%x!\n", __func__, pRscConfig->RSC_MVI_STRIDE); LOG_DBG("[%s] RSC_MVO_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_MVO_BASE_ADDR); LOG_DBG("[%s] RSC_MVO_STRIDE_REG:0x%x!\n", __func__, pRscConfig->RSC_MVO_STRIDE); LOG_DBG("[%s] RSC_BVO_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_BVO_BASE_ADDR); LOG_DBG("[%s] RSC_BVO_STRIDE_REG:0x%x!\n", __func__, pRscConfig->RSC_BVO_STRIDE); LOG_DBG("[%s] RSC_APLI_C_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_APLI_C_BASE_ADDR); LOG_DBG("[%s] RSC_APLI_P_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_APLI_P_BASE_ADDR); #endif } return 0; } signed int rsc_deque_cb(struct frame *frames, void *req) { unsigned int f, fcnt; struct RSC_Request *_req; struct RSC_Config *pRscConfig; _req = (struct RSC_Request *) req; if (frames == NULL || _req == NULL) return -1; /*TODO: m_ReqNum is FrmNum; FIFO only thus f starts from 0 */ fcnt = _req->m_ReqNum; for (f = 0; f < fcnt; f++) { memcpy(&_req->m_pRscConfig[f], frames[f].data, sizeof(struct RSC_Config)); LOG_DBG("[%s]request dequeued frame(%d/%d).", __func__, f, fcnt); pRscConfig = &_req->m_pRscConfig[f]; #if CHECK_SERVICE_IF_0 LOG_ERR( "[%s] request queued with frame(%d)", __func__, f); LOG_DBG( "[%s] RSC_CTRL_REG:0x%x!\n", __func__, pRscConfig->RSC_CTRL); LOG_DBG( "[%s] RSC_SIZE_REG:0x%x!\n", __func__, pRscConfig->RSC_SIZE); LOG_DBG( "[%s] RSC_IMGI_C_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_IMGI_C_BASE_ADDR); LOG_DBG( "[%s] RSC_IMGI_C_STRIDE_REG:0x%x!\n", __func__, pRscConfig->RSC_IMGI_C_STRIDE); LOG_DBG( "[%s] RSC_IMGI_P_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_IMGI_P_BASE_ADDR); LOG_DBG( "[%s] RSC_IMGI_P_STRIDE_REG:0x%x!\n", __func__, pRscConfig->RSC_IMGI_P_STRIDE); LOG_DBG( "[%s] RSC_MVI_C_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_MVI_BASE_ADDR); LOG_DBG( "[%s] RSC_MVI_C_STRIDE_REG:0x%x!\n", __func__, pRscConfig->RSC_MVI_STRIDE); LOG_DBG( "[%s] RSC_MVO_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_MVO_BASE_ADDR); LOG_DBG( "[%s] RSC_MVO_STRIDE_REG:0x%x!\n", __func__, pRscConfig->RSC_MVO_STRIDE); LOG_DBG( "[%s] RSC_BVO_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_BVO_BASE_ADDR); LOG_DBG( "[%s] RSC_BVO_STRIDE_REG:0x%x!\n", __func__, pRscConfig->RSC_BVO_STRIDE); LOG_DBG( "[%s] RSC_APLI_C_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_APLI_C_BASE_ADDR); LOG_DBG( "[%s] RSC_APLI_P_BASE_ADDR_REG:0x%x!\n", __func__, pRscConfig->RSC_APLI_P_BASE_ADDR); #endif } return 0; } static bool mmu_get_dma_buffer(struct tee_mmu *mmu, int fd) { struct dma_buf *buf; buf = dma_buf_get(fd); //LOG_INF("RSC_mmu_get_buffer:%x /BUF:%x\n", fd, buf); if (IS_ERR(buf)) { LOG_INF("[error buf]"); return false; } mmu->dma_buf = buf; mmu->attach = dma_buf_attach(mmu->dma_buf, RSC_devs->dev); if (IS_ERR(mmu->attach)) goto err_attach; mmu->sgt = dma_buf_map_attachment(mmu->attach, DMA_BIDIRECTIONAL); if (IS_ERR(mmu->sgt)) goto err_map; return true; err_map: dma_buf_detach(mmu->dma_buf, mmu->attach); LOG_INF("[error MAP]"); err_attach: dma_buf_put(mmu->dma_buf); LOG_INF("[error Attach]"); return false; } static void mmu_release(struct tee_mmu *mmu) { if (mmu->dma_buf) { dma_buf_unmap_attachment(mmu->attach, mmu->sgt, DMA_BIDIRECTIONAL); dma_buf_detach(mmu->dma_buf, mmu->attach); dma_buf_put(mmu->dma_buf); } } void rsc_cmdq_cb_destroy(struct cmdq_cb_data data) { if (data.data) { int i = 0; unsigned long *pkt_ptr = NULL; for (i = 0; i < NUM_BASEADDR; i++) mmu_release(((struct tee_mmu *)(data.data))+i); pkt_ptr = (unsigned long *)(((struct tee_mmu *)data.data)+NUM_BASEADDR); cmdq_pkt_destroy((struct cmdq_pkt *)(*pkt_ptr)); kfree((struct tee_mmu *)data.data); } #if defined(RSC_PMQOS_EN) && defined(CONFIG_MTK_QOS_SUPPORT) pm_qos_update_request(&rsc_pm_qos_request, 0); #endif } unsigned long FD_OFFSET_ADDR[NUM_BASEADDR]; signed int CmdqRSCHW(struct frame *frame) { struct tee_mmu mmu; struct tee_mmu *records = NULL; struct RSC_Config *pRscConfig = NULL; unsigned int hw_array[NUM_BASEADDR]; unsigned int fd_array[NUM_BASEADDR]; unsigned int offset_array[NUM_BASEADDR]; int i = 0; #if CHECK_SERVICE_IF_1 struct cmdq_pkt *pkt; #if CHECK_SERVICE_IF_0 uint64_t engineFlag = (uint64_t)(1LL << CMDQ_ENG_RSC); #endif #if defined(RSC_PMQOS_EN) && defined(CONFIG_MTK_QOS_SUPPORT) unsigned int w_imgi, h_imgi, w_mvio, h_mvio, w_bvo, h_bvo; unsigned int dma_bandwidth, trig_num; #endif #endif if (frame == NULL || frame->data == NULL) return -1; LOG_DBG("%s request sent to CMDQ driver", __func__); pRscConfig = (struct RSC_Config *) frame->data; LOG_DBG("RSC_CTRL_REG:0x%x!\n", pRscConfig->RSC_CTRL); LOG_DBG("RSC_SIZE_REG:0x%x!\n", pRscConfig->RSC_SIZE); LOG_DBG("RSC_IMGI_C_BASE_ADDR_REG:0x%x!\n", pRscConfig->RSC_IMGI_C_BASE_ADDR); LOG_DBG("RSC_IMGI_C_STRIDE_REG:0x%x!\n", pRscConfig->RSC_IMGI_C_STRIDE); LOG_DBG("RSC_IMGI_P_BASE_ADDR_REG:0x%x!\n", pRscConfig->RSC_IMGI_P_BASE_ADDR); LOG_DBG("RSC_IMGI_P_STRIDE_REG:0x%x!\n", pRscConfig->RSC_IMGI_P_STRIDE); LOG_DBG("RSC_MVI_C_BASE_ADDR_REG:0x%x!\n", pRscConfig->RSC_MVI_BASE_ADDR); LOG_DBG("RSC_MVI_C_STRIDE_REG:0x%x!\n", pRscConfig->RSC_MVI_STRIDE); LOG_DBG("RSC_MVO_BASE_ADDR_REG:0x%x!\n", pRscConfig->RSC_MVO_BASE_ADDR); LOG_DBG("RSC_MVO_STRIDE_REG:0x%x!\n", pRscConfig->RSC_MVO_STRIDE); LOG_DBG("RSC_BVO_BASE_ADDR_REG:0x%x!\n", pRscConfig->RSC_BVO_BASE_ADDR); LOG_DBG("RSC_BVO_STRIDE_REG:0x%x!\n", pRscConfig->RSC_BVO_STRIDE); LOG_DBG("RSC_APLI_C_BASE_ADDR_REG:0x%x!\n", pRscConfig->RSC_APLI_C_BASE_ADDR); LOG_DBG("RSC_APLI_P_BASE_ADDR_REG:0x%x!\n", pRscConfig->RSC_APLI_P_BASE_ADDR); #if CHECK_SERVICE_IF_1 // support cmdq mailmox pkt = cmdq_pkt_create(cmdq_clt); cmdq_pkt_write(pkt, cmdq_base, RSC_INT_CTL_HW, 0x1, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_CTRL_HW, pRscConfig->RSC_CTRL, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_SIZE_HW, pRscConfig->RSC_SIZE, ~0); if (!pRscConfig->IS_LEGACY) { records = kzalloc(sizeof(struct tee_mmu) * NUM_BASEADDR + sizeof(unsigned long), GFP_KERNEL); hw_array[0] = RSC_APLI_C_BASE_ADDR_HW; hw_array[1] = RSC_APLI_P_BASE_ADDR_HW; hw_array[2] = RSC_IMGI_C_BASE_ADDR_HW; hw_array[3] = RSC_IMGI_P_BASE_ADDR_HW; hw_array[4] = RSC_MVI_BASE_ADDR_HW; hw_array[5] = RSC_MVO_BASE_ADDR_HW; hw_array[6] = RSC_BVO_BASE_ADDR_HW; fd_array[0] = pRscConfig->RSC_APLI_C_FD; fd_array[1] = pRscConfig->RSC_APLI_P_FD; fd_array[2] = pRscConfig->RSC_IMGI_C_FD; fd_array[3] = pRscConfig->RSC_IMGI_P_FD; fd_array[4] = pRscConfig->RSC_MVI_FD; fd_array[5] = pRscConfig->RSC_MVO_FD; fd_array[6] = pRscConfig->RSC_BVO_FD; offset_array[0] = pRscConfig->RSC_APLI_C_OFFSET; offset_array[1] = pRscConfig->RSC_APLI_P_OFFSET; offset_array[2] = pRscConfig->RSC_IMGI_C_OFFSET; offset_array[3] = pRscConfig->RSC_IMGI_P_OFFSET; offset_array[4] = pRscConfig->RSC_MVI_OFFSET; offset_array[5] = pRscConfig->RSC_MVO_OFFSET; offset_array[6] = pRscConfig->RSC_BVO_OFFSET; for (i = 0; i < NUM_BASEADDR; i++) { unsigned int success = mmu_get_dma_buffer(&mmu, fd_array[i]); if (success) { dma_addr_t dma_addr; dma_addr = sg_dma_address(mmu.sgt->sgl); cmdq_pkt_write(pkt, cmdq_base, hw_array[i], dma_addr + offset_array[i], ~0); FD_OFFSET_ADDR[i] = dma_addr + offset_array[i]; memcpy(&records[i], &mmu, sizeof(struct tee_mmu)); } } } else { cmdq_pkt_write(pkt, cmdq_base, RSC_APLI_C_BASE_ADDR_HW, pRscConfig->RSC_APLI_C_BASE_ADDR, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_APLI_P_BASE_ADDR_HW, pRscConfig->RSC_APLI_P_BASE_ADDR, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_IMGI_C_BASE_ADDR_HW, pRscConfig->RSC_IMGI_C_BASE_ADDR, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_IMGI_P_BASE_ADDR_HW, pRscConfig->RSC_IMGI_P_BASE_ADDR, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_MVI_BASE_ADDR_HW, pRscConfig->RSC_MVI_BASE_ADDR, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_MVO_BASE_ADDR_HW, pRscConfig->RSC_MVO_BASE_ADDR, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_BVO_BASE_ADDR_HW, pRscConfig->RSC_BVO_BASE_ADDR, ~0); } cmdq_pkt_write(pkt, cmdq_base, RSC_IMGI_C_STRIDE_HW, pRscConfig->RSC_IMGI_C_STRIDE, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_IMGI_P_STRIDE_HW, pRscConfig->RSC_IMGI_P_STRIDE, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_MVI_STRIDE_HW, pRscConfig->RSC_MVI_STRIDE, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_MVO_STRIDE_HW, pRscConfig->RSC_MVO_STRIDE, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_BVO_STRIDE_HW, pRscConfig->RSC_BVO_STRIDE, ~0); #ifdef RSC_TUNABLE cmdq_pkt_write(pkt, cmdq_base, RSC_MV_OFFSET_HW, pRscConfig->RSC_MV_OFFSET, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_GMV_OFFSET_HW, pRscConfig->RSC_GMV_OFFSET, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_CAND_NUM_HW, pRscConfig->RSC_CAND_NUM, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_RAND_HORZ_LUT_HW, pRscConfig->RSC_RAND_HORZ_LUT, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_RAND_VERT_LUT_HW, pRscConfig->RSC_RAND_VERT_LUT, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_SAD_CTRL_HW, pRscConfig->RSC_SAD_CTRL, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_SAD_EDGE_GAIN_CTRL_HW, pRscConfig->RSC_SAD_EDGE_GAIN_CTRL, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_SAD_CRNR_GAIN_CTRL_HW, pRscConfig->RSC_SAD_CRNR_GAIN_CTRL, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_STILL_STRIP_CTRL_0_HW, pRscConfig->RSC_STILL_STRIP_CTRL0, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_STILL_STRIP_CTRL_1_HW, pRscConfig->RSC_STILL_STRIP_CTRL1, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_RAND_PNLTY_CTRL_HW, pRscConfig->RSC_RAND_PNLTY_CTRL, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_RAND_PNLTY_GAIN_CTRL_0_HW, pRscConfig->RSC_RAND_PNLTY_GAIN_CTRL0, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_RAND_PNLTY_GAIN_CTRL_1_HW, pRscConfig->RSC_RAND_PNLTY_GAIN_CTRL1, ~0); #endif cmdq_pkt_write(pkt, cmdq_base, RSC_DCM_CTL_HW, 0x1111, ~0); cmdq_pkt_write(pkt, cmdq_base, RSC_START_HW, 0x1, ~0); /* RSC Interrupt read-clear mode */ cmdq_pkt_wfe(pkt, cmdq_event_id); cmdq_pkt_write(pkt, cmdq_base, RSC_START_HW, 0x0, ~0); /* RSC Interrupt read-clear mode */ #if defined(RSC_PMQOS_EN) && defined(CONFIG_MTK_QOS_SUPPORT) trig_num = (pRscConfig->RSC_CTRL & 0x00000F00) >> 8; w_imgi = pRscConfig->RSC_SIZE & 0x000001FF; h_imgi = (pRscConfig->RSC_SIZE & 0x01FF0000) >> 16; w_mvio = ((w_imgi + 1) >> 1) - 1; w_mvio = ((w_mvio / 7) << 4) + (((((w_mvio % 7) + 1) * 18) + 7) >> 3); h_mvio = (h_imgi + 1) >> 1; w_bvo = (w_imgi + 1) >> 1; h_bvo = (h_imgi + 1) >> 1; dma_bandwidth = ((w_imgi * h_imgi) * 2 + (w_mvio * h_mvio) * 2 * 16 + (w_bvo * h_bvo)) * trig_num * 30 / 1000000; pm_qos_update_request(&rsc_pm_qos_request, dma_bandwidth); #endif /* non-blocking API, Please use cmdqRecFlushAsync() */ //cmdq_task_flush_async_destroy(handle); /* flush and destroy in cmdq */ //pkt_addr = (unsigned long *)&records[NUM_BASEADDR]; //*pkt_addr = (unsigned long)pkt; cmdq_pkt_flush_threaded(pkt, rsc_cmdq_cb_destroy, (void *)records); #else // old cmdq function cmdqRecCreate(CMDQ_SCENARIO_KERNEL_CONFIG_GENERAL, &handle); cmdqRecSetEngine(handle, engineFlag); cmdqRecReset(handle); cmdqRecWrite(handle, RSC_INT_CTL_HW, 0x1, CMDQ_REG_MASK); /* RSC Interrupt read-clear mode */ cmdqRecWrite(handle, RSC_CTRL_HW, pRscConfig->RSC_CTRL, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_SIZE_HW, pRscConfig->RSC_SIZE, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_APLI_C_BASE_ADDR_HW, pRscConfig->RSC_APLI_C_BASE_ADDR, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_APLI_P_BASE_ADDR_HW, pRscConfig->RSC_APLI_P_BASE_ADDR, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_IMGI_C_BASE_ADDR_HW, pRscConfig->RSC_IMGI_C_BASE_ADDR, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_IMGI_P_BASE_ADDR_HW, pRscConfig->RSC_IMGI_P_BASE_ADDR, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_IMGI_C_STRIDE_HW, pRscConfig->RSC_IMGI_C_STRIDE, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_IMGI_P_STRIDE_HW, pRscConfig->RSC_IMGI_P_STRIDE, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_MVI_BASE_ADDR_HW, pRscConfig->RSC_MVI_BASE_ADDR, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_MVI_STRIDE_HW, pRscConfig->RSC_MVI_STRIDE, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_MVO_BASE_ADDR_HW, pRscConfig->RSC_MVO_BASE_ADDR, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_MVO_STRIDE_HW, pRscConfig->RSC_MVO_STRIDE, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_BVO_BASE_ADDR_HW, pRscConfig->RSC_BVO_BASE_ADDR, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_BVO_STRIDE_HW, pRscConfig->RSC_BVO_STRIDE, CMDQ_REG_MASK); #ifdef RSC_TUNABLE cmdqRecWrite(handle, RSC_MV_OFFSET_HW, pRscConfig->RSC_MV_OFFSET, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_GMV_OFFSET_HW, pRscConfig->RSC_GMV_OFFSET, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_CAND_NUM_HW, pRscConfig->RSC_CAND_NUM, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_RAND_HORZ_LUT_HW, pRscConfig->RSC_RAND_HORZ_LUT, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_RAND_VERT_LUT_HW, pRscConfig->RSC_RAND_VERT_LUT, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_SAD_CTRL_HW, pRscConfig->RSC_SAD_CTRL, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_SAD_EDGE_GAIN_CTRL_HW, pRscConfig->RSC_SAD_EDGE_GAIN_CTRL, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_SAD_CRNR_GAIN_CTRL_HW, pRscConfig->RSC_SAD_CRNR_GAIN_CTRL, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_STILL_STRIP_CTRL_0_HW, pRscConfig->RSC_STILL_STRIP_CTRL0, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_STILL_STRIP_CTRL_1_HW, pRscConfig->RSC_STILL_STRIP_CTRL1, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_RAND_PNLTY_CTRL_HW, pRscConfig->RSC_RAND_PNLTY_CTRL, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_RAND_PNLTY_GAIN_CTRL_0_HW, pRscConfig->RSC_RAND_PNLTY_GAIN_CTRL0, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_RAND_PNLTY_GAIN_CTRL_1_HW, pRscConfig->RSC_RAND_PNLTY_GAIN_CTRL1, CMDQ_REG_MASK); #endif cmdqRecWrite(handle, RSC_DCM_CTL_HW, 0x1111, CMDQ_REG_MASK); cmdqRecWrite(handle, RSC_START_HW, 0x1, CMDQ_REG_MASK); /* RSC Interrupt read-clear mode */ cmdqRecWait(handle, CMDQ_EVENT_RSC_EOF); cmdqRecWrite(handle, RSC_START_HW, 0x0, CMDQ_REG_MASK); /* RSC Interrupt read-clear mode */ #if defined(RSC_PMQOS_EN) && defined(CONFIG_MTK_QOS_SUPPORT) trig_num = (pRscConfig->RSC_CTRL & 0x00000F00) >> 8; w_imgi = pRscConfig->RSC_SIZE & 0x000001FF; h_imgi = (pRscConfig->RSC_SIZE & 0x01FF0000) >> 16; w_mvio = ((w_imgi + 1) >> 1) - 1; w_mvio = ((w_mvio / 7) << 4) + (((((w_mvio % 7) + 1) * 18) + 7) >> 3); h_mvio = (h_imgi + 1) >> 1; w_bvo = (w_imgi + 1) >> 1; h_bvo = (h_imgi + 1) >> 1; dma_bandwidth = ((w_imgi * h_imgi) * 2 + (w_mvio * h_mvio) * 2 * 16 + (w_bvo * h_bvo)) * trig_num * 30 / 1000000; cmdq_task_update_property(handle, &dma_bandwidth, sizeof(unsigned int)); #endif /* non-blocking API, Please use cmdqRecFlushAsync() */ cmdqRecFlushAsync(handle); cmdqRecReset(handle); /* reset the handle to reuse */ cmdqRecDestroy(handle); /* recycle the memory */ #endif return 0; } signed int rsc_feedback(struct frame *frame) { struct RSC_Config *pRscConfig; pRscConfig = (struct RSC_Config *) frame->data; /* TODO: read statistics and write to the frame data */ pRscConfig->RSC_STA_0 = RSC_RD32(RSC_STA_0_REG); return 0; } static const struct engine_ops rsc_ops = { .req_enque_cb = rsc_enque_cb, .req_deque_cb = rsc_deque_cb, .frame_handler = CmdqRSCHW, .req_feedback_cb = rsc_feedback, }; #if CHECK_SERVICE_IF_0 // old cmdq command no more use in this version #if defined(RSC_PMQOS_EN) && defined(CONFIG_MTK_QOS_SUPPORT) void cmdq_pm_qos_start(struct TaskStruct *task, struct TaskStruct *task_list[], u32 size) { unsigned int dma_bandwidth; dma_bandwidth = *(unsigned int *) task->prop_addr; pm_qos_update_request(&rsc_pm_qos_request, dma_bandwidth); LOG_DBG("+ PMQOS Bandwidth : %d MB/sec\n", dma_bandwidth); } void cmdq_pm_qos_stop(struct TaskStruct *task, struct TaskStruct *task_list[], u32 size) { pm_qos_update_request(&rsc_pm_qos_request, 0); LOG_DBG("- PMQOS Bandwidth : %d\n", 0); } #endif #endif /* * */ static signed int RSC_DumpReg(void) #if BYPASS_REG { return 0; } #else { signed int Ret = 0; LOG_INF("- E."); LOG_INF("RSC Config Info\n"); /* RSC Config0 */ LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_CTRL_HW), (unsigned int)RSC_RD32(RSC_CTRL_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_SIZE_HW), (unsigned int)RSC_RD32(RSC_SIZE_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_IMGI_C_BASE_ADDR_HW), (unsigned int)RSC_RD32(RSC_IMGI_C_BASE_ADDR_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_IMGI_C_STRIDE_HW), (unsigned int)RSC_RD32(RSC_IMGI_C_STRIDE_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_IMGI_P_BASE_ADDR_HW), (unsigned int)RSC_RD32(RSC_IMGI_P_BASE_ADDR_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_IMGI_P_STRIDE_HW), (unsigned int)RSC_RD32(RSC_IMGI_P_STRIDE_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_MVI_BASE_ADDR_HW), (unsigned int)RSC_RD32(RSC_MVI_BASE_ADDR_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_MVI_STRIDE_HW), (unsigned int)RSC_RD32(RSC_MVI_STRIDE_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_APLI_C_BASE_ADDR_HW), (unsigned int)RSC_RD32(RSC_APLI_C_BASE_ADDR_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_APLI_P_BASE_ADDR_HW), (unsigned int)RSC_RD32(RSC_APLI_P_BASE_ADDR_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_MVO_BASE_ADDR_HW), (unsigned int)RSC_RD32(RSC_MVO_BASE_ADDR_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_MVO_STRIDE_HW), (unsigned int)RSC_RD32(RSC_MVO_STRIDE_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_BVO_BASE_ADDR_HW), (unsigned int)RSC_RD32(RSC_BVO_BASE_ADDR_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_BVO_STRIDE_HW), (unsigned int)RSC_RD32(RSC_BVO_STRIDE_REG)); LOG_INF("RSC Debug Info\n"); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DBG_INFO_00_HW), (unsigned int)RSC_RD32(RSC_DBG_INFO_00_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DBG_INFO_01_HW), (unsigned int)RSC_RD32(RSC_DBG_INFO_01_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DBG_INFO_02_HW), (unsigned int)RSC_RD32(RSC_DBG_INFO_02_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DBG_INFO_03_HW), (unsigned int)RSC_RD32(RSC_DBG_INFO_03_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DBG_INFO_04_HW), (unsigned int)RSC_RD32(RSC_DBG_INFO_04_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DBG_INFO_05_HW), (unsigned int)RSC_RD32(RSC_DBG_INFO_05_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DBG_INFO_06_HW), (unsigned int)RSC_RD32(RSC_DBG_INFO_06_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DMA_DBG_HW), (unsigned int)RSC_RD32(RSC_DMA_DBG_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DMA_REQ_STATUS_HW), (unsigned int)RSC_RD32(RSC_DMA_REQ_STATUS_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DMA_RDY_STATUS_HW), (unsigned int)RSC_RD32(RSC_DMA_RDY_STATUS_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DMA_DMA_ERR_CTRL_HW), (unsigned int)RSC_RD32(RSC_DMA_DMA_ERR_CTRL_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DMA_RSCI_ERR_STAT_HW), (unsigned int)RSC_RD32(RSC_DMA_RSCI_ERR_STAT_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DMA_RSCO_ERR_STAT_HW), (unsigned int)RSC_RD32(RSC_DMA_RSCO_ERR_STAT_REG)); LOG_INF("[0x%08X %08X]\n", (unsigned int)(RSC_DCM_STAUS_HW), (unsigned int)RSC_RD32(RSC_DCM_STAUS_REG)); LOG_INF("- X."); return Ret; } #endif #if !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK) /*CCF*/ static inline void RSC_Prepare_Enable_ccf_clock(void) { int ret; /* open order:CG_SCP_SYS_MM0>CG_MM_SMI_COMMON>CG_SCP_SYS_ISP>RSC clk */ #ifdef SMI_CLK //smi_bus_prepare_enable(SMI_LARB20, "camera_rsc"); #endif pm_runtime_get_sync(RSC_devs->dev); ret = mtk_smi_larb_get(RSC_devs->larb); if (ret) LOG_ERR("mtk_smi_larb_get larbvdec fail %d\n", ret); ret = clk_prepare_enable(rsc_clk.CG_IPESYS_LARB20); if (ret) LOG_ERR("cannot prepare and enable CG_IPESYS_LARB20 clock\n"); ret = clk_prepare_enable(rsc_clk.CG_IPESYS_RSC); if (ret) LOG_ERR("cannot prepare and enable CG_IPESYS_RSC clock\n"); } static inline void RSC_Disable_Unprepare_ccf_clock(void) { /* close order:RSC clk>CG_SCP_SYS_ISP>CG_MM_SMI_COMMON>CG_SCP_SYS_MM0 */ clk_disable_unprepare(rsc_clk.CG_IPESYS_RSC); clk_disable_unprepare(rsc_clk.CG_IPESYS_LARB20); mtk_smi_larb_put(RSC_devs->larb); #ifdef SMI_CLK //smi_bus_disable_unprepare(SMI_LARB20, "camera_rsc"); pm_runtime_put_sync(RSC_devs->dev); #endif } #endif #ifdef CONFIG_MTK_IOMMU_V2 static inline int m4u_control_iommu_port(void) { struct M4U_PORT_STRUCT sPort; int ret = 0; /* LARB19 */ int count_of_ports = 0; int i = 0; count_of_ports = M4U_PORT_L20_IPE_RSC_WDMA_DISP - M4U_PORT_L20_IPE_RSC_RDMA0_DISP + 1; for (i = 0; i < count_of_ports; i++) { sPort.ePortID = M4U_PORT_L20_IPE_RSC_RDMA0_DISP+i; sPort.Virtuality = RSC_MEM_USE_VIRTUL; LOG_INF("config M4U Port ePortID=%d\n", sPort.ePortID); #if defined(CONFIG_MTK_M4U) || defined(CONFIG_MTK_PSEUDO_M4U) //ret = m4u_config_port(&sPort); if (ret == 0) { LOG_INF("config M4U Port %s to %s SUCCESS\n", //iommu_get_port_name(M4U_PORT_L20_IPE_RSC_RDMA0_DISP+i), RSC_MEM_USE_VIRTUL ? "virtual" : "physical"); } else { LOG_INF("config M4U Port %s to %s FAIL(ret=%d)\n", //iommu_get_port_name(M4U_PORT_L20_IPE_RSC_RDMA0_DISP+i), RSC_MEM_USE_VIRTUL ? "virtual" : "physical", ret); ret = -1; } #endif } return ret; } #endif /******************************************************************************* * ******************************************************************************/ static void RSC_EnableClock(bool En) { #if defined(EP_NO_CLKMGR) unsigned int setReg; #endif #ifdef CONFIG_MTK_IOMMU_V2 int ret = 0; #endif if (En) { /* Enable clock. */ /* LOG_DBG("clock enbled. g_u4EnableClockCount: %d.", g_u4EnableClockCount); */ mutex_lock(&gRscClkMutex); switch (g_u4EnableClockCount) { case 0: #if !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK) /*CCF*/ #ifndef EP_NO_CLKMGR RSC_Prepare_Enable_ccf_clock(); #else /* Enable clock by hardcode: * 1. CAMSYS_CG_CLR (0x1A000008) = 0xffffffff; * 2. IMG_CG_CLR (0x15000008) = 0xffffffff; */ setReg = 0xFFFFFFFF; RSC_WR32(IPESYS_REG_CG_CLR, setReg); #endif #else enable_clock(MT_CG_DRSC0_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) */ break; default: break; } g_u4EnableClockCount++; mutex_unlock(&gRscClkMutex); //dma_set_mask_and_coherent(RSC_devs->dev, DMA_BIT_MASK(34)); #ifdef CONFIG_MTK_IOMMU_V2 if (g_u4EnableClockCount == 1) { ret = m4u_control_iommu_port(); if (ret) LOG_ERR("cannot config M4U IOMMU PORTS\n"); } #endif } else { /* Disable clock. */ /* LOG_DBG("Dpe clock disabled. g_u4EnableClockCount: %d.", * g_u4EnableClockCount); */ mutex_lock(&gRscClkMutex); g_u4EnableClockCount--; switch (g_u4EnableClockCount) { case 0: #if !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK) /*CCF*/ #ifndef EP_NO_CLKMGR RSC_Disable_Unprepare_ccf_clock(); #else /* Disable clock by hardcode: * 1. CAMSYS_CG_SET (0x1A000004) = 0xffffffff; * 2. IMG_CG_SET (0x15000004) = 0xffffffff; */ setReg = 0xFFFFFFFF; RSC_WR32(IPESYS_REG_CG_SET, setReg); #endif #else /* 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_DRSC0_SMI_COMMON, "CAMERA"); #endif break; default: break; } mutex_unlock(&gRscClkMutex); } } /******************************************************************************* * ******************************************************************************/ static inline void RSC_Reset(void) { LOG_INF("- E."); LOG_INF(" RSC Reset start!\n"); spin_lock(&(RSCInfo.SpinLockRSCRef)); if (RSCInfo.UserCount > 1) { spin_unlock(&(RSCInfo.SpinLockRSCRef)); LOG_INF("Curr UserCount(%d) users exist", RSCInfo.UserCount); } else { spin_unlock(&(RSCInfo.SpinLockRSCRef)); /* Reset RSC flow */ RSC_WR32(RSC_RST_REG, 0x1); while ((RSC_RD32(RSC_RST_REG) & 0x02) != 0x2) LOG_INF("RSC resetting...\n"); RSC_WR32(RSC_RST_REG, 0x11); RSC_WR32(RSC_RST_REG, 0x10); RSC_WR32(RSC_RST_REG, 0x0); RSC_WR32(RSC_START_REG, 0); LOG_INF(" RSC Reset end!\n"); } } /******************************************************************************* * ******************************************************************************/ static signed int RSC_ReadReg(struct RSC_REG_IO_STRUCT *pRegIo) { unsigned int i; signed int Ret = 0; struct RSC_REG_STRUCT reg; /* unsigned int* pData = (unsigned int*)pRegIo->Data; */ struct RSC_REG_STRUCT *pData = (struct RSC_REG_STRUCT *) pRegIo->pData; if ((pRegIo->pData == NULL) || (pRegIo->Count == 0) || (pRegIo->Count > (RSC_REG_RANGE>>2))) { LOG_ERR("RSC ReadReg pData is NULL or Count:%d is larger!!", pRegIo->Count); Ret = -EFAULT; goto EXIT; } for (i = 0; i < pRegIo->Count; i++) { if (get_user(reg.Addr, (unsigned int *) &pData->Addr) != 0) { LOG_ERR("get_user failed"); Ret = -EFAULT; goto EXIT; } /* pData++; */ if ((ISP_RSC_BASE + reg.Addr >= ISP_RSC_BASE) && (ISP_RSC_BASE + reg.Addr < (ISP_RSC_BASE + RSC_REG_RANGE)) && ((reg.Addr & 0x3) == 0)) { reg.Val = RSC_RD32(ISP_RSC_BASE + reg.Addr); } else { LOG_ERR( "Wrong address(0x%p)", (ISP_RSC_BASE + reg.Addr)); reg.Val = 0; } if (put_user(reg.Val, (unsigned int *) &(pData->Val)) != 0) { LOG_ERR("put_user failed"); Ret = -EFAULT; goto EXIT; } pData++; } EXIT: return Ret; } /******************************************************************************* * ******************************************************************************/ static signed int RSC_WriteRegToHw(struct RSC_REG_STRUCT *pReg, unsigned int Count) { signed int Ret = 0; unsigned int i; bool dbgWriteReg; spin_lock(&(RSCInfo.SpinLockRSC)); dbgWriteReg = RSCInfo.DebugMask & RSC_DBG_WRITE_REG; spin_unlock(&(RSCInfo.SpinLockRSC)); 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_RSC_BASE + pReg[i].Addr), (unsigned int) (pReg[i].Val)); } if (((ISP_RSC_BASE + pReg[i].Addr) < (ISP_RSC_BASE + RSC_REG_RANGE)) && ((pReg[i].Addr & 0x3) == 0)) { RSC_WR32(ISP_RSC_BASE + pReg[i].Addr, pReg[i].Val); } else { LOG_ERR("wrong address(0x%lx)\n", (unsigned long)(ISP_RSC_BASE + pReg[i].Addr)); } } return Ret; } /******************************************************************************* * ******************************************************************************/ static signed int RSC_WriteReg(struct RSC_REG_IO_STRUCT *pRegIo) { signed int Ret = 0; /* * signed int TimeVd = 0; * signed int TimeExpdone = 0; * signed int TimeTasklet = 0; */ /* unsigned char* pData = NULL; */ struct RSC_REG_STRUCT *pData = NULL; if (RSCInfo.DebugMask & RSC_DBG_WRITE_REG) LOG_DBG("Data(0x%p), Count(%d)\n", (pRegIo->pData), (pRegIo->Count)); pData = kmalloc((pRegIo->Count) * sizeof(struct RSC_REG_STRUCT), GFP_ATOMIC); if (pData == NULL) { LOG_DBG( "ERROR: kmalloc failed, (process, pid, tgid)=(%s, %d, %d)\n", current->comm, current->pid, current->tgid); Ret = -ENOMEM; goto EXIT; } if ((pRegIo->pData == NULL) || (pRegIo->Count == 0) || (pRegIo->Count > (RSC_REG_RANGE>>2))) { LOG_ERR("RSC WriteReg pData is NULL or Count:%d is larger!!", pRegIo->Count); Ret = -EFAULT; goto EXIT; } if (copy_from_user (pData, (void __user *)(pRegIo->pData), pRegIo->Count * sizeof(struct RSC_REG_STRUCT)) != 0) { LOG_ERR("copy_from_user failed\n"); Ret = -EFAULT; goto EXIT; } Ret = RSC_WriteRegToHw(pData, pRegIo->Count); EXIT: if (pData != NULL) { kfree(pData); pData = NULL; } return Ret; } /******************************************************************************* * ******************************************************************************/ static signed int RSC_WaitIrq(struct RSC_WAIT_IRQ_STRUCT *WaitIrq) { signed int Ret = 0; signed int Timeout = WaitIrq->Timeout; enum RSC_PROCESS_ID_ENUM whichReq = RSC_PROCESS_ID_NONE; /*unsigned int i;*/ unsigned long flags; /* old: unsigned int flags;*/ unsigned int irqStatus; /*int cnt = 0;*/ struct timespec64 time_getrequest; ktime_get_ts64(&time_getrequest); /* Debug interrupt */ if (RSCInfo.DebugMask & RSC_DBG_INT) { if (WaitIrq->Status & RSCInfo.IrqInfo.Mask[WaitIrq->Type]) { if (WaitIrq->UserKey > 0) { LOG_DBG( "+WaitIrq clr(%d), Type(%d), Stat(0x%08X), Timeout(%d),usr(%d), ProcID(%d)\n", WaitIrq->Clear, WaitIrq->Type, WaitIrq->Status, WaitIrq->Timeout, WaitIrq->UserKey, WaitIrq->ProcessID); } } } /* 1. wait type update */ if (WaitIrq->Clear == RSC_IRQ_CLEAR_STATUS) { spin_lock_irqsave(&(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); /* LOG_DBG( * "WARNING: Clear(%d), Type(%d): IrqStatus(0x%08X) has been * cleared" ,WaitIrq->EventInfo.Clear,WaitIrq->Type, * RSCInfo.IrqInfo.Status[WaitIrq->Type]); * RSCInfo.IrqInfo.Status[WaitIrq->Type][ * WaitIrq->EventInfo.UserKey] &= (~WaitIrq->EventInfo.Status); */ RSCInfo.IrqInfo.Status[WaitIrq->Type] &= (~WaitIrq->Status); spin_unlock_irqrestore(&(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); return Ret; } if (WaitIrq->Clear == RSC_IRQ_CLEAR_WAIT) { spin_lock_irqsave(&(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); if (RSCInfo.IrqInfo.Status[WaitIrq->Type] & WaitIrq->Status) RSCInfo.IrqInfo.Status[WaitIrq->Type] &= (~WaitIrq->Status); spin_unlock_irqrestore(&(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); } else if (WaitIrq->Clear == RSC_IRQ_CLEAR_ALL) { spin_lock_irqsave(&(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); RSCInfo.IrqInfo.Status[WaitIrq->Type] = 0; spin_unlock_irqrestore(&(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); } /* RSC_IRQ_WAIT_CLEAR ==> do nothing */ /* Store irqinfo status in here to redeuce time of spin_lock_irqsave */ spin_lock_irqsave(&(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); irqStatus = RSCInfo.IrqInfo.Status[WaitIrq->Type]; spin_unlock_irqrestore(&(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); if (WaitIrq->Status & RSC_INT_ST) { whichReq = RSC_PROCESS_ID_RSC; } else { 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); } /* 2. start to wait signal */ Timeout = wait_event_interruptible_timeout(RSCInfo.WaitQueueHead, RSC_GetIRQState( WaitIrq->Type, WaitIrq->UserKey, WaitIrq->Status, whichReq, WaitIrq->ProcessID), RSC_MsToJiffies( WaitIrq->Timeout)); /* check if user is interrupted by system signal */ if ((Timeout != 0) && (!RSC_GetIRQState(WaitIrq->Type, WaitIrq->UserKey, WaitIrq->Status, whichReq, WaitIrq->ProcessID))) { LOG_ERR( "interrupted by system, timeout(%d),irq Type/User/Sts/whichReq/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) { spin_lock_irqsave(&(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); irqStatus = RSCInfo.IrqInfo.Status[WaitIrq->Type]; spin_unlock_irqrestore(&(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); LOG_ERR( "WaitIrq Timeout:Tout(%d) clr(%d) Type(%d) IrqStat(0x%08X) WaitStat(0x%08X) usrKey(%d)\n", WaitIrq->Timeout, WaitIrq->Clear, WaitIrq->Type, irqStatus, WaitIrq->Status, WaitIrq->UserKey); LOG_ERR( "WaitIrq Timeout:whichReq(%d),ProcID(%d) RscIrqCnt(0x%08X) WriteReq(0x%08X) ReadReq(0x%08X)\n", whichReq, WaitIrq->ProcessID, RSCInfo.IrqInfo.RscIrqCnt, RSCInfo.WriteReqIdx, RSCInfo.ReadReqIdx); if (WaitIrq->bDumpReg) { RSC_DumpReg(); request_dump(&rsc_reqs); } Ret = -EFAULT; goto EXIT; } else { #ifdef __RSC_KERNEL_PERFORMANCE_MEASURE__ mt_kernel_trace_begin("%s", __func__); #endif spin_lock_irqsave(&(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); irqStatus = RSCInfo.IrqInfo.Status[WaitIrq->Type]; spin_unlock_irqrestore(&(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); if (WaitIrq->Clear == RSC_IRQ_WAIT_CLEAR) { spin_lock_irqsave(&(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); if (WaitIrq->Status & RSC_INT_ST) { RSCInfo.IrqInfo.RscIrqCnt--; if (RSCInfo.IrqInfo.RscIrqCnt == 0) RSCInfo.IrqInfo.Status[WaitIrq->Type] &= (~WaitIrq->Status); } else { LOG_ERR( "RSC_IRQ_WAIT_CLEAR Error, Type(%d), WaitStatus(0x%08X)", WaitIrq->Type, WaitIrq->Status); } spin_unlock_irqrestore( &(RSCInfo.SpinLockIrq[WaitIrq->Type]), flags); } #ifdef __RSC_KERNEL_PERFORMANCE_MEASURE__ mt_kernel_trace_end(); #endif } EXIT: return Ret; } /******************************************************************************* * ******************************************************************************/ static long RSC_ioctl(struct file *pFile, unsigned int Cmd, unsigned long Param) { signed int Ret = 0; /*unsigned int pid = 0;*/ struct RSC_REG_IO_STRUCT RegIo; struct RSC_WAIT_IRQ_STRUCT IrqInfo; struct RSC_CLEAR_IRQ_STRUCT ClearIrq; struct RSC_Config rsc_RscConfig; struct RSC_Request rsc_RscReq; signed int enqnum; struct RSC_USER_INFO_STRUCT *pUserInfo; int enqueNum; int dequeNum; unsigned long flags; /* old: unsigned int flags;*//* FIX to avoid build warning */ if (pFile->private_data == NULL) { LOG_WRN("private_data NULL,(process, pid, tgid)=(%s, %d, %d)", current->comm, current->pid, current->tgid); return -EFAULT; } pUserInfo = (struct RSC_USER_INFO_STRUCT *) (pFile->private_data); switch (Cmd) { case RSC_RESET: { spin_lock(&(RSCInfo.SpinLockRSC)); RSC_Reset(); spin_unlock(&(RSCInfo.SpinLockRSC)); break; } case RSC_DUMP_REG: { Ret = RSC_DumpReg(); break; } case RSC_DUMP_ISR_LOG: { unsigned int currentPPB = m_CurrentPPB; spin_lock_irqsave( &(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST]), flags); m_CurrentPPB = (m_CurrentPPB + 1) % LOG_PPNUM; spin_unlock_irqrestore( &(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST]), flags); IRQ_LOG_PRINTER(RSC_IRQ_TYPE_INT_RSC_ST, currentPPB, _LOG_INF); IRQ_LOG_PRINTER(RSC_IRQ_TYPE_INT_RSC_ST, currentPPB, _LOG_ERR); break; } case RSC_READ_REGISTER: { if (copy_from_user(&RegIo, (void *)Param, sizeof(struct RSC_REG_IO_STRUCT)) == 0) { Ret = RSC_ReadReg(&RegIo); } else { LOG_ERR( "RSC_READ_REGISTER copy_from_user failed"); Ret = -EFAULT; } break; } case RSC_WRITE_REGISTER: { if (copy_from_user(&RegIo, (void *)Param, sizeof(struct RSC_REG_IO_STRUCT)) == 0) { Ret = RSC_WriteReg(&RegIo); } else { LOG_ERR( "RSC_WRITE_REGISTER copy_from_user failed"); Ret = -EFAULT; } break; } case RSC_WAIT_IRQ: { if (copy_from_user(&IrqInfo, (void *)Param, sizeof(struct RSC_WAIT_IRQ_STRUCT)) == 0) { if ((IrqInfo.Type >= RSC_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( "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 = RSC_WaitIrq(&IrqInfo); if (copy_to_user((void *)Param, &IrqInfo, sizeof(struct RSC_WAIT_IRQ_STRUCT)) != 0) { LOG_ERR("copy_to_user failed\n"); Ret = -EFAULT; } } else { LOG_ERR("RSC_WAIT_IRQ copy_from_user failed"); Ret = -EFAULT; } break; } case RSC_CLEAR_IRQ: { if (copy_from_user(&ClearIrq, (void *)Param, sizeof(struct RSC_CLEAR_IRQ_STRUCT)) == 0) { LOG_DBG("RSC_CLEAR_IRQ Type(%d)", ClearIrq.Type); if ((ClearIrq.Type >= RSC_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( "RSC_CLEAR_IRQ:Type(%d),Status(0x%08X),IrqStatus(0x%08X)\n", ClearIrq.Type, ClearIrq.Status, RSCInfo.IrqInfo.Status[ClearIrq.Type]); spin_lock_irqsave( &(RSCInfo.SpinLockIrq[ClearIrq.Type]), flags); RSCInfo.IrqInfo.Status[ClearIrq.Type] &= (~ClearIrq.Status); spin_unlock_irqrestore( &(RSCInfo.SpinLockIrq[ClearIrq.Type]), flags); } else { LOG_ERR( "RSC_CLEAR_IRQ copy_from_user failed\n"); Ret = -EFAULT; } break; } case RSC_ENQNUE_NUM: { /* enqueNum */ if (copy_from_user(&enqueNum, (void *)Param, sizeof(int)) == 0) { if (RSC_REQUEST_STATE_EMPTY == g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.WriteIdx]. State) { spin_lock_irqsave( &(RSCInfo.SpinLockIrq[ RSC_IRQ_TYPE_INT_RSC_ST]), flags); g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.WriteIdx]. processID = pUserInfo->Pid; g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.WriteIdx]. enqueReqNum = enqueNum; spin_unlock_irqrestore( &(RSCInfo.SpinLockIrq[ RSC_IRQ_TYPE_INT_RSC_ST]), flags); if (enqueNum > _SUPPORT_MAX_RSC_FRAME_REQUEST_) { LOG_ERR( "RSC Enque Num is bigger than enqueNum:%d\n", enqueNum); } LOG_DBG( "RSC_ENQNUE_NUM:%d\n", enqueNum); } else { LOG_ERR( "WFME Enque request state is not empty:%d, writeIdx:%d, readIdx:%d\n", g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.WriteIdx].State, g_RSC_ReqRing.WriteIdx, g_RSC_ReqRing.ReadIdx); } } else { LOG_ERR( "RSC_EQNUE_NUM copy_from_user failed\n"); Ret = -EFAULT; } break; } /* struct RSC_Config */ case RSC_ENQUE: { if (copy_from_user(&rsc_RscConfig, (void *)Param, sizeof(struct RSC_Config)) == 0) { /* LOG_DBG( * "RSC_CLEAR_IRQ:Type(%d),Status(0x%08X), * IrqStatus(0x%08X)", * ClearIrq.Type, ClearIrq.Status, * RSCInfo.IrqInfo.Status[ClearIrq.Type]); */ spin_lock_irqsave( &(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST]), flags); if ((RSC_REQUEST_STATE_EMPTY == g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.WriteIdx].State) && (g_RSC_ReqRing .RSCReq_Struct[g_RSC_ReqRing.WriteIdx] .FrameWRIdx < g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.WriteIdx] .enqueReqNum)) { g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.WriteIdx] .RscFrameStatus[g_RSC_ReqRing .RSCReq_Struct[g_RSC_ReqRing .WriteIdx].FrameWRIdx] = RSC_FRAME_STATUS_ENQUE; memcpy(&g_RSC_ReqRing .RSCReq_Struct[g_RSC_ReqRing .WriteIdx] .RscFrameConfig[g_RSC_ReqRing .RSCReq_Struct[ g_RSC_ReqRing .WriteIdx]. FrameWRIdx++], &rsc_RscConfig, sizeof(struct RSC_Config)); if (g_RSC_ReqRing .RSCReq_Struct[g_RSC_ReqRing .WriteIdx] .FrameWRIdx == g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.WriteIdx] .enqueReqNum) { g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.WriteIdx] .State = RSC_REQUEST_STATE_PENDING; g_RSC_ReqRing.WriteIdx = (g_RSC_ReqRing.WriteIdx + 1) % _SUPPORT_MAX_RSC_REQUEST_RING_SIZE_; LOG_DBG("RSC enque done!!\n"); } else { LOG_DBG("RSC enque frame!!\n"); } } else { LOG_ERR( "No Buffer! WriteIdx(%d), Stat(%d), FrameWRIdx(%d), enqueReqNum(%d)\n", g_RSC_ReqRing.WriteIdx, g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.WriteIdx].State, g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.WriteIdx]. FrameWRIdx, g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.WriteIdx] .enqueReqNum); } spin_unlock_irqrestore( &(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST]), flags); LOG_ERR("ConfigRSC Not Support\n"); } else { LOG_ERR("RSC_ENQUE copy_from_user failed\n"); Ret = -EFAULT; } break; } case RSC_ENQUE_REQ: { if (copy_from_user(&rsc_RscReq, (void *)Param, sizeof(struct RSC_Request)) == 0) { LOG_DBG("RSC_ENQNUE_NUM:%d, pid:%d\n", rsc_RscReq.m_ReqNum, pUserInfo->Pid); if (rsc_RscReq.m_ReqNum > _SUPPORT_MAX_RSC_FRAME_REQUEST_) { LOG_ERR( "RSC Enque Num is bigger than enqueNum:%d\n", rsc_RscReq.m_ReqNum); Ret = -EFAULT; goto EXIT; } if (copy_from_user (g_RscEnqueReq_Struct.RscFrameConfig, (void *)rsc_RscReq.m_pRscConfig, rsc_RscReq.m_ReqNum * sizeof(struct RSC_Config)) != 0) { LOG_ERR( "copy RSCConfig from request fail!!\n"); Ret = -EFAULT; goto EXIT; } mutex_lock(&gRscMutex); spin_lock_irqsave( &(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST]), flags); kRscReq.m_ReqNum = rsc_RscReq.m_ReqNum; kRscReq.m_pRscConfig = g_RscEnqueReq_Struct.RscFrameConfig; enqnum = enque_request(&rsc_reqs, kRscReq.m_ReqNum, &kRscReq, pUserInfo->Pid); spin_unlock_irqrestore( &(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST]), flags); LOG_DBG("Config RSC Request!!\n"); /* Use a workqueue to set CMDQ to prevent * HW CMDQ request consuming speed from being * faster than SW frame-queue update speed. */ if (!request_running(&rsc_reqs)) { LOG_DBG("direct request_handler\n"); request_handler(&rsc_reqs, &(RSCInfo .SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST])); } mutex_unlock(&gRscMutex); } else { LOG_ERR( "RSC_ENQUE_REQ copy_from_user failed\n"); Ret = -EFAULT; } break; } case RSC_DEQUE_NUM: { if (RSC_REQUEST_STATE_FINISHED == g_RSC_ReqRing.RSCReq_Struct[g_RSC_ReqRing.ReadIdx] .State) { dequeNum = g_RSC_ReqRing .RSCReq_Struct[g_RSC_ReqRing.ReadIdx] .enqueReqNum; LOG_DBG("RSC_DEQUE_NUM(%d)\n", dequeNum); } else { dequeNum = 0; LOG_ERR( "DEQUE_NUM:No Buffer: ReadIdx(%d) State(%d) RrameRDIdx(%d) enqueReqNum(%d)\n", g_RSC_ReqRing.ReadIdx, g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx].State, g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx].RrameRDIdx, g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx].enqueReqNum); } if (copy_to_user((void *)Param, &dequeNum, sizeof(unsigned int)) != 0) { LOG_ERR("RSC_DEQUE_NUM copy_to_user failed\n"); Ret = -EFAULT; } break; } case RSC_DEQUE: { spin_lock_irqsave( &(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST]), flags); if ((RSC_REQUEST_STATE_FINISHED == g_RSC_ReqRing.RSCReq_Struct[g_RSC_ReqRing.ReadIdx] .State) && (g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx].RrameRDIdx < g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx].enqueReqNum)) { if (RSC_FRAME_STATUS_FINISHED == g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx] .RscFrameStatus[g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx].RrameRDIdx]) { memcpy(&rsc_RscConfig, &g_RSC_ReqRing .RSCReq_Struct[ g_RSC_ReqRing.ReadIdx] .RscFrameConfig[ g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx] .RrameRDIdx], sizeof(struct RSC_Config)); g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx] .RscFrameStatus[ g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx].RrameRDIdx++] = RSC_FRAME_STATUS_EMPTY; } if (g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx].RrameRDIdx == g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx].enqueReqNum) { g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx].State = RSC_REQUEST_STATE_EMPTY; g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx].FrameWRIdx = 0; g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx].RrameRDIdx = 0; g_RSC_ReqRing.RSCReq_Struct[ g_RSC_ReqRing.ReadIdx].enqueReqNum = 0; g_RSC_ReqRing.ReadIdx = (g_RSC_ReqRing.ReadIdx + 1) % _SUPPORT_MAX_RSC_REQUEST_RING_SIZE_; LOG_DBG("RSC ReadIdx(%d)\n", g_RSC_ReqRing.ReadIdx); } spin_unlock_irqrestore( &(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST]), flags); if (copy_to_user ((void *)Param, &g_RSC_ReqRing .RSCReq_Struct[g_RSC_ReqRing.ReadIdx] .RscFrameConfig[g_RSC_ReqRing .RSCReq_Struct[g_RSC_ReqRing.ReadIdx] .RrameRDIdx], sizeof(struct RSC_Config)) != 0) { LOG_ERR( "RSC_DEQUE copy_to_user fail\n"); Ret = -EFAULT; } } else { spin_unlock_irqrestore( &(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST]), flags); LOG_ERR("RSC_DEQUE No Buf: (%d)(%d)(%d)(%d)\n", g_RSC_ReqRing.ReadIdx, g_RSC_ReqRing.RSCReq_Struct[g_RSC_ReqRing .ReadIdx].State, g_RSC_ReqRing.RSCReq_Struct[g_RSC_ReqRing .ReadIdx].RrameRDIdx, g_RSC_ReqRing.RSCReq_Struct[g_RSC_ReqRing .ReadIdx].enqueReqNum); } break; } case RSC_DEQUE_REQ: { if (copy_from_user(&rsc_RscReq, (void *)Param, sizeof(struct RSC_Request)) == 0) { mutex_lock(&gRscDequeMutex); spin_lock_irqsave( &(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST]), flags); kRscReq.m_pRscConfig = g_RscDequeReq_Struct.RscFrameConfig; deque_request(&rsc_reqs, &kRscReq.m_ReqNum, &kRscReq); dequeNum = kRscReq.m_ReqNum; rsc_RscReq.m_ReqNum = dequeNum; spin_unlock_irqrestore( &(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST]), flags); mutex_unlock(&gRscDequeMutex); if (rsc_RscReq.m_pRscConfig == NULL) { LOG_ERR("NULL ptr:RscReq.m_pRscConfig"); Ret = -EFAULT; goto EXIT; } if (copy_to_user ((void *)rsc_RscReq.m_pRscConfig, &g_RscDequeReq_Struct.RscFrameConfig[0], dequeNum * sizeof(struct RSC_Config)) != 0) { LOG_ERR ("RSC_DEQUE_REQ frmcfg failed\n"); Ret = -EFAULT; } if (copy_to_user ((void *)Param, &rsc_RscReq, sizeof(struct RSC_Request)) != 0) { LOG_ERR("RSC_DEQUE_REQ RscReq fail\n"); Ret = -EFAULT; } } else { LOG_ERR("RSC_CMD_RSC_DEQUE_REQ failed\n"); Ret = -EFAULT; } break; } default: { LOG_ERR("Unknown Cmd(%d)", Cmd); LOG_ERR("Cmd(%d),Dir(%d),Typ(%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), (proc, pid, tgid)=(%s, %d, %d)", Cmd, pUserInfo->Pid, current->comm, current->pid, current->tgid); } return Ret; } #ifdef CONFIG_COMPAT /******************************************************************************* * ******************************************************************************/ static int compat_get_RSC_read_register_data( struct compat_RSC_REG_IO_STRUCT __user *data32, struct RSC_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_RSC_read_register_data( struct compat_RSC_REG_IO_STRUCT __user *data32, struct RSC_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_RSC_enque_req_data( struct compat_RSC_Request __user *data32, struct RSC_Request __user *data) { compat_uint_t count; compat_uptr_t uptr; int err = 0; err = get_user(uptr, &data32->m_pRscConfig); err |= put_user(compat_ptr(uptr), &data->m_pRscConfig); err |= get_user(count, &data32->m_ReqNum); err |= put_user(count, &data->m_ReqNum); return err; } static int compat_put_RSC_enque_req_data( struct compat_RSC_Request __user *data32, struct RSC_Request __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_pDpeConfig); */ /* err |= put_user(uptr, &data32->m_pDpeConfig); */ err |= get_user(count, &data->m_ReqNum); err |= put_user(count, &data32->m_ReqNum); return err; } static int compat_get_RSC_deque_req_data( struct compat_RSC_Request __user *data32, struct RSC_Request __user *data) { compat_uint_t count; compat_uptr_t uptr; int err = 0; err = get_user(uptr, &data32->m_pRscConfig); err |= put_user(compat_ptr(uptr), &data->m_pRscConfig); err |= get_user(count, &data32->m_ReqNum); err |= put_user(count, &data->m_ReqNum); return err; } static int compat_put_RSC_deque_req_data( struct compat_RSC_Request __user *data32, struct RSC_Request __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_pDpeConfig); */ /* err |= put_user(uptr, &data32->m_pDpeConfig); */ err |= get_user(count, &data->m_ReqNum); err |= put_user(count, &data32->m_ReqNum); return err; } static long RSC_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_RSC_READ_REGISTER: { struct compat_RSC_REG_IO_STRUCT __user *data32; struct RSC_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_RSC_read_register_data(data32, data); if (err) { LOG_ERR("compat_get_read_register_data err.\n"); return err; } ret = filp->f_op->unlocked_ioctl(filp, RSC_READ_REGISTER, (unsigned long)data); err = compat_put_RSC_read_register_data(data32, data); if (err) { LOG_ERR("compat_put_read_register_data err.\n"); return err; } return ret; } case COMPAT_RSC_WRITE_REGISTER: { struct compat_RSC_REG_IO_STRUCT __user *data32; struct RSC_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_RSC_read_register_data(data32, data); if (err) { LOG_ERR("COMPAT_RSC_WRITE_REGISTER error!!!\n"); return err; } ret = filp->f_op->unlocked_ioctl(filp, RSC_WRITE_REGISTER, (unsigned long)data); return ret; } case COMPAT_RSC_ENQUE_REQ: { struct compat_RSC_Request __user *data32; struct RSC_Request __user *data; int err; data32 = compat_ptr(arg); data = compat_alloc_user_space(sizeof(*data)); if (data == NULL) return -EFAULT; err = compat_get_RSC_enque_req_data(data32, data); if (err) { LOG_ERR("COMPAT_RSC_ENQUE_REQ error!!!\n"); return err; } ret = filp->f_op->unlocked_ioctl(filp, RSC_ENQUE_REQ, (unsigned long)data); err = compat_put_RSC_enque_req_data(data32, data); if (err) { LOG_ERR("COMPAT_RSC_ENQUE_REQ error!!!\n"); return err; } return ret; } case COMPAT_RSC_DEQUE_REQ: { struct compat_RSC_Request __user *data32; struct RSC_Request __user *data; int err; data32 = compat_ptr(arg); data = compat_alloc_user_space(sizeof(*data)); if (data == NULL) return -EFAULT; err = compat_get_RSC_deque_req_data(data32, data); if (err) { LOG_ERR("COMPAT_RSC_DEQUE_REQ error!!!\n"); return err; } ret = filp->f_op->unlocked_ioctl(filp, RSC_DEQUE_REQ, (unsigned long)data); err = compat_put_RSC_deque_req_data(data32, data); if (err) { LOG_ERR("COMPAT_RSC_DEQUE_REQ error!!!\n"); return err; } return ret; } case RSC_WAIT_IRQ: case RSC_CLEAR_IRQ: /* structure (no pointer) */ case RSC_ENQNUE_NUM: case RSC_ENQUE: case RSC_DEQUE_NUM: case RSC_DEQUE: case RSC_RESET: case RSC_DUMP_REG: case RSC_DUMP_ISR_LOG: return filp->f_op->unlocked_ioctl(filp, cmd, arg); default: return -ENOIOCTLCMD; /* return RSC_ioctl(filep, cmd, arg); */ } } #endif /******************************************************************************* * ******************************************************************************/ static signed int RSC_open(struct inode *pInode, struct file *pFile) { signed int Ret = 0; unsigned int i, j; /*int q = 0, p = 0;*/ struct RSC_USER_INFO_STRUCT *pUserInfo; LOG_DBG("- E. UserCount: %d.", RSCInfo.UserCount); spin_lock(&(RSCInfo.SpinLockRSCRef)); pFile->private_data = NULL; pFile->private_data = kmalloc(sizeof(struct RSC_USER_INFO_STRUCT), GFP_ATOMIC); if (pFile->private_data == NULL) { LOG_DBG("kmalloc failed, (proc, pid, tgid)=(%s, %d, %d)", current->comm, current->pid, current->tgid); Ret = -ENOMEM; } else { pUserInfo = (struct RSC_USER_INFO_STRUCT *) pFile->private_data; pUserInfo->Pid = current->pid; pUserInfo->Tid = current->tgid; } if (RSCInfo.UserCount > 0) { RSCInfo.UserCount++; spin_unlock(&(RSCInfo.SpinLockRSCRef)); LOG_DBG("Cur Usr(%d), (proc, pid, tgid)=(%s, %d, %d), exist", RSCInfo.UserCount, current->comm, current->pid, current->tgid); goto EXIT; } else { RSCInfo.UserCount++; spin_unlock(&(RSCInfo.SpinLockRSCRef)); LOG_DBG("Cur Usr(%d), (proc, pid, tgid)=(%s, %d, %d), 1st user", RSCInfo.UserCount, current->comm, current->pid, current->tgid); } /* do wait queue head init when re-enter in camera */ for (i = 0; i < _SUPPORT_MAX_RSC_REQUEST_RING_SIZE_; i++) { /* RSC */ g_RSC_ReqRing.RSCReq_Struct[i].processID = 0x0; g_RSC_ReqRing.RSCReq_Struct[i].callerID = 0x0; g_RSC_ReqRing.RSCReq_Struct[i].enqueReqNum = 0x0; /* g_RSC_ReqRing.RSCReq_Struct[i].enqueIdx = 0x0; */ g_RSC_ReqRing.RSCReq_Struct[i].State = RSC_REQUEST_STATE_EMPTY; g_RSC_ReqRing.RSCReq_Struct[i].FrameWRIdx = 0x0; g_RSC_ReqRing.RSCReq_Struct[i].RrameRDIdx = 0x0; for (j = 0; j < _SUPPORT_MAX_RSC_FRAME_REQUEST_; j++) { g_RSC_ReqRing.RSCReq_Struct[i].RscFrameStatus[j] = RSC_FRAME_STATUS_EMPTY; } } g_RSC_ReqRing.WriteIdx = 0x0; g_RSC_ReqRing.ReadIdx = 0x0; g_RSC_ReqRing.HWProcessIdx = 0x0; /* Enable clock */ RSC_EnableClock(MTRUE); g_SuspendCnt = 0; LOG_INF("RSC open g_u4EnableClockCount: %d", g_u4EnableClockCount); for (i = 0; i < RSC_IRQ_TYPE_AMOUNT; i++) RSCInfo.IrqInfo.Status[i] = 0; for (i = 0; i < _SUPPORT_MAX_RSC_FRAME_REQUEST_; i++) RSCInfo.ProcessID[i] = 0; RSCInfo.WriteReqIdx = 0; RSCInfo.ReadReqIdx = 0; RSCInfo.IrqInfo.RscIrqCnt = 0; /*#define KERNEL_LOG*/ #ifdef KERNEL_LOG /* In EP, Add RSC_DBG_WRITE_REG for debug. Should remove it after EP */ RSCInfo.DebugMask = (RSC_DBG_INT | RSC_DBG_DBGLOG | RSC_DBG_WRITE_REG); #endif register_requests(&rsc_reqs, sizeof(struct RSC_Config)); set_engine_ops(&rsc_reqs, &rsc_ops); EXIT: LOG_DBG("- X. Ret: %d. UserCount: %d.", Ret, RSCInfo.UserCount); return Ret; } /****************************************************************************** * ******************************************************************************/ static signed int RSC_release(struct inode *pInode, struct file *pFile) { struct RSC_USER_INFO_STRUCT *pUserInfo; /*unsigned int Reg;*/ LOG_DBG("- E. UserCount: %d.", RSCInfo.UserCount); if (pFile->private_data != NULL) { pUserInfo = (struct RSC_USER_INFO_STRUCT *) pFile->private_data; kfree(pFile->private_data); pFile->private_data = NULL; } spin_lock(&(RSCInfo.SpinLockRSCRef)); RSCInfo.UserCount--; if (RSCInfo.UserCount > 0) { spin_unlock(&(RSCInfo.SpinLockRSCRef)); LOG_DBG("Cur UsrCnt(%d), (proc, pid, tgid)=(%s, %d, %d), exist", RSCInfo.UserCount, current->comm, current->pid, current->tgid); goto EXIT; } else spin_unlock(&(RSCInfo.SpinLockRSCRef)); LOG_INF("Curr UsrCnt(%d), (process, pid, tgid)=(%s, %d, %d), last user", RSCInfo.UserCount, current->comm, current->pid, current->tgid); /* Disable clock. */ RSC_EnableClock(MFALSE); LOG_DBG("RSC release g_u4EnableClockCount: %d", g_u4EnableClockCount); unregister_requests(&rsc_reqs); EXIT: LOG_DBG("- X. UserCount: %d.", RSCInfo.UserCount); return 0; } /******************************************************************************* * ******************************************************************************/ static signed int RSC_mmap(struct file *pFile, struct vm_area_struct *pVma) { unsigned long length = 0; unsigned long pfn = 0x0; length = pVma->vm_end - pVma->vm_start; pVma->vm_page_prot = pgprot_noncached(pVma->vm_page_prot); pfn = pVma->vm_pgoff << PAGE_SHIFT; LOG_INF( "mmap:vm_pgoff(0x%lx) pfn(0x%lx) phy(0x%lx) vm_start(0x%lx) vm_end(0x%lx) length(0x%lx)", pVma->vm_pgoff, pfn, pVma->vm_pgoff << PAGE_SHIFT, pVma->vm_start, pVma->vm_end, length); switch (pfn) { case RSC_BASE_HW: if (length > RSC_REG_RANGE) { LOG_ERR("mmap err:mod:0x%lx len:0x%lx,REG_RANGE:0x%x", pfn, length, RSC_REG_RANGE); return -EAGAIN; } break; default: LOG_ERR("Illegal starting HW addr for mmap!"); return -EAGAIN; } if (remap_pfn_range (pVma, pVma->vm_start, pVma->vm_pgoff, pVma->vm_end - pVma->vm_start, pVma->vm_page_prot)) { return -EAGAIN; } return 0; } /******************************************************************************* * ******************************************************************************/ static dev_t RSCDevNo; static struct cdev *pRSCCharDrv; static struct class *pRSCClass; static const struct file_operations RSCFileOper = { .owner = THIS_MODULE, .open = RSC_open, .release = RSC_release, /* .flush = mt_RSC_flush, */ .mmap = RSC_mmap, .unlocked_ioctl = RSC_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = RSC_ioctl_compat, #endif }; /******************************************************************************* * ******************************************************************************/ static inline void RSC_UnregCharDev(void) { LOG_DBG("- E."); /* Release char driver */ if (pRSCCharDrv != NULL) { cdev_del(pRSCCharDrv); pRSCCharDrv = NULL; } unregister_chrdev_region(RSCDevNo, 1); } /******************************************************************************* * ******************************************************************************/ static inline signed int RSC_RegCharDev(void) { signed int Ret = 0; LOG_DBG("- E."); Ret = alloc_chrdev_region(&RSCDevNo, 0, 1, RSC_DEV_NAME); if (Ret < 0) { LOG_ERR("alloc_chrdev_region failed, %d", Ret); return Ret; } /* Allocate driver */ pRSCCharDrv = cdev_alloc(); if (pRSCCharDrv == NULL) { LOG_ERR("cdev_alloc failed"); Ret = -ENOMEM; goto EXIT; } /* Attatch file operation. */ cdev_init(pRSCCharDrv, &RSCFileOper); pRSCCharDrv->owner = THIS_MODULE; /* Add to system */ Ret = cdev_add(pRSCCharDrv, RSCDevNo, 1); if (Ret < 0) { LOG_ERR("Attatch file operation failed, %d", Ret); goto EXIT; } EXIT: if (Ret < 0) RSC_UnregCharDev(); LOG_DBG("- X."); return Ret; } /******************************************************************************* * ******************************************************************************/ static signed int RSC_probe(struct platform_device *pDev) { signed int Ret = 0; struct device_node *node = NULL; struct platform_device *pdev = NULL; /*struct resource *pRes = NULL;*/ signed int i = 0; unsigned char n; unsigned int irq_info[3]; struct device *dev = NULL; struct RSC_device *_rsc_dev = NULL; #ifdef CONFIG_OF struct RSC_device *RSC_dev; #endif LOG_INF("- E. RSC driver probe.\n"); /* Check platform_device parameters */ #ifdef CONFIG_OF if (pDev == NULL) { dev_dbg(&pDev->dev, "pDev is NULL"); return -ENXIO; } nr_RSC_devs += 1; _rsc_dev = krealloc(RSC_devs, sizeof(struct RSC_device) * nr_RSC_devs, GFP_KERNEL); if (!_rsc_dev) { dev_dbg(&pDev->dev, "Unable to allocate RSC_devs\n"); return -ENOMEM; } RSC_devs = _rsc_dev; RSC_dev = &(RSC_devs[nr_RSC_devs - 1]); RSC_dev->dev = &pDev->dev; dma_set_mask_and_coherent(RSC_devs->dev, DMA_BIT_MASK(34)); /* iomap registers */ RSC_dev->regs = of_iomap(pDev->dev.of_node, 0); if (!RSC_dev->regs) { dev_dbg(&pDev->dev, "of_iomap fail, nr_RSC_devs=%d, devnode(%s).\n", nr_RSC_devs, pDev->dev.of_node->name); return -ENOMEM; } /*temperate: power for larb20*/ node = of_parse_phandle(RSC_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); RSC_devs->larb = &pdev->dev; #if defined(CONFIG_MTK_IOMMU_PGTABLE_EXT) && \ (CONFIG_MTK_IOMMU_PGTABLE_EXT > 32) *(RSC_dev->dev->dma_mask) = (u64)DMA_BIT_MASK(CONFIG_MTK_IOMMU_PGTABLE_EXT); RSC_dev->dev->coherent_dma_mask = (u64)DMA_BIT_MASK(CONFIG_MTK_IOMMU_PGTABLE_EXT); #endif LOG_INF("nr_RSC_devs=%d, devnode(%s), map_addr=0x%lx\n", nr_RSC_devs, pDev->dev.of_node->name, (unsigned long)RSC_dev->regs); /* get IRQ ID and request IRQ */ RSC_dev->irq = irq_of_parse_and_map(pDev->dev.of_node, 0); if (RSC_dev->irq > 0) { LOG_INF("- E. RSC setup irq.\n"); /* 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 < RSC_IRQ_TYPE_AMOUNT; i++) { if (strcmp(pDev->dev.of_node->name, RSC_IRQ_CB_TBL[i].device_name) == 0) { Ret = request_irq(RSC_dev->irq, (irq_handler_t) RSC_IRQ_CB_TBL[i].isr_fp, irq_info[2], (const char *)RSC_IRQ_CB_TBL[i] .device_name, NULL); if (Ret) { dev_dbg(&pDev->dev, "nr_RSC_devs=%d, devnode(%s), irq=%d, ISR: %s\n", nr_RSC_devs, pDev->dev.of_node->name, RSC_dev->irq, RSC_IRQ_CB_TBL[i].device_name); return Ret; } LOG_INF( "nr_RSC_devs=%d, devnode(%s), irq=%d, ISR: %s\n", nr_RSC_devs, pDev->dev.of_node->name, RSC_dev->irq, RSC_IRQ_CB_TBL[i].device_name); break; } } if (i >= RSC_IRQ_TYPE_AMOUNT) { LOG_INF("No ISR:nr_RSC_devs=%d, devnode(%s), irq=%d\n", nr_RSC_devs, pDev->dev.of_node->name, RSC_dev->irq); } } else { LOG_INF("No IRQ!!: nr_RSC_devs=%d, devnode(%s), irq=%d\n", nr_RSC_devs, pDev->dev.of_node->name, RSC_dev->irq); } #endif /* Only register char driver in the 1st time */ if (nr_RSC_devs == 1) { /* Register char driver */ Ret = RSC_RegCharDev(); if (Ret) { dev_dbg(&pDev->dev, "register char failed"); return Ret; } #ifndef EP_NO_CLKMGR #if !defined(CONFIG_MTK_LEGACY) && defined(CONFIG_COMMON_CLK) /*CCF*/ /*CCF: Grab clock pointer (struct clk*) */ rsc_clk.CG_IPESYS_LARB20 = devm_clk_get(&pDev->dev, "RSC_CLK_IPE_LARB20"); if (IS_ERR(rsc_clk.CG_IPESYS_LARB20)) { LOG_ERR("cannot get CG_IPESYS_LARB20 clock\n"); return PTR_ERR(rsc_clk.CG_IPESYS_LARB20); } rsc_clk.CG_IPESYS_RSC = devm_clk_get(&pDev->dev, "RSC_CLK_IPE_RSC"); if (IS_ERR(rsc_clk.CG_IPESYS_RSC)) { LOG_ERR("cannot get CG_IPESYS_RSC clock\n"); return PTR_ERR(rsc_clk.CG_IPESYS_RSC); } #endif #endif /* Create class register */ pRSCClass = class_create(THIS_MODULE, "RSCdrv"); if (IS_ERR(pRSCClass)) { Ret = PTR_ERR(pRSCClass); LOG_ERR("Unable to create class, err = %d", Ret); goto EXIT; } dev = device_create(pRSCClass, NULL, RSCDevNo, NULL, RSC_DEV_NAME); if (IS_ERR(dev)) { Ret = PTR_ERR(dev); dev_dbg(&pDev->dev, "create dev err: /dev/%s, err = %d", RSC_DEV_NAME, Ret); goto EXIT; } pm_runtime_enable(RSC_devs->dev); /* Init spinlocks */ spin_lock_init(&(RSCInfo.SpinLockRSCRef)); spin_lock_init(&(RSCInfo.SpinLockRSC)); for (n = 0; n < RSC_IRQ_TYPE_AMOUNT; n++) spin_lock_init(&(RSCInfo.SpinLockIrq[n])); init_waitqueue_head(&RSCInfo.WaitQueueHead); INIT_WORK(&RSCInfo.ScheduleRscWork, RSC_ScheduleWork); RSCInfo.wkqueue = create_singlethread_workqueue("RSC-CMDQ-WQ"); if (!RSCInfo.wkqueue) LOG_ERR("NULL RSC-CMDQ-WQ\n"); //wakeup_source_init(&RSC_wake_lock, "rsc_lock_wakelock"); INIT_WORK(&logWork, logPrint); for (i = 0; i < RSC_IRQ_TYPE_AMOUNT; i++) tasklet_init(RSC_tasklet[i].pRSC_tkt, RSC_tasklet[i].tkt_cb, 0); /* Init RSCInfo */ spin_lock(&(RSCInfo.SpinLockRSCRef)); RSCInfo.UserCount = 0; spin_unlock(&(RSCInfo.SpinLockRSCRef)); RSCInfo.IrqInfo.Mask[RSC_IRQ_TYPE_INT_RSC_ST] = INT_ST_MASK_RSC; #if defined(RSC_PMQOS_EN) && defined(CONFIG_MTK_QOS_SUPPORT) pm_qos_add_request(&rsc_pm_qos_request, PM_QOS_MM_MEMORY_BANDWIDTH, PM_QOS_DEFAULT_VALUE); #if CHECK_SERVICE_IF_0 // old cmdq command and no more use cmdqCoreRegisterTaskCycleCB(CMDQ_GROUP_RSC, cmdq_pm_qos_start, cmdq_pm_qos_stop); #endif #endif seqlock_init(&(rsc_reqs.seqlock)); /* init cmdq */ cmdq_base = NULL; cmdq_base = cmdq_register_device(&pDev->dev); cmdq_clt = cmdq_mbox_create(&pDev->dev, 0); cmdq_event_id = cmdq_dev_get_event(&pDev->dev, "rsc_eof"); } EXIT: if (Ret < 0) RSC_UnregCharDev(); LOG_INF("- X. RSC driver probe."); return Ret; } /******************************************************************************* * Called when the device is being detached from the driver ******************************************************************************/ static signed int RSC_remove(struct platform_device *pDev) { /*struct resource *pRes;*/ signed int IrqNum; int i; LOG_DBG("- E."); /* wait for unfinished works in the workqueue. */ destroy_workqueue(RSCInfo.wkqueue); RSCInfo.wkqueue = NULL; /* unregister char driver. */ RSC_UnregCharDev(); /* Release IRQ */ disable_irq(RSCInfo.IrqNum); IrqNum = platform_get_irq(pDev, 0); free_irq(IrqNum, NULL); /* kill tasklet */ for (i = 0; i < RSC_IRQ_TYPE_AMOUNT; i++) tasklet_kill(RSC_tasklet[i].pRSC_tkt); #if CHECK_SERVICE_IF_0 /* free all registered irq(child nodes) */ RSC_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(pRSCClass, RSCDevNo); class_destroy(pRSCClass); pRSCClass = NULL; #if defined(RSC_PMQOS_EN) && defined(CONFIG_MTK_QOS_SUPPORT) pm_qos_remove_request(&rsc_pm_qos_request); #endif return 0; } /******************************************************************************* * ******************************************************************************/ static signed int bPass1_On_In_Resume_TG1; static signed int RSC_suspend(struct platform_device *pDev, pm_message_t Mesg) { /*signed int ret = 0;*/ LOG_DBG("bPass1_On_In_Resume_TG1(%d)\n", bPass1_On_In_Resume_TG1); if (g_u4EnableClockCount > 0) { RSC_EnableClock(MFALSE); g_SuspendCnt++; } bPass1_On_In_Resume_TG1 = 0; LOG_INF("%s:g_u4EnableClockCount(%d) g_SuspendCnt(%d).\n", __func__, g_u4EnableClockCount, g_SuspendCnt); return 0; } /******************************************************************************* * ******************************************************************************/ static signed int RSC_resume(struct platform_device *pDev) { LOG_DBG("bPass1_On_In_Resume_TG1(%d).\n", bPass1_On_In_Resume_TG1); if (g_SuspendCnt > 0) { RSC_EnableClock(MTRUE); g_SuspendCnt--; } LOG_INF("%s:g_u4EnableClockCount(%d) g_SuspendCnt(%d).\n", __func__, g_u4EnableClockCount, g_SuspendCnt); return 0; } /*---------------------------------------------------------------------------*/ #ifdef CONFIG_PM /*---------------------------------------------------------------------------*/ int RSC_pm_suspend(struct device *device) { struct platform_device *pdev = to_platform_device(device); WARN_ON(pdev == NULL); LOG_DBG("calling %s()\n", __func__); return RSC_suspend(pdev, PMSG_SUSPEND); } int RSC_pm_resume(struct device *device) { struct platform_device *pdev = to_platform_device(device); WARN_ON(pdev == NULL); LOG_DBG("calling %s()\n", __func__); return RSC_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 RSC_pm_restore_noirq(struct device *device) { pr_debug("calling %s()\n", __func__); #ifndef CONFIG_OF /* mt_irq_set_sens(RSC_IRQ_BIT_ID, MT_LEVEL_SENSITIVE);*/ /* mt_irq_set_polarity(RSC_IRQ_BIT_ID, MT_POLARITY_LOW);*/ #endif return 0; } /*---------------------------------------------------------------------------*/ #else /*CONFIG_PM */ /*---------------------------------------------------------------------------*/ #define RSC_pm_suspend NULL #define RSC_pm_resume NULL #define RSC_pm_restore_noirq NULL /*---------------------------------------------------------------------------*/ #endif /*CONFIG_PM */ /*---------------------------------------------------------------------------*/ #ifdef CONFIG_OF static const struct of_device_id RSC_of_ids[] = { /* {.compatible = "mediatek,ipesys_config",},*/ {.compatible = "mediatek,rsc",}, {} }; #endif const struct dev_pm_ops RSC_pm_ops = { .suspend = RSC_pm_suspend, .resume = RSC_pm_resume, .freeze = RSC_pm_suspend, .thaw = RSC_pm_resume, .poweroff = RSC_pm_suspend, .restore = RSC_pm_resume, .restore_noirq = RSC_pm_restore_noirq, }; /******************************************************************************* * ******************************************************************************/ static struct platform_driver RSCDriver = { .probe = RSC_probe, .remove = RSC_remove, .suspend = RSC_suspend, .resume = RSC_resume, .driver = { .name = RSC_DEV_NAME, .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = RSC_of_ids, #endif #ifdef CONFIG_PM .pm = &RSC_pm_ops, #endif } }; static int rsc_dump_read(struct seq_file *m, void *v) { int i, j; if (RSCInfo.UserCount <= 0) return 0; spin_lock(&(RSCInfo.SpinLockRSC)); if (g_u4EnableClockCount == 0) { spin_unlock(&(RSCInfo.SpinLockRSC)); return 0; } spin_unlock(&(RSCInfo.SpinLockRSC)); seq_puts(m, "\n============ rsc dump register============\n"); seq_puts(m, "RSC Config Info\n"); for (i = 0x2C; i < 0x8C; i = i + 4) { seq_printf(m, "[0x%08X %08X]\n", (unsigned int)(RSC_BASE_HW + i), (unsigned int)RSC_RD32(ISP_RSC_BASE + i)); } seq_puts(m, "RSC Debug Info\n"); for (i = 0x120; i < 0x148; i = i + 4) { seq_printf(m, "[0x%08X %08X]\n", (unsigned int)(RSC_BASE_HW + i), (unsigned int)RSC_RD32(ISP_RSC_BASE + i)); } seq_puts(m, "RSC Config Info\n"); for (i = 0x230; i < 0x2D8; i = i + 4) { seq_printf(m, "[0x%08X %08X]\n", (unsigned int)(RSC_BASE_HW + i), (unsigned int)RSC_RD32(ISP_RSC_BASE + i)); } seq_puts(m, "RSC Debug Info\n"); for (i = 0x2F4; i < 0x30C; i = i + 4) { seq_printf(m, "[0x%08X %08X]\n", (unsigned int)(RSC_BASE_HW + i), (unsigned int)RSC_RD32(ISP_RSC_BASE + i)); } seq_puts(m, "\n"); seq_printf(m, "Dpe Clock Count:%d\n", g_u4EnableClockCount); seq_printf(m, "[0x%08X %08X]\n", (unsigned int)(RSC_DMA_DBG_HW), (unsigned int)RSC_RD32(RSC_DMA_DBG_REG)); seq_printf(m, "[0x%08X %08X]\n", (unsigned int)(RSC_DMA_REQ_STATUS_HW), (unsigned int)RSC_RD32(RSC_DMA_REQ_STATUS_REG)); seq_printf(m, "[0x%08X %08X]\n", (unsigned int)(RSC_DMA_RDY_STATUS_HW), (unsigned int)RSC_RD32(RSC_DMA_RDY_STATUS_REG)); seq_printf(m, "[0x%08X %08X]\n", (unsigned int)(RSC_DMA_RDY_STATUS_HW), (unsigned int)RSC_RD32(RSC_DMA_RDY_STATUS_REG)); seq_printf(m, "RSC:HWProcessIdx:%d, WriteIdx:%d, ReadIdx:%d\n", g_RSC_ReqRing.HWProcessIdx, g_RSC_ReqRing.WriteIdx, g_RSC_ReqRing.ReadIdx); for (i = 0; i < _SUPPORT_MAX_RSC_REQUEST_RING_SIZE_; i++) { seq_printf(m, "RSC:State:%d, processID:0x%08X, callerID:0x%08X, enqueReqNum:%d, FrameWRIdx:%d, RrameRDIdx:%d\n", g_RSC_ReqRing.RSCReq_Struct[i].State, g_RSC_ReqRing.RSCReq_Struct[i].processID, g_RSC_ReqRing.RSCReq_Struct[i].callerID, g_RSC_ReqRing.RSCReq_Struct[i].enqueReqNum, g_RSC_ReqRing.RSCReq_Struct[i].FrameWRIdx, g_RSC_ReqRing.RSCReq_Struct[i].RrameRDIdx); for (j = 0; j < _SUPPORT_MAX_RSC_FRAME_REQUEST_;) { seq_printf(m, "RSC:FrmStat[%d]:%d, FrmStat[%d]:%d\n", j, g_RSC_ReqRing.RSCReq_Struct[i].RscFrameStatus[j], j + 1, g_RSC_ReqRing.RSCReq_Struct[i].RscFrameStatus[j + 1]); j = j + 2; } } seq_puts(m, "\n============ rsc dump debug ============\n"); return 0; } static int proc_rsc_dump_open(struct inode *inode, struct file *file) { return single_open(file, rsc_dump_read, NULL); } static const struct file_operations rsc_dump_proc_fops = { .owner = THIS_MODULE, .open = proc_rsc_dump_open, .read = seq_read, }; static int rsc_reg_read(struct seq_file *m, void *v) { unsigned int i; if (RSCInfo.UserCount <= 0) return 0; spin_lock(&(RSCInfo.SpinLockRSC)); if (g_u4EnableClockCount == 0) { spin_unlock(&(RSCInfo.SpinLockRSC)); return 0; } spin_unlock(&(RSCInfo.SpinLockRSC)); seq_puts(m, "======== read rsc register ========\n"); for (i = 0x1C; i <= 0x308; i = i + 4) { seq_printf(m, "[0x%08X 0x%08X]\n", (unsigned int)(RSC_BASE_HW + i), (unsigned int)RSC_RD32(ISP_RSC_BASE + i)); } seq_printf(m, "[0x%08X 0x%08X]\n", (unsigned int)(RSC_DMA_DBG_HW), (unsigned int)RSC_RD32(RSC_DMA_DBG_REG)); seq_printf(m, "[0x%08X 0x%08X]\n", (unsigned int)(RSC_DMA_REQ_STATUS_HW), (unsigned int)RSC_RD32(RSC_DMA_REQ_STATUS_REG)); seq_printf(m, "[0x%08X 0x%08X]\n", (unsigned int)(RSC_BASE_HW + 0x7FC), (unsigned int)RSC_RD32(RSC_DMA_RDY_STATUS_REG)); return 0; } static ssize_t rsc_reg_write(struct file *file, const char __user *buffer, size_t count, loff_t *data) { char desc[128]; int len = 0; /*char *pEnd;*/ char addrSzBuf[24]; char valSzBuf[24]; char *pszTmp; int addr = 0, val = 0; if (RSCInfo.UserCount <= 0) return 0; len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1); if (copy_from_user(desc, buffer, len)) return 0; desc[len] = '\0'; addrSzBuf[23] = '\0'; valSzBuf[23] = '\0'; if (sscanf(desc, "%23s %23s", addrSzBuf, valSzBuf) == 2) { pszTmp = strstr(addrSzBuf, "0x"); if (pszTmp == NULL) { /*if (1 != sscanf(addrSzBuf, "%d", &addr))*/ #if CHECK_SERVICE_IF_0 if (kstrtoint(addrSzBuf, 0, &addr) != 0) LOG_ERR("scan decimal addr is wrong !!:%s", addrSzBuf); #else LOG_ERR("hex address only:%s", addrSzBuf); #endif } else { if (strlen(addrSzBuf) > 2) { if (sscanf(addrSzBuf + 2, "%x", &addr) != 1) LOG_ERR("error hex addr:%s", addrSzBuf); } else { LOG_INF("RSC Write Addr Error!!:%s", addrSzBuf); } } pszTmp = strstr(valSzBuf, "0x"); if (pszTmp == NULL) { /*if (1 != sscanf(valSzBuf, "%d", &val))*/ #if CHECK_SERVICE_IF_0 if (kstrtoint(valSzBuf, 0, &val) != 0) LOG_ERR("scan decimal value is wrong !!:%s", valSzBuf); #else LOG_ERR("HEX address only :%s", valSzBuf); #endif } else { if (strlen(valSzBuf) > 2) { if (sscanf(valSzBuf + 2, "%x", &val) != 1) LOG_ERR("error hex val:%s", valSzBuf); } else { LOG_INF("RSC Write Value Error!!:%s\n", valSzBuf); } } if ((addr >= RSC_BASE_HW) && (addr <= RSC_DMA_RDY_STATUS_HW) && ((addr & 0x3) == 0)) { LOG_INF("Write Request - addr:0x%x, value:0x%x\n", addr, val); RSC_WR32((ISP_RSC_BASE + (addr - RSC_BASE_HW)), val); } else { LOG_INF ("write add out-of-range addr:0x%x, value:0x%x\n", addr, val); } } else if (sscanf(desc, "%23s", addrSzBuf) == 1) { pszTmp = strstr(addrSzBuf, "0x"); if (pszTmp == NULL) { /*if (1 != sscanf(addrSzBuf, "%d", &addr))*/ #if CHECK_SERVICE_IF_0 if (kstrtoint(addrSzBuf, 0, &addr) != 0) LOG_ERR("scan decimal addr is wrong !!:%s", addrSzBuf); #else LOG_ERR("HEX address only :%s", addrSzBuf); #endif } else { if (strlen(addrSzBuf) > 2) { if (sscanf(addrSzBuf + 2, "%x", &addr) != 1) LOG_ERR("hex addr err:%s", addrSzBuf); } else { LOG_INF("RSC Read Addr Error!!:%s", addrSzBuf); } } if ((addr >= RSC_BASE_HW) && (addr <= RSC_DMA_RDY_STATUS_HW) && ((addr & 0x3) == 0)) { val = RSC_RD32((ISP_RSC_BASE + (addr - RSC_BASE_HW))); LOG_INF("Read Request - addr:0x%x,value:0x%x\n", addr, val); } else { LOG_INF ("Read-Addr out-of-range!! addr:0x%x, value:0x%x\n", addr, val); } } return count; } static int proc_rsc_reg_open(struct inode *inode, struct file *file) { return single_open(file, rsc_reg_read, NULL); } static const struct file_operations rsc_reg_proc_fops = { .owner = THIS_MODULE, .open = proc_rsc_reg_open, .read = seq_read, .write = rsc_reg_write, }; /******************************************************************************* * ******************************************************************************/ #if CHECK_SERVICE_IF_0 int32_t RSC_ClockOnCallback(uint64_t engineFlag) { /* LOG_DBG("RSC_ClockOnCallback"); */ /* LOG_DBG("+CmdqEn:%d", g_u4EnableClockCount); */ /* RSC_EnableClock(MTRUE); */ return 0; } int32_t RSC_DumpCallback(uint64_t engineFlag, int level) { LOG_DBG("%s", __func__); RSC_DumpReg(); request_dump(&rsc_reqs); return 0; } int32_t RSC_ResetCallback(uint64_t engineFlag) { LOG_DBG("%s", __func__); RSC_Reset(); return 0; } int32_t RSC_ClockOffCallback(uint64_t engineFlag) { /* LOG_DBG("RSC_ClockOffCallback"); */ /* RSC_EnableClock(MFALSE); */ /* LOG_DBG("-CmdqEn:%d", g_u4EnableClockCount); */ return 0; } #endif static signed int __init RSC_Init(void) { signed int Ret = 0, j; void *tmp; /* FIX-ME: linux-3.10 procfs API changed */ /* use proc_create */ #if CHECK_SERVICE_IF_0 struct proc_dir_entry *proc_entry; struct proc_dir_entry *isp_rsc_dir; #endif int i; LOG_DBG("- E."); Ret = platform_driver_register(&RSCDriver); 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,RSC"); if (!node) { LOG_ERR("find mediatek,RSC node failed!!!\n"); return -ENODEV; } ISP_RSC_BASE = of_iomap(node, 0); if (!ISP_RSC_BASE) { LOG_ERR("unable to map ISP_RSC_BASE registers!!!\n"); return -ENODEV; } LOG_DBG("ISP_RSC_BASE: %lx\n", ISP_RSC_BASE); #endif #if CHECK_SERVICE_IF_0 isp_rsc_dir = proc_mkdir("rsc", NULL); if (!isp_rsc_dir) { LOG_ERR("[%s]: fail to mkdir /proc/rsc\n", __func__); return 0; } proc_entry = proc_create("rsc_dump", 0444, isp_rsc_dir, &rsc_dump_proc_fops); proc_entry = proc_create("rsc_reg", 0644, isp_rsc_dir, &rsc_reg_proc_fops); #endif /* isr log */ if (PAGE_SIZE < ((RSC_IRQ_TYPE_AMOUNT * NORMAL_STR_LEN * ((DBG_PAGE + INF_PAGE + ERR_PAGE) + 1)) * LOG_PPNUM)) { i = 0; while (i < ((RSC_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 < RSC_IRQ_TYPE_AMOUNT; j++) { gSvLog[j]._str[i][_LOG_DBG] = (char *)tmp; tmp = (void *)((char *)tmp + (NORMAL_STR_LEN * DBG_PAGE)); gSvLog[j]._str[i][_LOG_INF] = (char *)tmp; tmp = (void *)((char *)tmp + (NORMAL_STR_LEN * INF_PAGE)); gSvLog[j]._str[i][_LOG_ERR] = (char *)tmp; tmp = (void *)((char *)tmp + (NORMAL_STR_LEN * ERR_PAGE)); } /* tmp = (void*) ((unsigned int)tmp + NORMAL_STR_LEN); */ tmp = (void *)((char *)tmp + NORMAL_STR_LEN); /* overflow */ } #if CHECK_SERVICE_IF_0 /* Cmdq */ /* Register RSC callback */ LOG_DBG("register rsc callback for CMDQ"); cmdqCoreRegisterCB(CMDQ_GROUP_RSC, RSC_ClockOnCallback, RSC_DumpCallback, RSC_ResetCallback, RSC_ClockOffCallback); #endif LOG_DBG("- X. Ret: %d.", Ret); return Ret; } /******************************************************************************* * ******************************************************************************/ static void __exit RSC_Exit(void) { /*int i;*/ LOG_DBG("- E."); platform_driver_unregister(&RSCDriver); #if CHECK_SERVICE_IF_0 /* Cmdq */ /* Unregister RSC callback */ cmdqCoreRegisterCB(CMDQ_GROUP_RSC, NULL, NULL, NULL, NULL); #endif kfree(pLog_kmalloc); } /******************************************************************************* * ******************************************************************************/ void RSC_ScheduleWork(struct work_struct *data) { if (RSC_DBG_DBGLOG & RSCInfo.DebugMask) LOG_DBG("- E."); request_handler(&rsc_reqs, &(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST])); if (!request_running(&rsc_reqs)) LOG_DBG("[%s]no more requests", __func__); } static irqreturn_t ISP_Irq_RSC(signed int Irq, void *DeviceId) { unsigned int RscStatus; bool bResulst = MFALSE; pid_t ProcessID; RscStatus = RSC_RD32(RSC_INT_STATUS_REG); /* RSC Status */ spin_lock(&(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST])); if (RSC_INT_ST == (RSC_INT_ST & RscStatus)) { /* Update the frame status. */ #ifdef __RSC_KERNEL_PERFORMANCE_MEASURE__ mt_kernel_trace_begin("rsc_irq"); #endif if (update_request(&rsc_reqs, &ProcessID) == 0) bResulst = MTRUE; if (bResulst == MTRUE) { #if REQUEST_REGULATION == REQUEST_BASE_REGULATION /* schedule_work(&RSCInfo.ScheduleRscWork); */ queue_work(RSCInfo.wkqueue, &RSCInfo.ScheduleRscWork); #endif RSCInfo.IrqInfo.Status[RSC_IRQ_TYPE_INT_RSC_ST] |= RSC_INT_ST; RSCInfo.IrqInfo.ProcessID[RSC_PROCESS_ID_RSC] = ProcessID; RSCInfo.IrqInfo.RscIrqCnt++; RSCInfo.ProcessID[RSCInfo.WriteReqIdx] = ProcessID; RSCInfo.WriteReqIdx = (RSCInfo.WriteReqIdx + 1) % _SUPPORT_MAX_RSC_FRAME_REQUEST_; } #ifdef __RSC_KERNEL_PERFORMANCE_MEASURE__ mt_kernel_trace_end(); #endif /* Config the Next frame */ } spin_unlock(&(RSCInfo.SpinLockIrq[RSC_IRQ_TYPE_INT_RSC_ST])); if (bResulst == MTRUE) wake_up_interruptible(&RSCInfo.WaitQueueHead); /* dump log, use tasklet */ IRQ_LOG_KEEPER( RSC_IRQ_TYPE_INT_RSC_ST, m_CurrentPPB, _LOG_INF, "%s:%d, reg 0x%x : 0x%x, bResulst:%d, RscHWSta:0x%x, RscIrqCnt:0x%x, WriteReqIdx:0x%x, ReadReqIdx:0x%x\n", __func__, Irq, RSC_INT_STATUS_HW, RscStatus, bResulst, RscStatus, RSCInfo.IrqInfo.RscIrqCnt, RSCInfo.WriteReqIdx, RSCInfo.ReadReqIdx); /* IRQ_LOG_KEEPER(RSC_IRQ_TYPE_INT_RSC_ST, m_CurrentPPB, _LOG_INF, * "RscHWSta:0x%x, RscHWSta:0x%x, DpeDveSta0:0x%x\n", * DveStatus, RscStatus, DpeDveSta0); */ #if (REQUEST_REGULATION == FRAME_BASE_REGULATION) /* schedule_work(&RSCInfo.ScheduleRscWork); */ queue_work(RSCInfo.wkqueue, &RSCInfo.ScheduleRscWork); #endif if (RscStatus & RSC_INT_ST) #if CHECK_SERVICE_IF_1 schedule_work(&logWork); #else tasklet_schedule(RSC_tasklet[RSC_IRQ_TYPE_INT_RSC_ST].pRSC_tkt); #endif return IRQ_HANDLED; } static void ISP_TaskletFunc_RSC(unsigned long data) { IRQ_LOG_PRINTER(RSC_IRQ_TYPE_INT_RSC_ST, m_CurrentPPB, _LOG_DBG); IRQ_LOG_PRINTER(RSC_IRQ_TYPE_INT_RSC_ST, m_CurrentPPB, _LOG_INF); IRQ_LOG_PRINTER(RSC_IRQ_TYPE_INT_RSC_ST, m_CurrentPPB, _LOG_ERR); } static void logPrint(struct work_struct *data) { unsigned long arg = 0; ISP_TaskletFunc_RSC(arg); } /****************************************************************************** * ******************************************************************************/ module_init(RSC_Init); module_exit(RSC_Exit); MODULE_DESCRIPTION("Camera RSC driver"); MODULE_AUTHOR("MM3SW2"); MODULE_LICENSE("GPL");