All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jungo Lin <jungo.lin@mediatek.com>
To: <tfiga@chromium.org>, <hans.verkuil@cisco.com>,
	<laurent.pinchart+renesas@ideasonboard.com>,
	<matthias.bgg@gmail.com>, <mchehab@kernel.org>
Cc: <linux-mediatek@lists.infradead.org>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-media@vger.kernel.org>, <Sean.Cheng@mediatek.com>,
	<sj.huang@mediatek.com>, <christie.yu@mediatek.com>,
	<holmes.chiou@mediatek.com>, <frederic.chen@mediatek.com>,
	<Jerry-ch.Chen@mediatek.com>, <jungo.lin@mediatek.com>,
	<frankie.chiu@mediatek.com>, <seraph.huang@mediatek.com>,
	<ryan.yu@mediatek.com>, <Rynn.Wu@mediatek.com>,
	<yuzhao@chromium.org>, <zwisler@chromium.org>,
	<srv_heupstream@mediatek.com>
Subject: [RFC V1 10/12] media: platform: Add Mediatek ISP P1 device driver
Date: Thu, 28 Mar 2019 17:56:45 +0800	[thread overview]
Message-ID: <1553767007-11909-11-git-send-email-jungo.lin@mediatek.com> (raw)
In-Reply-To: <1553767007-11909-1-git-send-email-jungo.lin@mediatek.com>

This patch adds the Mediatek ISP P1 HW control device driver.
It handles the ISP HW configuration, provides interrupt handling and
initializes the V4L2 device nodes and other functions.

Signed-off-by: Jungo Lin <jungo.lin@mediatek.com>
---
 .../platform/mtk-isp/isp_50/cam/mtk_cam-regs.h     |  147 +++
 .../media/platform/mtk-isp/isp_50/cam/mtk_cam.c    | 1098 ++++++++++++++++++++
 .../media/platform/mtk-isp/isp_50/cam/mtk_cam.h    |  288 +++++
 3 files changed, 1533 insertions(+)
 create mode 100644 drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam-regs.h
 create mode 100644 drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.c
 create mode 100644 drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.h

diff --git a/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam-regs.h b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam-regs.h
new file mode 100644
index 0000000..90736a1
--- /dev/null
+++ b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam-regs.h
@@ -0,0 +1,147 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ryan Yu <ryan.yu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_REGS_H
+#define _CAM_REGS_H
+
+/* TG Bit Mask */
+#define VFDATA_EN_BIT	BIT(0)
+#define CMOS_EN_BIT	BIT(0)
+
+/* normal signal bit */
+#define VS_INT_ST	BIT(0)
+#define HW_PASS1_DON_ST	BIT(11)
+#define SOF_INT_ST	BIT(12)
+#define SW_PASS1_DON_ST	BIT(30)
+
+/* err status bit */
+#define TG_ERR_ST	BIT(4)
+#define TG_GBERR_ST	BIT(5)
+#define CQ_CODE_ERR_ST	BIT(6)
+#define CQ_APB_ERR_ST	BIT(7)
+#define CQ_VS_ERR_ST	BIT(8)
+#define AMX_ERR_ST	BIT(15)
+#define RMX_ERR_ST	BIT(16)
+#define BMX_ERR_ST	BIT(17)
+#define RRZO_ERR_ST	BIT(18)
+#define AFO_ERR_ST	BIT(19)
+#define IMGO_ERR_ST	BIT(20)
+#define AAO_ERR_ST	BIT(21)
+#define PSO_ERR_ST	BIT(22)
+#define LCSO_ERR_ST	BIT(23)
+#define BNR_ERR_ST	BIT(24)
+#define LSCI_ERR_ST	BIT(25)
+#define DMA_ERR_ST	BIT(29)
+
+/* CAM DMA done status */
+#define FLKO_DONE_ST	BIT(4)
+#define AFO_DONE_ST	BIT(5)
+#define AAO_DONE_ST	BIT(7)
+#define PSO_DONE_ST	BIT(14)
+
+/* IRQ signal mask */
+#define INT_ST_MASK_CAM	( \
+			VS_INT_ST |\
+			HW_PASS1_DON_ST |\
+			SOF_INT_ST |\
+			SW_PASS1_DON_ST)
+
+/* IRQ Warning Mask */
+#define INT_ST_MASK_CAM_WARN	(\
+				RRZO_ERR_ST |\
+				AFO_ERR_ST |\
+				IMGO_ERR_ST |\
+				AAO_ERR_ST |\
+				PSO_ERR_ST | \
+				LCSO_ERR_ST |\
+				BNR_ERR_ST |\
+				LSCI_ERR_ST)
+
+/* IRQ Error Mask */
+#define INT_ST_MASK_CAM_ERR	(\
+				TG_ERR_ST |\
+				TG_GBERR_ST |\
+				CQ_CODE_ERR_ST |\
+				CQ_APB_ERR_ST |\
+				CQ_VS_ERR_ST |\
+				BNR_ERR_ST |\
+				RMX_ERR_ST |\
+				BMX_ERR_ST |\
+				BNR_ERR_ST |\
+				LSCI_ERR_ST |\
+				DMA_ERR_ST)
+
+/* IRQ Signal Log Mask */
+#define INT_ST_LOG_MASK_CAM	(\
+				SOF_INT_ST |\
+				SW_PASS1_DON_ST |\
+				VS_INT_ST |\
+				TG_ERR_ST |\
+				TG_GBERR_ST |\
+				RRZO_ERR_ST |\
+				AFO_ERR_ST |\
+				IMGO_ERR_ST |\
+				AAO_ERR_ST |\
+				DMA_ERR_ST)
+
+/* DMA Event Notification Mask */
+#define DMA_ST_MASK_CAM	(\
+			AFO_DONE_ST |\
+			AAO_DONE_ST |\
+			PSO_DONE_ST |\
+			FLKO_DONE_ST)
+
+/* Status check */
+#define REG_CTL_EN		0x0004
+#define REG_CTL_DMA_EN		0x0008
+#define REG_CTL_FMT_SEL		0x0010
+#define REG_CTL_EN2		0x0018
+#define REG_CTL_RAW_INT_EN	0x0020
+#define REG_CTL_RAW_INT_STAT	0x0024
+#define REG_CTL_RAW_INT2_STAT	0x0034
+#define REG_CTL_RAW_INT3_STAT	0x00c4
+#define REG_CTL_TWIN_STAT	0x0050
+
+#define REG_TG_SEN_MODE		0x0230
+#define REG_TG_SEN_GRAB_PIX	0x0238
+#define REG_TG_SEN_GRAB_LIN	0x023c
+#define REG_TG_VF_CON		0x0234
+#define REG_TG_INTER_ST		0x026c
+#define REG_TG_SUB_PERIOD	0x02a4
+
+#define REG_IMGO_BASE_ADDR	0x1020
+#define REG_RRZO_BASE_ADDR	0x1050
+
+/* Error status log */
+#define REG_IMGO_ERR_STAT	0x1360
+#define REG_RRZO_ERR_STAT	0x1364
+#define REG_AAO_ERR_STAT	0x1368
+#define REG_AFO_ERR_STAT	0x136c
+#define REG_LCSO_ERR_STAT	0x1370
+#define REG_UFEO_ERR_STAT	0x1374
+#define REG_PDO_ERR_STAT	0x1378
+#define REG_BPCI_ERR_STAT	0x137c
+#define REG_LSCI_ERR_STAT	0x1384
+#define REG_PDI_ERR_STAT	0x138c
+#define REG_LMVO_ERR_STAT	0x1390
+#define REG_FLKO_ERR_STAT	0x1394
+#define REG_PSO_ERR_STAT	0x13a0
+
+/* ISP command */
+#define REG_CQ_THR0_BASEADDR	0x0198
+#define REG_CTL_SPARE2		0x0058
+#define REG_HW_FRAME_NUM	0x13b8
+
+#endif	/* _CAM_REGS_H */
diff --git a/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.c b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.c
new file mode 100644
index 0000000..935cf7e
--- /dev/null
+++ b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.c
@@ -0,0 +1,1098 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ryan Yu <ryan.yu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/atomic.h>
+#include <linux/cdev.h>
+#include <linux/compat.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/mtk_scp.h>
+#include <linux/pm_runtime.h>
+#include <linux/remoteproc.h>
+#include <linux/sched/clock.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+
+#include "mtk_cam.h"
+#include "mtk_cam-regs.h"
+#include "mtk_cam-ctx.h"
+
+static const struct of_device_id mtk_isp_of_ids[] = {
+	{.compatible = "mediatek,mt8183-camisp",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, mtk_isp_of_ids);
+
+/* list of clocks required by isp cam */
+static const char * const mtk_isp_clks[] = {
+	"CAMSYS_CAM_CGPDN", "CAMSYS_CAMTG_CGPDN"
+};
+
+static void isp_dumpdmastat(struct isp_device *isp_dev)
+{
+	dev_err(isp_dev->dev,
+		"IMGO:0x%x, RRZO:0x%x, AAO=0x%x, AFO=0x%x, LMVO=0x%x\n",
+		readl(isp_dev->regs + REG_IMGO_ERR_STAT),
+		readl(isp_dev->regs + REG_RRZO_ERR_STAT),
+		readl(isp_dev->regs + REG_AAO_ERR_STAT),
+		readl(isp_dev->regs + REG_AFO_ERR_STAT),
+		readl(isp_dev->regs + REG_LMVO_ERR_STAT));
+	dev_err(isp_dev->dev,
+		"LCSO=0x%x, PSO=0x%x, FLKO=0x%x, BPCI:0x%x, LSCI=0x%x\n",
+		readl(isp_dev->regs + REG_LCSO_ERR_STAT),
+		readl(isp_dev->regs + REG_PSO_ERR_STAT),
+		readl(isp_dev->regs + REG_FLKO_ERR_STAT),
+		readl(isp_dev->regs + REG_BPCI_ERR_STAT),
+		readl(isp_dev->regs + REG_LSCI_ERR_STAT));
+}
+
+static void mtk_isp_notify(struct mtk_isp_p1_ctx *isp_ctx,
+			   unsigned int request_fd,
+			   unsigned int frame_seq_no,
+			   struct list_head *list_buf,
+			   enum vb2_buffer_state state)
+{
+	struct isp_p1_device *p1_dev = p1_ctx_to_dev(isp_ctx);
+	struct device *dev = &p1_dev->pdev->dev;
+	struct mtk_cam_dev_finish_param fram_param;
+
+	fram_param.list_buf = list_buf;
+	fram_param.request_fd = request_fd;
+	fram_param.frame_seq_no = frame_seq_no;
+	fram_param.state = state;
+	dev_dbg(dev, "request fd(%d) frame_seq_no(%d)\n",
+		fram_param.request_fd,
+		fram_param.frame_seq_no);
+	mtk_cam_dev_core_job_finish(p1_dev->cam_dev, &fram_param);
+}
+
+static void isp_deque_frame(struct isp_p1_device *p1_dev, int frame_seq_no)
+{
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct platform_device *pdev = p1_dev->pdev;
+	struct mtk_isp_queue_job *framejob, *tmp;
+	struct isp_queue *p1_enqueue_list = &isp_ctx->p1_enqueue_list;
+
+	/* Match dequeue work and enqueue frame */
+	spin_lock(&p1_enqueue_list->lock);
+	list_for_each_entry_safe(framejob, tmp, &p1_enqueue_list->queue,
+				 list_entry) {
+		dev_dbg(&pdev->dev,
+			"%s frame_seq_no=%d, isp_composer_work->req_num=%d\n",
+			__func__,
+			framejob->frame_seq_no, frame_seq_no);
+		/* Match by the en-queued request number */
+		if (framejob->frame_seq_no == frame_seq_no) {
+			/* Pass to user space */
+			mtk_isp_notify(isp_ctx,
+				       framejob->request_fd,
+				       framejob->frame_seq_no,
+				       &framejob->list_buf,
+				       VB2_BUF_STATE_DONE);
+			atomic_dec(&p1_enqueue_list->queue_cnt);
+			dev_dbg(&pdev->dev,
+				"frame(frame_seq_no=%d) is done, queue_cnt(%d)\n",
+				framejob->frame_seq_no,
+				atomic_read(&p1_enqueue_list->queue_cnt));
+
+			/* remove only when frame ready */
+			list_del(&framejob->list_entry);
+			kfree(framejob);
+			break;
+		} else if (framejob->frame_seq_no < frame_seq_no) {
+			/* Pass to user space for frame drop */
+			mtk_isp_notify(isp_ctx,
+				       framejob->request_fd,
+				       framejob->frame_seq_no,
+				       &framejob->list_buf,
+				       VB2_BUF_STATE_ERROR);
+			atomic_dec(&p1_enqueue_list->queue_cnt);
+			dev_dbg(&pdev->dev,
+				"frame(frame_seq_no=%d) drop, queue_cnt(%d)\n",
+				framejob->frame_seq_no,
+				atomic_read(&p1_enqueue_list->queue_cnt));
+
+			/* remove only drop frame */
+			list_del(&framejob->list_entry);
+			kfree(framejob);
+		}
+	}
+	spin_unlock(&p1_enqueue_list->lock);
+}
+
+static int isp_deque_work(void *data)
+{
+	struct isp_p1_device *p1_dev = (struct isp_p1_device *)data;
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct device *dev = &p1_dev->pdev->dev;
+	struct mtk_cam_dev *cam_dev = p1_dev->cam_dev;
+	struct mtk_cam_dev_stat_event_data event_data;
+	atomic_t *irq_data_end = &isp_ctx->irq_data_end;
+	atomic_t *irq_data_start = &isp_ctx->irq_data_start;
+	unsigned long flags;
+	int ret, i;
+
+	while (1) {
+		ret = wait_event_interruptible(isp_ctx->isp_deque_thread.wq,
+					       (atomic_read(irq_data_end) !=
+					       atomic_read(irq_data_start)) ||
+					       kthread_should_stop());
+
+		if (kthread_should_stop())
+			break;
+
+		if (ret == ERESTARTSYS) {
+			dev_err(dev, "interrupted by a signal!\n");
+			continue;
+		}
+
+		spin_lock_irqsave(&isp_ctx->irq_dequeue_lock, flags);
+		i = atomic_read(&isp_ctx->irq_data_start);
+		memcpy(&event_data, &isp_ctx->irq_event_datas[i],
+		       sizeof(event_data));
+		memset(&isp_ctx->irq_event_datas[i], 0x00, sizeof(event_data));
+		atomic_set(&isp_ctx->irq_data_start, ++i & 0x3);
+		spin_unlock_irqrestore(&isp_ctx->irq_dequeue_lock, flags);
+
+		if (event_data.irq_status_mask & VS_INT_ST) {
+			/* Notify specific HW events to user space */
+			mtk_cam_dev_queue_event_dev_state(cam_dev,
+							  &event_data);
+			dev_dbg(dev,
+				"event IRQ(0x%x) DMA(0x%x) is sent\n",
+				event_data.irq_status_mask,
+				event_data.dma_status_mask);
+			mtk_cam_dev_queue_event_dev_state(cam_dev,
+							  &event_data);
+		} else if (event_data.irq_status_mask & SW_PASS1_DON_ST) {
+			isp_deque_frame(p1_dev,
+					event_data.frame_seq_no);
+		}
+	}
+	return 0;
+}
+
+static int irq_handle_sof(struct isp_device *isp_dev,
+			  dma_addr_t base_addr,
+			  unsigned int frame_num)
+{
+	unsigned int cq_addr_index;
+	struct isp_p1_device *p1_dev = get_p1_device(isp_dev->dev);
+	int cq_num = atomic_read(&p1_dev->isp_ctx.composed_frame_id);
+
+	if (cq_num > frame_num) {
+		cq_addr_index = frame_num % CQ_BUFFER_COUNT;
+
+		writel(base_addr +
+			(dma_addr_t)(CQ_ADDRESS_OFFSET * cq_addr_index),
+			isp_dev->regs + REG_CQ_THR0_BASEADDR);
+		dev_dbg(isp_dev->dev,
+			"SOF_INT_ST cq_num:%d, frame_num:%d cq_addr:%d",
+			cq_num, frame_num, cq_addr_index);
+	} else {
+		dev_dbg(isp_dev->dev,
+			"SOF_INT_ST cq_num:%d, frame_num:%d",
+			cq_num, frame_num);
+	}
+
+	isp_dev->sof_count += 1;
+
+	return cq_num;
+}
+
+static int irq_handle_notify_event(struct isp_device *isp_dev,
+				   unsigned int irqstatus,
+				   unsigned int dmastatus)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(isp_dev->dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&isp_ctx->irq_dequeue_lock, flags);
+	i = atomic_read(&isp_ctx->irq_data_end);
+	isp_ctx->irq_event_datas[i].frame_seq_no = isp_dev->current_frame;
+	isp_ctx->irq_event_datas[i].irq_status_mask |=
+		(irqstatus & INT_ST_MASK_CAM);
+	isp_ctx->irq_event_datas[i].dma_status_mask |=
+		(dmastatus & DMA_ST_MASK_CAM);
+	atomic_set(&isp_ctx->irq_data_end, ++i & 0x3);
+	spin_unlock_irqrestore(&isp_ctx->irq_dequeue_lock, flags);
+
+	wake_up_interruptible(&isp_ctx->isp_deque_thread.wq);
+
+	dev_dbg(isp_dev->dev,
+		"%s notify IRQ (0x%x) DMA status (0x%x) for frame_seq_no: %d\n",
+		__func__,
+		(irqstatus & INT_ST_MASK_CAM),
+		(dmastatus & DMA_ST_MASK_CAM),
+		isp_dev->current_frame);
+
+	return 0;
+}
+
+irqreturn_t isp_irq_cam(int irq, void *data)
+{
+	struct isp_device *isp_dev = (struct isp_device *)data;
+	struct isp_p1_device *p1_dev = get_p1_device(isp_dev->dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct device *dev = isp_dev->dev;
+	unsigned int cardinalnum, cq_num, hw_frame_num;
+	unsigned int irqstatus, errstatus, warnstatus, dmastatus;
+	unsigned long flags;
+
+	/* Check the streaming is off or not */
+	if (!p1_dev->cam_dev->streaming)
+		return IRQ_HANDLED;
+
+	cardinalnum = isp_dev->isp_hw_module - ISP_CAM_A_IDX;
+	cq_num = 0;
+
+	spin_lock_irqsave(&isp_dev->spinlock_irq, flags);
+	irqstatus = readl(isp_dev->regs + REG_CTL_RAW_INT_STAT);
+	dmastatus = readl(isp_dev->regs + REG_CTL_RAW_INT2_STAT);
+	hw_frame_num = readl(isp_dev->regs + REG_HW_FRAME_NUM);
+	spin_unlock_irqrestore(&isp_dev->spinlock_irq, flags);
+
+	/* Ignore unnecessary IRQ */
+	if (irqstatus == 0)
+		return IRQ_HANDLED;
+
+	errstatus = irqstatus & INT_ST_MASK_CAM_ERR;
+	warnstatus = irqstatus & INT_ST_MASK_CAM_WARN;
+	irqstatus = irqstatus & INT_ST_MASK_CAM;
+
+	/* sof , done order check . */
+	spin_lock_irqsave(&isp_dev->spinlock_irq, flags);
+	if ((irqstatus & HW_PASS1_DON_ST) && (irqstatus & SOF_INT_ST)) {
+		dev_warn(dev,
+			 "isp sof_don block, %d\n",
+			 isp_dev->sof_count);
+
+		/* Notify IRQ event and enqueue ready frame */
+		irq_handle_notify_event(isp_dev, irqstatus, dmastatus);
+		isp_dev->current_frame = hw_frame_num;
+	} else {
+		if (irqstatus & SOF_INT_ST)
+			isp_dev->current_frame = hw_frame_num;
+
+		if ((irqstatus & INT_ST_MASK_CAM) ||
+		    (dmastatus & DMA_ST_MASK_CAM))
+			irq_handle_notify_event(isp_dev, irqstatus, dmastatus);
+	}
+	spin_unlock_irqrestore(&isp_dev->spinlock_irq, flags);
+
+	if (irqstatus & SOF_INT_ST)
+		cq_num = irq_handle_sof(isp_dev, isp_ctx->scp_mem_iova,
+					hw_frame_num);
+
+	if (irqstatus & SW_PASS1_DON_ST) {
+		int num = atomic_dec_return(&isp_ctx->composing_frame);
+
+		dev_dbg(dev, "SW_PASS1_DON_ST queued frame:%d\n", num);
+		/* Notify TX thread to send if TX frame is blocked */
+		wake_up_interruptible
+				(&isp_ctx->composer_tx_thread.wq);
+	}
+
+	/* check ISP error status */
+	if (errstatus) {
+		dev_err(dev,
+			"raw_int_err:0x%x/0x%x, raw_int3_err:0x%x\n",
+			irqstatus, warnstatus, errstatus);
+
+		/* show DMA errors in detail */
+		if (errstatus & DMA_ERR_ST)
+			isp_dumpdmastat(isp_dev);
+	}
+
+	if (irqstatus & INT_ST_LOG_MASK_CAM)
+		dev_dbg(dev, IRQ_STAT_STR,
+			'A' + cardinalnum,
+			isp_dev->sof_count,
+			irqstatus,
+			dmastatus,
+			hw_frame_num,
+			cq_num);
+	return IRQ_HANDLED;
+}
+
+static int enable_sys_clock(struct isp_p1_device *p1_dev)
+{
+	struct device *dev = &p1_dev->pdev->dev;
+	int ret;
+
+	dev_info(dev, "- %s dev id:%d\n", __func__, dev->id);
+
+	ret = clk_bulk_prepare_enable(p1_dev->isp_clk.num_clks,
+				      p1_dev->isp_clk.clk_list);
+	if (ret < 0)
+		goto clk_err;
+	return 0;
+clk_err:
+	dev_err(dev, "cannot pre-en isp_cam clock:%d\n", ret);
+	clk_bulk_disable_unprepare(p1_dev->isp_clk.num_clks,
+				   p1_dev->isp_clk.clk_list);
+	return ret;
+}
+
+static void disable_sys_clock(struct isp_p1_device *p1_dev)
+{
+	struct device *dev = &p1_dev->pdev->dev;
+
+	dev_info(dev, "- %s dev id:%d\n", __func__, dev->id);
+	clk_bulk_disable_unprepare(p1_dev->isp_clk.num_clks,
+				   p1_dev->isp_clk.clk_list);
+}
+
+static int mtk_isp_probe(struct platform_device *pdev)
+{
+	struct isp_p1_device *p1_dev;
+	struct mtk_isp_p1_ctx *isp_ctx;
+	struct isp_device *isp_dev;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int ret;
+	unsigned int i;
+
+	/* Allocate context */
+	p1_dev = devm_kzalloc(dev, sizeof(*p1_dev), GFP_KERNEL);
+	if (!p1_dev)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, p1_dev);
+	isp_ctx = &p1_dev->isp_ctx;
+	p1_dev->pdev = pdev;
+
+	p1_dev->isp_devs =
+		devm_kzalloc(dev,
+			     sizeof(struct isp_device) * ISP_DEV_NODE_NUM,
+			     GFP_KERNEL);
+	if (!p1_dev->isp_devs)
+		return -ENOMEM;
+
+	p1_dev->cam_dev =
+		devm_kzalloc(dev, sizeof(struct mtk_cam_dev), GFP_KERNEL);
+	if (!p1_dev->isp_devs)
+		return -ENOMEM;
+
+	/* iomap registers */
+	for (i = ISP_CAMSYS_CONFIG_IDX; i < ISP_DEV_NODE_NUM; i++) {
+		isp_dev = &p1_dev->isp_devs[i];
+		isp_dev->isp_hw_module = i;
+		isp_dev->dev = dev;
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		isp_dev->regs = devm_ioremap_resource(dev, res);
+
+		dev_info(dev, "cam%u, map_addr=0x%lx\n",
+			 i, (unsigned long)isp_dev->regs);
+
+		if (!isp_dev->regs)
+			return PTR_ERR(isp_dev->regs);
+
+		/* support IRQ from ISP_CAM_A_IDX */
+		if (i >= ISP_CAM_A_IDX) {
+			/* reg & interrupts index is shifted with 1  */
+			isp_dev->irq = platform_get_irq(pdev, i - 1);
+			if (isp_dev->irq > 0) {
+				ret = devm_request_irq(dev, isp_dev->irq,
+						       isp_irq_cam,
+						       IRQF_SHARED,
+						       dev_driver_string(dev),
+						       (void *)isp_dev);
+				if (ret) {
+					dev_err(dev,
+						"req_irq fail, dev(%s) irq=%d\n",
+						dev->of_node->name,
+						isp_dev->irq);
+					return ret;
+				}
+				dev_info(dev, "Registered irq=%d, ISR: %s\n",
+					 isp_dev->irq, dev_driver_string(dev));
+			}
+		}
+		spin_lock_init(&isp_dev->spinlock_irq);
+	}
+
+	p1_dev->isp_clk.num_clks = ARRAY_SIZE(mtk_isp_clks);
+	p1_dev->isp_clk.clk_list =
+		devm_kcalloc(dev,
+			     p1_dev->isp_clk.num_clks,
+			     sizeof(*p1_dev->isp_clk.clk_list),
+			     GFP_KERNEL);
+	if (!p1_dev->isp_clk.clk_list)
+		return -ENOMEM;
+
+	for (i = 0; i < p1_dev->isp_clk.num_clks; ++i)
+		p1_dev->isp_clk.clk_list->id = mtk_isp_clks[i];
+
+	ret = devm_clk_bulk_get(dev,
+				p1_dev->isp_clk.num_clks,
+				p1_dev->isp_clk.clk_list);
+	if (ret) {
+		dev_err(dev, "cannot get isp cam clock:%d\n", ret);
+		return ret;
+	}
+
+	/* initialize the v4l2 common part */
+	ret = mtk_cam_dev_core_init(pdev, p1_dev->cam_dev);
+	if (ret)
+		return ret;
+
+	spin_lock_init(&isp_ctx->p1_enqueue_list.lock);
+	atomic_set(&p1_dev->isp_ctx.isp_user_cnt, 0);
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int mtk_isp_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct isp_p1_device *p1_dev = dev_get_drvdata(dev);
+
+	pm_runtime_disable(dev);
+	mtk_cam_dev_core_release(pdev, p1_dev->cam_dev);
+
+	return 0;
+}
+
+static int mtk_isp_suspend(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct isp_device *isp_dev;
+	unsigned int reg_val;
+	int usercount, module;
+
+	module = p1_dev->isp_ctx.isp_hw_module;
+	usercount = atomic_read(&p1_dev->isp_ctx.isp_user_cnt);
+
+	dev_dbg(dev, "- %s:%d\n", __func__, usercount);
+
+	/* If no user count, no further action */
+	if (!usercount)
+		return 0;
+
+	isp_dev = &p1_dev->isp_devs[module];
+	reg_val = readl(isp_dev->regs + REG_TG_VF_CON);
+	if (reg_val & VFDATA_EN_BIT) {
+		dev_dbg(dev, "Cam:%d suspend, disable VF\n", module);
+		/* disable VF */
+		writel((reg_val & (~VFDATA_EN_BIT)),
+		       isp_dev->regs + REG_TG_VF_CON);
+		/*
+		 * After VF enable, The TG frame count will be reset to 0;
+		 */
+		reg_val = readl(isp_dev->regs + REG_TG_SEN_MODE);
+		writel((reg_val & (~CMOS_EN_BIT)),
+		       isp_dev->regs +  + REG_TG_SEN_MODE);
+	}
+
+	disable_sys_clock(p1_dev);
+
+	return 0;
+}
+
+static int mtk_isp_resume(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct isp_device *isp_dev;
+	unsigned int reg_val;
+	int module, usercount;
+
+	module = p1_dev->isp_ctx.isp_hw_module;
+	usercount = atomic_read(&p1_dev->isp_ctx.isp_user_cnt);
+
+	dev_dbg(dev, "- %s:%d\n", __func__, usercount);
+
+	/* If no user count, no further action */
+	if (!usercount)
+		return 0;
+
+	enable_sys_clock(p1_dev);
+
+	/* V4L2 stream-on phase & restore HW stream-on status */
+	if (p1_dev->cam_dev->streaming) {
+		isp_dev = &p1_dev->isp_devs[module];
+		dev_dbg(dev, "Cam:%d resume,enable VF\n", module);
+		/* Enable CMOS */
+		reg_val = readl(isp_dev->regs + REG_TG_SEN_MODE);
+		writel((reg_val | CMOS_EN_BIT),
+		       isp_dev->regs + REG_TG_SEN_MODE);
+		/* Enable VF */
+		reg_val = readl(isp_dev->regs + REG_TG_VF_CON);
+		writel((reg_val | VFDATA_EN_BIT),
+		       isp_dev->regs + REG_TG_VF_CON);
+	}
+	return 0;
+}
+
+static int isp_init_context(struct isp_p1_device *p1_dev)
+{
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct device *dev = &p1_dev->pdev->dev;
+	unsigned int i;
+
+	dev_dbg(dev, "init irq work thread\n");
+	if (!isp_ctx->isp_deque_thread.thread) {
+		mutex_init(&isp_ctx->composer_tx_lock);
+		init_waitqueue_head(&isp_ctx->isp_deque_thread.wq);
+		isp_ctx->isp_deque_thread.thread =
+			kthread_run(isp_deque_work, (void *)p1_dev,
+				    "isp_deque_work");
+		if (IS_ERR(isp_ctx->isp_deque_thread.thread)) {
+			dev_err(dev, "unable to alloc kthread\n");
+			isp_ctx->isp_deque_thread.thread = NULL;
+			return -ENOMEM;
+		}
+	}
+	spin_lock_init(&isp_ctx->irq_dequeue_lock);
+
+	INIT_LIST_HEAD(&isp_ctx->p1_enqueue_list.queue);
+	atomic_set(&isp_ctx->p1_enqueue_list.queue_cnt, 0);
+
+	for (i = 0; i < ISP_DEV_NODE_NUM; i++)
+		spin_lock_init(&p1_dev->isp_devs[i].spinlock_irq);
+
+	spin_lock_init(&isp_ctx->p1_enqueue_list.lock);
+	spin_lock_init(&isp_ctx->composer_txlist.lock);
+
+	atomic_set(&isp_ctx->irq_data_end, 0);
+	atomic_set(&isp_ctx->irq_data_start, 0);
+	return 0;
+}
+
+static int isp_uninit_context(struct isp_p1_device *p1_dev)
+{
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct mtk_isp_queue_job *framejob, *tmp_framejob;
+
+	spin_lock_irq(&isp_ctx->p1_enqueue_list.lock);
+	list_for_each_entry_safe(framejob, tmp_framejob,
+				 &isp_ctx->p1_enqueue_list.queue, list_entry) {
+		list_del(&framejob->list_entry);
+		kfree(framejob);
+	}
+	spin_unlock_irq(&isp_ctx->p1_enqueue_list.lock);
+
+	atomic_set(&isp_ctx->isp_user_cnt, 0);
+
+	if (!IS_ERR(isp_ctx->isp_deque_thread.thread)) {
+		kthread_stop(isp_ctx->isp_deque_thread.thread);
+		wake_up_interruptible(&isp_ctx->isp_deque_thread.wq);
+		isp_ctx->isp_deque_thread.thread = NULL;
+	}
+
+	return 0;
+}
+
+/* Utility functions */
+static unsigned int get_sensor_pixel_id(unsigned int fmt)
+{
+	switch (fmt) {
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+	case MEDIA_BUS_FMT_SBGGR14_1X14:
+		return raw_pxl_id_b;
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SGBRG14_1X14:
+		return raw_pxl_id_gb;
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SGRBG14_1X14:
+		return raw_pxl_id_gr;
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+	case MEDIA_BUS_FMT_SRGGB14_1X14:
+		return raw_pxl_id_r;
+	default:
+		return raw_pxl_id_b;
+	}
+}
+
+static unsigned int get_sensor_fmt(unsigned int fmt)
+{
+	switch (fmt) {
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+		return img_fmt_bayer8;
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+		return img_fmt_bayer10;
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+		return img_fmt_bayer12;
+	case MEDIA_BUS_FMT_SBGGR14_1X14:
+	case MEDIA_BUS_FMT_SGBRG14_1X14:
+	case MEDIA_BUS_FMT_SGRBG14_1X14:
+	case MEDIA_BUS_FMT_SRGGB14_1X14:
+		return img_fmt_bayer14;
+	default:
+		return img_fmt_unknown;
+	}
+}
+
+static unsigned int get_img_fmt(unsigned int fourcc)
+{
+	switch (fourcc) {
+	case V4L2_PIX_FMT_MTISP_B8:
+		return img_fmt_bayer8;
+	case V4L2_PIX_FMT_MTISP_F8:
+		return img_fmt_fg_bayer8;
+	case V4L2_PIX_FMT_MTISP_B10:
+		return img_fmt_bayer10;
+	case V4L2_PIX_FMT_MTISP_F10:
+		return img_fmt_fg_bayer10;
+	case V4L2_PIX_FMT_MTISP_B12:
+		return img_fmt_bayer12;
+	case V4L2_PIX_FMT_MTISP_F12:
+		return img_fmt_fg_bayer12;
+	case V4L2_PIX_FMT_MTISP_B14:
+		return img_fmt_bayer14;
+	case V4L2_PIX_FMT_MTISP_F14:
+		return img_fmt_fg_bayer14;
+	default:
+		return img_fmt_unknown;
+	}
+}
+
+static unsigned int get_pixel_byte(unsigned int fourcc)
+{
+	switch (fourcc) {
+	case V4L2_PIX_FMT_MTISP_B8:
+	case V4L2_PIX_FMT_MTISP_F8:
+		return 8;
+	case V4L2_PIX_FMT_MTISP_B10:
+	case V4L2_PIX_FMT_MTISP_F10:
+		return 10;
+	case V4L2_PIX_FMT_MTISP_B12:
+	case V4L2_PIX_FMT_MTISP_F12:
+		return 12;
+	case V4L2_PIX_FMT_MTISP_B14:
+	case V4L2_PIX_FMT_MTISP_F14:
+		return 14;
+	case V4L2_PIX_FMT_MTISP_U8:
+	case V4L2_PIX_FMT_MTISP_U10:
+	case V4L2_PIX_FMT_MTISP_U12:
+	case V4L2_PIX_FMT_MTISP_U14:
+		return 16;
+	default:
+		return 10;
+	}
+}
+
+static void composer_deinit_done_cb(void *data)
+{
+	struct isp_p1_device *p1_dev = p1_ctx_to_dev(data);
+
+	disable_sys_clock(p1_dev);
+	/* Notify PM */
+	pm_runtime_put_sync(&p1_dev->pdev->dev);
+}
+
+/* ISP P1 interface functions */
+int mtk_isp_open(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	s32 usercount = atomic_inc_return(&isp_ctx->isp_user_cnt);
+	phandle rproc_phandle;
+	int ret;
+
+	dev_dbg(dev, "%s usercount=%d\n", __func__, usercount);
+
+	if (usercount == 1) {
+		p1_dev->scp_pdev = scp_get_pdev(p1_dev->pdev);
+		if (!p1_dev->scp_pdev) {
+			dev_err(dev, "Failed to get scp device\n");
+			return -EINVAL;
+		}
+		ret = of_property_read_u32(dev->of_node, "mediatek,scp",
+					   &rproc_phandle);
+		if (ret) {
+			dev_err(dev, "fail to get rproc_phandle:%d\n", ret);
+			return ret;
+		}
+
+		p1_dev->rproc_handle = rproc_get_by_phandle(rproc_phandle);
+		dev_dbg(dev, "p1 rproc_phandle: 0x%pK\n\n",
+			p1_dev->rproc_handle);
+		if (!p1_dev->rproc_handle) {
+			dev_err(dev, "fail to get rproc_handle\n");
+			return -EINVAL;
+		}
+
+		ret = rproc_boot(p1_dev->rproc_handle);
+		if (ret < 0) {
+			/*
+			 * Return 0 if downloading firmware successfully,
+			 * otherwise it is failed
+			 */
+			dev_err(dev, "rproc_boot failed:%d\n", ret);
+			return -EINVAL;
+		}
+
+		pm_runtime_get_sync(dev);
+
+		/* ISP HW INIT */
+		isp_ctx->isp_hw_module = ISP_CAM_B_IDX;
+		/* Use pure RAW as default HW path */
+		isp_ctx->isp_raw_path = ISP_PURE_RAW_PATH;
+
+		ret = isp_init_context(p1_dev);
+		if (ret)
+			return ret;
+		ret = isp_composer_init(isp_ctx);
+		if (ret)
+			return ret;
+		ret = isp_composer_hw_init(isp_ctx);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int mtk_isp_release(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+
+	if (atomic_dec_and_test(&p1_dev->isp_ctx.isp_user_cnt)) {
+		isp_composer_hw_deinit(isp_ctx, composer_deinit_done_cb);
+		isp_uninit_context(p1_dev);
+	}
+
+	dev_dbg(dev, "%s usercount = %d\n", __func__,
+		atomic_read(&p1_dev->isp_ctx.isp_user_cnt));
+
+	return 0;
+}
+
+int mtk_isp_streamon(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct p1_config_param config_param;
+	struct mtk_cam_dev *cam_dev = p1_dev->cam_dev;
+	struct v4l2_subdev_format sd_format;
+	unsigned int sd_width, sd_height;
+	unsigned int enable_dma, idx, i;
+	int ret;
+
+	p1_dev->isp_devs[isp_ctx->isp_hw_module].current_frame = 0;
+	p1_dev->isp_devs[isp_ctx->isp_hw_module].sof_count = 0;
+
+	isp_ctx->frame_seq_no = 1;
+	atomic_set(&isp_ctx->composed_frame_id, 0);
+
+	/* Get the enabled DMA ports */
+	enable_dma = 0;
+	for (i = 0; i < cam_dev->dev_node_num; i++) {
+		if (cam_dev->mem2mem2_nodes[i].enabled)
+			enable_dma |=
+				cam_dev->mem2mem2_nodes[i].desc.dma_port;
+	}
+	dev_dbg(dev, "%s enable_dma:0x%x", __func__, enable_dma);
+
+	/* sensor config */
+	sd_format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	ret = v4l2_subdev_call(cam_dev->sensor,
+			       pad, get_fmt, NULL, &sd_format);
+
+	if (ret) {
+		dev_dbg(dev, "sensor(%s) g_fmt on failed(%d)\n",
+			cam_dev->sensor->entity.name, ret);
+		return -EPERM;
+	}
+
+	dev_dbg(dev,
+		"sensor get_fmt ret=%d, w=%d, h=%d, code=0x%x, field=%d, color=%d\n",
+		ret, sd_format.format.width, sd_format.format.height,
+		sd_format.format.code, sd_format.format.field,
+		sd_format.format.colorspace);
+
+	config_param.cfg_in_param.continuous = 0x1;
+	config_param.cfg_in_param.subsample = 0x0;
+	/* fix to one pixel mode in default */
+	config_param.cfg_in_param.pixel_mode = one_pixel_mode;
+	/* support normal pattern in default */
+	config_param.cfg_in_param.data_pattern = 0x0;
+
+	config_param.cfg_in_param.crop.left = 0x0;
+	config_param.cfg_in_param.crop.top = 0x0;
+
+	config_param.cfg_in_param.raw_pixel_id =
+		get_sensor_pixel_id(sd_format.format.code);
+	config_param.cfg_in_param.img_fmt =
+		get_sensor_fmt(sd_format.format.code);
+	config_param.cfg_in_param.crop.width = sd_format.format.width;
+	config_param.cfg_in_param.crop.height = sd_format.format.height;
+	sd_width = sd_format.format.width;
+	sd_height = sd_format.format.height;
+
+	idx = MTK_CAM_P1_MAIN_STREAM_OUT;
+	if ((enable_dma & R_IMGO) == R_IMGO) {
+		struct v4l2_format *imgo_fmt =
+			&p1_dev->cam_dev->mem2mem2_nodes[idx].vdev_fmt;
+
+		config_param.cfg_main_param.pure_raw = isp_ctx->isp_raw_path;
+		config_param.cfg_main_param.pure_raw_pack = 1;
+		config_param.cfg_main_param.bypass = 0;
+
+		config_param.cfg_main_param.output.img_fmt =
+			get_img_fmt(imgo_fmt->fmt.pix_mp.pixelformat);
+		config_param.cfg_main_param.output.pixel_byte =
+			get_pixel_byte(imgo_fmt->fmt.pix_mp.pixelformat);
+		config_param.cfg_main_param.output.size.w =
+			imgo_fmt->fmt.pix_mp.width;
+		config_param.cfg_main_param.output.size.h =
+			imgo_fmt->fmt.pix_mp.height;
+
+		config_param.cfg_main_param.output.size.stride =
+			imgo_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+		config_param.cfg_main_param.output.size.xsize =
+			imgo_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+
+		config_param.cfg_main_param.output.crop.left = 0x0;
+		config_param.cfg_main_param.output.crop.top = 0x0;
+
+		config_param.cfg_main_param.output.crop.width = sd_width;
+		config_param.cfg_main_param.output.crop.height = sd_height;
+
+		WARN_ONCE(imgo_fmt->fmt.pix_mp.width > sd_width ||
+			  imgo_fmt->fmt.pix_mp.height > sd_height,
+			  "img out:%d:%d in:%d:%d",
+			  imgo_fmt->fmt.pix_mp.width,
+			  imgo_fmt->fmt.pix_mp.height,
+			  sd_width,
+			  sd_height);
+
+		dev_dbg(dev,
+			"imgo pixel_byte:%d img_fmt:0x%x raw:%d\n",
+			config_param.cfg_main_param.output.pixel_byte,
+			config_param.cfg_main_param.output.img_fmt,
+			config_param.cfg_main_param.pure_raw);
+		dev_dbg(dev,
+			"imgo param:size=(%0dx%0d),stride:%d,xsize:%d,crop=(%0dx%0d)\n",
+			config_param.cfg_main_param.output.size.w,
+			config_param.cfg_main_param.output.size.h,
+			config_param.cfg_main_param.output.size.stride,
+			config_param.cfg_main_param.output.size.xsize,
+			config_param.cfg_main_param.output.crop.width,
+			config_param.cfg_main_param.output.crop.height);
+	} else {
+		config_param.cfg_main_param.bypass = 1;
+	}
+
+	idx = MTK_CAM_P1_PACKED_BIN_OUT;
+	if ((enable_dma & R_RRZO) == R_RRZO) {
+		struct v4l2_format *rrzo_fmt =
+			&p1_dev->cam_dev->mem2mem2_nodes[idx].vdev_fmt;
+
+		config_param.cfg_resize_param.bypass = 0;
+		config_param.cfg_resize_param.output.img_fmt =
+			get_img_fmt(rrzo_fmt->fmt.pix_mp.pixelformat);
+		config_param.cfg_resize_param.output.pixel_byte =
+			get_pixel_byte(rrzo_fmt->fmt.pix_mp.pixelformat);
+		config_param.cfg_resize_param.output.size.w =
+			rrzo_fmt->fmt.pix_mp.width;
+		config_param.cfg_resize_param.output.size.h =
+			rrzo_fmt->fmt.pix_mp.height;
+		config_param.cfg_resize_param.output.size.stride =
+			rrzo_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+		config_param.cfg_resize_param.output.size.xsize =
+			rrzo_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+
+		config_param.cfg_resize_param.output.crop.left = 0x0;
+		config_param.cfg_resize_param.output.crop.top = 0x0;
+		config_param.cfg_resize_param.output.crop.width = sd_width;
+		config_param.cfg_resize_param.output.crop.height = sd_height;
+
+		WARN_ONCE(rrzo_fmt->fmt.pix_mp.width > sd_width ||
+			  rrzo_fmt->fmt.pix_mp.height > sd_height,
+			  "rrz out:%d:%d in:%d:%d",
+			  rrzo_fmt->fmt.pix_mp.width,
+			  rrzo_fmt->fmt.pix_mp.height,
+			  sd_width,
+			  sd_height);
+
+		dev_dbg(dev, "rrzo pixel_byte:%d img_fmt:0x%x\n",
+			config_param.cfg_resize_param.output.pixel_byte,
+			config_param.cfg_resize_param.output.img_fmt);
+		dev_dbg(dev,
+			"rrzo param:size=(%0dx%0d),stride:%d,xsize:%d,crop=(%0dx%0d)\n",
+			config_param.cfg_resize_param.output.size.w,
+			config_param.cfg_resize_param.output.size.h,
+			config_param.cfg_resize_param.output.size.stride,
+			config_param.cfg_resize_param.output.size.xsize,
+			config_param.cfg_resize_param.output.crop.width,
+			config_param.cfg_resize_param.output.crop.height);
+	} else {
+		config_param.cfg_resize_param.bypass = 1;
+	}
+
+	/* Configure meta DMAs info. */
+	config_param.cfg_meta_param.enabled_meta_dmas = enable_dma;
+
+	isp_composer_hw_config(isp_ctx, &config_param);
+
+	/* Stream on */
+	isp_composer_stream(isp_ctx, 1);
+	dev_dbg(dev, "%s done\n", __func__);
+	return 0;
+}
+
+int mtk_isp_streamoff(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+
+	isp_composer_stream(isp_ctx, 0);
+	dev_dbg(dev, "%s done\n", __func__);
+
+	return 0;
+}
+
+int mtk_isp_enqueue(struct device *dev,
+		    struct mtk_cam_dev_start_param *frameparamsbase)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct p1_frame_param frameparams;
+	struct mtk_isp_queue_job *framejob;
+	struct mtk_cam_dev_buffer **bundle_buffers;
+	unsigned int i, idx;
+
+	framejob = kzalloc(sizeof(*framejob), GFP_ATOMIC);
+	memset(framejob, 0, sizeof(*framejob));
+	memset(&frameparams, 0, sizeof(frameparams));
+	INIT_LIST_HEAD(&framejob->list_buf);
+
+	bundle_buffers = &frameparamsbase->buffers[0];
+	frameparams.frame_seq_no = isp_ctx->frame_seq_no++;
+	frameparams.sof_idx =
+		p1_dev->isp_devs[isp_ctx->isp_hw_module].sof_count;
+	framejob->request_fd = frameparamsbase->request_fd;
+	framejob->frame_seq_no = frameparams.frame_seq_no;
+
+	idx = MTK_CAM_P1_META_IN_0;
+	if (bundle_buffers[idx]) {
+		frameparams.tuning_addr.iova =
+			bundle_buffers[idx]->daddr;
+		frameparams.tuning_addr.scp_addr =
+			bundle_buffers[idx]->scp_addr;
+		list_add_tail(&bundle_buffers[idx]->list,
+			      &framejob->list_buf);
+	}
+
+	/* Image output */
+	idx = MTK_CAM_P1_MAIN_STREAM_OUT;
+	if (bundle_buffers[idx]) {
+		frameparams.img_dma_buffers[0].buffer.iova =
+			bundle_buffers[idx]->daddr;
+		frameparams.img_dma_buffers[0].buffer.scp_addr =
+			bundle_buffers[idx]->scp_addr;
+		dev_dbg(dev, "main stream address pa:0x%x iova:0x%x\n",
+			frameparams.img_dma_buffers[0].buffer.scp_addr,
+			frameparams.img_dma_buffers[0].buffer.iova);
+		list_add_tail(&bundle_buffers[idx]->list,
+			      &framejob->list_buf);
+	}
+
+	/* Resize output */
+	idx = MTK_CAM_P1_PACKED_BIN_OUT;
+	if (bundle_buffers[idx]) {
+		frameparams.img_dma_buffers[1].buffer.iova =
+			bundle_buffers[idx]->daddr;
+		frameparams.img_dma_buffers[1].buffer.scp_addr =
+			bundle_buffers[idx]->scp_addr;
+		dev_dbg(dev, "packed out address:0x%x iova:0x%x\n",
+			frameparams.img_dma_buffers[1].buffer.scp_addr,
+			frameparams.img_dma_buffers[1].buffer.iova);
+		list_add_tail(&bundle_buffers[idx]->list,
+			      &framejob->list_buf);
+	}
+
+	/* Meta output DMAs */
+	for (i = 0; i < MAX_META_DMA_NODES; i++) {
+		idx = MTK_CAM_P1_META_OUT_0 + i;
+		if (bundle_buffers[idx]) {
+			frameparams.meta_addrs[i].iova =
+			  bundle_buffers[idx]->daddr;
+			frameparams.meta_addrs[i].scp_addr =
+			  bundle_buffers[idx]->scp_addr;
+			list_add_tail(&bundle_buffers[idx]->list,
+				      &framejob->list_buf);
+		} else {
+			frameparams.meta_addrs[i].iova = 0;
+			frameparams.meta_addrs[i].scp_addr = 0;
+		}
+	}
+
+	spin_lock(&isp_ctx->p1_enqueue_list.lock);
+	list_add_tail(&framejob->list_entry, &isp_ctx->p1_enqueue_list.queue);
+	atomic_inc(&isp_ctx->p1_enqueue_list.queue_cnt);
+	spin_unlock(&isp_ctx->p1_enqueue_list.lock);
+
+	isp_composer_enqueue(isp_ctx, &frameparams, SCP_ISP_FRAME);
+	dev_dbg(dev, "request fd(0x%x) frame_seq_no(%d) is queued cnt:(%d)\n",
+		frameparamsbase->request_fd,
+		frameparams.frame_seq_no,
+		atomic_read(&isp_ctx->p1_enqueue_list.queue_cnt));
+
+	return 0;
+}
+
+static const struct dev_pm_ops mtk_isp_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mtk_isp_suspend, mtk_isp_resume)
+	SET_RUNTIME_PM_OPS(mtk_isp_suspend, mtk_isp_resume, NULL)
+};
+
+static struct platform_driver mtk_isp_driver = {
+	.probe   = mtk_isp_probe,
+	.remove  = mtk_isp_remove,
+	.driver  = {
+		.name  = ISP_DEV_NAME,
+		.of_match_table = mtk_isp_of_ids,
+		.pm     = &mtk_isp_pm_ops,
+	}
+};
+
+module_platform_driver(mtk_isp_driver);
+
+MODULE_DESCRIPTION("Camera ISP driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.h b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.h
new file mode 100644
index 0000000..6d13058
--- /dev/null
+++ b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.h
@@ -0,0 +1,288 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ryan Yu <ryan.yu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CAMERA_ISP_H
+#define __CAMERA_ISP_H
+
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/irqreturn.h>
+#include <linux/miscdevice.h>
+#include <linux/pm_qos.h>
+#include <linux/scatterlist.h>
+
+#include "mtk_cam-dev.h"
+#include "mtk_cam-ctx.h"
+#include "mtk_cam-scp.h"
+
+#define ISP_DEV_NAME		"mtk-cam"
+
+#define CAM_A_MAX_WIDTH		3328U
+#define CAM_A_MAX_HEIGHT	2496U
+#define CAM_B_MAX_WIDTH		5376U
+#define CAM_B_MAX_HEIGHT	4032U
+
+#define CAM_MIN_WIDTH		80U
+#define CAM_MIN_HEIGHT		60U
+
+#define IMG_MAX_WIDTH		CAM_B_MAX_WIDTH
+#define IMG_MAX_HEIGHT		CAM_B_MAX_HEIGHT
+#define IMG_MIN_WIDTH		CAM_MIN_WIDTH
+#define IMG_MIN_HEIGHT		CAM_MIN_HEIGHT
+
+#define RRZ_MAX_WIDTH		CAM_B_MAX_WIDTH
+#define RRZ_MAX_HEIGHT		CAM_B_MAX_HEIGHT
+#define RRZ_MIN_WIDTH		CAM_MIN_WIDTH
+#define RRZ_MIN_HEIGHT		CAM_MIN_HEIGHT
+
+#define R_IMGO		BIT(0)
+#define R_RRZO		BIT(1)
+#define R_AAO		BIT(3)
+#define R_AFO		BIT(4)
+#define R_LCSO		BIT(5)
+#define R_PDO		BIT(6)
+#define R_LMVO		BIT(7)
+#define R_FLKO		BIT(8)
+#define R_RSSO		BIT(9)
+#define R_PSO		BIT(10)
+
+#define ISP_COMPOSING_MAX_NUM		4
+#define ISP_FRAME_COMPOSING_MAX_NUM	3
+
+#define IRQ_DATA_BUF_SIZE		4
+#define COMPOSRE_EVENT_BUF_SIZE		4
+
+#define CQ_ADDRESS_OFFSET		0x640
+#define CQ_BUFFER_COUNT			3
+
+#define IRQ_STAT_STR "cam%c, SOF_%d irq(0x%x), " \
+			"dma(0x%x), frame_num(%d)/cq_num(%d)\n"
+
+/*
+ * In order with the sequence of device nodes defined in dtsi rule,
+ * one hardware module should be mapping to one node.
+ */
+enum isp_dev_node_enum {
+	ISP_CAMSYS_CONFIG_IDX = 0,
+	ISP_CAM_UNI_IDX,
+	ISP_CAM_A_IDX,
+	ISP_CAM_B_IDX,
+	ISP_DEV_NODE_NUM
+};
+
+/* Image RAW path for ISP P1 module. */
+enum isp_raw_path_enum {
+	ISP_PROCESS_RAW_PATH = 0,
+	ISP_PURE_RAW_PATH
+};
+
+enum {
+	img_fmt_unknown		= 0x0000,
+	img_fmt_raw_start	= 0x2200,
+	img_fmt_bayer8		= img_fmt_raw_start,
+	img_fmt_bayer10,
+	img_fmt_bayer12,
+	img_fmt_bayer14,
+	img_fmt_fg_bayer8,
+	img_fmt_fg_bayer10,
+	img_fmt_fg_bayer12,
+	img_fmt_fg_bayer14,
+};
+
+enum {
+	raw_pxl_id_b   = 0,
+	raw_pxl_id_gb,
+	raw_pxl_id_gr,
+	raw_pxl_id_r
+};
+
+enum {
+	default_pixel_mode = 0,
+	one_pixel_mode,
+	two_pixel_mode,
+	four_pixel_mode,
+	pixel_mode_num,
+};
+
+struct isp_queue {
+	struct list_head queue;
+	atomic_t queue_cnt;
+	spinlock_t lock; /* queue attributes protection */
+};
+
+struct isp_thread {
+	struct task_struct *thread;
+	wait_queue_head_t wq;
+};
+
+enum mtk_isp_scp_ipi_type {
+	SCP_ISP_CMD = 0,
+	SCP_ISP_FRAME,
+};
+
+struct mtk_isp_queue_work {
+	union {
+		struct mtk_isp_scp_p1_cmd cmd;
+		struct p1_frame_param frameparams;
+	};
+	struct list_head list_entry;
+	enum mtk_isp_scp_ipi_type type;
+};
+
+struct mtk_isp_queue_job {
+	struct list_head list_entry;
+	struct list_head list_buf;
+	unsigned int request_fd;
+	unsigned int frame_seq_no;
+};
+
+struct isp_clk_struct {
+	int num_clks;
+	struct clk_bulk_data *clk_list;
+};
+
+struct isp_device {
+	struct device *dev;
+	void __iomem *regs;
+	int irq;
+	spinlock_t spinlock_irq; /* ISP reg setting integrity */
+	unsigned int current_frame;
+	u8 sof_count;
+	u8 isp_hw_module;
+};
+
+struct mtk_isp_p1_ctx {
+	atomic_t scp_state;
+	struct isp_queue composer_txlist;
+	struct isp_thread composer_tx_thread;
+	atomic_t cmd_queued;
+	struct mutex composer_tx_lock; /* isp composer work protection */
+
+	struct isp_thread composer_rx_thread;
+	struct mtk_isp_scp_p1_cmd composer_evts[COMPOSRE_EVENT_BUF_SIZE];
+	atomic_t composer_evts_start;
+	atomic_t composer_evts_end;
+	spinlock_t composer_evts_lock; /* SCP events protection */
+	/* increase after ipi */
+	atomic_t ipi_occupied;
+	/* increase after frame enqueue */
+	atomic_t composing_frame;
+	/* current composed frame id */
+	atomic_t composed_frame_id;
+
+	struct isp_queue p1_enqueue_list;
+
+	struct isp_thread isp_deque_thread;
+	struct mtk_cam_dev_stat_event_data irq_event_datas[IRQ_DATA_BUF_SIZE];
+	atomic_t irq_data_start;
+	atomic_t irq_data_end;
+	spinlock_t irq_dequeue_lock; /* ISP frame dequeuq protection */
+
+	dma_addr_t scp_mem_pa;
+	dma_addr_t scp_mem_iova;
+	struct sg_table sgtable;
+
+	/* increase after open, decrease when close */
+	atomic_t isp_user_cnt;
+	/* frame sequence number, increase per en-queue*/
+	int frame_seq_no;
+	unsigned int isp_hw_module;
+	unsigned int isp_raw_path;
+
+	void (*composer_deinit_donecb)(void *isp_ctx);
+
+	struct list_head list;
+};
+
+struct isp_p1_device {
+	struct platform_device *pdev;
+
+	/* for SCP driver  */
+	struct platform_device *scp_pdev;
+	struct rproc *rproc_handle;
+
+	struct mtk_isp_p1_ctx isp_ctx;
+	struct isp_clk_struct isp_clk;
+	struct mtk_cam_dev *cam_dev;
+	struct isp_device *isp_devs;
+};
+
+static inline struct isp_p1_device *
+p1_ctx_to_dev(const struct mtk_isp_p1_ctx *__p1_ctx)
+{
+	return container_of(__p1_ctx, struct isp_p1_device, isp_ctx);
+}
+
+static inline struct isp_p1_device *get_p1_device(struct device *dev)
+{
+	return ((struct isp_p1_device *)dev_get_drvdata(dev));
+}
+
+int isp_composer_init(struct mtk_isp_p1_ctx *isp_ctx);
+int isp_composer_hw_init(struct mtk_isp_p1_ctx *isp_ctx);
+void isp_composer_hw_config(struct mtk_isp_p1_ctx *isp_ctx,
+			    struct p1_config_param *config_param);
+void isp_composer_stream(struct mtk_isp_p1_ctx *isp_ctx, int on);
+void isp_composer_hw_deinit(struct mtk_isp_p1_ctx *isp_ctx,
+			    void (*donecb)(void *data));
+void isp_composer_enqueue(struct mtk_isp_p1_ctx *isp_ctx,
+			  void *data,
+			  enum mtk_isp_scp_ipi_type type);
+
+/**
+ * mtk_isp_open - open isp driver and initialize related resources.
+ *
+ * @dev:	isp device.
+ *
+ */
+int mtk_isp_open(struct device *dev);
+
+/**
+ * mtk_isp_release - release isp driver and related resources.
+ *
+ * @dev:	isp device.
+ *
+ */
+int mtk_isp_release(struct device *dev);
+
+/**
+ * mtk_isp_streamon - start to output image & meta data.
+ *
+ * @dev:	isp device.
+ *
+ */
+int mtk_isp_streamon(struct device *dev);
+
+/**
+ * mtk_isp_streamoff -  stop to output image & meta data.
+ *
+ * @dev:	isp device.
+ *
+ */
+int mtk_isp_streamoff(struct device *dev);
+
+/**
+ * mtk_isp_enqueue - enqueue a frame bundle to ISP driver.
+ *
+ * @dev:	isp device.
+ * @frameparamsbase: pointer to &struct mtk_cam_dev_start_param.
+ *
+ */
+int mtk_isp_enqueue(struct device *dev,
+		    struct mtk_cam_dev_start_param *frameparamsbase);
+
+#endif /*__CAMERA_ISP_H*/
-- 
1.9.1


WARNING: multiple messages have this Message-ID (diff)
From: Jungo Lin <jungo.lin@mediatek.com>
To: tfiga@chromium.org, hans.verkuil@cisco.com,
	laurent.pinchart+renesas@ideasonboard.com,
	matthias.bgg@gmail.com, mchehab@kernel.org
Cc: Sean.Cheng@mediatek.com, Rynn.Wu@mediatek.com,
	srv_heupstream@mediatek.com, holmes.chiou@mediatek.com,
	ryan.yu@mediatek.com, Jerry-ch.Chen@mediatek.com,
	frankie.chiu@mediatek.com, jungo.lin@mediatek.com,
	sj.huang@mediatek.com, yuzhao@chromium.org,
	christie.yu@mediatek.com, seraph.huang@mediatek.com,
	zwisler@chromium.org, linux-mediatek@lists.infradead.org,
	frederic.chen@mediatek.com, linux-arm-kernel@lists.infradead.org,
	linux-media@vger.kernel.org
Subject: [RFC V1 10/12] media: platform: Add Mediatek ISP P1 device driver
Date: Thu, 28 Mar 2019 17:56:45 +0800	[thread overview]
Message-ID: <1553767007-11909-11-git-send-email-jungo.lin@mediatek.com> (raw)
In-Reply-To: <1553767007-11909-1-git-send-email-jungo.lin@mediatek.com>

This patch adds the Mediatek ISP P1 HW control device driver.
It handles the ISP HW configuration, provides interrupt handling and
initializes the V4L2 device nodes and other functions.

Signed-off-by: Jungo Lin <jungo.lin@mediatek.com>
---
 .../platform/mtk-isp/isp_50/cam/mtk_cam-regs.h     |  147 +++
 .../media/platform/mtk-isp/isp_50/cam/mtk_cam.c    | 1098 ++++++++++++++++++++
 .../media/platform/mtk-isp/isp_50/cam/mtk_cam.h    |  288 +++++
 3 files changed, 1533 insertions(+)
 create mode 100644 drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam-regs.h
 create mode 100644 drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.c
 create mode 100644 drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.h

diff --git a/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam-regs.h b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam-regs.h
new file mode 100644
index 0000000..90736a1
--- /dev/null
+++ b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam-regs.h
@@ -0,0 +1,147 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ryan Yu <ryan.yu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_REGS_H
+#define _CAM_REGS_H
+
+/* TG Bit Mask */
+#define VFDATA_EN_BIT	BIT(0)
+#define CMOS_EN_BIT	BIT(0)
+
+/* normal signal bit */
+#define VS_INT_ST	BIT(0)
+#define HW_PASS1_DON_ST	BIT(11)
+#define SOF_INT_ST	BIT(12)
+#define SW_PASS1_DON_ST	BIT(30)
+
+/* err status bit */
+#define TG_ERR_ST	BIT(4)
+#define TG_GBERR_ST	BIT(5)
+#define CQ_CODE_ERR_ST	BIT(6)
+#define CQ_APB_ERR_ST	BIT(7)
+#define CQ_VS_ERR_ST	BIT(8)
+#define AMX_ERR_ST	BIT(15)
+#define RMX_ERR_ST	BIT(16)
+#define BMX_ERR_ST	BIT(17)
+#define RRZO_ERR_ST	BIT(18)
+#define AFO_ERR_ST	BIT(19)
+#define IMGO_ERR_ST	BIT(20)
+#define AAO_ERR_ST	BIT(21)
+#define PSO_ERR_ST	BIT(22)
+#define LCSO_ERR_ST	BIT(23)
+#define BNR_ERR_ST	BIT(24)
+#define LSCI_ERR_ST	BIT(25)
+#define DMA_ERR_ST	BIT(29)
+
+/* CAM DMA done status */
+#define FLKO_DONE_ST	BIT(4)
+#define AFO_DONE_ST	BIT(5)
+#define AAO_DONE_ST	BIT(7)
+#define PSO_DONE_ST	BIT(14)
+
+/* IRQ signal mask */
+#define INT_ST_MASK_CAM	( \
+			VS_INT_ST |\
+			HW_PASS1_DON_ST |\
+			SOF_INT_ST |\
+			SW_PASS1_DON_ST)
+
+/* IRQ Warning Mask */
+#define INT_ST_MASK_CAM_WARN	(\
+				RRZO_ERR_ST |\
+				AFO_ERR_ST |\
+				IMGO_ERR_ST |\
+				AAO_ERR_ST |\
+				PSO_ERR_ST | \
+				LCSO_ERR_ST |\
+				BNR_ERR_ST |\
+				LSCI_ERR_ST)
+
+/* IRQ Error Mask */
+#define INT_ST_MASK_CAM_ERR	(\
+				TG_ERR_ST |\
+				TG_GBERR_ST |\
+				CQ_CODE_ERR_ST |\
+				CQ_APB_ERR_ST |\
+				CQ_VS_ERR_ST |\
+				BNR_ERR_ST |\
+				RMX_ERR_ST |\
+				BMX_ERR_ST |\
+				BNR_ERR_ST |\
+				LSCI_ERR_ST |\
+				DMA_ERR_ST)
+
+/* IRQ Signal Log Mask */
+#define INT_ST_LOG_MASK_CAM	(\
+				SOF_INT_ST |\
+				SW_PASS1_DON_ST |\
+				VS_INT_ST |\
+				TG_ERR_ST |\
+				TG_GBERR_ST |\
+				RRZO_ERR_ST |\
+				AFO_ERR_ST |\
+				IMGO_ERR_ST |\
+				AAO_ERR_ST |\
+				DMA_ERR_ST)
+
+/* DMA Event Notification Mask */
+#define DMA_ST_MASK_CAM	(\
+			AFO_DONE_ST |\
+			AAO_DONE_ST |\
+			PSO_DONE_ST |\
+			FLKO_DONE_ST)
+
+/* Status check */
+#define REG_CTL_EN		0x0004
+#define REG_CTL_DMA_EN		0x0008
+#define REG_CTL_FMT_SEL		0x0010
+#define REG_CTL_EN2		0x0018
+#define REG_CTL_RAW_INT_EN	0x0020
+#define REG_CTL_RAW_INT_STAT	0x0024
+#define REG_CTL_RAW_INT2_STAT	0x0034
+#define REG_CTL_RAW_INT3_STAT	0x00c4
+#define REG_CTL_TWIN_STAT	0x0050
+
+#define REG_TG_SEN_MODE		0x0230
+#define REG_TG_SEN_GRAB_PIX	0x0238
+#define REG_TG_SEN_GRAB_LIN	0x023c
+#define REG_TG_VF_CON		0x0234
+#define REG_TG_INTER_ST		0x026c
+#define REG_TG_SUB_PERIOD	0x02a4
+
+#define REG_IMGO_BASE_ADDR	0x1020
+#define REG_RRZO_BASE_ADDR	0x1050
+
+/* Error status log */
+#define REG_IMGO_ERR_STAT	0x1360
+#define REG_RRZO_ERR_STAT	0x1364
+#define REG_AAO_ERR_STAT	0x1368
+#define REG_AFO_ERR_STAT	0x136c
+#define REG_LCSO_ERR_STAT	0x1370
+#define REG_UFEO_ERR_STAT	0x1374
+#define REG_PDO_ERR_STAT	0x1378
+#define REG_BPCI_ERR_STAT	0x137c
+#define REG_LSCI_ERR_STAT	0x1384
+#define REG_PDI_ERR_STAT	0x138c
+#define REG_LMVO_ERR_STAT	0x1390
+#define REG_FLKO_ERR_STAT	0x1394
+#define REG_PSO_ERR_STAT	0x13a0
+
+/* ISP command */
+#define REG_CQ_THR0_BASEADDR	0x0198
+#define REG_CTL_SPARE2		0x0058
+#define REG_HW_FRAME_NUM	0x13b8
+
+#endif	/* _CAM_REGS_H */
diff --git a/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.c b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.c
new file mode 100644
index 0000000..935cf7e
--- /dev/null
+++ b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.c
@@ -0,0 +1,1098 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ryan Yu <ryan.yu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/atomic.h>
+#include <linux/cdev.h>
+#include <linux/compat.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/mtk_scp.h>
+#include <linux/pm_runtime.h>
+#include <linux/remoteproc.h>
+#include <linux/sched/clock.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+
+#include "mtk_cam.h"
+#include "mtk_cam-regs.h"
+#include "mtk_cam-ctx.h"
+
+static const struct of_device_id mtk_isp_of_ids[] = {
+	{.compatible = "mediatek,mt8183-camisp",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, mtk_isp_of_ids);
+
+/* list of clocks required by isp cam */
+static const char * const mtk_isp_clks[] = {
+	"CAMSYS_CAM_CGPDN", "CAMSYS_CAMTG_CGPDN"
+};
+
+static void isp_dumpdmastat(struct isp_device *isp_dev)
+{
+	dev_err(isp_dev->dev,
+		"IMGO:0x%x, RRZO:0x%x, AAO=0x%x, AFO=0x%x, LMVO=0x%x\n",
+		readl(isp_dev->regs + REG_IMGO_ERR_STAT),
+		readl(isp_dev->regs + REG_RRZO_ERR_STAT),
+		readl(isp_dev->regs + REG_AAO_ERR_STAT),
+		readl(isp_dev->regs + REG_AFO_ERR_STAT),
+		readl(isp_dev->regs + REG_LMVO_ERR_STAT));
+	dev_err(isp_dev->dev,
+		"LCSO=0x%x, PSO=0x%x, FLKO=0x%x, BPCI:0x%x, LSCI=0x%x\n",
+		readl(isp_dev->regs + REG_LCSO_ERR_STAT),
+		readl(isp_dev->regs + REG_PSO_ERR_STAT),
+		readl(isp_dev->regs + REG_FLKO_ERR_STAT),
+		readl(isp_dev->regs + REG_BPCI_ERR_STAT),
+		readl(isp_dev->regs + REG_LSCI_ERR_STAT));
+}
+
+static void mtk_isp_notify(struct mtk_isp_p1_ctx *isp_ctx,
+			   unsigned int request_fd,
+			   unsigned int frame_seq_no,
+			   struct list_head *list_buf,
+			   enum vb2_buffer_state state)
+{
+	struct isp_p1_device *p1_dev = p1_ctx_to_dev(isp_ctx);
+	struct device *dev = &p1_dev->pdev->dev;
+	struct mtk_cam_dev_finish_param fram_param;
+
+	fram_param.list_buf = list_buf;
+	fram_param.request_fd = request_fd;
+	fram_param.frame_seq_no = frame_seq_no;
+	fram_param.state = state;
+	dev_dbg(dev, "request fd(%d) frame_seq_no(%d)\n",
+		fram_param.request_fd,
+		fram_param.frame_seq_no);
+	mtk_cam_dev_core_job_finish(p1_dev->cam_dev, &fram_param);
+}
+
+static void isp_deque_frame(struct isp_p1_device *p1_dev, int frame_seq_no)
+{
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct platform_device *pdev = p1_dev->pdev;
+	struct mtk_isp_queue_job *framejob, *tmp;
+	struct isp_queue *p1_enqueue_list = &isp_ctx->p1_enqueue_list;
+
+	/* Match dequeue work and enqueue frame */
+	spin_lock(&p1_enqueue_list->lock);
+	list_for_each_entry_safe(framejob, tmp, &p1_enqueue_list->queue,
+				 list_entry) {
+		dev_dbg(&pdev->dev,
+			"%s frame_seq_no=%d, isp_composer_work->req_num=%d\n",
+			__func__,
+			framejob->frame_seq_no, frame_seq_no);
+		/* Match by the en-queued request number */
+		if (framejob->frame_seq_no == frame_seq_no) {
+			/* Pass to user space */
+			mtk_isp_notify(isp_ctx,
+				       framejob->request_fd,
+				       framejob->frame_seq_no,
+				       &framejob->list_buf,
+				       VB2_BUF_STATE_DONE);
+			atomic_dec(&p1_enqueue_list->queue_cnt);
+			dev_dbg(&pdev->dev,
+				"frame(frame_seq_no=%d) is done, queue_cnt(%d)\n",
+				framejob->frame_seq_no,
+				atomic_read(&p1_enqueue_list->queue_cnt));
+
+			/* remove only when frame ready */
+			list_del(&framejob->list_entry);
+			kfree(framejob);
+			break;
+		} else if (framejob->frame_seq_no < frame_seq_no) {
+			/* Pass to user space for frame drop */
+			mtk_isp_notify(isp_ctx,
+				       framejob->request_fd,
+				       framejob->frame_seq_no,
+				       &framejob->list_buf,
+				       VB2_BUF_STATE_ERROR);
+			atomic_dec(&p1_enqueue_list->queue_cnt);
+			dev_dbg(&pdev->dev,
+				"frame(frame_seq_no=%d) drop, queue_cnt(%d)\n",
+				framejob->frame_seq_no,
+				atomic_read(&p1_enqueue_list->queue_cnt));
+
+			/* remove only drop frame */
+			list_del(&framejob->list_entry);
+			kfree(framejob);
+		}
+	}
+	spin_unlock(&p1_enqueue_list->lock);
+}
+
+static int isp_deque_work(void *data)
+{
+	struct isp_p1_device *p1_dev = (struct isp_p1_device *)data;
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct device *dev = &p1_dev->pdev->dev;
+	struct mtk_cam_dev *cam_dev = p1_dev->cam_dev;
+	struct mtk_cam_dev_stat_event_data event_data;
+	atomic_t *irq_data_end = &isp_ctx->irq_data_end;
+	atomic_t *irq_data_start = &isp_ctx->irq_data_start;
+	unsigned long flags;
+	int ret, i;
+
+	while (1) {
+		ret = wait_event_interruptible(isp_ctx->isp_deque_thread.wq,
+					       (atomic_read(irq_data_end) !=
+					       atomic_read(irq_data_start)) ||
+					       kthread_should_stop());
+
+		if (kthread_should_stop())
+			break;
+
+		if (ret == ERESTARTSYS) {
+			dev_err(dev, "interrupted by a signal!\n");
+			continue;
+		}
+
+		spin_lock_irqsave(&isp_ctx->irq_dequeue_lock, flags);
+		i = atomic_read(&isp_ctx->irq_data_start);
+		memcpy(&event_data, &isp_ctx->irq_event_datas[i],
+		       sizeof(event_data));
+		memset(&isp_ctx->irq_event_datas[i], 0x00, sizeof(event_data));
+		atomic_set(&isp_ctx->irq_data_start, ++i & 0x3);
+		spin_unlock_irqrestore(&isp_ctx->irq_dequeue_lock, flags);
+
+		if (event_data.irq_status_mask & VS_INT_ST) {
+			/* Notify specific HW events to user space */
+			mtk_cam_dev_queue_event_dev_state(cam_dev,
+							  &event_data);
+			dev_dbg(dev,
+				"event IRQ(0x%x) DMA(0x%x) is sent\n",
+				event_data.irq_status_mask,
+				event_data.dma_status_mask);
+			mtk_cam_dev_queue_event_dev_state(cam_dev,
+							  &event_data);
+		} else if (event_data.irq_status_mask & SW_PASS1_DON_ST) {
+			isp_deque_frame(p1_dev,
+					event_data.frame_seq_no);
+		}
+	}
+	return 0;
+}
+
+static int irq_handle_sof(struct isp_device *isp_dev,
+			  dma_addr_t base_addr,
+			  unsigned int frame_num)
+{
+	unsigned int cq_addr_index;
+	struct isp_p1_device *p1_dev = get_p1_device(isp_dev->dev);
+	int cq_num = atomic_read(&p1_dev->isp_ctx.composed_frame_id);
+
+	if (cq_num > frame_num) {
+		cq_addr_index = frame_num % CQ_BUFFER_COUNT;
+
+		writel(base_addr +
+			(dma_addr_t)(CQ_ADDRESS_OFFSET * cq_addr_index),
+			isp_dev->regs + REG_CQ_THR0_BASEADDR);
+		dev_dbg(isp_dev->dev,
+			"SOF_INT_ST cq_num:%d, frame_num:%d cq_addr:%d",
+			cq_num, frame_num, cq_addr_index);
+	} else {
+		dev_dbg(isp_dev->dev,
+			"SOF_INT_ST cq_num:%d, frame_num:%d",
+			cq_num, frame_num);
+	}
+
+	isp_dev->sof_count += 1;
+
+	return cq_num;
+}
+
+static int irq_handle_notify_event(struct isp_device *isp_dev,
+				   unsigned int irqstatus,
+				   unsigned int dmastatus)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(isp_dev->dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&isp_ctx->irq_dequeue_lock, flags);
+	i = atomic_read(&isp_ctx->irq_data_end);
+	isp_ctx->irq_event_datas[i].frame_seq_no = isp_dev->current_frame;
+	isp_ctx->irq_event_datas[i].irq_status_mask |=
+		(irqstatus & INT_ST_MASK_CAM);
+	isp_ctx->irq_event_datas[i].dma_status_mask |=
+		(dmastatus & DMA_ST_MASK_CAM);
+	atomic_set(&isp_ctx->irq_data_end, ++i & 0x3);
+	spin_unlock_irqrestore(&isp_ctx->irq_dequeue_lock, flags);
+
+	wake_up_interruptible(&isp_ctx->isp_deque_thread.wq);
+
+	dev_dbg(isp_dev->dev,
+		"%s notify IRQ (0x%x) DMA status (0x%x) for frame_seq_no: %d\n",
+		__func__,
+		(irqstatus & INT_ST_MASK_CAM),
+		(dmastatus & DMA_ST_MASK_CAM),
+		isp_dev->current_frame);
+
+	return 0;
+}
+
+irqreturn_t isp_irq_cam(int irq, void *data)
+{
+	struct isp_device *isp_dev = (struct isp_device *)data;
+	struct isp_p1_device *p1_dev = get_p1_device(isp_dev->dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct device *dev = isp_dev->dev;
+	unsigned int cardinalnum, cq_num, hw_frame_num;
+	unsigned int irqstatus, errstatus, warnstatus, dmastatus;
+	unsigned long flags;
+
+	/* Check the streaming is off or not */
+	if (!p1_dev->cam_dev->streaming)
+		return IRQ_HANDLED;
+
+	cardinalnum = isp_dev->isp_hw_module - ISP_CAM_A_IDX;
+	cq_num = 0;
+
+	spin_lock_irqsave(&isp_dev->spinlock_irq, flags);
+	irqstatus = readl(isp_dev->regs + REG_CTL_RAW_INT_STAT);
+	dmastatus = readl(isp_dev->regs + REG_CTL_RAW_INT2_STAT);
+	hw_frame_num = readl(isp_dev->regs + REG_HW_FRAME_NUM);
+	spin_unlock_irqrestore(&isp_dev->spinlock_irq, flags);
+
+	/* Ignore unnecessary IRQ */
+	if (irqstatus == 0)
+		return IRQ_HANDLED;
+
+	errstatus = irqstatus & INT_ST_MASK_CAM_ERR;
+	warnstatus = irqstatus & INT_ST_MASK_CAM_WARN;
+	irqstatus = irqstatus & INT_ST_MASK_CAM;
+
+	/* sof , done order check . */
+	spin_lock_irqsave(&isp_dev->spinlock_irq, flags);
+	if ((irqstatus & HW_PASS1_DON_ST) && (irqstatus & SOF_INT_ST)) {
+		dev_warn(dev,
+			 "isp sof_don block, %d\n",
+			 isp_dev->sof_count);
+
+		/* Notify IRQ event and enqueue ready frame */
+		irq_handle_notify_event(isp_dev, irqstatus, dmastatus);
+		isp_dev->current_frame = hw_frame_num;
+	} else {
+		if (irqstatus & SOF_INT_ST)
+			isp_dev->current_frame = hw_frame_num;
+
+		if ((irqstatus & INT_ST_MASK_CAM) ||
+		    (dmastatus & DMA_ST_MASK_CAM))
+			irq_handle_notify_event(isp_dev, irqstatus, dmastatus);
+	}
+	spin_unlock_irqrestore(&isp_dev->spinlock_irq, flags);
+
+	if (irqstatus & SOF_INT_ST)
+		cq_num = irq_handle_sof(isp_dev, isp_ctx->scp_mem_iova,
+					hw_frame_num);
+
+	if (irqstatus & SW_PASS1_DON_ST) {
+		int num = atomic_dec_return(&isp_ctx->composing_frame);
+
+		dev_dbg(dev, "SW_PASS1_DON_ST queued frame:%d\n", num);
+		/* Notify TX thread to send if TX frame is blocked */
+		wake_up_interruptible
+				(&isp_ctx->composer_tx_thread.wq);
+	}
+
+	/* check ISP error status */
+	if (errstatus) {
+		dev_err(dev,
+			"raw_int_err:0x%x/0x%x, raw_int3_err:0x%x\n",
+			irqstatus, warnstatus, errstatus);
+
+		/* show DMA errors in detail */
+		if (errstatus & DMA_ERR_ST)
+			isp_dumpdmastat(isp_dev);
+	}
+
+	if (irqstatus & INT_ST_LOG_MASK_CAM)
+		dev_dbg(dev, IRQ_STAT_STR,
+			'A' + cardinalnum,
+			isp_dev->sof_count,
+			irqstatus,
+			dmastatus,
+			hw_frame_num,
+			cq_num);
+	return IRQ_HANDLED;
+}
+
+static int enable_sys_clock(struct isp_p1_device *p1_dev)
+{
+	struct device *dev = &p1_dev->pdev->dev;
+	int ret;
+
+	dev_info(dev, "- %s dev id:%d\n", __func__, dev->id);
+
+	ret = clk_bulk_prepare_enable(p1_dev->isp_clk.num_clks,
+				      p1_dev->isp_clk.clk_list);
+	if (ret < 0)
+		goto clk_err;
+	return 0;
+clk_err:
+	dev_err(dev, "cannot pre-en isp_cam clock:%d\n", ret);
+	clk_bulk_disable_unprepare(p1_dev->isp_clk.num_clks,
+				   p1_dev->isp_clk.clk_list);
+	return ret;
+}
+
+static void disable_sys_clock(struct isp_p1_device *p1_dev)
+{
+	struct device *dev = &p1_dev->pdev->dev;
+
+	dev_info(dev, "- %s dev id:%d\n", __func__, dev->id);
+	clk_bulk_disable_unprepare(p1_dev->isp_clk.num_clks,
+				   p1_dev->isp_clk.clk_list);
+}
+
+static int mtk_isp_probe(struct platform_device *pdev)
+{
+	struct isp_p1_device *p1_dev;
+	struct mtk_isp_p1_ctx *isp_ctx;
+	struct isp_device *isp_dev;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int ret;
+	unsigned int i;
+
+	/* Allocate context */
+	p1_dev = devm_kzalloc(dev, sizeof(*p1_dev), GFP_KERNEL);
+	if (!p1_dev)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, p1_dev);
+	isp_ctx = &p1_dev->isp_ctx;
+	p1_dev->pdev = pdev;
+
+	p1_dev->isp_devs =
+		devm_kzalloc(dev,
+			     sizeof(struct isp_device) * ISP_DEV_NODE_NUM,
+			     GFP_KERNEL);
+	if (!p1_dev->isp_devs)
+		return -ENOMEM;
+
+	p1_dev->cam_dev =
+		devm_kzalloc(dev, sizeof(struct mtk_cam_dev), GFP_KERNEL);
+	if (!p1_dev->isp_devs)
+		return -ENOMEM;
+
+	/* iomap registers */
+	for (i = ISP_CAMSYS_CONFIG_IDX; i < ISP_DEV_NODE_NUM; i++) {
+		isp_dev = &p1_dev->isp_devs[i];
+		isp_dev->isp_hw_module = i;
+		isp_dev->dev = dev;
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		isp_dev->regs = devm_ioremap_resource(dev, res);
+
+		dev_info(dev, "cam%u, map_addr=0x%lx\n",
+			 i, (unsigned long)isp_dev->regs);
+
+		if (!isp_dev->regs)
+			return PTR_ERR(isp_dev->regs);
+
+		/* support IRQ from ISP_CAM_A_IDX */
+		if (i >= ISP_CAM_A_IDX) {
+			/* reg & interrupts index is shifted with 1  */
+			isp_dev->irq = platform_get_irq(pdev, i - 1);
+			if (isp_dev->irq > 0) {
+				ret = devm_request_irq(dev, isp_dev->irq,
+						       isp_irq_cam,
+						       IRQF_SHARED,
+						       dev_driver_string(dev),
+						       (void *)isp_dev);
+				if (ret) {
+					dev_err(dev,
+						"req_irq fail, dev(%s) irq=%d\n",
+						dev->of_node->name,
+						isp_dev->irq);
+					return ret;
+				}
+				dev_info(dev, "Registered irq=%d, ISR: %s\n",
+					 isp_dev->irq, dev_driver_string(dev));
+			}
+		}
+		spin_lock_init(&isp_dev->spinlock_irq);
+	}
+
+	p1_dev->isp_clk.num_clks = ARRAY_SIZE(mtk_isp_clks);
+	p1_dev->isp_clk.clk_list =
+		devm_kcalloc(dev,
+			     p1_dev->isp_clk.num_clks,
+			     sizeof(*p1_dev->isp_clk.clk_list),
+			     GFP_KERNEL);
+	if (!p1_dev->isp_clk.clk_list)
+		return -ENOMEM;
+
+	for (i = 0; i < p1_dev->isp_clk.num_clks; ++i)
+		p1_dev->isp_clk.clk_list->id = mtk_isp_clks[i];
+
+	ret = devm_clk_bulk_get(dev,
+				p1_dev->isp_clk.num_clks,
+				p1_dev->isp_clk.clk_list);
+	if (ret) {
+		dev_err(dev, "cannot get isp cam clock:%d\n", ret);
+		return ret;
+	}
+
+	/* initialize the v4l2 common part */
+	ret = mtk_cam_dev_core_init(pdev, p1_dev->cam_dev);
+	if (ret)
+		return ret;
+
+	spin_lock_init(&isp_ctx->p1_enqueue_list.lock);
+	atomic_set(&p1_dev->isp_ctx.isp_user_cnt, 0);
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int mtk_isp_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct isp_p1_device *p1_dev = dev_get_drvdata(dev);
+
+	pm_runtime_disable(dev);
+	mtk_cam_dev_core_release(pdev, p1_dev->cam_dev);
+
+	return 0;
+}
+
+static int mtk_isp_suspend(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct isp_device *isp_dev;
+	unsigned int reg_val;
+	int usercount, module;
+
+	module = p1_dev->isp_ctx.isp_hw_module;
+	usercount = atomic_read(&p1_dev->isp_ctx.isp_user_cnt);
+
+	dev_dbg(dev, "- %s:%d\n", __func__, usercount);
+
+	/* If no user count, no further action */
+	if (!usercount)
+		return 0;
+
+	isp_dev = &p1_dev->isp_devs[module];
+	reg_val = readl(isp_dev->regs + REG_TG_VF_CON);
+	if (reg_val & VFDATA_EN_BIT) {
+		dev_dbg(dev, "Cam:%d suspend, disable VF\n", module);
+		/* disable VF */
+		writel((reg_val & (~VFDATA_EN_BIT)),
+		       isp_dev->regs + REG_TG_VF_CON);
+		/*
+		 * After VF enable, The TG frame count will be reset to 0;
+		 */
+		reg_val = readl(isp_dev->regs + REG_TG_SEN_MODE);
+		writel((reg_val & (~CMOS_EN_BIT)),
+		       isp_dev->regs +  + REG_TG_SEN_MODE);
+	}
+
+	disable_sys_clock(p1_dev);
+
+	return 0;
+}
+
+static int mtk_isp_resume(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct isp_device *isp_dev;
+	unsigned int reg_val;
+	int module, usercount;
+
+	module = p1_dev->isp_ctx.isp_hw_module;
+	usercount = atomic_read(&p1_dev->isp_ctx.isp_user_cnt);
+
+	dev_dbg(dev, "- %s:%d\n", __func__, usercount);
+
+	/* If no user count, no further action */
+	if (!usercount)
+		return 0;
+
+	enable_sys_clock(p1_dev);
+
+	/* V4L2 stream-on phase & restore HW stream-on status */
+	if (p1_dev->cam_dev->streaming) {
+		isp_dev = &p1_dev->isp_devs[module];
+		dev_dbg(dev, "Cam:%d resume,enable VF\n", module);
+		/* Enable CMOS */
+		reg_val = readl(isp_dev->regs + REG_TG_SEN_MODE);
+		writel((reg_val | CMOS_EN_BIT),
+		       isp_dev->regs + REG_TG_SEN_MODE);
+		/* Enable VF */
+		reg_val = readl(isp_dev->regs + REG_TG_VF_CON);
+		writel((reg_val | VFDATA_EN_BIT),
+		       isp_dev->regs + REG_TG_VF_CON);
+	}
+	return 0;
+}
+
+static int isp_init_context(struct isp_p1_device *p1_dev)
+{
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct device *dev = &p1_dev->pdev->dev;
+	unsigned int i;
+
+	dev_dbg(dev, "init irq work thread\n");
+	if (!isp_ctx->isp_deque_thread.thread) {
+		mutex_init(&isp_ctx->composer_tx_lock);
+		init_waitqueue_head(&isp_ctx->isp_deque_thread.wq);
+		isp_ctx->isp_deque_thread.thread =
+			kthread_run(isp_deque_work, (void *)p1_dev,
+				    "isp_deque_work");
+		if (IS_ERR(isp_ctx->isp_deque_thread.thread)) {
+			dev_err(dev, "unable to alloc kthread\n");
+			isp_ctx->isp_deque_thread.thread = NULL;
+			return -ENOMEM;
+		}
+	}
+	spin_lock_init(&isp_ctx->irq_dequeue_lock);
+
+	INIT_LIST_HEAD(&isp_ctx->p1_enqueue_list.queue);
+	atomic_set(&isp_ctx->p1_enqueue_list.queue_cnt, 0);
+
+	for (i = 0; i < ISP_DEV_NODE_NUM; i++)
+		spin_lock_init(&p1_dev->isp_devs[i].spinlock_irq);
+
+	spin_lock_init(&isp_ctx->p1_enqueue_list.lock);
+	spin_lock_init(&isp_ctx->composer_txlist.lock);
+
+	atomic_set(&isp_ctx->irq_data_end, 0);
+	atomic_set(&isp_ctx->irq_data_start, 0);
+	return 0;
+}
+
+static int isp_uninit_context(struct isp_p1_device *p1_dev)
+{
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct mtk_isp_queue_job *framejob, *tmp_framejob;
+
+	spin_lock_irq(&isp_ctx->p1_enqueue_list.lock);
+	list_for_each_entry_safe(framejob, tmp_framejob,
+				 &isp_ctx->p1_enqueue_list.queue, list_entry) {
+		list_del(&framejob->list_entry);
+		kfree(framejob);
+	}
+	spin_unlock_irq(&isp_ctx->p1_enqueue_list.lock);
+
+	atomic_set(&isp_ctx->isp_user_cnt, 0);
+
+	if (!IS_ERR(isp_ctx->isp_deque_thread.thread)) {
+		kthread_stop(isp_ctx->isp_deque_thread.thread);
+		wake_up_interruptible(&isp_ctx->isp_deque_thread.wq);
+		isp_ctx->isp_deque_thread.thread = NULL;
+	}
+
+	return 0;
+}
+
+/* Utility functions */
+static unsigned int get_sensor_pixel_id(unsigned int fmt)
+{
+	switch (fmt) {
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+	case MEDIA_BUS_FMT_SBGGR14_1X14:
+		return raw_pxl_id_b;
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SGBRG14_1X14:
+		return raw_pxl_id_gb;
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SGRBG14_1X14:
+		return raw_pxl_id_gr;
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+	case MEDIA_BUS_FMT_SRGGB14_1X14:
+		return raw_pxl_id_r;
+	default:
+		return raw_pxl_id_b;
+	}
+}
+
+static unsigned int get_sensor_fmt(unsigned int fmt)
+{
+	switch (fmt) {
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+		return img_fmt_bayer8;
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+		return img_fmt_bayer10;
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+		return img_fmt_bayer12;
+	case MEDIA_BUS_FMT_SBGGR14_1X14:
+	case MEDIA_BUS_FMT_SGBRG14_1X14:
+	case MEDIA_BUS_FMT_SGRBG14_1X14:
+	case MEDIA_BUS_FMT_SRGGB14_1X14:
+		return img_fmt_bayer14;
+	default:
+		return img_fmt_unknown;
+	}
+}
+
+static unsigned int get_img_fmt(unsigned int fourcc)
+{
+	switch (fourcc) {
+	case V4L2_PIX_FMT_MTISP_B8:
+		return img_fmt_bayer8;
+	case V4L2_PIX_FMT_MTISP_F8:
+		return img_fmt_fg_bayer8;
+	case V4L2_PIX_FMT_MTISP_B10:
+		return img_fmt_bayer10;
+	case V4L2_PIX_FMT_MTISP_F10:
+		return img_fmt_fg_bayer10;
+	case V4L2_PIX_FMT_MTISP_B12:
+		return img_fmt_bayer12;
+	case V4L2_PIX_FMT_MTISP_F12:
+		return img_fmt_fg_bayer12;
+	case V4L2_PIX_FMT_MTISP_B14:
+		return img_fmt_bayer14;
+	case V4L2_PIX_FMT_MTISP_F14:
+		return img_fmt_fg_bayer14;
+	default:
+		return img_fmt_unknown;
+	}
+}
+
+static unsigned int get_pixel_byte(unsigned int fourcc)
+{
+	switch (fourcc) {
+	case V4L2_PIX_FMT_MTISP_B8:
+	case V4L2_PIX_FMT_MTISP_F8:
+		return 8;
+	case V4L2_PIX_FMT_MTISP_B10:
+	case V4L2_PIX_FMT_MTISP_F10:
+		return 10;
+	case V4L2_PIX_FMT_MTISP_B12:
+	case V4L2_PIX_FMT_MTISP_F12:
+		return 12;
+	case V4L2_PIX_FMT_MTISP_B14:
+	case V4L2_PIX_FMT_MTISP_F14:
+		return 14;
+	case V4L2_PIX_FMT_MTISP_U8:
+	case V4L2_PIX_FMT_MTISP_U10:
+	case V4L2_PIX_FMT_MTISP_U12:
+	case V4L2_PIX_FMT_MTISP_U14:
+		return 16;
+	default:
+		return 10;
+	}
+}
+
+static void composer_deinit_done_cb(void *data)
+{
+	struct isp_p1_device *p1_dev = p1_ctx_to_dev(data);
+
+	disable_sys_clock(p1_dev);
+	/* Notify PM */
+	pm_runtime_put_sync(&p1_dev->pdev->dev);
+}
+
+/* ISP P1 interface functions */
+int mtk_isp_open(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	s32 usercount = atomic_inc_return(&isp_ctx->isp_user_cnt);
+	phandle rproc_phandle;
+	int ret;
+
+	dev_dbg(dev, "%s usercount=%d\n", __func__, usercount);
+
+	if (usercount == 1) {
+		p1_dev->scp_pdev = scp_get_pdev(p1_dev->pdev);
+		if (!p1_dev->scp_pdev) {
+			dev_err(dev, "Failed to get scp device\n");
+			return -EINVAL;
+		}
+		ret = of_property_read_u32(dev->of_node, "mediatek,scp",
+					   &rproc_phandle);
+		if (ret) {
+			dev_err(dev, "fail to get rproc_phandle:%d\n", ret);
+			return ret;
+		}
+
+		p1_dev->rproc_handle = rproc_get_by_phandle(rproc_phandle);
+		dev_dbg(dev, "p1 rproc_phandle: 0x%pK\n\n",
+			p1_dev->rproc_handle);
+		if (!p1_dev->rproc_handle) {
+			dev_err(dev, "fail to get rproc_handle\n");
+			return -EINVAL;
+		}
+
+		ret = rproc_boot(p1_dev->rproc_handle);
+		if (ret < 0) {
+			/*
+			 * Return 0 if downloading firmware successfully,
+			 * otherwise it is failed
+			 */
+			dev_err(dev, "rproc_boot failed:%d\n", ret);
+			return -EINVAL;
+		}
+
+		pm_runtime_get_sync(dev);
+
+		/* ISP HW INIT */
+		isp_ctx->isp_hw_module = ISP_CAM_B_IDX;
+		/* Use pure RAW as default HW path */
+		isp_ctx->isp_raw_path = ISP_PURE_RAW_PATH;
+
+		ret = isp_init_context(p1_dev);
+		if (ret)
+			return ret;
+		ret = isp_composer_init(isp_ctx);
+		if (ret)
+			return ret;
+		ret = isp_composer_hw_init(isp_ctx);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int mtk_isp_release(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+
+	if (atomic_dec_and_test(&p1_dev->isp_ctx.isp_user_cnt)) {
+		isp_composer_hw_deinit(isp_ctx, composer_deinit_done_cb);
+		isp_uninit_context(p1_dev);
+	}
+
+	dev_dbg(dev, "%s usercount = %d\n", __func__,
+		atomic_read(&p1_dev->isp_ctx.isp_user_cnt));
+
+	return 0;
+}
+
+int mtk_isp_streamon(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct p1_config_param config_param;
+	struct mtk_cam_dev *cam_dev = p1_dev->cam_dev;
+	struct v4l2_subdev_format sd_format;
+	unsigned int sd_width, sd_height;
+	unsigned int enable_dma, idx, i;
+	int ret;
+
+	p1_dev->isp_devs[isp_ctx->isp_hw_module].current_frame = 0;
+	p1_dev->isp_devs[isp_ctx->isp_hw_module].sof_count = 0;
+
+	isp_ctx->frame_seq_no = 1;
+	atomic_set(&isp_ctx->composed_frame_id, 0);
+
+	/* Get the enabled DMA ports */
+	enable_dma = 0;
+	for (i = 0; i < cam_dev->dev_node_num; i++) {
+		if (cam_dev->mem2mem2_nodes[i].enabled)
+			enable_dma |=
+				cam_dev->mem2mem2_nodes[i].desc.dma_port;
+	}
+	dev_dbg(dev, "%s enable_dma:0x%x", __func__, enable_dma);
+
+	/* sensor config */
+	sd_format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	ret = v4l2_subdev_call(cam_dev->sensor,
+			       pad, get_fmt, NULL, &sd_format);
+
+	if (ret) {
+		dev_dbg(dev, "sensor(%s) g_fmt on failed(%d)\n",
+			cam_dev->sensor->entity.name, ret);
+		return -EPERM;
+	}
+
+	dev_dbg(dev,
+		"sensor get_fmt ret=%d, w=%d, h=%d, code=0x%x, field=%d, color=%d\n",
+		ret, sd_format.format.width, sd_format.format.height,
+		sd_format.format.code, sd_format.format.field,
+		sd_format.format.colorspace);
+
+	config_param.cfg_in_param.continuous = 0x1;
+	config_param.cfg_in_param.subsample = 0x0;
+	/* fix to one pixel mode in default */
+	config_param.cfg_in_param.pixel_mode = one_pixel_mode;
+	/* support normal pattern in default */
+	config_param.cfg_in_param.data_pattern = 0x0;
+
+	config_param.cfg_in_param.crop.left = 0x0;
+	config_param.cfg_in_param.crop.top = 0x0;
+
+	config_param.cfg_in_param.raw_pixel_id =
+		get_sensor_pixel_id(sd_format.format.code);
+	config_param.cfg_in_param.img_fmt =
+		get_sensor_fmt(sd_format.format.code);
+	config_param.cfg_in_param.crop.width = sd_format.format.width;
+	config_param.cfg_in_param.crop.height = sd_format.format.height;
+	sd_width = sd_format.format.width;
+	sd_height = sd_format.format.height;
+
+	idx = MTK_CAM_P1_MAIN_STREAM_OUT;
+	if ((enable_dma & R_IMGO) == R_IMGO) {
+		struct v4l2_format *imgo_fmt =
+			&p1_dev->cam_dev->mem2mem2_nodes[idx].vdev_fmt;
+
+		config_param.cfg_main_param.pure_raw = isp_ctx->isp_raw_path;
+		config_param.cfg_main_param.pure_raw_pack = 1;
+		config_param.cfg_main_param.bypass = 0;
+
+		config_param.cfg_main_param.output.img_fmt =
+			get_img_fmt(imgo_fmt->fmt.pix_mp.pixelformat);
+		config_param.cfg_main_param.output.pixel_byte =
+			get_pixel_byte(imgo_fmt->fmt.pix_mp.pixelformat);
+		config_param.cfg_main_param.output.size.w =
+			imgo_fmt->fmt.pix_mp.width;
+		config_param.cfg_main_param.output.size.h =
+			imgo_fmt->fmt.pix_mp.height;
+
+		config_param.cfg_main_param.output.size.stride =
+			imgo_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+		config_param.cfg_main_param.output.size.xsize =
+			imgo_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+
+		config_param.cfg_main_param.output.crop.left = 0x0;
+		config_param.cfg_main_param.output.crop.top = 0x0;
+
+		config_param.cfg_main_param.output.crop.width = sd_width;
+		config_param.cfg_main_param.output.crop.height = sd_height;
+
+		WARN_ONCE(imgo_fmt->fmt.pix_mp.width > sd_width ||
+			  imgo_fmt->fmt.pix_mp.height > sd_height,
+			  "img out:%d:%d in:%d:%d",
+			  imgo_fmt->fmt.pix_mp.width,
+			  imgo_fmt->fmt.pix_mp.height,
+			  sd_width,
+			  sd_height);
+
+		dev_dbg(dev,
+			"imgo pixel_byte:%d img_fmt:0x%x raw:%d\n",
+			config_param.cfg_main_param.output.pixel_byte,
+			config_param.cfg_main_param.output.img_fmt,
+			config_param.cfg_main_param.pure_raw);
+		dev_dbg(dev,
+			"imgo param:size=(%0dx%0d),stride:%d,xsize:%d,crop=(%0dx%0d)\n",
+			config_param.cfg_main_param.output.size.w,
+			config_param.cfg_main_param.output.size.h,
+			config_param.cfg_main_param.output.size.stride,
+			config_param.cfg_main_param.output.size.xsize,
+			config_param.cfg_main_param.output.crop.width,
+			config_param.cfg_main_param.output.crop.height);
+	} else {
+		config_param.cfg_main_param.bypass = 1;
+	}
+
+	idx = MTK_CAM_P1_PACKED_BIN_OUT;
+	if ((enable_dma & R_RRZO) == R_RRZO) {
+		struct v4l2_format *rrzo_fmt =
+			&p1_dev->cam_dev->mem2mem2_nodes[idx].vdev_fmt;
+
+		config_param.cfg_resize_param.bypass = 0;
+		config_param.cfg_resize_param.output.img_fmt =
+			get_img_fmt(rrzo_fmt->fmt.pix_mp.pixelformat);
+		config_param.cfg_resize_param.output.pixel_byte =
+			get_pixel_byte(rrzo_fmt->fmt.pix_mp.pixelformat);
+		config_param.cfg_resize_param.output.size.w =
+			rrzo_fmt->fmt.pix_mp.width;
+		config_param.cfg_resize_param.output.size.h =
+			rrzo_fmt->fmt.pix_mp.height;
+		config_param.cfg_resize_param.output.size.stride =
+			rrzo_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+		config_param.cfg_resize_param.output.size.xsize =
+			rrzo_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+
+		config_param.cfg_resize_param.output.crop.left = 0x0;
+		config_param.cfg_resize_param.output.crop.top = 0x0;
+		config_param.cfg_resize_param.output.crop.width = sd_width;
+		config_param.cfg_resize_param.output.crop.height = sd_height;
+
+		WARN_ONCE(rrzo_fmt->fmt.pix_mp.width > sd_width ||
+			  rrzo_fmt->fmt.pix_mp.height > sd_height,
+			  "rrz out:%d:%d in:%d:%d",
+			  rrzo_fmt->fmt.pix_mp.width,
+			  rrzo_fmt->fmt.pix_mp.height,
+			  sd_width,
+			  sd_height);
+
+		dev_dbg(dev, "rrzo pixel_byte:%d img_fmt:0x%x\n",
+			config_param.cfg_resize_param.output.pixel_byte,
+			config_param.cfg_resize_param.output.img_fmt);
+		dev_dbg(dev,
+			"rrzo param:size=(%0dx%0d),stride:%d,xsize:%d,crop=(%0dx%0d)\n",
+			config_param.cfg_resize_param.output.size.w,
+			config_param.cfg_resize_param.output.size.h,
+			config_param.cfg_resize_param.output.size.stride,
+			config_param.cfg_resize_param.output.size.xsize,
+			config_param.cfg_resize_param.output.crop.width,
+			config_param.cfg_resize_param.output.crop.height);
+	} else {
+		config_param.cfg_resize_param.bypass = 1;
+	}
+
+	/* Configure meta DMAs info. */
+	config_param.cfg_meta_param.enabled_meta_dmas = enable_dma;
+
+	isp_composer_hw_config(isp_ctx, &config_param);
+
+	/* Stream on */
+	isp_composer_stream(isp_ctx, 1);
+	dev_dbg(dev, "%s done\n", __func__);
+	return 0;
+}
+
+int mtk_isp_streamoff(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+
+	isp_composer_stream(isp_ctx, 0);
+	dev_dbg(dev, "%s done\n", __func__);
+
+	return 0;
+}
+
+int mtk_isp_enqueue(struct device *dev,
+		    struct mtk_cam_dev_start_param *frameparamsbase)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct p1_frame_param frameparams;
+	struct mtk_isp_queue_job *framejob;
+	struct mtk_cam_dev_buffer **bundle_buffers;
+	unsigned int i, idx;
+
+	framejob = kzalloc(sizeof(*framejob), GFP_ATOMIC);
+	memset(framejob, 0, sizeof(*framejob));
+	memset(&frameparams, 0, sizeof(frameparams));
+	INIT_LIST_HEAD(&framejob->list_buf);
+
+	bundle_buffers = &frameparamsbase->buffers[0];
+	frameparams.frame_seq_no = isp_ctx->frame_seq_no++;
+	frameparams.sof_idx =
+		p1_dev->isp_devs[isp_ctx->isp_hw_module].sof_count;
+	framejob->request_fd = frameparamsbase->request_fd;
+	framejob->frame_seq_no = frameparams.frame_seq_no;
+
+	idx = MTK_CAM_P1_META_IN_0;
+	if (bundle_buffers[idx]) {
+		frameparams.tuning_addr.iova =
+			bundle_buffers[idx]->daddr;
+		frameparams.tuning_addr.scp_addr =
+			bundle_buffers[idx]->scp_addr;
+		list_add_tail(&bundle_buffers[idx]->list,
+			      &framejob->list_buf);
+	}
+
+	/* Image output */
+	idx = MTK_CAM_P1_MAIN_STREAM_OUT;
+	if (bundle_buffers[idx]) {
+		frameparams.img_dma_buffers[0].buffer.iova =
+			bundle_buffers[idx]->daddr;
+		frameparams.img_dma_buffers[0].buffer.scp_addr =
+			bundle_buffers[idx]->scp_addr;
+		dev_dbg(dev, "main stream address pa:0x%x iova:0x%x\n",
+			frameparams.img_dma_buffers[0].buffer.scp_addr,
+			frameparams.img_dma_buffers[0].buffer.iova);
+		list_add_tail(&bundle_buffers[idx]->list,
+			      &framejob->list_buf);
+	}
+
+	/* Resize output */
+	idx = MTK_CAM_P1_PACKED_BIN_OUT;
+	if (bundle_buffers[idx]) {
+		frameparams.img_dma_buffers[1].buffer.iova =
+			bundle_buffers[idx]->daddr;
+		frameparams.img_dma_buffers[1].buffer.scp_addr =
+			bundle_buffers[idx]->scp_addr;
+		dev_dbg(dev, "packed out address:0x%x iova:0x%x\n",
+			frameparams.img_dma_buffers[1].buffer.scp_addr,
+			frameparams.img_dma_buffers[1].buffer.iova);
+		list_add_tail(&bundle_buffers[idx]->list,
+			      &framejob->list_buf);
+	}
+
+	/* Meta output DMAs */
+	for (i = 0; i < MAX_META_DMA_NODES; i++) {
+		idx = MTK_CAM_P1_META_OUT_0 + i;
+		if (bundle_buffers[idx]) {
+			frameparams.meta_addrs[i].iova =
+			  bundle_buffers[idx]->daddr;
+			frameparams.meta_addrs[i].scp_addr =
+			  bundle_buffers[idx]->scp_addr;
+			list_add_tail(&bundle_buffers[idx]->list,
+				      &framejob->list_buf);
+		} else {
+			frameparams.meta_addrs[i].iova = 0;
+			frameparams.meta_addrs[i].scp_addr = 0;
+		}
+	}
+
+	spin_lock(&isp_ctx->p1_enqueue_list.lock);
+	list_add_tail(&framejob->list_entry, &isp_ctx->p1_enqueue_list.queue);
+	atomic_inc(&isp_ctx->p1_enqueue_list.queue_cnt);
+	spin_unlock(&isp_ctx->p1_enqueue_list.lock);
+
+	isp_composer_enqueue(isp_ctx, &frameparams, SCP_ISP_FRAME);
+	dev_dbg(dev, "request fd(0x%x) frame_seq_no(%d) is queued cnt:(%d)\n",
+		frameparamsbase->request_fd,
+		frameparams.frame_seq_no,
+		atomic_read(&isp_ctx->p1_enqueue_list.queue_cnt));
+
+	return 0;
+}
+
+static const struct dev_pm_ops mtk_isp_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mtk_isp_suspend, mtk_isp_resume)
+	SET_RUNTIME_PM_OPS(mtk_isp_suspend, mtk_isp_resume, NULL)
+};
+
+static struct platform_driver mtk_isp_driver = {
+	.probe   = mtk_isp_probe,
+	.remove  = mtk_isp_remove,
+	.driver  = {
+		.name  = ISP_DEV_NAME,
+		.of_match_table = mtk_isp_of_ids,
+		.pm     = &mtk_isp_pm_ops,
+	}
+};
+
+module_platform_driver(mtk_isp_driver);
+
+MODULE_DESCRIPTION("Camera ISP driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.h b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.h
new file mode 100644
index 0000000..6d13058
--- /dev/null
+++ b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.h
@@ -0,0 +1,288 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ryan Yu <ryan.yu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CAMERA_ISP_H
+#define __CAMERA_ISP_H
+
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/irqreturn.h>
+#include <linux/miscdevice.h>
+#include <linux/pm_qos.h>
+#include <linux/scatterlist.h>
+
+#include "mtk_cam-dev.h"
+#include "mtk_cam-ctx.h"
+#include "mtk_cam-scp.h"
+
+#define ISP_DEV_NAME		"mtk-cam"
+
+#define CAM_A_MAX_WIDTH		3328U
+#define CAM_A_MAX_HEIGHT	2496U
+#define CAM_B_MAX_WIDTH		5376U
+#define CAM_B_MAX_HEIGHT	4032U
+
+#define CAM_MIN_WIDTH		80U
+#define CAM_MIN_HEIGHT		60U
+
+#define IMG_MAX_WIDTH		CAM_B_MAX_WIDTH
+#define IMG_MAX_HEIGHT		CAM_B_MAX_HEIGHT
+#define IMG_MIN_WIDTH		CAM_MIN_WIDTH
+#define IMG_MIN_HEIGHT		CAM_MIN_HEIGHT
+
+#define RRZ_MAX_WIDTH		CAM_B_MAX_WIDTH
+#define RRZ_MAX_HEIGHT		CAM_B_MAX_HEIGHT
+#define RRZ_MIN_WIDTH		CAM_MIN_WIDTH
+#define RRZ_MIN_HEIGHT		CAM_MIN_HEIGHT
+
+#define R_IMGO		BIT(0)
+#define R_RRZO		BIT(1)
+#define R_AAO		BIT(3)
+#define R_AFO		BIT(4)
+#define R_LCSO		BIT(5)
+#define R_PDO		BIT(6)
+#define R_LMVO		BIT(7)
+#define R_FLKO		BIT(8)
+#define R_RSSO		BIT(9)
+#define R_PSO		BIT(10)
+
+#define ISP_COMPOSING_MAX_NUM		4
+#define ISP_FRAME_COMPOSING_MAX_NUM	3
+
+#define IRQ_DATA_BUF_SIZE		4
+#define COMPOSRE_EVENT_BUF_SIZE		4
+
+#define CQ_ADDRESS_OFFSET		0x640
+#define CQ_BUFFER_COUNT			3
+
+#define IRQ_STAT_STR "cam%c, SOF_%d irq(0x%x), " \
+			"dma(0x%x), frame_num(%d)/cq_num(%d)\n"
+
+/*
+ * In order with the sequence of device nodes defined in dtsi rule,
+ * one hardware module should be mapping to one node.
+ */
+enum isp_dev_node_enum {
+	ISP_CAMSYS_CONFIG_IDX = 0,
+	ISP_CAM_UNI_IDX,
+	ISP_CAM_A_IDX,
+	ISP_CAM_B_IDX,
+	ISP_DEV_NODE_NUM
+};
+
+/* Image RAW path for ISP P1 module. */
+enum isp_raw_path_enum {
+	ISP_PROCESS_RAW_PATH = 0,
+	ISP_PURE_RAW_PATH
+};
+
+enum {
+	img_fmt_unknown		= 0x0000,
+	img_fmt_raw_start	= 0x2200,
+	img_fmt_bayer8		= img_fmt_raw_start,
+	img_fmt_bayer10,
+	img_fmt_bayer12,
+	img_fmt_bayer14,
+	img_fmt_fg_bayer8,
+	img_fmt_fg_bayer10,
+	img_fmt_fg_bayer12,
+	img_fmt_fg_bayer14,
+};
+
+enum {
+	raw_pxl_id_b   = 0,
+	raw_pxl_id_gb,
+	raw_pxl_id_gr,
+	raw_pxl_id_r
+};
+
+enum {
+	default_pixel_mode = 0,
+	one_pixel_mode,
+	two_pixel_mode,
+	four_pixel_mode,
+	pixel_mode_num,
+};
+
+struct isp_queue {
+	struct list_head queue;
+	atomic_t queue_cnt;
+	spinlock_t lock; /* queue attributes protection */
+};
+
+struct isp_thread {
+	struct task_struct *thread;
+	wait_queue_head_t wq;
+};
+
+enum mtk_isp_scp_ipi_type {
+	SCP_ISP_CMD = 0,
+	SCP_ISP_FRAME,
+};
+
+struct mtk_isp_queue_work {
+	union {
+		struct mtk_isp_scp_p1_cmd cmd;
+		struct p1_frame_param frameparams;
+	};
+	struct list_head list_entry;
+	enum mtk_isp_scp_ipi_type type;
+};
+
+struct mtk_isp_queue_job {
+	struct list_head list_entry;
+	struct list_head list_buf;
+	unsigned int request_fd;
+	unsigned int frame_seq_no;
+};
+
+struct isp_clk_struct {
+	int num_clks;
+	struct clk_bulk_data *clk_list;
+};
+
+struct isp_device {
+	struct device *dev;
+	void __iomem *regs;
+	int irq;
+	spinlock_t spinlock_irq; /* ISP reg setting integrity */
+	unsigned int current_frame;
+	u8 sof_count;
+	u8 isp_hw_module;
+};
+
+struct mtk_isp_p1_ctx {
+	atomic_t scp_state;
+	struct isp_queue composer_txlist;
+	struct isp_thread composer_tx_thread;
+	atomic_t cmd_queued;
+	struct mutex composer_tx_lock; /* isp composer work protection */
+
+	struct isp_thread composer_rx_thread;
+	struct mtk_isp_scp_p1_cmd composer_evts[COMPOSRE_EVENT_BUF_SIZE];
+	atomic_t composer_evts_start;
+	atomic_t composer_evts_end;
+	spinlock_t composer_evts_lock; /* SCP events protection */
+	/* increase after ipi */
+	atomic_t ipi_occupied;
+	/* increase after frame enqueue */
+	atomic_t composing_frame;
+	/* current composed frame id */
+	atomic_t composed_frame_id;
+
+	struct isp_queue p1_enqueue_list;
+
+	struct isp_thread isp_deque_thread;
+	struct mtk_cam_dev_stat_event_data irq_event_datas[IRQ_DATA_BUF_SIZE];
+	atomic_t irq_data_start;
+	atomic_t irq_data_end;
+	spinlock_t irq_dequeue_lock; /* ISP frame dequeuq protection */
+
+	dma_addr_t scp_mem_pa;
+	dma_addr_t scp_mem_iova;
+	struct sg_table sgtable;
+
+	/* increase after open, decrease when close */
+	atomic_t isp_user_cnt;
+	/* frame sequence number, increase per en-queue*/
+	int frame_seq_no;
+	unsigned int isp_hw_module;
+	unsigned int isp_raw_path;
+
+	void (*composer_deinit_donecb)(void *isp_ctx);
+
+	struct list_head list;
+};
+
+struct isp_p1_device {
+	struct platform_device *pdev;
+
+	/* for SCP driver  */
+	struct platform_device *scp_pdev;
+	struct rproc *rproc_handle;
+
+	struct mtk_isp_p1_ctx isp_ctx;
+	struct isp_clk_struct isp_clk;
+	struct mtk_cam_dev *cam_dev;
+	struct isp_device *isp_devs;
+};
+
+static inline struct isp_p1_device *
+p1_ctx_to_dev(const struct mtk_isp_p1_ctx *__p1_ctx)
+{
+	return container_of(__p1_ctx, struct isp_p1_device, isp_ctx);
+}
+
+static inline struct isp_p1_device *get_p1_device(struct device *dev)
+{
+	return ((struct isp_p1_device *)dev_get_drvdata(dev));
+}
+
+int isp_composer_init(struct mtk_isp_p1_ctx *isp_ctx);
+int isp_composer_hw_init(struct mtk_isp_p1_ctx *isp_ctx);
+void isp_composer_hw_config(struct mtk_isp_p1_ctx *isp_ctx,
+			    struct p1_config_param *config_param);
+void isp_composer_stream(struct mtk_isp_p1_ctx *isp_ctx, int on);
+void isp_composer_hw_deinit(struct mtk_isp_p1_ctx *isp_ctx,
+			    void (*donecb)(void *data));
+void isp_composer_enqueue(struct mtk_isp_p1_ctx *isp_ctx,
+			  void *data,
+			  enum mtk_isp_scp_ipi_type type);
+
+/**
+ * mtk_isp_open - open isp driver and initialize related resources.
+ *
+ * @dev:	isp device.
+ *
+ */
+int mtk_isp_open(struct device *dev);
+
+/**
+ * mtk_isp_release - release isp driver and related resources.
+ *
+ * @dev:	isp device.
+ *
+ */
+int mtk_isp_release(struct device *dev);
+
+/**
+ * mtk_isp_streamon - start to output image & meta data.
+ *
+ * @dev:	isp device.
+ *
+ */
+int mtk_isp_streamon(struct device *dev);
+
+/**
+ * mtk_isp_streamoff -  stop to output image & meta data.
+ *
+ * @dev:	isp device.
+ *
+ */
+int mtk_isp_streamoff(struct device *dev);
+
+/**
+ * mtk_isp_enqueue - enqueue a frame bundle to ISP driver.
+ *
+ * @dev:	isp device.
+ * @frameparamsbase: pointer to &struct mtk_cam_dev_start_param.
+ *
+ */
+int mtk_isp_enqueue(struct device *dev,
+		    struct mtk_cam_dev_start_param *frameparamsbase);
+
+#endif /*__CAMERA_ISP_H*/
-- 
1.9.1

WARNING: multiple messages have this Message-ID (diff)
From: Jungo Lin <jungo.lin@mediatek.com>
To: <tfiga@chromium.org>, <hans.verkuil@cisco.com>,
	<laurent.pinchart+renesas@ideasonboard.com>,
	<matthias.bgg@gmail.com>, <mchehab@kernel.org>
Cc: Sean.Cheng@mediatek.com, Rynn.Wu@mediatek.com,
	srv_heupstream@mediatek.com, holmes.chiou@mediatek.com,
	ryan.yu@mediatek.com, Jerry-ch.Chen@mediatek.com,
	frankie.chiu@mediatek.com, jungo.lin@mediatek.com,
	sj.huang@mediatek.com, yuzhao@chromium.org,
	christie.yu@mediatek.com, seraph.huang@mediatek.com,
	zwisler@chromium.org, linux-mediatek@lists.infradead.org,
	frederic.chen@mediatek.com, linux-arm-kernel@lists.infradead.org,
	linux-media@vger.kernel.org
Subject: [RFC V1 10/12] media: platform: Add Mediatek ISP P1 device driver
Date: Thu, 28 Mar 2019 17:56:45 +0800	[thread overview]
Message-ID: <1553767007-11909-11-git-send-email-jungo.lin@mediatek.com> (raw)
In-Reply-To: <1553767007-11909-1-git-send-email-jungo.lin@mediatek.com>

This patch adds the Mediatek ISP P1 HW control device driver.
It handles the ISP HW configuration, provides interrupt handling and
initializes the V4L2 device nodes and other functions.

Signed-off-by: Jungo Lin <jungo.lin@mediatek.com>
---
 .../platform/mtk-isp/isp_50/cam/mtk_cam-regs.h     |  147 +++
 .../media/platform/mtk-isp/isp_50/cam/mtk_cam.c    | 1098 ++++++++++++++++++++
 .../media/platform/mtk-isp/isp_50/cam/mtk_cam.h    |  288 +++++
 3 files changed, 1533 insertions(+)
 create mode 100644 drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam-regs.h
 create mode 100644 drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.c
 create mode 100644 drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.h

diff --git a/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam-regs.h b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam-regs.h
new file mode 100644
index 0000000..90736a1
--- /dev/null
+++ b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam-regs.h
@@ -0,0 +1,147 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ryan Yu <ryan.yu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_REGS_H
+#define _CAM_REGS_H
+
+/* TG Bit Mask */
+#define VFDATA_EN_BIT	BIT(0)
+#define CMOS_EN_BIT	BIT(0)
+
+/* normal signal bit */
+#define VS_INT_ST	BIT(0)
+#define HW_PASS1_DON_ST	BIT(11)
+#define SOF_INT_ST	BIT(12)
+#define SW_PASS1_DON_ST	BIT(30)
+
+/* err status bit */
+#define TG_ERR_ST	BIT(4)
+#define TG_GBERR_ST	BIT(5)
+#define CQ_CODE_ERR_ST	BIT(6)
+#define CQ_APB_ERR_ST	BIT(7)
+#define CQ_VS_ERR_ST	BIT(8)
+#define AMX_ERR_ST	BIT(15)
+#define RMX_ERR_ST	BIT(16)
+#define BMX_ERR_ST	BIT(17)
+#define RRZO_ERR_ST	BIT(18)
+#define AFO_ERR_ST	BIT(19)
+#define IMGO_ERR_ST	BIT(20)
+#define AAO_ERR_ST	BIT(21)
+#define PSO_ERR_ST	BIT(22)
+#define LCSO_ERR_ST	BIT(23)
+#define BNR_ERR_ST	BIT(24)
+#define LSCI_ERR_ST	BIT(25)
+#define DMA_ERR_ST	BIT(29)
+
+/* CAM DMA done status */
+#define FLKO_DONE_ST	BIT(4)
+#define AFO_DONE_ST	BIT(5)
+#define AAO_DONE_ST	BIT(7)
+#define PSO_DONE_ST	BIT(14)
+
+/* IRQ signal mask */
+#define INT_ST_MASK_CAM	( \
+			VS_INT_ST |\
+			HW_PASS1_DON_ST |\
+			SOF_INT_ST |\
+			SW_PASS1_DON_ST)
+
+/* IRQ Warning Mask */
+#define INT_ST_MASK_CAM_WARN	(\
+				RRZO_ERR_ST |\
+				AFO_ERR_ST |\
+				IMGO_ERR_ST |\
+				AAO_ERR_ST |\
+				PSO_ERR_ST | \
+				LCSO_ERR_ST |\
+				BNR_ERR_ST |\
+				LSCI_ERR_ST)
+
+/* IRQ Error Mask */
+#define INT_ST_MASK_CAM_ERR	(\
+				TG_ERR_ST |\
+				TG_GBERR_ST |\
+				CQ_CODE_ERR_ST |\
+				CQ_APB_ERR_ST |\
+				CQ_VS_ERR_ST |\
+				BNR_ERR_ST |\
+				RMX_ERR_ST |\
+				BMX_ERR_ST |\
+				BNR_ERR_ST |\
+				LSCI_ERR_ST |\
+				DMA_ERR_ST)
+
+/* IRQ Signal Log Mask */
+#define INT_ST_LOG_MASK_CAM	(\
+				SOF_INT_ST |\
+				SW_PASS1_DON_ST |\
+				VS_INT_ST |\
+				TG_ERR_ST |\
+				TG_GBERR_ST |\
+				RRZO_ERR_ST |\
+				AFO_ERR_ST |\
+				IMGO_ERR_ST |\
+				AAO_ERR_ST |\
+				DMA_ERR_ST)
+
+/* DMA Event Notification Mask */
+#define DMA_ST_MASK_CAM	(\
+			AFO_DONE_ST |\
+			AAO_DONE_ST |\
+			PSO_DONE_ST |\
+			FLKO_DONE_ST)
+
+/* Status check */
+#define REG_CTL_EN		0x0004
+#define REG_CTL_DMA_EN		0x0008
+#define REG_CTL_FMT_SEL		0x0010
+#define REG_CTL_EN2		0x0018
+#define REG_CTL_RAW_INT_EN	0x0020
+#define REG_CTL_RAW_INT_STAT	0x0024
+#define REG_CTL_RAW_INT2_STAT	0x0034
+#define REG_CTL_RAW_INT3_STAT	0x00c4
+#define REG_CTL_TWIN_STAT	0x0050
+
+#define REG_TG_SEN_MODE		0x0230
+#define REG_TG_SEN_GRAB_PIX	0x0238
+#define REG_TG_SEN_GRAB_LIN	0x023c
+#define REG_TG_VF_CON		0x0234
+#define REG_TG_INTER_ST		0x026c
+#define REG_TG_SUB_PERIOD	0x02a4
+
+#define REG_IMGO_BASE_ADDR	0x1020
+#define REG_RRZO_BASE_ADDR	0x1050
+
+/* Error status log */
+#define REG_IMGO_ERR_STAT	0x1360
+#define REG_RRZO_ERR_STAT	0x1364
+#define REG_AAO_ERR_STAT	0x1368
+#define REG_AFO_ERR_STAT	0x136c
+#define REG_LCSO_ERR_STAT	0x1370
+#define REG_UFEO_ERR_STAT	0x1374
+#define REG_PDO_ERR_STAT	0x1378
+#define REG_BPCI_ERR_STAT	0x137c
+#define REG_LSCI_ERR_STAT	0x1384
+#define REG_PDI_ERR_STAT	0x138c
+#define REG_LMVO_ERR_STAT	0x1390
+#define REG_FLKO_ERR_STAT	0x1394
+#define REG_PSO_ERR_STAT	0x13a0
+
+/* ISP command */
+#define REG_CQ_THR0_BASEADDR	0x0198
+#define REG_CTL_SPARE2		0x0058
+#define REG_HW_FRAME_NUM	0x13b8
+
+#endif	/* _CAM_REGS_H */
diff --git a/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.c b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.c
new file mode 100644
index 0000000..935cf7e
--- /dev/null
+++ b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.c
@@ -0,0 +1,1098 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ryan Yu <ryan.yu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/atomic.h>
+#include <linux/cdev.h>
+#include <linux/compat.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/mtk_scp.h>
+#include <linux/pm_runtime.h>
+#include <linux/remoteproc.h>
+#include <linux/sched/clock.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+
+#include "mtk_cam.h"
+#include "mtk_cam-regs.h"
+#include "mtk_cam-ctx.h"
+
+static const struct of_device_id mtk_isp_of_ids[] = {
+	{.compatible = "mediatek,mt8183-camisp",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, mtk_isp_of_ids);
+
+/* list of clocks required by isp cam */
+static const char * const mtk_isp_clks[] = {
+	"CAMSYS_CAM_CGPDN", "CAMSYS_CAMTG_CGPDN"
+};
+
+static void isp_dumpdmastat(struct isp_device *isp_dev)
+{
+	dev_err(isp_dev->dev,
+		"IMGO:0x%x, RRZO:0x%x, AAO=0x%x, AFO=0x%x, LMVO=0x%x\n",
+		readl(isp_dev->regs + REG_IMGO_ERR_STAT),
+		readl(isp_dev->regs + REG_RRZO_ERR_STAT),
+		readl(isp_dev->regs + REG_AAO_ERR_STAT),
+		readl(isp_dev->regs + REG_AFO_ERR_STAT),
+		readl(isp_dev->regs + REG_LMVO_ERR_STAT));
+	dev_err(isp_dev->dev,
+		"LCSO=0x%x, PSO=0x%x, FLKO=0x%x, BPCI:0x%x, LSCI=0x%x\n",
+		readl(isp_dev->regs + REG_LCSO_ERR_STAT),
+		readl(isp_dev->regs + REG_PSO_ERR_STAT),
+		readl(isp_dev->regs + REG_FLKO_ERR_STAT),
+		readl(isp_dev->regs + REG_BPCI_ERR_STAT),
+		readl(isp_dev->regs + REG_LSCI_ERR_STAT));
+}
+
+static void mtk_isp_notify(struct mtk_isp_p1_ctx *isp_ctx,
+			   unsigned int request_fd,
+			   unsigned int frame_seq_no,
+			   struct list_head *list_buf,
+			   enum vb2_buffer_state state)
+{
+	struct isp_p1_device *p1_dev = p1_ctx_to_dev(isp_ctx);
+	struct device *dev = &p1_dev->pdev->dev;
+	struct mtk_cam_dev_finish_param fram_param;
+
+	fram_param.list_buf = list_buf;
+	fram_param.request_fd = request_fd;
+	fram_param.frame_seq_no = frame_seq_no;
+	fram_param.state = state;
+	dev_dbg(dev, "request fd(%d) frame_seq_no(%d)\n",
+		fram_param.request_fd,
+		fram_param.frame_seq_no);
+	mtk_cam_dev_core_job_finish(p1_dev->cam_dev, &fram_param);
+}
+
+static void isp_deque_frame(struct isp_p1_device *p1_dev, int frame_seq_no)
+{
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct platform_device *pdev = p1_dev->pdev;
+	struct mtk_isp_queue_job *framejob, *tmp;
+	struct isp_queue *p1_enqueue_list = &isp_ctx->p1_enqueue_list;
+
+	/* Match dequeue work and enqueue frame */
+	spin_lock(&p1_enqueue_list->lock);
+	list_for_each_entry_safe(framejob, tmp, &p1_enqueue_list->queue,
+				 list_entry) {
+		dev_dbg(&pdev->dev,
+			"%s frame_seq_no=%d, isp_composer_work->req_num=%d\n",
+			__func__,
+			framejob->frame_seq_no, frame_seq_no);
+		/* Match by the en-queued request number */
+		if (framejob->frame_seq_no == frame_seq_no) {
+			/* Pass to user space */
+			mtk_isp_notify(isp_ctx,
+				       framejob->request_fd,
+				       framejob->frame_seq_no,
+				       &framejob->list_buf,
+				       VB2_BUF_STATE_DONE);
+			atomic_dec(&p1_enqueue_list->queue_cnt);
+			dev_dbg(&pdev->dev,
+				"frame(frame_seq_no=%d) is done, queue_cnt(%d)\n",
+				framejob->frame_seq_no,
+				atomic_read(&p1_enqueue_list->queue_cnt));
+
+			/* remove only when frame ready */
+			list_del(&framejob->list_entry);
+			kfree(framejob);
+			break;
+		} else if (framejob->frame_seq_no < frame_seq_no) {
+			/* Pass to user space for frame drop */
+			mtk_isp_notify(isp_ctx,
+				       framejob->request_fd,
+				       framejob->frame_seq_no,
+				       &framejob->list_buf,
+				       VB2_BUF_STATE_ERROR);
+			atomic_dec(&p1_enqueue_list->queue_cnt);
+			dev_dbg(&pdev->dev,
+				"frame(frame_seq_no=%d) drop, queue_cnt(%d)\n",
+				framejob->frame_seq_no,
+				atomic_read(&p1_enqueue_list->queue_cnt));
+
+			/* remove only drop frame */
+			list_del(&framejob->list_entry);
+			kfree(framejob);
+		}
+	}
+	spin_unlock(&p1_enqueue_list->lock);
+}
+
+static int isp_deque_work(void *data)
+{
+	struct isp_p1_device *p1_dev = (struct isp_p1_device *)data;
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct device *dev = &p1_dev->pdev->dev;
+	struct mtk_cam_dev *cam_dev = p1_dev->cam_dev;
+	struct mtk_cam_dev_stat_event_data event_data;
+	atomic_t *irq_data_end = &isp_ctx->irq_data_end;
+	atomic_t *irq_data_start = &isp_ctx->irq_data_start;
+	unsigned long flags;
+	int ret, i;
+
+	while (1) {
+		ret = wait_event_interruptible(isp_ctx->isp_deque_thread.wq,
+					       (atomic_read(irq_data_end) !=
+					       atomic_read(irq_data_start)) ||
+					       kthread_should_stop());
+
+		if (kthread_should_stop())
+			break;
+
+		if (ret == ERESTARTSYS) {
+			dev_err(dev, "interrupted by a signal!\n");
+			continue;
+		}
+
+		spin_lock_irqsave(&isp_ctx->irq_dequeue_lock, flags);
+		i = atomic_read(&isp_ctx->irq_data_start);
+		memcpy(&event_data, &isp_ctx->irq_event_datas[i],
+		       sizeof(event_data));
+		memset(&isp_ctx->irq_event_datas[i], 0x00, sizeof(event_data));
+		atomic_set(&isp_ctx->irq_data_start, ++i & 0x3);
+		spin_unlock_irqrestore(&isp_ctx->irq_dequeue_lock, flags);
+
+		if (event_data.irq_status_mask & VS_INT_ST) {
+			/* Notify specific HW events to user space */
+			mtk_cam_dev_queue_event_dev_state(cam_dev,
+							  &event_data);
+			dev_dbg(dev,
+				"event IRQ(0x%x) DMA(0x%x) is sent\n",
+				event_data.irq_status_mask,
+				event_data.dma_status_mask);
+			mtk_cam_dev_queue_event_dev_state(cam_dev,
+							  &event_data);
+		} else if (event_data.irq_status_mask & SW_PASS1_DON_ST) {
+			isp_deque_frame(p1_dev,
+					event_data.frame_seq_no);
+		}
+	}
+	return 0;
+}
+
+static int irq_handle_sof(struct isp_device *isp_dev,
+			  dma_addr_t base_addr,
+			  unsigned int frame_num)
+{
+	unsigned int cq_addr_index;
+	struct isp_p1_device *p1_dev = get_p1_device(isp_dev->dev);
+	int cq_num = atomic_read(&p1_dev->isp_ctx.composed_frame_id);
+
+	if (cq_num > frame_num) {
+		cq_addr_index = frame_num % CQ_BUFFER_COUNT;
+
+		writel(base_addr +
+			(dma_addr_t)(CQ_ADDRESS_OFFSET * cq_addr_index),
+			isp_dev->regs + REG_CQ_THR0_BASEADDR);
+		dev_dbg(isp_dev->dev,
+			"SOF_INT_ST cq_num:%d, frame_num:%d cq_addr:%d",
+			cq_num, frame_num, cq_addr_index);
+	} else {
+		dev_dbg(isp_dev->dev,
+			"SOF_INT_ST cq_num:%d, frame_num:%d",
+			cq_num, frame_num);
+	}
+
+	isp_dev->sof_count += 1;
+
+	return cq_num;
+}
+
+static int irq_handle_notify_event(struct isp_device *isp_dev,
+				   unsigned int irqstatus,
+				   unsigned int dmastatus)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(isp_dev->dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&isp_ctx->irq_dequeue_lock, flags);
+	i = atomic_read(&isp_ctx->irq_data_end);
+	isp_ctx->irq_event_datas[i].frame_seq_no = isp_dev->current_frame;
+	isp_ctx->irq_event_datas[i].irq_status_mask |=
+		(irqstatus & INT_ST_MASK_CAM);
+	isp_ctx->irq_event_datas[i].dma_status_mask |=
+		(dmastatus & DMA_ST_MASK_CAM);
+	atomic_set(&isp_ctx->irq_data_end, ++i & 0x3);
+	spin_unlock_irqrestore(&isp_ctx->irq_dequeue_lock, flags);
+
+	wake_up_interruptible(&isp_ctx->isp_deque_thread.wq);
+
+	dev_dbg(isp_dev->dev,
+		"%s notify IRQ (0x%x) DMA status (0x%x) for frame_seq_no: %d\n",
+		__func__,
+		(irqstatus & INT_ST_MASK_CAM),
+		(dmastatus & DMA_ST_MASK_CAM),
+		isp_dev->current_frame);
+
+	return 0;
+}
+
+irqreturn_t isp_irq_cam(int irq, void *data)
+{
+	struct isp_device *isp_dev = (struct isp_device *)data;
+	struct isp_p1_device *p1_dev = get_p1_device(isp_dev->dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct device *dev = isp_dev->dev;
+	unsigned int cardinalnum, cq_num, hw_frame_num;
+	unsigned int irqstatus, errstatus, warnstatus, dmastatus;
+	unsigned long flags;
+
+	/* Check the streaming is off or not */
+	if (!p1_dev->cam_dev->streaming)
+		return IRQ_HANDLED;
+
+	cardinalnum = isp_dev->isp_hw_module - ISP_CAM_A_IDX;
+	cq_num = 0;
+
+	spin_lock_irqsave(&isp_dev->spinlock_irq, flags);
+	irqstatus = readl(isp_dev->regs + REG_CTL_RAW_INT_STAT);
+	dmastatus = readl(isp_dev->regs + REG_CTL_RAW_INT2_STAT);
+	hw_frame_num = readl(isp_dev->regs + REG_HW_FRAME_NUM);
+	spin_unlock_irqrestore(&isp_dev->spinlock_irq, flags);
+
+	/* Ignore unnecessary IRQ */
+	if (irqstatus == 0)
+		return IRQ_HANDLED;
+
+	errstatus = irqstatus & INT_ST_MASK_CAM_ERR;
+	warnstatus = irqstatus & INT_ST_MASK_CAM_WARN;
+	irqstatus = irqstatus & INT_ST_MASK_CAM;
+
+	/* sof , done order check . */
+	spin_lock_irqsave(&isp_dev->spinlock_irq, flags);
+	if ((irqstatus & HW_PASS1_DON_ST) && (irqstatus & SOF_INT_ST)) {
+		dev_warn(dev,
+			 "isp sof_don block, %d\n",
+			 isp_dev->sof_count);
+
+		/* Notify IRQ event and enqueue ready frame */
+		irq_handle_notify_event(isp_dev, irqstatus, dmastatus);
+		isp_dev->current_frame = hw_frame_num;
+	} else {
+		if (irqstatus & SOF_INT_ST)
+			isp_dev->current_frame = hw_frame_num;
+
+		if ((irqstatus & INT_ST_MASK_CAM) ||
+		    (dmastatus & DMA_ST_MASK_CAM))
+			irq_handle_notify_event(isp_dev, irqstatus, dmastatus);
+	}
+	spin_unlock_irqrestore(&isp_dev->spinlock_irq, flags);
+
+	if (irqstatus & SOF_INT_ST)
+		cq_num = irq_handle_sof(isp_dev, isp_ctx->scp_mem_iova,
+					hw_frame_num);
+
+	if (irqstatus & SW_PASS1_DON_ST) {
+		int num = atomic_dec_return(&isp_ctx->composing_frame);
+
+		dev_dbg(dev, "SW_PASS1_DON_ST queued frame:%d\n", num);
+		/* Notify TX thread to send if TX frame is blocked */
+		wake_up_interruptible
+				(&isp_ctx->composer_tx_thread.wq);
+	}
+
+	/* check ISP error status */
+	if (errstatus) {
+		dev_err(dev,
+			"raw_int_err:0x%x/0x%x, raw_int3_err:0x%x\n",
+			irqstatus, warnstatus, errstatus);
+
+		/* show DMA errors in detail */
+		if (errstatus & DMA_ERR_ST)
+			isp_dumpdmastat(isp_dev);
+	}
+
+	if (irqstatus & INT_ST_LOG_MASK_CAM)
+		dev_dbg(dev, IRQ_STAT_STR,
+			'A' + cardinalnum,
+			isp_dev->sof_count,
+			irqstatus,
+			dmastatus,
+			hw_frame_num,
+			cq_num);
+	return IRQ_HANDLED;
+}
+
+static int enable_sys_clock(struct isp_p1_device *p1_dev)
+{
+	struct device *dev = &p1_dev->pdev->dev;
+	int ret;
+
+	dev_info(dev, "- %s dev id:%d\n", __func__, dev->id);
+
+	ret = clk_bulk_prepare_enable(p1_dev->isp_clk.num_clks,
+				      p1_dev->isp_clk.clk_list);
+	if (ret < 0)
+		goto clk_err;
+	return 0;
+clk_err:
+	dev_err(dev, "cannot pre-en isp_cam clock:%d\n", ret);
+	clk_bulk_disable_unprepare(p1_dev->isp_clk.num_clks,
+				   p1_dev->isp_clk.clk_list);
+	return ret;
+}
+
+static void disable_sys_clock(struct isp_p1_device *p1_dev)
+{
+	struct device *dev = &p1_dev->pdev->dev;
+
+	dev_info(dev, "- %s dev id:%d\n", __func__, dev->id);
+	clk_bulk_disable_unprepare(p1_dev->isp_clk.num_clks,
+				   p1_dev->isp_clk.clk_list);
+}
+
+static int mtk_isp_probe(struct platform_device *pdev)
+{
+	struct isp_p1_device *p1_dev;
+	struct mtk_isp_p1_ctx *isp_ctx;
+	struct isp_device *isp_dev;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int ret;
+	unsigned int i;
+
+	/* Allocate context */
+	p1_dev = devm_kzalloc(dev, sizeof(*p1_dev), GFP_KERNEL);
+	if (!p1_dev)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, p1_dev);
+	isp_ctx = &p1_dev->isp_ctx;
+	p1_dev->pdev = pdev;
+
+	p1_dev->isp_devs =
+		devm_kzalloc(dev,
+			     sizeof(struct isp_device) * ISP_DEV_NODE_NUM,
+			     GFP_KERNEL);
+	if (!p1_dev->isp_devs)
+		return -ENOMEM;
+
+	p1_dev->cam_dev =
+		devm_kzalloc(dev, sizeof(struct mtk_cam_dev), GFP_KERNEL);
+	if (!p1_dev->isp_devs)
+		return -ENOMEM;
+
+	/* iomap registers */
+	for (i = ISP_CAMSYS_CONFIG_IDX; i < ISP_DEV_NODE_NUM; i++) {
+		isp_dev = &p1_dev->isp_devs[i];
+		isp_dev->isp_hw_module = i;
+		isp_dev->dev = dev;
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		isp_dev->regs = devm_ioremap_resource(dev, res);
+
+		dev_info(dev, "cam%u, map_addr=0x%lx\n",
+			 i, (unsigned long)isp_dev->regs);
+
+		if (!isp_dev->regs)
+			return PTR_ERR(isp_dev->regs);
+
+		/* support IRQ from ISP_CAM_A_IDX */
+		if (i >= ISP_CAM_A_IDX) {
+			/* reg & interrupts index is shifted with 1  */
+			isp_dev->irq = platform_get_irq(pdev, i - 1);
+			if (isp_dev->irq > 0) {
+				ret = devm_request_irq(dev, isp_dev->irq,
+						       isp_irq_cam,
+						       IRQF_SHARED,
+						       dev_driver_string(dev),
+						       (void *)isp_dev);
+				if (ret) {
+					dev_err(dev,
+						"req_irq fail, dev(%s) irq=%d\n",
+						dev->of_node->name,
+						isp_dev->irq);
+					return ret;
+				}
+				dev_info(dev, "Registered irq=%d, ISR: %s\n",
+					 isp_dev->irq, dev_driver_string(dev));
+			}
+		}
+		spin_lock_init(&isp_dev->spinlock_irq);
+	}
+
+	p1_dev->isp_clk.num_clks = ARRAY_SIZE(mtk_isp_clks);
+	p1_dev->isp_clk.clk_list =
+		devm_kcalloc(dev,
+			     p1_dev->isp_clk.num_clks,
+			     sizeof(*p1_dev->isp_clk.clk_list),
+			     GFP_KERNEL);
+	if (!p1_dev->isp_clk.clk_list)
+		return -ENOMEM;
+
+	for (i = 0; i < p1_dev->isp_clk.num_clks; ++i)
+		p1_dev->isp_clk.clk_list->id = mtk_isp_clks[i];
+
+	ret = devm_clk_bulk_get(dev,
+				p1_dev->isp_clk.num_clks,
+				p1_dev->isp_clk.clk_list);
+	if (ret) {
+		dev_err(dev, "cannot get isp cam clock:%d\n", ret);
+		return ret;
+	}
+
+	/* initialize the v4l2 common part */
+	ret = mtk_cam_dev_core_init(pdev, p1_dev->cam_dev);
+	if (ret)
+		return ret;
+
+	spin_lock_init(&isp_ctx->p1_enqueue_list.lock);
+	atomic_set(&p1_dev->isp_ctx.isp_user_cnt, 0);
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int mtk_isp_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct isp_p1_device *p1_dev = dev_get_drvdata(dev);
+
+	pm_runtime_disable(dev);
+	mtk_cam_dev_core_release(pdev, p1_dev->cam_dev);
+
+	return 0;
+}
+
+static int mtk_isp_suspend(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct isp_device *isp_dev;
+	unsigned int reg_val;
+	int usercount, module;
+
+	module = p1_dev->isp_ctx.isp_hw_module;
+	usercount = atomic_read(&p1_dev->isp_ctx.isp_user_cnt);
+
+	dev_dbg(dev, "- %s:%d\n", __func__, usercount);
+
+	/* If no user count, no further action */
+	if (!usercount)
+		return 0;
+
+	isp_dev = &p1_dev->isp_devs[module];
+	reg_val = readl(isp_dev->regs + REG_TG_VF_CON);
+	if (reg_val & VFDATA_EN_BIT) {
+		dev_dbg(dev, "Cam:%d suspend, disable VF\n", module);
+		/* disable VF */
+		writel((reg_val & (~VFDATA_EN_BIT)),
+		       isp_dev->regs + REG_TG_VF_CON);
+		/*
+		 * After VF enable, The TG frame count will be reset to 0;
+		 */
+		reg_val = readl(isp_dev->regs + REG_TG_SEN_MODE);
+		writel((reg_val & (~CMOS_EN_BIT)),
+		       isp_dev->regs +  + REG_TG_SEN_MODE);
+	}
+
+	disable_sys_clock(p1_dev);
+
+	return 0;
+}
+
+static int mtk_isp_resume(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct isp_device *isp_dev;
+	unsigned int reg_val;
+	int module, usercount;
+
+	module = p1_dev->isp_ctx.isp_hw_module;
+	usercount = atomic_read(&p1_dev->isp_ctx.isp_user_cnt);
+
+	dev_dbg(dev, "- %s:%d\n", __func__, usercount);
+
+	/* If no user count, no further action */
+	if (!usercount)
+		return 0;
+
+	enable_sys_clock(p1_dev);
+
+	/* V4L2 stream-on phase & restore HW stream-on status */
+	if (p1_dev->cam_dev->streaming) {
+		isp_dev = &p1_dev->isp_devs[module];
+		dev_dbg(dev, "Cam:%d resume,enable VF\n", module);
+		/* Enable CMOS */
+		reg_val = readl(isp_dev->regs + REG_TG_SEN_MODE);
+		writel((reg_val | CMOS_EN_BIT),
+		       isp_dev->regs + REG_TG_SEN_MODE);
+		/* Enable VF */
+		reg_val = readl(isp_dev->regs + REG_TG_VF_CON);
+		writel((reg_val | VFDATA_EN_BIT),
+		       isp_dev->regs + REG_TG_VF_CON);
+	}
+	return 0;
+}
+
+static int isp_init_context(struct isp_p1_device *p1_dev)
+{
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct device *dev = &p1_dev->pdev->dev;
+	unsigned int i;
+
+	dev_dbg(dev, "init irq work thread\n");
+	if (!isp_ctx->isp_deque_thread.thread) {
+		mutex_init(&isp_ctx->composer_tx_lock);
+		init_waitqueue_head(&isp_ctx->isp_deque_thread.wq);
+		isp_ctx->isp_deque_thread.thread =
+			kthread_run(isp_deque_work, (void *)p1_dev,
+				    "isp_deque_work");
+		if (IS_ERR(isp_ctx->isp_deque_thread.thread)) {
+			dev_err(dev, "unable to alloc kthread\n");
+			isp_ctx->isp_deque_thread.thread = NULL;
+			return -ENOMEM;
+		}
+	}
+	spin_lock_init(&isp_ctx->irq_dequeue_lock);
+
+	INIT_LIST_HEAD(&isp_ctx->p1_enqueue_list.queue);
+	atomic_set(&isp_ctx->p1_enqueue_list.queue_cnt, 0);
+
+	for (i = 0; i < ISP_DEV_NODE_NUM; i++)
+		spin_lock_init(&p1_dev->isp_devs[i].spinlock_irq);
+
+	spin_lock_init(&isp_ctx->p1_enqueue_list.lock);
+	spin_lock_init(&isp_ctx->composer_txlist.lock);
+
+	atomic_set(&isp_ctx->irq_data_end, 0);
+	atomic_set(&isp_ctx->irq_data_start, 0);
+	return 0;
+}
+
+static int isp_uninit_context(struct isp_p1_device *p1_dev)
+{
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct mtk_isp_queue_job *framejob, *tmp_framejob;
+
+	spin_lock_irq(&isp_ctx->p1_enqueue_list.lock);
+	list_for_each_entry_safe(framejob, tmp_framejob,
+				 &isp_ctx->p1_enqueue_list.queue, list_entry) {
+		list_del(&framejob->list_entry);
+		kfree(framejob);
+	}
+	spin_unlock_irq(&isp_ctx->p1_enqueue_list.lock);
+
+	atomic_set(&isp_ctx->isp_user_cnt, 0);
+
+	if (!IS_ERR(isp_ctx->isp_deque_thread.thread)) {
+		kthread_stop(isp_ctx->isp_deque_thread.thread);
+		wake_up_interruptible(&isp_ctx->isp_deque_thread.wq);
+		isp_ctx->isp_deque_thread.thread = NULL;
+	}
+
+	return 0;
+}
+
+/* Utility functions */
+static unsigned int get_sensor_pixel_id(unsigned int fmt)
+{
+	switch (fmt) {
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+	case MEDIA_BUS_FMT_SBGGR14_1X14:
+		return raw_pxl_id_b;
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SGBRG14_1X14:
+		return raw_pxl_id_gb;
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SGRBG14_1X14:
+		return raw_pxl_id_gr;
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+	case MEDIA_BUS_FMT_SRGGB14_1X14:
+		return raw_pxl_id_r;
+	default:
+		return raw_pxl_id_b;
+	}
+}
+
+static unsigned int get_sensor_fmt(unsigned int fmt)
+{
+	switch (fmt) {
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+		return img_fmt_bayer8;
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+		return img_fmt_bayer10;
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+		return img_fmt_bayer12;
+	case MEDIA_BUS_FMT_SBGGR14_1X14:
+	case MEDIA_BUS_FMT_SGBRG14_1X14:
+	case MEDIA_BUS_FMT_SGRBG14_1X14:
+	case MEDIA_BUS_FMT_SRGGB14_1X14:
+		return img_fmt_bayer14;
+	default:
+		return img_fmt_unknown;
+	}
+}
+
+static unsigned int get_img_fmt(unsigned int fourcc)
+{
+	switch (fourcc) {
+	case V4L2_PIX_FMT_MTISP_B8:
+		return img_fmt_bayer8;
+	case V4L2_PIX_FMT_MTISP_F8:
+		return img_fmt_fg_bayer8;
+	case V4L2_PIX_FMT_MTISP_B10:
+		return img_fmt_bayer10;
+	case V4L2_PIX_FMT_MTISP_F10:
+		return img_fmt_fg_bayer10;
+	case V4L2_PIX_FMT_MTISP_B12:
+		return img_fmt_bayer12;
+	case V4L2_PIX_FMT_MTISP_F12:
+		return img_fmt_fg_bayer12;
+	case V4L2_PIX_FMT_MTISP_B14:
+		return img_fmt_bayer14;
+	case V4L2_PIX_FMT_MTISP_F14:
+		return img_fmt_fg_bayer14;
+	default:
+		return img_fmt_unknown;
+	}
+}
+
+static unsigned int get_pixel_byte(unsigned int fourcc)
+{
+	switch (fourcc) {
+	case V4L2_PIX_FMT_MTISP_B8:
+	case V4L2_PIX_FMT_MTISP_F8:
+		return 8;
+	case V4L2_PIX_FMT_MTISP_B10:
+	case V4L2_PIX_FMT_MTISP_F10:
+		return 10;
+	case V4L2_PIX_FMT_MTISP_B12:
+	case V4L2_PIX_FMT_MTISP_F12:
+		return 12;
+	case V4L2_PIX_FMT_MTISP_B14:
+	case V4L2_PIX_FMT_MTISP_F14:
+		return 14;
+	case V4L2_PIX_FMT_MTISP_U8:
+	case V4L2_PIX_FMT_MTISP_U10:
+	case V4L2_PIX_FMT_MTISP_U12:
+	case V4L2_PIX_FMT_MTISP_U14:
+		return 16;
+	default:
+		return 10;
+	}
+}
+
+static void composer_deinit_done_cb(void *data)
+{
+	struct isp_p1_device *p1_dev = p1_ctx_to_dev(data);
+
+	disable_sys_clock(p1_dev);
+	/* Notify PM */
+	pm_runtime_put_sync(&p1_dev->pdev->dev);
+}
+
+/* ISP P1 interface functions */
+int mtk_isp_open(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	s32 usercount = atomic_inc_return(&isp_ctx->isp_user_cnt);
+	phandle rproc_phandle;
+	int ret;
+
+	dev_dbg(dev, "%s usercount=%d\n", __func__, usercount);
+
+	if (usercount == 1) {
+		p1_dev->scp_pdev = scp_get_pdev(p1_dev->pdev);
+		if (!p1_dev->scp_pdev) {
+			dev_err(dev, "Failed to get scp device\n");
+			return -EINVAL;
+		}
+		ret = of_property_read_u32(dev->of_node, "mediatek,scp",
+					   &rproc_phandle);
+		if (ret) {
+			dev_err(dev, "fail to get rproc_phandle:%d\n", ret);
+			return ret;
+		}
+
+		p1_dev->rproc_handle = rproc_get_by_phandle(rproc_phandle);
+		dev_dbg(dev, "p1 rproc_phandle: 0x%pK\n\n",
+			p1_dev->rproc_handle);
+		if (!p1_dev->rproc_handle) {
+			dev_err(dev, "fail to get rproc_handle\n");
+			return -EINVAL;
+		}
+
+		ret = rproc_boot(p1_dev->rproc_handle);
+		if (ret < 0) {
+			/*
+			 * Return 0 if downloading firmware successfully,
+			 * otherwise it is failed
+			 */
+			dev_err(dev, "rproc_boot failed:%d\n", ret);
+			return -EINVAL;
+		}
+
+		pm_runtime_get_sync(dev);
+
+		/* ISP HW INIT */
+		isp_ctx->isp_hw_module = ISP_CAM_B_IDX;
+		/* Use pure RAW as default HW path */
+		isp_ctx->isp_raw_path = ISP_PURE_RAW_PATH;
+
+		ret = isp_init_context(p1_dev);
+		if (ret)
+			return ret;
+		ret = isp_composer_init(isp_ctx);
+		if (ret)
+			return ret;
+		ret = isp_composer_hw_init(isp_ctx);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int mtk_isp_release(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+
+	if (atomic_dec_and_test(&p1_dev->isp_ctx.isp_user_cnt)) {
+		isp_composer_hw_deinit(isp_ctx, composer_deinit_done_cb);
+		isp_uninit_context(p1_dev);
+	}
+
+	dev_dbg(dev, "%s usercount = %d\n", __func__,
+		atomic_read(&p1_dev->isp_ctx.isp_user_cnt));
+
+	return 0;
+}
+
+int mtk_isp_streamon(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct p1_config_param config_param;
+	struct mtk_cam_dev *cam_dev = p1_dev->cam_dev;
+	struct v4l2_subdev_format sd_format;
+	unsigned int sd_width, sd_height;
+	unsigned int enable_dma, idx, i;
+	int ret;
+
+	p1_dev->isp_devs[isp_ctx->isp_hw_module].current_frame = 0;
+	p1_dev->isp_devs[isp_ctx->isp_hw_module].sof_count = 0;
+
+	isp_ctx->frame_seq_no = 1;
+	atomic_set(&isp_ctx->composed_frame_id, 0);
+
+	/* Get the enabled DMA ports */
+	enable_dma = 0;
+	for (i = 0; i < cam_dev->dev_node_num; i++) {
+		if (cam_dev->mem2mem2_nodes[i].enabled)
+			enable_dma |=
+				cam_dev->mem2mem2_nodes[i].desc.dma_port;
+	}
+	dev_dbg(dev, "%s enable_dma:0x%x", __func__, enable_dma);
+
+	/* sensor config */
+	sd_format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	ret = v4l2_subdev_call(cam_dev->sensor,
+			       pad, get_fmt, NULL, &sd_format);
+
+	if (ret) {
+		dev_dbg(dev, "sensor(%s) g_fmt on failed(%d)\n",
+			cam_dev->sensor->entity.name, ret);
+		return -EPERM;
+	}
+
+	dev_dbg(dev,
+		"sensor get_fmt ret=%d, w=%d, h=%d, code=0x%x, field=%d, color=%d\n",
+		ret, sd_format.format.width, sd_format.format.height,
+		sd_format.format.code, sd_format.format.field,
+		sd_format.format.colorspace);
+
+	config_param.cfg_in_param.continuous = 0x1;
+	config_param.cfg_in_param.subsample = 0x0;
+	/* fix to one pixel mode in default */
+	config_param.cfg_in_param.pixel_mode = one_pixel_mode;
+	/* support normal pattern in default */
+	config_param.cfg_in_param.data_pattern = 0x0;
+
+	config_param.cfg_in_param.crop.left = 0x0;
+	config_param.cfg_in_param.crop.top = 0x0;
+
+	config_param.cfg_in_param.raw_pixel_id =
+		get_sensor_pixel_id(sd_format.format.code);
+	config_param.cfg_in_param.img_fmt =
+		get_sensor_fmt(sd_format.format.code);
+	config_param.cfg_in_param.crop.width = sd_format.format.width;
+	config_param.cfg_in_param.crop.height = sd_format.format.height;
+	sd_width = sd_format.format.width;
+	sd_height = sd_format.format.height;
+
+	idx = MTK_CAM_P1_MAIN_STREAM_OUT;
+	if ((enable_dma & R_IMGO) == R_IMGO) {
+		struct v4l2_format *imgo_fmt =
+			&p1_dev->cam_dev->mem2mem2_nodes[idx].vdev_fmt;
+
+		config_param.cfg_main_param.pure_raw = isp_ctx->isp_raw_path;
+		config_param.cfg_main_param.pure_raw_pack = 1;
+		config_param.cfg_main_param.bypass = 0;
+
+		config_param.cfg_main_param.output.img_fmt =
+			get_img_fmt(imgo_fmt->fmt.pix_mp.pixelformat);
+		config_param.cfg_main_param.output.pixel_byte =
+			get_pixel_byte(imgo_fmt->fmt.pix_mp.pixelformat);
+		config_param.cfg_main_param.output.size.w =
+			imgo_fmt->fmt.pix_mp.width;
+		config_param.cfg_main_param.output.size.h =
+			imgo_fmt->fmt.pix_mp.height;
+
+		config_param.cfg_main_param.output.size.stride =
+			imgo_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+		config_param.cfg_main_param.output.size.xsize =
+			imgo_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+
+		config_param.cfg_main_param.output.crop.left = 0x0;
+		config_param.cfg_main_param.output.crop.top = 0x0;
+
+		config_param.cfg_main_param.output.crop.width = sd_width;
+		config_param.cfg_main_param.output.crop.height = sd_height;
+
+		WARN_ONCE(imgo_fmt->fmt.pix_mp.width > sd_width ||
+			  imgo_fmt->fmt.pix_mp.height > sd_height,
+			  "img out:%d:%d in:%d:%d",
+			  imgo_fmt->fmt.pix_mp.width,
+			  imgo_fmt->fmt.pix_mp.height,
+			  sd_width,
+			  sd_height);
+
+		dev_dbg(dev,
+			"imgo pixel_byte:%d img_fmt:0x%x raw:%d\n",
+			config_param.cfg_main_param.output.pixel_byte,
+			config_param.cfg_main_param.output.img_fmt,
+			config_param.cfg_main_param.pure_raw);
+		dev_dbg(dev,
+			"imgo param:size=(%0dx%0d),stride:%d,xsize:%d,crop=(%0dx%0d)\n",
+			config_param.cfg_main_param.output.size.w,
+			config_param.cfg_main_param.output.size.h,
+			config_param.cfg_main_param.output.size.stride,
+			config_param.cfg_main_param.output.size.xsize,
+			config_param.cfg_main_param.output.crop.width,
+			config_param.cfg_main_param.output.crop.height);
+	} else {
+		config_param.cfg_main_param.bypass = 1;
+	}
+
+	idx = MTK_CAM_P1_PACKED_BIN_OUT;
+	if ((enable_dma & R_RRZO) == R_RRZO) {
+		struct v4l2_format *rrzo_fmt =
+			&p1_dev->cam_dev->mem2mem2_nodes[idx].vdev_fmt;
+
+		config_param.cfg_resize_param.bypass = 0;
+		config_param.cfg_resize_param.output.img_fmt =
+			get_img_fmt(rrzo_fmt->fmt.pix_mp.pixelformat);
+		config_param.cfg_resize_param.output.pixel_byte =
+			get_pixel_byte(rrzo_fmt->fmt.pix_mp.pixelformat);
+		config_param.cfg_resize_param.output.size.w =
+			rrzo_fmt->fmt.pix_mp.width;
+		config_param.cfg_resize_param.output.size.h =
+			rrzo_fmt->fmt.pix_mp.height;
+		config_param.cfg_resize_param.output.size.stride =
+			rrzo_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+		config_param.cfg_resize_param.output.size.xsize =
+			rrzo_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+
+		config_param.cfg_resize_param.output.crop.left = 0x0;
+		config_param.cfg_resize_param.output.crop.top = 0x0;
+		config_param.cfg_resize_param.output.crop.width = sd_width;
+		config_param.cfg_resize_param.output.crop.height = sd_height;
+
+		WARN_ONCE(rrzo_fmt->fmt.pix_mp.width > sd_width ||
+			  rrzo_fmt->fmt.pix_mp.height > sd_height,
+			  "rrz out:%d:%d in:%d:%d",
+			  rrzo_fmt->fmt.pix_mp.width,
+			  rrzo_fmt->fmt.pix_mp.height,
+			  sd_width,
+			  sd_height);
+
+		dev_dbg(dev, "rrzo pixel_byte:%d img_fmt:0x%x\n",
+			config_param.cfg_resize_param.output.pixel_byte,
+			config_param.cfg_resize_param.output.img_fmt);
+		dev_dbg(dev,
+			"rrzo param:size=(%0dx%0d),stride:%d,xsize:%d,crop=(%0dx%0d)\n",
+			config_param.cfg_resize_param.output.size.w,
+			config_param.cfg_resize_param.output.size.h,
+			config_param.cfg_resize_param.output.size.stride,
+			config_param.cfg_resize_param.output.size.xsize,
+			config_param.cfg_resize_param.output.crop.width,
+			config_param.cfg_resize_param.output.crop.height);
+	} else {
+		config_param.cfg_resize_param.bypass = 1;
+	}
+
+	/* Configure meta DMAs info. */
+	config_param.cfg_meta_param.enabled_meta_dmas = enable_dma;
+
+	isp_composer_hw_config(isp_ctx, &config_param);
+
+	/* Stream on */
+	isp_composer_stream(isp_ctx, 1);
+	dev_dbg(dev, "%s done\n", __func__);
+	return 0;
+}
+
+int mtk_isp_streamoff(struct device *dev)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+
+	isp_composer_stream(isp_ctx, 0);
+	dev_dbg(dev, "%s done\n", __func__);
+
+	return 0;
+}
+
+int mtk_isp_enqueue(struct device *dev,
+		    struct mtk_cam_dev_start_param *frameparamsbase)
+{
+	struct isp_p1_device *p1_dev = get_p1_device(dev);
+	struct mtk_isp_p1_ctx *isp_ctx = &p1_dev->isp_ctx;
+	struct p1_frame_param frameparams;
+	struct mtk_isp_queue_job *framejob;
+	struct mtk_cam_dev_buffer **bundle_buffers;
+	unsigned int i, idx;
+
+	framejob = kzalloc(sizeof(*framejob), GFP_ATOMIC);
+	memset(framejob, 0, sizeof(*framejob));
+	memset(&frameparams, 0, sizeof(frameparams));
+	INIT_LIST_HEAD(&framejob->list_buf);
+
+	bundle_buffers = &frameparamsbase->buffers[0];
+	frameparams.frame_seq_no = isp_ctx->frame_seq_no++;
+	frameparams.sof_idx =
+		p1_dev->isp_devs[isp_ctx->isp_hw_module].sof_count;
+	framejob->request_fd = frameparamsbase->request_fd;
+	framejob->frame_seq_no = frameparams.frame_seq_no;
+
+	idx = MTK_CAM_P1_META_IN_0;
+	if (bundle_buffers[idx]) {
+		frameparams.tuning_addr.iova =
+			bundle_buffers[idx]->daddr;
+		frameparams.tuning_addr.scp_addr =
+			bundle_buffers[idx]->scp_addr;
+		list_add_tail(&bundle_buffers[idx]->list,
+			      &framejob->list_buf);
+	}
+
+	/* Image output */
+	idx = MTK_CAM_P1_MAIN_STREAM_OUT;
+	if (bundle_buffers[idx]) {
+		frameparams.img_dma_buffers[0].buffer.iova =
+			bundle_buffers[idx]->daddr;
+		frameparams.img_dma_buffers[0].buffer.scp_addr =
+			bundle_buffers[idx]->scp_addr;
+		dev_dbg(dev, "main stream address pa:0x%x iova:0x%x\n",
+			frameparams.img_dma_buffers[0].buffer.scp_addr,
+			frameparams.img_dma_buffers[0].buffer.iova);
+		list_add_tail(&bundle_buffers[idx]->list,
+			      &framejob->list_buf);
+	}
+
+	/* Resize output */
+	idx = MTK_CAM_P1_PACKED_BIN_OUT;
+	if (bundle_buffers[idx]) {
+		frameparams.img_dma_buffers[1].buffer.iova =
+			bundle_buffers[idx]->daddr;
+		frameparams.img_dma_buffers[1].buffer.scp_addr =
+			bundle_buffers[idx]->scp_addr;
+		dev_dbg(dev, "packed out address:0x%x iova:0x%x\n",
+			frameparams.img_dma_buffers[1].buffer.scp_addr,
+			frameparams.img_dma_buffers[1].buffer.iova);
+		list_add_tail(&bundle_buffers[idx]->list,
+			      &framejob->list_buf);
+	}
+
+	/* Meta output DMAs */
+	for (i = 0; i < MAX_META_DMA_NODES; i++) {
+		idx = MTK_CAM_P1_META_OUT_0 + i;
+		if (bundle_buffers[idx]) {
+			frameparams.meta_addrs[i].iova =
+			  bundle_buffers[idx]->daddr;
+			frameparams.meta_addrs[i].scp_addr =
+			  bundle_buffers[idx]->scp_addr;
+			list_add_tail(&bundle_buffers[idx]->list,
+				      &framejob->list_buf);
+		} else {
+			frameparams.meta_addrs[i].iova = 0;
+			frameparams.meta_addrs[i].scp_addr = 0;
+		}
+	}
+
+	spin_lock(&isp_ctx->p1_enqueue_list.lock);
+	list_add_tail(&framejob->list_entry, &isp_ctx->p1_enqueue_list.queue);
+	atomic_inc(&isp_ctx->p1_enqueue_list.queue_cnt);
+	spin_unlock(&isp_ctx->p1_enqueue_list.lock);
+
+	isp_composer_enqueue(isp_ctx, &frameparams, SCP_ISP_FRAME);
+	dev_dbg(dev, "request fd(0x%x) frame_seq_no(%d) is queued cnt:(%d)\n",
+		frameparamsbase->request_fd,
+		frameparams.frame_seq_no,
+		atomic_read(&isp_ctx->p1_enqueue_list.queue_cnt));
+
+	return 0;
+}
+
+static const struct dev_pm_ops mtk_isp_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mtk_isp_suspend, mtk_isp_resume)
+	SET_RUNTIME_PM_OPS(mtk_isp_suspend, mtk_isp_resume, NULL)
+};
+
+static struct platform_driver mtk_isp_driver = {
+	.probe   = mtk_isp_probe,
+	.remove  = mtk_isp_remove,
+	.driver  = {
+		.name  = ISP_DEV_NAME,
+		.of_match_table = mtk_isp_of_ids,
+		.pm     = &mtk_isp_pm_ops,
+	}
+};
+
+module_platform_driver(mtk_isp_driver);
+
+MODULE_DESCRIPTION("Camera ISP driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.h b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.h
new file mode 100644
index 0000000..6d13058
--- /dev/null
+++ b/drivers/media/platform/mtk-isp/isp_50/cam/mtk_cam.h
@@ -0,0 +1,288 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ryan Yu <ryan.yu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CAMERA_ISP_H
+#define __CAMERA_ISP_H
+
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/irqreturn.h>
+#include <linux/miscdevice.h>
+#include <linux/pm_qos.h>
+#include <linux/scatterlist.h>
+
+#include "mtk_cam-dev.h"
+#include "mtk_cam-ctx.h"
+#include "mtk_cam-scp.h"
+
+#define ISP_DEV_NAME		"mtk-cam"
+
+#define CAM_A_MAX_WIDTH		3328U
+#define CAM_A_MAX_HEIGHT	2496U
+#define CAM_B_MAX_WIDTH		5376U
+#define CAM_B_MAX_HEIGHT	4032U
+
+#define CAM_MIN_WIDTH		80U
+#define CAM_MIN_HEIGHT		60U
+
+#define IMG_MAX_WIDTH		CAM_B_MAX_WIDTH
+#define IMG_MAX_HEIGHT		CAM_B_MAX_HEIGHT
+#define IMG_MIN_WIDTH		CAM_MIN_WIDTH
+#define IMG_MIN_HEIGHT		CAM_MIN_HEIGHT
+
+#define RRZ_MAX_WIDTH		CAM_B_MAX_WIDTH
+#define RRZ_MAX_HEIGHT		CAM_B_MAX_HEIGHT
+#define RRZ_MIN_WIDTH		CAM_MIN_WIDTH
+#define RRZ_MIN_HEIGHT		CAM_MIN_HEIGHT
+
+#define R_IMGO		BIT(0)
+#define R_RRZO		BIT(1)
+#define R_AAO		BIT(3)
+#define R_AFO		BIT(4)
+#define R_LCSO		BIT(5)
+#define R_PDO		BIT(6)
+#define R_LMVO		BIT(7)
+#define R_FLKO		BIT(8)
+#define R_RSSO		BIT(9)
+#define R_PSO		BIT(10)
+
+#define ISP_COMPOSING_MAX_NUM		4
+#define ISP_FRAME_COMPOSING_MAX_NUM	3
+
+#define IRQ_DATA_BUF_SIZE		4
+#define COMPOSRE_EVENT_BUF_SIZE		4
+
+#define CQ_ADDRESS_OFFSET		0x640
+#define CQ_BUFFER_COUNT			3
+
+#define IRQ_STAT_STR "cam%c, SOF_%d irq(0x%x), " \
+			"dma(0x%x), frame_num(%d)/cq_num(%d)\n"
+
+/*
+ * In order with the sequence of device nodes defined in dtsi rule,
+ * one hardware module should be mapping to one node.
+ */
+enum isp_dev_node_enum {
+	ISP_CAMSYS_CONFIG_IDX = 0,
+	ISP_CAM_UNI_IDX,
+	ISP_CAM_A_IDX,
+	ISP_CAM_B_IDX,
+	ISP_DEV_NODE_NUM
+};
+
+/* Image RAW path for ISP P1 module. */
+enum isp_raw_path_enum {
+	ISP_PROCESS_RAW_PATH = 0,
+	ISP_PURE_RAW_PATH
+};
+
+enum {
+	img_fmt_unknown		= 0x0000,
+	img_fmt_raw_start	= 0x2200,
+	img_fmt_bayer8		= img_fmt_raw_start,
+	img_fmt_bayer10,
+	img_fmt_bayer12,
+	img_fmt_bayer14,
+	img_fmt_fg_bayer8,
+	img_fmt_fg_bayer10,
+	img_fmt_fg_bayer12,
+	img_fmt_fg_bayer14,
+};
+
+enum {
+	raw_pxl_id_b   = 0,
+	raw_pxl_id_gb,
+	raw_pxl_id_gr,
+	raw_pxl_id_r
+};
+
+enum {
+	default_pixel_mode = 0,
+	one_pixel_mode,
+	two_pixel_mode,
+	four_pixel_mode,
+	pixel_mode_num,
+};
+
+struct isp_queue {
+	struct list_head queue;
+	atomic_t queue_cnt;
+	spinlock_t lock; /* queue attributes protection */
+};
+
+struct isp_thread {
+	struct task_struct *thread;
+	wait_queue_head_t wq;
+};
+
+enum mtk_isp_scp_ipi_type {
+	SCP_ISP_CMD = 0,
+	SCP_ISP_FRAME,
+};
+
+struct mtk_isp_queue_work {
+	union {
+		struct mtk_isp_scp_p1_cmd cmd;
+		struct p1_frame_param frameparams;
+	};
+	struct list_head list_entry;
+	enum mtk_isp_scp_ipi_type type;
+};
+
+struct mtk_isp_queue_job {
+	struct list_head list_entry;
+	struct list_head list_buf;
+	unsigned int request_fd;
+	unsigned int frame_seq_no;
+};
+
+struct isp_clk_struct {
+	int num_clks;
+	struct clk_bulk_data *clk_list;
+};
+
+struct isp_device {
+	struct device *dev;
+	void __iomem *regs;
+	int irq;
+	spinlock_t spinlock_irq; /* ISP reg setting integrity */
+	unsigned int current_frame;
+	u8 sof_count;
+	u8 isp_hw_module;
+};
+
+struct mtk_isp_p1_ctx {
+	atomic_t scp_state;
+	struct isp_queue composer_txlist;
+	struct isp_thread composer_tx_thread;
+	atomic_t cmd_queued;
+	struct mutex composer_tx_lock; /* isp composer work protection */
+
+	struct isp_thread composer_rx_thread;
+	struct mtk_isp_scp_p1_cmd composer_evts[COMPOSRE_EVENT_BUF_SIZE];
+	atomic_t composer_evts_start;
+	atomic_t composer_evts_end;
+	spinlock_t composer_evts_lock; /* SCP events protection */
+	/* increase after ipi */
+	atomic_t ipi_occupied;
+	/* increase after frame enqueue */
+	atomic_t composing_frame;
+	/* current composed frame id */
+	atomic_t composed_frame_id;
+
+	struct isp_queue p1_enqueue_list;
+
+	struct isp_thread isp_deque_thread;
+	struct mtk_cam_dev_stat_event_data irq_event_datas[IRQ_DATA_BUF_SIZE];
+	atomic_t irq_data_start;
+	atomic_t irq_data_end;
+	spinlock_t irq_dequeue_lock; /* ISP frame dequeuq protection */
+
+	dma_addr_t scp_mem_pa;
+	dma_addr_t scp_mem_iova;
+	struct sg_table sgtable;
+
+	/* increase after open, decrease when close */
+	atomic_t isp_user_cnt;
+	/* frame sequence number, increase per en-queue*/
+	int frame_seq_no;
+	unsigned int isp_hw_module;
+	unsigned int isp_raw_path;
+
+	void (*composer_deinit_donecb)(void *isp_ctx);
+
+	struct list_head list;
+};
+
+struct isp_p1_device {
+	struct platform_device *pdev;
+
+	/* for SCP driver  */
+	struct platform_device *scp_pdev;
+	struct rproc *rproc_handle;
+
+	struct mtk_isp_p1_ctx isp_ctx;
+	struct isp_clk_struct isp_clk;
+	struct mtk_cam_dev *cam_dev;
+	struct isp_device *isp_devs;
+};
+
+static inline struct isp_p1_device *
+p1_ctx_to_dev(const struct mtk_isp_p1_ctx *__p1_ctx)
+{
+	return container_of(__p1_ctx, struct isp_p1_device, isp_ctx);
+}
+
+static inline struct isp_p1_device *get_p1_device(struct device *dev)
+{
+	return ((struct isp_p1_device *)dev_get_drvdata(dev));
+}
+
+int isp_composer_init(struct mtk_isp_p1_ctx *isp_ctx);
+int isp_composer_hw_init(struct mtk_isp_p1_ctx *isp_ctx);
+void isp_composer_hw_config(struct mtk_isp_p1_ctx *isp_ctx,
+			    struct p1_config_param *config_param);
+void isp_composer_stream(struct mtk_isp_p1_ctx *isp_ctx, int on);
+void isp_composer_hw_deinit(struct mtk_isp_p1_ctx *isp_ctx,
+			    void (*donecb)(void *data));
+void isp_composer_enqueue(struct mtk_isp_p1_ctx *isp_ctx,
+			  void *data,
+			  enum mtk_isp_scp_ipi_type type);
+
+/**
+ * mtk_isp_open - open isp driver and initialize related resources.
+ *
+ * @dev:	isp device.
+ *
+ */
+int mtk_isp_open(struct device *dev);
+
+/**
+ * mtk_isp_release - release isp driver and related resources.
+ *
+ * @dev:	isp device.
+ *
+ */
+int mtk_isp_release(struct device *dev);
+
+/**
+ * mtk_isp_streamon - start to output image & meta data.
+ *
+ * @dev:	isp device.
+ *
+ */
+int mtk_isp_streamon(struct device *dev);
+
+/**
+ * mtk_isp_streamoff -  stop to output image & meta data.
+ *
+ * @dev:	isp device.
+ *
+ */
+int mtk_isp_streamoff(struct device *dev);
+
+/**
+ * mtk_isp_enqueue - enqueue a frame bundle to ISP driver.
+ *
+ * @dev:	isp device.
+ * @frameparamsbase: pointer to &struct mtk_cam_dev_start_param.
+ *
+ */
+int mtk_isp_enqueue(struct device *dev,
+		    struct mtk_cam_dev_start_param *frameparamsbase);
+
+#endif /*__CAMERA_ISP_H*/
-- 
1.9.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2019-03-28  9:57 UTC|newest]

Thread overview: 388+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-28  9:56 [RFC V1 00/12] meida: platform: mtk-isp: Add Mediatek ISP Pass 1 driver Jungo Lin
2019-03-28  9:56 ` Jungo Lin
2019-03-28  9:56 ` Jungo Lin
2019-03-28  9:56 ` [RFC V1 01/12] dt-bindings: mt8183: Add binding for ISP Pass 1 reserved memory Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56 ` [RFC V1 02/12] dts: arm64: mt8183: Add ISP Pass 1 shared memory node Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56 ` [RFC V1 03/12] dt-bindings: mt8183: Added cam-smem dt-bindings Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56 ` [RFC V1 04/12] dt-bindings: mt8183: Added camera ISP Pass 1 Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56 ` [RFC V1 05/12] dts: arm64: mt8183: Add ISP Pass 1 nodes Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56 ` [RFC V1 06/12] media: platform: Add Mediatek ISP Pass 1 driver Kconfig Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56 ` [RFC V1 07/12] media: platform: Add Mediatek ISP P1 image & meta formats Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56 ` [RFC V1 08/12] media: platform: Add Mediatek ISP P1 private control Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56 ` [RFC V1 09/12] media: platform: Add Mediatek ISP P1 V4L2 functions Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56 ` Jungo Lin [this message]
2019-03-28  9:56   ` [RFC V1 10/12] media: platform: Add Mediatek ISP P1 device driver Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56 ` [RFC V1 11/12] media: platform: Add Mediatek ISP P1 SCP communication Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56 ` [RFC V1 12/12] media: platform: Add Mediatek ISP P1 shared memory driver Jungo Lin
2019-03-28  9:56   ` Jungo Lin
2019-03-28  9:56   ` Jungo Lin
     [not found] <Jungo Lin <jungo.lin@mediatek.com>
2019-04-02 10:04 ` [PATCH v1] media: media_device_enum_links32: fix missing reserved field copy Jungo Lin
2019-04-02 10:04   ` Jungo Lin
2019-04-02 10:04   ` Jungo Lin
2019-04-02 11:33   ` Laurent Pinchart
2019-04-02 11:33     ` Laurent Pinchart
2019-04-02 11:33     ` Laurent Pinchart
2019-04-03  0:30     ` Jungo Lin
2019-04-03  0:30       ` Jungo Lin
2019-04-03  0:30       ` Jungo Lin
2019-04-03  1:44 ` [PATCH] media: media_device_enum_links32: clean a reserved field Jungo Lin
2019-04-03  1:44   ` Jungo Lin
2019-04-03  1:44   ` Jungo Lin
2019-05-10  1:57 ` [RFC, V2, 00/11] meida: platform: mtk-isp: Add Mediatek ISP Pass 1 driver Jungo Lin
2019-05-10  1:57   ` Jungo Lin
2019-05-10  1:57   ` [RFC,V2,00/11] " Jungo Lin
2019-05-10  1:57 ` [RFC, V2, 01/11] dt-bindings: mt8183: Add binding for ISP Pass 1 reserved memory Jungo Lin
2019-05-10  1:57   ` Jungo Lin
2019-05-10  1:57   ` [RFC,V2,01/11] " Jungo Lin
2019-05-14 19:50   ` Rob Herring
2019-05-14 19:50     ` Rob Herring
2019-05-14 19:50     ` Rob Herring
2019-05-15 13:02     ` Jungo Lin
2019-05-15 13:02       ` Jungo Lin
2019-05-15 13:02       ` Jungo Lin
2019-05-10  1:57 ` [RFC,V2,02/11] dts: arm64: mt8183: Add ISP Pass 1 shared memory node Jungo Lin
2019-05-10  1:57   ` Jungo Lin
2019-05-10  1:57   ` Jungo Lin
2019-05-10  1:57 ` [RFC,V2,03/11] dt-bindings: mt8183: Added camera ISP Pass 1 Jungo Lin
2019-05-10  1:57   ` Jungo Lin
2019-05-10  1:57   ` Jungo Lin
2019-05-14 19:54   ` Rob Herring
2019-05-14 19:54     ` Rob Herring
2019-05-14 19:54     ` Rob Herring
2019-05-16  6:12     ` Jungo Lin
2019-05-16  6:12       ` Jungo Lin
2019-05-16  6:12       ` Jungo Lin
2019-05-10  1:57 ` [RFC,V2,04/11] dts: arm64: mt8183: Add ISP Pass 1 nodes Jungo Lin
2019-05-10  1:57   ` Jungo Lin
2019-05-10  1:57   ` Jungo Lin
2019-05-10  1:57 ` [RFC, V2, 05/11] media: platform: Add Mediatek ISP Pass 1 driver Kconfig Jungo Lin
2019-05-10  1:57   ` Jungo Lin
2019-05-10  1:57   ` [RFC,V2,05/11] " Jungo Lin
2019-05-10  1:57 ` [RFC, V2, 06/11] media: platform: Add Mediatek ISP P1 image & meta formats Jungo Lin
2019-05-10  1:57   ` Jungo Lin
2019-05-10  1:57   ` [RFC,V2,06/11] " Jungo Lin
2019-05-13  8:35   ` [RFC, V2, 06/11] " Hans Verkuil
2019-05-13  8:35     ` Hans Verkuil
2019-05-13  8:35     ` [RFC,V2,06/11] " Hans Verkuil
2019-05-15 12:49     ` [RFC, V2, 06/11] " Jungo Lin
2019-05-15 12:49       ` Jungo Lin
2019-05-15 12:49       ` Jungo Lin
2019-05-10  1:58 ` [RFC,V2,07/11] media: platform: Add Mediatek ISP P1 private control Jungo Lin
2019-05-10  1:58   ` Jungo Lin
2019-05-10  1:58   ` Jungo Lin
2019-05-13  8:46   ` Hans Verkuil
2019-05-13  8:46     ` Hans Verkuil
2019-05-13  8:46     ` Hans Verkuil
     [not found]     ` <49a8ba54-aba4-1915-6732-987a58e8bd3c-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>
2019-05-14  6:23       ` Jungo Lin
2019-05-14  6:23         ` Jungo Lin
2019-05-14  6:23         ` Jungo Lin
2019-10-02 10:55     ` Sakari Ailus
2019-10-02 10:55       ` Sakari Ailus
2019-10-02 10:55       ` Sakari Ailus
2019-10-02 11:02       ` Sakari Ailus
2019-10-02 11:02         ` Sakari Ailus
2019-10-02 11:02         ` Sakari Ailus
     [not found] ` <Jungo Lin <jungo.lin-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
2019-05-10  1:58   ` [RFC,V2,08/11] media: platform: Add Mediatek ISP P1 V4L2 functions Jungo Lin
2019-05-10  1:58     ` Jungo Lin
2019-05-10  1:58     ` Jungo Lin
2019-05-24 18:49     ` Drew Davenport
2019-05-24 18:49       ` Drew Davenport
2019-05-24 18:49       ` Drew Davenport
2019-05-28  1:00       ` Jungo Lin
2019-05-28  1:00         ` Jungo Lin
2019-05-28  1:00         ` Jungo Lin
2019-05-10  1:58 ` [RFC,V2,09/11] media: platform: Add Mediatek ISP P1 device driver Jungo Lin
2019-05-10  1:58   ` Jungo Lin
2019-05-10  1:58   ` Jungo Lin
2019-05-24 21:19   ` [RFC, V2, 09/11] " Drew Davenport
2019-05-24 21:19     ` Drew Davenport
2019-05-24 21:19     ` [RFC,V2,09/11] " Drew Davenport
2019-05-27 13:07     ` [RFC, V2, 09/11] " Jungo Lin
2019-05-27 13:07       ` Jungo Lin
2019-05-27 13:07       ` Jungo Lin
2019-05-10  1:58 ` [RFC, V2, 10/11] media: platform: Add Mediatek ISP P1 SCP communication Jungo Lin
2019-05-10  1:58   ` Jungo Lin
2019-05-10  1:58   ` [RFC,V2,10/11] " Jungo Lin
2019-05-10  1:58 ` [RFC, V2, 11/11] media: platform: Add Mediatek ISP P1 shared memory device Jungo Lin
2019-05-10  1:58   ` Jungo Lin
2019-05-10  1:58   ` [RFC,V2,11/11] " Jungo Lin
2019-08-07 12:47 ` [RFC, v4, 0/4] media: platform: mtk-isp: Add Mediatek ISP Pass 1 driver Jungo Lin
2019-08-07 12:47   ` Jungo Lin
2019-08-07 12:47   ` [RFC,v4,0/4] " Jungo Lin
2019-08-07 12:48   ` [RFC,v4,1/4] media: dt-bindings: mt8183: Added camera ISP Pass 1 Jungo Lin
2019-08-07 12:48     ` Jungo Lin
2019-08-07 12:48     ` Jungo Lin
2019-08-21 19:47     ` Rob Herring
2019-08-21 19:47       ` Rob Herring
2019-08-21 19:47       ` Rob Herring
2019-08-22 12:47       ` Jungo Lin
2019-08-22 12:47         ` Jungo Lin
2019-08-22 12:47         ` Jungo Lin
     [not found]     ` <20190807124803.29884-2-jungo.lin-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
2019-08-21 20:17       ` Rob Herring
2019-08-21 20:17         ` Rob Herring
2019-08-21 20:17         ` Rob Herring
2019-08-22 12:48         ` Jungo Lin
2019-08-22 12:48           ` Jungo Lin
2019-08-22 12:48           ` Jungo Lin
2019-08-07 12:48   ` [RFC,v4,2/4] dts: arm64: mt8183: Add ISP Pass 1 nodes Jungo Lin
2019-08-07 12:48     ` Jungo Lin
2019-08-07 12:48     ` Jungo Lin
2019-08-07 12:48   ` [RFC, v4, 3/4] media: platform: Add Mediatek ISP P1 image & meta formats Jungo Lin
2019-08-07 12:48     ` Jungo Lin
2019-08-07 12:48     ` [RFC,v4,3/4] " Jungo Lin
2019-08-07 12:48   ` [RFC,v4,4/4] media: platform: Add Mediatek ISP P1 V4L2 device driver Jungo Lin
2019-08-07 12:48     ` Jungo Lin
2019-08-07 12:48     ` Jungo Lin
2019-09-02  7:51 ` [RFC, v5, 0/5] media: platform: mtk-isp: Add Mediatek ISP Pass 1 driver Jungo Lin
2019-09-02  7:51   ` Jungo Lin
2019-09-02  7:51   ` [RFC,v5,0/5] " Jungo Lin
2019-09-02  7:51   ` [RFC,v5, 1/5] media: dt-bindings: mt8183: Added camera ISP Pass 1 Jungo Lin
2019-09-02  7:51     ` Jungo Lin
2019-09-02  7:51     ` Jungo Lin
2019-09-02 15:17     ` [RFC, v5, " Rob Herring
2019-09-02 15:17       ` Rob Herring
2019-09-02 15:17       ` [RFC,v5, " Rob Herring
2019-09-02  7:51   ` [RFC,v5, 2/5] dts: arm64: mt8183: Add ISP Pass 1 nodes Jungo Lin
2019-09-02  7:51     ` Jungo Lin
2019-09-02  7:51     ` Jungo Lin
2019-09-02  7:51   ` [RFC,v5, 3/5] media: videodev2.h: Add new boottime timestamp type Jungo Lin
2019-09-02  7:51     ` Jungo Lin
2019-09-02  7:51     ` Jungo Lin
2019-09-02  7:51   ` [RFC, v5, 4/5] media: pixfmt: Add Mediatek ISP P1 image & meta formats Jungo Lin
2019-09-02  7:51     ` Jungo Lin
2019-09-02  7:51     ` [RFC,v5, " Jungo Lin
2019-09-02  7:51   ` [RFC, v5, 5/5] media: platform: Add Mediatek ISP P1 V4L2 device driver Jungo Lin
2019-09-02  7:51     ` Jungo Lin
2019-09-02  7:51     ` [RFC,v5, " Jungo Lin
2019-12-19  5:49 ` [v6, 0/5] media: media: platform: mtk-isp: Add Mediatek ISP Pass 1 driver Jungo Lin
2019-12-19  5:49   ` Jungo Lin
2019-12-19  5:49   ` [v6, 1/5] media: dt-bindings: mt8183: Added camera ISP Pass 1 Jungo Lin
2019-12-19  5:49     ` Jungo Lin
2019-12-19  5:49     ` Jungo Lin
2020-03-31 15:34     ` Helen Koike
2020-03-31 15:34       ` Helen Koike
2020-03-31 15:34       ` Helen Koike
2020-04-10 10:04       ` Jungo Lin
2020-04-10 10:04         ` Jungo Lin
2020-04-10 10:04         ` Jungo Lin
2019-12-19  5:49   ` [v6, 2/5] dts: arm64: mt8183: Add ISP Pass 1 nodes Jungo Lin
2019-12-19  5:49     ` Jungo Lin
2019-12-19  5:49     ` Jungo Lin
2019-12-19  5:49   ` [v6, 3/5] media: videodev2.h: Add new boottime timestamp type Jungo Lin
2019-12-19  5:49     ` Jungo Lin
2019-12-19  5:49     ` Jungo Lin
2020-01-07 14:10     ` Hans Verkuil
2020-01-07 14:10       ` Hans Verkuil
2020-01-07 14:10       ` Hans Verkuil
     [not found]       ` <e833b88ba74945c495a102c98cd54725@mtkmbs07n1.mediatek.inc>
2020-01-10  9:59         ` Jungo Lin
2020-01-10 10:08       ` Jungo Lin
2020-01-10 10:08         ` Jungo Lin
2020-01-10 10:08         ` Jungo Lin
2019-12-19  5:49   ` [v6, 4/5] media: platform: Add Mediatek ISP P1 image & meta formats Jungo Lin
2019-12-19  5:49     ` Jungo Lin
2019-12-19  5:49     ` Jungo Lin
2020-04-03  2:30     ` Laurent Pinchart
2020-04-03  2:30       ` Laurent Pinchart
2020-04-03  2:30       ` Laurent Pinchart
2020-04-10 10:00       ` Jungo Lin
2020-04-10 10:00         ` Jungo Lin
2020-04-10 10:00         ` Jungo Lin
2019-12-19  5:49   ` [v6, 5/5] media: platform: Add Mediatek ISP P1 V4L2 device driver Jungo Lin
2019-12-19  5:49     ` Jungo Lin
2020-01-23 13:59     ` Hans Verkuil
2020-01-23 13:59       ` Hans Verkuil
2020-01-23 13:59       ` Hans Verkuil
2020-01-28  2:13       ` Jungo Lin
2020-01-28  2:13         ` Jungo Lin
2020-01-28  2:13         ` Jungo Lin
2020-03-31 15:34     ` Helen Koike
2020-03-31 15:34       ` Helen Koike
2020-04-09  2:05       ` Jungo Lin
2020-04-09  2:05         ` Jungo Lin
2020-04-14 12:25         ` Helen Koike
2020-04-14 12:25           ` Helen Koike
     [not found]           ` <b2c30e560e9b4ec488957ca62bae09fe@mtkmbs01n2.mediatek.inc>
2020-05-04 12:27             ` Jungo Lin
2020-05-04 12:27               ` Jungo Lin
2020-05-04 12:27               ` Jungo Lin
2020-05-05 15:38               ` Helen Koike
2020-05-05 15:38                 ` Helen Koike
2020-05-05 15:38                 ` Helen Koike
2020-04-02 16:45     ` Dafna Hirschfeld
2020-04-02 16:45       ` Dafna Hirschfeld
2020-04-09  2:49       ` Jungo Lin
2020-04-09  2:49         ` Jungo Lin
2020-03-31 15:34   ` [v6, 0/5] media: media: platform: mtk-isp: Add Mediatek ISP Pass 1 driver Helen Koike
2020-03-31 15:34     ` Helen Koike
2020-03-31 15:34     ` Helen Koike
2020-04-10 10:32     ` Jungo Lin
2020-04-10 10:32       ` Jungo Lin
2020-04-14 12:25       ` Helen Koike
2020-04-14 12:25         ` Helen Koike
2020-04-14 12:25         ` Helen Koike
     [not found]         ` <1fd3615eb18f48ada186bfe228fc907b@mtkmbs01n2.mediatek.inc>
2020-05-04 12:40           ` Jungo Lin
2020-05-04 12:40             ` Jungo Lin
2020-05-05 15:30             ` Helen Koike
2020-05-05 15:30               ` Helen Koike
2020-05-05 15:30               ` Helen Koike
2020-05-05 16:18               ` Tomasz Figa
2020-05-05 16:18                 ` Tomasz Figa
2020-05-05 16:18                 ` Tomasz Figa
     [not found] <jungo.lin@mediatek.com>
2019-06-11  3:53 ` [RFC, V3 0/9] " Jungo Lin
2019-06-11  3:53   ` Jungo Lin
2019-06-11  3:53   ` [RFC,V3 " Jungo Lin
2019-06-11  3:53   ` [RFC,v3 1/9] dt-bindings: mt8183: Added camera ISP Pass 1 Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-06-11  3:53   ` [RFC,v3 2/9] dts: arm64: mt8183: Add ISP Pass 1 nodes Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-06-11  3:53   ` [RFC,v3 3/9] media: platform: Add Mediatek ISP Pass 1 driver Kconfig Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-06-11  3:53   ` [RFC, v3 4/9] media: platform: Add Mediatek ISP P1 image & meta formats Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-06-11  3:53     ` [RFC,v3 " Jungo Lin
2019-06-11  3:53   ` [RFC,v3 5/9] media: platform: Add Mediatek ISP P1 V4L2 control Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-07-01  5:50     ` Tomasz Figa
2019-07-01  5:50       ` Tomasz Figa
2019-07-01  5:50       ` Tomasz Figa
2019-07-02 11:34       ` Jungo Lin
2019-07-02 11:34         ` Jungo Lin
2019-07-02 11:34         ` Jungo Lin
2019-06-11  3:53   ` [RFC,v3 6/9] media: platform: Add Mediatek ISP P1 V4L2 functions Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-07-10  9:54     ` Tomasz Figa
2019-07-10  9:54       ` Tomasz Figa
2019-07-10  9:54       ` Tomasz Figa
2019-07-18  4:39       ` Jungo Lin
2019-07-18  4:39         ` Jungo Lin
2019-07-18  4:39         ` Jungo Lin
2019-07-23 10:21         ` Tomasz Figa
2019-07-23 10:21           ` Tomasz Figa
2019-07-23 10:21           ` Tomasz Figa
2019-07-24  4:31           ` Jungo Lin
2019-07-24  4:31             ` Jungo Lin
2019-07-24  4:31             ` Jungo Lin
2019-07-26  5:49             ` Tomasz Figa
2019-07-26  5:49               ` Tomasz Figa
2019-07-26  5:49               ` Tomasz Figa
2019-07-29  1:18               ` Jungo Lin
2019-07-29  1:18                 ` Jungo Lin
2019-07-29  1:18                 ` Jungo Lin
2019-07-29 10:04                 ` Tomasz Figa
2019-07-29 10:04                   ` Tomasz Figa
2019-07-29 10:04                   ` Tomasz Figa
2019-07-30  1:44                   ` Jungo Lin
2019-07-30  1:44                     ` Jungo Lin
2019-07-30  1:44                     ` Jungo Lin
2019-08-05  9:59                     ` Tomasz Figa
2019-08-05  9:59                       ` Tomasz Figa
2019-08-05  9:59                       ` Tomasz Figa
2019-06-11  3:53   ` [RFC,v3 7/9] media: platform: Add Mediatek ISP P1 device driver Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-07-10  9:56     ` Tomasz Figa
2019-07-10  9:56       ` Tomasz Figa
2019-07-10  9:56       ` Tomasz Figa
2019-07-20  9:58       ` Jungo Lin
2019-07-20  9:58         ` Jungo Lin
2019-07-20  9:58         ` Jungo Lin
2019-07-25  9:23         ` Tomasz Figa
2019-07-25  9:23           ` Tomasz Figa
2019-07-25  9:23           ` Tomasz Figa
2019-07-26  7:23           ` Jungo Lin
2019-07-26  7:23             ` Jungo Lin
2019-07-26  7:23             ` Jungo Lin
2019-08-06  9:47             ` Tomasz Figa
2019-08-06  9:47               ` Tomasz Figa
2019-08-06  9:47               ` Tomasz Figa
2019-08-07  2:11               ` Jungo Lin
2019-08-07  2:11                 ` Jungo Lin
2019-08-07  2:11                 ` Jungo Lin
2019-08-07 13:25                 ` Tomasz Figa
2019-08-07 13:25                   ` Tomasz Figa
2019-08-07 13:25                   ` Tomasz Figa
2019-06-11  3:53   ` [RFC,v3 8/9] media: platform: Add Mediatek ISP P1 SCP communication Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-06-11  3:53     ` Jungo Lin
     [not found]     ` <20190611035344.29814-9-jungo.lin-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
2019-07-10  9:58       ` Tomasz Figa
2019-07-10  9:58         ` Tomasz Figa
2019-07-10  9:58         ` Tomasz Figa
2019-07-21  2:18         ` Jungo Lin
2019-07-21  2:18           ` Jungo Lin
2019-07-21  2:18           ` Jungo Lin
2019-07-25 10:56           ` [RFC, v3 " Tomasz Figa
2019-07-25 10:56             ` Tomasz Figa
2019-07-25 10:56             ` [RFC,v3 " Tomasz Figa
2019-07-26  8:07             ` Jungo Lin
2019-07-26  8:07               ` Jungo Lin
2019-07-26  8:07               ` Jungo Lin
2019-06-11  3:53   ` [RFC, v3 9/9] media: platform: Add Mediatek ISP P1 shared memory device Jungo Lin
2019-06-11  3:53     ` Jungo Lin
2019-06-11  3:53     ` [RFC,v3 " Jungo Lin
2019-07-01  7:25     ` Tomasz Figa
2019-07-01  7:25       ` Tomasz Figa
2019-07-01  7:25       ` Tomasz Figa
2019-07-05  3:33       ` Jungo Lin
2019-07-05  3:33         ` Jungo Lin
2019-07-05  3:33         ` Jungo Lin
2019-07-05  4:22         ` [RFC, v3 " Tomasz Figa
2019-07-05  4:22           ` Tomasz Figa
2019-07-05  4:22           ` [RFC,v3 " Tomasz Figa
     [not found]           ` <CAAFQd5BaTQ-Q7gsE0X+d4_81OZq9WHaCYkmALt7_4A1JFo=_8g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2019-07-05  5:44             ` Jungo Lin
2019-07-05  5:44               ` Jungo Lin
2019-07-05  5:44               ` Jungo Lin
2019-07-05  7:59             ` Jungo Lin
2019-07-05  7:59               ` Jungo Lin
2019-07-05  7:59               ` Jungo Lin
2019-07-23  7:20               ` [RFC, v3 " Tomasz Figa
2019-07-23  7:20                 ` Tomasz Figa
2019-07-23  7:20                 ` [RFC,v3 " Tomasz Figa
     [not found]                 ` <CAAFQd5AaNFpMGCVJREY85n8UetEwd99TOka8-ECoLzMbMkos_g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2019-07-23  8:21                   ` [RFC, v3 " Jungo Lin
2019-07-23  8:21                     ` Jungo Lin
2019-07-23  8:21                     ` Jungo Lin
2019-07-26  5:15                     ` Tomasz Figa
2019-07-26  5:15                       ` Tomasz Figa
2019-07-26  5:15                       ` Tomasz Figa
     [not found]                       ` <CAAFQd5Bh80N+cMhz=eyHUGJLaE5uuypOawQvHrTgGSMDvmcpLA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2019-07-26  7:41                         ` Christoph Hellwig
2019-07-26  7:41                           ` Christoph Hellwig
2019-07-26  7:41                           ` Christoph Hellwig
2019-07-26  7:42                           ` Tomasz Figa
2019-07-26  7:42                             ` Tomasz Figa
2019-07-26  7:42                             ` Tomasz Figa
     [not found]                             ` <CAAFQd5CXwRm-3jD+rfNNDNLH=gT_i0QYSAG3XBo3SJnPTY56_w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2019-07-26 11:04                               ` Robin Murphy
2019-07-26 11:04                                 ` Robin Murphy
2019-07-26 11:04                                 ` Robin Murphy
2019-07-26 11:04                                 ` Robin Murphy
     [not found]                                 ` <4460bc91-352a-7f3a-cbed-1b95e743ca8c-5wv7dgnIgG8@public.gmane.org>
2019-07-26 11:59                                   ` Jungo Lin
2019-07-26 11:59                                     ` Jungo Lin
2019-07-26 11:59                                     ` Jungo Lin
2019-07-26 11:59                                     ` Jungo Lin
2019-07-26 14:04                                     ` Tomasz Figa
2019-07-26 14:04                                       ` Tomasz Figa
2019-07-26 14:04                                       ` Tomasz Figa
2019-07-26 14:04                                       ` Tomasz Figa

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1553767007-11909-11-git-send-email-jungo.lin@mediatek.com \
    --to=jungo.lin@mediatek.com \
    --cc=Jerry-ch.Chen@mediatek.com \
    --cc=Rynn.Wu@mediatek.com \
    --cc=Sean.Cheng@mediatek.com \
    --cc=christie.yu@mediatek.com \
    --cc=frankie.chiu@mediatek.com \
    --cc=frederic.chen@mediatek.com \
    --cc=hans.verkuil@cisco.com \
    --cc=holmes.chiou@mediatek.com \
    --cc=laurent.pinchart+renesas@ideasonboard.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=matthias.bgg@gmail.com \
    --cc=mchehab@kernel.org \
    --cc=ryan.yu@mediatek.com \
    --cc=seraph.huang@mediatek.com \
    --cc=sj.huang@mediatek.com \
    --cc=srv_heupstream@mediatek.com \
    --cc=tfiga@chromium.org \
    --cc=yuzhao@chromium.org \
    --cc=zwisler@chromium.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.