[PATCH v1 07/10] media: platform: mediatek: add isp_7x video ops
From: Shu-hsiang Yang
Date: Wed Oct 09 2024 - 07:17:38 EST
Introduces the V4L2 video interface and feature management for the
MediaTek ISP7x CAMSYS. These interfaces include various functionalities,
such as video operation initialization and registration. They also
manage MediaTek-specific formats and handle buffers for MediaTek camera
video devices. This integrates CAMSYS functionalities to be compatible
with the V4L2 framework.
Signed-off-by: Shu-hsiang Yang <Shu-hsiang.Yang@xxxxxxxxxxxx>
---
.../isp/isp_7x/camsys/mtk_cam-feature.c | 40 +
.../isp/isp_7x/camsys/mtk_cam-feature.h | 26 +
.../isp/isp_7x/camsys/mtk_cam-video.c | 1817 +++++++++++++++++
.../isp/isp_7x/camsys/mtk_cam-video.h | 224 ++
4 files changed, 2107 insertions(+)
create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.c
create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.h
create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.c
create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.h
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.c
new file mode 100644
index 000000000000..639c1e1671fc
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2022 MediaTek Inc.
+
+#include "mtk_cam-feature.h"
+
+struct mtk_cam_ctx;
+
+/*
+ * mtk_cam_is_[feature] is used for raw_feature,
+ * which must not change during streaming.
+ */
+
+static bool mtk_cam_is_no_seninf(struct mtk_cam_ctx *ctx)
+{
+ return !media_pad_remote_pad_first(&ctx->pipe->pads[MTK_RAW_SINK]);
+}
+
+bool mtk_cam_is_pure_m2m(struct mtk_cam_ctx *ctx)
+{
+ if (!ctx->used_raw_num)
+ return false;
+
+ if (ctx->pipe->feature_pending & MTK_CAM_FEATURE_PURE_OFFLINE_M2M_MASK ||
+ mtk_cam_is_no_seninf(ctx))
+ return true;
+ else
+ return false;
+}
+
+bool mtk_cam_is_m2m(struct mtk_cam_ctx *ctx)
+{
+ if (!ctx->used_raw_num)
+ return false;
+
+ if (mtk_cam_is_no_seninf(ctx))
+ return true;
+ else
+ return mtk_cam_feature_is_m2m(ctx->pipe->feature_pending);
+}
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.h
new file mode 100644
index 000000000000..dd5acc754765
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAM_FEATURE_H
+#define __MTK_CAM_FEATURE_H
+
+#include "mtk_cam.h"
+#include "mtk_cam-raw.h"
+
+static inline bool mtk_cam_feature_is_m2m(int feature)
+{
+ return !!(feature & MTK_CAM_FEATURE_OFFLINE_M2M_MASK) ||
+ !!(feature & MTK_CAM_FEATURE_PURE_OFFLINE_M2M_MASK);
+}
+
+static inline bool mtk_cam_feature_is_pure_m2m(int feature)
+{
+ return !!(feature & MTK_CAM_FEATURE_PURE_OFFLINE_M2M_MASK);
+}
+
+bool mtk_cam_is_m2m(struct mtk_cam_ctx *ctx);
+bool mtk_cam_is_pure_m2m(struct mtk_cam_ctx *ctx);
+
+#endif /*__MTK_CAM_FEATURE_H */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.c
new file mode 100644
index 000000000000..95cdf1a2fb4c
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.c
@@ -0,0 +1,1817 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2022 MediaTek Inc.
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+#include <linux/videodev2.h>
+#include <linux/iommu.h>
+
+#include "mtk_cam.h"
+#include "mtk_cam-feature.h"
+#include "mtk_cam-video.h"
+#include "mtk_camera-v4l2-controls.h"
+#include "mtk_cam-ufbc-def.h"
+
+/*
+ * differt dma (fmt) would have different bus_size
+ * align xsize(bytes per line) with [bus_size * pixel_mode]
+ */
+static inline int mtk_cam_is_fullg(unsigned int ipi_fmt)
+{
+ return (ipi_fmt == MTKCAM_IPI_IMG_FMT_FG_BAYER8) ||
+ (ipi_fmt == MTKCAM_IPI_IMG_FMT_FG_BAYER10) ||
+ (ipi_fmt == MTKCAM_IPI_IMG_FMT_FG_BAYER12);
+}
+
+static inline
+unsigned int mtk_cam_dma_bus_size(int bpp, int pixel_mode_shift, int is_fg)
+{
+ unsigned int bus_size = ALIGN(bpp, 16) << pixel_mode_shift;
+
+ if (is_fg)
+ bus_size <<= 1;
+ return bus_size / 8; /* in bytes */
+}
+
+static inline
+unsigned int mtk_cam_yuv_dma_bus_size(int bpp, int pixel_mode_shift)
+{
+ unsigned int bus_size = ALIGN(bpp, 32) << pixel_mode_shift;
+
+ return bus_size / 8; /* in bytes */
+}
+
+static inline
+unsigned int mtk_cam_dmao_xsize(int w, unsigned int ipi_fmt, int pixel_mode_shift)
+{
+ const unsigned int is_fg = mtk_cam_is_fullg(ipi_fmt);
+ const unsigned int bpp = mtk_cam_get_pixel_bits(ipi_fmt);
+ const unsigned int bytes = is_fg ?
+ DIV_ROUND_UP(w * bpp * 3 / 2, 8) : DIV_ROUND_UP(w * bpp, 8);
+ const unsigned int bus_size =
+ mtk_cam_dma_bus_size(bpp, pixel_mode_shift, is_fg);
+
+ return ALIGN(bytes, bus_size);
+}
+
+static void mtk_cam_release_all_buffer(struct mtk_cam_device *cam)
+{
+ struct mtk_cam_buffer *buf, *tmp;
+
+ spin_lock(&cam->dma_pending_lock);
+ list_for_each_entry_safe(buf, tmp, &cam->dma_pending, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vbb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock(&cam->dma_pending_lock);
+
+ spin_lock(&cam->dma_processing_lock);
+ list_for_each_entry_safe(buf, tmp, &cam->dma_processing, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vbb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock(&cam->dma_processing_lock);
+}
+
+static int mtk_cam_vb2_queue_setup(struct vb2_queue *vq,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct mtk_cam_device *cam = vb2_get_drv_priv(vq);
+ struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vq);
+ struct mtk_raw_pipeline *raw_pipeline;
+ unsigned int max_buffer_count = node->desc.max_buf_count;
+ const struct v4l2_format *fmt = &node->active_fmt;
+ unsigned int size;
+ int i;
+
+ /* Check the limitation of buffer size */
+ if (max_buffer_count)
+ *num_buffers = clamp_val(*num_buffers, 1, max_buffer_count);
+
+ if (node->desc.smem_alloc)
+ vq->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
+
+ if (vq->type == V4L2_BUF_TYPE_META_OUTPUT ||
+ vq->type == V4L2_BUF_TYPE_META_CAPTURE)
+ size = fmt->fmt.meta.buffersize;
+ else
+ size = fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
+
+ /* Add for q.create_bufs with fmt.g_sizeimage(p) / 2 test */
+ if (*num_planes) {
+ if (sizes[0] < size || *num_planes != 1)
+ return -EINVAL;
+ } else {
+ /* Set default as one plane */
+ *num_planes = 1;
+ sizes[0] = size;
+
+ if (is_raw_subdev(node->uid.pipe_id)) {
+ raw_pipeline =
+ mtk_cam_dev_get_raw_pipeline(cam, node->uid.pipe_id);
+
+ if (raw_pipeline &&
+ raw_pipeline->user_res.raw_res.feature &&
+ fmt->fmt.pix_mp.num_planes > 1) {
+ *num_planes = fmt->fmt.pix_mp.num_planes;
+ for (i = 0; i < *num_planes; i++)
+ sizes[i] = size;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int mtk_cam_vb2_buf_init(struct vb2_buffer *vb)
+{
+ struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vb->vb2_queue);
+ struct mtk_cam_buffer *buf;
+ struct mtk_cam_device *cam = vb2_get_drv_priv(vb->vb2_queue);
+ struct device *dev = cam->raw.devs[0];
+ dma_addr_t addr;
+
+ buf = mtk_cam_vb2_buf_to_dev_buf(vb);
+ buf->daddr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ buf->scp_addr = 0;
+
+ /* SCP address is only valid for meta input buffer */
+ if (!node->desc.smem_alloc)
+ return 0;
+
+ /* Use coherent address to get iova address */
+ addr = dma_map_resource(dev, buf->daddr, vb->planes[0].length,
+ DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC);
+ if (dma_mapping_error(dev, addr)) {
+ dev_err(dev, "failed to map addr:%pad\n", &buf->daddr);
+ return -EFAULT;
+ }
+ buf->scp_addr = buf->daddr;
+ buf->daddr = addr;
+
+ return 0;
+}
+
+static int mtk_cam_vb2_buf_prepare(struct vb2_buffer *vb)
+{
+ struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vb->vb2_queue);
+ struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
+ const struct v4l2_format *fmt = &node->active_fmt;
+ unsigned int size;
+
+ dev_dbg(vb->vb2_queue->dev, "%s: %s\n", __func__, node->desc.name);
+
+ if (vb->vb2_queue->type == V4L2_BUF_TYPE_META_OUTPUT ||
+ vb->vb2_queue->type == V4L2_BUF_TYPE_META_CAPTURE)
+ size = fmt->fmt.meta.buffersize;
+ else
+ size = fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
+
+ if (vb2_plane_size(vb, 0) < size) {
+ dev_info(vb->vb2_queue->dev,
+ "plane size is too small:%lu<%u\n",
+ vb2_plane_size(vb, 0), size);
+ }
+
+ if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+ if ((vb2_get_plane_payload(vb, 0) != size) &&
+ vb->vb2_queue->streaming) {
+ dev_dbg(vb->vb2_queue->dev,
+ "plane payload is mismatch:%lu:%u\n",
+ vb2_get_plane_payload(vb, 0), size);
+ }
+ return 0;
+ }
+
+ v4l2_buf->field = V4L2_FIELD_NONE;
+ vb2_set_plane_payload(vb, 0, size);
+
+ return 0;
+}
+
+static int mtk_cam_vb2_start_streaming(struct vb2_queue *vq,
+ unsigned int count)
+{
+ struct mtk_cam_device *cam = vb2_get_drv_priv(vq);
+ struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vq);
+ struct media_entity *entity = &node->vdev.entity;
+ struct mtk_cam_ctx *ctx = NULL;
+ struct device *dev = cam->dev;
+ int ret;
+
+ /* check entity is linked */
+ if (!node->enabled) {
+ dev_info(cam->dev,
+ "%s: stream on failed, node is not enabled\n",
+ node->desc.name);
+ ret = -ENOLINK;
+ goto fail_return_buffer;
+ }
+
+ if (!media_entity_is_streaming(entity)) {
+ ctx = mtk_cam_start_ctx(cam, node);
+ if (!ctx) {
+ ret = -ENOLINK;
+ goto fail_return_buffer;
+ }
+ } else {
+ ctx = mtk_cam_find_ctx(cam, entity);
+ if (WARN_ON(!ctx)) {
+ ret = -ENOLINK;
+ goto fail_return_buffer;
+ }
+ }
+
+ cam->streaming_pipe |= (1 << node->uid.pipe_id);
+ ctx->streaming_pipe |= (1 << node->uid.pipe_id);
+ ctx->streaming_node_cnt++;
+
+ if (ctx->streaming_node_cnt == 1)
+ if (is_raw_subdev(node->uid.pipe_id)) {
+ if (!isp_composer_create_session(ctx)) {
+ ctx->session_created = 1;
+ } else {
+ complete(&ctx->session_complete);
+ ret = -EBUSY;
+ goto fail_stop_ctx;
+ }
+ }
+
+ dev_dbg(dev, "%s:%s:ctx(%d): node:%d count info:%d\n", __func__,
+ node->desc.name, ctx->stream_id, node->desc.id,
+ ctx->streaming_node_cnt);
+
+ ret = mtk_cam_ctx_stream_on(ctx, node);
+ if (ret)
+ goto fail_destroy_session;
+
+ mtk_cam_buf_try_queue(ctx);
+
+ return 0;
+
+fail_destroy_session:
+ if (ctx->session_created)
+ isp_composer_destroy_session(ctx);
+fail_stop_ctx:
+ ctx->streaming_node_cnt--;
+ ctx->streaming_pipe &= ~(1 << node->uid.pipe_id);
+ cam->streaming_pipe &= ~(1 << node->uid.pipe_id);
+ mtk_cam_dev_req_cleanup(ctx, node->uid.pipe_id, VB2_BUF_STATE_QUEUED);
+ mtk_cam_stop_ctx(ctx, node);
+fail_return_buffer:
+ mtk_cam_release_all_buffer(cam);
+ /* relese bufs by request */
+ return ret;
+}
+
+static void mtk_cam_vb2_stop_streaming(struct vb2_queue *vq)
+{
+ struct mtk_cam_device *cam = vb2_get_drv_priv(vq);
+ struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vq);
+ struct device *dev = cam->dev;
+ struct mtk_cam_ctx *ctx;
+
+ ctx = mtk_cam_find_ctx(cam, &node->vdev.entity);
+ if (WARN_ON(!ctx)) {
+ /* the ctx is stop, media_pipeline_stop is called */
+ mtk_cam_dev_req_clean_pending(cam, node->uid.pipe_id,
+ VB2_BUF_STATE_ERROR);
+ return;
+ }
+
+ dev_dbg(dev, "%s:%s:ctx(%d): node:%d count info:%d\n", __func__,
+ node->desc.name, ctx->stream_id, node->desc.id,
+ ctx->streaming_node_cnt);
+
+ mtk_cam_ctx_stream_off(ctx, node);
+
+ if (cam->streaming_pipe & (1 << node->uid.pipe_id)) {
+ /* NOTE: take multi-pipelines case into consideration */
+ /* Moreover, must clean bit mask before req cleanup */
+ /* Otherwise, would cause req not removed in pending list */
+ cam->streaming_pipe &= ~(1 << node->uid.pipe_id);
+ mtk_cam_dev_req_cleanup(ctx, node->uid.pipe_id, VB2_BUF_STATE_ERROR);
+ }
+
+ /* all bufs of node should be return by per requests */
+ mtk_cam_release_all_buffer(ctx->cam);
+
+ /* NOTE: take multi-pipelines case into consideration */
+ cam->streaming_pipe &= ~(1 << node->uid.pipe_id);
+ ctx->streaming_node_cnt--;
+ if (ctx->streaming_node_cnt)
+ return;
+
+ mtk_cam_stop_ctx(ctx, node);
+}
+
+int is_mtk_format(u32 pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_YUYV10:
+ case V4L2_PIX_FMT_YVYU10:
+ case V4L2_PIX_FMT_UYVY10:
+ case V4L2_PIX_FMT_VYUY10:
+ case V4L2_PIX_FMT_YUYV12:
+ case V4L2_PIX_FMT_YVYU12:
+ case V4L2_PIX_FMT_UYVY12:
+ case V4L2_PIX_FMT_VYUY12:
+ case V4L2_PIX_FMT_MTISP_YUYV10P:
+ case V4L2_PIX_FMT_MTISP_YVYU10P:
+ case V4L2_PIX_FMT_MTISP_UYVY10P:
+ case V4L2_PIX_FMT_MTISP_VYUY10P:
+ case V4L2_PIX_FMT_MTISP_YUYV12P:
+ case V4L2_PIX_FMT_MTISP_YVYU12P:
+ case V4L2_PIX_FMT_MTISP_UYVY12P:
+ case V4L2_PIX_FMT_MTISP_VYUY12P:
+ case V4L2_PIX_FMT_NV12_10:
+ case V4L2_PIX_FMT_NV21_10:
+ case V4L2_PIX_FMT_NV16_10:
+ case V4L2_PIX_FMT_NV61_10:
+ case V4L2_PIX_FMT_NV12_12:
+ case V4L2_PIX_FMT_NV21_12:
+ case V4L2_PIX_FMT_NV16_12:
+ case V4L2_PIX_FMT_NV61_12:
+ case V4L2_PIX_FMT_MTISP_NV12_10P:
+ case V4L2_PIX_FMT_MTISP_NV21_10P:
+ case V4L2_PIX_FMT_MTISP_NV16_10P:
+ case V4L2_PIX_FMT_MTISP_NV61_10P:
+ case V4L2_PIX_FMT_MTISP_NV12_12P:
+ case V4L2_PIX_FMT_MTISP_NV21_12P:
+ case V4L2_PIX_FMT_MTISP_NV16_12P:
+ case V4L2_PIX_FMT_MTISP_NV61_12P:
+ case V4L2_PIX_FMT_MTISP_NV12_UFBC:
+ case V4L2_PIX_FMT_MTISP_NV21_UFBC:
+ case V4L2_PIX_FMT_MTISP_NV12_10_UFBC:
+ case V4L2_PIX_FMT_MTISP_NV21_10_UFBC:
+ case V4L2_PIX_FMT_MTISP_NV12_12_UFBC:
+ case V4L2_PIX_FMT_MTISP_NV21_12_UFBC:
+ case V4L2_PIX_FMT_MTISP_BAYER8_UFBC:
+ case V4L2_PIX_FMT_MTISP_BAYER10_UFBC:
+ case V4L2_PIX_FMT_MTISP_BAYER12_UFBC:
+ case V4L2_PIX_FMT_MTISP_BAYER14_UFBC:
+ case V4L2_PIX_FMT_MTISP_SGRB8F:
+ case V4L2_PIX_FMT_MTISP_SGRB10F:
+ case V4L2_PIX_FMT_MTISP_SGRB12F:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int is_yuv_ufo(u32 pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_MTISP_NV12_UFBC:
+ case V4L2_PIX_FMT_MTISP_NV21_UFBC:
+ case V4L2_PIX_FMT_MTISP_NV12_10_UFBC:
+ case V4L2_PIX_FMT_MTISP_NV21_10_UFBC:
+ case V4L2_PIX_FMT_MTISP_NV12_12_UFBC:
+ case V4L2_PIX_FMT_MTISP_NV21_12_UFBC:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int is_raw_ufo(u32 pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_MTISP_BAYER8_UFBC:
+ case V4L2_PIX_FMT_MTISP_BAYER10_UFBC:
+ case V4L2_PIX_FMT_MTISP_BAYER12_UFBC:
+ case V4L2_PIX_FMT_MTISP_BAYER14_UFBC:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int is_fullg_rb(u32 pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_MTISP_SGRB8F:
+ case V4L2_PIX_FMT_MTISP_SGRB10F:
+ case V4L2_PIX_FMT_MTISP_SGRB12F:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+const struct mtk_format_info *mtk_format_info(u32 format)
+{
+ static const struct mtk_format_info formats[] = {
+ /* YUV planar formats */
+ { .format = V4L2_PIX_FMT_NV12_10,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_NV21_10,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_NV16_10,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_NV61_10,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_YUYV10,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_YVYU10,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_UYVY10,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_VYUY10,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_NV12_12,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_NV21_12,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_NV16_12,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_NV61_12,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_YUYV12,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_YVYU12,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_UYVY12,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_VYUY12,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 },
+ /* YUV packed formats */
+ { .format = V4L2_PIX_FMT_MTISP_YUYV10P,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 },
+ { .format = V4L2_PIX_FMT_MTISP_YVYU10P,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 },
+ { .format = V4L2_PIX_FMT_MTISP_UYVY10P,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 },
+ { .format = V4L2_PIX_FMT_MTISP_VYUY10P,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 },
+ { .format = V4L2_PIX_FMT_MTISP_NV12_10P,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 5, .bit_r_den = 4 },
+ { .format = V4L2_PIX_FMT_MTISP_NV21_10P,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 5, .bit_r_den = 4 },
+ { .format = V4L2_PIX_FMT_MTISP_NV16_10P,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 },
+ { .format = V4L2_PIX_FMT_MTISP_NV61_10P,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 },
+ { .format = V4L2_PIX_FMT_MTISP_YUYV12P,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 },
+ { .format = V4L2_PIX_FMT_MTISP_YVYU12P,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 },
+ { .format = V4L2_PIX_FMT_MTISP_UYVY12P,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 },
+ { .format = V4L2_PIX_FMT_MTISP_VYUY12P,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 },
+ { .format = V4L2_PIX_FMT_MTISP_NV12_12P,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 3, .bit_r_den = 2 },
+ { .format = V4L2_PIX_FMT_MTISP_NV21_12P,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 3, .bit_r_den = 2 },
+ { .format = V4L2_PIX_FMT_MTISP_NV16_12P,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 },
+ { .format = V4L2_PIX_FMT_MTISP_NV61_12P,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 },
+ /* YUV UFBC formats */
+ { .format = V4L2_PIX_FMT_MTISP_NV12_UFBC,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_MTISP_NV21_UFBC,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 2, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_MTISP_NV12_10_UFBC,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 5, .bit_r_den = 4 },
+ { .format = V4L2_PIX_FMT_MTISP_NV21_10_UFBC,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 5, .bit_r_den = 4 },
+ { .format = V4L2_PIX_FMT_MTISP_NV12_12_UFBC,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 3, .bit_r_den = 2 },
+ { .format = V4L2_PIX_FMT_MTISP_NV21_12_UFBC,
+ .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 3, .bit_r_den = 2 },
+ { .format = V4L2_PIX_FMT_MTISP_BAYER8_UFBC,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 },
+ .hdiv = 1, .vdiv = 1, .bit_r_num = 1, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_MTISP_BAYER10_UFBC,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 },
+ .hdiv = 1, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 },
+ { .format = V4L2_PIX_FMT_MTISP_BAYER12_UFBC,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 },
+ .hdiv = 1, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 },
+ { .format = V4L2_PIX_FMT_MTISP_BAYER14_UFBC,
+ .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 },
+ .hdiv = 1, .vdiv = 1, .bit_r_num = 7, .bit_r_den = 4 },
+ /* Full-G RGB formats */
+ { .format = V4L2_PIX_FMT_MTISP_SGRB8F,
+ .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 1, .bit_r_den = 1 },
+ { .format = V4L2_PIX_FMT_MTISP_SGRB10F,
+ .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 5, .bit_r_den = 4 },
+ { .format = V4L2_PIX_FMT_MTISP_SGRB12F,
+ .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 },
+ .hdiv = 2, .vdiv = 2, .bit_r_num = 3, .bit_r_den = 2 },
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i)
+ if (formats[i].format == format)
+ return &formats[i];
+ return NULL;
+}
+
+static void mtk_cam_vb2_buf_queue(struct vb2_buffer *vb)
+{
+ struct mtk_cam_device *cam = vb2_get_drv_priv(vb->vb2_queue);
+ struct mtk_cam_buffer *buf = mtk_cam_vb2_buf_to_dev_buf(vb);
+ struct mtk_cam_request *req = to_mtk_cam_req(vb->request);
+ struct mtk_cam_request_stream_data *req_stream_data;
+ struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vb->vb2_queue);
+ struct mtk_raw_pde_config *pde_cfg;
+ struct device *dev = cam->dev;
+ struct mtkcam_ipi_frame_param *frame_param;
+ struct mtkcam_ipi_meta_input *meta_in;
+ struct mtkcam_ipi_meta_output *meta_out;
+ struct mtk_cam_ctx *ctx;
+ unsigned int pipe_id;
+ unsigned int desc_id;
+ unsigned int dma_port = node->desc.dma_port;
+
+ if (!vb->vb2_queue->uses_requests) {
+ spin_lock(&cam->dma_pending_lock);
+ list_add_tail(&buf->list, &cam->dma_pending);
+ spin_unlock(&cam->dma_pending_lock);
+ buf->state.estate = E_BUF_STATE_QUEUED;
+ if (media_entity_is_streaming(&node->vdev.entity)) {
+ ctx = mtk_cam_find_ctx(cam, &node->vdev.entity);
+ mtk_cam_buf_try_queue(ctx);
+ }
+ return;
+ }
+
+ dma_port = node->desc.dma_port;
+ pipe_id = node->uid.pipe_id;
+ req_stream_data = mtk_cam_req_get_s_data(req, pipe_id, 0);
+ frame_param = &req_stream_data->frame_params;
+ mtk_cam_s_data_set_vbuf(req_stream_data, buf, node->desc.id);
+
+ /* update buffer internal address */
+ switch (dma_port) {
+ case MTKCAM_IPI_RAW_META_STATS_CFG:
+ desc_id = node->desc.id - MTK_RAW_SINK_NUM;
+ meta_in = &frame_param->meta_inputs[desc_id];
+ meta_in->buf.size = node->active_fmt.fmt.meta.buffersize;
+ meta_in->buf.iova = buf->daddr;
+ meta_in->buf.scp_addr = buf->scp_addr;
+ meta_in->uid.id = dma_port;
+ break;
+ case MTKCAM_IPI_RAW_META_STATS_0:
+ case MTKCAM_IPI_RAW_META_STATS_1:
+ case MTKCAM_IPI_RAW_META_STATS_2:
+ pde_cfg = &cam->raw.pipelines[node->uid.pipe_id].pde_config;
+ desc_id = node->desc.id - MTK_RAW_META_OUT_BEGIN;
+ meta_out = &frame_param->meta_outputs[desc_id];
+ meta_out->buf.size = node->active_fmt.fmt.meta.buffersize;
+ meta_out->buf.iova = buf->daddr;
+ meta_out->buf.scp_addr = buf->scp_addr;
+ meta_out->uid.id = dma_port;
+ camsys_set_meta_stats_info(dma_port, vb, pde_cfg);
+ break;
+ default:
+ dev_dbg(dev, "%s:pipe(%d):buffer with invalid port(%d)\n",
+ __func__, pipe_id, dma_port);
+ break;
+ }
+}
+
+static void mtk_cam_vb2_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vb->vb2_queue);
+ struct mtk_cam_buffer *buf;
+ struct mtk_cam_device *cam = vb2_get_drv_priv(vb->vb2_queue);
+ struct device *dev = cam->raw.devs[0];
+
+ /* SCP address is only valid for meta input buffer */
+ if (!node->desc.smem_alloc)
+ return;
+
+ buf = mtk_cam_vb2_buf_to_dev_buf(vb);
+ dma_unmap_page_attrs(dev, buf->daddr, vb->planes[0].length,
+ DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC);
+}
+
+static void mtk_cam_vb2_request_complete(struct vb2_buffer *vb)
+{
+ struct mtk_cam_device *cam = vb2_get_drv_priv(vb->vb2_queue);
+
+ dev_dbg(vb->vb2_queue->dev, "camsys | request %s\n", __func__);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, cam->v4l2_dev.ctrl_handler);
+}
+
+static int mtk_cam_vb2_buf_out_validate(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
+
+ if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (v4l2_buf->field == V4L2_FIELD_ANY)
+ v4l2_buf->field = V4L2_FIELD_NONE;
+
+ if (v4l2_buf->field != V4L2_FIELD_NONE)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct vb2_ops mtk_cam_vb2_ops = {
+ .queue_setup = mtk_cam_vb2_queue_setup,
+
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+
+ .buf_out_validate = mtk_cam_vb2_buf_out_validate,
+ .buf_init = mtk_cam_vb2_buf_init,
+ .buf_prepare = mtk_cam_vb2_buf_prepare,
+
+ .start_streaming = mtk_cam_vb2_start_streaming,
+ .stop_streaming = mtk_cam_vb2_stop_streaming,
+
+ .buf_queue = mtk_cam_vb2_buf_queue,
+ .buf_cleanup = mtk_cam_vb2_buf_cleanup,
+ .buf_request_complete = mtk_cam_vb2_request_complete,
+};
+
+static const struct v4l2_file_operations mtk_cam_v4l2_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = video_ioctl2,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = v4l2_compat_ioctl32,
+#endif
+};
+
+unsigned int mtk_cam_get_sensor_pixel_id(unsigned int fmt)
+{
+ switch (fmt & SENSOR_FMT_MASK) {
+ 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 MTKCAM_IPI_BAYER_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 MTKCAM_IPI_BAYER_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 MTKCAM_IPI_BAYER_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 MTKCAM_IPI_BAYER_PXL_ID_R;
+ default:
+ return MTKCAM_IPI_BAYER_PXL_ID_UNKNOWN;
+ }
+}
+
+unsigned int mtk_cam_get_sensor_fmt(unsigned int fmt)
+{
+ switch (fmt & SENSOR_FMT_MASK) {
+ 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 MTKCAM_IPI_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 MTKCAM_IPI_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 MTKCAM_IPI_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 MTKCAM_IPI_IMG_FMT_BAYER14;
+ default:
+ return MTKCAM_IPI_IMG_FMT_UNKNOWN;
+ }
+}
+
+unsigned int mtk_cam_get_pixel_bits(unsigned int ipi_fmt)
+{
+ switch (ipi_fmt) {
+ case MTKCAM_IPI_IMG_FMT_BAYER8:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER8:
+ return 8;
+ case MTKCAM_IPI_IMG_FMT_BAYER10:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER10:
+ case MTKCAM_IPI_IMG_FMT_BAYER10_MIPI:
+ return 10;
+ case MTKCAM_IPI_IMG_FMT_BAYER12:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER12:
+ return 12;
+ case MTKCAM_IPI_IMG_FMT_BAYER14:
+ case MTKCAM_IPI_IMG_FMT_UFBC_BAYER14:
+ return 14;
+ case MTKCAM_IPI_IMG_FMT_BAYER10_UNPACKED:
+ case MTKCAM_IPI_IMG_FMT_BAYER12_UNPACKED:
+ case MTKCAM_IPI_IMG_FMT_BAYER14_UNPACKED:
+ case MTKCAM_IPI_IMG_FMT_BAYER16:
+ case MTKCAM_IPI_IMG_FMT_YUYV:
+ case MTKCAM_IPI_IMG_FMT_YVYU:
+ case MTKCAM_IPI_IMG_FMT_UYVY:
+ case MTKCAM_IPI_IMG_FMT_VYUY:
+ return 16;
+ case MTKCAM_IPI_IMG_FMT_Y8:
+ case MTKCAM_IPI_IMG_FMT_YUV_422_2P:
+ case MTKCAM_IPI_IMG_FMT_YVU_422_2P:
+ case MTKCAM_IPI_IMG_FMT_YUV_422_3P:
+ case MTKCAM_IPI_IMG_FMT_YVU_422_3P:
+ case MTKCAM_IPI_IMG_FMT_YUV_420_2P:
+ case MTKCAM_IPI_IMG_FMT_YVU_420_2P:
+ case MTKCAM_IPI_IMG_FMT_YUV_420_3P:
+ case MTKCAM_IPI_IMG_FMT_YVU_420_3P:
+ return 8;
+ case MTKCAM_IPI_IMG_FMT_YUYV_Y210:
+ case MTKCAM_IPI_IMG_FMT_YVYU_Y210:
+ case MTKCAM_IPI_IMG_FMT_UYVY_Y210:
+ case MTKCAM_IPI_IMG_FMT_VYUY_Y210:
+ return 32;
+ case MTKCAM_IPI_IMG_FMT_YUV_P210:
+ case MTKCAM_IPI_IMG_FMT_YVU_P210:
+ case MTKCAM_IPI_IMG_FMT_YUV_P010:
+ case MTKCAM_IPI_IMG_FMT_YVU_P010:
+ case MTKCAM_IPI_IMG_FMT_YUV_P212:
+ case MTKCAM_IPI_IMG_FMT_YVU_P212:
+ case MTKCAM_IPI_IMG_FMT_YUV_P012:
+ case MTKCAM_IPI_IMG_FMT_YVU_P012:
+ return 16;
+ case MTKCAM_IPI_IMG_FMT_YUYV_Y210_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YVYU_Y210_PACKED:
+ case MTKCAM_IPI_IMG_FMT_UYVY_Y210_PACKED:
+ case MTKCAM_IPI_IMG_FMT_VYUY_Y210_PACKED:
+ return 20;
+ case MTKCAM_IPI_IMG_FMT_YUV_P210_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YVU_P210_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YUV_P010_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YVU_P010_PACKED:
+ return 10;
+ case MTKCAM_IPI_IMG_FMT_YUV_P212_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YVU_P212_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YUV_P012_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YVU_P012_PACKED:
+ return 12;
+ case MTKCAM_IPI_IMG_FMT_RGB_8B_3P:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER8_3P:
+ case MTKCAM_IPI_IMG_FMT_UFBC_NV12:
+ case MTKCAM_IPI_IMG_FMT_UFBC_NV21:
+ case MTKCAM_IPI_IMG_FMT_UFBC_BAYER8:
+ return 8;
+ case MTKCAM_IPI_IMG_FMT_RGB_10B_3P_PACKED:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER10_3P_PACKED:
+ case MTKCAM_IPI_IMG_FMT_UFBC_YUV_P010:
+ case MTKCAM_IPI_IMG_FMT_UFBC_YVU_P010:
+ case MTKCAM_IPI_IMG_FMT_UFBC_BAYER10:
+ return 10;
+ case MTKCAM_IPI_IMG_FMT_RGB_12B_3P_PACKED:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER12_3P_PACKED:
+ case MTKCAM_IPI_IMG_FMT_UFBC_YUV_P012:
+ case MTKCAM_IPI_IMG_FMT_UFBC_YVU_P012:
+ case MTKCAM_IPI_IMG_FMT_UFBC_BAYER12:
+ return 12;
+ case MTKCAM_IPI_IMG_FMT_RGB_10B_3P:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER10_3P:
+ case MTKCAM_IPI_IMG_FMT_RGB_12B_3P:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER12_3P:
+ return 16;
+ default:
+ break;
+ }
+ pr_debug("not supported ipi-fmt 0x%08x", ipi_fmt);
+
+ return -1;
+}
+
+unsigned int mtk_cam_get_img_fmt(unsigned int fourcc)
+{
+ switch (fourcc) {
+ case V4L2_PIX_FMT_GREY:
+ return MTKCAM_IPI_IMG_FMT_Y8;
+ case V4L2_PIX_FMT_YUYV:
+ return MTKCAM_IPI_IMG_FMT_YUYV;
+ case V4L2_PIX_FMT_YVYU:
+ return MTKCAM_IPI_IMG_FMT_YVYU;
+ case V4L2_PIX_FMT_NV16:
+ return MTKCAM_IPI_IMG_FMT_YUV_422_2P;
+ case V4L2_PIX_FMT_NV61:
+ return MTKCAM_IPI_IMG_FMT_YVU_422_2P;
+ case V4L2_PIX_FMT_NV12:
+ return MTKCAM_IPI_IMG_FMT_YUV_420_2P;
+ case V4L2_PIX_FMT_NV21:
+ return MTKCAM_IPI_IMG_FMT_YVU_420_2P;
+ case V4L2_PIX_FMT_YUV422P:
+ return MTKCAM_IPI_IMG_FMT_YUV_422_3P;
+ case V4L2_PIX_FMT_YUV420:
+ return MTKCAM_IPI_IMG_FMT_YUV_420_3P;
+ case V4L2_PIX_FMT_YVU420:
+ return MTKCAM_IPI_IMG_FMT_YVU_420_3P;
+ case V4L2_PIX_FMT_NV12_10:
+ return MTKCAM_IPI_IMG_FMT_YUV_P010;
+ case V4L2_PIX_FMT_NV21_10:
+ return MTKCAM_IPI_IMG_FMT_YVU_P010;
+ case V4L2_PIX_FMT_NV16_10:
+ return MTKCAM_IPI_IMG_FMT_YUV_P210;
+ case V4L2_PIX_FMT_NV61_10:
+ return MTKCAM_IPI_IMG_FMT_YVU_P210;
+ case V4L2_PIX_FMT_MTISP_NV12_10P:
+ return MTKCAM_IPI_IMG_FMT_YUV_P010_PACKED;
+ case V4L2_PIX_FMT_MTISP_NV21_10P:
+ return MTKCAM_IPI_IMG_FMT_YVU_P010_PACKED;
+ case V4L2_PIX_FMT_MTISP_NV16_10P:
+ return MTKCAM_IPI_IMG_FMT_YUV_P210_PACKED;
+ case V4L2_PIX_FMT_MTISP_NV61_10P:
+ return MTKCAM_IPI_IMG_FMT_YVU_P210_PACKED;
+ case V4L2_PIX_FMT_YUYV10:
+ return MTKCAM_IPI_IMG_FMT_YUYV_Y210;
+ case V4L2_PIX_FMT_YVYU10:
+ return MTKCAM_IPI_IMG_FMT_YVYU_Y210;
+ case V4L2_PIX_FMT_UYVY10:
+ return MTKCAM_IPI_IMG_FMT_UYVY_Y210;
+ case V4L2_PIX_FMT_VYUY10:
+ return MTKCAM_IPI_IMG_FMT_VYUY_Y210;
+ case V4L2_PIX_FMT_MTISP_YUYV10P:
+ return MTKCAM_IPI_IMG_FMT_YUYV_Y210_PACKED;
+ case V4L2_PIX_FMT_MTISP_YVYU10P:
+ return MTKCAM_IPI_IMG_FMT_YVYU_Y210_PACKED;
+ case V4L2_PIX_FMT_MTISP_UYVY10P:
+ return MTKCAM_IPI_IMG_FMT_UYVY_Y210_PACKED;
+ case V4L2_PIX_FMT_MTISP_VYUY10P:
+ return MTKCAM_IPI_IMG_FMT_VYUY_Y210_PACKED;
+ case V4L2_PIX_FMT_NV12_12:
+ return MTKCAM_IPI_IMG_FMT_YUV_P012;
+ case V4L2_PIX_FMT_NV21_12:
+ return MTKCAM_IPI_IMG_FMT_YVU_P012;
+ case V4L2_PIX_FMT_NV16_12:
+ return MTKCAM_IPI_IMG_FMT_YUV_P212;
+ case V4L2_PIX_FMT_NV61_12:
+ return MTKCAM_IPI_IMG_FMT_YVU_P212;
+ case V4L2_PIX_FMT_MTISP_NV12_12P:
+ return MTKCAM_IPI_IMG_FMT_YUV_P012_PACKED;
+ case V4L2_PIX_FMT_MTISP_NV21_12P:
+ return MTKCAM_IPI_IMG_FMT_YVU_P012_PACKED;
+ case V4L2_PIX_FMT_MTISP_NV16_12P:
+ return MTKCAM_IPI_IMG_FMT_YUV_P212_PACKED;
+ case V4L2_PIX_FMT_MTISP_NV61_12P:
+ return MTKCAM_IPI_IMG_FMT_YVU_P212_PACKED;
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ return MTKCAM_IPI_IMG_FMT_BAYER8;
+ case V4L2_PIX_FMT_MTISP_SBGGR8F:
+ case V4L2_PIX_FMT_MTISP_SGBRG8F:
+ case V4L2_PIX_FMT_MTISP_SGRBG8F:
+ case V4L2_PIX_FMT_MTISP_SRGGB8F:
+ return MTKCAM_IPI_IMG_FMT_FG_BAYER8;
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ return MTKCAM_IPI_IMG_FMT_BAYER10_UNPACKED;
+ case V4L2_PIX_FMT_SBGGR10P:
+ case V4L2_PIX_FMT_SGBRG10P:
+ case V4L2_PIX_FMT_SGRBG10P:
+ case V4L2_PIX_FMT_SRGGB10P:
+ return MTKCAM_IPI_IMG_FMT_BAYER10_MIPI;
+ case V4L2_PIX_FMT_MTISP_SBGGR10:
+ case V4L2_PIX_FMT_MTISP_SGBRG10:
+ case V4L2_PIX_FMT_MTISP_SGRBG10:
+ case V4L2_PIX_FMT_MTISP_SRGGB10:
+ return MTKCAM_IPI_IMG_FMT_BAYER10;
+ case V4L2_PIX_FMT_MTISP_SBGGR10F:
+ case V4L2_PIX_FMT_MTISP_SGBRG10F:
+ case V4L2_PIX_FMT_MTISP_SGRBG10F:
+ case V4L2_PIX_FMT_MTISP_SRGGB10F:
+ return MTKCAM_IPI_IMG_FMT_FG_BAYER10;
+ case V4L2_PIX_FMT_SBGGR12:
+ case V4L2_PIX_FMT_SGBRG12:
+ case V4L2_PIX_FMT_SGRBG12:
+ case V4L2_PIX_FMT_SRGGB12:
+ return MTKCAM_IPI_IMG_FMT_BAYER12_UNPACKED;
+ case V4L2_PIX_FMT_MTISP_SBGGR12:
+ case V4L2_PIX_FMT_MTISP_SGBRG12:
+ case V4L2_PIX_FMT_MTISP_SGRBG12:
+ case V4L2_PIX_FMT_MTISP_SRGGB12:
+ return MTKCAM_IPI_IMG_FMT_BAYER12;
+ case V4L2_PIX_FMT_MTISP_SBGGR12F:
+ case V4L2_PIX_FMT_MTISP_SGBRG12F:
+ case V4L2_PIX_FMT_MTISP_SGRBG12F:
+ case V4L2_PIX_FMT_MTISP_SRGGB12F:
+ return MTKCAM_IPI_IMG_FMT_FG_BAYER12;
+ case V4L2_PIX_FMT_SBGGR14:
+ case V4L2_PIX_FMT_SGBRG14:
+ case V4L2_PIX_FMT_SGRBG14:
+ case V4L2_PIX_FMT_SRGGB14:
+ return MTKCAM_IPI_IMG_FMT_BAYER14_UNPACKED;
+ case V4L2_PIX_FMT_MTISP_SBGGR14:
+ case V4L2_PIX_FMT_MTISP_SGBRG14:
+ case V4L2_PIX_FMT_MTISP_SGRBG14:
+ case V4L2_PIX_FMT_MTISP_SRGGB14:
+ return MTKCAM_IPI_IMG_FMT_BAYER14;
+ case V4L2_PIX_FMT_MTISP_SBGGR14F:
+ case V4L2_PIX_FMT_MTISP_SGBRG14F:
+ case V4L2_PIX_FMT_MTISP_SGRBG14F:
+ case V4L2_PIX_FMT_MTISP_SRGGB14F:
+ return MTKCAM_IPI_IMG_FMT_FG_BAYER14;
+ case V4L2_PIX_FMT_SBGGR16:
+ case V4L2_PIX_FMT_SGBRG16:
+ case V4L2_PIX_FMT_SGRBG16:
+ case V4L2_PIX_FMT_SRGGB16:
+ return MTKCAM_IPI_IMG_FMT_BAYER16;
+ case V4L2_PIX_FMT_MTISP_NV12_UFBC:
+ return MTKCAM_IPI_IMG_FMT_UFBC_NV12;
+ case V4L2_PIX_FMT_MTISP_NV21_UFBC:
+ return MTKCAM_IPI_IMG_FMT_UFBC_NV21;
+ case V4L2_PIX_FMT_MTISP_NV12_10_UFBC:
+ return MTKCAM_IPI_IMG_FMT_UFBC_YUV_P010;
+ case V4L2_PIX_FMT_MTISP_NV21_10_UFBC:
+ return MTKCAM_IPI_IMG_FMT_UFBC_YVU_P010;
+ case V4L2_PIX_FMT_MTISP_NV12_12_UFBC:
+ return MTKCAM_IPI_IMG_FMT_UFBC_YUV_P012;
+ case V4L2_PIX_FMT_MTISP_NV21_12_UFBC:
+ return MTKCAM_IPI_IMG_FMT_UFBC_YVU_P012;
+ case V4L2_PIX_FMT_MTISP_BAYER8_UFBC:
+ return MTKCAM_IPI_IMG_FMT_UFBC_BAYER8;
+ case V4L2_PIX_FMT_MTISP_BAYER10_UFBC:
+ return MTKCAM_IPI_IMG_FMT_UFBC_BAYER10;
+ case V4L2_PIX_FMT_MTISP_BAYER12_UFBC:
+ return MTKCAM_IPI_IMG_FMT_UFBC_BAYER12;
+ case V4L2_PIX_FMT_MTISP_BAYER14_UFBC:
+ return MTKCAM_IPI_IMG_FMT_UFBC_BAYER14;
+ case V4L2_PIX_FMT_MTISP_SGRB8F:
+ return MTKCAM_IPI_IMG_FMT_FG_BAYER8_3P;
+ case V4L2_PIX_FMT_MTISP_SGRB10F:
+ return MTKCAM_IPI_IMG_FMT_FG_BAYER10_3P_PACKED;
+ case V4L2_PIX_FMT_MTISP_SGRB12F:
+ return MTKCAM_IPI_IMG_FMT_FG_BAYER12_3P_PACKED;
+ default:
+ return MTKCAM_IPI_IMG_FMT_UNKNOWN;
+ }
+}
+
+static void mtk_cam_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
+ u32 pixelformat, u32 width, u32 height)
+{
+ struct v4l2_plane_pix_format *plane;
+ unsigned int ipi_fmt = mtk_cam_get_img_fmt(pixelformat);
+ u8 pixel_bits = mtk_cam_get_pixel_bits(ipi_fmt);
+ u32 stride;
+ u32 aligned_width;
+ u8 bus_size;
+ u8 i;
+
+ pixfmt->width = width;
+ pixfmt->height = height;
+ pixfmt->pixelformat = pixelformat;
+ plane = &pixfmt->plane_fmt[0];
+ bus_size = mtk_cam_yuv_dma_bus_size(pixel_bits, 0);
+ plane->sizeimage = 0;
+
+ if (is_mtk_format(pixelformat)) {
+ const struct mtk_format_info *info;
+
+ info = mtk_format_info(pixelformat);
+ if (!info)
+ return;
+
+ pixfmt->num_planes = info->mem_planes;
+ if (info->mem_planes == 1) {
+ if (is_yuv_ufo(pixelformat)) {
+ /* UFO format width should align 64 pixel */
+ aligned_width = ALIGN(width, 64);
+ stride = aligned_width * info->bit_r_num / info->bit_r_den;
+
+ if (stride > plane->bytesperline)
+ plane->bytesperline = stride;
+ plane->sizeimage = stride * height;
+ plane->sizeimage += stride * height / 2;
+ plane->sizeimage += ALIGN((aligned_width / 64), 8) * height;
+ plane->sizeimage += ALIGN((aligned_width / 64), 8) * height / 2;
+ plane->sizeimage += sizeof(struct ufbc_buffer_header);
+ } else if (is_raw_ufo(pixelformat)) {
+ /* UFO format width should align 64 pixel */
+ aligned_width = ALIGN(width, 64);
+ stride = aligned_width * info->bit_r_num / info->bit_r_den;
+
+ if (stride > plane->bytesperline)
+ plane->bytesperline = stride;
+ plane->sizeimage = stride * height;
+ plane->sizeimage += ALIGN((aligned_width / 64), 8) * height;
+ plane->sizeimage += sizeof(struct ufbc_buffer_header);
+ } else {
+ /* width should be bus_size align */
+ aligned_width = ALIGN(DIV_ROUND_UP(width
+ * info->bit_r_num, info->bit_r_den), bus_size);
+ stride = aligned_width * info->bpp[0];
+
+ if (stride > plane->bytesperline)
+ plane->bytesperline = stride;
+
+ for (i = 0; i < info->comp_planes; i++) {
+ unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
+ unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
+
+ if (plane->bytesperline > stride &&
+ is_fullg_rb(pixelformat)) {
+ plane->sizeimage +=
+ DIV_ROUND_UP(plane->bytesperline, hdiv)
+ * DIV_ROUND_UP(height, vdiv);
+ } else if (plane->bytesperline > stride &&
+ !is_fullg_rb(pixelformat)) {
+ plane->sizeimage +=
+ plane->bytesperline
+ * DIV_ROUND_UP(height, vdiv);
+ } else {
+ plane->sizeimage += info->bpp[i]
+ * DIV_ROUND_UP(aligned_width, hdiv)
+ * DIV_ROUND_UP(height, vdiv);
+ }
+ }
+ }
+ pr_debug("%s stride %d sizeimage %d\n", __func__,
+ plane->bytesperline, plane->sizeimage);
+ } else {
+ pr_debug("do not support non contiguous mplane\n");
+ }
+ } else {
+ const struct v4l2_format_info *info;
+
+ pr_debug("pixelformat:0x%x sizeimage:%d\n",
+ pixelformat, plane->sizeimage);
+ info = v4l2_format_info(pixelformat);
+ if (!info)
+ return;
+
+ pixfmt->num_planes = info->mem_planes;
+ if (info->mem_planes == 1) {
+ aligned_width = ALIGN(width, bus_size);
+ stride = aligned_width * info->bpp[0];
+ if (stride > plane->bytesperline)
+ plane->bytesperline = stride;
+
+ for (i = 0; i < info->comp_planes; i++) {
+ unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
+ unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
+
+ plane->sizeimage += info->bpp[i]
+ * DIV_ROUND_UP(aligned_width, hdiv)
+ * DIV_ROUND_UP(height, vdiv);
+ }
+ pr_debug("%s stride %d sizeimage %d\n", __func__,
+ plane->bytesperline, plane->sizeimage);
+ } else {
+ pr_warn("do not support non contiguous mplane\n");
+ }
+ }
+}
+
+static void mtk_cam_fill_ext_fmtdesc(struct v4l2_fmtdesc *fmt)
+{
+ const char *descr = NULL;
+ const unsigned int sz = sizeof(fmt->description);
+
+ switch (fmt->pixelformat) {
+ case V4L2_PIX_FMT_MTISP_SBGGR8:
+ descr = "8-bit Bayer BGGR MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGBRG8:
+ descr = "8-bit Bayer GBRG MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGRBG8:
+ descr = "8-bit Bayer GRBG MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SRGGB8:
+ descr = "8-bit Bayer RGGB MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SBGGR10:
+ descr = "10-bit Bayer BGGR MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGBRG10:
+ descr = "10-bit Bayer GBRG MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGRBG10:
+ descr = "10-bit Bayer GRBG MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SRGGB10:
+ descr = "10-bit Bayer RGGB MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SBGGR12:
+ descr = "12-bit Bayer BGGR MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGBRG12:
+ descr = "12-bit Bayer GBRG MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGRBG12:
+ descr = "12-bit Bayer GRBG MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SRGGB12:
+ descr = "12-bit Bayer RGGB MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SBGGR14:
+ descr = "14-bit Bayer BGGR MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGBRG14:
+ descr = "14-bit Bayer GBRG MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGRBG14:
+ descr = "14-bit Bayer GRBG MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SRGGB14:
+ descr = "14-bit Bayer RGGB MTISP Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SBGGR8F:
+ descr = "8-bit Full-G Bayer BGGR Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGBRG8F:
+ descr = "8-bit Full-G Bayer GBRG Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGRBG8F:
+ descr = "8-bit Full-G Bayer GRBG Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SRGGB8F:
+ descr = "8-bit Full-G Bayer RGGB Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SBGGR10F:
+ descr = "10-bit Full-G Bayer BGGR Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGBRG10F:
+ descr = "10-bit Full-G Bayer GBRG Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGRBG10F:
+ descr = "10-bit Full-G Bayer GRBG Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SRGGB10F:
+ descr = "10-bit Full-G Bayer RGGB Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SBGGR12F:
+ descr = "12-bit Full-G Bayer BGGR Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGBRG12F:
+ descr = "12-bit Full-G Bayer GBRG Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGRBG12F:
+ descr = "12-bit Full-G Bayer GRBG Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SRGGB12F:
+ descr = "12-bit Full-G Bayer RGGB Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SBGGR14F:
+ descr = "14-bit Full-G Bayer BGGR Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGBRG14F:
+ descr = "14-bit Full-G Bayer GBRG Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGRBG14F:
+ descr = "14-bit Full-G Bayer GRBG Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SRGGB14F:
+ descr = "14-bit Full-G Bayer RGGB Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV12_10P:
+ descr = "Y/CbCr 4:2:0 10 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV21_10P:
+ descr = "Y/CrCb 4:2:0 10 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV16_10P:
+ descr = "Y/CbCr 4:2:2 10 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV61_10P:
+ descr = "Y/CrCb 4:2:2 10 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_YUYV10P:
+ descr = "YUYV 4:2:2 10 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_YVYU10P:
+ descr = "YVYU 4:2:2 10 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_UYVY10P:
+ descr = "UYVY 4:2:2 10 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_VYUY10P:
+ descr = "VYUY 4:2:2 10 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV12_12P:
+ descr = "Y/CbCr 4:2:0 12 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV21_12P:
+ descr = "Y/CrCb 4:2:0 12 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV16_12P:
+ descr = "Y/CbCr 4:2:2 12 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV61_12P:
+ descr = "Y/CrCb 4:2:2 12 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_YUYV12P:
+ descr = "YUYV 4:2:2 12 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_YVYU12P:
+ descr = "YVYU 4:2:2 12 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_UYVY12P:
+ descr = "UYVY 4:2:2 12 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_VYUY12P:
+ descr = "VYUY 4:2:2 12 bits packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV12_UFBC:
+ descr = "YCbCr 420 8 bits compress";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV21_UFBC:
+ descr = "YCrCb 420 8 bits compress";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV12_10_UFBC:
+ descr = "YCbCr 420 10 bits compress";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV21_10_UFBC:
+ descr = "YCrCb 420 10 bits compress";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV12_12_UFBC:
+ descr = "YCbCr 420 12 bits compress";
+ break;
+ case V4L2_PIX_FMT_MTISP_NV21_12_UFBC:
+ descr = "YCrCb 420 12 bits compress";
+ break;
+ case V4L2_PIX_FMT_MTISP_BAYER8_UFBC:
+ descr = "RAW 8 bits compress";
+ break;
+ case V4L2_PIX_FMT_MTISP_BAYER10_UFBC:
+ descr = "RAW 10 bits compress";
+ break;
+ case V4L2_PIX_FMT_MTISP_BAYER12_UFBC:
+ descr = "RAW 12 bits compress";
+ break;
+ case V4L2_PIX_FMT_MTISP_BAYER14_UFBC:
+ descr = "RAW 14 bits compress";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGRB8F:
+ descr = "8-bit 3 plane GRB Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGRB10F:
+ descr = "10-bit 3 plane GRB Packed";
+ break;
+ case V4L2_PIX_FMT_MTISP_SGRB12F:
+ descr = "12-bit 3 plane GRB Packed";
+ break;
+ case V4L2_META_FMT_MTISP_PARAMS:
+ descr = "MTK ISP Tuning Metadata";
+ break;
+ case V4L2_META_FMT_MTISP_3A:
+ descr = "MTK 3A Statistics";
+ break;
+ case V4L2_META_FMT_MTISP_AF:
+ descr = "MTK AF Statistics";
+ break;
+ case V4L2_META_FMT_MTISP_LCS:
+ descr = "MTK LCS Statistics";
+ break;
+ case V4L2_META_FMT_MTISP_LMV:
+ descr = "MTK LMV Statistics";
+ break;
+ default:
+ descr = NULL;
+ break;
+ }
+
+ if (descr)
+ WARN_ON(strscpy(fmt->description, descr, sz) < 0);
+}
+
+static void cal_image_pix_mp(unsigned int node_id,
+ struct v4l2_pix_format_mplane *mp,
+ unsigned int pixel_mode)
+{
+ unsigned int ipi_fmt = mtk_cam_get_img_fmt(mp->pixelformat);
+ unsigned int width = mp->width;
+ unsigned int height = mp->height;
+ unsigned int stride, i;
+
+ pr_debug("fmt:0x%x ipi_fmt:%d\n", mp->pixelformat, ipi_fmt);
+ switch (ipi_fmt) {
+ case MTKCAM_IPI_IMG_FMT_BAYER8:
+ case MTKCAM_IPI_IMG_FMT_BAYER10:
+ case MTKCAM_IPI_IMG_FMT_BAYER12:
+ case MTKCAM_IPI_IMG_FMT_BAYER14:
+ case MTKCAM_IPI_IMG_FMT_BAYER16:
+ case MTKCAM_IPI_IMG_FMT_BAYER10_MIPI:
+ case MTKCAM_IPI_IMG_FMT_BAYER10_UNPACKED:
+ case MTKCAM_IPI_IMG_FMT_BAYER12_UNPACKED:
+ case MTKCAM_IPI_IMG_FMT_BAYER14_UNPACKED:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER8:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER10:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER12:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER14:
+ stride = mtk_cam_dmao_xsize(width, ipi_fmt, pixel_mode);
+ for (i = 0; i < mp->num_planes; i++) {
+ if (stride > mp->plane_fmt[i].bytesperline)
+ mp->plane_fmt[i].bytesperline = stride;
+ mp->plane_fmt[i].sizeimage =
+ mp->plane_fmt[i].bytesperline * height;
+ }
+ break;
+ case MTKCAM_IPI_IMG_FMT_YUYV:
+ case MTKCAM_IPI_IMG_FMT_YVYU:
+ case MTKCAM_IPI_IMG_FMT_UYVY:
+ case MTKCAM_IPI_IMG_FMT_VYUY:
+ case MTKCAM_IPI_IMG_FMT_YUV_422_2P:
+ case MTKCAM_IPI_IMG_FMT_YVU_422_2P:
+ case MTKCAM_IPI_IMG_FMT_YUV_422_3P:
+ case MTKCAM_IPI_IMG_FMT_YVU_422_3P:
+ case MTKCAM_IPI_IMG_FMT_YUV_420_2P:
+ case MTKCAM_IPI_IMG_FMT_YVU_420_2P:
+ case MTKCAM_IPI_IMG_FMT_YUV_420_3P:
+ case MTKCAM_IPI_IMG_FMT_YVU_420_3P:
+ case MTKCAM_IPI_IMG_FMT_Y8:
+ case MTKCAM_IPI_IMG_FMT_YUYV_Y210:
+ case MTKCAM_IPI_IMG_FMT_YVYU_Y210:
+ case MTKCAM_IPI_IMG_FMT_UYVY_Y210:
+ case MTKCAM_IPI_IMG_FMT_VYUY_Y210:
+ case MTKCAM_IPI_IMG_FMT_YUYV_Y210_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YVYU_Y210_PACKED:
+ case MTKCAM_IPI_IMG_FMT_UYVY_Y210_PACKED:
+ case MTKCAM_IPI_IMG_FMT_VYUY_Y210_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YUV_P210:
+ case MTKCAM_IPI_IMG_FMT_YVU_P210:
+ case MTKCAM_IPI_IMG_FMT_YUV_P010:
+ case MTKCAM_IPI_IMG_FMT_YVU_P010:
+ case MTKCAM_IPI_IMG_FMT_YUV_P210_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YVU_P210_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YUV_P010_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YVU_P010_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YUV_P212:
+ case MTKCAM_IPI_IMG_FMT_YVU_P212:
+ case MTKCAM_IPI_IMG_FMT_YUV_P012:
+ case MTKCAM_IPI_IMG_FMT_YVU_P012:
+ case MTKCAM_IPI_IMG_FMT_YUV_P212_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YVU_P212_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YUV_P012_PACKED:
+ case MTKCAM_IPI_IMG_FMT_YVU_P012_PACKED:
+ case MTKCAM_IPI_IMG_FMT_UFBC_NV12:
+ case MTKCAM_IPI_IMG_FMT_UFBC_NV21:
+ case MTKCAM_IPI_IMG_FMT_UFBC_YUV_P010:
+ case MTKCAM_IPI_IMG_FMT_UFBC_YVU_P010:
+ case MTKCAM_IPI_IMG_FMT_UFBC_YUV_P012:
+ case MTKCAM_IPI_IMG_FMT_UFBC_YVU_P012:
+ case MTKCAM_IPI_IMG_FMT_UFBC_BAYER8:
+ case MTKCAM_IPI_IMG_FMT_UFBC_BAYER10:
+ case MTKCAM_IPI_IMG_FMT_UFBC_BAYER12:
+ case MTKCAM_IPI_IMG_FMT_UFBC_BAYER14:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER8_3P:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER10_3P_PACKED:
+ case MTKCAM_IPI_IMG_FMT_FG_BAYER12_3P_PACKED:
+ mtk_cam_fill_pixfmt_mp(mp, mp->pixelformat, width, height);
+ break;
+ default:
+ break;
+ }
+}
+
+static int mtk_video_init_format(struct mtk_cam_video_device *video)
+{
+ struct mtk_cam_dev_node_desc *desc = &video->desc;
+ struct v4l2_format *active = &video->active_fmt;
+ const struct v4l2_format *default_fmt =
+ &desc->fmts[desc->default_fmt_idx].vfmt;
+
+ active->type = desc->buf_type;
+
+ if (!desc->image) {
+ active->fmt.meta.dataformat = default_fmt->fmt.meta.dataformat;
+ active->fmt.meta.buffersize = default_fmt->fmt.meta.buffersize;
+ return 0;
+ }
+
+ active->fmt.pix_mp.pixelformat = default_fmt->fmt.pix_mp.pixelformat;
+ active->fmt.pix_mp.width = default_fmt->fmt.pix_mp.width;
+ active->fmt.pix_mp.height = default_fmt->fmt.pix_mp.height;
+ active->fmt.pix_mp.num_planes = default_fmt->fmt.pix_mp.num_planes;
+
+ cal_image_pix_mp(desc->id, &active->fmt.pix_mp, 0);
+
+ /* set init one-plane */
+ active->fmt.pix_mp.num_planes = 1;
+ active->fmt.pix_mp.colorspace = V4L2_COLORSPACE_SRGB;
+ active->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ active->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ active->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
+ active->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_SRGB;
+
+ return 0;
+}
+
+int mtk_cam_video_register(struct mtk_cam_video_device *video,
+ struct v4l2_device *v4l2_dev)
+{
+ struct mtk_cam_device *cam =
+ container_of(v4l2_dev, struct mtk_cam_device, v4l2_dev);
+ struct media_pad *pad = &video->pad;
+ struct video_device *vdev = &video->vdev;
+ struct vb2_queue *q = &video->vb2_q;
+ unsigned int output = V4L2_TYPE_IS_OUTPUT(video->desc.buf_type);
+ int ret;
+
+ if (video->desc.link_flags & MEDIA_LNK_FL_ENABLED)
+ video->enabled = true;
+ else
+ video->enabled = false;
+
+ mutex_init(&video->q_lock);
+
+ /* initialize vb2_queue */
+ q->type = video->desc.buf_type;
+ q->io_modes = VB2_MMAP | VB2_DMABUF;
+
+ if (q->type == V4L2_BUF_TYPE_META_OUTPUT)
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ else
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_BOOTIME;
+
+ if (video->desc.smem_alloc) {
+ q->bidirectional = 1;
+ /* reserved memory */
+ q->dev = cam->smem_dev;
+ } else if (is_yuv_node(video->desc.id)) {
+ q->dev = cam->raw.yuvs[0];
+ } else {
+ q->dev = cam->raw.devs[0];
+ }
+
+ q->supports_requests = true;
+ q->lock = &video->q_lock;
+ q->ops = &mtk_cam_vb2_ops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->drv_priv = cam;
+ q->buf_struct_size = sizeof(struct mtk_cam_buffer);
+
+ if (output)
+ q->timestamp_flags |= V4L2_BUF_FLAG_TSTAMP_SRC_EOF;
+ else
+ q->timestamp_flags |= V4L2_BUF_FLAG_TSTAMP_SRC_SOE;
+
+ /* No minimum buffers limitation */
+ q->min_queued_buffers = 0;
+
+ ret = vb2_queue_init(q);
+ if (ret < 0) {
+ dev_info(v4l2_dev->dev, "Failed to init vb2 queue: %d\n", ret);
+ goto error_vb2_init;
+ }
+
+ pad->flags = output ? MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vdev->entity, 1, pad);
+ if (ret < 0) {
+ dev_info(v4l2_dev->dev, "Failed to init video entity: %d\n", ret);
+ goto error_media_init;
+ }
+
+ ret = mtk_video_init_format(video);
+ if (ret < 0) {
+ dev_info(v4l2_dev->dev, "Failed to init format: %d\n", ret);
+ goto error_video_register;
+ }
+
+ vdev->entity.function = MEDIA_ENT_F_IO_V4L;
+ vdev->entity.ops = NULL;
+ vdev->fops = &mtk_cam_v4l2_fops;
+ vdev->device_caps = video->desc.cap | V4L2_CAP_STREAMING;
+ vdev->v4l2_dev = v4l2_dev;
+
+ vdev->vfl_dir = output ? VFL_DIR_TX : VFL_DIR_RX;
+ vdev->queue = &video->vb2_q;
+ vdev->ioctl_ops = video->desc.ioctl_ops;
+ vdev->release = video_device_release_empty;
+ /* share q_lock */
+ vdev->lock = &video->q_lock;
+ strscpy(vdev->name, video->desc.name, sizeof(vdev->name));
+
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ if (ret < 0) {
+ dev_info(v4l2_dev->dev, "Failed to register video device: %d\n",
+ ret);
+ goto error_video_register;
+ }
+ video_set_drvdata(vdev, cam);
+
+ dev_dbg(v4l2_dev->dev, "registered vdev:%d:%s\n",
+ video->desc.id, vdev->name);
+
+ return 0;
+
+error_video_register:
+ media_entity_cleanup(&vdev->entity);
+error_media_init:
+ vb2_queue_release(&video->vb2_q);
+error_vb2_init:
+ mutex_destroy(&video->q_lock);
+
+ return ret;
+}
+
+void mtk_cam_video_unregister(struct mtk_cam_video_device *video)
+{
+ video_unregister_device(&video->vdev);
+ vb2_queue_release(&video->vb2_q);
+ media_entity_cleanup(&video->vdev.entity);
+ mutex_destroy(&video->q_lock);
+}
+
+const struct v4l2_format *
+mtk_cam_dev_find_fmt(struct mtk_cam_dev_node_desc *desc, u32 format)
+{
+ unsigned int i;
+ const struct v4l2_format *fmt;
+
+ for (i = 0; i < desc->num_fmts; i++) {
+ fmt = &desc->fmts[i].vfmt;
+ if (fmt->fmt.pix_mp.pixelformat == format)
+ return fmt;
+ }
+
+ return NULL;
+}
+
+int mtk_cam_vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct mtk_cam_device *cam = video_drvdata(file);
+
+ strscpy(cap->driver, dev_driver_string(cam->dev), sizeof(cap->driver));
+ strscpy(cap->card, dev_driver_string(cam->dev), sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ dev_name(cam->dev));
+
+ return 0;
+}
+
+int mtk_cam_vidioc_enum_framesizes(struct file *filp, void *priv,
+ struct v4l2_frmsizeenum *sizes)
+{
+ struct mtk_cam_video_device *node = file_to_mtk_cam_node(filp);
+ const struct v4l2_format *dev_fmt;
+
+ dev_fmt = mtk_cam_dev_find_fmt(&node->desc, sizes->pixel_format);
+ if (!dev_fmt || sizes->index)
+ return -EINVAL;
+
+ sizes->type = node->desc.frmsizes->type;
+ memcpy(&sizes->stepwise, &node->desc.frmsizes->stepwise,
+ sizeof(sizes->stepwise));
+ return 0;
+}
+
+int mtk_cam_vidioc_enum_fmt(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct mtk_cam_video_device *node = file_to_mtk_cam_node(file);
+
+ if (f->index >= node->desc.num_fmts)
+ return -EINVAL;
+
+ f->pixelformat = node->desc.fmts[f->index].vfmt.fmt.pix_mp.pixelformat;
+ f->flags = 0;
+ /* extended fmt description is filled here */
+ /* common fmt description is filled in v4l_fill_fmtdesc */
+ mtk_cam_fill_ext_fmtdesc(f);
+
+ return 0;
+}
+
+int mtk_cam_vidioc_g_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct mtk_cam_video_device *node = file_to_mtk_cam_node(file);
+
+ f->fmt = node->active_fmt.fmt;
+
+ return 0;
+}
+
+int mtk_cam_vidioc_s_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct mtk_cam_device *cam = video_drvdata(file);
+ struct mtk_cam_video_device *node = file_to_mtk_cam_node(file);
+ struct mtk_raw_pipeline *raw_pipeline;
+ int raw_feature = 0;
+
+ raw_pipeline = mtk_cam_dev_get_raw_pipeline(cam, node->uid.pipe_id);
+
+ if (!vb2_is_busy(node->vdev.queue)) {
+ /* Get the valid format */
+ if (raw_pipeline)
+ raw_feature = raw_pipeline->user_res.raw_res.feature;
+
+ mtk_cam_video_set_fmt(node, f, raw_feature);
+
+ /* Configure to video device */
+ node->active_fmt = *f;
+ return 0;
+ }
+
+ dev_info(cam->dev,
+ "%s:pipe(%d):%s:Cannot change format while streaming\n",
+ __func__, node->uid.pipe_id, node->desc.name);
+
+ return -EBUSY;
+}
+
+int mtk_cam_video_set_fmt(struct mtk_cam_video_device *node,
+ struct v4l2_format *f, int raw_feature)
+{
+ struct mtk_cam_device *cam = video_get_drvdata(&node->vdev);
+ const struct v4l2_format *dev_fmt;
+ struct v4l2_format try_fmt;
+ s32 i;
+
+ dev_dbg(cam->dev,
+ "%s:pipe(%d):%s:feature(0x%x)\n",
+ __func__, node->uid.pipe_id, node->desc.name, raw_feature);
+
+ memset(&try_fmt, 0, sizeof(try_fmt));
+ try_fmt.type = f->type;
+
+ /* Validate pixelformat */
+ dev_fmt = mtk_cam_dev_find_fmt(&node->desc, f->fmt.pix_mp.pixelformat);
+ if (!dev_fmt) {
+ dev_dbg(cam->dev, "unknown fmt:%d\n",
+ f->fmt.pix_mp.pixelformat);
+ dev_fmt = &node->desc.fmts[node->desc.default_fmt_idx].vfmt;
+ }
+ try_fmt.fmt.pix_mp.pixelformat = dev_fmt->fmt.pix_mp.pixelformat;
+
+ /* Validate image width & height range */
+ try_fmt.fmt.pix_mp.width = clamp_val(f->fmt.pix_mp.width,
+ IMG_MIN_WIDTH, IMG_MAX_WIDTH);
+ try_fmt.fmt.pix_mp.height = clamp_val(f->fmt.pix_mp.height,
+ IMG_MIN_HEIGHT, IMG_MAX_HEIGHT);
+ /* 4 bytes alignment for width */
+ /* width and stride should align bus_size */
+ try_fmt.fmt.pix_mp.width = ALIGN(try_fmt.fmt.pix_mp.width, IMG_PIX_ALIGN);
+ try_fmt.fmt.pix_mp.num_planes = 1;
+
+ for (i = 0 ; i < try_fmt.fmt.pix_mp.num_planes ; i++)
+ try_fmt.fmt.pix_mp.plane_fmt[i].bytesperline =
+ f->fmt.pix_mp.plane_fmt[i].bytesperline;
+
+ /* bytesperline & sizeimage calculation */
+ cal_image_pix_mp(node->desc.id, &try_fmt.fmt.pix_mp, 0);
+
+ /* Constant format fields */
+ try_fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_SRGB;
+ try_fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
+ try_fmt.fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ try_fmt.fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
+ try_fmt.fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_SRGB;
+
+ *f = try_fmt;
+
+ return 0;
+}
+
+int mtk_cam_vidioc_try_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct mtk_cam_video_device *node = file_to_mtk_cam_node(file);
+
+ mtk_cam_video_set_fmt(node, f, 0);
+
+ return 0;
+}
+
+int mtk_cam_vidioc_meta_enum_fmt(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct mtk_cam_video_device *node = file_to_mtk_cam_node(file);
+
+ if (f->index)
+ return -EINVAL;
+
+ f->pixelformat = node->active_fmt.fmt.meta.dataformat;
+ f->flags = 0;
+ /* extended fmt description is filled here */
+ /* common fmt description is filled in v4l_fill_fmtdesc */
+ mtk_cam_fill_ext_fmtdesc(f);
+
+ return 0;
+}
+
+int mtk_cam_vidioc_g_meta_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct mtk_cam_device *cam = video_drvdata(file);
+ struct mtk_cam_video_device *node = file_to_mtk_cam_node(file);
+ struct mtk_cam_dev_node_desc *desc = &node->desc;
+ const struct v4l2_format *default_fmt =
+ &desc->fmts[desc->default_fmt_idx].vfmt;
+ struct mtk_raw_pde_config *pde_cfg;
+ struct mtk_cam_pde_info *pde_info;
+
+ if (node->desc.dma_port == MTKCAM_IPI_RAW_META_STATS_CFG) {
+ pde_cfg = &cam->raw.pipelines[node->uid.pipe_id].pde_config;
+ pde_info = &pde_cfg->pde_info;
+ if (pde_info->pd_table_offset) {
+ node->active_fmt.fmt.meta.buffersize =
+ default_fmt->fmt.meta.buffersize +
+ pde_info->pdi_max_size;
+
+ dev_dbg(cam->dev, "PDE: node(%d), enlarge meta size(%u)",
+ node->desc.dma_port,
+ node->active_fmt.fmt.meta.buffersize);
+ }
+ }
+ if (node->desc.dma_port == MTKCAM_IPI_RAW_META_STATS_0) {
+ pde_cfg = &cam->raw.pipelines[node->uid.pipe_id].pde_config;
+ pde_info = &pde_cfg->pde_info;
+ if (pde_info->pd_table_offset) {
+ node->active_fmt.fmt.meta.buffersize =
+ default_fmt->fmt.meta.buffersize +
+ pde_info->pdo_max_size;
+
+ dev_dbg(cam->dev, "PDE: node(%d), enlarge meta size(%u)",
+ node->desc.dma_port,
+ node->active_fmt.fmt.meta.buffersize);
+ }
+ }
+ f->fmt.meta.dataformat = node->active_fmt.fmt.meta.dataformat;
+ f->fmt.meta.buffersize = node->active_fmt.fmt.meta.buffersize;
+
+ return 0;
+}
+
+int mtk_cam_vidioc_s_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
+{
+ struct mtk_cam_device *cam = video_drvdata(file);
+ struct mtk_cam_video_device *node = file_to_mtk_cam_node(file);
+ struct mtk_raw_pipeline *raw_pipeline;
+
+ raw_pipeline = mtk_cam_dev_get_raw_pipeline(cam, node->uid.pipe_id);
+ if (raw_pipeline) {
+ node->active_crop = *s;
+
+ dev_dbg(raw_pipeline->subdev.v4l2_dev->dev,
+ "%s:%s:%s:Set selection (%d,%d,%d,%d)\n",
+ __func__, raw_pipeline->subdev.name, node->desc.name,
+ s->r.left, s->r.top, s->r.width, s->r.height);
+ }
+
+ return 0;
+}
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.h
new file mode 100644
index 000000000000..6c79987670f8
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.h
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAM_VIDEO_H
+#define __MTK_CAM_VIDEO_H
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "mtk_cam-ipi.h"
+
+#define MAX_PLANE_NUM 3
+
+struct mtk_cam_resource;
+struct mtk_raw_pde_config;
+
+typedef int (*set_pad_fmt_func_t)(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_mbus_framefmt *sink_fmt,
+ struct mtk_cam_resource *res,
+ int pad, int which);
+
+typedef int (*set_pad_selection_func_t)(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_mbus_framefmt *sink_fmt,
+ struct mtk_cam_resource *res,
+ int pad, int which);
+
+/*For state analysis and controlling for request*/
+enum MTK_BUF_STATE {
+ E_BUF_STATE_QUEUED = 0x0,
+ E_BUF_STATE_COMPOSED,
+ E_BUF_STATE_CQ,
+ E_BUF_STATE_OUTER,
+};
+
+struct mtk_buf_state {
+ enum MTK_BUF_STATE estate;
+ struct list_head list;
+};
+
+/**
+ * struct mtk_cam_buffer - MTK camera device buffer.
+ *
+ * @vbb: Embedded struct vb2_v4l2_buffer.
+ * @list: List entry for the buffer queue
+ * @daddr: The DMA address of this buffer.
+ * @scp_addr: The SCP address of this buffer which
+ * is only supported for meta input node.
+ * @state: The camera buffer status.
+ */
+struct mtk_cam_buffer {
+ struct vb2_v4l2_buffer vbb;
+ struct list_head list;
+
+ dma_addr_t daddr;
+ dma_addr_t scp_addr;
+ struct mtk_buf_state state;
+};
+
+struct mtk_cam_format_desc {
+ struct v4l2_format vfmt;
+ struct v4l2_mbus_framefmt pfmt;
+};
+
+struct mtk_cam_pad_ops {
+ set_pad_fmt_func_t set_pad_fmt;
+ set_pad_selection_func_t set_pad_selection;
+};
+
+/**
+ * struct mtk_cam_dev_node_desc - MTK camera device node descriptor
+ *
+ * @id: id of the node
+ * @name: name of the node
+ * @cap: supported V4L2 capabilities
+ * @buf_type: supported V4L2 buffer type
+ * @dma_port: the dma ports associated to the node
+ * @link_flags: default media link flags
+ * @smem_alloc: using the smem_dev as alloc device or not
+ * @need_cache_sync_on_prepare: do cache sync at buf_prepare (userspace sync)
+ * @need_cache_sync_on_finish: do cache sync at buf_finish (userspace sync)
+ * @image: true for image node, false for meta node
+ * @num_fmts: the number of supported node formats
+ * @default_fmt_idx: default format of this node
+ * @max_buf_count: maximum VB2 buffer count
+ * @ioctl_ops: mapped to v4l2_ioctl_ops
+ * @fmts: supported format
+ * @frmsizes: supported V4L2 frame size number
+ * @pad_ops: set and select pad configurations and formats
+ */
+struct mtk_cam_dev_node_desc {
+ u8 id;
+ const char *name;
+ u32 cap;
+ u32 buf_type;
+ u32 dma_port;
+ u32 link_flags;
+ u8 smem_alloc:1;
+ u8 image:1;
+ u8 num_fmts;
+ u8 default_fmt_idx;
+ u8 max_buf_count;
+ const struct v4l2_ioctl_ops *ioctl_ops;
+ const struct mtk_cam_format_desc *fmts;
+ const struct v4l2_frmsizeenum *frmsizes;
+ struct mtk_cam_pad_ops *pad_ops;
+};
+
+/**
+ * struct mtk_cam_video_device - MediaTek video device structure.
+ */
+struct mtk_cam_video_device {
+ struct mtkcam_ipi_uid uid;
+ struct mtk_cam_dev_node_desc desc;
+ unsigned int enabled;
+
+ struct vb2_queue vb2_q;
+ struct video_device vdev;
+ struct media_pad pad;
+ struct v4l2_format active_fmt;
+ /* use first 4 elements of reserved field of v4l2_pix_format_mplane as request fd */
+ struct v4l2_format pending_fmt;
+ /* use first elements of reserved field of v4l2_selection as request fd*/
+ struct v4l2_selection active_crop;
+ /* Serializes vb2 queue and video device operations */
+ struct mutex q_lock;
+ int streaming_id;
+
+ /* cached ctx info */
+ struct mtk_cam_ctx *ctx;
+};
+
+struct mtk_format_info {
+ u32 format;
+ u8 mem_planes;
+ u8 comp_planes;
+ u8 bpp[4];
+ u8 hdiv;
+ u8 vdiv;
+ u8 bit_r_num; /* numerator of bit ratio */
+ u8 bit_r_den; /* denominator of bit ratio */
+};
+
+int mtk_cam_video_register(struct mtk_cam_video_device *video,
+ struct v4l2_device *v4l2_dev);
+
+void mtk_cam_video_unregister(struct mtk_cam_video_device *video);
+
+static inline struct mtk_cam_video_device *
+file_to_mtk_cam_node(struct file *__file)
+{
+ return container_of(video_devdata(__file), struct mtk_cam_video_device, vdev);
+}
+
+static inline struct mtk_cam_buffer *
+mtk_cam_vb2_buf_to_dev_buf(struct vb2_buffer *__vb)
+{
+ return container_of(__vb, struct mtk_cam_buffer, vbb.vb2_buf);
+}
+
+static inline struct mtk_cam_video_device *
+mtk_cam_vbq_to_vdev(struct vb2_queue *__vq)
+{
+ return container_of(__vq, struct mtk_cam_video_device, vb2_q);
+}
+
+const struct v4l2_format *
+mtk_cam_dev_find_fmt(struct mtk_cam_dev_node_desc *desc, u32 format);
+
+int mtk_cam_vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap);
+
+int mtk_cam_vidioc_enum_framesizes(struct file *filp, void *priv,
+ struct v4l2_frmsizeenum *sizes);
+
+int mtk_cam_vidioc_enum_fmt(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+
+int mtk_cam_vidioc_g_fmt(struct file *file, void *fh, struct v4l2_format *f);
+
+int mtk_cam_vidioc_s_fmt(struct file *file, void *fh, struct v4l2_format *f);
+
+int mtk_cam_vidioc_try_fmt(struct file *file, void *fh, struct v4l2_format *f);
+
+int mtk_cam_vidioc_meta_enum_fmt(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+
+int mtk_cam_vidioc_s_selection(struct file *file, void *fh,
+ struct v4l2_selection *s);
+
+int mtk_cam_vidioc_g_meta_fmt(struct file *file, void *fh,
+ struct v4l2_format *f);
+
+/* Utility functions to convert format enum */
+unsigned int mtk_cam_get_sensor_pixel_id(unsigned int fmt);
+
+unsigned int mtk_cam_get_sensor_fmt(unsigned int fmt);
+
+unsigned int mtk_cam_get_pixel_bits(unsigned int pix_fmt);
+
+unsigned int mtk_cam_get_img_fmt(unsigned int fourcc);
+
+int mtk_cam_video_set_fmt(struct mtk_cam_video_device *node,
+ struct v4l2_format *f, int feature);
+
+int is_mtk_format(u32 pixelformat);
+
+int is_yuv_ufo(u32 pixelformat);
+
+int is_raw_ufo(u32 pixelformat);
+
+int is_fullg_rb(u32 pixelformat);
+
+const struct mtk_format_info *mtk_format_info(u32 format);
+
+#endif /*__MTK_CAM_VIDEO_H */
--
2.18.0